commit 99a67e6133b8e91f24cfed478ab52c84bcddea8b Author: MSVSphere Packaging Team Date: Fri Mar 29 15:40:34 2024 +0300 import glibc-2.28-251.el8 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..182f659 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +SOURCES/glibc-2.28.tar.xz diff --git a/.glibc.metadata b/.glibc.metadata new file mode 100644 index 0000000..175a3ec --- /dev/null +++ b/.glibc.metadata @@ -0,0 +1 @@ +ccb5dc9e51a9884df8488f86982439d47b283b2a SOURCES/glibc-2.28.tar.xz diff --git a/SOURCES/ChangeLog.old b/SOURCES/ChangeLog.old new file mode 100644 index 0000000..28b5ace --- /dev/null +++ b/SOURCES/ChangeLog.old @@ -0,0 +1,6058 @@ +* Wed Aug 02 2017 Fedora Release Engineering - 2.25.90-30.1 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_27_Binutils_Mass_Rebuild + +* Sat Jul 29 2017 Florian Weimer - 2.25.90-30 +- Auto-sync with upstream master, + commit 5920a4a624b1f4db310d1c44997b640e2a4653e5: +- mutex: Fix robust mutex lock acquire (swbz#21778) + +* Fri Jul 28 2017 Florian Weimer - 2.25.90-29 +- Auto-sync with upstream master, + commit d95fcb2df478efbf4f8537ba898374043ac4561f: +- rwlock: Fix explicit hand-over (swbz#21298) +- tunables: Use direct syscall for access (swbz#21744) +- Avoid accessing corrupted stack from __stack_chk_fail (swbz#21752) +- Remove extra semicolons in struct pthread_mutex (swbz#21804) +- grp: Fix cast-after-dereference (another big-endian group merge issue) +- S390: fix sys/ptrace.h to make it includible again after asm/ptrace.h +- Don't add stack_chk_fail_local.o to libc.a (swbz#21740) +- i386: Test memmove_chk and memset_chk only in libc.so (swbz#21741) +- Add new locales az_IR, mai_NP (swbz#14172) +- Various locale improvements + +* Thu Jul 27 2017 Carlos O'Donell - 2.25.90-28 +- Adjust to new rpm debuginfo generation (#1475009). + +* Wed Jul 26 2017 Fedora Release Engineering - 2.25.90-27.1 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_27_Mass_Rebuild + +* Wed Jul 19 2017 Florian Weimer - 2.25.90-27 +- Auto-sync with upstream master, + commit 00d7a3777369bac3d8d44152dde2bb7381984ef6: +- aarch64: Fix out of bound array access in _dl_hwcap_string + +* Mon Jul 17 2017 Florian Weimer - 2.25.90-26 +- Drop glibc-rh1467518.patch in favor of upstream patch (#1467518) +- Auto-sync with upstream master, + commit 91ac3a7d8474480685632cd25f844d3154c69fdf: +- Fix pointer alignment in NSS group merge result construction (#1471985) +- Various locale fixes + +* Fri Jul 14 2017 Carlos O'Donell - 2.25.90-25 +- armv7hl: Drop 32-bit ARM build fix, already in upstream master. +- s390x: Apply glibc fix again, removing PTRACE_GETREGS etc. (#1469536). +- Auto-sync with upstream master, + commit de895ddcd7fc45caeeeb0ae312311b8bd31d82c5: +- Added Fiji Hindi language locale for Fiji (swbz#21694). +- Added yesstr/nostr for nds_DE and nds_NL (swbz#21756). +- Added yesstr and nostr for Tigrinya (swbz#21759). +- Fix LC_MESSAGES and LC_ADDRESS for anp_IN (swbz#21760). +- Added yesstr/nostr and fix yesexpr for pap_AW and pap_CW (swbz#21757). +- Added Tongan language locale for Tonga (swbz#21728). +- [ARM] Fix ld.so crash when built using Binutils 2.29. +- Added yesstr and nostr for aa_ET (swbz#21768). +- New locale for bi_VU (swbz#21767). +- Disable single thread optimization for open_memstream + +* Wed Jul 12 2017 Carlos O'Donell - 2.25.90-24 +- Fix IFUNC crash in early startup for ppc64le static binaries (#1467518). +- Enable building with BIND_NOW on ppc64le (#1467518). +- Fix 32-bit ARM builds in presence of new binutils. + +* Wed Jul 12 2017 Florian Weimer - 2.25.90-23 +- malloc: Tell GCC optimizers about MAX_FAST_SIZE in _int_malloc (#1470060) +- Auto-sync with upstream master, + commit 30200427a99e5ddac9bad08599418d44d54aa9aa: +- Add per-thread cache to malloc +- Add Samoan language locale for Samoa +- Add Awajún / Aguaruna locale for Peru +- CVE-2010-3192: Avoid backtrace from __stack_chk_fail (swbz#12189) +- Add preadv2, writev2 RWF_NOWAIT flag (swbz#21738) +- Fix abday strings for ar_JO/ar_LB/ar_SY locales (swbz#21749) +- Fix abday strings for ar_SA locale (swbz#21748, swbz#19066) +- Set data_fmt for da_DK locale (swbz#17297) +- Add yesstr and nostr for the zh_HK locale (swbz#21733) +- Fix abday strings for the ksIN@devanagari locale (swbz#21743) +- Do not include _dl_resolv_conflicts in libc.a (swbz#21742) +- Test __memmove_chk, __memset_chk only in libc.so (swbz#21741) +- Add iI and eE to yesexpr and noexpr respectively for ts_ZA locale +- Add yesstr/nostr for kw_GB locale (swbz#21734) +- Add yesstr and nostr for the ts_ZA locale (swbz#21727) +- Fix LC_NAME for hi_IN locale (swbz#21729) +- Add yesstr and nostr for the xh_ZA locale (swbz#21724) +- Add yesstr and nostr for the zh_CN locale (swbz#21723) +- Fix full weekday names for the ks_IN@devanagari locale (swbz#21721) +- Various fixes to Arabic locales after CLDR import + +* Tue Jul 11 2017 Florian Weimer - 2.25.90-22 +- Reinstantiate stack_t cleanup (#1468904) +- s390x: Restore PTRACE_GETREGS etc. to get GCC to build (#1469536) + +* Sun Jul 9 2017 Florian Weimer - 2.25.90-21 +- Back out stack_t cleanup (#1468904) + +* Thu Jul 06 2017 Florian Weimer - 2.25.90-20 +- Auto-sync with upstream master, + commit 031e519c95c069abe4e4c7c59e2b4b67efccdee5: +- x86-64: Align the stack in __tls_get_addr (#1440287) +- Add Tok-Pisin (tpi_PG) locale. +- Add missing yesstr/nostr for Pashto locale (swbz#21711) +- Add missing yesstr/nostr for Breton locale (swbz#21706) +- Single threaded stdio optimization +- sysconf: Use conservative default for _SC_NPROCESSORS_ONLN (swbz#21542) + +* Tue Jul 04 2017 Florian Weimer - 2.25.90-19 +- Auto-sync with upstream master, + commit 4446a885f3aeb3a33b95c72bae1f115bed77f0cb. + +* Tue Jul 04 2017 Florian Weimer - 2.25.90-18 +- Auto-sync with upstream master, + commit 89f6307c5d270ed4f11cee373031fa9f2222f2b9. + +* Tue Jul 4 2017 Florian Weimer - 2.25.90-17 +- Disable building with BIND_NOW on ppc64le (#1467518) + +* Mon Jul 03 2017 Florian Weimer - 2.25.90-16 +- Auto-sync with upstream master, + commit e237357a5a0559dee92261f1914d1fa2cd43a1a8: +- Support an arbitrary number of search domains in the stub resolver (#168253) +- Detect and apply /etc/resolv.conf changes in libresolv (#1374239) +- Increase malloc alignment on i386 to 16 (swbz#21120) +- Make RES_ROTATE start with a random name server (swbz#19570) +- Fix tgmath.h totalorder, totalordermag return type (swbz#21687) +- Miscellaneous sys/ucontext.h namespace fixes (swbz#21457) +- Rename struct ucontext tag (swbz#21457) +- Call exit system call directly in clone (swbz#21512) +- powerpc64le: Enable float128 +- getaddrinfo: Merge IPv6 addresses and IPv4 addresses (swbz#21295) +- Avoid .symver on common symbols (swbz#21666) +- inet_pton: Reject IPv6 addresses with many leading zeros (swbz#16637) + +* Fri Jun 23 2017 Florian Weimer - 2.25.90-15 +- Auto-sync with upstream master, + commit 3ec7c02cc3e922b9364dc8cfd1d4546671b91003, fixing: +- memcmp-avx2-movbe.S incorrect results for lengths 2/3 (#1464403) + +* Fri Jun 23 2017 Florian Weimer - 2.25.90-14 +- Auto-sync with upstream master, + commit 12f50337ae80672c393c2317d471d097ad92c492, changing: +- localedata: fur_IT: Fix spelling of Wednesday (Miercus) +- Update to Unicode 10.0.0 +- inet: __inet6_scopeid_pton should accept node-local addresses (swbz#21657) + +* Fri Jun 23 2017 Florian Weimer - 2.25.90-13 +- Reenable valgrind on aarch64 + +* Thu Jun 22 2017 Florian Weimer - 2.25.90-12 +- Log auxiliary vector during build + +* Thu Jun 22 2017 Florian Weimer - 2.25.90-11 +- Auto-sync with upstream master, + commit 0a47d031e44f15236bcef8aeba80e737bd013c6f. + +* Thu Jun 22 2017 Florian Weimer - 2.25.90-10 +- Disable valgrind on aarch64 + +* Wed Jun 21 2017 Florian Weimer - 2.25.90-9 +- Drop historic aarch64 TLS patches +- Drop workaround for GCC PR69537 +- Auto-sync with upstream master, + commit 9649350d2ee47fae00794d57e2526aa5d67d900e. + +* Wed Jun 21 2017 Florian Weimer - 2.25.90-8 +- Adjust build requirements for gcc, binutils, kernel-headers. +- Auto-sync with upstream master, + commit 43e0ac24c836eed627a75ca932eb7e64698407c6, changing: +- Remove + +* Mon Jun 19 2017 Florian Weimer - 2.25.90-7 +- Drop glibc-Disable-buf-NULL-in-login-tst-ptsname.c, applied upstream. +- Auto-sync with upstream master, + commit 37e9dc814636915afb88d0779e5e897e90e7b8c0, fixing: +- CVE-2017-1000366: Avoid large allocas in the dynamic linker (#1462820) +- wait3 namespace (swbz#21625) +- S390: Sync ptrace.h with kernel (swbz#21539) +- Another x86 sys/ucontext.h namespace issue (swbz#21457) +- siginterrupt namespace (swbz#21597) +- Signal stack namespace (swbz#21584) +- Define struct rusage in sys/wait.h when required (swbz#21575) +- S390: Fix build with gcc configured with --enable-default-pie (swbz#21537) +- Update timezone code from tzcode 2017b +- nptl: Invert the mmap/mprotect logic on allocated stacks (swbz#18988) +- PowerPC64 ELFv2 PPC64_OPT_LOCALENTRY +- Make copy of from GCC (swbz#21573) +- localedata: ce_RU: update weekdays from CLDR (swbz#21207) +- localedata: Remove trailing spaces (swbz#20275) +- XPG4 bsd_signal namespace (swbz#21552) +- Correct collation rules for Malayalam (swbz#19922, swbz#19919) +- waitid namespace (swbz#21561) +- Condition signal.h inclusion in sys/wait.h (swbz#21560) +- ld.so: Consolidate 2 strtouls into _dl_strtoul (swbz#21528) +- tst-timezone race (swbz#14096) +- Define SIG_HOLD for XPG4 (swbz#21538) +- struct sigaltstack namespace (swbz#21517) +- sigevent namespace (swbz#21543) +- Add shim header for bits/syscall.h (swbz#21514) +- namespace issues in sys/ucontext.h (swbz#21457) +- posix: Implement preadv2 and pwritev2 +- Various float128 and tunables improvements + +* Tue Jun 06 2017 Stephen Gallagher - 2.25.90-6 +- Reduce libcrypt-nss dependency to 'Suggests:' + +* Wed May 31 2017 Arjun Shankar - 2.25.90-5 +- Auto-sync with upstream master, + commit cfa9bb61cd09c40def96f042a3123ec0093c4ad0. +- Fix sys/ucontext.h namespace from signal.h etc. inclusion (swbz#21457) +- Fix sigstack namespace (swbz#21511) + +* Wed May 31 2017 Arjun Shankar - 2.25.90-4 +- Disable the NULL buffer test in login/tst-ptsname.c. It leads to a build + failure during 'make check'. A permanent solution is being discussed + upstream. + +* Tue May 23 2017 Arjun Shankar - 2.25.90-3 +- Auto-sync with upstream master, + commit 231a59ce2c5719d2d77752c21092960e28837b4a. +- Add el_GR@euro support (swbz#20686) +- Set dl_platform and dl_hwcap from CPU features (swbz#21391) +- Use __glibc_reserved convention in mcontext, sigcontext (swbz#21457) +- Fix signal.h bsd_signal namespace (swbz#21445) +- Fix network headers stdint.h namespace (swbz#21455) +- resolv: Use RES_DFLRETRY consistently (swbz#21474) +- Condition some sys/ucontext.h contents on __USE_MISC (swbz#21457) +- Consolidate Linux read syscall (swbz#21428) +- fork: Remove bogus parent PID assertions (swbz#21386) +- Reduce value of LD_HWCAP_MASK for tst-env-setuid test case (swbz#21502) +- libio: Avoid dup already opened file descriptor (swbz#21393) + +* Mon May 01 2017 Carlos O'Donell - 2.25.90-2 +- Auto-sync with upstream master, + commit 25e39b4229fb365a605dc4c8f5d6426a77bc08a6. +- logbl for POWER7 return incorrect results (swbz#21280) +- sys/socket.h uio.h namespace (swbz#21426) +- Support POSIX_SPAWN_SETSID (swbz#21340) +- Document how to provide a malloc replacement (swbz#20424) +- Verify that all internal sockets opened with SOCK_CLOEXEC (swbz#15722) +- Use AVX2 memcpy/memset on Skylake server (swbz#21396) +- unwind-dw2-fde deadlock when using AddressSanitizer (swbz#21357) +- resolv: Reduce advertised EDNS0 buffer size to guard against + fragmentation attacks (swbz#21361) +- mmap64 silently truncates large offset values (swbz#21270) +- _dl_map_segments does not test for __mprotect failures consistently + (swbz#20831) + +* Thu Mar 02 2017 Florian Weimer - 2.25.90-1 +- Switch back to upstream master branch. +- Drop Unicode 9 patch, merged upstream. +- Auto-sync with upstream master, + commit a10e9c4e53fc652b79abf838f7f837589d2c84db, fixing: +- Build all DSOs with BIND_NOW (#1406731) + +* Wed Mar 1 2017 Jakub Hrozek - 2.25-3 +- NSS: Prefer sss service for passwd, group databases (#1427646) + +* Tue Feb 28 2017 Florian Weimer - 2.25-2 +- Auto-sync with upstream release/2.25/master, + commit 93cf93e06ce123439e41d3d62790601c313134cb, fixing: +- sunrpc: Improvements for UDP client timeout handling (#1346406) +- sunrpc: Avoid use-after-free read access in clntudp_call (swbz#21115) +- Fix getting tunable values on big-endian (swbz#21109) + +* Wed Feb 08 2017 Carlos O'Donell - 2.25-1 +- Update to final released glibc 2.25. + +* Wed Feb 08 2017 Carlos O'Donell - 2.24.90-31 +- Fix builds with GCC 7.0. + +* Wed Feb 01 2017 Carlos O'Donell - 2.24.90-30 +- Optimize IBM z System builds for zEC12. + +* Wed Jan 25 2017 Florian Weimer - 2.24.90-29 +- Use vpath in crypt-glibc/Makefile to obtain the test input file. +- Auto-sync with upstream master, + commit 5653ab12b4ae15b32d41de7c56b2a4626cd0437a, fixing: +- ARM fpu_control.h for assemblers requiring VFP insn names (swbz#21047) +- FAIL in test string/tst-xbzero-opt (swbz#21006) +- Make soft-float powerpc swapcontext restore the signal mask (swbz#21045) +- Clear list of acquired robust mutexes in the child after fork (swbz#19402) + +* Thu Jan 12 2017 Carlos O'Donell - 2.24.90-28 +- Auto-sync with upstream master, + commit 468e525c81a4af10f2e613289b6ff7c950773a9e: +- Drop rwlock related patches applied upstream. +- Fix i686 memchr for large input sizes (swbz#21014) +- Fix x86 strncat for large input sizes (swbz#19390) +- powerpc: Fix write-after-destroy in lock elision (swbz#20822) +- New pthread rwlock that is more scalable. +- Fix testsuite build for GCC 7 -Wformat-truncation. + +* Mon Jan 02 2017 Florian Weimer - 2.24.90-27 +- Auto-sync with upstream master, + commit 73dfd088936b9237599e4ab737c7ae2ea7d710e1: +- Enable tunables. +- Drop condvar-related patches applied upstream. +- Update DNS RR type definitions (swbz#20593) +- CVE-2015-5180: resolv: Fix crash with internal QTYPE (#1249603) +- sunrpc: Always obtain AF_INET addresses from NSS (swbz#20964) + + +* Mon Dec 26 2016 Florian Weimer - 2.24.90-26 +- Auto-sync with upstream master, + commit cecbc7967f0bcac718b6f8f8942b58403c0e917c +- Enable stack protector for most of glibc (#1406731) + +* Fri Dec 23 2016 Carlos O'Donell - 2.24.90-25 +- Auto-sync with upstream master, + commit 81e0662e5f2c342ffa413826b7b100d56677b613, fixing: +- Shared object unload assert when calling dlclose (#1398370, swbz#11941) +- Fix nss_nisplus build with mainline GCC (swbz#20978) +- Add Intel TSX blacklist for silicon with known errata. +- Add fmax, fmin, fmaxf, fminf microbenchmarks. +- Robust mutexes: Fix lost wake-up (swbz#20973). +- Add fmaxmag, fminmag, roundeven, roundevenf, roundevenl functions. + +* Sun Dec 18 2016 Florian Weimer - 2.24.90-24 +- Auto-sync with upstream master, + commit e077349ce589466eecd47213db4fae6b80ec18c4, fixing: +- Warn about assignment in assertions (#1105335) +- powerpc64/power7 memchr for large input sizes (swbz#20971) +- fmax, fmin sNaN handling (swbz#20947) + +* Mon Dec 12 2016 Florian Weimer - 2.24.90-23 +- Auto-sync with upstream master, + commit 92dcaa3e2f7bf0f7f1c04cd2fb6a317df1a4e225, fixing: +- Add getrandom, getentropy (#1172273) +- Add additional compiler barriers to backtrace tests (swbz#20956) + +* Fri Dec 09 2016 Florian Weimer - 2.24.90-22 +- Auto-sync with upstream master, + commit 0abbe7cd700951082b314182a0958d65238297ef, changing: +- IN6_IS_ADDR_ does not require enabling non-standard extensions (#1138893) +- Install libm.a as linker script (swbz#20539) +- Fix writes past the allocated array bounds in execvpe (swbz#20847) +- Fix hypot sNaN handling (swbz#20940) +- Fix x86_64/x86 powl handling of sNaN arguments (swbz#20916) +- Fix sysdeps/ieee754 pow handling of sNaN arguments (swbz#20916) +- Fix pow (qNaN, 0) result with -lieee (swbz#20919) +- Fix --enable-nss-crypt failure of tst-linkall-static (swbz#20918) + +* Fri Dec 02 2016 Florian Weimer - 2.24.90-21 +- Auto-sync with upstream master, + commit 01b23a30b42a90b1ebd882a0d81110a1542e504a, fixing: +- aarch64: Incorrect dynamic TLS resolution (#1400347) + +* Wed Nov 30 2016 Florian Weimer - 2.24.90-20 +- Auto-sync with upstream master, + commit 9e78f6f6e7134a5f299cc8de77370218f8019237, fixing: +- stdio buffering with certain network file systems (#1400144) +- libpthread initialization breaks ld.so exceptions (#1393909) +- x86_64: Use of PLT and GOT in static archives (swbz#20750) +- localedata, iconvdata: 0x80->Euro sign mapping for GBK (swbz#20864) +- math: x86_64 -mfpmath=387 float_t, double_t (swbz#20787) + +* Wed Nov 23 2016 Florian Weimer - 2.24.90-19 +- Auto-sync with upstream master, + commit 7a5e3d9d633c828d84a9535f26b202a6179978e7: +- Fix default float_t definition (swbz#20855) +- Fix writes past the allocated array bounds in execvpe (swbz#20847) + +* Tue Nov 22 2016 Florian Weimer - 2.24.90-18 +- Auto-sync with upstream master, + commit 5ee1a4443a3eb0868cef1fe506ae6fb6af33d4ad. + +* Wed Nov 16 2016 Carlos O'Donell - 2.24.90-17 +* Add new scalable implementation of POSIX read-write locks. + +* Wed Nov 16 2016 Florian Weimer - 2.24.90-16 +- Do not try to link libcrypt statically during tests + +* Wed Nov 16 2016 Florian Weimer - 2.24.90-15 +- Auto-sync with upstream master, + commit 530862a63e0929128dc98fbbd463b120934434fb, fixing: +- Fix rpcgen buffer overrun (swbz#20790) +- Fix ppc64 build failure to swbz#20729 fix attempt + +* Wed Nov 2 2016 Florian Weimer - 2.24.90-14 +- Drop glibc-swbz20019.patch, applied upstream. +- dlerror returns NULL after dlsym (RTLD_NEXT) lookup failure (#1333945) + (fixed by dropping the revert) +- Auto-sync with upstream master, + commit 9032070deaa03431921315f973c548c2c403fecc, fixing: +- Correct clog10 documentation (swbz#19673) +- Fix building with -Os (swbz#20729) +- Properly initialize glob structure with GLOB_BRACE|GLOB_DOOFFS (swbz#20707) +- powerpc: Fix TOC stub on powerpc64 clone (swbz#20728) +- math: Make strtod raise "inexact" exceptions (swbz#19380) +- malloc: Remove malloc_get_state, malloc_set_state (swbz#19473) + +* Sat Oct 22 2016 Florian Weimer - 2.24.90-13 +- Auto-sync with upstream master, + commit e37208ce86916af9510ffb9ce7b3c187986f07de, changing: +- Restore compatbility with extern "C" wrappers + +* Fri Oct 21 2016 Florian Weimer - 2.24.90-12 +- Auto-sync with upstream master, + commit b3918c44db615637b26d919ce599cd86592316b3, fixing: +- math: Turn iszero into a function template (#1387415) +- ARM: Use VSQRT instruction (swbz#20660) +- math: Stop powerpc copysignl raising "invalid" for sNaN (swbz#20718) +- x86: Fix FMA and AVX2 detection (swbz#20689) +- x86: Avoid assertion failure on older Intel CPus (swbz#20647) + +* Mon Oct 17 2016 Carlos O'Donell - 2.24.90-11 +- Add prototype support for detecting invalid IFUNC calls (swbz#20019). +- New POSIX thread condition variable implementation (swbz#13165). + +* Fri Oct 07 2016 Florian Weimer - 2.24.90-10 +- Auto-sync with upstream master, + commit 5140d036f9c16585448b5908c3a219bd96842161, fixing: +- resolv: Remove RES_USEBSTRING and its implementation (swbz#20629) +- Refactor ifunc resolvers due to false debuginfo (swbz#20478) + +* Tue Oct 04 2016 Florian Weimer - 2.24.90-9 +- Auto-sync with upstream master, + commit ff88ee7edfaa439e23c42fccaf3a36cd5f041894, fixing: +- LONG_WIDTH is incorrectly set to the 64 on 32-bit platforms (#1381582) +- libio: Multiple fixes for open_{w}memstream (swbz#18241, swbz#20181) +- Simplify and test _dl_addr_inside_object (swbz#20292) + +* Thu Sep 22 2016 Florian Weimer - 2.24.90-8 +- Add support for MIPS (#1377795) +- Drop glibc-rh1315476-1.patch (sln pre-processor cleanup), it was + applied upstream. +- Auto-sync with upstream master, + commit 17af5da98cd2c9ec958421ae2108f877e0945451, fixing the following bugs: +- Fix non-LE TLS in static programs (swbz#19826) +- resolv: Remove unsupported hook functions from the API (swbz#20016) +- Remove RR type classification macros (swbz#20592) +- Remove obsolete DNSSEC support (swbz#20591) +- manual: Clarify the documentation of strverscmp (swbz#20524) + +* Tue Sep 20 2016 Carlos O'Donell - 2.24.90-7 +- Auto-sync with upstream master. + +* Thu Sep 01 2016 Florian Weimer - 2.24.90-6 +- Auto-sync with upstream master, + commit 4d728087ef8cc826b05bd21d0c74d4eca9b1a27d, fixing: +- Base on Linux headers (#1360480) +- Simplify static malloc interposition (swbz#20432) + +* Fri Aug 26 2016 Florian Weimer - 2.24.90-5 +- Auto-sync with upstream master, + commit 7e625f7e85b4e88f10dbde35a0641742af581806, fixing: +- lt_LT locale: use hyphens in d_fmt (swbz#20497) +- nptl test time reductions (swbz#19946) + +* Sun Aug 21 2016 Florian Weimer - 2.24.90-4 +- Auto-sync with upstream master, + commit 66abf9bfbe24ac1e7207d26ccad725ed938dc52c, fixing: +- argp: Do not override GCC keywords with macros (#1366830) + +* Wed Aug 17 2016 Florian Weimer - 2.24.90-3 +- Auto-sync with upstream master, + commit d9067fca40b8aac156d73cfa44d6875813555a6c, with these changes: +- Avoid duplicating object files already in libc.a (#1352625) +- CVE-2016-6323: Backtraces can hang on ARM EABI (32-bit) (swbz#20435) +- et_EE: locale has wrong {p,n}_cs_precedes value (swbz#20459 + +* Thu Aug 11 2016 Florian Weimer - 2.24.90-2 +- Auto-sync with upstream master, + commit f79211792127f38d5954419bb3784c8eb7f5e4e5 + +* Mon Aug 08 2016 Carlos O'Donell - 2.24.90-1 +- Set version to 2.24.90 to match upstream development. + +* Mon Aug 08 2016 Carlos O'Donell - 2.23.90-31 +- Auto-sync with upstream master. + +* Thu Jul 21 2016 Florian Weimer - 2.23.90-30 +- Drop sendmsg/recvmsg compatibility patch (#1344830) +- glibc-devel depends on libgcc%%{_isa} (#1289356) +- Drop Requires(pre) on libgcc +- Introduce libcrypt and libcrypt-nss (#1324623) +- Do not try to install mtrace when bootstrapping + +* Wed Jul 20 2016 Florian Weimer - 2.23.90-29 +- Move NSS modules to subpackages (#1338889) + +* Wed Jul 13 2016 Florian Weimer - 2.23.90-28 +- Auto-sync with upstream master, commit + f531f93056b34800383c5154280e7ba5112563c7. +- Add de_LI.UTF-8 locale. +- Make ldconfig and sln the same binary. (#1315476) + +* Fri Jul 08 2016 Mike FABIAN - 2.23.90-27 +- Unicode 9.0.0 updates (ctype, charmap, transliteration) (#1351108) + +* Tue Jul 05 2016 Florian Weimer - 2.23.90-26 +- Auto-sync with upstream master, up to commit + 30e4cc5413f72c2c728a544389da0c48500d9904, fixing these bug: +- strcasecmp failure on ppc64le (#nscd breaks initgroups with nis (initgroups are empty) (#1294574) + +* Fri Jun 24 2016 Carlos O'Donell - 2.23.90-25 +- Properly handle more invalid --install-langs arguments (#1349906). + +* Tue Jun 21 2016 Florian Weimer - 2.23.90-24 +- Auto-sync with upstream master, commit + a3b473373ee43a292f5ec68a7fda6b9cfb26a9b0, fixing these bugs: +- Unnecessary mmap fallback in malloc (#1348620) +- pwritev system call passes incorrect offset to kernel (#1346070) + +* Sat Jun 18 2016 Carlos O'Donell - 2.23.90-23 +- Use scriptlet expansion in all-langpacks posttrans script to expand + _install_langes macro. + +* Mon Jun 13 2016 Florian Weimer - 2.23.90-22 +- Remove glibc-fedora-uname-getrlimit.patch. This patch was + introduced to fix bug rhbz#579086 (Preloading a replacement uname + is causing environment to be cleaned if libpthread is loaded). + UTS namespaces should now offer a cleaner way yo do this. +- Drop sendmmsg/recvmmsg compat symbols on 32-bit architectures (#1344830) +* Sat Jun 11 2016 Florian Weimer - 2.23.90-21 +- First phase of sendmsg/recvmsg/sendmmsg/recvmmsg ABI revert: + GLIBC_2.24 compatibility symbols (#1344830) +- Auto-sync with upstream master + (commit 31d0a4fa646db8b8c97ce24e0ec0a7b73de4fca1), + fixing the following bugs: +- Add eo locale +- Crash in the nss_db NSS service module during iteration (#1344480) + +* Thu Jun 09 2016 Florian Weimer - 2.23.90-20 +- Auto-sync with upstream master, fixing this bug: +- Emacs crashes on startup (#1342976) + +* Wed Jun 01 2016 Florian Weimer - 2.23.90-19 +- Auto-sync with upstream master. +- Adjust glibc-rh1315108.patch accordingly. +- Fix fork redirection in libpthread (#1326903) +- CVE-2016-4429: stack overflow in Sun RPC clntudp_call (#1337140) +- Do not disable assertions in release builds (#1338887) + +* Wed May 11 2016 Carlos O'Donell - 2.23.90-18 +- Move support for building GCC 2.96 into compat-gcc-296. + +* Wed May 11 2016 Florian Weimer - 2.23.90-17 +- Temporily revert dlsym (RTLD_NEXT)/dlerror change, to unbreak + ASAN until it is fixed (#1335011) + +* Mon May 9 2016 Florian Weimer - 2.23.90-16 +- Drop the “fix” for fork/vfork NULL symbols in libpthread. It does + not work because ld.so apparently supports some variant of direct + binding. + +* Mon May 09 2016 Florian Weimer - 2.23.90-15 +- Auto-sync with upstream master. +- Drop glibc-nsswitch-Add-group-merging-support.patch, applied upstream. +- Drop glibc-rh1252570.patch, alternative fixes applied upstream. +- Adjust glibc-rh1315108.patch to minor upstream change. +- Update SUPPORTED file. +- Experimental fix for NULL fork/vfork symbols in libpthread (#1326903) + +* Tue May 03 2016 Carlos O'Donell - 2.23.90-14 +- Require libselinux for nscd in non-bootstrap configuration. + +* Fri Apr 29 2016 Carlos O'Donell - 2.23.90-13 +- Auto-sync with upstream master. + +* Thu Apr 28 2016 Carlos O'Donell - 2.23.90-12 +- Move spec file system information logging to the build stage. + +* Thu Apr 14 2016 Florian Weimer - 2.23.90-11 +- Auto-sync with upstream master. +- Unbreak pread/pread64 on armhfp (#1327277) + +* Thu Apr 14 2016 Florian Weimer - 2.23.90-10 +- Auto-sync with upstream master. + +* Thu Apr 14 2016 Florian Weimer - 2.23.90-9 +- Auto-sync with upstream master. Removes type union wait. +- Update SUPPORTED locales file. + +* Fri Apr 08 2016 Florian Weimer - 2.23.90-8 +- Auto-sync with upstream master. + +* Tue Mar 29 2016 Florian Weimer - 2.23.90-7 +- Auto-sync with upstream master. +- Adjust glibc-rh1252570.patch to partial upstream fix. +- Drop glibc-fix-an_ES.patch, now included upstream. + +* Wed Mar 16 2016 Carlos O'Donell - 2.23.90-6 +- Use 'an' as language abbreviation for an_ES. + +* Mon Mar 07 2016 Carlos O'Donell - 2.23.90-5 +- Auto-sync with upstream master. + +* Sun Mar 6 2016 Florian Weimer - 2.23.90-4 +- Remove extend_alloca (#1315108) + +* Mon Feb 29 2016 Carlos O'Donell - 2.23.90-3 +- Enhance support for upgrading from a non-language-pack system. + +* Fri Feb 26 2016 Mike FABIAN - 2.23.90-2 +- Create new language packages for all supported languages. + Locales, translations, and locale sources are split into + distinct sub-packages. A meta-package is created for users + to install all languages. Transparent installation support + is provided via dnf langpacks. + +* Fri Feb 26 2016 Carlos O'Donell - 2.23.90-1 +- Upstream development version is now 2.23.90. + +* Thu Feb 25 2016 Carlos O'Donell - 2.22.90-38 +- Auto-sync with upstream master. + +* Fri Feb 19 2016 Florian Weimer - 2.22.90-37 +- Remove stray newline from Serbian locales (#1114591). + +* Tue Feb 16 2016 CArlos O'Donell - 2.22.90-36 +- Fix CVE-2015-7547: getaddrinfo() stack-based buffer overflow (#1308943). + +* Mon Feb 15 2016 Florian Weimer - 2.22.90-35 +- Revert may_alias attribute for struct sockaddr (#1306511). +- Revert upstream commit 2212c1420c92a33b0e0bd9a34938c9814a56c0f7 (#1252570). + +* Sat Feb 13 2016 Florian Weimer - 2.22.90-34 +- Auto-sync with upstream master. +- Support aliasing with struct sockaddr pointers (#1306511). + +* Tue Feb 09 2016 Carlos O'Donell - 2.22.90-33 +- Use --with-cpu=power8 for ppc64le default runtime (#1227361). + +* Tue Feb 02 2016 Florian Weimer - 2.22.90-32 +- Auto-sync with upstream master. +- Add glibc-isinf-cxx11.patch to improve C++11 compatibility. + +* Thu Jan 28 2016 Florian Weimer - 2.22.90-31 +- Add workaround for GCC PR69537. + +* Thu Jan 28 2016 Florian Weimer - 2.22.90-30 +- Auto-sync with upstream master. + +* Wed Jan 13 2016 Carlos O'Donell - 2.22.90-29 +- New pthread_barrier algorithm with improved standards compliance. + +* Wed Jan 13 2016 Carlos O'Donell - 2.22.90-28 +- Add group merging support for distributed management (#1146822). + +* Tue Jan 12 2016 Carlos O'Donell - 2.22.90-27 +- Remove 32-bit POWER support. +- Add 64-bit POWER7 BE and 64-bit POWER8 BE optimized libraries. + +* Mon Dec 21 2015 Florian Weimer - 2.22.90-26 +- Auto-sync with upstream master. + +* Wed Dec 16 2015 Florian Weimer - 2.22.90-25 +- Auto-sync with upstream master. +- Includes fix for malloc assertion failure in get_free_list. (#1281714) +- Drop Unicode 8.0 patches (now merged upstream). + +* Sat Dec 5 2015 Florian Weimer - 2.22.90-24 +- Put libmvec_nonshared.a into the -devel package. (#1288738) + +* Sat Dec 05 2015 Florian Weimer - 2.22.90-23 +- Auto-sync with upstream master. + +* Thu Nov 26 2015 Carlos O'Donell - 2.22.90-22 +- The generic hidden directive support is already used for + preinit/init/fini-array symbols so we drop the Fedora-specific + patch that does the same thing. + Reported by Dmitry V. Levin + +* Thu Nov 26 2015 DJ Delorie - 2.22.90-22 +- Require glibc-static for C++ tests. +- Require gcc-c++, libstdc++-static, and glibc-static only when needed. +- Fix --without docs to not leave info files. + +* Fri Nov 20 2015 Florian Weimer - 2.22.90-21 +- Auto-sync with upstream master. + +* Wed Nov 18 2015 Florian Weimer - 2.22.90-20 +- Auto-sync with upstream master. + +* Wed Nov 18 2015 Florian Weimer - 2.22.90-19 +- Disable -Werror on s390 (#1283184). + +* Mon Nov 16 2015 Florian Weimer - 2.22.90-18 +- Auto-sync with upstream master. + +* Mon Nov 16 2015 Florian Weimer - 2.22.90-17 +- Revert temporary armhfp build fix. + +* Mon Nov 9 2015 Florian Weimer - 2.22.90-16 +- Apply temporary fix for armhfp build issue. + +* Mon Nov 09 2015 Florian Weimer - 2.22.90-15 +- Auto-sync with upstream master. + +* Tue Nov 3 2015 Florian Weimer - 2.22.90-14 +- Log uname, cpuinfo, meminfo during build (#1276636) + +* Fri Oct 30 2015 Florian Weimer - 2.22.90-13 +- Auto-sync with upstream master. + +* Fri Oct 30 2015 Florian Weimer - 2.22.90-12 +- Revert to upstream implementation of condition variables (#1229659) + +* Wed Oct 28 2015 Florian Weimer - 2.22.90-11 +- Disable valgrind test on ppc64p7, too. + +* Mon Oct 26 2015 Carlos O'Donell - 2.22.90-10 +- Disable valgrind test for ppc64. + +* Wed Oct 21 2015 Carlos O'Donell - 2.22.90-9 +- Sync with upstream master. +- Update new condvar implementation. + +* Fri Oct 9 2015 Carlos O'Donell - 2.22.90-8 +- Remove libbsd.a (#1193168). + +* Wed Sep 16 2015 Mike FABIAN - 2.22.90-7 +- Add the C.UTF-8 locale (#902094). + +* Wed Sep 16 2015 Carlos O'Donell - 2.22.90-6 +- Fix GCC 5 and -Werror related build failures. +- Fix --install-langs bug which causes SIGABRT (#1262040). + +* Fri Aug 28 2015 Carlos O'Donell - 2.22.90-5 +- Auto-sync with upstream master. + +* Thu Aug 27 2015 Carlos O'Donell - 2.22.90-4 +- Build require gcc-c++ for the C++ tests. +- Support --without testsuite option to disable testing after build. +- Support --without benchtests option to disable microbenchmarks. +- Update --with bootstrap to disable benchtests, valgrind, documentation, + selinux, and nss-crypt during bootstrap. +- Support --without werror to disable building with -Werror. +- Support --without docs to disable build requirement on texinfo. +- Support --without valgrind to disable testing with valgrind. +- Remove c_stubs add-on and enable fuller support for static binaries. +- Remove librtkaio support (#1227855). + +* Sun Aug 16 2015 Siddhesh Poyarekar - 2.22.90-3 +- Auto-sync with upstream master. + +* Fri Aug 14 2015 Siddhesh Poyarekar - 2.22.90-2 +- Remove initgroups from the default nsswitch.conf (#751450). + +* Fri Aug 14 2015 Siddhesh Poyarekar - 2.22.90-1 +- Sync with upstream master. + +* Tue Jul 28 2015 Siddhesh Poyarekar - 2.21.90-20 +- Sync with upstream master. + +* Thu Jul 23 2015 Mike FABIAN - 2.21.90-19 +- some more additions to the translit_neutral file by Marko Myllynen + +* Tue Jul 14 2015 Mike FABIAN - 2.21.90-18 +- Unicode 8.0.0 updates, including the transliteration files (#1238412). + +* Sun Jun 21 2015 Carlos O'Donell - 2.21.90-17 +- Remove all linuxthreads handling from glibc spec file. + +* Wed Jun 17 2015 Carlos O'Donell - 2.21.90-16 +- Move split out architecture-dependent header files into devel package + and keep generic variant in headers package, thus keeping headers package + content and file list identical across multilib rpms. + +* Wed Jun 17 2015 Fedora Release Engineering - 2.21.90-15.1 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_23_Mass_Rebuild + +* Wed Jun 3 2015 Carlos O'Donell - 2.21.90-15 +- Remove patch to increase DTV surplus which is no longer needed after + upstream commit f8aeae347377f3dfa8cbadde057adf1827fb1d44. + +* Sat May 30 2015 Siddhesh Poyarekar - 2.21.90-14 +- Fix build failure on aarch64 (#1226459). + +* Mon May 18 2015 Siddhesh Poyarekar - 2.21.90-13 +- Sync with upstream master. +- Install new condvar implementation. + +* Fri May 08 2015 Siddhesh Poyarekar - 2.21.90-12 +- Add benchmark comparison scripts. + +* Thu May 07 2015 Siddhesh Poyarekar - 2.21.90-11 +- Auto-sync with upstream master. +- Revert arena threshold fix to work around #1209451. + +* Tue Apr 07 2015 Siddhesh Poyarekar - 2.21.90-10 +- Revert last auto-sync (#1209451). + +* Mon Apr 06 2015 Siddhesh Poyarekar - 2.21.90-9 +- Auto-sync with upstream master. + +* Tue Mar 24 2015 Siddhesh Poyarekar - 2.21.90-8 +- Auto-sync with upstream master. + +* Tue Mar 17 2015 Carlos O'Donell - 2.21.90-7 +- Use rpm.expand in scripts to reduce set of required RPM features. + +* Thu Mar 12 2015 Siddhesh Poyarekar - 2.21.90-6 +- Auto-sync with upstream master. + +* Tue Mar 3 2015 Mike Fabian - 2.21.90-5 +- Support installing only those locales specified by the RPM macro + %%_install_langs (#156477). + +* Mon Feb 23 2015 Siddhesh Poyarekar - 2.21.90-4 +- Auto-sync with upstream master. + +* Sat Feb 21 2015 Till Maas - 2.21.90-3.1 +- Rebuilt for Fedora 23 Change + https://fedoraproject.org/wiki/Changes/Harden_all_packages_with_position-independent_code + +* Thu Feb 12 2015 Carlos O'Donell - 2.21.90-3 +- Fix missing clock_* IFUNCs in librtkaio. + +* Thu Feb 12 2015 Carlos O'Donell - 2.21.90-2 +- Auto-sync with upstream master. + +* Wed Feb 11 2015 Carlos O'Donell - 2.21.90-1 +- Add back x86 vDSO support. +- Fix rtkaio build to reference clock_* functions from libc. + +* Wed Jan 21 2015 Siddhesh Poyarekar - 2.20.90-20 +- Sync with upstream master. +- Disable werror on s390x. +- Revert x86 vDSO support since it breaks i686 rtkaio build. + +* Tue Jan 20 2015 Peter Robinson 2.20.90-19 +- Drop large ancient ChangeLogs (rhbz #1169546) + +* Mon Jan 12 2015 Siddhesh Poyarekar - 2.20.90-18 +- Pass address of main_arena.mutex to mutex_lock/unlock. + +* Thu Jan 08 2015 Siddhesh Poyarekar - 2.20.90-17 +- Define a __tls_get_addr macro to avoid a conflicting declaration. + +* Wed Jan 07 2015 Siddhesh Poyarekar - 2.20.90-16 +- Disable -Werror for s390 as well. + +* Wed Jan 07 2015 Siddhesh Poyarekar - 2.20.90-14 +- Sync with upstream master. +- Disable -Werror on powerpc and armv7hl. +- Temporarily disable valgrind test on ppc64. + +* Sun Dec 28 2014 Dan Horák +- valgrind available only on selected arches (missing on s390) + +* Wed Dec 10 2014 Kyle McMartin +- aarch64: Drop strchrnul.S revert, apply fix from Richard Earnshaw. + +* Fri Dec 05 2014 Carlos O'Donell - 2.20.90-13 +- Fix permission of debuginfo source files to allow multiarch + debuginfo packages to be installed and upgraded. + +* Fri Dec 05 2014 Siddhesh Poyarekar - 2.20.90-12 +- Remove LIB_LANG since we don't install locales in /usr/lib/locale anymore. +- Don't own any directories in /usr/share/locale (#1167445). +- Use the %%find_lang macro to get the *.mo files (#1167445). +- Add %%lang tags to language locale files in /usr/share/i18n/locale (#1169044). + +* Wed Dec 03 2014 Kyle McMartin - 2.20.90-11 +- aarch64: revert optimized strchrnul.S implementation (rhbz#1167501) + until it can be debugged. + +* Fri Nov 28 2014 Carlos O'Donell - 2.20.90-10 +- Auto-sync with upstream master. + +* Wed Nov 19 2014 Carlos O'Donell - 2.20.90-9 +- Sync with upstream master. + +* Wed Nov 05 2014 Siddhesh Poyarekar - 2.20.90-8 +- Make getconf return only /usr/bin (#1138835). +- Sync with upstream master. + +* Tue Nov 04 2014 Arjun Shankar - 2.20.90-7 +- Add patch that modifies several tests to use test-skeleton.c. + The patch is accepted but not yet committed upstream. + https://sourceware.org/ml/libc-alpha/2014-10/msg00744.html + +* Tue Sep 30 2014 Siddhesh Poyarekar - 2.20.90-6 +- Sync with upstream master. +- Disable more Intel TSX usage in rwlocks (#1146967). +- Enable lock elision again on s390 and s390x. +- Enable Systemtap SDT probes for all architectures (#985109). + +* Fri Sep 26 2014 Carlos O'Donell - 2.20.90-5 +- Disable lock elision support for Intel hardware until microcode + updates can be done in early bootup (#1146967). +- Fix building test tst-strtod-round for ARM. + +* Tue Sep 23 2014 Siddhesh Poyarekar - 2.20.90-4 +- Sync with upstream master. +- Don't own the common debuginfo directories (#1144853). +- Run valgrind in the %%check section to ensure that it does not break. + +* Tue Sep 16 2014 Siddhesh Poyarekar - 2.20.90-3 +- Sync with upstream master. +- Revert patch for #737223. + +* Mon Sep 08 2014 Siddhesh Poyarekar - 2.20.90-2 +- Build build-locale-archive statically again. + +* Mon Sep 08 2014 Siddhesh Poyarekar - 2.20.90-1 +- Sync with upstream master. + +* Thu Sep 4 2014 Carlos O'Donell - 2.19.90-36 +- Allow up to 32 dlopened modules to use static TLS (#1124987). +- Run glibc tests in %%check section of RPM spec file. +- Do not run tests with `-k` and fail if any test fails to build. + +* Tue Aug 26 2014 Siddhesh Poyarekar - 2.19.90-35 +- Sync with upstream master. +- Use INTERNAL_SYSCALL in TLS_INIT_TP (#1133134). +- Remove gconv loadable module transliteration support (CVE-2014-5119, #1119128). + +* Fri Aug 22 2014 Dennis Gilmore - 2.19.90-34 +- add back sss to nsswitch.conf we have added workarounds in the tools + +* Thu Aug 21 2014 Kevin Fenzi - 2.19.90-33.1 +- Rebuild for rpm bug 1131960 + +* Tue Aug 19 2014 Dennis Gilmore - 2.19.90-33 +- remove sss from default nsswitch.conf it causes issues with live image composing + +* Wed Aug 13 2014 Siddhesh Poyarekar - 2.19.90-32 +- Auto-sync with upstream master. +- Revert to only defining __extern_always_inline for g++-4.3+. +- Fix build failure in compat-gcc-32 (#186410). + +* Mon Jul 28 2014 Siddhesh Poyarekar - 2.19.90-31 +- Auto-sync with upstream master. + +* Wed Jul 23 2014 Siddhesh Poyarekar - 2.19.90-30 +- Undo last master sync to fix up rawhide. + +* Tue Jul 15 2014 Siddhesh Poyarekar - 2.19.90-29 +- Auto-sync with upstream master. + +* Sat Jul 12 2014 Tom Callaway - 2.19.90-28 +- fix license handling + +* Mon Jul 07 2014 Siddhesh Poyarekar - 2.19.90-27 +- Auto-sync with upstream master. + +* Fri Jul 04 2014 Siddhesh Poyarekar - 2.19.90-26 +- Sync with upstream roland/nptl branch. +- Improve testsuite failure outputs in build.log + +* Thu Jul 03 2014 Siddhesh Poyarekar - 2.19.90-25 +- Sync with upstream roland/nptl branch. + +* Wed Jul 02 2014 Siddhesh Poyarekar - 2.19.90-24 +- Sync with upstream master. + +* Tue Jun 24 2014 Siddhesh Poyarekar - 2.19.90-23 +- Sync with upstream master. +- Add fix to unbreak i386 ABI breakage due to a change in scalbn. + +* Fri Jun 20 2014 Kyle McMartin - 2.19.90-22 +- AArch64: Save & restore NZCV (flags) upon entry to _dl_tlsdesc_dynamic + in order to work around GCC reordering compares across the TLS + descriptor sequence (GCC PR61545.) Committing a (temporary) fix here + allows us to avoid rebuilding the world with gcc 4.9.0-11.fc21. + +* Mon Jun 16 2014 Kyle McMartin - 2.19.90-21 +- Auto-sync with upstream master. + +* Thu Jun 12 2014 Siddhesh Poyarekar - 2.19.90-20 +- Auto-sync with upstream master. + +* Sat Jun 07 2014 Fedora Release Engineering - 2.19.90-19.1 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_21_Mass_Rebuild + +* Tue Jun 03 2014 Siddhesh Poyarekar - 2.19.90-19 +- Sync with upstream master. + +* Mon May 26 2014 Siddhesh Poyarekar - 2.19.90-18 +- Sync with upstream master. +- Adjust rtkaio patches to build with upstream master. + +* Wed May 21 2014 Kyle McMartin - 2.19.90-17 +- Backport some upstream-wards patches to fix TLS issues on AArch64. + +* Wed May 21 2014 Kyle McMartin - 2.19.90-16 +- AArch64: Fix handling of nocancel syscall failures (#1098327) + +* Thu May 15 2014 Siddhesh Poyarekar - 2.19.90-15 +- Sync with upstream master. + +* Wed May 14 2014 Carlos O'Donell - 2.19.90-14 +- Add support for displaying all test results in build logs. + +* Wed May 14 2014 Carlos O'Donell - 2.19.90-13 +- Add initial support for ppc64le. + +* Tue Apr 29 2014 Siddhesh Poyarekar - 2.19.90-12 +- Auto-sync with upstream master. +- Remove ports addon. + +* Fri Apr 18 2014 Siddhesh Poyarekar - 2.19.90-11 +- Sync with upstream master. + +* Thu Apr 10 2014 Siddhesh Poyarekar - 2.19.90-10 +- Sync with upstream master. + +* Thu Apr 03 2014 Siddhesh Poyarekar - 2.19.90-9 +- Sync with upstream master. + +* Wed Mar 26 2014 Siddhesh Poyarekar - 2.19.90-8 +- Sync with upstream master. + +* Wed Mar 19 2014 Siddhesh Poyarekar - 2.19.90-7 +- Sync with upstream master. +- Fix offset computation for append+ mode on switching from read (#1078355). + +* Wed Mar 12 2014 Carlos O'Donell - 2.19.90-6 +- Sync with upstream master. +- Use cleaner upstream solution for -ftree-loop-distribute-patterns (#911307). + +* Tue Mar 04 2014 Siddhesh Poyarekar - 2.19.90-5 +- Sync with upstream master. + +* Thu Feb 27 2014 Siddhesh Poyarekar - 2.19.90-4 +- Use nscd service files from glibc sources. +- Make nscd service forking in systemd service file. + +* Tue Feb 25 2014 Siddhesh Poyarekar - 2.19.90-3 +- Sync with upstream master. +- Separate ftell from fseek logic and avoid modifying FILE data (#1069559). + +* Mon Feb 24 2014 Carlos O'Donell - 2.19.90-2 +- Fix build-locale-archive failure to open default template. + +* Tue Feb 18 2014 Siddhesh Poyarekar - 2.19.90-1 +- Sync with upstream master. + +* Tue Feb 04 2014 Siddhesh Poyarekar - 2.18.90-27 +- Sync with upstream master. + +* Wed Jan 29 2014 Siddhesh Poyarekar - 2.18.90-26 +- Modify regular expressions to include powerpcle stubs-*.h (#1058258). + +* Wed Jan 29 2014 Siddhesh Poyarekar - 2.18.90-25 +- Sync with upstream master. + +* Sat Jan 25 2014 Ville Skyttä - 2.18.90-24 +- Own the %%{_prefix}/lib/locale dir. + +* Thu Jan 23 2014 Siddhesh Poyarekar - 2.18.90-23 +- Sync with upstream master. + +* Thu Jan 16 2014 Siddhesh Poyarekar - 2.18.90-22 +- Back out ftell test case (#1052846). + +* Tue Jan 14 2014 Siddhesh Poyarekar - 2.18.90-21 +- Sync with upstream master. +- Fix infinite loop in ftell when writing wide char data (#1052846). + +* Tue Jan 7 2014 Siddhesh Poyarekar - 2.18.90-20 +- Sync with upstream master. +- Enable systemtap probes on Power and S/390. + +* Fri Dec 27 2013 Siddhesh Poyarekar - 2.18.90-19 +- Sync with upstream master. + +* Fri Dec 20 2013 Siddhesh Poyarekar - 2.18.90-18 +- Sync with upstream master. + +* Wed Dec 4 2013 Siddhesh Poyarekar - 2.18.90-17 +- Sync with upstream master. + - Fix shm_open validation (#1037787); + +* Thu Nov 28 2013 Siddhesh Poyarekar - 2.18.90-16 +- Sync with upstream master. + +* Wed Nov 20 2013 Siddhesh Poyarekar - 2.18.90-15 +- Sync with upstream master. + +* Fri Nov 8 2013 Carlos O'Donell - 2.18.90-14 +- Enhance NSCD's SELinux support to use dynamic permission names (#1025126). + +* Mon Oct 28 2013 Siddhesh Poyarekar - 2.18.90-13 +- Sync with upstream master. + - Skip over unimplemented timezone format specifier in strptime (#947722). + +* Mon Oct 21 2013 Siddhesh Poyarekar - 2.18.90-12 +- Allow fill_archive to be called with NULL fname. +- Sync with upstream master. + +* Tue Oct 15 2013 Siddhesh Poyarekar - 2.18.90-11 +- Sync with upstream master. + +* Thu Oct 3 2013 Carlos O'Donell - 2.18.90-10 +- Allow applications to use pthread_atfork without explicitly + requiring libpthread.so. (#1013801) +- Support `--list-archive FILE' in localedef utility. + +* Thu Oct 3 2013 Siddhesh Poyarekar - 2.18.90-9 +- Define swap_endianness_p in build-locale-archive. + +* Wed Oct 2 2013 Carlos O'Donell - 2.18.90-8 +- Allow ldconfig cached objects previously marked as hard or soft + ABI to now become unmarked without raising an error. This works + around a binutils bug that caused objects to become unmarked. + (#1009145) + +* Tue Oct 1 2013 Siddhesh Poyarekar - 2.18.90-7 +- Fix check for PI mutex on non-x86 systems (#1007590). +- Resync with upstream master. + +* Tue Sep 24 2013 Carlos O'Donell - 2.18.90-6 +- Avoid the use of __block which is a reserved keyword for clang++ + (#1009623). + +* Mon Sep 23 2013 Siddhesh Poyarekar - 2.18.90-5 +- Resync with upstream master. + +* Sun Sep 22 2013 Carlos O'Donell - 2.18.90-4 +- Fix CVE-2013-4788: Static applications now support pointer mangling. + Existing static applications must be recompiled (#985625). + +* Wed Sep 18 2013 Patsy Franklin - 2.18.90-3 +- Fix conditional requiring specific binutils for s390/s390x. + +* Mon Sep 16 2013 Siddhesh Poyarekar - 2.18.90-2 +- Resync with upstream master. +- Fix CVE-2013-4332 (#1008299). + +* Thu Sep 5 2013 Siddhesh Poyarekar - 2.18.90-1 +- Resync with upstream master. +- Drop patch for #800224. + +* Thu Aug 29 2013 Carlos O'Donell - 2.18-6 +- Fix Power build (#997531). + +* Wed Aug 28 2013 Carlos O'Donell - 2.18-5 +- Fix indirect function support to avoid calling optimized routines + for the wrong hardware (#985342). + +* Mon Aug 26 2013 Siddhesh Poyarekar - 2.18-4 +- Initialize res_hconf in nscd. (#1000924). + +* Tue Aug 20 2013 Siddhesh Poyarekar - 2.18-3 +- Remove non-ELF support in rtkaio. +- Avoid inlining of cleanup function for kaio_suspend. +- Expand sizes of some types in strcoll (#855399, CVE-2012-4424). +- Fix tst-aiod2 and tst-aiod3 test failures (#970865). + +* Mon Aug 19 2013 Siddhesh Poyarekar - 2.18-2 +- Fix buffer overflow in readdir_r (#995841, CVE-2013-4237). +- Remove releng tarball. + +* Fri Aug 16 2013 Siddhesh Poyarekar - 2.18-1 +- Upstream release 2.18. +- Pull in systemd during build and use the tmpfilesdir macro. + +* Wed Aug 14 2013 Carlos O'Donell - 2.17.90-14 +- Update spec file to use rpm prefix everywhere. + +* Tue Aug 13 2013 Carlos O'Donell - 2.17.90-13 +- Revert `Move to /usr' transition. + +* Tue Aug 13 2013 Carlos O'Donell - 2.17.90-12 +- Complete `Move to /usr' transition. All relevant files are now + installed into `/usr'. + +* Wed Aug 07 2013 Karsten Hopp 2.17.90-11 +- rebuild with the latest rpm to fix missing ld64.so provides on PPC + +* Mon Jul 29 2013 Carlos O'Donell - 2.17.90-10 +- Fix missing libbsd.a in debuginfo packages. + +* Mon Jul 29 2013 Siddhesh Poyarekar - 2.17.90-9 +- Fix strcoll flaws (#855399, CVE-2012-4412, CVE-2012-4424). + +* Mon Jul 29 2013 Siddhesh Poyarekar - 2.17.90-8 +- Resync with upstream master. +- Disable pt_chown (CVE-2013-2207). + +* Thu Jul 25 2013 Carlos O'Donell - 2.17.90-7 +- Correctly name the 240-bit slow path sytemtap probe slowpow_p10 for slowpow. + +* Wed Jul 24 2013 Carlos O'Donell - 2.17.90-6 +- Add build requirement on static libstdc++ library to fix testsuite failures + for static C++ tests. + +* Fri Jul 12 2013 Siddhesh Poyarekar - 2.17.90-5 +- Enable lock elision support (#982363). +- Depend on systemd instead of systemd-units (#983760). + +* Tue Jul 9 2013 Siddhesh Poyarekar - 2.17.90-4 +- Resync with upstream master. + +* Thu Jun 20 2013 Siddhesh Poyarekar - 2.17.90-3 +- Resync with upstream master. + +* Tue Jun 11 2013 Remi Collet - 2.17.90-2 +- rebuild for new GD 2.1.0 + +* Tue Jun 4 2013 Siddhesh Poyarekar - 2.17.90-1 +- Resync with upstream master. + +* Tue May 14 2013 Siddhesh Poyarekar - 2.17-9 +- Avoid crashing in LD_DEBUG when program name is unavailable (#961238). + +* Sun May 5 2013 Patsy Franklin - 2.17-8 +- Fix _nl_find_msg malloc failure case, and callers. (#959034). + +* Tue Apr 23 2013 Patsy Franklin - 2.17-7 +- Test init_fct for NULL, not result->__init_fct, after demangling (#952799). + +* Tue Apr 23 2013 Patsy Franklin - 2.17-6 +- Increase limits on xdr name and record requests (#892777). +- Consistently MANGLE/DEMANGLE init_fct, end_fct and btow_fct (#952799). + +* Thu Mar 28 2013 Siddhesh Poyarekar - 2.17-5 +- Don't add input group during initgroups_dyn in hesiod (#921760). + +* Sun Mar 17 2013 Carlos O'Donell - 2.17-4 +- Fixed i386 glibc builds (#917161). +- Fixed multibyte character processing crash in regexp (#905877, CVE-2013-0242) + +* Wed Feb 27 2013 Carlos O'Donell - 2.17-3 +- Renamed release engineering directory to `releng' (#903754). +- Fix building with gcc 4.8.0 (#911307). + +* Thu Feb 7 2013 Carlos O'Donell - 2.17-2 +- Fix ownership of /usr/lib[64]/audit (#894307). +- Support unmarked ARM objects in ld.so.cache and aux cache (#905184). + +* Tue Jan 1 2013 Jeff Law - 2.17-1 +- Resync with official glibc-2.17 release +* Fri Dec 21 2012 Jeff Law - 2.16.90-40 +- Resync with master + +* Wed Dec 19 2012 Jeff Law - 2.16.90-39 +- Add rtld-debugger-interface.txt as documentation. (#872242) + +* Fri Dec 7 2012 Jeff Law - 2.16.90-38 +- Resync with master +- Drop patch for 731228 that is no longer needed. + +* Thu Dec 6 2012 Jeff Law - 2.16.90-37 +- Resync with master +- Patch for 697421 has been submitted upstream. +- Drop local patch for 691912 that is no longer needed. + +* Mon Dec 3 2012 Jeff Law - 2.16.90-36 +- Resync with master +- Drop local patch for 657588 that is no longer needed. +- Drop local patch for 740682 that is no longer needed. +- Drop local patch for 770439 that is no longer needed. +- Drop local patch for 789209 that is no longer needed. +- Drop local patch for nss-files-overflow that seems + useless. +- Drop localedata-locales-fixes as they were rejected + upstream. +- Drop test-debug-gnuc-hack.patch that seems useless now. +- Repack patchlist. + +* Fri Nov 30 2012 Jeff Law - 2.16.90-35 +- Resync with master (#882137). +- Remove local patch for strict-aliasing warnings that + is no longer needed. +- Remove local patch for 730856 that is no longer needed. +- Repack patchlist. + +* Thu Nov 29 2012 Jeff Law - 2.16.90-34 +- Remove local patch which "temporarily" re-added currences + obsoleted by the Euro. +- Remove hunks from strict-aliasing patch that are no longer + needed. + +* Thu Nov 29 2012 Jeff Law - 2.16.90-33 +- Resync with master. +- Drop local patch for 788989. +- Repack patchlist. + +* Wed Nov 28 2012 Jeff Law - 2.16.90-32 +- Resync with master. +- Drop local patch for 878913. +- Drop local patch for 880666. +- Drop local patch for 767693. +- Repack patchlist. + +* Tue Nov 27 2012 Siddhesh Poyarekar - 2.16.90-31 +- Ensure that hashtable size is greater than 3 (#878913). +- fwrite returns 0 on EOF (#880666). + +* Mon Nov 26 2012 Jeff Law - 2.16.90-30 +- Resync with upstream sources +- Drop local patch for getconf. +- Repack patchlist. + +* Fri Nov 16 2012 Jeff Law - 2.16.90-29 +- Rsync with upstream sources +- Drop local patches for 803286, 791161, 790292, 790298 + +* Wed Nov 7 2012 Jeff Law - 2.16.90-28 +- Resync with upstream sources (#873397) + +* Mon Nov 5 2012 Jeff Law - 2.16.90-27 +- Resync with upstream sources. +- Don't use distinct patches for 770869, 787201 and 688948 + as they all modify stuff under fedora/ +- Repack patchlist + +* Thu Nov 1 2012 Jeff Law - 2.16.90-26 +- Resync with upstream sources (#872336) + +* Mon Oct 22 2012 Jeff Law - 2.16.90-25 +- Rsync with upstream sources +- Drop 864820 patch as now that it's upstream. +- Add sss to /etc/nsswitch.conf (#867473) + +* Thu Oct 11 2012 Jeff Law - 2.16.90-24 +- Rsync with upstream sources +- Drop local 552960-2 patch now that it's upstream. +- Drop local 858274 patch now that the root problem is fixed upstream. +- Repack patchlist. + +* Wed Oct 10 2012 Siddhesh Poyarekar - 2.16.90-23 +- Fix Marathi names for Wednesday, September and October (#rh864820). + +* Fri Oct 5 2012 Jeff Law - 2.16.90-22 +- Resync with upstream sources +- Drop local 552960 patch now that it's upstream +- Drop local stap patch now obsolete +- Drop local s390 patch which avoided problems with old assemblers +- Drop old fortify source patch to deal with old compilers + +* Thu Oct 4 2012 Siddhesh Poyarekar - 2.16.90-21 +- Take mutex in cleanup only if it is not already taken. + +* Tue Oct 2 2012 Jeff Law - 2.16.90-20 +- Resync with upstream sources. +- Repack patchlist. + +* Mon Oct 1 2012 Jeff Law - 2.16.90-19 +- Resync with upstream sources to pick up fma fixes + +* Fri Sep 28 2012 Jeff Law - 2.16.90-18 +- Resync with upstream sources. +- Drop fedora-cdefs-gnuc.patch, it's not needed anymore. +- Drop fedora-gai-rfc1918.patch, it's upstream now. +- Drop fedora-localedata-no_NO.patch, it was supposed to be + temporary -- that was back in 2003. This should have been + sorted out long ago. We'll just have to deal with the + fallout. +- Drop fedora-vfprintf-sw6530.patch, it's upstream now. +- Drop rh769421.patch; Siddhesh has fixed this properly with 552960. + +* Fri Sep 28 2012 Siddhesh Poyarekar - 2.16.90-17 +- Release mutex before going back to wait for PI mutexes (#552960). + +* Tue Sep 25 2012 Jeff Law - 2.16.90-16 +- Resync with upstream sources. + +* Fri Sep 21 2012 Jeff Law - 2.16.90-15 +- Remove most of fedora-nscd patch as we no longer use the + old init files, but systemd instead. +- Remove path-to-vi patch. With the usr-move changes that + patch is totally unnecessary. +- Remove i686-nopl patch. Gas was changed back in 2011 to + avoid nopl. +- Move gai-rfc1918 patch to submitted upstream status + +* Fri Sep 21 2012 Jeff Law - 2.16.90-14 +- Revert patch for 816647, it's blatently broken. + +* Fri Sep 21 2012 Siddhesh Poyarekar - 2.16.90-13 +- Bring back byteswap-16.h (#859268). + +* Thu Sep 20 2012 Jeff Law - 2.16.90-12 +- Revert recent upstream strstr changes (#858274) +- Demangle function pointers before testing them (#816647) +- Remove handling of /etc/localtime and /var/spool/postfix/etc/localtime + as systemd will be handling them from now on (#858735). + +* Fri Sep 14 2012 Jeff Law - 2.16.90-11 +- Resync with upstream sources (#857236). + +* Sat Sep 8 2012 Peter Robinson - 2.16.90-10 +- Enable ports to fix FTBFS on ARM + +* Wed Sep 5 2012 Jeff Law - 2.16.90-9 +- Resync with upstream sources. + +* Tue Sep 4 2012 Jeff Law - 2.16.90-8 +- Incorporate ppc64p7 arch changes (#854250) + +* Thu Aug 30 2012 Jeff Law - 2.16.90-7 +- Resync with upstream sources. + +* Wed Aug 22 2012 Jeff Law - 2.16.90-6 +- Resync with upstream sources. + +* Tue Aug 21 2012 Jeff Law - 2.16.90-5 +- Replace manual systemd scriptlets with macroized scriptlets (#850129) + +* Mon Aug 20 2012 Jeff Law - 2.16.90-4 +- Move /etc/localtime into glibc-common package since glibc-common + owns the scriptlets which update it. + +* Mon Aug 20 2012 Jeff Law - 2.16.90-3 +- Remove obsolete patches from glibc-fedora.patch. Explode + remaining patches into distinct patchfiles. Thanks to + Dmitry V. Levin for identifying them! + Drop ia64 specific patches and specfile fragments + +* Wed Aug 15 2012 Jeff Law - 2.16.90-2 +- Fix integer overflow leading to buffer overflow in strto* (#847718) + +* Mon Aug 13 2012 Jeff Law - 2.16.90-1 +- Resync with upstream sources, drop obsolete patches. +- Drop glibc-ports bits as they're part of the master + sources now. + +* Mon Aug 13 2012 Jeff Law - 2.16-9 +- Replace patch for 179072 with official version from upstream. + +* Fri Aug 10 2012 Jeff Law - 2.16-8 +- Replace patch for 789238 with official version from upstream. + +* Wed Jul 25 2012 Jeff Law - 2.16-7 +- Pack IPv4 servers at the start of nsaddr_list and + only track the number of IPV4 servers in EXT(statp->nscounti (#808147) +- Mark set*uid, set*gid as __wur (warn unused result) (#845960) + +* Wed Jul 25 2012 Jeff Law - 2.16-6 +- Revert patch for BZ696143, it made it impossible to use IPV6 + addresses explicitly in getaddrinfo, which in turn broke + ssh, apache and other code. (#808147) +- Avoid another unbound alloca in vfprintf (#841318) +- Remove /etc/localtime.tzupdate in lua scriptlets +- Revert back to using posix.symlink as posix.link with a 3rd + argument isn't supported in the lua version embedded in rpm. +- Revert recent changes to res_send (804630, 835090). +- Fix memcpy args in res_send (#841787). + +* Thu Jul 19 2012 Fedora Release Engineering - 2.16-3 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_18_Mass_Rebuild + +* Thu Jul 5 2012 Jeff Law - 2.16-2 +- Use posix.link rather than posix.symlink in scriptlet to + update /etc/localtime (#837344). + +* Mon Jul 2 2012 Jeff Law - 2.16-1 +- Resync with upstream glibc-2.16 release. + +* Fri Jun 22 2012 Jeff Law - 2.15.90-16 +- Resync with upstream sources, drop obsolete patch. + +* Thu Jun 21 2012 Jeff Law - 2.15.90-15 +- Resync with upstream sources (#834447). +- Fix use-after-free in dcigettext.c (#816647). + +* Fri Jun 15 2012 Jeff Law - 2.15.90-14 +- Resync with master. + +* Thu Jun 14 2012 Jeff Law - 2.15.90-13 +- Delay setting DECIDED field in locale file structure until + we have read the file's data (#827510). + +* Mon Jun 11 2012 Dennis Gilmore - 2.15.90-12 +- actually apply the arm linker hack + +* Mon Jun 11 2012 Dennis Gilmore - 2.15.90-11 +- only deal with the arm linker compat hack on armhfp arches +- armsfp arches do not have a linker change +- Backward compat hack for armhf binaries. + +* Thu Jun 7 2012 Jeff Law - 2.15.90-10 +- Fix parsing of /etc/sysconfig/clock when ZONE has spaces. (#828291) + +* Tue Jun 5 2012 Jeff Law - 2.15.90-9 +- Resync with upstream sources, drop unnecessary patches. +- Fix DoS in RPC implementation (#767693) +- Remove deprecated alpha support. +- Remove redundant hunk from patch. (#823905) + +* Fri Jun 1 2012 Patsy Franklin - 2.15.90-8 +- Fix iconv() segfault when the invalid multibyte character 0xffff is input + when converting from IBM930 (#823905) + +* Fri Jun 1 2012 Jeff Law - 2.15.90-7 +- Resync with upstream sources. (#827040) + +* Thu May 31 2012 Patsy Franklin - 2.15.90-6 +- Fix fnmatch() when '*' wildcard is applied on a file name containing + multibyte chars. (#819430) + +* Wed May 30 2012 Jeff Law - 2.15.90-5 +- Resync with upstream sources, drop unnecessary patches. + +* Tue May 29 2012 Jeff Law - 2.15.90-4 +- Build info files in the source dir, then move to objdir + to avoid multilib conflicts (#825061) + +* Fri May 25 2012 Jeff Law - 2.15.90-3 +- Work around RPM dropping the contents of /etc/localtime + when it turns into a symlink with %post common script (#825159). + +* Wed May 23 2012 Jeff Law - 2.15.90-2 +- Fix option rotate when one IPV6 server is enabled (#804630) +- Reenable slow/uberslow path taps slowpow/slowexp. + +* Wed May 23 2012 Jeff Law - 2.15.90-1 +- Resync with upstream sources, drop unnecessary patches. + +* Tue May 22 2012 Patsy Franklin - 2.15-41 +- Fix tzdata trigger (#822200) +- Make the symlink relative rather than linking into the buildroot (#822200). +- Changed /etc/localtime to a symlink. 8222000 (#822200) + +* Tue May 15 2012 Jeff Law - 2.15-40 +- Update to upstream patch for 806070 (#806070) + +* Mon May 14 2012 Jeff Law - 2.15-39 +- Update upstream patch for AVX testing (#801650) + +* Fri May 11 2012 Jeff Law - 2.15-38 +- Upstream patch to fix AVX testing (#801650) + +* Thu May 10 2012 Jeff Law - 2.15-37 +- Try again to fix AVX testing (#801650) + +* Mon May 7 2012 Jeff Law - 2.15-36 +- Improve fortification disabled warning. +- Change location of dynamic linker for armhf. + +* Mon Apr 30 2012 Jeff Law - 2.15-35 +- Implement context routines for ARM (#817276) + +* Fri Apr 13 2012 Jeff Law - 2.15-34 +- Issue a warning if FORTIFY_CHECKING is requested, but disabled. + +* Thu Apr 12 2012 Jeff Law - 2.15-33 +- Fix another unbound alloca in nscd groups (#788989) + +* Tue Apr 3 2012 Jeff Law - 2.15-32 +- Fix first day of week for lv_LV (#682500) + +* Mon Apr 2 2012 Jeff Law - 2.15-31 +- When retrying after main arena failure, always retry in a + different arena. (#789238) + +* Tue Mar 27 2012 Jeff Law - 2.15-30 +- Avoid unbound alloca usage in *-crypt routines (#804792) +- Fix data race in nscd (#806070) + +* Fri Mar 23 2012 Jeff Law - 2.15-29 +- Fix typo in __nss_getent (#806403). + +* Wed Mar 14 2012 Jeff Law - 2.15-28 +- Add doi_IN, sat_IN and mni_IN to SUPPORTED locals (#803286) +- Add stap probes in slowpow and slowexp. + +* Fri Mar 09 2012 Jeff Law - 2.15-27 +- Fix AVX checks (#801650) + +* Wed Feb 29 2012 Jeff Law - 2.15-26 +- Set errno properly in vfprintf (#794797) +- Don't kill application when LD_PROFILE is set. (#800224) + +* Wed Feb 29 2012 Jeff Law - 2.15-25 +- Fix out of bounds memory access in resolver (#798471) +- Always mark vDSO as used (#758888) + +* Fri Feb 24 2012 Jeff Law - 2.15-24 +- Fix bogus underflow (#760935) +- Correctly handle dns request where large numbers of A and AAA records + are returned (#795498) +- Fix nscd crash when group has many members (#788989) + +* Mon Feb 20 2012 Jeff Law - 2.15-23 +- Avoid "nargs" integer overflow which could be used to bypass FORTIFY_SOURCE (#794797) + +* Mon Feb 20 2012 Jeff Law - 2.15-22 +- Fix main arena locking in malloc/calloc retry path (#789238) + +* Fri Feb 17 2012 Jeff Law - 2.15-21 +- Correctly identify all 127.x.y.z addresses (#739743) +- Don't assign native result if result has no associated interface (#739743) + +* Fri Feb 17 2012 Jeff Law - 2.15-20 +- Ignore link-local IPV6 addresses for AI_ADDRCONFIG (#697149) + +* Fri Feb 17 2012 Jeff Law - 2.15-19 +- Fix reply buffer mismanagement in resolver (#730856) + +* Thu Feb 16 2012 Jeff Law - 2.15-18 +- Revert 552960/769421 changes again, still causing problems. +- Add doi_IN (#791161) +- Add sat_IN (#790292) +- Add mni_IN (#790298) + +* Thu Feb 9 2012 Jeff Law - 2.15-17 +- Fix lost wakeups in pthread_cond_*. (#552960, #769421) +- Clarify info page for snprintf (#564528) +- Fix first_weekday and first_workday for ru_UA (#624296) + +* Tue Feb 7 2012 Jeff Law - 2.15-16 +- Fix currency_symbol for uk_UA (#789209) +- Fix weekday names in Kashmiri locale (#770439) + +* Tue Feb 7 2012 Jeff Law - 2.15-15 +- Remove change for 787662, correct fix is in gcc. + +* Mon Feb 6 2012 Jeff Law - 2.15-13 +- More accurately detect if we're in a chroot (#688948) + +* Fri Feb 3 2012 Jeff Law - 2.15-12 +- Add fedfs to /etc/rpc (#691912) +- Run nscd in the foreground w/ syslogging, fix systemd config (#770869) +- Avoid mapping past end of shared object (#741105) +- Turn off -mno-minimal-toc on PPC (#787201) +- Remove hunk from glibc-rh657588.patch that didn't belong + +* Wed Feb 1 2012 Jeff Law - 2.15-8 +- Prevent erroneous inline optimization of initfini.s on PowerPC64 (#783979) +- Use upstream variant of fix for 740506. +- Fix month abbreviations for zh_CN (#657588) + +* Sun Jan 29 2012 Jeff Law - 2.15-7 +- Sort objects before relocations (sw#13618) +- Fix bogus sort code that was copied from dl-deps.c. + +* Thu Jan 26 2012 Jeff Law - 2.15-6 +- First argument to settimeofday can be null (#740682) +- Add aliases for ISO-10646-UCS-2 (#697421) + +* Tue Jan 24 2012 Jeff Law - 2.15-4 +- Update ports from master. +- Fix first workday/weekday for it_IT (#622499) +- Fix type to uint16_t based on upstream comments (729661) +- Do not cache negative results in nscd if these are transient (#784402) + +* Mon Jan 23 2012 Jeff Law - 2.15-3 +- Fix cycle detection (#729661) +- Fix first workday/weekday for it_IT (#446078) +- Fix first workday/weekday for ca_ES (#454629) + +* Fri Jan 13 2012 Fedora Release Engineering - 2.15-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_17_Mass_Rebuild + +* Sun Jan 1 2012 Jeff Law - 2.15-1.fc17 +- Update from master (a316c1f) + +* Thu Dec 22 2011 Jeff Law - 2.14.90-26.fc17 +- Update from master (16c6f99) +- Fix typo in recent tzfile change (#769476) +- Make MALLOC_ARENA_MAX and MALLOC_ARENA_TEST match documentation (#740506) +- Revert "fix" to pthread_cond_wait (#769421) +- Extract patch for 730856 from fedora-patch into a distinct patchfile + +* Mon Dec 19 2011 Jeff Law - 2.14.90-25.fc17 +- Update from master (a4647e7). + +* Sun Dec 18 2011 Jeff Law - 2.14.90-24.fc16.3 +- Check values from TZ file header (#767696) +- Handle EAGAIN from FUTEX_WAIT_REQUEUE_PI (#552960) +- Add {dist}.# +- Correct return value from pthread_create when stack alloction fails. + (#767746) + +* Wed Dec 7 2011 Jeff Law - 2.14.90-23 +- Fix a wrong constant in powerpc hypot implementation (#750811) + #13534 in python bug database + #13472 in glibc bug database +- Truncate time values in Linux futimes when falling back to utime + +* Mon Dec 5 2011 Jeff Law - 2.14.90-22 +- Mark fortified __FD_ELT as extension (#761021) +- Fix typo in manual (#708455) + +* Wed Nov 30 2011 Jeff Law - 2.14.90-21 +- Don't fail in makedb if SELinux is disabled (#750858) +- Fix access after end of search string in regex matcher (#757887) + +* Mon Nov 28 2011 Jeff Law - 2.14.90-20 +- Drop lock before calling malloc_printerr (#757881) + +* Fri Nov 18 2011 Jeff Law - 2.14.90-19 +- Check malloc arena atomically (BZ#13071) +- Don't call reused_arena when _int_new_arena failed (#753601) + +* Wed Nov 16 2011 Jeff Law - 2.14.90-18 +- Fix grouping and reuse other locales in various locales (BZ#13147) + +* Tue Nov 15 2011 Jeff Law - 2.14.90-17 +- Revert bogus commits/rebasing of Nov 14, Nov 11 and Nov 8. Sources + should be equivalent to Fedora 16's initial release. + +* Wed Oct 26 2011 Fedora Release Engineering - 2.14.90-15 +- Rebuilt for glibc bug#747377 + +* Wed Oct 19 2011 Jim Meyering - 2.14.90-14 +- Revert the upstream patch that added the leaf attribute, since it + caused gcc -O2 to move code past thread primitives and sometimes + even out of critical sections. See http://bugzilla.redhat.com/747377 + +* Wed Oct 19 2011 Andreas Schwab - 2.14.90-13 +- Update from master + - Fix linkage conflict with feraiseexcept (#746753) + - More libm optimisations + +* Mon Oct 17 2011 Andreas Schwab - 2.14.90-12 +- Update from master + - Correctly handle missing initgroups database (#745675) + - Optimize many libm functions + - Optimize access to isXYZ and toXYZ tables + - Optimized memcmp and wmemcmp for x86-64 and x86-32 + - Add parameter annotation to modf (BZ#13268) + - Support optimized isXXX functions in C++ code + - Check for zero size in memrchr for x86_64 (#745739) + - Optimized memchr, memrchr, rawmemchr for x86-32 + +* Tue Oct 11 2011 Andreas Schwab - 2.14.90-11 +- Update from master + - Clean up locarchive mmap reservation code + - Fix netname2host (BZ#13179) + - Fix remainder (NaN, 0) (BZ#6779, BZ#6783) + - S/390: Fix longlong.h inline asms for zarch + - Improve 64 bit memchr, memrchr, rawmemchr with SSE2 + - Update translations + - Implement caching of netgroups in nscd + - Handle OOM in NSS + - Don't call ifunc functions in trace mode +- Convert tzdata-update to lua (#729796) +- Horrible workaround for horribly broken software (#737223) + +* Wed Sep 28 2011 Andreas Schwab - 2.14.90-10 +- Update from master + - Correctly reparse group line after enlarging the buffer (#739360) + - Fix parse error in bits/mathinline.h with --std=c99 (#740235) +- Update nscd service file (#740284) +- Drop nscd init file (#740196) + +* Fri Sep 16 2011 Andreas Schwab - 2.14.90-9 +- Update from master + - Define IP_MULTICAST_ALL (BZ#13192) + - Add fmax and fmin inlines for x86-64 + - Avoid race between {,__de}allocate_stack and __reclaim_stacks + during fork (#737387) + - Optimized lrint and llrint for x86-64 + - Also relocate in dependency order when doing symbol dependency + testing (#737459) + - Optimize logb code for 64-bit machines + - Fix jn precision (BZ#11589) + - Fix boundary conditions in scanf (BZ#13138) + - Don't lock string streams in stream cleanup code (BZ#12847) + - Define ELFOSABI_GNU + - Fix lround loss of precision + - Add range checking for FD_SET, FD_CLR, and FD_ISSET +- Make sure AVC thread has capabilities + +* Thu Sep 8 2011 Andreas Schwab - 2.14.90-8 +- Update from master + - Use O_CLOEXEC when loading objects and cache in ld.so (BZ#13068) + - Fix memory leak in case of failed dlopen (BZ#13123) + - Optimizations for POWER + - Prefer real syscalls instead of vsyscalls on x86-64 outside libc.so + - Add Atom-optimized strchr and strrchr for x86-64 + - Try shell in posix_spawn* only in compat mode (BZ#13134) + - Fix glob.h header by removing gcc 1.x support (BZ#13150) + - Optimized strchr and strrchr with SSE2 on x86-32 + - Add optimized x86 wcscmp + - Fixes and optimizations for 32-bit sparc fabs + - Fix nptl semaphore cleanup invocation + - Sanitize HWCAP_SPARC_* defines/usage, and add new entries + +* Thu Sep 1 2011 Andreas Schwab - 2.14.90-7 +- Update from master + - Relocate objects in dependency order (#733462) +- Avoid assertion failure when first DNS answer was empty (#730856) +- Don't treat tls_offset == 1 as forced dynamic (#731228) + +* Wed Aug 24 2011 Andreas Schwab - 2.14.90-6 +- Update from master + - Correct cycle detection during dependency sorting + - Use ifuncs for time and gettimeofday on x86-64 + - Fix fopen (non-existing-file, "re") errno + - Fix CFI info in x86-64 trampolines for non-AVX code + - Build libresolv with SSP flags + - Avoid executable stack in makedb (#731063) + - Align x86 TCB to 64 bytes (cache line size), important for Atom + +* Mon Aug 15 2011 Andreas Schwab - 2.14.90-5 +- Update from master + - Implement LD_DEBUG=scopes + - Locale-independent parsing in libintl (#726536) + - Fix stack alignment on x86_64 (#728762) + - Implement scandirat function + +* Tue Aug 9 2011 Andreas Schwab - 2.14.90-4 +- Update from master + - Properly tokenize nameserver line for servers with IPv6 address + - Fix encoding name for IDN in getaddrinfo (#725755) + - Fix inline strncat/strncmp on x86 + - Define SEEK_DATA and SEEK_HOLE + - Define AF_NFC and PF_NFC + - Update ptrace constants + - Add read barriers in cancellation initialization + - Add read barrier protecting DES initialization + - Fix overflow bug in optimized strncat for x86-64 + - Check for overflows in expressions (BZ#12852) + - Fix check for AVX enablement (#720176, BZ#13007) + - Force La_x86_64_ymm to be 16-byte aligned + - Add const attr to gnu_dev_{major,minor,makedev} +- Filter out GLIBC_PRIVATE symbols again + +* Wed Jul 20 2011 Andreas Schwab - 2.14.90-3 +- Update from master + - S/390: Don't use r11 in INTERNAL_VSYSCALL_NCS macro + - Avoid warning in nscd config file parsing code + - Improve 64 bit strcat functions with SSE2/SSSE3 + - Fix alloca accounting in strxfrm + - Avoid possible crashes in anormal nscd exits + - Updated Swedish and Dutch translations + +* Thu Jul 14 2011 Andreas Schwab - 2.14.90-2 +- Update from master + - Generalize framework to register monitoring of files in nscd + - Handle ext4 in {,f}pathconf + - Handle Lustre filesystem (BZ#12868) + - Handle W; without long options in getopt (BZ#12922) + - Change error code for underflows in strtod (BZ#9696) + - Fix handling of chained netgroups + - Optimize long-word additions in SHA implementation + - Handle nscd negtimeout==0 + - nss_compat: query NIS domain only when needed + - Fix robust mutex handling after fork + - Make sure RES_USE_INET6 is always restored +- Add systemd configuration for nscd +- Be more careful running build-locale-archive + +* Thu Jun 30 2011 Andreas Schwab - 2.14.90-1 +- Update from master + - Fix quoting in some installed shell scripts (BZ#12935) + - Fix missing .ctors/.dtors lead word in soinit + - Improved st{r,p}{,n}cpy for SSE2 and SSSE3 on x86 + - Avoid __check_pf calls in getaddrinfo unless really needed + (BZ#12907) + - Rate limit expensive _SC_NPROCESSORS_ONLN computation + - Add initgroups lookup support to getent + - Reenable nss_db with a completely new implementation + - Rewrite makedb to avoid using db library + - Add pldd program +- Obsolete nss_db +- Don't build tzdata-update and build-locale-archive statically + +* Tue Jun 28 2011 Andreas Schwab - 2.14-4 +- Update from 2.14 branch + - Fix crash in GB18030 encoder (#712901) +- Fix more bugs in GB18030 charmap +- Don't use gethostbyaddr to determine canonical name + +* Tue Jun 21 2011 Andreas Schwab - 2.14-3 +- Update from 2.14 branch + - Fix typo in recent resolver change which causes segvs (#710279) + - Fix memory leak in getaddrinfo (#712178) + - Fix for C++ (BZ#12841) + - Assume Intel Core i3/i5/i7 processor if AVX is available +- Filter results from gethostbyname4_r according to request flags + (#711827) +- Repair GB18030 charmap (#712901) +- Revert "Use .machine to prevent AS from complaining about z9-109 + instructions in iconv modules" (#711330) + +* Fri Jun 3 2011 Andreas Schwab - 2.14-2 +- Revert "Handle DNS server failures in case of AF_UNSPEC lookups + correctly" (#710279) + +* Tue May 31 2011 Andreas Schwab - 2.14-1 +- Update to 2.14 release + - Handle DNS server failures in case of AF_UNSPEC lookups correctly + (BZ#12684) + - Prevent loader from loading itself + - Restore _res correctly (BZ#12350) + - Interpret numeric values in shadow file as signed (BZ#11099) + - Recognize use-vc option in resolv.conf (BZ#11558) + - Mark malloc hook variables as deprecated + - Declare malloc hook variables as volatile (BZ#11781) + - Don't document si_code used for raise (BZ#11799) + - Fix unnecessary overallocation due to incomplete character (BZ#12811) + - Handle failure of _nl_explode_name in all cases + - Add support for time syscall in vDSO (BZ#12813) + - Add sendmmsg and setns syscalls + - Use getcpu definition from vDSO on x86-64 (BZ#12813) +- Don't free non-malloced memory and fix memory leak (#709267) + +* Fri May 27 2011 Andreas Schwab - 2.13.90-14 +- Update from master + - Fix conversion to ISO-2022-JP-2 with ISO-8859-7 designation + (BZ#12814) + - Undo accidental change in x86-64 user.h + - Update Japanese translation + - Define RLIMIT_RTTIME (BZ#12795) + - Update longlong.h from GCC + - Add a few more alloca size checks (BZ#12671) + - Fix flags parameter value passed to pltenter and pltexit + - Define CLOCK_REALTIME_ALARM and CLOCK_BOOTTIME_ALARM + - Always fill output buffer in XPG strerror function (BZ#12782) + - Nicer output for negative error numbers in strerror_r + - Fix CP1258 conversion (BZ#12777) + - Fix handling of LC_CTYPE in locale name handling (BZ#12788) + - Set stream errors in more cases (BZ#12792) + - Don't unconditionally use alloca in gaih_inet (BZ#11869) + - Update documentation in regex.h (BZ#11857) + - Prevent Altivec and VSX insns on PowerPC64 when no FPRs or VRs are + available + - Fix typo in x86-64 powl (BZ#12775) +- Avoid overriding CFLAGS (#703880) + +* Wed May 18 2011 Andreas Schwab - 2.13.90-13 +- Update from master + - Update GB18030 to 2005 version (BZ#11837) + - Update RE_SYNTAX*_AWK constants in regex.h + - Handle long variable names in putenv (BZ#11892) + - Fix test for error_one_per_line mode in error (BZ#12766) + - Cleanup x86-64 sys/user.h (BZ#11820) + - Several locale data updates (BZ#11987, BZ#9732, BZ#9730, BZ#4357, + BZ#12582) + - Avoid potential deadlock in mtrace (BZ#6420) + - Fix a few problems in fopen and freopen + - Provide more helpful error message in getopt (BZ#7101) + - Make stack canary value harder to read through read overflow (BZ#10149) + - Use mmap for allocation of buffers used for __abort_msg (BZ#11901) + - Fix handling of static TLS in dlopen'ed objects (BZ#12453) + - Fix initialization of optimization values for AIO (BZ#12083) + - Fix handling of conversion problem in CP932 module (BZ#12601) + - Fix potential problem with out-of-scope buffer (BZ#12626) + - Handle recursive calls in backtrace better (BZ#12432) + - Fix handling of incomplete character storage in state + - Fix file descriptor position after fclose (BZ#12724) +- Reinstall NIS RPC headers + +* Fri May 13 2011 Andreas Schwab - 2.13.90-12 +- Update from master + - Fix resizing table for unique symbols when adding symbol for copy + relocation (BZ#12511) + - Fix sched_setscheduler call in spawn implementation (BZ#12052) + - Report write error in addmnt even for cached streams (BZ#12625) + - Translate kernel error into what pthread_create should return + (BZ#386) + - More configurability for secondary group lookup (BZ#11257) + - Several locale data updates (BZ#11258, BZ#11487, BZ#11532, + BZ#11578, BZ#11653, BZ#11668, BZ#11945, BZ#11947, BZ#12158, + BZ#12200, BZ#12178, BZ#12178, BZ#12346, BZ#12449, BZ#12545, + BZ#12551, BZ#12611, BZ#12660, BZ#12681, BZ#12541, BZ#12711, + BZ#12738) + - Fix Linux getcwd for long paths (BZ#12713) + - static tls memory leak on TLS_DTV_AT_TP archs + - Actually undefine ARG_MAX from + - Backport BIND code to query name as TLD (BZ#12734) + - Allow $ORIGIN to reference trusted directoreis in SUID binaries + (BZ #12393) + - Add missing {__BEGIN,__END}_DECLS to sys/sysmacros.h + - Report if no record is found by initgroups in nss_files +- Never leave $ORIGIN unexpanded +- Revert "Ignore origin of privileged program" +- Reexport RPC interface + +* Thu May 5 2011 Andreas Schwab - 2.13.90-11 +- Update from master + - Don't use removed rpc headers +- Install rpc/netdb.h again + +* Wed May 4 2011 Andreas Schwab - 2.13.90-10 +- Update from master + - ldconfig: don't crash on empty path in config file (#699784) + - getaddrinfo(AF_INET6) does not return scope_id info provided by + NSS modules (BZ#12714) + - Fix pathconf(_PC_BUF_SIZE) (BZ#12723) + - Fix getnameinfo flags parameter type (BZ#12717) + - Add finer grained control for initgroups lookups to NSS + - Use all possible bytes from fopen mode string (BZ#12685, #698025) + - Define initgroups callback for nss_files + - elf.h: Define R_ARM_IRELATIVE reloc type + - Fix static linking with checking x86/x86-64 memcpy (BZ#12653) + - Fix POWER4/POWER7 optimized strncmp to not read past differing bytes + - Fix FPU context handling in getcontext on x86-64 (BZ#12420) + - Skip extra zeroes when searching auxv on s390 + - Obsolete RPC implementation in libc + - Fix memory leak in TLS of loaded objects (BZ#12650) + - Don't leave empty element in rpath when skipping an element + - Make ppc sync_file_range cancelable + - Maintain stack alignment in ____longjmp_chk on x86_64 + +* Thu Apr 7 2011 Andreas Schwab - 2.13.90-9 +- Update from master + - Fix typo in cache information table for x86-{32,64} + - Define CLOCK_BOOTTIME, O_PATH, AT_EMPTY_PATH + - Work around old buggy program which cannot cope with memcpy + semantics (BZ#12518) + - Fix visibility of declarations of wcpcpy and wcpncpy (BZ#12631) + - Add clock_adjtime, name_to_handle_at, open_by_handle_at, syncfs + syscalls + - Really implement fallocate{,64} and sync_file_range as + cancellation points +- Enable systemtap support (#690281) + +* Thu Mar 24 2011 Andreas Schwab - 2.13.90-8 +- Update from master + - Fix infinite loop (#690323) + +* Mon Mar 21 2011 Andreas Schwab - 2.13.90-7 +- Update from master + - Handle page boundaries in x86 SSE4.2 strncmp (BZ#12597) + - Implement x86 cpuid handling of leaf4 for cache information (BZ#12587) + - Check size of pattern in wide character representation in fnmatch + (BZ #12583) + - Remove __restrict quals from wmemcmp prototype + - Fix copy relocations handling of unique objects (BZ#12510) +- ldd: never run file directly +- Ignore rpath elements containing non-isolated use of $ORIGIN when + privileged +- Don't leave empty element in rpath when skipping the first element +- Revert "Don't crash when dependencies are missing" (#688990) + +* Mon Mar 7 2011 Andreas Schwab - 2.13.90-6 +- Update from master + - Fix loading first object along a path when tracing + - Enable SSE2 memset for AMD'supcoming Orochi processor + - Don't read past end of buffer in fmemopen +- Revert broken changes (#682307) + +* Wed Mar 2 2011 Andreas Schwab - 2.13.90-5 +- Update from master + - Fix memory leak in dlopen with RTLD_NOLOAD (BZ#12509) + - Don't crash when dependencies are missing (BZ#12454) + - Fix allocation when handling positional parameters in printf + (BZ#12445) + - Fix two printf handler issues +- Fix false assertion (BZ#12454, #673014) + +* Mon Feb 14 2011 Andreas Schwab - 2.13.90-4 +- Update from master + - Update sysdeps/unix/sysv/linux/sparc/bits/socket.h + - Synchronize generic bits/sched.h cpu_set_t with Linux implementation + - Schedule nscd cache pruning more accurately from re-added values + - Fix passing symbol value to pltexit callbacks when ld.so auditing + - Fix range error handling in sgetspent +- Revert "Fix ordering of DSO constructors and destructors" (#673014) +- Create debuginfo-common on biarch archs +- Reinstall assembler workaround. +- Replace setuid by file capabilities (#646469) + +* Tue Jan 25 2011 Andreas Schwab - 2.13.90-1 +- Update from master + - Fix ordering of DSO constructors and destructors (BZ#11724) +- Remove no longer needed assembler workaround + +* Tue Jan 18 2011 Andreas Schwab - 2.13-1 +- Update to 2.13 release + - Define AT_NO_AUTOMOUNT + - Define MADV_HUGEPAGE and MADV_NOHUGEPAGE + - Add definitions for new socket protocols + - Signal temporary host lookup errors in nscd as such to the + requester (BZ#6812) + - Change setgroups to affect all the threads in the process + (BZ#10563) + - FIx handling of unterminated [ expression in fnmatch (BZ#12378) + - Relax requirement on close in child created by posix_spawn + - Fix handling of missing syscall in Linux mkdirat (BZ#12397) + - Handle long lines in host lookups in the right place (BZ#10484) + - Fix assertion when handling DSTs during auditing + - Fix alignment in x86 destructor calls + - Fix grouping when rounding increases number of integer digits + (BZ#12394) + - Update Japanese translations + - Fix infloop on persistent failing calloc in regex (BZ#12348) + - Use prlimit64 for 32-bit [gs]etrlimit64 implementation (BZ#12201) + - Change XPG-compliant strerror_r function to return error code + (BZ#12204) + - Always allow overwriting printf modifiers etc. + - Make PowerPC64 default to nonexecutable stack + +* Tue Dec 14 2010 Andreas Schwab - 2.12.90-21 +- Revert bogus change + +* Mon Dec 13 2010 Andreas Schwab - 2.12.90-20 +- Update from master + - Declare wcpcpy and wcpncpy only under _GNU_SOURCE + - Fix use of restrict in wchar.h and string.h + - Fix race in qsort_r initialization (BZ#11655) + - Don't ignore zero TTL in DNS answers + - Allow aux_cache_file open()ing to fail silently even in the chroot + mode (BZ#11149) + - Fix multiple nss_compat initgroups() bugs (BZ#10085) + - Define MAP_HUGETLB and SWAP_FLAG_DISCARD +- Remove .UTF-8 suffix from locale names when it is the only supported + codeset (#657556) +- Don't ignore $ORIGIN in libraries + +* Fri Nov 12 2010 Andreas Schwab - 2.12.90-19 +- Update from master + - Fix memory leak in fnmatch + - Support Intel processor model 6 and model 0x2c + - Fix comparison in sqrtl for IBM long double + - Fix one exit path in x86-64 SSE4.2 str{,n}casecmp (BZ#12205, #651638) + - Fix warnings in __bswap_16 (BZ#12194) + - Use IFUNC on x86-64 memset + - Power7-optimized mempcpy + - Handle uneven cache size in 32bit SSE2 memset (BZ#12191) + - Verify in ttyname that the symlink is valid (BZ#12167) + - Update Danish translations + - Fix concurrency problem between dl_open and dl_iterate_phdr + - Fix x86-64 strchr propagation of search byte into all bytes of SSE + register (BZ#12159) + - Fix perturbing in malloc on free (BZ#12140) + - PPC/A2 optimized memcpy function + - Add C99 FP_FAST_FMA{,F,L} macros to +- Check that the running kernel is new enough (#649589) + +* Fri Oct 22 2010 Andreas Schwab - 2.12.90-18 +- Require suid bit on audit objects in privileged programs (CVE-2010-3856) + +* Tue Oct 19 2010 Andreas Schwab - 2.12.90-17 +- Update from master + - Fix some fma issues, implement fmal (BZ#3268, #43358) + - Expect PLT call to _Unwind_Find_FDE on s390*-linux +- Never expand $ORIGIN in privileged programs (#643306, CVE-2010-3847) + +* Thu Oct 14 2010 Andreas Schwab - 2.12.90-16 +- Update from master + - Implement accurate fma (BZ#3268, #43358) + - Fix alignment of AVX save area on x86-64 (BZ#12113) + - Fix regex memory leaks (BZ#12078) + - Improve output of psiginfo (BZ#12107, BZ#12108) + - Don't return NULL address in getifaddrs (BZ#12093) + - Fix strstr and memmem algorithm (BZ#12092, #641124) +- Don't discard result of decoding ACE if AI_CANONIDN (#636642) +- Remove /etc/gai.conf from glibc-common and mark it %%ghost in glibc +- Require exact glibc version in nscd + +* Mon Oct 4 2010 Andreas Schwab - 2.12.90-15 +- Update from master + - Handle large requests in debugging hooks for malloc (BZ#12005) + - Fix handling of remaining bytes in buffer for strncmp and + strncasecmp (BZ#12077) + - Handle cgroup and btrfs filesystems in statvfs + - S/390: Fix highgprs check in startup code (BZ#12067) + - Properly convert f_fsid in statvfs (BZ#11611) + +* Tue Sep 28 2010 Andreas Schwab - 2.12.90-14 +- Don't try to write to _rtld_global_ro after performing relro + protection (#638091) + +* Mon Sep 27 2010 Andreas Schwab - 2.12.90-13 +- Update from master + - Add two forgotten licence exceptions + - getdents64 fallback d_type support + - Move freeres function from ld.so to libc.so + - Undo feature selection for ftruncate (BZ#12037) + - Fix namespace pollution in pthread_cleanup_push + - Fix limit detection in x86-64 SSE2 strncasecmp (#632560) + - Add support for fanotify_mark on sparc32 and s390 + - Fix register conflict in s390 ____longjmp_chk (#629970) + - Don't try to free rpath strings allocated during startup (#629976) + - Actually make it possible to user the default name server +- Fix memory leak on init/fini dependency list (#632936) +- Fix handling of collating symbols in regexps (BZ#11561) +- Don't parse %%s format argument as multibyte string (BZ#6530) +- Fix overflow in nss files parser +- Fix spurious nop at start of __strspn_ia32 + +* Wed Sep 15 2010 Dennis Gilmore - 2.12.90-12 +- dont build sparcv9v and sparc64v anymore + +* Mon Sep 13 2010 Andreas Schwab - 2.12.90-11 +- Update from master + - Fix _FORITY_SOURCE version of longjmp for Linux/x86-64 (BZ#11968) +- Work around shortest-stem feature in make 3.82+ + +* Mon Sep 6 2010 Andreas Schwab - 2.12.90-10 +- Update from master + - Remove invalid iconv aliases (BZ#11979) + - Update x86-64 mpn routines from GMP 5.0.1 + - Fix array overflow in floating point parser (BZ#7066) + - Support fanotify_mark syscall on powerpc32 + - Unroll x86-64 strlen + - Unroll 32bit SSE strlen and handle slow bsf + - Missing server address again leads to localhost being used (BZ#10851) +- Revert last change +- Remove or don't install unpackaged files for auxarches + +* Sat Sep 04 2010 Dennis Gilmore - 2.12.90-9 +- disable unpackaged file check on auxarches + +* Mon Aug 23 2010 Andreas Schwab - 2.12.90-8 +- Update from master + - Fix static strspn on x86 (#624852) + - Various POWER7 optimized string functions + - Fix x86 pthread_cond_signal() FUTEX_WAKE_OP fallback + - Add optimized strncasecmp versions for x86-64 + - PowerPC64 ABI fixes + - Properly quote output of locale (BZ#11904) + - f_flags in statfs implementation + - Add support for fanotify_init and fanotify_mask syscalls + - Add support for prlimit and prlimit64 + - Fix IPTOS_CLASS definition (BZ#11903) + - Avoid too much stack use in fnmatch (BZ#11883) + - x86: Add support for frame pointer less mcount +- Disable asynchronous-unwind-tables during configure run + +* Mon Aug 2 2010 Andreas Schwab - 2.12.90-7 +- Update from master + - Add optimized x86-64 implementation of strnlen and strcaecmp + - Document M_PERTURB + - Fix vDSO synthetic hwcap handling so they are not masked out from + ld.so.cache matching + - POWER6/7 optimizations for copysign +- Build with ports addon on alpha and armv5tel +- Add conflict with kernel < 2.6.32 (#619538) +- Switch to xz compressed tar files +- build-locale-archive: process only directories matching *_* + +* Wed Jul 21 2010 Andreas Schwab - 2.12.90-6 +- Bump minimum kernel version to 2.6.32 + +* Mon Jul 12 2010 Andreas Schwab - 2.12.90-5 +- Update from master + - Don't pass NULL occation to dl_signal_cerror + - Implement _PC_PIPE_BUF. +- Add glibc-ports tarball + +* Fri Jul 2 2010 Andreas Schwab - 2.12.90-4 +- Update from master + - Work around kernel rejecting valid absolute timestamps + - Improve 64bit memcpy/memmove for Atom, Core 2 and Core i7 + - Fix error handling in Linux getlogin* +- Workaround assembler bug sneaking in nopl (#579838) +- Fix scope handling during dl_close +- Fix setxid race handling exiting threads + +* Tue Jun 15 2010 Andreas Schwab - 2.12.90-3 +- Update from master + - Power7 string compare optimizations + - Properly resize buffer in NIS initgroups + - Define F_SETPIPE_SZ and F_GETPIPE_SZ + - Fix more C++ incompatibility problems in headers +- Properly set __libc_multiple_libcs +- Don't assume AT_PAGESIZE is always available (#597578) +- Don't call uname or getrlimit in libpthread init function (#579086) +- Mark /etc/rpc as %%config (#587050) + +* Mon May 31 2010 Andreas Schwab - 2.12.90-2 +- Update from master + - Small fix to POWER7 32-bit memcpy + - Correct x86 CPU family and model check (BZ#11640, #596554) + - Fix iov size in SH register_dump + - Don't crash on unresolved weak symbol reference + - Implement recvmmsg also as socketcall + - sunrpc: Fix spurious fall-through + - Make compatible with C++ (#593762) +- Fix users and groups creation in nscd %%post script + +* Wed May 19 2010 Andreas Schwab - 2.12.90-1 +- Update from master + - POWER7 optimized memset + - Fix typo in es_CR locale + - Enable IDN support in getent + - Fix race in free sanity check + - Fix lookup of collation sequence value during regexp matching + - Fix name of tt_RU.UTF-8@iqtelif locale (#589138) + - Handle too-small buffers in Linux getlogin_r (BZ#11571, #589946) + +* Tue May 4 2010 Roland McGrath - 2.12-1 +- Update to 2.12 release. + - Fix ldconfig chroot handling. + - Don't deadlock in __dl_iterate_phdr while (un)loading objects. + - Fix handling of newline in addmntent. + - Fix AIO when thread creation failed. + +* Fri Apr 16 2010 Andreas Schwab - 2.11.90-20 +- Update from master + - Fix bugs in x86-32 strcmp-sse4.S and strcmp-ssse3.S + - Add x86-32 FMA support + - Don't crash in trace mode when dependencies are missing + - x86-64 SSE4 optimized memcmp + - Fix makecontext on s390/s390x + +* Tue Apr 13 2010 Andreas Schwab - 2.11.90-19 +- Avoid multiarch memcmp in tzdata-update (#581677) + +* Mon Apr 12 2010 Andreas Schwab - 2.11.90-18 +- Update from master + - Implement interfaces to set and get names of threads (BZ#11390) + - Locale data updates (BZ#10824, BZ#10936, BZ#11470, BZ#11471) + - Print reload count in nscd statistics (BZ#10915) + - Fix reading loginuid file in getlogin{,_r} + - Fix fallocate error return on i386 + - Fix cproj implmentation (BZ#10401) + - Fix getopt handing (BZ#11039, BZ#11040, BZ#11041) + - Implement new mode for NIS passwd.adjunct.byname table (BZ#11134) + - Obey LD_HWCAP_MASK in ld.so.cache lookups + +* Tue Apr 6 2010 Andreas Schwab - 2.11.90-17 +- Update from master + - Locale data updates (BZ#11007, BZ#11258, BZ#11272, BZ#10554) + - Handle DNS timeouts in old-style lookup code (BZ#11010) + - Fix aux cache handling in ldconfig with chroot (BZ#11149) + - Fix printing error messages in getopt (BZ#11043) + - Declare iruserok and iruserok_af (BZ#11070) + - Fix option aliasing in argp (BZ#11254) + - Handle POSIX-compliant errno value of unlink in remove (BZ#11276) + - Fix definition and testing of S_ISSOCK (BZ#11279) + - Fix retrieving of kernel header version (BZ#11287) + - Fix concurrent handling of __cpu_features (BZ#11292) + - Handle unnecessary padding in getdents64 (BZ#11333) + - Fix changes to interface list during getifaddrs calls (BZ#11387) + - Missing memory barrier in DES initialization (BZ#11449) + - Fix spurious UNAVAIL status is getaddrinfo + - Add support for new clocks (BZ#11389) + - Fix Linux getlogin{_r,} implementation + - Fix missing zero-termination in cuserid (BZ#11397) + - Fix glob with empty pattern + - Fix handling of STB_GNU_UNIQUE in LD_TRACE_PRELINKING + - Unify wint_t handling in wchar.h and wctype.h (BZ#11410) + - Implement handling of libc ABI in ELF header + - Don't underestimate length of DST substitution in rpath + - Power7-optimized 64-bit and 32-bit memcpy +- Assign global scope to RFC 1918 addresses (#577626) + +* Thu Mar 18 2010 Andreas Schwab - 2.11.90-16 +- Fix SSSE3 memcmp (#574210) + +* Tue Mar 9 2010 Andreas Schwab - 2.11.90-15 +- Update from master + - sparc64: Fix handling of R_SPARC_TLS_LE_* relocations (#571551) + - Handle ext4 and logfs in statvfs functions + - Fix setxid race with thread creation + - Pass -mtune=i686 to assembler when compiling for i686 + - Fix R_X86_64_PC32 overflow detection + - Fix msgrcv on sparc64 + - Fix unwind info in x86 strcmp-sse4.S (BZ#11332) + - sparc: Add multiarch support for memset/bzero/memcpy +- Remove directories owned by filesystem (#569414) +- Add %%ghost /etc/gai.conf to glibc-common (#567748) + +* Tue Feb 23 2010 Andreas Schwab - 2.11.90-14 +- Update from master + - Sparc updates +- Fix SSSE3 memcpy (#556584) + +* Mon Feb 22 2010 Andreas Schwab - 2.11.90-13 +- Update from master + - Use CPUID_OFFSET instead of FEATURE_OFFSET + - Add 32bit memcmp/strcmp/strncmp optimized for SSSE3/SSS4.2 + - Fix file descriotor leak in nftw with FTW_CHDIR (BZ#11271) + - Add Sparc STT_GNU_IFUNC support + - Add power7-optimized classification functions +- Reapply "Optimize 32bit memset/memcpy with SSE2/SSSE3." +- Use unsigned comparison in sse memcpy/memset + +* Mon Feb 8 2010 Andreas Schwab - 2.11.90-12 +- Update from master + - Update constants in for current kernels (#11235) + - Fix endless loop with invalid /etc/shells file (#11242) + - Fix sorting of malayalam letter 'na' (#10414) + - Add kok_IN locale + - Use common collation data in as_IN locale + - Avoid alloca in setenv for long strings +- Use shared mapping to reserve memory when creating locale archive (#10855) +- Fix fstat on Linux/sparc64 (#11155) + +* Mon Feb 1 2010 Andreas Schwab - 2.11.90-11 +- Update from master + - Fix error checking in iconv (#558053) + - Don't map U00DF to U1E9E in toupper table + - _nl_load_locale() incorrectly handles mmap() failures (BZ#11200) + - Fix various issues in regex matcher (BZ#11183, BZ#11184, BZ#11185, + BZ#11186, BZ#11187, BZ#11188, BZ#11189, BZ#11190, BZ#11191, + BZ#11192, BZ#11193) + +* Tue Jan 19 2010 Andreas Schwab - 2.11.90-10 +- Update from master + - Fix ____longjmp_chk for s390/s390x + - Remove duplicate definitions of O_DSYNC and O_RSYNC for Linux/sparc + - Ignore negative dynamic entry types (#546890) + - Fix pthread_cond_*wait with requeue-PI on i386 (#548989) + - Fix _XOPEN_SOURCE_EXTENDED handling +- Revert "Optimize 32bit memset/memcpy with SSE2/SSSE3." + +* Fri Jan 15 2010 Andreas Schwab - 2.11.90-9 +- Update from master. + - Define IPTOS_CLASS_* macros according to RFC 2474 (BZ#11027) + - Always use IPv4 sockets for IPv4 addresses (BZ#11141) + - regcomp.c: do not ignore memory allocation failure (BZ#11127) + - Fix malloc_info without prior allocations (BZ#11126) + - Optimize 32bit memset/memcpy with SSE2/SSSE3 + - Relax feature tests in headers + +* Tue Jan 12 2010 Andreas Schwab - 2.11.90-8 +- Update from master. + - More POSIX conformance fixes. + +* Mon Jan 11 2010 Andreas Schwab - 2.11.90-7 +- Fix build failure. + +* Mon Jan 11 2010 Andreas Schwab - 2.11.90-6 +- Update from master. + - POSIX conformance fixes (BZ#11125). + +* Mon Jan 4 2010 Andreas Schwab - 2.11.90-5 +- Update from master. + - Additional setcontext(), etc. conformance tests (BZ#11115). + - Handle AT_FDCWD in futimens (BZ#10992). + - Update poll.h header for POSIX 2008 (BZ#11093). + - Avoid ELF lookup race. + +* Mon Dec 14 2009 Andreas Schwab - 2.11.90-4 +- Update from master. + - Add Requeue-PI support for x86 arch. + - Redefine O_SYNC and O_DSYNC to match 2.6.33+ kernels. + - Fix a few error cases in *name4_r lookup handling (BZ#11000). + - Fix kernel version check in recent ptsname change (BZ#11046). + - Add more warnings to exec functions (BZ#11056). + - Add recvmmsg interface. + - Define SCHED_IDLE and SCHED_RESET_ON_FORK for Linux. + +* Mon Nov 30 2009 Andreas Schwab - 2.11.90-3 +- Update from master. + - Fix infloop in __pthread_disable_asynccancel on x86_64 (#537690). + - Prevent unintended file desriptor leak in grantpt (#530558). + - Fix startup to security-relevant statically linked binaries (#528631). +- Re-install CFI in x86/x86_64 clone (#491542). + +* Tue Nov 24 2009 Andreas Schwab - 2.11.90-2 +- Update from master. + - Define week, first_weekday, and first_workday for en_DK locale (#525126). + - Use struct timespec for timestamps in struct stat also if + __USE_XOPEN2K8 (#539870). + - Fix week information for nl_NL locale (#499748). + - Update ntp_gettime for Linux (#479558). + - Fix getwc* and putwc* on non-wide streams (BZ#10958). + - Avoid warnings in CPU_* macros when using const bitsets (BZ#10918). + - Handle LC_GLOBAL_LOCALE in duplocale (BZ#10969). + - Fix _NC_LOCALE_NAME definition (BZ#10968). + - Add missing Linux MADV_* definitions (BZ#10972). + - Add support for new Linux error ERFKILL (BZ#10939). +- Enable multi-arch support on ppc and ppc64. + +* Thu Nov 12 2009 Andreas Schwab - 2.11.90-1 +- Update from master. + +* Thu Nov 5 2009 Andreas Schwab - 2.11-2 +- Fix readahead on powerpc32. +- Fix R_PPC64_{JMP_IREL,IRELATIVE} handling. +- Fix preadv, pwritev and fallocate for -D_FILE_OFFSET_BITS=64 (#533063). + +* Mon Nov 2 2009 Andreas Schwab - 2.11-1 +- Update to 2.11 release. +- Disable multi-arch support on PowerPC again since binutils is too old. +- Fix crash in tzdata-update due to use of multi-arch symbol (#532128). + +* Fri Oct 30 2009 Andreas Schwab - 2.10.90-27 +- Update from master. + - Fix races in setXid implementation (BZ#3270). + - Implement IFUNC for PPC and enable multi-arch support. + - Implement mkstemps/mkstemps64 and mkostemps/mkostemps64 (BZ#10349). + - Fix IA-64 and S390 sigevent definitions (BZ#10446). + - Fix memory leak in NIS grp database handling (BZ#10713). + - Print timestamp in nscd debug messages (BZ#10742). + - Fix mixing IPv4 and IPv6 name server in resolv.conf. + - Fix range checks in coshl. + - Implement SSE4.2 optimized strchr and strrchr. + - Handle IFUNC symbols in dlsym (#529965). + - Misc fixes (BZ#10312, BZ#10315, BZ#10319, BZ#10391, BZ#10425, + BZ#10540, BZ#10553, BZ#10564, BZ#10609, BZ#10692, BZ#10780, + BZ#10717, BZ#10784, BZ#10789, BZ#10847 +- No longer build with -fno-var-tracking-assignments. + +* Mon Oct 19 2009 Andreas Schwab - 2.10.90-26 +- Update from master. + - Add ____longjmp_chk for sparc. +- Avoid installing the same libraries twice. + +* Mon Oct 12 2009 Andreas Schwab - 2.10.90-25 +- Update from master + - Fix descriptor leak when calling dlopen with RTLD_NOLOAD (#527409). + - Fix week-1stday in C locale. + - Check for integer overflows in formatting functions. + - Fix locale program error handling (#525363). + +* Mon Sep 28 2009 Andreas Schwab - 2.10.90-24 +- Update from master. + - Fix missing reloc dependency (#517001). + +* Mon Sep 21 2009 Andreas Schwab - 2.10.90-23 +- Update from master. + +* Mon Sep 14 2009 Andreas Schwab - 2.10.90-22 +- Update from master. + - Fix endless loop in localedef. + - Fix __longjmp_chk on s390/s390x. +- Fix exit codes in nscd start script (#521848). +- Build with -fno-var-tracking-assignments for now (#523172). + +* Mon Sep 7 2009 Andreas Schwab - 2.10.90-21 +- Update from master. + - Fix strstr/strcasestr on i386 (#519226). + +* Thu Sep 3 2009 Andreas Schwab - 2.10.90-20 +- Update from master. + - Fix strstr/strcasestr/fma/fmaf on x86_64 (#519226). + - Fix lookup of group names in hesiod initgroups (#520472). + +* Wed Sep 2 2009 Andreas Schwab - 2.10.90-19 +- Update from master. + - Fix x86_64 bits/mathinline.h for -m32 compilation. + +* Tue Sep 1 2009 Andreas Schwab - 2.10.90-18 +- Update from master. + - fix parse error in (#520209). + +* Thu Aug 27 2009 Roland McGrath - 2.10.90-17 +- Update from master. + +* Wed Aug 26 2009 Andreas Schwab - 2.10.90-16 +- Update from master. + - handle AVX saving on x86-64 in interrupted symbol lookups (#519081). + +* Mon Aug 24 2009 Andreas Schwab - 2.10.90-15 +- Update from master. + - fix fortify failure with longjmp from alternate stack (#512103). +- Add conflict with prelink (#509655). + +* Mon Aug 17 2009 Andreas Schwab - 2.10.90-14 +- Update from master. + - fix pthread_cond_signal (#516469) + +* Mon Aug 10 2009 Andreas Schwab - 2.10.90-13 +- Update from master. + - fix rehashing of unique symbols (#515677) +- Fix spurious messages with --excludedocs (#515948) + +* Mon Aug 3 2009 Andreas Schwab - 2.10.90-12 +- Update from master. + - fix fortify failure with longjmp from alternate stack (#512103) + +* Thu Jul 30 2009 Andreas Schwab - 2.10.90-11 +- Update from master. +- Don't package debuginfo files in glibc-devel. + +* Tue Jul 28 2009 Andreas Schwab - 2.10.90-10 +- Update from master. + * fix memory ordering in pthread_mutex_unlock (BZ#10418) + * implement RES_USE_DNSSEC option in resolver (#205842) + * fix hang in ldd -r (#513945) + +* Mon Jul 27 2009 Andreas Schwab - 2.10.90-9 +- Update from master. + +* Fri Jul 24 2009 Fedora Release Engineering - 2.10.90-8.1 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_12_Mass_Rebuild + +* Fri Jul 24 2009 Jakub Jelinek - 2.10.90-7.1 +- Fix up pthread_cond_timedwait on x86_64 with old kernels. + +* Thu Jul 23 2009 Andreas Schwab - 2.10.90-7 +- Update from master. +- Build with -DNDEBUG unless using a prerelease. + +* Thu Jul 23 2009 Andreas Schwab - 2.10.90-6 +- Rebuilt with binutils-2.19.51.0.14-29.fc12 to fix static binaries + +* Wed Jul 22 2009 Andreas Schwab - 2.10.90-5 +- Update from master. +- Undefine __i686 on x86 to fix build. + +* Mon Jul 20 2009 Andreas Schwab - 2.10.90-4 +- Update from master. +- Don't build separate i686 package. + +* Wed Jul 8 2009 Andreas Schwab 2.10.90-3 +- Reenable setuid on pt_chown. + +* Thu Jul 2 2009 Andreas Schwab 2.10.90-2 +- Update from master. + +* Fri Jun 26 2009 Andreas Schwab 2.10.90-1 +- Update from master. +- Enable multi-arch support on x86/x86-64. +- Add requires glibc-headers to glibc-devel (#476295). +- Implement second fallback mode for DNS requests (#505105). +- Don't generate invalid POSIX TZ string for Asia/Dhaka timezone (#506941). +- Allow backtrace through __longjmp_chk on powerpc. + +* Fri May 22 2009 Jakub Jelinek 2.10.1-2 +- fix accept4 on architectures other than i?86/x86_64 +- robustify nscd client code during server GC +- fix up nscd segfaults during daemon shutdown +- fix memchr on ia64 (BZ#10162) +- replace the Sun RPC license with the BSD license, with the explicit + permission of Sun Microsystems +- fix up powerpc long double errno reporting + +* Sun May 10 2009 Jakub Jelinek 2.10.1-1 +- fix up getsgent_r and getsgnam_r exports on i?86 and ppc + +* Sat May 9 2009 Jakub Jelinek 2.10-2 +- update from trunk + - glibc 2.10 release + - fix memchr on x86_64 (#499689) + +* Mon Apr 27 2009 Jakub Jelinek 2.9.90-22 +- update from trunk + - further localedef fixes +- fix build-locale-archive + +* Fri Apr 24 2009 Jakub Jelinek 2.9.90-21 +- update from trunk + - fix localedef + - fix SHIFT_JIS iconv EILSEQ handling (#497267) + - misc fixes (BZ#10093, BZ#10100) + +* Fri Apr 24 2009 Jakub Jelinek 2.9.90-20 +- update from trunk + - fix p{read,write}v{,64} (#497429, #497434) + - fix strfmon (#496386) + +* Thu Apr 16 2009 Jakub Jelinek 2.9.90-19 +- update from trunk + - fix dlopen from statically linked binaries (#495830) + +* Thu Apr 16 2009 Jakub Jelinek 2.9.90-18 +- update from trunk + - fix fallocate + +* Wed Apr 15 2009 Jakub Jelinek 2.9.90-17 +- update from trunk + - if threads have very small stack sizes, use much smaller buffer + in __get_nprocs when called from within malloc (#494631) + +* Tue Apr 14 2009 Jakub Jelinek 2.9.90-16 +- update from trunk + +* Thu Apr 9 2009 Jakub Jelinek 2.9.90-15 +- rebuilt with fixed gcc to avoid miscompilation of i586 memmove +- reenable experimental malloc again + +* Wed Apr 8 2009 Jakub Jelinek 2.9.90-14 +- update from trunk +- temporarily disable experimental malloc + +* Tue Apr 7 2009 Jakub Jelinek 2.9.90-13 +- update from trunk + - fix strverscmp (#494457) +- configure with --enable-nss-crypt + +* Wed Apr 1 2009 Jakub Jelinek 2.9.90-12 +- update from trunk +- configure with --enable-experimental-malloc + +* Fri Mar 20 2009 Jakub Jelinek 2.9.90-11 +- update from trunk + - POSIX 2008 prototype adjustments for scandir{,64}, alphasort{,64} and + versionsort{,64} + - fix libthread_db (#491197) + +* Tue Mar 10 2009 Jakub Jelinek 2.9.90-10 +- update from trunk + - fix atexit/__cxa_atexit + +* Mon Mar 9 2009 Jakub Jelinek 2.9.90-9 +- update from trunk + - POSIX 2008 support: -D_XOPEN_SOURCE=700 and -D_POSIX_C_SOURCE=200809L +- move libnldbl_nonshared.a on ppc*/s390*/sparc* back to glibc-devel + +* Fri Feb 27 2009 Roland McGrath - 2.9.90-8.1 +- fix libthread_db (#487212) + +* Tue Feb 24 2009 Fedora Release Engineering - 2.9.90-8 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_11_Mass_Rebuild + +* Wed Feb 18 2009 Jakub Jelinek 2.9.90-7 +- update from trunk +- adjust for i586 + i686 from i386 + i686 build +- split static libraries into glibc-static subpackage +- ld -r the whole libpthread.a together to avoid endless issues with + -static ... -lpthread +- require 2.6.18 and later kernel + +* Wed Feb 4 2009 Jakub Jelinek 2.9.90-3 +- update from trunk + - ISO C++ compliant strchr etc. with GCC 4.4+ + - AT_RANDOM support + +* Thu Jan 8 2009 Jakub Jelinek 2.9.90-2 +- update from trunk + +* Fri Jan 2 2009 Jakub Jelinek 2.9.90-1 +- update from trunk (#478314) + +* Mon Dec 8 2008 Jakub Jelinek 2.9-3 +- temporarily disable _nss_dns_gethostbyname4_r (#459756) +- NIS hostname lookup fixes (#473073, #474800, BZ#7058) +- fix unsetenv (#472941) + +* Thu Nov 13 2008 Jakub Jelinek 2.9-2 +- glibc 2.9 release +- fix CPU_ALLOC_SIZE on 32-bit arches (BZ#7029) + +* Wed Nov 12 2008 Jakub Jelinek 2.8.90-17 +- update from trunk + - don't abort on broken DNS replies (#469299, BZ#7009) + - misc fixes (BZ#6966, BZ#7008, BZ#6955, BZ#6843) + +* Fri Oct 31 2008 Jakub Jelinek 2.8.90-16 +- update from trunk + - further resolver fixes + - another dynamic TLS handling fix (#469263) + - misc fixes (BZ#6867, BZ#6875, BZ#6919, BZ#6920, BZ#6942, BZ#6947, + BZ#6968, BZ#6974, BZ#6980, BZ#6995) +- rebuild with newer rpm to avoid stripping + shared libraries when they shouldn't be (#468129) + +* Tue Oct 28 2008 Jakub Jelinek 2.8.90-15 +- update from trunk + - __libc_res_nquery fixes (#466786) + +* Sun Oct 19 2008 Jakub Jelinek 2.8.90-14 +- update from trunk + - fix dynamic TLS handling (#467309) + - fix sys/signalfd.h for C++ (#467172) + - fix sprof (#458861) + - fix _mcount and socket syscalls on s390x (#464146) + - try harder to allocate memory in valloc and pvalloc (#461481) +- fix power6 32-bit libs (#467311) + +* Fri Oct 10 2008 Dennis Gilmore 2.8.90-13 +- apply sparcv9v memset patch from jakub and davem + +* Fri Aug 29 2008 Jakub Jelinek 2.8.90-12 +- update from trunk + - revert origin changes (#457849) + - use MAP_STACK for thread stacks + - misc fixes (BZ#6845, BZ#6544, BZ#6634, BZ#6589, BZ#6790, BZ#6791, + BZ#6824) + - power7 bits (BZ#6817) + - fix expm1 on i?86/x86_64 (#43354, BZ#5794) + +* Sat Aug 2 2008 Jakub Jelinek 2.8.90-11 +- update from trunk + - fix non-absolute $ORIGIN handling (#457560) + - exported some further libresolv APIs (#453325) + - misc fixes + +* Tue Jul 29 2008 Jakub Jelinek 2.8.90-10 +- update from trunk + - resolver fixes + - misc fixes (BZ#6771, BZ#6763, BZ#6698, BZ#6712) + - s390{,x} utmp/utmpx bi-arch support (BZ#6724) + - popen "e" flag +- fr_FR locale changes reenabled + +* Wed Jul 16 2008 Jakub Jelinek 2.8.90-9 +- update from trunk + - fix unbuffered vfprintf if writing to the stream fails (#455360) + - remove useless "malloc: using debugging hooks" message (#455355) + - nscd fixes + - fix resolver alignment issues (#454500) + - fix setvbuf (BZ#6719) + +* Thu Jul 3 2008 Jakub Jelinek 2.8.90-8 +- update from trunk + - watch even resolv.conf in nscd using inotify + - some nscd fixes + +* Fri Jun 13 2008 Jakub Jelinek 2.8.90-7 +- update from trunk + - avoid *lround* on ppc* clobbering cr3/cr4 registers (#450790) + - further nscd fixes (#450704) + - use inotify in nscd to watch files + +* Thu Jun 12 2008 Jakub Jelinek 2.8.90-6 +- update from trunk + - nscd fixes (#450704) + - fix getservbyport (#449358) + - fix regexp.h (#446406) + - avoid crashing on T_DNAME in DNS responses (#450766) + +* Sun May 25 2008 Jakub Jelinek 2.8.90-5 +- update from trunk + +* Tue May 20 2008 Jakub Jelinek 2.8.90-4 +- further getaddrinfo and nscd fixes + +* Sun May 18 2008 Jakub Jelinek 2.8.90-3 +- getaddrinfo and nscd fixes +- reenable assertion checking in rawhide + +* Fri May 16 2008 Jakub Jelinek 2.8.90-2 +- fix getaddrinfo (#446801, #446808) + +* Thu May 15 2008 Jakub Jelinek 2.8.90-1 +- update to trunk + - O(n) memmem/strstr/strcasestr + - i386/x86_64 TLS descriptors support + - concurrent IPv4 and IPv6 DNS lookups by getaddrinfo + +* Mon May 5 2008 Jakub Jelinek 2.8-3 +- don't run telinit u in %%post if both /dev/initctl and + /sbin/initctl exist (#444978) +- workaround GCC ppc64 miscompilation of c{log{,10},acosh,atan}l + (#444996) + +* Wed Apr 30 2008 Jakub Jelinek 2.8-2 +- fix nscd races during GC (BZ#5381) +- rebuilt with fixed GCC to fix regex miscompilation on power6 +- SPARC fixes + +* Sat Apr 12 2008 Jakub Jelinek 2.8-1 +- 2.8 release + +* Fri Apr 11 2008 Jakub Jelinek 2.7.90-16 +- update to trunk + - misc fixes (BZ#4997, BZ#5741) + - make sure all users of __libc_setlocale_lock know it is + now a rwlock + - fix ppc/ppc64 compatibility _sys_errlist and _sys_siglist + symbols + +* Thu Apr 10 2008 Jakub Jelinek 2.7.90-15 +- update to trunk + - misc fixes (BZ#4314, BZ#4407, BZ#5209, BZ#5436, BZ#5768, BZ#5998, + BZ#6024) +- restart sshd in %%post when upstart is used - it doesn't have + /dev/initctl (#441763) +- disable assert checking again + +* Tue Apr 8 2008 Jakub Jelinek 2.7.90-14 +- update to trunk + - misc fixes (BZ#5443, BZ#5475, BZ#5478, BZ#5939, BZ#5979, BZ#5995, + BZ#6004, BZ#6007, BZ#6020, BZ#6021, BZ#6042) + - change mtrace to keep perl 5.10 quiet (#441082) + - don't share conversion state between mbtowc and wctomb (#438687) + - if st_blksize is too large and malloc fails, retry with smaller + buffer in opendir (#430768) + - correct *printf overflow test (#358111) + +* Fri Mar 28 2008 Jakub Jelinek 2.7.90-13 +- update to trunk + - don't define ARG_MAX in , as it is no longer + constant - use sysconf (_SC_ARG_MAX) to get the current + argument size limit + - fix build on sparc64 +- only service sshd condrestart if /etc/rc.d/init.d/sshd exists + (#428859) + +* Wed Mar 26 2008 Jakub Jelinek 2.7.90-12 +- update to trunk + - new CLONE_* flags in (#438542) + - nis+ errno clobbering fix (#437945) + - fix adjtime (#437974) + +* Fri Mar 14 2008 Jakub Jelinek 2.7.90-11 +- update to trunk +- remove , define _XOPEN_STREAMS -1 (#436349) + +* Wed Mar 5 2008 Jakub Jelinek 2.7.90-8 +- update to trunk + - {,v}{as,d}printf and obstack_{,v}printf fortification (#435905) + - fix getnameinfo/gethostbyaddr (#428067, BZ#5790) + - fix yp_order (#435519, BZ#5854) + - misc fixes (BZ#5779, BZ#5736, BZ#5627, BZ#5818, BZ#5012) +- merge review cleanup (Tom Callaway, #225806) + +* Sat Feb 16 2008 Jakub Jelinek 2.7.90-7 +- update to trunk + - make NI_MAXHOST and NI_MAXSERV available even in BSDish + namespaces (BZ#5737) + - timerfd_* syscalls + +* Fri Feb 1 2008 Jakub Jelinek 2.7.90-6 +- fix build + +* Thu Jan 31 2008 Jakub Jelinek 2.7.90-5 +- update to trunk +- rebuild with gcc 4.3 + +* Fri Jan 11 2008 Jakub Jelinek 2.7.90-4 +- update to trunk + - misc fixes (BZ#5541, BZ#5545, BZ#5553, BZ#5112, BZ#5520) + - getaddrinfo fixes + - signalize EOVERFLOW from sem_post instead of overflowing + the counter + - fix i?86 makecontext + - fix iconv for iso-2022-jp//translit (#397021) + +* Thu Jan 3 2008 Jakub Jelinek 2.7.90-3 +- update to trunk + - fix recognition of interface family (#425768) + - add __THROW to __ctype_{b,tolower,toupper}_loc prototypes + +* Thu Dec 27 2007 Jakub Jelinek 2.7.90-2 +- update to trunk + - nsswitch fix (#425768) +- temporarily enable assert checking + +* Wed Dec 12 2007 Jakub Jelinek 2.7.90-1 +- update to trunk + - fix __USE_STRING_INLINES on i?86 (#408731, #371711) + - fix *scanf (#388751) + +* Wed Oct 17 2007 Jakub Jelinek 2.7-1 +- glibc 2.7 release +- fix tzfile.c for times after last transition (#333561) +- fix sem_post@GLIBC_2.0 on i?86 +- appease valgrind in libpthread.so initialization +- misc fixes (BZ#3425, BZ#5184, BZ#5186) + +* Mon Oct 15 2007 Jakub Jelinek 2.6.90-21 +- fix getgr{name,gid}{,_r} with nscd + +* Sun Oct 14 2007 Jakub Jelinek 2.6.90-20 +- install (#330031) +- disable -D_FORTIFY_SOURCE{,=2} support (with a warning) for + GCC 3.4.x and earlier(#327641) +- pl_PL locale changes (BZ#4098, #242296) +- misc fixes (BZ#1140, BZ#3195, BZ#3242, BZ#4359) + +* Thu Oct 11 2007 Jakub Jelinek 2.6.90-19 +- fix +- simple preprocessor in localedef, fix de_DE collation with it + +* Wed Oct 10 2007 Jakub Jelinek 2.6.90-18 +- add signalfd, eventfd, eventfd_read, eventfd_write +- qsort speedups +- workaround for cpuid bugs (#324081) +- make sure gettext's conversion_lock is initialized even if + program isn't linked against libpthread.so.0, only dlopens it (#321761) +- misc fixes (BZ#5112, BZ#5113, BZ#5104, BZ#5063, BZ#5010, BZ#4407, + BZ#3924, BZ#5103, BZ#2633, BZ#181, BZ#73, #321901) + +* Wed Oct 3 2007 Jakub Jelinek 2.6.90-17 +- fix {,v}swprintf with -D_FORTIFY_SOURCE=1 -mlong-double-64 on ppc*/s390*/sparc* +- strcoll fixes +- misc fixes (BZ#645, BZ#5071) +- locale fixes (BZ#4941, #299321, #203364, #196711, #236212) + +* Sat Sep 29 2007 Jakub Jelinek 2.6.90-16 +- misc fixes (BZ#4963, BZ#4972, BZ#5028, BZ#5043, BZ#5058) +- improve -D_FORTIFY_SOURCE{,=2} diagnostic through warning/error + attributes +- fix wcscpy, wcpcpy, fgetws, fgetws_unlocked, swprintf and vswprintf + fortification inlines +- fix a scalability issue with lazy binding in heavily multithreaded + programs + +* Thu Sep 20 2007 Jakub Jelinek 2.6.90-15 +- $5$ (SHA-256) and $6$ (SHA-512) support in crypt + (#228697, #249477, #173834) + +* Tue Sep 18 2007 Jakub Jelinek 2.6.90-14 +- -D_FORTIFY_SOURCE{,=2} support for C++ +- fortification of fread{,_unlocked} +- support *scanf m allocation modifier (%%ms, %%mls, %%mc, ...) +- in -std=c99 or -D_XOPEN_SOURCE=600 mode don't recognize + %%as, %%aS and %%a[ as a GNU extension for *scanf +- fix splice, vmsplice, tee return value, make them cancellation + points +- mq_open checking +- use inline function rather than function-like macro + for open{,at}{,64} checking +- IFA_F_OPTIMISTIC handling in getaddrinfo (#259681) +- fix an ABBA deadlock in ld.so (#284171) +- remove sparc{32,64} unwind info from _start and clone + +* Mon Aug 27 2007 Jakub Jelinek 2.6.90-13 +- fix personality on x86_64/ppc/ppc64 (#256281) + +* Sat Aug 25 2007 Jakub Jelinek 2.6.90-12 +- readd x86_64 gettimeofday stuff, initialize it earlier +- nis_list fix (#254115) +- workaround for bugs in ia64 silly /emul/ia32-linux hack (#253961) +- misc fixes (BZ#3924, BZ#4566, BZ#4582, BZ#4588, BZ#4726, BZ#4946, + BZ#4905, BZ#4814, BZ#4925, BZ#4936, BZ#4896, BZ#4937, BZ#3842, + BZ#4554, BZ#4557, BZ#4938) + +* Fri Aug 17 2007 Jakub Jelinek 2.6.90-11 +- remove __strtold_internal and __wcstold_internal from ppc*/s390*/sparc* + *-ldbl.h headers +- temporarily backout x86_64 gettimeofday.S changes (#252453) +- some further sparc, sparc64 and alpha fixes + +* Wed Aug 15 2007 Jakub Jelinek 2.6.90-10 +- don't open /etc/ld.so.{cache,preload} with O_NOATIME (#252146) +- s390{,x}, alpha and sparc fixes +- sparcv9 is no longer an aux arch, as we expect + to not build sparc.rpm glibc any longer, only sparcv9.rpm, + sparc64.rpm and new two aux arches sparcv9v.rpm and sparc64v.rpm + +* Tue Aug 14 2007 Jakub Jelinek 2.6.90-9 +- private futex even for mutexes and condvars +- some further O_CLOEXEC changes +- use vDSO on x86_64 if available +- ia64 build fixes (#251983) + +* Fri Aug 10 2007 Roland McGrath 2.6.90-8 +- update to trunk + - fix missing strtold_l export on ppc64 + +* Thu Aug 9 2007 Roland McGrath 2.6.90-6 +- update to trunk + - fix local PLT regressions +- spec file revamp for new find-debuginfo.sh + +* Sun Aug 5 2007 Jakub Jelinek 2.6.90-4 +- fix librt.so and librtkaio.so on ppc32, so that it is not using + bss PLT + +* Sat Aug 4 2007 Jakub Jelinek 2.6.90-3 +- fix open{,at}{,64} macro for -pedantic (#250897) +- add transliteration for l with stroke (#250492) +- fix strtod ("-0", NULL) +- update License tag + +* Wed Aug 1 2007 Jakub Jelinek 2.6.90-2 +- make aux-cache purely optional performance optimization in ldconfig, + don't issue any errors if it can't be created (#250430) +- remove override_headers hack, BuildRequire >= 2.6.22 kernel-headers + and rely on its content + +* Tue Jul 31 2007 Jakub Jelinek 2.6.90-1 +- update to trunk + - private futex optimizations + - open{,at}{,64} argument checking +- ldconfig speedups + +* Sun Jul 8 2007 Jakub Jelinek 2.6-4 +- filter pseudo-files from debuginfo source lists (#245714) +- fix sscanf when errno is EINTR before the call (BZ#4745) +- save/restore errno around reading /etc/default/nss (BZ#4702) +- fix LD_HWCAP_MASK handling +- disable workaround for #210748, instead backport + ld.so locking fixes from the trunk (#235026) +- new x86_64 memcpy +- don't write uninitialized padding bytes to nscd socket +- fix dl{,v}sym, dl_iterate_phdr and dlopen if some library is + mapped into ld.so's inter-segment hole on x86_64 (#245035, #244545) +- fix LD_AUDIT=a:b program (#180432) +- don't crash on pseudo-zero long double values passed to + *printf on i?86/x86_64/ia64 (BZ#4586) +- fix *printf %%La and strtold with some hexadecimal floating point + constants on ppc/ppc64 +- fix nextafterl on ppc/ppc64 +- fix sem_timedwait on i?86 and x86_64 + +* Thu May 24 2007 Jakub Jelinek 2.6-3 +- don't use %%config(missingok) for locale-archive.tmpl, + instead of removing it altogether truncate it to zero + size (#240697) +- add a workaround for #210748 + +* Mon May 21 2007 Jakub Jelinek 2.6-2 +- restore malloc_set_state backwards compatibility (#239344) +- fix epoll_pwait (BZ#4525) +- fix printf with unknown format spec or positional arguments + and large width and/or precision (BZ#4514) +- robust mutexes fix (BZ#4512) + +* Tue May 15 2007 Roland McGrath 2.6-1 +- glibc 2.6 release + +* Fri May 11 2007 Jakub Jelinek 2.5.90-24 +- utimensat, futimens and lutimes support + +* Thu May 10 2007 Jakub Jelinek 2.5.90-23 +- use madvise MADV_DONTNEED in malloc +- fix ia64 feraiseexcept +- fix s390{,x} feholdexcept (BZ#3427) +- ppc fenv fixes +- make fdatasync a cancellation point (BZ#4465) +- fix *printf for huge precisions with wide char code and multi-byte + strings +- fix dladdr (#232224, BZ#4131) + +* Fri May 4 2007 Jakub Jelinek 2.5.90-22 +- add transliteration for (BZ#3213) +- fix *scanf with %%f on hexadecimal floats without exponent (BZ#4342) +- fix *printf with very large precisions for %%s (#238406, BZ#4438) +- fix inet_ntop size checking for AF_INET (BZ#4439) +- for *printf %%e avoid 1.000e-00, for exponent 0 always use + sign (#238431) +- fix a regression introduced in #223467 changes +- gethostby*_r alignment fixes (BZ#4381) +- fix ifaddrs error handling + +* Mon Apr 16 2007 Jakub Jelinek 2.5.90-21 +- don't include individual locale files in glibc-common, + rather include prepared locale-archive template and let + build-locale-archive create locale-archive from the template + and any user supplied /usr/lib/locale/*_* directories, + then unlink the locale-archive template - this should save + > 80MB of glibc-common occupied disk space +- fix _XOPEN_VERSION (BZ#4364) +- fix printf with %%g and values tiny bit smaller than 1.e-4 (#235864, + BZ#4362) +- fix NIS+ __nisfind_server (#235229) + +* Sat Mar 31 2007 Jakub Jelinek 2.5.90-20 +- assorted NIS+ speedups (#223467) +- fix HAVE_LIBCAP configure detection (#178934) +- remove %%{_prefix}/sbin/rpcinfo from glibc-common (#228894) +- nexttoward*/nextafter* fixes (BZ#3306) +- feholdexcept/feupdateenv fixes (BZ#3427) +- speed up fnmatch with two or more * in the pattern + +* Sat Mar 17 2007 Jakub Jelinek 2.5.90-19 +- fix power6 libm compat symbols on ppc32 (#232633) +- fix child refcntr in NPTL fork (#230198) +- fix ifaddrs with many net devices on > 4KB page size arches (#230151) +- fix pthread_mutex_timedlock on x86_64 (#228103) +- various fixes (BZ#3919, BZ#4101, BZ#4130, BZ#4181, BZ#4069, BZ#3458) + +* Wed Feb 21 2007 Jakub Jelinek 2.5.90-18 +- fix nftw with FTW_CHDIR on / (BZ#4076) +- nscd fixes (BZ#4074) +- fix fmod{,f,l} on i?86 (BZ#3325) +- support localized digits for fp values in *scanf (BZ#2211) +- namespaces fixes (BZ#2633) +- fix euidaccess (BZ#3842) +- glob fixes (BZ#3996) +- assorted locale data fixes (BZ#1430, BZ#672, BZ#58, BZ#3156, + BZ#2692, BZ#2648, BZ#3363, BZ#3334, BZ#3326, BZ#3322, BZ#3995, + BZ#3885, BZ#3884, BZ#3851) + +* Sun Feb 11 2007 Jakub Jelinek 2.5.90-17 +- RFC2671 support in resolver (#205842) +- fix strptime (BZ#3944) +- fix regcomp with REG_NEWLINE (BZ#3957) +- fix pthread_mutex_timedlock on x86_64 (#228103) + +* Fri Feb 2 2007 Jakub Jelinek 2.5.90-16 +- add strerror_l +- fix application crashes when doing NSS lookups through nscd + mmapped databases and nscd decides to start garbage collection + during the lookups (#219145, #225315) +- fix %%0lld printing of 0LL on 32-bit architectures (BZ#3902) +- ignore errors from install-info in glibc-devel scriptlets + (#223691) + +* Wed Jan 17 2007 Jakub Jelinek 2.5.90-15 +- fix NIS getservbyname when proto is NULL +- fix nss_compat +group handling (#220658) +- cache services in nscd +- fix double free in fts_close (#222089) +- fix vfork+execvp memory leak (#221187) +- soft-fp fixes (BZ#2749) +- further strtod fixes (BZ#3855) +- make sure pthread_kill doesn't return EINVAL even if + the target thread exits in between pthread_kill ESRCH check + and the actual tgkill syscall (#220420) +- fix ABBA deadlock possibility in ld.so scope locking code + +* Tue Dec 19 2006 Jakub Jelinek 2.5.90-14 +- fix {j,m}rand48{,_r} on 64-bit arches (BZ#3747) +- handle power6x AT_PLATFORM (#216970) +- fix a race condition in getXXbyYY_r (#219145) +- fix tst-pselect testcase + +* Thu Dec 14 2006 Jakub Jelinek 2.5.90-13 +- fix setcontext on ppc32 (#219107) +- fix wide stdio after setvbuf (#217064, BZ#2337) +- handle relatime mount option in statvfs +- revert i?86/x86_64 clone CFI temporarily + +* Sun Dec 10 2006 Jakub Jelinek 2.5.90-12 +- fix hasmntopt (#218802) +- fix setusershell and getusershell (#218782) +- strtod fixes (BZ#3664, BZ#3673, BZ#3674) +- fix memusage with realloc (x, 0) + +* Tue Dec 5 2006 Jakub Jelinek 2.5.90-11 +- allow suid apps to setenv NIS_PATH and influence through that + nis_list and nis_lookup (#209155) +- fix ttyname and ttyname_r with invalid file descriptor (#218276) +- cs_CZ LC_TIME fixes (#218438) +- fix build with 2.6.19+ headers (#217723) + +* Fri Dec 1 2006 Jakub Jelinek 2.5.90-10 +- fix x86-64 restore_rt unwind info + +* Thu Nov 30 2006 Jakub Jelinek 2.5.90-9 +- fix last svc_run change (#217850) +- on ppc64 build __libc_start_main without unwind info, + as it breaks MD_FROB_UPDATE_CONTEXT (#217729, #217775; in the + future that could be fixable just by providing .cfi_undefined r2 + in __libc_start_main instead) +- add unwind info for x86-64 restore_rt signal return landing pad + (#217087) +- add power6x subdir to /%%{_lib}/ and /%%{_lib}/rtkaio/, + link all libs from ../power6/* into them + +* Tue Nov 28 2006 Jakub Jelinek 2.5.90-8 +- fix svc_run (#216834, BZ#3559) +- add -fasynchronous-unwind-tables to CFLAGS (#216518) +- make sure there is consistent timestamp for /etc/ld.so.conf, + /etc/localtime and /etc/rpc between multilib glibc rpms + +* Mon Nov 20 2006 Jakub Jelinek 2.5.90-7 +- handle IPv6 addresses in /etc/hosts that are mappable to + IPv4 addresses in IPv4 host lookups (#215283) +- fix :include: /etc/alias handling (#215572) +- handle new tzdata format to cope with year > 2037 transitions + on 64-bit architectures + +* Fri Nov 10 2006 Jakub Jelinek 2.5.90-6 +- fix strxfrm fix +- fix i?86 floor and ceil inlines (BZ#3451) + +* Thu Nov 9 2006 Jakub Jelinek 2.5.90-5 +- fix sysconf (_SC_LEVEL{2,3}_CACHE_SIZE) on Intel Core Duo + CPUs +- fix libthread_db.so on TLS_DTV_AT_TP architectures +- fix --inhibit-rpath (#214569) +- fix _r_debug content when prelinked ld.so executes + a program as its argument +- fix strxfrm +- powerpc-cpu add-on updates + +* Fri Nov 3 2006 Jakub Jelinek 2.5.90-4 +- fix atexit backwards compatibility (#213388) +- add mai_IN locale (#213415) +- remove bogus %%{_libdir}/librt.so.1 symlink (#213555) +- fix memusage (#213656) +- change libc.info category (#209493) + +* Sun Oct 29 2006 Jakub Jelinek 2.5.90-3 +- fix suid/sgid binaries on i?86/x86_64 (#212723) + +* Fri Oct 27 2006 Jakub Jelinek 2.5.90-2 +- fix ia64 build +- don't call _dl_close outside of dl_load_lock critical section + if dlopen failed (BZ#3426) +- add rtld scope locking (#211133) + +* Wed Oct 25 2006 Jakub Jelinek 2.5.90-1 +- fix i?86 6 argument syscalls (e.g. splice) +- fix rtld minimal realloc (BZ#3352) +- fix RFC3484 getaddrinfo sorting according to rules 4 and 7 (BZ#3369) +- fix xdrmem_setpos (#211452) +- bump __GLIBC_MINOR__ +- increase PTHREAD_STACK_MIN on ppc{,64} to 128K to allow + 64K pagesize kernels (#209877) +- speed up initgroups on NIS+ (#208203) + +* Mon Oct 2 2006 Jakub Jelinek 2.5-2 +- fix nscd database growing (#207928) +- bypass prelinking when LD_DYNAMIC_WEAK=1 is in the environment + +* Fri Sep 29 2006 Jakub Jelinek 2.5-1 +- glibc 2.5 release + +* Wed Sep 27 2006 Jakub Jelinek 2.4.90-36 +- rebuilt with gcc-4.1.1-26 to fix unwind info + +* Mon Sep 25 2006 Jakub Jelinek 2.4.90-35 +- fix glob with large number of matches (BZ#3253) +- fix fchownat on kernels that don't support that syscall (BZ#3252) +- fix lrintl on s390{,64} + +* Sat Sep 23 2006 Jakub Jelinek 2.4.90-34 +- fix ppc{32,64} longjmp (BZ#3225) +- fix user visible spelling errors (BZ#3137) +- fix l{,l}rint{,f,l} around zero (BZ#2592) +- avoid stack trampoline in s390{,x} makecontext + +* Tue Sep 19 2006 Jakub Jelinek 2.4.90-33 +- fix dlclose (#206639) +- don't load platform optimized libraries if kernel doesn't set + AT_PLATFORM +- fix ppc{32,64} libSegFault.so +- use -mtune=generic even for glibc-devel.i386 (#206437) +- fix /%%{_lib}/librt.so.1 symlink + +* Fri Sep 15 2006 Jakub Jelinek 2.4.90-32 +- on ppc* use just AT_PLATFORM and altivec AT_HWCAP bit for library selection +- fix lrintl and lroundl on ppc{,64} +- use hidden visibility on fstatat{,64} and mknodat in libc_nonshared.a + +* Sun Sep 10 2006 Jakub Jelinek 2.4.90-31 +- fix pthread_cond_{,timed}wait cancellation (BZ#3123) +- fix lrint on ppc32 (BZ#3155) +- fix malloc allocating more than half of address space (BZ#2775) +- fix mktime on 32-bit arches a few years after 2038 (BZ#2821) + +* Thu Sep 7 2006 Jakub Jelinek 2.4.90-30 +- add librtkaio, to use it add /%%{lib}/rtkaio to your + LD_LIBRARY_PATH or /etc/ld.so.conf +- fix or_IN February name (#204730) +- fix pthread_create called from cancellation handlers (BZ#3124) +- fix regex case insensitive searches with characters where upper + and lower case multibyte representations have different length + (e.g. I and dotless i, #202991) + +* Tue Sep 5 2006 Jakub Jelinek 2.4.90-29 +- randomize resolver query ids before use instead after use (#205113) +- fix resolver symver checking with DT_GNU_HASH (#204909) +- put .hash section in glibc libraries at the end of RO segment + when .gnu.hash is present + +* Thu Aug 31 2006 Jakub Jelinek 2.4.90-28 +- another malloc doubly linked list corruption problem fix (#204653) + +* Thu Aug 31 2006 Jakub Jelinek 2.4.90-27 +- allow $LIB and $PLATFORM in dlopen parameters even in suid/sgid (#204399) +- handle $LIB/$PLATFORM in LD_LIBRARY_PATH +- fix splice prototype (#204530) + +* Mon Aug 28 2006 Jakub Jelinek 2.4.90-26 +- real fix for the doubly linked list corruption problem +- try harder in realloc to allocate memory (BZ#2684) +- fix getnameinfo error reporting (#204122) +- make localedef more robust on invalid input (#203728) + +* Fri Aug 25 2006 Jakub Jelinek 2.4.90-25 +- temporarily back out code to limit number of unsorted block + sort iterations (#203735, #204027) +- handle PLT symbols in dladdr properly (BZ#2683) +- avoid malloc infinite looping for allocations larger than + the system can allocate (#203915) + +* Tue Aug 22 2006 Jakub Jelinek 2.4.90-23 +- malloc fixes, especially for 32-bit arches (#202309) +- further *_IN locale fixes (#200230) +- fix get{serv,rpc}ent{,_r} if NIS map is empty (#203237) +- fix /usr/bin/iconv (#203400) + +* Fri Aug 18 2006 Jakub Jelinek 2.4.90-22 +- rebuilt with latest binutils to pick up 64K -z commonpagesize + on ppc/ppc64 (#203001) + +* Tue Aug 15 2006 Jakub Jelinek 2.4.90-21 +- if some test gets stuck, kill the tee process after make check + finishes +- build with -mtune=generic on i686 and x86_64 + +* Tue Aug 15 2006 Jakub Jelinek 2.4.90-20 +- PTHREAD_PRIO_PROTECT support +- fix errno if nice() fails (#201826) + +* Thu Aug 10 2006 Jakub Jelinek 2.4.90-19 +- adaptive malloc brk/mmap threshold +- fix fchownat to use kernel syscall (if available) on many arches (#201870) +- only define O_DIRECT with -D_GNU_SOURCE on ia64 to match all + other arches (#201748) + +* Mon Aug 7 2006 Jakub Jelinek 2.4.90-18 +- NIS+ fixes +- fix memusage and xtrace scripts (#200736) +- redirect /sbin/service sshd condrestart std{out,err} to /dev/null + when executed from glibc_post_upgrade + +* Wed Aug 2 2006 Jakub Jelinek 2.4.90-17 +- typo fix for the dladdr patch +- build i?86 glibc with -mno-tls-direct-seg-refs (#200469) + +* Wed Aug 2 2006 Jakub Jelinek 2.4.90-16 +- fix dladdr on binaries/libraries with only DT_GNU_HASH and no + DT_HASH (#200635) +- fix early timeout of initgroups data in nscd (#173019) +- add am/pm display to es_PE and es_NI locales (#167101) +- fix nss_compat failures when nis/nis+ unavailable (#192072) + +* Mon Jul 31 2006 Roland McGrath 2.4.90-15 +- fix missing destructor calls in dlclose (#197932) +- enable transliteration support in all locales (#196713) +- disallow RTLD_GLOBAL flag for dlmopen in secondary namespaces (#197462) +- PI mutex support + +* Mon Jul 10 2006 Jakub Jelinek 2.4.90-13 +- DT_GNU_HASH support + +* Fri Jun 30 2006 Jakub Jelinek 2.4.90-12 +- buildrequire gettext +- enable fstatat64/newfstatat syscalls even on ppc*/s390*/ia64 (#196494) +- fix out of memory behavior in gettext (#194321) +- fix regex on multi-byte non-UTF-8 charsets (#193873) +- minor NIS+ fixes (#190803) +- don't use cancellable calls in posix_spawn* and only set{u,g}id + current thread if requested (#193631) + +* Wed May 31 2006 Jakub Jelinek 2.4.90-11 +- don't exit from nscd -i before the database is + actually invalidated, add locking to prune_cache (#191464) +- build glibc-devel.i386 static libraries with + -mno-tls-direct-seg-refs -DNO_TLS_DIRECT_SEG_REFS +- RFC3542 support (advanced API for IPv6; #191001, BZ##2693) + +* Wed May 24 2006 Jakub Jelinek 2.4.90-10 +- on i686 make glibc owner of /lib/i686 directory (#192597) +- search parent NIS+ domains (#190803) + +* Sun May 21 2006 Jakub Jelinek 2.4.90-9 +- update from CVS + - big NIS+ changes + +* Fri May 19 2006 Jakub Jelinek 2.4.90-8 +- update from CVS + - fix nss_compat when SETENT_BATCH_READ=TRUE is in /etc/default/nss + - fix RFC3484 precedence table for site-local and ULA addresses (#188364) + - fix a sunrpc memory leak + +* Thu May 11 2006 Jakub Jelinek 2.4.90-7 +- update from CVS + - fix tcgetattr (#177965) + - fix (#191264) + +* Fri May 5 2006 Jakub Jelinek 2.4.90-6 +- update from CVS +- rebuilt using fixed rpm + +* Fri May 5 2006 Jakub Jelinek 2.4.90-5 +- update from CVS + - some NIS+ fixes + - allow overriding rfc3484 address sorting tables for getaddrinfo + through /etc/gai.conf (sample config file included in %%doc directory) + +* Mon May 1 2006 Jakub Jelinek 2.4.90-4 +- update from CVS + - SETENT_BATCH_READ /etc/default/nss option for speeding up + some usages of NIS+ (#188246) + - move debug state change notification (#179208) + - fix ldd script if one of the dynamic linkers is not installed (#190259) + +* Thu Apr 27 2006 Jakub Jelinek 2.4.90-3 +- update from CVS + - fix a typo in nscd.conf (#190085) + - fix handling of SIGHUP in nscd when some caches are disabled (#189978) + - make nscd paranoia mode working with non-root server-user (#189779) + +* Wed Apr 26 2006 Jakub Jelinek 2.4.90-2 +- update from CVS + - fix getaddrinfo (#190002) + - add auto-propagate nscd.conf options (#177154) + - fix nscd auditing (#169148) + +* Tue Apr 25 2006 Jakub Jelinek 2.4.90-1 +- update from CVS + +* Mon Apr 24 2006 Jakub Jelinek 2.4-6 +- update from CVS + - NIS+ fixes + - don't segfault on too large argp key values (#189545) + - getaddrinfo fixes for RFC3484 (#188364) + +* Tue Mar 28 2006 Jakub Jelinek 2.4-5 +- update from CVS + - pshared robust mutex support + - fix btowc and bwtoc in C++ (#186410) + - fix NIS+ (#186592) + - don't declare __wcsto*l_internal for non-GCC or if not -O1+ (#185667) +- don't mention nscd failures on 2.0 kernels (#185335) + +* Tue Mar 7 2006 Roland McGrath 2.4-4 +- back up %%{ix86} gdb conflicts to < 6.3.0.0-1.111 + +* Tue Mar 7 2006 Jakub Jelinek 2.4-3 +- really fix rintl on ppc64 + +* Tue Mar 7 2006 Jakub Jelinek 2.4-2 +- accurate unwind info for lowlevellock.h stubs on %%{ix86} +- fix ppc/ppc64 ceill, floorl, rintl, roundl and truncl (BZ#2423) + +* Mon Mar 6 2006 Jakub Jelinek 2.4-1 +- update from CVS + - glibc 2.4 release + +* Mon Mar 6 2006 Jakub Jelinek 2.3.91-2 +- update from CVS + - fix sYSMALLOc for MALLOC_ALIGNMENT > 2 * SIZE_SZ (#183895) + - revert ppc32 malloc alignment patch, it breaks malloc_set_state + and needs some further thoughts and time (#183894) +- provide accurate unwind info for lowlevellock.h stubs on x86_64 + +* Thu Mar 2 2006 Jakub Jelinek 2.3.91-1 +- update from CVS + - fixes for various arches +- ensure malloc returns pointers aligned to at least + MIN (2 * sizeof (size_t), __alignof__ (long double)) + (only on ppc32 this has not been the case lately with addition + of 128-bit long double, #182742) + +* Wed Mar 1 2006 Jakub Jelinek 2.3.90-39 +- update from CVS + +* Fri Feb 17 2006 Jakub Jelinek 2.3.90-38 +- update from CVS + - robust mutexes rewrite + +* Mon Feb 13 2006 Jakub Jelinek 2.3.90-37 +- update from CVS + - *at fixes + - unshare syscall wrapper + +* Sat Feb 4 2006 Jakub Jelinek 2.3.90-36 +- update from CVS + - fix frequency setting for ITIMER_PROF (#179938, BZ#2268) + - fix powerpc inline fegetround () + - fix nptl_db (#179946) + +* Fri Feb 3 2006 Jakub Jelinek 2.3.90-35 +- update from CVS + - handle futimesat (fd, NULL, tvp) as futimes (fd, tvp) +- fix q{e,f,g}cvt{,_r} for -mlong-double-64 + +* Thu Feb 2 2006 Jakub Jelinek 2.3.90-34 +- fix with C++ and -mlong-double-64 (#179742) +- add nexttowardl redirect for -mlong-double-64 + +* Thu Feb 2 2006 Jakub Jelinek 2.3.90-33 +- update from CVS + - long double support fixes + +* Wed Feb 1 2006 Jakub Jelinek 2.3.90-32 +- update from CVS + - 128-bit long double fixes for ppc{,64}, s390{,x} and sparc{,v9}, + alpha 128-bit long double support +- add inotify syscall numbers to the override headers + (#179366) + +* Mon Jan 30 2006 Jakub Jelinek 2.3.90-31 +- update from CVS + - 128-bit long double on ppc, ppc64, s390, s390x and sparc{,v9} +- add some new syscall numbers to the override + headers + +* Mon Jan 9 2006 Jakub Jelinek 2.3.90-30 +- update from CVS + - initializer fixes for -std=c{8,9}9 on 32-bit + arches +- avoid writable .rodata (#177121) + +* Fri Jan 6 2006 Jakub Jelinek 2.3.90-29 +- update from CVS + - make pthread_mutex_t an unnamed union again, as it affects + libstdc++ ABI mangling + +* Fri Jan 6 2006 Jakub Jelinek 2.3.90-28 +- update from CVS + - make aio_suspend interruptible by signals (#171968) + +* Fri Jan 6 2006 Jakub Jelinek 2.3.90-27 +- only rely on d_type in 32-bit getdents on s390 for 2.6.11+ + +* Wed Jan 4 2006 Jakub Jelinek 2.3.90-26 +- update from CVS + - for newly linked lio_listio* callers, send per request + notifications (#170116) + - fixup nscd -S option removal changes (#176860) + - remove nonnull attribute from ctermid (#176753) + - fix PTHREAD_*_INITIALIZER{,_NP} on 64-bit arches + - SPARC NPTL support for pre-v9 CPUs +- drop support for 2.4.xx and < 2.6.9 kernels + +* Mon Jan 2 2006 Jakub Jelinek 2.3.90-25 +- update from CVS + - s390{,x} and sparc{,64} pointer mangling fixes +- install a sanitized LinuxThreads + +* Mon Jan 2 2006 Jakub Jelinek 2.3.90-24 +- update from CVS + - nscd audit changes (#174422) + - ppc{32,64} vDSO support and ppc32 hp-timing + +* Tue Dec 27 2005 Jakub Jelinek 2.3.90-23 +- update from CVS + - robust mutexes +- fix transliteration segfaults (#176573, #176583) +- ignore prelink temporaries in ldconfig (#176570) + +* Wed Dec 21 2005 Jakub Jelinek 2.3.90-22 +- update from CVS + - minor fts fixes +- revert broken _Pragma () workaround +- fix ldconfig on bi-arch architectures (#176316) + +* Tue Dec 20 2005 Jakub Jelinek 2.3.90-21 +- update from CVS + - fix pointer (de)mangling in gconv_cache.c + +* Tue Dec 20 2005 Jakub Jelinek 2.3.90-20 +- update from CVS + - time ((void *) 1) should segfault, not return -EFAULT (#174856, BZ#1952) + - fix errlist generation +- update ulps for GCC 4.1 on IA-64 + +* Mon Dec 19 2005 Jakub Jelinek 2.3.90-19 +- update from CVS + - sysdeps/generic reorg + - setjmp/longjmp jump pointer mangling +- rebuilt with GCC 4.1-RH prerelease, worked around broken _Pragma () + handling in it +- remove glibc-profile subpackage +- use non-PLT calls for malloc/free/realloc/memalign invocations in + mtrace and mcheck hooks (#175261) +- setjmp/longjmp jump pointer mangling on ppc{,64}/ia64/s390{,x} + +* Sat Nov 19 2005 Jakub Jelinek 2.3.90-18 +- update from CVS + - change for broken apps that #define const /**/, + handle non-GCC compilers + - fix ppc{32,64} strncmp (BZ#1877, #173643, IT#83510) + - provide shmatt_t typedef in ia64 2.3.90-17 +- update from CVS + - fix in C++ + - {fstat,fchown,rename,unlink}at fixes + - epoll_wait is now a cancellation point + +* Tue Nov 15 2005 Jakub Jelinek 2.3.90-16 +- update from CVS +- make sure waitid syscall is used on ppc*/s390* + +* Thu Oct 20 2005 Jakub Jelinek 2.3.90-15 +- update from CVS + - be permissive in %%n check because of kernel bug #165351 (#171240) + - don't misalign stack in pthread_once on x86_64 (#170786, IT#81521) + - many locale fixes + +* Mon Oct 10 2005 Jakub Jelinek 2.3.90-14 +- update from CVS + - fix malloc bug after fork introduced in the last update + - fix getent hosts IP for IPv4 IPs (#169831) + +* Mon Oct 3 2005 Jakub Jelinek 2.3.90-13 +- update from CVS + - fix setuid etc. hangs if some thread exits during the call (#167766) + - fix innetgr memory leak (#169051) + - support > 2GB nscd log files (#168851) + - too many other changes to list here +- include errno in nscd message if audit_open failed (#169148) + +* Mon Sep 12 2005 Jakub Jelinek 2.3.90-12 +- update from CVS + - netgrp handling fixes (#167728) + - fix memory leak in setlocale (BZ#1318) + - fix hwcaps computation + - several regex portability improvements (#167019) + - hypotf fix + - fix *printf return code if underlying write fails (BZ#1146) + - PPC64 dl{,v}sym fixes for new ABI .opd symbols +- fix calloc with MALLOC_PERTURB_ in environment on 64-bit architectures + (#166719) +- source /etc/sysconfig/nscd (if it exists) in /etc/rc.d/init.d/nscd + (#167083) +- add %%triggerin for tzdata to glibc-common, so that tzdata updates + update /etc/localtime and /var/spool/postfix/etc/localtime if they + exist (#167787) + +* Mon Aug 29 2005 Jakub Jelinek 2.3.90-11 +- FUTEX_WAKE_OP support to speed up pthread_cond_signal + +* Wed Aug 24 2005 Jakub Jelinek 2.3.90-10 +- update from CVS + - fix growing of nscd persistent database (BZ#1204) + - fix _FORTIFY_SOURCE mbstowcs and wcstombs if destination size + is known at compile time, but length argument is not + +* Mon Aug 22 2005 Jakub Jelinek 2.3.90-9 +- update from CVS + - fix resolving over TCP (#161181, #165802) + - on ia64 don't abort on unhandled math function exception codes + (#165693) + +* Mon Aug 8 2005 Jakub Jelinek 2.3.90-8 +- update from CVS + - nscd persistent database verifier (#164001) + - cleanup _FORTIFY_SOURCE bits/*.h headers (#165000) + - handle EINTR in sigwait properly +- make sure poor man's stack guard randomization keeps first + byte 0 even on big-endian 32-bit arches +- fix {elf,nptl}/tst-stackguard1 +- obsolete linuxthreads-devel in glibc-devel + +* Fri Jul 29 2005 Jakub Jelinek 2.3.90-7 +- update from CVS +- do some poor man's stack guard randomization even without + the costly --enable-stackguard-randomization +- rebuilt with new GCC to make it use -msecure-plt on PPC32 + +* Mon Jul 25 2005 Jakub Jelinek 2.3.90-6 +- update from CVS + - fix execvp if PATH is not in environment and the call is going + to fail (BZ#1125) + - another bits/wchar2.h fix (#163990) + +* Fri Jul 22 2005 Jakub Jelinek 2.3.90-5 +- update from CVS + - fix stubs.h generation +- don't use _G_va_list in bits/wchar2.h + +* Fri Jul 22 2005 Jakub Jelinek 2.3.90-4 +- update from CVS + - make sure bits/wchar2.h header is installed + - fix __getgroups_chk return type + +* Thu Jul 21 2005 Jakub Jelinek 2.3.90-3 +- update from CVS + - make sure nscd cmsg buffers aren't misaligned, handle EINTR from + poll when contacting nscd more gracefully + - remove malloc attribute from posix_memalign + - correctly size nscd buffer for grpcache key (#163538) + - fix atan2f + - fix error memory leaks + - some more _FORTIFY_SOURCE protection + +* Fri Jul 8 2005 Jakub Jelinek 2.3.90-2 +- update from CVS + - ia64 stack protector support + - handle DNS referral results as server errors (#162625) + - ctan{,h}{,f,l} fixes (#160759) + - pass argc, argv and envp also to executable's *ni_array + functions (BZ#974) + - add ellipsis to clone prototype (#161593) + - fix glibc-profile (#162601) + - nss_compat fixes +- use sysdeps/generic version of in installed + headers instead of NPTL version (#162634) + +* Mon Jun 27 2005 Jakub Jelinek 2.3.90-1 +- update from CVS + - stack protector support + - fix xdr_{,u_}{longlong_t,hyper} on 64-bit arches (#161583) +- enable @GLIBC_2.4 symbols +- remove linuxthreads + +* Mon Jun 20 2005 Jakub Jelinek 2.3.5-11 +- update from CVS + - PPC32 -msecure-plt support + - support classes keyword in /etc/hesiod.conf (#150350) + - add RLIMIT_NICE and RLIMIT_RTPRIO to (#157049) + - decrease number of .plt relocations in libc.so + - use -laudit in nscd (#159217) + - handle big amounts of networking interfaces in getifaddrs/if_nameindex + (#159399) + - fix pa_IN locale's am_pm (#158715, BZ#622) + - fix debugging of PIEs + +* Mon May 30 2005 Jakub Jelinek 2.3.5-10 +- fix LD_ASSUME_KERNEL (since 2.3.5-8 GLRO(dl_osversion) + has been always overwritten with the version of currently + running kernel) +- remove linuxthreads man pages other than those covered in + 3p section, as 3p man pages are far better quality and describe + POSIX behaviour that NPTL implements (#159084) + +* Tue May 24 2005 Jakub Jelinek 2.3.5-9 +- update from CVS + - increase bindresvport's LOWPORT to 512, apparently some + broken daemons don't think 0 .. 511 ports are reserved + +* Mon May 23 2005 Jakub Jelinek 2.3.5-8 +- update from CVS + - fix kernel version check in ld.so +- fix sendfile{,64} prototypes (BZ#961) +- try more ports in bindresvport if all 600..1023 are + used, don't use priviledged ports when talking to portmap + (#141773) + +* Fri May 20 2005 Jakub Jelinek 2.3.5-7 +- update from CVS + - make regexec thread safe (BZ#934) +- fix statically linked programs on i?86, x86_64, s390* and + sparc* (#158027) +- fix IBM939 iconv module (BZ#955) + +* Wed May 4 2005 Jakub Jelinek 2.3.5-6 +- update from CVS + - fix cancellation on i?86 + - add call frame information to i?86 assembly + +* Tue May 3 2005 Jakub Jelinek 2.3.5-5 +- update from CVS + - add some more UTF-8 locales (#156115) +- clean up /lib64/tls instead of /lib/tls on x86-64, s390x and + ppc64 in glibc_post_upgrade (#156656) +- fix posix_fallocate{,64} (#156289) + +* Thu Apr 28 2005 Jakub Jelinek 2.3.5-4 +- update from CVS + - fix nscd cache pruning (#150748) + +* Wed Apr 27 2005 Jakub Jelinek 2.3.5-3 +- update from CVS + - fix linuxthreads clocks +- put xen libs into the glibc-2*.i686 package instead of a separate one +- fix librt.so symlink in linuxthreads-devel +- do not include linuxthreads-devel on %%{auxarches}, + just on the base architectures + +* Wed Apr 27 2005 Jakub Jelinek 2.3.5-2 +- update from CVS + - with MALLOC_CHECK_=N N>0 (#153003) + - fix recursive dlclose (#154641) + - handle %%z in strptime (#154804) + - automatically append /%%{_lib}/obsolete/linuxthreads/ + to standard library search path if LD_ASSUME_KERNEL=N N <= 2.4.19 + or for glibc 2.0 binaries (or broken ones that don't use errno/h_errno + properly). Warning: all those will stop working when LinuxThreads + is finally nuked, which is not very far away + - remove nonnull attribute from acct prototype (BZ#877) + - kernel CPU clocks support + - fix *scanf in locales with multi-byte decimal point + +* Wed Apr 27 2005 Roland McGrath +- glibc-xen subpackage for i686 + +* Fri Apr 15 2005 Roland McGrath 2.3.5-1 +- update from CVS + - fix execvp regression (BZ#851) + - ia64 libm updates + - sparc updates + - fix initstate{,_r}/strfry (#154504) + - grok PT_NOTE in vDSO for kernel version and extra hwcap dirs, + support "hwcap" keyword in ld.so.conf files + +* Tue Apr 5 2005 Jakub Jelinek 2.3.4-21 +- update from CVS + - fix xdr_rmtcall_args on 64-bit arches (#151686) +- fix and with -std=c89 -fexceptions (#153774) + +* Mon Apr 4 2005 Jakub Jelinek 2.3.4-20 +- move LinuxThreads libraries to /%%{_lib}/obsolete/linuxthreads/ + and NPTL libraries to /%%{_lib}. To run a program against LinuxThreads, + LD_ASSUME_KERNEL=2.4.xx LD_LIBRARY_PATH=/%%{_lib}/obsolete/linuxthreads/ + is now needed +- bzip2 ChangeLog* files instead of gzipping them + +* Sat Apr 2 2005 Jakub Jelinek 2.3.4-19 +- update from CVS + - fix nextafterl and several other libm routines on ia64 + - fix initgroups (BZ#661) +- kill nptl-devel subpackage, add linuxthreads-devel, + compile and link by default against NPTL and only with + -I/usr/include/linuxthreads -L/usr/%%{_lib}/linuxthreads + against LinuxThreads +- package /usr/lib/debug/%%{_lib}/tls/i{5,6}86 symlinks in + i386 glibc-debuginfo +- limit number of ChangeLog* files in glibc-common %%doc + to last 2.5 years of changes only to save space + +* Fri Mar 25 2005 Jakub Jelinek 2.3.4-18 +- fix build on 64-bit arches with new GCC + +* Thu Mar 24 2005 Jakub Jelinek 2.3.4-17 +- update from CVS + - fix LD_AUDIT in LinuxThreads ld.so + - fix calloc with M_PERTURB + - fix error handling in pthread_create with PTHREAD_EXPLICIT_SCHED + on ppc*/ia64/alpha/mips (BZ#801) + - fix a typo in WINDOWS-31J charmap (#151739) + - fix NIS ypprot_err (#151469) + +* Sun Mar 20 2005 Jakub Jelinek 2.3.4-16 +- fix pread with -D_FILE_OFFSET_BITS=64 (#151573) + +* Sat Mar 19 2005 Jakub Jelinek 2.3.4-15 +- update from CVS + - better fix for the dlclose bug (#145810, #150414) + - fix regex crash on case insensitive search in zh_CN locale + (#151215) + - fix malloc_trim (BZ#779) + - with -D_FORTIFY_SOURCE=*, avoid defining read and a bunch of others + as function-like macros, there are too many broken programs + out there +- add %%dir %%{_prefix}/%%{_lib}/gconv to glibc's file list (#151372) + +* Sun Mar 6 2005 Roland McGrath 2.3.4-14 +- fix bits/socket2.h macro typos + +* Sat Mar 5 2005 Jakub Jelinek 2.3.4-12 +- fix tst-chk{2,3} +- fix up AS_NEEDED directive in /usr/%%{_lib}/libc.so +- BuildReq binutils >= 2.15.94.0.2-1 for AS_NEEDED, in + glibc-devel Conflict with binutils < 2.15.94.0.2-1 + +* Thu Mar 3 2005 Jakub Jelinek 2.3.4-11 +- update from CVS + - fix execvp (#149290) + - fix dlclose (#145810) + - clear padding in gconv-modules.cache (#146614, BZ#776) +- rebuilt with GCC4 +- changed __GLIBC_MINOR__ for now back to 3 +- back out the newly added GLIBC_2.4 *_chk routines, instead + do the checking in macros + +* Sat Feb 12 2005 Jakub Jelinek 2.3.4-10 +- hopefully fix interaction with prelink (#147655) + +* Fri Feb 11 2005 Jakub Jelinek 2.3.4-9 +- update from CVS + - bi-arch (BZ#715) + +* Fri Feb 11 2005 Jakub Jelinek 2.3.4-8 +- update from CVS + - bi-arch (BZ#632) + - fix libdl on s390 and maybe other platforms + - fix initstate{,_r} (BZ#710) + - fix generation (BZ#157) +- define CMSPAR in bits/termios.h (#147533) + +* Tue Feb 8 2005 Jakub Jelinek 2.3.4-7 +- update from CVS + - fix TLS handling in linuxthreads + +* Tue Feb 8 2005 Jakub Jelinek 2.3.4-6 +- update from CVS + - ld.so auditing + - fix segfault if chrooted app attempts to dlopen a library + and no standard library directory exists at all (#147067, #144303) + - fix initgroups when nscd is running, but has group caching disabled + (#146588) + - fix pthread_key_{create,destroy} in LinuxThreads when pthread_create + has not been called yet (#146710) + - fix ppc64 swapcontext and setcontext (#146736, BZ#700) + - service nscd cosmetic fixes (#146776) + - fix IA-32 and x86-64 stack alignment in DSO constructors (#145689) + - fix zdump -v segfaults on x86-64 (#146210) + - avoid calling sigaction (SIGPIPE, ...) inside syslog (#146021, IT#56686) + - fix errno values for futimes (BZ#633) + - unconditionally include in malloc.h (BZ#650) + - change regex \B handling to match old GNU regex as well as perl/grep's dfa + (from empty string inside of word to empty string not at a word boundary, + BZ#693) + - slightly optimize i686 TLS accesses, use direct TLS %%gs access in sem_* + and allow building -mno-tls-direct-seg-refs glibc that is free of direct TLS + %%gs access with negative offsets + - fix addseverity + - fix fmemopen + - fix rewinddir + - increase svc{tcp,unix}_create listen backlog + +* Thu Jan 6 2005 Jakub Jelinek 2.3.4-5 +- update from CVS + - add some warn_unused_result marking + - make ftruncate available even for just -D_POSIX_C_SOURCE=200112L + (BZ#640) + +* Thu Jan 6 2005 Jakub Jelinek 2.3.4-4 +- update from CVS + - fix IA-32 stack alignment for LinuxThreads thread functions + and functions passed to clone(2) directly + - fix ecvt{,_r} on denormals (#143279) + - fix __tls_get_addr typo + - fix rounding in IA-64 alarm (#143710) + - don't reinitialize __environ in __libc_start_main, so that + effects of setenv/putenv done in DSO initializers are preserved + (#144037, IT#57403) + - fix fmemopen + - fix vDSO l_map_end and l_text_end values + - IA64 libm update (#142494) +- fix ppc rint/ceil etc. (BZ#602) + +* Tue Dec 21 2004 Jakub Jelinek 2.3.4-3 +- rebuilt + +* Mon Dec 20 2004 Jakub Jelinek 2.3.4-2 +- work around rpm bug some more, this time by copying + iconvconfig to iconvconfig.%%{_target_cpu}. + +* Mon Dec 20 2004 Jakub Jelinek 2.3.4-1 +- update from CVS + - glibc 2.3.4 release + - add -o and --nostdlib options to iconvconfig +- if /sbin/ldconfig doesn't exist when running + glibc_post_upgrade.%%{_target_cpu}, just don't attempt to run it. + This can happen during first install of bi-arch glibc and the + other arch glibc's %%post wil run /sbin/ldconfig (#143326) +- use -o and --nostdlib options to create all needed + gconv-modules.cache files on bi-arch setups + +* Sun Dec 19 2004 Jakub Jelinek 2.3.3-99 +- rebuilt + +* Sat Dec 18 2004 Jakub Jelinek 2.3.3-98 +- add .%%{_target_cpu} to glibc_post_upgrade, only run telinit u + if /sbin/init is the same ELF class and machine as + glibc_post_upgrade.%%{_target_cpu} and similarly with + condrestarting sshd (#143046) + +* Fri Dec 17 2004 Jakub Jelinek 2.3.3-97 +- update from CVS + - fix ppc64 getcontext and swapcontext (BZ#610) + - sparc/sparc64 fixes + +* Wed Dec 15 2004 Jakub Jelinek 2.3.3-96 +- update from CVS + - fix i686 __USE_STRING_INLINES strncat + - make sure ppc/ppc64 maintain correct stack alignment + across clone + +* Wed Dec 15 2004 Jakub Jelinek 2.3.3-95 +- export nis_domain_of_r from libnsl.so again which was + unintentionally lost + +* Wed Dec 15 2004 Jakub Jelinek 2.3.3-93 +- update from CVS + - ppc/ppc64 clone without CLONE_THREAD getpid () adjustement + - fix MALLOC_CHECK_={1,2,3} for non-contiguous main arena + (BZ#457) + - fix sysconf (_POSIX_V6_*) for other ABI environments in + bi-arch setups +- s390/s390x clone without CLONE_THREAD getpid () adjustement + +* Tue Dec 14 2004 Jakub Jelinek 2.3.3-92 +- update from CVS +- fix %%{_prefix}/libexec/getconf filenames generation + +* Tue Dec 14 2004 Jakub Jelinek 2.3.3-91 +- update from CVS + - double buffer size in getXXbyYY or getXXent on ERANGE + instead of adding BUFLEN (#142617) + - avoid busy loop in malloc if another thread is doing fork + (#142214) + - some more realloc corruption checks + - fix getconf _POSIX_V6_WIDTH_RESTRICTED_ENVS output, + tweak %%{_prefix}/libexec/getconf/ filenames + +* Fri Dec 10 2004 Jakub Jelinek 2.3.3-90 +- update from CVS + - regex speedups + - use | cat in ldd if running under bash3+ to allow running + it on binaries that are not through SELinux allowed to access + console or tty +- add __NR_waitid defines for alpha and ia64 + +* Wed Dec 8 2004 Jakub Jelinek 2.3.3-89 +- update from CVS + - fix clone2 on ia64 + - avoid tst-timer5 failing with linuxthreads implementation +- if __libc_enable_secure, disallow mode != normal +- change ldd script to imply -r when -u is used, properly + propagate return value and handle suid binaries + +* Tue Dec 7 2004 Jakub Jelinek 2.3.3-88 +- update from CVS + - disregard LD_SHOW_AUXV and LD_DYNAMIC_WEAK if __libc_enable_secure + - disregard LD_DEBUG if __libc_enable_secure in normal mode + if /suid-debug doesn't exist + - fix fseekpos after ungetc + - avoid reading bytes before start of buffers in regex's + check_dst_limits_calc_pos_1 (#142060) + - make getpid () working with clone/clone2 without CLONE_THREAD + (so far on i386/x86_64/ia64 only) +- move %%{_prefix}/libexec/getconf/* to glibc from glibc-common +- make %%{_prefix}/libexec/getconf directory owned by glibc package + +* Fri Dec 3 2004 Jakub Jelinek 2.3.3-87 +- update from CVS + - build libpthread_nonshared.a objects with -fPIC on s390/s390x + - fix mktime with < 0 or > 59 tm_sec on entry + - remove nonnull attribute for realpath + - add $(make-target-directory) for errlist-compat.c rule + (hopefully fix #141404) +- add testcase for ungetc bug +- define _POSIX_{,THREAD_}CPUTIME to 0 on all Linux arches + +* Tue Nov 30 2004 Jakub Jelinek 2.3.3-86 +- update from CVS + - some posix_opt.h fixes +- fix strtold use of unitialized memory (#141000) +- some more bugfixes for bugs detected by valgrind +- rebuilt with GCC >= 3.4.3-5 to avoid packed stack layout + on s390{,x} (#139678) + +* Fri Nov 26 2004 Jakub Jelinek 2.3.3-85 +- update from CVS + - support -v specification in getconf + - fix sysconf (_SC_LFS64_CFLAGS) etc. + - avoid thread stack aliasing issues on EM64T (#140803) +- move %%{_prefix}/include/nptl headers from nptl-devel + to glibc-headers, so that even NPTL specific programs + can be built bi-arch without problems + +* Wed Nov 24 2004 Jakub Jelinek 2.3.3-84 +- update from CVS + - fix memory leak in getaddrinfo if using nscd (#139559) + - handle large lines in /etc/hosts and /etc/networks + (#140378) + - add nonnull attributes to selected dirent.h and dlfcn.h + functions + +* Sun Nov 21 2004 Jakub Jelinek 2.3.3-83 +- update from CVS + - add deprecated and/or nonnull attribute to some signal.h + functions + - speed up tzset () by only using stat instead of open/fstat + when calling tzset for the second and following time if + /etc/localtime has not changed +- fix tgamma (BZ #552) + +* Sat Nov 20 2004 Jakub Jelinek 2.3.3-82 +- update from CVS + - some malloc () checking + - libpthread.a object dependency cleanups (#115157) + - fix for -std=c89 -pedantic-errors (#140132) + +* Fri Nov 19 2004 Jakub Jelinek 2.3.3-81 +- don't use chunksize in <= 2 * SIZE_SZ free () checks + +* Fri Nov 19 2004 Jakub Jelinek 2.3.3-80 +- update from CVS + - with -D_FORTIFY_SOURCE=2, prevent missing %%N$ formats + - for -D_FORTIFY_SOURCE=2 and %%n in writable format string, + issue special error message instead of using the buffer overflow + detected one + - speedup regex searching with REG_NOSUB, add RE_NO_SUB, + speedup searching with nested subexps (BZ #544) + - block SIGCANCEL in NPTL timer_* helper thread +- further free () checking + +* Tue Nov 16 2004 Jakub Jelinek 2.3.3-79 +- update from CVS +- fix free () checking +- move /etc/default/nss into glibc-common (hopefully fix #132392) + +* Mon Nov 15 2004 Jakub Jelinek 2.3.3-78 +- update from CVS + - fix LD_DEBUG=statistics + - issue error message before aborting in __chk_fail () +- some more free () checking + +* Fri Nov 12 2004 Jakub Jelinek 2.3.3-77 +- update from CVS + - speedup regex on palindromes (BZ #429) + - fix NPTL set{,e,re,res}[ug]id, so that even if making process + less priviledged all threads change their credentials successfully + +* Wed Nov 10 2004 Jakub Jelinek 2.3.3-76 +- update from CVS + - fix regcomp crash (#138439) + - fix ftell{,o,o64} (#137885) + - robustification of nscd to cope with corrupt databases (#137140) + - fix NPTL with pthread_exit immediately after pthread_create (BZ #530) + - some regex optimizations + +* Tue Nov 2 2004 Jakub Jelinek 2.3.3-75 +- update from CVS + - mktime cleanups (BZ #487, #473) + - unique comments in free(3) check error messages +- adjust some x86_64 headers for -m32 (#129712) +- object size checking support even with GCC-3.4.2-RH >= 3.4.2-8 + +* Wed Oct 27 2004 Jakub Jelinek 2.3.3-74 +- fix header +- fix globfree (#137176) +- fix exiting if there are dlmopened libraries in namespaces + other than main one not closed yet +- export again _res_opcodes and __p_{class,type}_syms from + libresolv.so that were lost in -69 + +* Thu Oct 21 2004 Jakub Jelinek 2.3.3-73 +- remove setaltroot and key{_add,_request,ctl} also from Versions +- back out _sys_errlist changes + +* Thu Oct 21 2004 Jakub Jelinek 2.3.3-72 +- back out setaltroot and key{_add,_request,ctl} addition +- fix severe x86-64 symbol versioning regressions that breaks + e.g. java binaries + +* Wed Oct 20 2004 Jakub Jelinek 2.3.3-71 +- update from CVS + - fix minor catchsegv temp file handling vulnerability + (CAN-2004-0968, #136319) + - add 4 new errno codes + - setaltroot, key{_add,_request,ctl} syscalls on some arches + - export _dl_debug_state@GLIBC_PRIVATE from ld.so again for + gdb purpose + - use inet_pton to decide what is address and what is hostname + in getent (#135422) + - change dladdr/dladdr1, so that dli_saddr is the same kind + of value as dlsym/dlvsym return (makes difference on ia64/hppa only) + - fix catchsegv script so that it works with both 32-bit and 64-bit + programs on multi-arch platforms + +* Tue Oct 19 2004 Jakub Jelinek 2.3.3-70 +- update from CVS +- require newer selinux-policy (#135978) +- add %%dir for /var/run/nscd and /var/db/nscd and %%ghost + files in it +- conflict with gcc4 4.0.0-0.6 and earlier (needs __builtin_object_size) + +* Mon Oct 18 2004 Jakub Jelinek 2.3.3-69 +- update from CVS + - object size checking support (-D_FORTIFY_SOURCE={1,2}) + +* Thu Oct 14 2004 Jakub Jelinek 2.3.3-68 +- update from CVS + - support for namespaces in the dynamic linker + - fix dlclose (BZ #77) + - libSegFault.so uses now backtrace() to work on IA-64, x86-64 + and s390 (#130254) + +* Tue Oct 12 2004 Jakub Jelinek 2.3.3-67 +- update from CVS + - use non-blocking sockets in resolver (#135234) + - reset pd->res options on thread exit, so that threads + reusing cached stacks get resolver state properly initialized + (BZ #434) + +* Wed Oct 6 2004 Jakub Jelinek 2.3.3-66 +- update from CVS +- avoid using perl in the spec file, buildrequire sed >= 3.95 + (#127671) +- export TIMEOUTFACTOR=16 +- fix _JMPBUF_CFA_UNWINDS_ADJ on s390{,x} + +* Tue Oct 5 2004 Jakub Jelinek 2.3.3-65 +- update from CVS + - define _POSIX_THREAD_PROCESS_SHARED and _POSIX_CLOCK_SELECTION + to -1 in LinuxThreads + - define _POSIX_CPUTIME and _POSIX_THREAD_CPUTIME to 0 + on i?86/ia64 and make sure sysconf (_SC_{,THREAD_}CPUTIME) + returns correct value +- if _POSIX_CLOCK_SELECTION == -1 in nscd, still try + sysconf (_SC_CLOCK_SELECTION) and if it returns true, + dlopen libpthread.so and dlsym pthread_condattr_setclock +- build nscd with -z relro and -z now + +* Mon Oct 4 2004 Jakub Jelinek 2.3.3-64 +- update from CVS + - stop using __builtin_expect in assert and assert_perror + (#127606) + - try to avoid too much VA fragmentation with malloc + on flexmap layout (#118574) + - nscd robustification + - change valloc to use debugging hooks (#134385) +- make glibc_post_upgrade more verbose on errors (Fergal Daly, + #125700) + +* Fri Oct 1 2004 Jakub Jelinek 2.3.3-63 +- update from CVS + - fix __nscd_getgrouplist + - fix a typo in x86_64 pthread_mutex_timedwait fix + +* Fri Oct 1 2004 Jakub Jelinek 2.3.3-62 +- update from CVS + - fix NPTL pthread_mutex_timedwait on i386/x86_64 (BZ #417) + +* Thu Sep 30 2004 Jakub Jelinek 2.3.3-61 +- update from CVS + - some nscd fixes (#134193) + - cache initgroups in nscd (#132850) + - reread /etc/localtime in tzset () even if just mtime changed + (#133481) + - fix glob (#126460) + - another get_myaddress fix + +* Wed Sep 29 2004 Jakub Jelinek 2.3.3-60 +- update from CVS + - fix get_myaddress (#133982) + - remove nonnull attribute from second utime argument (#133866) + - handle SIGSETXID the same way as SIGCANCEL in + sigaction/pthread_kill/sigwait/sigwaitinfo etc. + - add __extension__ to long long types in NPTL + +* Mon Sep 27 2004 Jakub Jelinek 2.3.3-59 +- update from CVS + - fix BZ #151, #362, #381, #407 + - fdim fix for +inf/+inf (BZ #376) + +* Sun Sep 26 2004 Jakub Jelinek 2.3.3-58 +- update from CVS + - vasprintf fix (BZ #346) + - gettext locking (BZ #322) +- change linuxthreads useldt.h inclusion login again, the last + one failed all linuxthreads FLOATING_STACKS tests + +* Sat Sep 25 2004 Jakub Jelinek 2.3.3-57 +- update from CVS + - fix setuid in LD_ASSUME_KERNEL=2.2.5 libc (#133558) + - fix nis locking (#132204) + - RTLD_DEEPBIND support + - fix pthread_create bugs (BZ #401, #405) + +* Wed Sep 22 2004 Roland McGrath 2.3.3-56 +- migrated CVS to fedora-branch in sources.redhat.com glibc repository + - source tarballs renamed + - redhat/ moved to fedora/, some old cruft removed +- update from trunk + - some __nonnull annotations + +* Wed Sep 22 2004 Jakub Jelinek 2.3.3-55 +- update from CVS + - set{re,e,res}[ug]id now affect the whole process in NPTL + - return EAGAIN instead of ENOMEM when not enough memory + in pthread_create + +* Fri Sep 17 2004 Jakub Jelinek 2.3.3-54 +- update from CVS + - nscd getaddrinfo caching + +* Tue Sep 14 2004 Jakub Jelinek 2.3.3-53 +- restore temporarily old definition of __P()/__PMT() + for third party apps + +* Tue Sep 14 2004 Jakub Jelinek 2.3.3-52 +- update from CVS + - nscd bi-arch fix + - remove all uses of __P()/__PMT() from glibc headers +- update and reenable nscd SELinux patch +- remove libnss1* and libnss*.so.1 compatibility NSS modules + on IA-32, SPARC and Alpha + +* Fri Sep 10 2004 Jakub Jelinek 2.3.3-51 +- update from CVS + - disable one of the malloc double free checks for non-contiguous + arenas where it doesn't have to be true even for non-broken + apps + +* Thu Sep 9 2004 Jakub Jelinek 2.3.3-50 +- update from CVS + - pwd/grp/host loops with nscd speed up by sharing the + nscd cache r/o with applications + - inexpensive double free check in free(3) + - make NPTL pthread.h initializers usable even from C++ + (BZ #375) +- use atomic instructions even in i386 nscd on i486+ CPUs + (conditionally) + +* Fri Sep 3 2004 Jakub Jelinek 2.3.3-49 +- update from CVS +- fix linuxthreads tst-cancel{[45],-static} + +* Fri Sep 3 2004 Jakub Jelinek 2.3.3-48 +- update from CVS + - fix pthread_cond_destroy (BZ #342) + - fix fnmatch without FNM_NOESCAPE (BZ #361) + - fix ppc32 setcontext (BZ #357) +- add NPTL support for i386 glibc (only if run on i486 or higher CPU) +- add __NR_waitid defines for i386, x86_64 and sparc* + +* Tue Aug 31 2004 Jakub Jelinek 2.3.3-47 +- update from CVS + - persistent nscd caching + - ppc64 32-bit atomicity fix + - fix x86-64 nptl-devel headers for -m32 compilation +- %%ghost /etc/ld.so.cache (#130597) +- edit /etc/ld.so.conf in glibc_post_upgrade if + include ld.so.conf.d/*.conf line is missing (#120588) +- ugly hacks for the IA-64 /emul braindamage (#124996, #128267) + +* Sat Aug 21 2004 Jakub Jelinek 2.3.3-46 +- update from CVS + +* Thu Aug 19 2004 Jakub Jelinek 2.3.3-45 +- update from CVS + - fix nss_compat's initgroups handling (#130363) + - fix getaddrinfo ai_canonname setting + +* Thu Aug 19 2004 Jakub Jelinek 2.3.3-44 +- update from CVS + - add ip6-dotint resolv.conf option, make + no-ip6-dotint the default +- BuildPrereq libselinux-devel (#129946) +- on ppc64, build without dot symbols + +* Thu Aug 12 2004 Jakub Jelinek 2.3.3-43 +- update from CVS + - remove debugging printout (#129747) + - make usable in C++ (IT#45148) +- update RLIMIT_* constants in , make + POSIX compliant (#129740) + +* Wed Aug 11 2004 Jakub Jelinek 2.3.3-42 +- fix last tzset () fixes, disable rereading of /etc/localtime + every time for now +- really enable SELinux support for NSCD + +* Wed Aug 11 2004 Jakub Jelinek 2.3.3-41 +- update from CVS + - fread_unlocked/fwrite_unlocked macro fixes (BZ #309, #316) + - tzset () fixes (BZ #154) +- speed up pthread_rwlock_unlock on arches other than i386 and + x86_64 (#129455) +- fix compilation with -ansi (resp. -std=c89 or -std=c99) and + -D_XOPEN_SOURCE=[56]00 but no -D_POSIX_SOURCE* or -D_POSIX_C_SOURCE* + (BZ #284) +- add SELinux support for NSCD + +* Fri Aug 6 2004 Jakub Jelinek 2.3.3-40 +- update from CVS + - change res_init to force all threads to re-initialize + resolver before they use it next time (#125712) + - various getaddrinfo and related fixes (BZ #295, #296) + - fix IBM{932,943} iconv modules (#128674) + - some nscd fixes (e.g. BZ #292) + - RFC 3678 support (Multicast Source Filters) +- handle /lib/i686/librtkaio-* in i386 glibc_post_upgrade + the same as /lib/i686/librt-* + +* Fri Jul 23 2004 Jakub Jelinek 2.3.3-39 +- update from CVS + - conformance related changes in headers +- remove -finline-limit=2000 for GCC 3.4.x+ + +* Thu Jul 22 2004 Jakub Jelinek 2.3.3-38 +- update from CVS + - fix res_init leaks + - fix newlocale races + - fix ppc64 setjmp +- fix strtold (BZ #274) + +* Fri Jul 16 2004 Jakub Jelinek 2.3.3-37 +- update from CVS + - allow pthread_cancel in DSO destructors run at exit time +- fix pow{f,,l} on IA-32 and powl on x86-64 +- allow PIEs on IA-32 to have main in a shared library they depend on + +* Mon Jul 5 2004 Jakub Jelinek 2.3.3-36 +- s390* .plt slot reduction +- fix pthread_rwlock_timedrdlock on x86_64 + +* Wed Jun 30 2004 Jakub Jelinek 2.3.3-35 +- tweak spec file for the libpthread-0.61.so -> libpthread-2.3.3.so + NPTL changes + +* Wed Jun 30 2004 Jakub Jelinek 2.3.3-34 +- update from CVS + - if_nameindex using preferably netlink + - printf_parsemb initialization fix + - NPTL version is now the same as glibc version + +* Mon Jun 28 2004 Jakub Jelinek 2.3.3-33 +- update from CVS + - reread resolv.conf for nscd --invalidate=hosts + - fix F_GETLK/F_SETLK/F_SETLKW constants on x86_64 for + -m32 -D_FILE_OFFSET_BITS=64 compilations + - avoid calling non-existing fcntl64 syscall on ppc64 + +* Mon Jun 14 2004 Jakub Jelinek 2.3.3-32 +- update from CVS + - FUTEX_CMP_REQUEUE support (fix pthread_cond_* deadlocks) + - fix backtrace in statically linked programs +- rebuilt with GCC 3.4, adjusted ulps and i386 + +* Fri May 28 2004 Jakub Jelinek 2.3.3-31 +- update from CVS +- and changes for GCC 3.{2,4,5}+ +- make c_stubs buildable even with GCC 3.2.x (#123042) + +* Fri May 21 2004 Jakub Jelinek 2.3.3-30 +- fix pthread_cond_wait on architectures other than IA-32 and + x86_64 + +* Thu May 20 2004 Jakub Jelinek 2.3.3-29 +- use lib64 instead of lib on ia64 if %%{_lib} is defined to lib64 + +* Wed May 19 2004 Jakub Jelinek 2.3.3-28 +- update from CVS + - FUTEX_REQUEUE fixes (#115349) + - SPARC GCC 3.4 build fix + - fix handling of undefined TLS symbols on IA32 (RELA only), + SPARC and SH + - regex translate fix + - speed up sprintf + - x86_64 makecontext alignment fix + - make POSIX sigpause the default sigpause, unless BSD sigpause + requested + +* Tue May 11 2004 Jakub Jelinek 2.3.3-27 +- remove /lib64/tls/librtkaio-2.3.[23].so in glibc_post_upgrade + on x86-64, s390x and ppc64 instead of /lib/tls/librtkaio-2.3.[23].so +- build mq_{send,receive} with -fexceptions + +* Fri May 7 2004 Jakub Jelinek 2.3.3-26 +- update from CVS + - fix + - fix memory leaks in nis, getifaddrs, etc. caused by incorrect + use of realloc +- remove /lib/{tls,i686}/librtkaio-2.3.[23].so in glibc_post_upgrade + and rerun ldconfig if needed, otherwise after glibc upgrade librt.so.1 + might be a stale symlink + +* Wed May 5 2004 Jakub Jelinek 2.3.3-25 +- update from CVS +- disable FUTEX_REQUEUE (work around #115349) +- mq for sparc/sparc64/ia64 + +* Tue May 4 2004 Jakub Jelinek 2.3.3-24 +- update from CVS + - define S_ISSOCK in -D_XOPEN_SOURCE=600 and S_I[FS]SOCK + plus F_[SG]ETOWN also in -D_XOPEN_SOURCE=500 (both + included already in XNS5) + - reorder dlopen checks, so that dlopening ET_REL objects + complains about != ET_DYN != ET_EXEC, not about phentsize + (#121606) + - fix strpbrk macro for GCC 3.4+ (BZ #130) + - fix (BZ #140) + - sched_[gs]etaffinity documentation fix (BZ #131) + - fix sparc64 build (BZ #139) + - change linuxthreads back to use non-cancellable writes + to manager pipes etc. + - fix sem_timedwait return value in linuxthreads (BZ #133) + - ia64 unnecessary PLT relocs removal + +* Thu Apr 22 2004 Jakub Jelinek 2.3.3-23 +- update from CVS + - fix *scanf + - fix shm_unlink, sem_unlink and mq_unlink errno values + - avoid memory leaks in error + - execstack fixes on s390 + +* Mon Apr 19 2004 Jakub Jelinek 2.3.3-22 +- update from CVS + - mq and timer fixes +- rebuilt with binutils >= 2.15.90.0.3-2 to fix IA-64 statically + linked binaries +- fix linuxthreads librt.so on s390{,x}, so it is no longer DT_TEXTREL + +* Sat Apr 17 2004 Jakub Jelinek 2.3.3-21 +- disable rtkaio +- update from CVS + - POSIX message passing support + - fixed SIGEV_THREAD support for POSIX timers + - fix free on non-malloced memory in syslog + - fix ffsl on some 64-bit arches + - fix sched_setaffinity on x86-64, ia64 + - fix ppc64 umount + - NETID_AUTHORITATIVE, SERVICES_AUTHORITATIVE support + - various NIS speedups + - fix fwrite with > 2GB sizes on 64-bit arches + - fix pthread_getattr_np guardsize reporting in NPTL +- report PLT relocations in ld.so and libc.so during the build + +* Thu Mar 25 2004 Jakub Jelinek 2.3.3-20 +- update from CVS + - change NPTL PTHREAD_MUTEX_ADAPTIVE_NP mutexes to spin on SMP + - strtol speed optimization + - don't try to use certainly unimplemented syscalls on ppc64 +- kill -debug subpackage, move the libs to glibc-debuginfo{,-common} + into /usr/lib/debug/usr/%%{_lib}/ directory +- fix c_stubs with gcc 3.4 +- move all the up to 3 builds into %%build scriptlet and + leave only installation in the %%install scriptlet + +* Mon Mar 22 2004 Jakub Jelinek 2.3.3-19 +- update from CVS + - affinity API changes + +* Thu Mar 18 2004 Jakub Jelinek 2.3.3-18 +- update from CVS + - fix ia64 iopl (#118591) + - add support for /etc/ld.so.conf.d/*.conf + - fix x86-64 LD_DEBUG=statistics +- fix hwcap handling when using ld.so.cache (#118518) + +* Mon Mar 15 2004 Jakub Jelinek 2.3.3-17 +- update from CVS + - implement non-_l function on top of _l functions + +* Thu Mar 11 2004 Jakub Jelinek 2.3.3-16 +- update from CVS +- fix s390{,x} TLS handling + +* Wed Mar 10 2004 Jakub Jelinek 2.3.3-15 +- update from CVS + - special section for compatibility code + - make getpid () work even in vfork () child +- configure with --enable-bind-now to avoid lazy binding in ld.so + and libc.so + +* Fri Mar 5 2004 Jakub Jelinek 2.3.3-14 +- update from CVS + - fix iconv -c (#117021) + - fix PIEs on sparc/sparc64 + - fix posix_fadvise on 64-bit architectures +- add locale-archive as %%ghost file (#117014) + +* Mon Mar 1 2004 Jakub Jelinek 2.3.3-13 +- update from CVS + +* Fri Feb 27 2004 Jakub Jelinek 2.3.3-12 +- update from CVS + +* Fri Feb 27 2004 Jakub Jelinek 2.3.3-11 +- update from CVS + - fix ld.so when vDSO is randomized + +* Fri Feb 20 2004 Jakub Jelinek 2.3.3-10 +- update from CVS + +* Fri Feb 20 2004 Jakub Jelinek 2.3.3-9 +- update from CVS + +* Tue Feb 10 2004 Jakub Jelinek 2.3.3-8 +- update from CVS + +* Tue Jan 27 2004 Jakub Jelinek 2.3.3-7 +- update from CVS + - dl_iterate_phdr extension to signal number of added/removed + libraries +- fix PT_GNU_RELRO support on ppc* with prelinking + +* Fri Jan 23 2004 Jakub Jelinek 2.3.3-6 +- rebuilt with fixed GCC on IA-64 + +* Thu Jan 22 2004 Jakub Jelinek 2.3.3-5 +- fix PT_GNU_RELRO support + +* Wed Jan 21 2004 Jakub Jelinek 2.3.3-4 +- update from CVS + - some further regex speedups + - fix re.translate handling in regex (#112869) + - change regfree to match old regex behaviour (what is freed + and clearing of freed pointers) + - fix accesses to unitialized memory in regex (#113507, #113425, + #113421) + - PT_GNU_RELRO support + +* Tue Dec 30 2003 Jakub Jelinek 2.3.3-3 +- update from CVS + - fix pmap_set fd and memory leak (#112726) +- fix backreference handling in regex +- rebuilt under glibc without the above bug to fix + libc.so linker script (#112738) + +* Mon Dec 29 2003 Jakub Jelinek 2.3.3-2 +- update from CVS + - faster getpid () in NPTL builds + - fix to make pthread_setcancelstate (PTHREAD_CANCEL_DISABLE, ) + really disable cancellation (#112512) + - more regex fixes and speedups + - fix nextafter*/nexttoward* + - handle 6th syscall(3) argument on AMD64 + - handle memalign/posix_memalign in mtrace + - fix linuxthreads memory leak (#112208) + - remove throw () from cancellation points in linuxthreads (#112602) + - fix NPTL unregister_atfork + - fix unwinding through alternate signal stacks + +* Mon Dec 1 2003 Jakub Jelinek 2.3.3-1 +- update from CVS + - 2.3.3 release + - lots of regex fixes and speedups (#110401) + - fix atan2 + - fix pshared condvars in NPTL + - fix pthread_attr_destroy for attributes created with + pthread_attr_init@GLIBC_2.0 +- for the time being, include both nb_NO* and no_NO* as locales + so that the distribution can catch up with the no_NO->nb_NO + transition +- add BuildPrereq texinfo (#110252) + +* Tue Nov 18 2003 Jakub Jelinek 2.3.2-102 +- update from CVS + - fix getifaddrs (CAN-2003-0859) + - fix ftw fd leak + - fix linuxthreads sigaction (#108634) + - fix glibc 2.0 stdio compatibility + - fix uselocale (LC_GLOBAL_LOCALE) + - speed up stdio locking in non-threaded programs on IA-32 + - try to maintain correct order of cleanups between those + registered with __attribute__((cleanup)) + and with LinuxThreads style pthread_cleanup_push/pop (#108631) + - fix segfault in regex (#109606) + - fix RE_ICASE multi-byte handling in regex + - fix pthread_exit in libpthread.a (#109790) + - FTW_ACTIONRETVAL support + - lots of regex fixes and speedups + - fix ceill/floorl on AMD64 + +* Mon Oct 27 2003 Jakub Jelinek 2.3.2-101 +- update from CVS + - fix ld.so --verify (and ldd) + +* Mon Oct 27 2003 Jakub Jelinek 2.3.2-100 +- update from CVS + - fix sprof (#103727) + - avoid infinite loops in {,f}statvfs{,64} with hosed mounts file + - prevent dlopening of executables + - fix glob with GLOB_BRACE and without GLOB_NOESCAPE + - fix locale printing of word values on 64-bit big-endian arches + (#107846) + - fix getnameinfo and getaddrinfo with reverse IPv6 lookups + (#101261) + +* Wed Oct 22 2003 Jakub Jelinek 2.3.2-99 +- update from CVS + - dl_iterate_phdr in libc.a on arches other than IA-64 + - LD_DEBUG=statistics prints number of relative relocations + - fix hwcap computation +- NPTL is now part of upstream glibc CVS +- include {st,xh,zu}_ZA{,.UTF-8} locales + +* Sat Oct 4 2003 Jakub Jelinek 2.3.2-98 +- update from CVS + - fix close, pause and fsync (#105348) + - fix pthread_once on IA-32 +- implement backtrace () on IA-64, handle -fomit-frame-pointer + in AMD64 backtrace () (#90402) + +* Tue Sep 30 2003 Jakub Jelinek 2.3.2-97 +- update from CVS + - fix with C++ or -ansi or -pedantic C + - fix mknod/ustat return value when given bogus device number (#105768) + +* Fri Sep 26 2003 Jakub Jelinek 2.3.2-96 +- rebuilt + +* Fri Sep 26 2003 Jakub Jelinek 2.3.2-95 +- fix IA-64 getcontext + +* Thu Sep 25 2003 Jakub Jelinek 2.3.2-94 +- update from CVS +- fix syslog with non-C non-en_* locales (#61296, #104979) +- filter GLIBC_PRIVATE symbols from glibc provides +- fix NIS+ + +* Thu Sep 25 2003 Jakub Jelinek 2.3.2-93 +- update from CVS +- assume 2.4.21 kernel features on RHEL/ppc*, so that + {make,set,get,swap}context works +- backout execstack support for RHEL +- build rtkaio on amd64 too + +* Wed Sep 24 2003 Jakub Jelinek 2.3.2-92 +- update from CVS + - execstack/noexecstack support + - build nscd as PIE +- move __libc_stack_end back to @GLIBC_2.1 +- build against elfutils >= 0.86 to fix stripping on s390x + +* Mon Sep 22 2003 Jakub Jelinek 2.3.2-91 +- rebuilt + +* Mon Sep 22 2003 Jakub Jelinek 2.3.2-90 +- update from CVS + - NPTL locking change (#102682) +- don't jump around lock on amd64 + +* Thu Sep 18 2003 Jakub Jelinek 2.3.2-89 +- fix open_memstream/syslog (#104661) + +* Thu Sep 18 2003 Jakub Jelinek 2.3.2-88 +- update from CVS + - retrieve affinity in pthread_getattr_np + - fix pthread_attr_[gs]etaffinity_np + - handle hex and octal in wordexp + +* Wed Sep 17 2003 Jakub Jelinek 2.3.2-87 +- update from CVS + - truncate instead of round in utimes when utimes syscall is not available + - don't align stack in every glibc function unnecessarily on IA-32 + - make sure threads have their stack 16 byte aligned on IA-32 + - move sched_[sg]etaffinity to GLIBC_2.3.3 symbol version (#103231) + - fix pthread_getattr_np for the initial thread (#102683) + - avoid linuxthreads signal race (#104368) +- ensure all gzip invocations are done with -n option + +* Fri Sep 12 2003 Jakub Jelinek 2.3.2-86 +- update from CVS +- avoid linking in libgcc_eh.a unnecessarily +- change ssize_t back to long int on s390 -m31, unless + gcc 2.95.x is used + +* Wed Sep 10 2003 Jakub Jelinek 2.3.2-85 +- update from CVS + - fix IA-64 memccpy (#104114) + +* Tue Sep 9 2003 Jakub Jelinek 2.3.2-84 +- update from CVS + - undo broken amd64 signal context changes + +* Tue Sep 9 2003 Jakub Jelinek 2.3.2-83 +- update from CVS +- change *nlink_t, *ssize_t and *intptr_t types on s390 -m31 to + {unsigned,} int +- change *u_quad_t, *quad_t, *qaddr_t, *dev_t, *ino64_t, *loff_t, + *off64_t, *rlim64_t, *blkcnt64_t, *fsblkcnt64_t, *fsfilcnt64_t + on 64-bit arches from {unsigned,} long long int {,*} to + {unsigned,} long int {,*} to restore binary compatibility + for C++ functions using these types as arguments + +* Sun Sep 7 2003 Jakub Jelinek 2.3.2-82 +- rebuilt + +* Sat Sep 6 2003 Jakub Jelinek 2.3.2-81 +- update from CVS + - fix tc[gs]etattr/cf[gs]et[io]speed on ppc (#102732) + - libio fixes + +* Thu Sep 4 2003 Jakub Jelinek 2.3.2-80 +- update from CVS + - fix IA-64 cancellation when mixing __attribute__((cleanup ())) + and old-style pthread_cleanup_push cleanups + +* Tue Sep 2 2003 Jakub Jelinek 2.3.2-79 +- updated from CVS + - lots of cancellation fixes + - fix posix_fadvise* on ppc32 + - TLS layout fix + - optimize stdio cleanups (#103354) + - sparcv9 NPTL + - include sigset, sighold, sigrelse, sigpause and sigignore prototypes + in signal.h even if -D_XOPEN_SOURCE_EXTENDED (#103269) + - fix svc_getreqset on 64-bit big-endian arches + - return ENOSYS in linuxthreads pthread_barrierattr_setpshared for + PTHREAD_PROCESS_SHARED + - add pthread_cond_timedwait stubs to libc.so (#102709) +- split glibc-devel into glibc-devel and glibc-headers to ensure + amd64 /usr/include always wins on amd64/i386 bi-arch installs +- increase PTHREAD_STACK_MIN on alpha, ia64 and sparc* +- get rid of __syscall_* prototypes and stubs in sysdeps/unix/sysv/linux +- run make check also with linuxthreads (on IA-32 non-FLOATING_STACKS) + ld.so and NPTL (on IA-32 also FLOATING_STACKS linuxthreads) libraries + and tests + +* Mon Aug 25 2003 Jakub Jelinek 2.3.2-78 +- include dl-osinfo.h only in glibc-debuginfo-2*.rpm, not + in glibc-debuginfo-common* + +* Mon Aug 25 2003 Jakub Jelinek 2.3.2-77 +- update from CVS + - fix glibc 2.0 libio compatibility (#101385) + - fix ldconfig with /usr/lib/lib*.so symlinks (#102853) + - fix assert.h (#102916, #103017) + - make ld.so.cache identical between IA-32 and AMD64 (#102887) + - fix static linking of large IA-64 binaries (#102586) +- avoid using floating point regs in lazy binding code on ppc64 (#102763) + +* Fri Aug 22 2003 Roland McGrath 2.3.2-76 +- add td_thr_tls_get_addr changes missed in initial nptl_db rewrite + +* Sun Aug 17 2003 Roland McGrath 2.3.2-74 +- nptl_db rewrite not yet in CVS + +* Thu Aug 14 2003 Jakub Jelinek 2.3.2-72 +- update from CVS + - fix rtkaio aio_fsync{,64} + - update rtkaio for !BROKEN_THREAD_SIGNALS + - fix assert macro when used on pointers + +* Wed Aug 13 2003 Jakub Jelinek 2.3.2-71 +- update from CVS + +* Tue Aug 12 2003 Jakub Jelinek 2.3.2-70 +- update from CVS +- disable CLONE_STOPPED for now until it is resolved +- strip crt files +- fix libio on arches with no < GLIBC_2.2 support (#102102, #102105) +- fix glibc-debuginfo to include all nptl and nptl_db sources + +* Thu Aug 7 2003 Jakub Jelinek 2.3.2-69 +- update from CVS + - fix pthread_create@GLIBC_2.0 (#101767) +- __ASSUME_CLONE_STOPPED on all arches but s390* in RHEL + +* Sun Aug 3 2003 Jakub Jelinek 2.3.2-68 +- update from CVS + - only use CLONE_STOPPED if kernel supports it, fix setting of thread + explicit scheduling (#101457) + +* Fri Aug 1 2003 Jakub Jelinek 2.3.2-67 +- update from CVS + - fix utimes and futimes if kernel doesn't support utimes syscall + - fix s390 ssize_t type + - fix dlerror when called before any dlopen/dlsym + - update IA-64 bits/sigcontext.h (#101344) + - various warning fixes + - fix pthread.h comment typos (#101363) + +* Wed Jul 30 2003 Jakub Jelinek 2.3.2-66 +- update from CVS +- fix dlopen of libraries using TLS IE/LE models + +* Tue Jul 29 2003 Jakub Jelinek 2.3.2-65 +- update from CVS + - fix timer_create + - use __extension__ before long long typedefs in (#100718) + +* Mon Jul 28 2003 Jakub Jelinek 2.3.2-64 +- update from CVS + - fix wcpncpy (#99462) + - export _res@GLIBC_2.0 even from NPTL libc.so (__res_state () + unlike __errno_location () or __h_errno_location () was introduced + in glibc 2.2) + - fix zic bug on 64-bit platforms + - some TLS handling fixes + - make ldconfig look into alternate ABI dirs by default (#99402) +- move %%{_datadir}/zoneinfo to tzdata package, so that it can be + errataed separately from glibc +- new add-on - rtkaio +- prereq libgcc, as glibc now relies on libgcc_s.so.1 for pthread_cancel + +* Tue Jul 15 2003 Jakub Jelinek 2.3.2-63 +- fix thread cancellation on ppc64 + +* Sat Jul 12 2003 Jakub Jelinek 2.3.2-62 +- update from CVS + - fix thread cancellation on ppc32, s390 and s390x + +* Thu Jul 10 2003 Jakub Jelinek 2.3.2-61 +- update from CVS + - build libc_nonshared.a with -fPIC instead of -fpic +- fix ppc64 PIE support +- add cfi directives to NPTL sysdep-cancel.h on ppc/ppc64/s390/s390x + +* Tue Jul 8 2003 Jakub Jelinek 2.3.2-60 +- update from CVS + +* Thu Jul 3 2003 Jakub Jelinek 2.3.2-59 +- update from CVS +- on IA-64 use different symbols for cancellation portion of syscall + handlers to make gdb happier + +* Thu Jun 26 2003 Jakub Jelinek 2.3.2-58 +- update from CVS + - nss_compat supporting LDAP etc. + +* Tue Jun 24 2003 Jakub Jelinek 2.3.2-57 +- update from CVS + +* Thu Jun 19 2003 Jakub Jelinek 2.3.2-56 +- fix condvars and semaphores in ppc* NPTL +- fix test-skeleton.c reporting of timed-out tests (#91269) +- increase timeouts for tests during make check + +* Wed Jun 18 2003 Jakub Jelinek 2.3.2-55 +- make ldconfig default to both /lib+/usr/lib and /lib64+/usr/lib64 + on bi-ABI architectures (#97557) +- disable FUTEX_REQUEUE on ppc* temporarily + +* Wed Jun 18 2003 Jakub Jelinek 2.3.2-54 +- update from CVS +- fix glibc_post_upgrade on ppc + +* Tue Jun 17 2003 Jakub Jelinek 2.3.2-53 +- update from CVS +- fix localedef (#90659) +- tweak linuxthreads for librt cancellation + +* Mon Jun 16 2003 Jakub Jelinek 2.3.2-52 +- update from CVS + +* Thu Jun 12 2003 Jakub Jelinek 2.3.2-51 +- update from CVS +- fix (#97169) + +* Wed Jun 11 2003 Jakub Jelinek 2.3.2-50 +- update from CVS + +* Tue Jun 10 2003 Jakub Jelinek 2.3.2-49 +- update from CVS + - fix pthread_cond_signal on IA-32 (#92080, #92253) + - fix setegid (#91567) +- don't prelink -R libc.so on any architecture, it prohibits + address randomization + +* Thu Jun 5 2003 Jakub Jelinek 2.3.2-48 +- update from CVS + - fix IA-64 NPTL build + +* Thu Jun 5 2003 Jakub Jelinek 2.3.2-47 +- update from CVS +- PT_GNU_STACK segment in binaries/executables and .note.GNU-stack + section in *.[oa] + +* Sun Jun 1 2003 Jakub Jelinek 2.3.2-46 +- update from CVS +- enable NPTL on AMD64 +- avoid using trampolines in localedef + +* Thu May 29 2003 Jakub Jelinek 2.3.2-45 +- enable NPTL on IA-64 + +* Thu May 29 2003 Jakub Jelinek 2.3.2-44 +- update from CVS +- enable NPTL on s390 and s390x +- make __init_array_start etc. symbols in elf-init.oS hidden undefined + +* Thu May 29 2003 Jakub Jelinek 2.3.2-43 +- update from CVS + +* Fri May 23 2003 Jakub Jelinek 2.3.2-42 +- update from CVS + +* Tue May 20 2003 Jakub Jelinek 2.3.2-41 +- update from CVS +- use NPTL libs if uname -r contains nptl substring or is >= 2.5.69 + or set_tid_address syscall is available instead of checking + AT_SYSINFO dynamic tag + +* Thu May 15 2003 Jakub Jelinek 2.3.2-40 +- update from CVS + +* Wed May 14 2003 Jakub Jelinek 2.3.2-39 +- update from CVS + - fix for prelinking of libraries with no dependencies + +* Tue May 13 2003 Jakub Jelinek 2.3.2-38 +- update from CVS +- enable NPTL on ppc and ppc64 + +* Tue May 6 2003 Matt Wilson 2.3.2-37 +- rebuild + +* Sun May 4 2003 Jakub Jelinek 2.3.2-36 +- update from CVS + +* Sat May 3 2003 Jakub Jelinek 2.3.2-35 +- update from CVS + - make -jN build fixes + +* Fri May 2 2003 Jakub Jelinek 2.3.2-34 +- update from CVS +- avoid using trampolines in iconvconfig for now + +* Sat Apr 26 2003 Jakub Jelinek 2.3.2-33 +- update from CVS + +* Fri Apr 25 2003 Jakub Jelinek 2.3.2-32 +- update from CVS +- more ppc TLS fixes + +* Wed Apr 23 2003 Jakub Jelinek 2.3.2-31 +- update from CVS + - nscd fixes + - fix Bahrain spelling (#56298) + - fix Ukrainian collation (#83973) + - accept trailing spaces in /etc/ld.so.conf (#86032) + - perror fix (#85994) + - fix localedef (#88978) + - fix getifaddrs (#89026) + - fix strxfrm (#88409) +- fix ppc TLS +- fix getaddrinfo (#89448) +- don't print warning about errno, h_errno or _res if + LD_ASSUME_KERNEL=2.4.1 or earlier + +* Tue Apr 15 2003 Jakub Jelinek 2.3.2-30 +- update from CVS +- fix prelink on ppc32 +- add TLS support on ppc32 and ppc64 +- make sure on -m64 arches all helper binaries are built with this + option + +* Mon Apr 14 2003 Jakub Jelinek 2.3.2-29 +- update from CVS + - fix strxfrm (#88409) +- use -m64 -mno-minimal-toc on ppc64 +- conflict with kernels < 2.4.20 on ppc64 and < 2.4.0 on x86_64 +- link glibc_post_upgrade against newly built libc.a + +* Sun Apr 13 2003 Jakub Jelinek 2.3.2-28 +- update from CVS + - fix NPTL pthread_detach and already terminated, but not yet + joined thread (#88219) + - fix bug-regex4 testcase (#88118) + - reenable prelink support broken in 2.3.2-13 + - fix register_printf_function (#88052) + - fix double free with fopen using ccs= (#88056) + - fix potential access below $esp in {set,swap}context (#88093) + - fix buffer underrun in gencat -H (#88099) + - avoid using unitialized variable in tst-tgmath (#88101) + - fix gammal (#88104) + - fix iconv -c + - fix xdr_string (PR libc/4999) + - fix /usr/lib/nptl/librt.so symlink + - avoid running NPTL cleanups twice in some cases + - unblock __pthread_signal_cancel in linuxthreads, so that + linuxthreads threaded programs work correctly if spawned + from NPTL threaded programs + - fix sysconf _SC_{NPROCESSORS_{CONF,ONLN},{,AV}PHYS_PAGES} +- remove /lib/i686 directory before running ldconfig in glibc post + during i686 -> i386 glibc "upgrades" (#88456) + +* Wed Apr 2 2003 Jakub Jelinek 2.3.2-22 +- update from CVS + - add pthread_atfork to libpthread.a + +* Tue Apr 1 2003 Jakub Jelinek 2.3.2-21 +- update from CVS +- make sure linuxthreads pthread_mutex_lock etc. is not a cancellation + point + +* Sat Mar 29 2003 Jakub Jelinek 2.3.2-20 +- update from CVS +- if kernel >= 2.4.1 doesn't support NPTL, fall back to + /lib/i686 libs on i686, not stright to /lib + +* Fri Mar 28 2003 Jakub Jelinek 2.3.2-19 +- update from CVS + - timers fixes + +* Thu Mar 27 2003 Jakub Jelinek 2.3.2-18 +- update from CVS +- fix NPTL pthread_cond_timedwait +- fix sysconf (_SC_MONOTONIC_CLOCK) +- use /%%{_lib}/tls instead of /lib/tls on x86-64 +- add /%%{_lib}/tls/librt*so* and /%%{_lib}/i686/librt*so* +- display content of .out files for all make check failures + +* Wed Mar 26 2003 Jakub Jelinek 2.3.2-17 +- update from CVS + - kernel POSIX timers support + +* Sat Mar 22 2003 Jakub Jelinek 2.3.2-16 +- update from CVS + - export __fork from glibc again +- fix glibc-compat build in NPTL +- fix c_stubs +- fix some more atomic.h problems +- don't check abi in glibc-compat libs + +* Fri Mar 21 2003 Jakub Jelinek 2.3.2-15 +- update from CVS +- build glibc-compat (for glibc 2.0 compatibility) and c_stubs add-ons +- condrestart sshd in glibc_post_upgrade so that the user can + log in remotely and handle the rest (#86339) +- fix a typo in glibc_post_upgrade on sparc + +* Tue Mar 18 2003 Jakub Jelinek 2.3.2-14 +- update from CVS +- change i686/athlon libc.so.6 base to 0x00e80000 + +* Mon Mar 17 2003 Jakub Jelinek 2.3.2-13 +- update from CVS + - hopefully last fix for condvar problems + +* Fri Mar 14 2003 Jakub Jelinek 2.3.2-12 +- fix bits/syscall.h creation on x86-64 + +* Thu Mar 13 2003 Jakub Jelinek 2.3.2-11 +- update from CVS + +* Wed Mar 12 2003 Jakub Jelinek 2.3.2-10 +- update from CVS + +* Tue Mar 11 2003 Jakub Jelinek 2.3.2-9 +- update from CVS +- fix glibc-debug description (#85111) +- make librt.so a symlink again, not linker script + +* Tue Mar 4 2003 Jakub Jelinek 2.3.2-8 +- update from CVS +- remove the workarounds for broken software accessing GLIBC_PRIVATE + symbols + +* Mon Mar 3 2003 Jakub Jelinek 2.3.2-7 +- update from CVS + +* Sun Mar 2 2003 Jakub Jelinek 2.3.2-6 +- fix TLS IE/LE model handling in dlopened libraries + on TCB_AT_TP arches + +* Tue Feb 25 2003 Jakub Jelinek 2.3.2-5 +- update from CVS + +* Tue Feb 25 2003 Jakub Jelinek 2.3.2-4 +- update from CVS + +* Mon Feb 24 2003 Jakub Jelinek 2.3.2-3 +- update from CVS +- only warn about errno, h_errno or _res for binaries, never + libraries +- rebuilt with gcc-3.2.2-4 to use direct %%gs TLS access insn sequences + +* Sun Feb 23 2003 Jakub Jelinek 2.3.2-2 +- update from CVS + +* Sat Feb 22 2003 Jakub Jelinek 2.3.2-1 +- update from CVS + +* Thu Feb 20 2003 Jakub Jelinek 2.3.1-51 +- update from CVS + +* Wed Feb 19 2003 Jakub Jelinek 2.3.1-50 +- update from CVS + +* Wed Feb 19 2003 Jakub Jelinek 2.3.1-49 +- update from CVS +- remove nisplus and nis from the default nsswitch.conf (#67401, #9952) + +* Tue Feb 18 2003 Jakub Jelinek 2.3.1-48 +- update from CVS + +* Sat Feb 15 2003 Jakub Jelinek 2.3.1-47 +- update from CVS + +* Fri Feb 14 2003 Jakub Jelinek 2.3.1-46 +- update from CVS + - pthread_cond* NPTL fixes, new NPTL testcases + +* Thu Feb 13 2003 Jakub Jelinek 2.3.1-45 +- update from CVS +- include also linuxthreads FLOATING_STACKS libs on i686 and athlon: + LD_ASSUME_KERNEL=2.2.5 to LD_ASSUME_KERNEL=2.4.0 is non-FLOATING_STACKS lt, + LD_ASSUME_KERNEL=2.4.1 to LD_ASSUME_KERNEL=2.4.19 is FLOATING_STACKS lt, + later is NPTL +- enable TLS on alpha/alphaev6 +- add BuildPreReq: /usr/bin/readlink + +* Tue Feb 11 2003 Jakub Jelinek 2.3.1-44 +- update from CVS + - pthread_once fix + +* Mon Feb 10 2003 Jakub Jelinek 2.3.1-43 +- update from CVS +- vfork fix on s390 +- rebuilt with binutils 2.13.90.0.18-5 so that accesses to errno + don't bind locally (#83325) + +* Thu Feb 06 2003 Jakub Jelinek 2.3.1-42 +- update from CVS +- fix pthread_create after vfork+exec in linuxthreads + +* Wed Feb 05 2003 Jakub Jelinek 2.3.1-41 +- update from CVS + +* Thu Jan 30 2003 Jakub Jelinek 2.3.1-40 +- update from CVS + +* Wed Jan 29 2003 Jakub Jelinek 2.3.1-39 +- update from CVS +- enable TLS on s390{,x} and sparc{,v9} + +* Fri Jan 17 2003 Jakub Jelinek 2.3.1-38 +- update from CVS +- initialize __environ in glibc_post_upgrade to empty array, + so that it is not NULL +- compat symlink for s390x /lib/ld64.so.1 +- enable glibc-profile on x86-64 +- only include libNoVersion.so on IA-32, Alpha and Sparc 32-bit + +* Thu Jan 16 2003 Jakub Jelinek 2.3.1-37 +- update from CVS + - nscd fixes, *scanf fix +- fix %%nptlarches noarch build (#81909) +- IA-64 TLS fixes + +* Tue Jan 14 2003 Jakub Jelinek 2.3.1-36 +- update from CVS +- rework -debuginfo subpackage, add -debuginfo-common + subpackage on IA-32, Alpha and Sparc (ie. auxiliary arches) +- fix vfork in libc.a on PPC32, Alpha, Sparc +- fix libio locks in linuxthreads libc.so if libpthread.so + is dlopened later (#81374) + +* Mon Jan 13 2003 Jakub Jelinek 2.3.1-35 +- update from CVS + - dlclose bugfixes +- fix NPTL libpthread.a +- fix glibc_post_upgrade on several arches + +* Sat Jan 11 2003 Jakub Jelinek 2.3.1-34 +- update from CVS +- TLS support on IA-64 + +* Wed Jan 8 2003 Jakub Jelinek 2.3.1-33 +- fix vfork in linuxthreads (#81377, #81363) + +* Tue Jan 7 2003 Jakub Jelinek 2.3.1-32 +- update from CVS +- don't use TLS libs if kernel doesn't set AT_SYSINFO + (#80921, #81212) +- add ntp_adjtime on alpha (#79996) +- fix nptl_db (#81116) + +* Sun Jan 5 2003 Jakub Jelinek 2.3.1-31 +- update from CVS +- support all architectures again + +* Fri Jan 3 2003 Jakub Jelinek 2.3.1-30 +- fix condvar compatibility wrappers +- add ugly hack to use non-TLS libs if a binary is seen + to have errno, h_errno or _res symbols in .dynsym + +* Fri Jan 3 2003 Jakub Jelinek 2.3.1-29 +- update from CVS + - fixes for new condvar + +* Thu Jan 2 2003 Jakub Jelinek 2.3.1-28 +- new NPTL condvar implementation plus related linuxthreads + symbol versioning updates + +* Thu Jan 2 2003 Jakub Jelinek 2.3.1-27 +- update from CVS +- fix #include with -D_BSD_SOURCE or without + feature set macros +- make *sigaction, sigwait and raise the same between + -lpthread -lc and -lc -lpthread in linuxthreads builds + +* Tue Dec 31 2002 Jakub Jelinek 2.3.1-26 +- fix dlclose + +* Sun Dec 29 2002 Jakub Jelinek 2.3.1-25 +- enable sysenter by default for now +- fix endless loop in ldconfig + +* Sat Dec 28 2002 Jakub Jelinek 2.3.1-24 +- update from CVS + +* Fri Dec 27 2002 Jakub Jelinek 2.3.1-23 +- update from CVS + - fix ptmalloc_init after clearenv (#80370) + +* Sun Dec 22 2002 Jakub Jelinek 2.3.1-22 +- update from CVS +- add IA-64 back +- move TLS libraries from /lib/i686 to /lib/tls + +* Thu Dec 19 2002 Jakub Jelinek 2.3.1-21 +- system(3) fix for linuxthreads +- don't segfault in pthread_attr_init from libc.so +- add cancellation tests from nptl to linuxthreads + +* Wed Dec 18 2002 Jakub Jelinek 2.3.1-20 +- fix up lists of exported symbols + their versions + from the libraries + +* Wed Dec 18 2002 Jakub Jelinek 2.3.1-19 +- fix --with-tls --enable-kernel=2.2.5 libc on IA-32 + +* Wed Dec 18 2002 Jakub Jelinek 2.3.1-18 +- update from CVS + - fix NPTL hanging mozilla + - initialize malloc in mALLOPt (fixes problems with squid, #79957) + - make linuxthreads work with dl_dynamic_weak 0 + - clear dl_dynamic_weak everywhere + +* Tue Dec 17 2002 Jakub Jelinek 2.3.1-17 +- update from CVS + - NPTL socket fixes, flockfile/ftrylockfile/funlockfile fix + - kill -debug sub-package, rename -debug-static to -debug + - clear dl_dynamic_weak for NPTL + +* Mon Dec 16 2002 Jakub Jelinek 2.3.1-16 +- fix and for C++ +- automatically generate NPTL libpthread wrappers + +* Mon Dec 16 2002 Jakub Jelinek 2.3.1-15 +- update from CVS + - all functions which need cancellation should now be cancellable + both in libpthread.so and libc.so + - removed @@GLIBC_2.3.2 cancellation wrappers + +* Fri Dec 13 2002 Jakub Jelinek 2.3.1-14 +- update from CVS + - replace __libc_lock_needed@GOTOFF(%%ebx) with + %%gs:offsetof(tcbhead_t, multiple_threads) + - start of new NPTL cancellation wrappers + +* Thu Dec 12 2002 Jakub Jelinek 2.3.1-13 +- update from CVS +- use inline locks in malloc + +* Tue Dec 10 2002 Jakub Jelinek 2.3.1-12 +- update from CVS + - support LD_ASSUME_KERNEL=2.2.5 in statically linked programs + +* Mon Dec 9 2002 Jakub Jelinek 2.3.1-11 +- update from CVS +- rebuilt with gcc-3.2.1-2 + +* Fri Dec 6 2002 Jakub Jelinek 2.3.1-10 +- update from CVS +- non-nptl --with-tls --without-__thread FLOATING_STACKS libpthread + should work now +- faster libc locking when using nptl +- add OUTPUT_FORMAT to linker scripts +- fix x86_64 sendfile (#79111) + +* Wed Dec 4 2002 Jakub Jelinek 2.3.1-9 +- update from CVS + - RUSCII support (#78906) +- for nptl builds add BuildRequires +- fix byteswap.h for non-gcc (#77689) +- add nptl-devel package + +* Tue Dec 3 2002 Jakub Jelinek 2.3.1-8 +- update from CVS + - make --enable-kernel=2.2.5 --with-tls --without-__thread + ld.so load nptl and other --with-__thread libs +- disable nptl by default for now + +* Wed Nov 27 2002 Jakub Jelinek 2.3.1-7 +- update from CVS +- restructured redhat/Makefile and spec, so that src.rpm contains + glibc-.tar.bz2, glibc-redhat-.tar.bz2 and glibc-redhat.patch +- added nptl + +* Fri Nov 8 2002 Jakub Jelinek 2.3.1-6 +- update from CVS + - even more regex fixes +- run sed testsuite to check glibc regex + +* Thu Oct 24 2002 Jakub Jelinek 2.3.1-5 +- fix LD_DEBUG=statistics and LD_TRACE_PRELINKING in programs + using libpthread.so. + +* Thu Oct 24 2002 Jakub Jelinek 2.3.1-4 +- update from CVS + - fixed %%a and %%A in *printf (#75821) + - fix re_comp memory leaking (#76594) + +* Tue Oct 22 2002 Jakub Jelinek 2.3.1-3 +- update from CVS + - some more regex fixes +- fix libpthread.a (#76484) +- fix locale-archive enlarging + +* Fri Oct 18 2002 Jakub Jelinek 2.3.1-2 +- update from CVS + - don't need to use 128K of stacks for DNS lookups + - regex fixes + - updated timezone data e.g. for this year's Brasil DST + changes + - expand ${LIB} in RPATH/RUNPATH/dlopen filenames + +* Fri Oct 11 2002 Jakub Jelinek 2.3.1-1 +- update to 2.3.1 final + - support really low thread stack sizes (#74073) +- tzdata update + +* Wed Oct 9 2002 Jakub Jelinek 2.3-2 +- update from CVS + - handle low stack limits + - move s390x into */lib64 + +* Thu Oct 3 2002 Jakub Jelinek 2.3-1 +- update to 2.3 final + - fix freopen on libstdc++ <= 2.96 stdin/stdout/stderr (#74800) + +* Sun Sep 29 2002 Jakub Jelinek 2.2.94-3 +- don't prelink -r libc.so on ppc/x86-64/sparc*, it doesn't + speed things up, because they are neither REL arches, nor + ELF_MACHINE_REL_RELATIVE +- fix sparc64 build + +* Sun Sep 29 2002 Jakub Jelinek 2.2.94-2 +- update from CVS + +* Sat Sep 28 2002 Jakub Jelinek 2.2.94-1 +- update from CVS +- prelink on ppc and x86-64 too +- don't remove ppc memset +- instead of listing on which arches to remove glibc-compat + list where it should stay + +* Fri Sep 6 2002 Jakub Jelinek 2.2.93-5 +- fix wcsmbs functions with invalid character sets (or malloc + failures) +- make sure __ctype_b etc. compat vars are updated even if + they are copy relocs in the main program + +* Thu Sep 5 2002 Jakub Jelinek 2.2.93-4 +- fix /lib/libnss1_dns.so.1 (missing __set_h_errno definition + leading to unresolved __set_h_errno symbol) + +* Wed Sep 4 2002 Jakub Jelinek 2.2.93-3 +- security fix - increase dns-network.c MAXPACKET to at least + 65536 to avoid buffer overrun. Likewise glibc-compat + dns-{host,network}.c. + +* Tue Sep 3 2002 Jakub Jelinek 2.2.93-2 +- temporarily add back __ctype_b, __ctype_tolower and __ctype_toupper to + libc.a and export them as @@GLIBC_2.0 symbols, not @GLIBC_2.0 + from libc.so - we have still lots of .a libraries referencing + __ctype_{b,tolower,toupper} out there... + +* Tue Sep 3 2002 Jakub Jelinek 2.2.93-1 +- update from CVS + - 2.2.93 release + - use double instead of single indirection in isXXX macros + - per-locale wcsmbs conversion state + +* Sat Aug 31 2002 Jakub Jelinek 2.2.92-2 +- update from CVS + - fix newlocale/duplocale/uselocale +- disable profile on x86_64 for now + +* Sat Aug 31 2002 Jakub Jelinek 2.2.92-1 +- update from CVS + - 2.2.92 release + - fix gettext after uselocale + - fix locales in statically linked threaded programs + - fix NSS + +* Thu Aug 29 2002 Jakub Jelinek 2.2.91-1 +- update from CVS + - 2.2.91 release + - fix fd leaks in locale-archive reader (#72043) +- handle EROFS in build-locale-archive gracefully (#71665) + +* Wed Aug 28 2002 Jakub Jelinek 2.2.90-27 +- update from CVS + - fix re_match (#72312) +- support more than 1024 threads + +* Fri Aug 23 2002 Jakub Jelinek 2.2.90-26 +- update from CVS + - fix i386 build + +* Thu Aug 22 2002 Jakub Jelinek 2.2.90-25 +- update from CVS + - fix locale-archive loading hang on some (non-primary) locales + (#72122, #71878) + - fix umount problems with locale-archives when /usr is a separate + partition (#72043) +- add LICENSES file + +* Fri Aug 16 2002 Jakub Jelinek 2.2.90-24 +- update from CVS + - only mmap up to 2MB of locale-archive on 32-bit machines + initially + - fix fseek past end + fread segfault with mmaped stdio +- include which is mistakenly not included + in glibc-devel on IA-32 + +* Fri Aug 16 2002 Jakub Jelinek 2.2.90-23 +- don't return normalized locale name in setlocale when using + locale-archive + +* Thu Aug 15 2002 Jakub Jelinek 2.2.90-22 +- update from CVS + - optimize for primary system locale +- localedef fixes (#71552, #67705) + +* Wed Aug 14 2002 Jakub Jelinek 2.2.90-21 +- fix path to locale-archive in libc reader +- build locale archive at glibc-common %%post time +- export __strtold_internal and __wcstold_internal on Alpha again +- workaround some localedata problems + +* Tue Aug 13 2002 Jakub Jelinek 2.2.90-20 +- update from CVS +- patch out set_thread_area for now + +* Fri Aug 9 2002 Jakub Jelinek 2.2.90-19 +- update from CVS +- GB18030 patch from Yu Shao +- applied Debian patch for getaddrinfo IPv4 vs. IPv6 +- fix regcomp (#71039) + +* Sun Aug 4 2002 Jakub Jelinek 2.2.90-18 +- update from CVS +- use /usr/sbin/prelink, not prelink (#70376) + +* Thu Jul 25 2002 Jakub Jelinek 2.2.90-17 +- update from CVS + +* Thu Jul 25 2002 Jakub Jelinek 2.2.90-16 +- update from CVS + - ungetc fix (#69586) + - fseek errno fix (#69589) + - change *etrlimit prototypes for C++ (#68588) +- use --without-tls instead of --disable-tls + +* Thu Jul 11 2002 Jakub Jelinek 2.2.90-15 +- set nscd user's shell to /sbin/nologin (#68369) +- fix glibc-compat buffer overflows (security) +- buildrequire prelink, don't build glibc's own copy of it (#67567) +- update from CVS + - regex fix (#67734) + - fix unused warnings (#67706) + - fix freopen with mmap stdio (#67552) + - fix realloc (#68499) + +* Tue Jun 25 2002 Bill Nottingham 2.2.90-14 +- update from CVS + - fix argp on long words + - update atime in libio + +* Sat Jun 22 2002 Jakub Jelinek 2.2.90-13 +- update from CVS + - a thread race fix + - fix readdir on invalid dirp + +* Wed Jun 19 2002 Jakub Jelinek 2.2.90-12 +- update from CVS + - don't use __thread in headers +- fix system(3) in threaded apps +- update prelink, so that it is possible to prelink -u libc.so.6.1 + on Alpha + +* Fri Jun 7 2002 Jakub Jelinek 2.2.90-11 +- update from CVS + - fix __moddi3 (#65612, #65695) + - fix ether_line (#64427) +- fix setvbuf with mmap stdio (#65864) +- --disable-tls for now, waiting for kernel +- avoid duplication of __divtf3 etc. on IA-64 +- make sure get*ent_r and _IO_wfile_jumps are exported (#62278) + +* Tue May 21 2002 Jakub Jelinek 2.2.90-10 +- update from CVS + - fix Alpha pthread bug with gcc 3.1 + +* Fri Apr 19 2002 Jakub Jelinek 2.2.5-35 +- fix nice + +* Mon Apr 15 2002 Jakub Jelinek 2.2.5-34 +- add relocation dependencies even for weak symbols (#63422) +- stricter check_fds check for suid/sgid binaries +- run make check at %%install time + +* Sat Apr 13 2002 Jakub Jelinek 2.2.5-33 +- handle Dec 31 1969 in mktime for timezones west of GMT (#63369) +- back out do-lookup.h change (#63261, #63305) +- use "memory" clobber instead all the fancy stuff in i386/i686/bits/string.h + since lots of compilers break on it +- fix sparc build with gcc 3.1 +- fix spec file for athlon + +* Tue Apr 9 2002 Jakub Jelinek 2.2.5-32 +- fix debugging of threaded apps (#62804) +- fix DST for Estonia (#61494) +- document that pthread_mutexattr_?etkind_np are deprecated + and pthread_mutexattr_?ettype should be used instead in man + pages (#61485) +- fix libSegFault.so undefined externals + +* Fri Apr 5 2002 Jakub Jelinek 2.2.5-31 +- temporarily disable prelinking ld.so, as some statically linked + binaries linked against debugging versions of old glibcs die on it + (#62352) +- fix for -std=c99 (#62516) +- fix ether_ntohost segfault (#62397) +- remove in glibc_post_upgrade on i386 all /lib/i686/libc-*.so, + /lib/i686/libm-*.so and /lib/i686/libpthread-*.so, not just current + version (#61633) +- prelink -r on alpha too + +* Thu Mar 28 2002 Jakub Jelinek 2.2.5-30 +- update GB18030 iconv module (Yu Shao) + +* Tue Mar 26 2002 Jakub Jelinek 2.2.5-29 +- features.h fix + +* Tue Mar 26 2002 Jakub Jelinek 2.2.5-28 +- update from CVS + - fix nscd with huge groups + - fix nis to not close fds it shouldn't +- rebuilt against newer glibc-kernheaders to use the correct + PATH_MAX +- handle .athlon.rpm glibc the same way as .i686.rpm +- add a couple of .ISO-8859-15 locales (#61908) +- readd temporarily currencies which were superceeded by Euro + into the list of accepted currencies by localedef to make + standard conformance testsuites happy +- temporarily moved __libc_waitpid back to make Sun JDK happy +- use old malloc code +- prelink i686/athlon ld.so and prelink -r i686/athlon libc.so + +* Thu Mar 14 2002 Jakub Jelinek 2.2.5-27 +- update from CVS + - fix DST handling for southern hemisphere (#60747) + - fix daylight setting for tzset (#59951) + - fix ftime (#60350) + - fix nice return value + - fix a malloc segfault +- temporarily moved __libc_wait, __libc_fork and __libc_stack_end + back to what they used to be exported at +- censorship (#60758) + +* Thu Feb 28 2002 Jakub Jelinek 2.2.5-26 +- update from CVS +- use __attribute__((visibility(...))) if supported, use _rtld_local + for ld.so only objects +- provide libc's own __{,u}{div,mod}di3 + +* Wed Feb 27 2002 Jakub Jelinek 2.2.5-25 +- switch back to 2.2.5, mmap stdio needs work + +* Mon Feb 25 2002 Jakub Jelinek 2.2.90-8 +- fix two other mmap stdio bugs (#60228) + +* Thu Feb 21 2002 Jakub Jelinek 2.2.90-7 +- fix yet another mmap stdio bug (#60145) + +* Tue Feb 19 2002 Jakub Jelinek 2.2.90-6 +- fix mmap stdio bug (seen on ld as File truncated error, #60043) +- apply Andreas Schwab's fix for pthread sigwait +- remove /lib/i686/ libraries in glibc_post_upgrade when + performing i386 glibc install + +* Thu Feb 14 2002 Jakub Jelinek 2.2.90-5 +- update to CVS +- added glibc-utils subpackage +- disable autoreq in glibc-debug +- readd %%lang() to locale files + +* Thu Feb 7 2002 Jakub Jelinek 2.2.90-4 +- update to CVS +- move glibc private symbols to GLIBC_PRIVATE symbol version + +* Wed Jan 9 2002 Jakub Jelinek 2.2.90-3 +- fix a sqrt bug on alpha which caused SHN_UNDEF $__full_ieee754_sqrt..ng + symbol in libm + +* Tue Jan 8 2002 Jakub Jelinek 2.2.90-2 +- add debug-static package + +* Mon Dec 31 2001 Jakub Jelinek 2.2.90-1 +- update from CVS +- remove -D__USE_STRING_INLINES +- add debug subpackage to trim glibc and glibc-devel size + +* Wed Oct 3 2001 Jakub Jelinek 2.2.4-19 +- fix strsep + +* Fri Sep 28 2001 Jakub Jelinek 2.2.4-18 +- fix a ld.so bug with duplicate searchlists in l_scope +- fix erfcl(-inf) +- turn /usr/lib/librt.so into linker script + +* Wed Sep 26 2001 Jakub Jelinek 2.2.4-17 +- fix a ld.so lookup bug after lots of dlopen calls +- fix CMSG_DATA for non-gcc non-ISOC99 compilers (#53984) +- prelinking support for Sparc64 + +* Fri Sep 21 2001 Jakub Jelinek 2.2.4-16 +- update from CVS to fix DT_SYMBOLIC +- prelinking support for Alpha and Sparc + +* Tue Sep 18 2001 Jakub Jelinek 2.2.4-15 +- update from CVS + - linuxthreads now retries if -1/EINTR is returned from + reading or writing to thread manager pipe (#43742) +- use DT_FILTER in librt.so (#53394) + - update glibc prelink patch so that it handles filters +- fix timer_* with SIGEV_NONE (#53494) +- make glibc_post_upgrade work on PPC (patch from Franz Sirl) + +* Mon Sep 10 2001 Jakub Jelinek 2.2.4-14 +- fix build on sparc32 +- 2.2.4-13 build for some reason missed some locales + on alpha/ia64 + +* Mon Sep 3 2001 Jakub Jelinek 2.2.4-13 +- fix iconvconfig + +* Mon Sep 3 2001 Jakub Jelinek 2.2.4-12 +- add fam to /etc/rpc (#52863) +- fix for C++ (#52960) +- fix perror + +* Mon Aug 27 2001 Jakub Jelinek 2.2.4-11 +- fix strnlen(x, -1) + +* Mon Aug 27 2001 Jakub Jelinek 2.2.4-10 +- doh, should only define __libc_rwlock_t + if __USE_UNIX98. + +* Mon Aug 27 2001 Jakub Jelinek 2.2.4-9 +- fix bits/libc-lock.h so that gcc can compile +- fix s390 build + +* Fri Aug 24 2001 Jakub Jelinek 2.2.4-8 +- kill stale library symlinks in ldconfig (#52350) +- fix inttypes.h for G++ < 3.0 +- use DT_REL*COUNT + +* Wed Aug 22 2001 Jakub Jelinek 2.2.4-7 +- fix strnlen on IA-64 (#50077) + +* Thu Aug 16 2001 Jakub Jelinek 2.2.4-6 +- glibc 2.2.4 final +- fix -lpthread -static (#51672) + +* Fri Aug 10 2001 Jakub Jelinek 2.2.4-5 +- doh, include libio/tst-swscanf.c + +* Fri Aug 10 2001 Jakub Jelinek 2.2.4-4 +- don't crash on catclose(-1) +- fix wscanf %%[] handling +- fix return value from swprintf +- handle year + %%U/%%W week + week day in strptime + +* Thu Aug 9 2001 Jakub Jelinek 2.2.4-3 +- update from CVS to + - fix strcoll (#50548) + - fix seekdir (#51132) + - fix memusage (#50606) +- don't make gconv-modules.cache %%config file, just don't verify + its content. + +* Mon Aug 6 2001 Jakub Jelinek +- fix strtod and *scanf (#50723, #50724) + +* Sat Aug 4 2001 Jakub Jelinek +- update from CVS + - fix iconv cache handling +- glibc should not own %%{_infodir}, %%{_mandir} nor %%{_mandir}/man3 (#50673) +- add gconv-modules.cache as emtpy config file (#50699) +- only run iconvconfig if /usr is mounted read-write (#50667) + +* Wed Jul 25 2001 Jakub Jelinek +- move iconvconfig from glibc-common into glibc subpackage, + call it from glibc_post_upgrade instead of common's post. + +* Tue Jul 24 2001 Jakub Jelinek +- turn off debugging printouts in iconvconfig + +* Tue Jul 24 2001 Jakub Jelinek +- update from CVS + - fix IA-32 makecontext + - make fflush(0) thread-safe (#46446) + +* Mon Jul 23 2001 Jakub Jelinek +- adjust prelinking DT_* and SHT_* values in elf.h +- update from CVS + - iconv cache + - make iconv work in SUID/SGID programs (#34611) + +* Fri Jul 20 2001 Jakub Jelinek +- update from CVS + - kill non-pic code in libm.so + - fix getdate + - fix some locales (#49402) +- rebuilt with binutils-2.11.90.0.8-5 to place .interp section + properly in libBrokenLocale.so, libNoVersion.so and libanl.so +- add floating stacks on IA-64, Alpha, Sparc (#49308) + +* Mon Jul 16 2001 Jakub Jelinek +- make /lib/i686 directory owned by glibc*.i686.rpm + +* Mon Jul 9 2001 Jakub Jelinek +- remove rquota.[hx] headers which are now provided by quota (#47141) +- add prelinking patch + +* Thu Jul 5 2001 Jakub Jelinek +- require sh-utils for nscd + +* Mon Jun 25 2001 Jakub Jelinek +- update from CVS (#43681, #43350, #44663, #45685) +- fix ro_RO bug (#44644) + +* Wed Jun 6 2001 Jakub Jelinek +- fix a bunch of math bugs (#43210, #43345, #43346, #43347, #43348, #43355) +- make rpc headers -ansi compilable (#42390) +- remove alphaev6 optimized memcpy, since there are still far too many + broken apps which call memcpy where they should call memmove +- update from CVS to (among other things): + - fix tanhl bug (#43352) + +* Tue May 22 2001 Jakub Jelinek +- fix #include with -D_XOPEN_SOURCE=500 on ia64 (#35968) +- fix a dlclose reldeps handling bug +- some more profiling fixes +- fix tgmath.h + +* Thu May 17 2001 Jakub Jelinek +- make ldconfig more quiet +- fix LD_PROFILE on i686 (#41030) + +* Wed May 16 2001 Jakub Jelinek +- fix the hardlink program, so that it really catches all files with + identical content +- add a s390x clone fix + +* Wed May 16 2001 Jakub Jelinek +- fix rpc for non-threaded apps using svc_fdset and similar variables (#40409) +- fix nss compatibility DSO versions for alphaev6 +- add a hardlink program instead of the shell 3x for plus cmp -s/link + which takes a lot of time during build +- rework BuildPreReq and Conflicts with gcc, so that + it applies only where it has to + +* Fri May 11 2001 Jakub Jelinek +- fix locale name of ja_JP in UTF-8 (#39783) +- fix re_search_2 (#40244) +- fix memusage script (#39138, #39823) +- fix dlsym(RTLD_NEXT, ) from main program (#39803) +- fix xtrace script (#39609) +- make glibc conflict with glibc-devel 2.2.2 and below (to make sure + libc_nonshared.a has atexit) +- fix getconf LFS_CFLAGS on 64bitters +- recompile with gcc-2.96-84 or above to fix binary compatibility problem + with __frame_state_for function (#37933) + +* Fri Apr 27 2001 Jakub Jelinek +- glibc 2.2.3 release + - fix strcoll (#36539) +- add BuildPreReqs (#36378) + +* Wed Apr 25 2001 Jakub Jelinek +- update from CVS + +* Fri Apr 20 2001 Jakub Jelinek +- update from CVS + - fix sparc64, ia64 + - fix some locale syntax errors (#35982) + +* Wed Apr 18 2001 Jakub Jelinek +- update from CVS + +* Wed Apr 11 2001 Jakub Jelinek +- update from CVS + +* Fri Apr 6 2001 Jakub Jelinek +- support even 2.4.0 kernels on ia64, sparc64 and s390x +- include UTF-8 locales +- make gconv-modules %%config(noreplace) + +* Fri Mar 23 2001 Jakub Jelinek +- back out sunrpc changes + +* Wed Mar 21 2001 Jakub Jelinek +- update from CVS + - fix ia64 build + - fix pthread_getattr_np + +* Fri Mar 16 2001 Jakub Jelinek +- update from CVS + - run atexit() registered functions at dlclose time if they are in shared + libraries (#28625) + - add pthread_getattr_np API to make JVM folks happy + +* Wed Mar 14 2001 Jakub Jelinek +- require 2.4.1 instead of 2.4.0 on platforms where it required 2.4 kernel +- fix ldd behaviour on unresolved symbols +- remove nonsensical ldconfig warning, update osversion for the most + recent library with the same soname in the same directory instead (#31703) +- apply selected patches from CVS +- s390x spec file changes from Florian La Roche + +* Wed Mar 7 2001 Jakub Jelinek +- fix gencat (#30894) +- fix ldconfig changes from yesterday, fix LD_ASSUME_KERNEL handling + +* Tue Mar 6 2001 Jakub Jelinek +- update from CVS +- make pthread_attr_setstacksize consistent before and after pthread manager + is started (#28194) +- pass back struct sigcontext from pthread signal wrapper (on ia32 only so + far, #28493) +- on i686 ship both --enable-kernel 2.2.5 and 2.4.0 libc/libm/libpthread, + make ld.so pick the right one + +* Sat Feb 17 2001 Preston Brown +- glib-common doesn't require glibc, until we can figure out how to get out of dependency hell. + +* Sat Feb 17 2001 Jakub Jelinek +- make glibc require particular version of glibc-common + and glibc-common prerequire glibc. + +* Fri Feb 16 2001 Jakub Jelinek +- glibc 2.2.2 release + - fix regex REG_ICASE bug seen in ksymoops + +* Sat Feb 10 2001 Jakub Jelinek +- fix regexec leaking memory (#26864) + +* Fri Feb 9 2001 Jakub Jelinek +- update from CVS + - fix ia64 build with gnupro + - make regex 64bit clean + - fix tgmath make check failures on alpha + +* Tue Feb 6 2001 Jakub Jelinek +- update again for ia64 DF_1_INITFIRST + +* Fri Feb 2 2001 Jakub Jelinek +- update from CVS + - fix getaddrinfo (#25437) + - support DF_1_INITFIRST (#25029) + +* Wed Jan 24 2001 Jakub Jelinek +- build all auxiliary arches with --enablekernel 2.4.0, those wanting + to run 2.2 kernels can downgrade to the base architecture glibc. + +* Sat Jan 20 2001 Jakub Jelinek +- remove %%lang() flags from %%{_prefix}/lib/locale files temporarily + +* Sun Jan 14 2001 Jakub Jelinek +- update to 2.2.1 final + - fix a pthread_kill_other_threads_np breakage (#23966) + - make static binaries using dlopen work on ia64 again +- fix a typo in glibc-common group + +* Wed Jan 10 2001 Bernhard Rosenkraenzer +- devel requires glibc = %%{version} +- noreplace /etc/nscd.conf + +* Wed Jan 10 2001 Jakub Jelinek +- some more security fixes: + - don't look up LD_PRELOAD libs in cache for SUID apps + (because that bypasses SUID bit checking on the library) + - place output files for profiling SUID apps into /var/profile, + use O_NOFOLLOW for them + - add checks for $MEMUSAGE_OUTPUT and $SEGFAULT_OUTPUT_NAME +- hardlink identical locale files together +- add %%lang() tags to locale stuff +- remove ko_KR.utf8 for now, it is provided by locale-utf8 package + +* Mon Jan 8 2001 Jakub Jelinek +- add glibc-common subpackage +- fix alphaev6 memcpy (#22494) +- fix sys/cdefs.h (#22908) +- don't define stdin/stdout/stderr as macros for -traditional (#22913) +- work around a bug in IBM JDK (#22932, #23012) +- fix pmap_unset when network is down (#23176) +- move nscd in rc.d before netfs on shutdown +- fix $RESOLV_HOST_CONF in SUID apps (#23562) + +* Fri Dec 15 2000 Jakub Jelinek +- fix ftw and nftw + +* Wed Dec 13 2000 Jakub Jelinek +- fix fcvt (#22184) +- ldd /lib/ld-linux.so.2 is not crashing any longer again (#22197) +- fix gencat + +* Mon Dec 11 2000 Jakub Jelinek +- fix alpha htonl and alphaev6 stpcpy + +* Sat Dec 9 2000 Jakub Jelinek +- update to CVS to: + - fix getnameinfo (#21934) + - don't stomp on memory in rpath handling (#21544) + - fix setlocale (#21507) +- fix libNoVersion.so.1 loading code (#21579) +- use auxarches define in spec file for auxiliary + architectures (#21219) +- remove /usr/share directory from filelist (#21218) + +* Sun Nov 19 2000 Jakub Jelinek +- update to CVS to fix getaddrinfo + +* Fri Nov 17 2000 Jakub Jelinek +- update to CVS to fix freopen +- remove all alpha workarounds, not needed anymore + +* Wed Nov 15 2000 Jakub Jelinek +- fix dladdr bug on alpha/sparc32/sparc64 +- fix Makefiles so that they run static tests properly + +* Tue Nov 14 2000 Jakub Jelinek +- update to CVS to fix ldconfig + +* Thu Nov 9 2000 Jakub Jelinek +- update to glibc 2.2 release + +* Mon Nov 6 2000 Jakub Jelinek +- update to CVS to: + - export __sysconf@@GLIBC_2.2 (#20417) + +* Fri Nov 3 2000 Jakub Jelinek +- merge to 2.1.97 + +* Mon Oct 30 2000 Jakub Jelinek +- update to CVS, including: + - fix WORD_BIT/LONG_BIT definition in limits.h (#19088) + - fix hesiod (#19375) + - set LC_MESSAGES in zic/zdump for proper error message output (#19495) + - fix LFS fcntl when used with non-LFS aware kernels (#19730) + +* Thu Oct 19 2000 Jakub Jelinek +- fix alpha semctl (#19199) +- update to CVS, including: + - fix glibc headers for Compaq non-gcc compilers + - fix locale alias handling code (#18832) + - fix rexec on little endian machines (#18886) +- started writing changelog again + +* Thu Aug 10 2000 Adrian Havill +- added ja ujis alias for backwards compatibility diff --git a/SOURCES/SUPPORTED b/SOURCES/SUPPORTED new file mode 100644 index 0000000..fdf15fd --- /dev/null +++ b/SOURCES/SUPPORTED @@ -0,0 +1,496 @@ +# This file names the currently supported and somewhat tested locales. +# If you have any additions please file a glibc bug report. +SUPPORTED-LOCALES=\ +C.UTF-8/UTF-8 \ +aa_DJ.UTF-8/UTF-8 \ +aa_DJ/ISO-8859-1 \ +aa_ER/UTF-8 \ +aa_ER@saaho/UTF-8 \ +aa_ET/UTF-8 \ +af_ZA.UTF-8/UTF-8 \ +af_ZA/ISO-8859-1 \ +agr_PE/UTF-8 \ +ak_GH/UTF-8 \ +am_ET/UTF-8 \ +an_ES.UTF-8/UTF-8 \ +an_ES/ISO-8859-15 \ +anp_IN/UTF-8 \ +ar_AE.UTF-8/UTF-8 \ +ar_AE/ISO-8859-6 \ +ar_BH.UTF-8/UTF-8 \ +ar_BH/ISO-8859-6 \ +ar_DZ.UTF-8/UTF-8 \ +ar_DZ/ISO-8859-6 \ +ar_EG.UTF-8/UTF-8 \ +ar_EG/ISO-8859-6 \ +ar_IN/UTF-8 \ +ar_IQ.UTF-8/UTF-8 \ +ar_IQ/ISO-8859-6 \ +ar_JO.UTF-8/UTF-8 \ +ar_JO/ISO-8859-6 \ +ar_KW.UTF-8/UTF-8 \ +ar_KW/ISO-8859-6 \ +ar_LB.UTF-8/UTF-8 \ +ar_LB/ISO-8859-6 \ +ar_LY.UTF-8/UTF-8 \ +ar_LY/ISO-8859-6 \ +ar_MA.UTF-8/UTF-8 \ +ar_MA/ISO-8859-6 \ +ar_OM.UTF-8/UTF-8 \ +ar_OM/ISO-8859-6 \ +ar_QA.UTF-8/UTF-8 \ +ar_QA/ISO-8859-6 \ +ar_SA.UTF-8/UTF-8 \ +ar_SA/ISO-8859-6 \ +ar_SD.UTF-8/UTF-8 \ +ar_SD/ISO-8859-6 \ +ar_SS/UTF-8 \ +ar_SY.UTF-8/UTF-8 \ +ar_SY/ISO-8859-6 \ +ar_TN.UTF-8/UTF-8 \ +ar_TN/ISO-8859-6 \ +ar_YE.UTF-8/UTF-8 \ +ar_YE/ISO-8859-6 \ +ayc_PE/UTF-8 \ +az_AZ/UTF-8 \ +az_IR/UTF-8 \ +as_IN/UTF-8 \ +ast_ES.UTF-8/UTF-8 \ +ast_ES/ISO-8859-15 \ +be_BY.UTF-8/UTF-8 \ +be_BY/CP1251 \ +be_BY@latin/UTF-8 \ +bem_ZM/UTF-8 \ +ber_DZ/UTF-8 \ +ber_MA/UTF-8 \ +bg_BG.UTF-8/UTF-8 \ +bg_BG/CP1251 \ +bhb_IN.UTF-8/UTF-8 \ +bho_IN/UTF-8 \ +bho_NP/UTF-8 \ +bi_VU/UTF-8 \ +bn_BD/UTF-8 \ +bn_IN/UTF-8 \ +bo_CN/UTF-8 \ +bo_IN/UTF-8 \ +br_FR.UTF-8/UTF-8 \ +br_FR/ISO-8859-1 \ +br_FR@euro/ISO-8859-15 \ +brx_IN/UTF-8 \ +bs_BA.UTF-8/UTF-8 \ +bs_BA/ISO-8859-2 \ +byn_ER/UTF-8 \ +ca_AD.UTF-8/UTF-8 \ +ca_AD/ISO-8859-15 \ +ca_ES.UTF-8/UTF-8 \ +ca_ES/ISO-8859-1 \ +ca_ES@euro/ISO-8859-15 \ +ca_ES@valencia/UTF-8 \ +ca_FR.UTF-8/UTF-8 \ +ca_FR/ISO-8859-15 \ +ca_IT.UTF-8/UTF-8 \ +ca_IT/ISO-8859-15 \ +ce_RU/UTF-8 \ +chr_US/UTF-8 \ +cmn_TW/UTF-8 \ +crh_UA/UTF-8 \ +cs_CZ.UTF-8/UTF-8 \ +cs_CZ/ISO-8859-2 \ +csb_PL/UTF-8 \ +cv_RU/UTF-8 \ +cy_GB.UTF-8/UTF-8 \ +cy_GB/ISO-8859-14 \ +da_DK.UTF-8/UTF-8 \ +da_DK/ISO-8859-1 \ +da_DK.ISO-8859-15/ISO-8859-15 \ +de_AT.UTF-8/UTF-8 \ +de_AT/ISO-8859-1 \ +de_AT@euro/ISO-8859-15 \ +de_BE.UTF-8/UTF-8 \ +de_BE/ISO-8859-1 \ +de_BE@euro/ISO-8859-15 \ +de_CH.UTF-8/UTF-8 \ +de_CH/ISO-8859-1 \ +de_DE.UTF-8/UTF-8 \ +de_DE/ISO-8859-1 \ +de_DE@euro/ISO-8859-15 \ +de_IT.UTF-8/UTF-8 \ +de_IT/ISO-8859-1 \ +de_LI.UTF-8/UTF-8 \ +de_LU.UTF-8/UTF-8 \ +de_LU/ISO-8859-1 \ +de_LU@euro/ISO-8859-15 \ +doi_IN/UTF-8 \ +dsb_DE/UTF-8 \ +dv_MV/UTF-8 \ +dz_BT/UTF-8 \ +el_GR.UTF-8/UTF-8 \ +el_GR/ISO-8859-7 \ +el_GR@euro/ISO-8859-7 \ +el_CY.UTF-8/UTF-8 \ +el_CY/ISO-8859-7 \ +en_AG/UTF-8 \ +en_AU.UTF-8/UTF-8 \ +en_AU/ISO-8859-1 \ +en_BW.UTF-8/UTF-8 \ +en_BW/ISO-8859-1 \ +en_CA.UTF-8/UTF-8 \ +en_CA/ISO-8859-1 \ +en_DK.UTF-8/UTF-8 \ +en_DK/ISO-8859-1 \ +en_GB.UTF-8/UTF-8 \ +en_GB/ISO-8859-1 \ +en_GB.ISO-8859-15/ISO-8859-15 \ +en_HK.UTF-8/UTF-8 \ +en_HK/ISO-8859-1 \ +en_IE.UTF-8/UTF-8 \ +en_IE/ISO-8859-1 \ +en_IE@euro/ISO-8859-15 \ +en_IL/UTF-8 \ +en_IN/UTF-8 \ +en_NG/UTF-8 \ +en_NZ.UTF-8/UTF-8 \ +en_NZ/ISO-8859-1 \ +en_PH.UTF-8/UTF-8 \ +en_PH/ISO-8859-1 \ +en_SC.UTF-8/UTF-8 \ +en_SG.UTF-8/UTF-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 \ +en_US.UTF-8@ampm/UTF-8 \ +en_ZA.UTF-8/UTF-8 \ +en_ZA/ISO-8859-1 \ +en_ZM/UTF-8 \ +en_ZW.UTF-8/UTF-8 \ +en_ZW/ISO-8859-1 \ +eo/UTF-8 \ +es_AR.UTF-8/UTF-8 \ +es_AR/ISO-8859-1 \ +es_BO.UTF-8/UTF-8 \ +es_BO/ISO-8859-1 \ +es_CL.UTF-8/UTF-8 \ +es_CL/ISO-8859-1 \ +es_CO.UTF-8/UTF-8 \ +es_CO/ISO-8859-1 \ +es_CR.UTF-8/UTF-8 \ +es_CR/ISO-8859-1 \ +es_CU/UTF-8 \ +es_DO.UTF-8/UTF-8 \ +es_DO/ISO-8859-1 \ +es_EC.UTF-8/UTF-8 \ +es_EC/ISO-8859-1 \ +es_ES.UTF-8/UTF-8 \ +es_ES/ISO-8859-1 \ +es_ES@euro/ISO-8859-15 \ +es_GT.UTF-8/UTF-8 \ +es_GT/ISO-8859-1 \ +es_HN.UTF-8/UTF-8 \ +es_HN/ISO-8859-1 \ +es_MX.UTF-8/UTF-8 \ +es_MX/ISO-8859-1 \ +es_NI.UTF-8/UTF-8 \ +es_NI/ISO-8859-1 \ +es_PA.UTF-8/UTF-8 \ +es_PA/ISO-8859-1 \ +es_PE.UTF-8/UTF-8 \ +es_PE/ISO-8859-1 \ +es_PR.UTF-8/UTF-8 \ +es_PR/ISO-8859-1 \ +es_PY.UTF-8/UTF-8 \ +es_PY/ISO-8859-1 \ +es_SV.UTF-8/UTF-8 \ +es_SV/ISO-8859-1 \ +es_US.UTF-8/UTF-8 \ +es_US/ISO-8859-1 \ +es_UY.UTF-8/UTF-8 \ +es_UY/ISO-8859-1 \ +es_VE.UTF-8/UTF-8 \ +es_VE/ISO-8859-1 \ +et_EE.UTF-8/UTF-8 \ +et_EE/ISO-8859-1 \ +et_EE.ISO-8859-15/ISO-8859-15 \ +eu_ES.UTF-8/UTF-8 \ +eu_ES/ISO-8859-1 \ +eu_ES@euro/ISO-8859-15 \ +fa_IR/UTF-8 \ +ff_SN/UTF-8 \ +fi_FI.UTF-8/UTF-8 \ +fi_FI/ISO-8859-1 \ +fi_FI@euro/ISO-8859-15 \ +fil_PH/UTF-8 \ +fo_FO.UTF-8/UTF-8 \ +fo_FO/ISO-8859-1 \ +fr_BE.UTF-8/UTF-8 \ +fr_BE/ISO-8859-1 \ +fr_BE@euro/ISO-8859-15 \ +fr_CA.UTF-8/UTF-8 \ +fr_CA/ISO-8859-1 \ +fr_CH.UTF-8/UTF-8 \ +fr_CH/ISO-8859-1 \ +fr_FR.UTF-8/UTF-8 \ +fr_FR/ISO-8859-1 \ +fr_FR@euro/ISO-8859-15 \ +fr_LU.UTF-8/UTF-8 \ +fr_LU/ISO-8859-1 \ +fr_LU@euro/ISO-8859-15 \ +fur_IT/UTF-8 \ +fy_NL/UTF-8 \ +fy_DE/UTF-8 \ +ga_IE.UTF-8/UTF-8 \ +ga_IE/ISO-8859-1 \ +ga_IE@euro/ISO-8859-15 \ +gd_GB.UTF-8/UTF-8 \ +gd_GB/ISO-8859-15 \ +gez_ER/UTF-8 \ +gez_ER@abegede/UTF-8 \ +gez_ET/UTF-8 \ +gez_ET@abegede/UTF-8 \ +gl_ES.UTF-8/UTF-8 \ +gl_ES/ISO-8859-1 \ +gl_ES@euro/ISO-8859-15 \ +gu_IN/UTF-8 \ +gv_GB.UTF-8/UTF-8 \ +gv_GB/ISO-8859-1 \ +ha_NG/UTF-8 \ +hak_TW/UTF-8 \ +he_IL.UTF-8/UTF-8 \ +he_IL/ISO-8859-8 \ +hi_IN/UTF-8 \ +hif_FJ/UTF-8 \ +hne_IN/UTF-8 \ +hr_HR.UTF-8/UTF-8 \ +hr_HR/ISO-8859-2 \ +hsb_DE/ISO-8859-2 \ +hsb_DE.UTF-8/UTF-8 \ +ht_HT/UTF-8 \ +hu_HU.UTF-8/UTF-8 \ +hu_HU/ISO-8859-2 \ +hy_AM/UTF-8 \ +hy_AM.ARMSCII-8/ARMSCII-8 \ +ia_FR/UTF-8 \ +id_ID.UTF-8/UTF-8 \ +id_ID/ISO-8859-1 \ +ig_NG/UTF-8 \ +ik_CA/UTF-8 \ +is_IS.UTF-8/UTF-8 \ +is_IS/ISO-8859-1 \ +it_CH.UTF-8/UTF-8 \ +it_CH/ISO-8859-1 \ +it_IT.UTF-8/UTF-8 \ +it_IT/ISO-8859-1 \ +it_IT@euro/ISO-8859-15 \ +iu_CA/UTF-8 \ +ja_JP.EUC-JP/EUC-JP \ +ja_JP.UTF-8/UTF-8 \ +ka_GE.UTF-8/UTF-8 \ +ka_GE/GEORGIAN-PS \ +kab_DZ/UTF-8 \ +kk_KZ.UTF-8/UTF-8 \ +kk_KZ/PT154 \ +kl_GL.UTF-8/UTF-8 \ +kl_GL/ISO-8859-1 \ +km_KH/UTF-8 \ +kn_IN/UTF-8 \ +ko_KR.EUC-KR/EUC-KR \ +ko_KR.UTF-8/UTF-8 \ +kok_IN/UTF-8 \ +ks_IN/UTF-8 \ +ks_IN@devanagari/UTF-8 \ +ku_TR.UTF-8/UTF-8 \ +ku_TR/ISO-8859-9 \ +kw_GB.UTF-8/UTF-8 \ +kw_GB/ISO-8859-1 \ +ky_KG/UTF-8 \ +lb_LU/UTF-8 \ +lg_UG.UTF-8/UTF-8 \ +lg_UG/ISO-8859-10 \ +li_BE/UTF-8 \ +li_NL/UTF-8 \ +lij_IT/UTF-8 \ +ln_CD/UTF-8 \ +lo_LA/UTF-8 \ +lt_LT.UTF-8/UTF-8 \ +lt_LT/ISO-8859-13 \ +lv_LV.UTF-8/UTF-8 \ +lv_LV/ISO-8859-13 \ +lzh_TW/UTF-8 \ +mag_IN/UTF-8 \ +mai_IN/UTF-8 \ +mai_NP/UTF-8 \ +mfe_MU/UTF-8 \ +mg_MG.UTF-8/UTF-8 \ +mg_MG/ISO-8859-15 \ +mhr_RU/UTF-8 \ +mi_NZ.UTF-8/UTF-8 \ +mi_NZ/ISO-8859-13 \ +miq_NI/UTF-8 \ +mjw_IN/UTF-8 \ +mk_MK.UTF-8/UTF-8 \ +mk_MK/ISO-8859-5 \ +ml_IN/UTF-8 \ +mn_MN/UTF-8 \ +mni_IN/UTF-8 \ +mr_IN/UTF-8 \ +ms_MY.UTF-8/UTF-8 \ +ms_MY/ISO-8859-1 \ +mt_MT.UTF-8/UTF-8 \ +mt_MT/ISO-8859-3 \ +my_MM/UTF-8 \ +nan_TW/UTF-8 \ +nan_TW@latin/UTF-8 \ +nb_NO.UTF-8/UTF-8 \ +nb_NO/ISO-8859-1 \ +nds_DE/UTF-8 \ +nds_NL/UTF-8 \ +ne_NP/UTF-8 \ +nhn_MX/UTF-8 \ +niu_NU/UTF-8 \ +niu_NZ/UTF-8 \ +nl_AW/UTF-8 \ +nl_BE.UTF-8/UTF-8 \ +nl_BE/ISO-8859-1 \ +nl_BE@euro/ISO-8859-15 \ +nl_NL.UTF-8/UTF-8 \ +nl_NL/ISO-8859-1 \ +nl_NL@euro/ISO-8859-15 \ +nn_NO.UTF-8/UTF-8 \ +nn_NO/ISO-8859-1 \ +nr_ZA/UTF-8 \ +nso_ZA/UTF-8 \ +oc_FR.UTF-8/UTF-8 \ +oc_FR/ISO-8859-1 \ +om_ET/UTF-8 \ +om_KE.UTF-8/UTF-8 \ +om_KE/ISO-8859-1 \ +or_IN/UTF-8 \ +os_RU/UTF-8 \ +pa_IN/UTF-8 \ +pa_PK/UTF-8 \ +pap_AW/UTF-8 \ +pap_CW/UTF-8 \ +pl_PL.UTF-8/UTF-8 \ +pl_PL/ISO-8859-2 \ +ps_AF/UTF-8 \ +pt_BR.UTF-8/UTF-8 \ +pt_BR/ISO-8859-1 \ +pt_PT.UTF-8/UTF-8 \ +pt_PT/ISO-8859-1 \ +pt_PT@euro/ISO-8859-15 \ +quz_PE/UTF-8 \ +raj_IN/UTF-8 \ +ro_RO.UTF-8/UTF-8 \ +ro_RO/ISO-8859-2 \ +ru_RU.KOI8-R/KOI8-R \ +ru_RU.UTF-8/UTF-8 \ +ru_RU/ISO-8859-5 \ +ru_UA.UTF-8/UTF-8 \ +ru_UA/KOI8-U \ +rw_RW/UTF-8 \ +sa_IN/UTF-8 \ +sah_RU/UTF-8 \ +sat_IN/UTF-8 \ +sc_IT/UTF-8 \ +sd_IN/UTF-8 \ +sd_IN@devanagari/UTF-8 \ +se_NO/UTF-8 \ +sgs_LT/UTF-8 \ +shn_MM/UTF-8 \ +shs_CA/UTF-8 \ +si_LK/UTF-8 \ +sid_ET/UTF-8 \ +sk_SK.UTF-8/UTF-8 \ +sk_SK/ISO-8859-2 \ +sl_SI.UTF-8/UTF-8 \ +sl_SI/ISO-8859-2 \ +sm_WS/UTF-8 \ +so_DJ.UTF-8/UTF-8 \ +so_DJ/ISO-8859-1 \ +so_ET/UTF-8 \ +so_KE.UTF-8/UTF-8 \ +so_KE/ISO-8859-1 \ +so_SO.UTF-8/UTF-8 \ +so_SO/ISO-8859-1 \ +sq_AL.UTF-8/UTF-8 \ +sq_AL/ISO-8859-1 \ +sq_MK/UTF-8 \ +sr_ME/UTF-8 \ +sr_RS/UTF-8 \ +sr_RS@latin/UTF-8 \ +ss_ZA/UTF-8 \ +st_ZA.UTF-8/UTF-8 \ +st_ZA/ISO-8859-1 \ +sv_FI.UTF-8/UTF-8 \ +sv_FI/ISO-8859-1 \ +sv_FI@euro/ISO-8859-15 \ +sv_SE.UTF-8/UTF-8 \ +sv_SE/ISO-8859-1 \ +sv_SE.ISO-8859-15/ISO-8859-15 \ +sw_KE/UTF-8 \ +sw_TZ/UTF-8 \ +szl_PL/UTF-8 \ +ta_IN/UTF-8 \ +ta_LK/UTF-8 \ +tcy_IN.UTF-8/UTF-8 \ +te_IN/UTF-8 \ +tg_TJ.UTF-8/UTF-8 \ +tg_TJ/KOI8-T \ +th_TH.UTF-8/UTF-8 \ +th_TH/TIS-620 \ +the_NP/UTF-8 \ +ti_ER/UTF-8 \ +ti_ET/UTF-8 \ +tig_ER/UTF-8 \ +tk_TM/UTF-8 \ +tl_PH.UTF-8/UTF-8 \ +tl_PH/ISO-8859-1 \ +tn_ZA/UTF-8 \ +to_TO/UTF-8 \ +tpi_PG/UTF-8 \ +tr_CY.UTF-8/UTF-8 \ +tr_CY/ISO-8859-9 \ +tr_TR.UTF-8/UTF-8 \ +tr_TR/ISO-8859-9 \ +ts_ZA/UTF-8 \ +tt_RU/UTF-8 \ +tt_RU@iqtelif/UTF-8 \ +ug_CN/UTF-8 \ +uk_UA.UTF-8/UTF-8 \ +uk_UA/KOI8-U \ +unm_US/UTF-8 \ +ur_IN/UTF-8 \ +ur_PK/UTF-8 \ +uz_UZ.UTF-8/UTF-8 \ +uz_UZ/ISO-8859-1 \ +uz_UZ@cyrillic/UTF-8 \ +ve_ZA/UTF-8 \ +vi_VN/UTF-8 \ +wa_BE/ISO-8859-1 \ +wa_BE@euro/ISO-8859-15 \ +wa_BE.UTF-8/UTF-8 \ +wae_CH/UTF-8 \ +wal_ET/UTF-8 \ +wo_SN/UTF-8 \ +xh_ZA.UTF-8/UTF-8 \ +xh_ZA/ISO-8859-1 \ +yi_US.UTF-8/UTF-8 \ +yi_US/CP1255 \ +yo_NG/UTF-8 \ +yue_HK/UTF-8 \ +yuw_PG/UTF-8 \ +zh_CN.GB18030/GB18030 \ +zh_CN.GBK/GBK \ +zh_CN.UTF-8/UTF-8 \ +zh_CN/GB2312 \ +zh_HK.UTF-8/UTF-8 \ +zh_HK/BIG5-HKSCS \ +zh_SG.UTF-8/UTF-8 \ +zh_SG.GBK/GBK \ +zh_SG/GB2312 \ +zh_TW.EUC-TW/EUC-TW \ +zh_TW.UTF-8/UTF-8 \ +zh_TW/BIG5 \ +zu_ZA.UTF-8/UTF-8 \ +zu_ZA/ISO-8859-1 \ diff --git a/SOURCES/bench.mk b/SOURCES/bench.mk new file mode 100644 index 0000000..dfe46bd --- /dev/null +++ b/SOURCES/bench.mk @@ -0,0 +1,77 @@ +objpfx = $(prefix)/$(ver)/usr/libexec/glibc-benchtests/ + +bench-math := acos acosh asin asinh atan atanh cos cosh exp exp2 ffs ffsll \ + log log2 modf pow rint sin sincos sinh sqrt tan tanh + +bench-pthread := pthread_once + +bench := $(bench-math) $(bench-pthread) + +run-bench := $(prefix)/$(ver)/lib64/ld-linux-x86-64.so.2 --library-path $(prefix)/$(ver)/lib64 $${run} + +# String function benchmarks. +string-bench := bcopy bzero memccpy memchr memcmp memcpy memmem memmove \ + mempcpy memset rawmemchr stpcpy stpncpy strcasecmp strcasestr \ + strcat strchr strchrnul strcmp strcpy strcspn strlen \ + strncasecmp strncat strncmp strncpy strnlen strpbrk strrchr \ + strspn strstr strcpy_chk stpcpy_chk memrchr strsep strtok +string-bench-all := $(string-bench) + +stdlib-bench := strtod + +benchset := $(string-bench-all) $(stdlib-bench) + +bench-malloc := malloc-thread + +binaries-bench := $(addprefix $(objpfx)bench-,$(bench)) +binaries-benchset := $(addprefix $(objpfx)bench-,$(benchset)) +binaries-bench-malloc := $(addprefix $(objpfx)bench-,$(bench-malloc)) + +DETAILED_OPT := + +ifdef DETAILED + DETAILED_OPT := -d +endif + +bench: bench-set bench-func bench-malloc + +bench-set: $(binaries-benchset) + for run in $^; do \ + outfile=$(prefix)/$$(basename $${run}.$(ver).out); \ + echo "Running $${run}"; \ + $(run-bench) > $${outfile}.tmp; \ + mv $${outfile}{.tmp,}; \ + done + +bench-malloc: $(binaries-bench-malloc) + run=$(objpfx)bench-malloc-thread; \ + outfile=$(prefix)/$$(basename $${run}.$(ver).out); \ + for thr in 1 8 16 32; do \ + echo "Running $${run} $${thr}"; \ + $(run-bench) $${thr} > $${outfile}.tmp; \ + mv $${outfile}{.tmp,}; \ + done + +# Build and execute the benchmark functions. This target generates JSON +# formatted bench.out. Each of the programs produce independent JSON output, +# so one could even execute them individually and process it using any JSON +# capable language or tool. +bench-func: $(binaries-bench) + { echo "{\"timing_type\": \"hp-timing\","; \ + echo " \"functions\": {"; \ + for run in $^; do \ + if ! [ "x$${run}" = "x$<" ]; then \ + echo ","; \ + fi; \ + echo "Running $${run}" >&2; \ + $(run-bench) $(DETAILED_OPT); \ + done; \ + echo; \ + echo " }"; \ + echo "}"; } > $(prefix)/bench.$(ver).out-tmp; \ + if [ -f $(prefix)/bench.$(ver).out ]; then \ + mv -f $(prefix)/bench.$(ver).out{,.old}; \ + fi; \ + mv -f $(prefix)/bench.$(ver).out{-tmp,} +# scripts/validate_benchout.py bench.out \ +# scripts/benchout.schema.json diff --git a/SOURCES/build-locale-archive.c b/SOURCES/build-locale-archive.c new file mode 100644 index 0000000..3cb3b47 --- /dev/null +++ b/SOURCES/build-locale-archive.c @@ -0,0 +1,862 @@ +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "../locale/hashval.h" +#define __LC_LAST 13 +#include "../locale/locarchive.h" +#include "../crypt/md5.h" + +const char *alias_file = DATADIR "/locale/locale.alias"; +const char *locar_file = PREFIX "/lib/locale/locale-archive"; +const char *tmpl_file = PREFIX "/lib/locale/locale-archive.tmpl"; +const char *loc_path = PREFIX "/lib/locale/"; +/* Flags set by `--verbose` option. */ +int be_quiet = 1; +int verbose = 0; +int max_locarchive_open_retry = 10; +const char *output_prefix; + +/* Endianness should have been taken care of by localedef. We don't need to do + additional swapping. We need this variable exported however, since + locarchive.c uses it to determine if it needs to swap endianness of a value + before writing to or reading from the archive. */ +bool swap_endianness_p = false; + +static const char *locnames[] = + { +#define DEFINE_CATEGORY(category, category_name, items, a) \ + [category] = category_name, +#include "../locale/categories.def" +#undef DEFINE_CATEGORY + }; + +static int +is_prime (unsigned long candidate) +{ + /* No even number and none less than 10 will be passed here. */ + unsigned long int divn = 3; + unsigned long int sq = divn * divn; + + while (sq < candidate && candidate % divn != 0) + { + ++divn; + sq += 4 * divn; + ++divn; + } + + return candidate % divn != 0; +} + +unsigned long +next_prime (unsigned long seed) +{ + /* Make it definitely odd. */ + seed |= 1; + + while (!is_prime (seed)) + seed += 2; + + return seed; +} + +void +error (int status, int errnum, const char *message, ...) +{ + va_list args; + + va_start (args, message); + fflush (stdout); + fprintf (stderr, "%s: ", program_invocation_name); + vfprintf (stderr, message, args); + va_end (args); + if (errnum) + fprintf (stderr, ": %s", strerror (errnum)); + putc ('\n', stderr); + fflush (stderr); + if (status) + exit (errnum == EROFS ? 0 : status); +} + +void * +xmalloc (size_t size) +{ + void *p = malloc (size); + if (p == NULL) + error (EXIT_FAILURE, errno, "could not allocate %zd bytes of memory", size); + return p; +} + +static void +open_tmpl_archive (struct locarhandle *ah) +{ + struct stat64 st; + int fd; + struct locarhead head; + const char *archivefname = ah->fname == NULL ? tmpl_file : ah->fname; + + /* Open the archive. We must have exclusive write access. */ + fd = open64 (archivefname, O_RDONLY); + if (fd == -1) + error (EXIT_FAILURE, errno, "cannot open locale archive template file \"%s\"", + archivefname); + + if (fstat64 (fd, &st) < 0) + error (EXIT_FAILURE, errno, "cannot stat locale archive template file \"%s\"", + archivefname); + + /* Read the header. */ + if (TEMP_FAILURE_RETRY (read (fd, &head, sizeof (head))) != sizeof (head)) + error (EXIT_FAILURE, errno, "cannot read archive header"); + + ah->fd = fd; + ah->mmaped = (head.sumhash_offset + + head.sumhash_size * sizeof (struct sumhashent)); + if (ah->mmaped > (unsigned long) st.st_size) + error (EXIT_FAILURE, 0, "locale archive template file truncated"); + ah->mmaped = st.st_size; + ah->reserved = st.st_size; + + /* Now we know how large the administrative information part is. + Map all of it. */ + ah->addr = mmap64 (NULL, ah->mmaped, PROT_READ, MAP_SHARED, fd, 0); + if (ah->addr == MAP_FAILED) + error (EXIT_FAILURE, errno, "cannot map archive header"); +} + +/* Open the locale archive. */ +extern void open_archive (struct locarhandle *ah, bool readonly); + +/* Close the locale archive. */ +extern void close_archive (struct locarhandle *ah); + +/* Add given locale data to the archive. */ +extern int add_locale_to_archive (struct locarhandle *ah, const char *name, + locale_data_t data, bool replace); + +extern void add_alias (struct locarhandle *ah, const char *alias, + bool replace, const char *oldname, + uint32_t *locrec_offset_p); + +extern struct namehashent * +insert_name (struct locarhandle *ah, + const char *name, size_t name_len, bool replace); + +struct nameent +{ + char *name; + struct locrecent *locrec; +}; + +struct dataent +{ + const unsigned char *sum; + uint32_t file_offset; +}; + +static int +nameentcmp (const void *a, const void *b) +{ + struct locrecent *la = ((const struct nameent *) a)->locrec; + struct locrecent *lb = ((const struct nameent *) b)->locrec; + uint32_t start_a = -1, end_a = 0; + uint32_t start_b = -1, end_b = 0; + int cnt; + + for (cnt = 0; cnt < __LC_LAST; ++cnt) + if (cnt != LC_ALL) + { + if (la->record[cnt].offset < start_a) + start_a = la->record[cnt].offset; + if (la->record[cnt].offset + la->record[cnt].len > end_a) + end_a = la->record[cnt].offset + la->record[cnt].len; + } + assert (start_a != (uint32_t)-1); + assert (end_a != 0); + + for (cnt = 0; cnt < __LC_LAST; ++cnt) + if (cnt != LC_ALL) + { + if (lb->record[cnt].offset < start_b) + start_b = lb->record[cnt].offset; + if (lb->record[cnt].offset + lb->record[cnt].len > end_b) + end_b = lb->record[cnt].offset + lb->record[cnt].len; + } + assert (start_b != (uint32_t)-1); + assert (end_b != 0); + + if (start_a != start_b) + return (int)start_a - (int)start_b; + return (int)end_a - (int)end_b; +} + +static int +dataentcmp (const void *a, const void *b) +{ + if (((const struct dataent *) a)->file_offset + < ((const struct dataent *) b)->file_offset) + return -1; + + if (((const struct dataent *) a)->file_offset + > ((const struct dataent *) b)->file_offset) + return 1; + + return 0; +} + +static int +sumsearchfn (const void *key, const void *ent) +{ + uint32_t keyn = *(uint32_t *)key; + uint32_t entn = ((struct dataent *)ent)->file_offset; + + if (keyn < entn) + return -1; + if (keyn > entn) + return 1; + return 0; +} + +static void +compute_data (struct locarhandle *ah, struct nameent *name, size_t sumused, + struct dataent *files, locale_data_t data) +{ + int cnt; + struct locrecent *locrec = name->locrec; + struct dataent *file; + data[LC_ALL].addr = ((char *) ah->addr) + locrec->record[LC_ALL].offset; + data[LC_ALL].size = locrec->record[LC_ALL].len; + for (cnt = 0; cnt < __LC_LAST; ++cnt) + if (cnt != LC_ALL) + { + data[cnt].addr = ((char *) ah->addr) + locrec->record[cnt].offset; + data[cnt].size = locrec->record[cnt].len; + if (data[cnt].addr >= data[LC_ALL].addr + && data[cnt].addr + data[cnt].size + <= data[LC_ALL].addr + data[LC_ALL].size) + __md5_buffer (data[cnt].addr, data[cnt].size, data[cnt].sum); + else + { + file = bsearch (&locrec->record[cnt].offset, files, sumused, + sizeof (*files), sumsearchfn); + if (file == NULL) + error (EXIT_FAILURE, 0, "inconsistent template file"); + memcpy (data[cnt].sum, file->sum, sizeof (data[cnt].sum)); + } + } +} + +static int +fill_archive (struct locarhandle *tmpl_ah, + const char *fname, + size_t install_langs_count, char *install_langs_list[], + size_t nlist, char *list[], + const char *primary) +{ + struct locarhandle ah; + struct locarhead *head; + int result = 0; + struct nameent *names; + struct namehashent *namehashtab; + size_t cnt, used; + struct dataent *files; + struct sumhashent *sumhashtab; + size_t sumused; + struct locrecent *primary_locrec = NULL; + struct nameent *primary_nameent = NULL; + + head = tmpl_ah->addr; + names = (struct nameent *) malloc (head->namehash_used + * sizeof (struct nameent)); + files = (struct dataent *) malloc (head->sumhash_used + * sizeof (struct dataent)); + if (names == NULL || files == NULL) + error (EXIT_FAILURE, errno, "could not allocate tables"); + + namehashtab = (struct namehashent *) ((char *) tmpl_ah->addr + + head->namehash_offset); + sumhashtab = (struct sumhashent *) ((char *) tmpl_ah->addr + + head->sumhash_offset); + + for (cnt = used = 0; cnt < head->namehash_size; ++cnt) + if (namehashtab[cnt].locrec_offset != 0) + { + char * name; + int i; + assert (used < head->namehash_used); + name = tmpl_ah->addr + namehashtab[cnt].name_offset; + if (install_langs_count == 0) + { + /* Always intstall the entry. */ + names[used].name = name; + names[used++].locrec + = (struct locrecent *) ((char *) tmpl_ah->addr + + namehashtab[cnt].locrec_offset); + } + else + { + /* Only install the entry if the user asked for it via + --install-langs. */ + for (i = 0; i < install_langs_count; i++) + { + /* Add one for "_" and one for the null terminator. */ + size_t len = strlen (install_langs_list[i]) + 2; + char *install_lang = (char *)xmalloc (len); + strcpy (install_lang, install_langs_list[i]); + if (strchr (install_lang, '_') == NULL) + strcat (install_lang, "_"); + if (strncmp (name, install_lang, strlen (install_lang)) == 0) + { + names[used].name = name; + names[used++].locrec + = (struct locrecent *) ((char *)tmpl_ah->addr + + namehashtab[cnt].locrec_offset); + } + free (install_lang); + } + } + } + + /* Sort the names. */ + qsort (names, used, sizeof (struct nameent), nameentcmp); + + for (cnt = sumused = 0; cnt < head->sumhash_size; ++cnt) + if (sumhashtab[cnt].file_offset != 0) + { + assert (sumused < head->sumhash_used); + files[sumused].sum = (const unsigned char *) sumhashtab[cnt].sum; + files[sumused++].file_offset = sumhashtab[cnt].file_offset; + } + + /* Sort by file locations. */ + qsort (files, sumused, sizeof (struct dataent), dataentcmp); + + /* Open the archive. This call never returns if we cannot + successfully open the archive. */ + ah.fname = NULL; + if (fname != NULL) + ah.fname = fname; + open_archive (&ah, false); + + if (primary != NULL) + { + for (cnt = 0; cnt < used; ++cnt) + if (strcmp (names[cnt].name, primary) == 0) + break; + if (cnt < used) + { + locale_data_t data; + + compute_data (tmpl_ah, &names[cnt], sumused, files, data); + result |= add_locale_to_archive (&ah, primary, data, 0); + primary_locrec = names[cnt].locrec; + primary_nameent = &names[cnt]; + } + } + + for (cnt = 0; cnt < used; ++cnt) + if (&names[cnt] == primary_nameent) + continue; + else if ((cnt > 0 && names[cnt - 1].locrec == names[cnt].locrec) + || names[cnt].locrec == primary_locrec) + { + const char *oldname; + struct namehashent *namehashent; + uint32_t locrec_offset; + + if (names[cnt].locrec == primary_locrec) + oldname = primary; + else + oldname = names[cnt - 1].name; + namehashent = insert_name (&ah, oldname, strlen (oldname), true); + assert (namehashent->name_offset != 0); + assert (namehashent->locrec_offset != 0); + locrec_offset = namehashent->locrec_offset; + add_alias (&ah, names[cnt].name, 0, oldname, &locrec_offset); + } + else + { + locale_data_t data; + + compute_data (tmpl_ah, &names[cnt], sumused, files, data); + result |= add_locale_to_archive (&ah, names[cnt].name, data, 0); + } + + while (nlist-- > 0) + { + const char *fname = *list++; + size_t fnamelen = strlen (fname); + struct stat64 st; + DIR *dirp; + struct dirent64 *d; + int seen; + locale_data_t data; + int cnt; + + /* First see whether this really is a directory and whether it + contains all the require locale category files. */ + if (stat64 (fname, &st) < 0) + { + error (0, 0, "stat of \"%s\" failed: %s: ignored", fname, + strerror (errno)); + continue; + } + if (!S_ISDIR (st.st_mode)) + { + error (0, 0, "\"%s\" is no directory; ignored", fname); + continue; + } + + dirp = opendir (fname); + if (dirp == NULL) + { + error (0, 0, "cannot open directory \"%s\": %s: ignored", + fname, strerror (errno)); + continue; + } + + seen = 0; + while ((d = readdir64 (dirp)) != NULL) + { + for (cnt = 0; cnt < __LC_LAST; ++cnt) + if (cnt != LC_ALL) + if (strcmp (d->d_name, locnames[cnt]) == 0) + { + unsigned char d_type; + + /* We have an object of the required name. If it's + a directory we have to look at a file with the + prefix "SYS_". Otherwise we have found what we + are looking for. */ +#ifdef _DIRENT_HAVE_D_TYPE + d_type = d->d_type; + + if (d_type != DT_REG) +#endif + { + char fullname[fnamelen + 2 * strlen (d->d_name) + 7]; + +#ifdef _DIRENT_HAVE_D_TYPE + if (d_type == DT_UNKNOWN || d_type == DT_LNK) +#endif + { + strcpy (stpcpy (stpcpy (fullname, fname), "/"), + d->d_name); + + if (stat64 (fullname, &st) == -1) + /* We cannot stat the file, ignore it. */ + break; + + d_type = IFTODT (st.st_mode); + } + + if (d_type == DT_DIR) + { + /* We have to do more tests. The file is a + directory and it therefore must contain a + regular file with the same name except a + "SYS_" prefix. */ + char *t = stpcpy (stpcpy (fullname, fname), "/"); + strcpy (stpcpy (stpcpy (t, d->d_name), "/SYS_"), + d->d_name); + + if (stat64 (fullname, &st) == -1) + /* There is no SYS_* file or we cannot + access it. */ + break; + + d_type = IFTODT (st.st_mode); + } + } + + /* If we found a regular file (eventually after + following a symlink) we are successful. */ + if (d_type == DT_REG) + ++seen; + break; + } + } + + closedir (dirp); + + if (seen != __LC_LAST - 1) + { + /* We don't have all locale category files. Ignore the name. */ + error (0, 0, "incomplete set of locale files in \"%s\"", + fname); + continue; + } + + /* Add the files to the archive. To do this we first compute + sizes and the MD5 sums of all the files. */ + for (cnt = 0; cnt < __LC_LAST; ++cnt) + if (cnt != LC_ALL) + { + char fullname[fnamelen + 2 * strlen (locnames[cnt]) + 7]; + int fd; + + strcpy (stpcpy (stpcpy (fullname, fname), "/"), locnames[cnt]); + fd = open64 (fullname, O_RDONLY); + if (fd == -1 || fstat64 (fd, &st) == -1) + { + /* Cannot read the file. */ + if (fd != -1) + close (fd); + break; + } + + if (S_ISDIR (st.st_mode)) + { + char *t; + close (fd); + t = stpcpy (stpcpy (fullname, fname), "/"); + strcpy (stpcpy (stpcpy (t, locnames[cnt]), "/SYS_"), + locnames[cnt]); + + fd = open64 (fullname, O_RDONLY); + if (fd == -1 || fstat64 (fd, &st) == -1 + || !S_ISREG (st.st_mode)) + { + if (fd != -1) + close (fd); + break; + } + } + + /* Map the file. */ + data[cnt].addr = mmap64 (NULL, st.st_size, PROT_READ, MAP_SHARED, + fd, 0); + if (data[cnt].addr == MAP_FAILED) + { + /* Cannot map it. */ + close (fd); + break; + } + + data[cnt].size = st.st_size; + __md5_buffer (data[cnt].addr, st.st_size, data[cnt].sum); + + /* We don't need the file descriptor anymore. */ + close (fd); + } + + if (cnt != __LC_LAST) + { + while (cnt-- > 0) + if (cnt != LC_ALL) + munmap (data[cnt].addr, data[cnt].size); + + error (0, 0, "cannot read all files in \"%s\": ignored", fname); + + continue; + } + + result |= add_locale_to_archive (&ah, basename (fname), data, 0); + + for (cnt = 0; cnt < __LC_LAST; ++cnt) + if (cnt != LC_ALL) + munmap (data[cnt].addr, data[cnt].size); + } + + /* We are done. */ + close_archive (&ah); + + return result; +} + +void usage() +{ + printf ("\ +Usage: build-locale-archive [OPTION]... [TEMPLATE-FILE] [ARCHIVE-FILE]\n\ + Builds a locale archive from a template file.\n\ + Options:\n\ + -h, --help Print this usage message.\n\ + -v, --verbose Verbose execution.\n\ + -l, --install-langs=LIST Only include locales given in LIST into the \n\ + locale archive. LIST is a colon separated list\n\ + of locale prefixes, for example \"de:en:ja\".\n\ + The special argument \"all\" means to install\n\ + all languages and it must be present by itself.\n\ + If \"all\" is present with any other language it\n\ + will be treated as the name of a locale.\n\ + If the --install-langs option is missing, all\n\ + locales are installed. The colon separated list\n\ + can contain any strings matching the beginning of\n\ + locale names.\n\ + If a string does not contain a \"_\", it is added.\n\ + Examples:\n\ + --install-langs=\"en\"\n\ + installs en_US, en_US.iso88591,\n\ + en_US.iso885915, en_US.utf8,\n\ + en_GB ...\n\ + --install-langs=\"en_US.utf8\"\n\ + installs only en_US.utf8.\n\ + --install-langs=\"ko\"\n\ + installs ko_KR, ko_KR.euckr,\n\ + ko_KR.utf8 but *not* kok_IN\n\ + because \"ko\" does not contain\n\ + \"_\" and it is silently added\n\ + --install-langs\"ko:kok\"\n\ + installs ko_KR, ko_KR.euckr,\n\ + ko_KR.utf8, kok_IN, and\n\ + kok_IN.utf8.\n\ + --install-langs=\"POSIX\" will\n\ + installs *no* locales at all\n\ + because POSIX matches none of\n\ + the locales. Actually, any string\n\ + matching nothing will do that.\n\ + POSIX and C will always be\n\ + available because they are\n\ + builtin.\n\ + Aliases are installed as well,\n\ + i.e. --install-langs=\"de\"\n\ + will install not only every locale starting with\n\ + \"de\" but also the aliases \"deutsch\"\n\ + and and \"german\" although the latter does not\n\ + start with \"de\".\n\ +\n\ + If the arguments TEMPLATE-FILE and ARCHIVE-FILE are not given the locations\n\ + where the glibc used expects these files are used by default.\n\ +"); +} + +int main (int argc, char *argv[]) +{ + char path[4096]; + DIR *dirp; + struct dirent64 *d; + struct stat64 st; + char *list[16384], *primary; + char *lang; + int install_langs_count = 0; + int i; + char *install_langs_arg, *ila_start; + char **install_langs_list = NULL; + unsigned int cnt = 0; + struct locarhandle tmpl_ah; + char *new_locar_fname = NULL; + size_t loc_path_len = strlen (loc_path); + + while (1) + { + int c; + + static struct option long_options[] = + { + {"help", no_argument, 0, 'h'}, + {"verbose", no_argument, 0, 'v'}, + {"install-langs", required_argument, 0, 'l'}, + {0, 0, 0, 0} + }; + /* getopt_long stores the option index here. */ + int option_index = 0; + + c = getopt_long (argc, argv, "vhl:", + long_options, &option_index); + + /* Detect the end of the options. */ + if (c == -1) + break; + + switch (c) + { + case 0: + printf ("unknown option %s", long_options[option_index].name); + if (optarg) + printf (" with arg %s", optarg); + printf ("\n"); + usage (); + exit (1); + + case 'v': + verbose = 1; + be_quiet = 0; + break; + + case 'h': + usage (); + exit (0); + + case 'l': + install_langs_arg = ila_start = strdup (optarg); + /* If the argument to --install-lang is "all", do + not limit the list of languages to install and install + them all. We do not support installing a single locale + called "all". */ +#define MAGIC_INSTALL_ALL "all" + if (install_langs_arg != NULL + && install_langs_arg[0] != '\0' + && !(strncmp(install_langs_arg, MAGIC_INSTALL_ALL, + strlen(MAGIC_INSTALL_ALL)) == 0 + && strlen (install_langs_arg) == 3)) + { + /* Count the number of languages we will install. */ + while (true) + { + lang = strtok(install_langs_arg, ":;,"); + if (lang == NULL) + break; + install_langs_count++; + install_langs_arg = NULL; + } + free (ila_start); + + /* Reject an entire string made up of delimiters. */ + if (install_langs_count == 0) + break; + + /* Copy the list. */ + install_langs_list = (char **)xmalloc (sizeof(char *) * install_langs_count); + install_langs_arg = ila_start = strdup (optarg); + install_langs_count = 0; + while (true) + { + lang = strtok(install_langs_arg, ":;,"); + if (lang == NULL) + break; + install_langs_list[install_langs_count] = lang; + install_langs_count++; + install_langs_arg = NULL; + } + } + break; + + case '?': + /* getopt_long already printed an error message. */ + usage (); + exit (0); + + default: + abort (); + } + } + tmpl_ah.fname = NULL; + if (optind < argc) + tmpl_ah.fname = argv[optind]; + if (optind + 1 < argc) + new_locar_fname = argv[optind + 1]; + if (verbose) + { + if (tmpl_ah.fname) + printf("input archive file specified on command line: %s\n", + tmpl_ah.fname); + else + printf("using default input archive file.\n"); + if (new_locar_fname) + printf("output archive file specified on command line: %s\n", + new_locar_fname); + else + printf("using default output archive file.\n"); + } + + dirp = opendir (loc_path); + if (dirp == NULL) + error (EXIT_FAILURE, errno, "cannot open directory \"%s\"", loc_path); + + open_tmpl_archive (&tmpl_ah); + + if (new_locar_fname) + unlink (new_locar_fname); + else + unlink (locar_file); + primary = getenv ("LC_ALL"); + if (primary == NULL) + primary = getenv ("LANG"); + if (primary != NULL) + { + if (strncmp (primary, "ja", 2) != 0 + && strncmp (primary, "ko", 2) != 0 + && strncmp (primary, "zh", 2) != 0) + { + char *ptr = malloc (strlen (primary) + strlen (".utf8") + 1), *p, *q; + /* This leads to invalid locales sometimes: + de_DE.iso885915@euro -> de_DE.utf8@euro */ + if (ptr != NULL) + { + p = ptr; + q = primary; + while (*q && *q != '.' && *q != '@') + *p++ = *q++; + if (*q == '.') + while (*q && *q != '@') + q++; + p = stpcpy (p, ".utf8"); + strcpy (p, q); + primary = ptr; + } + else + primary = NULL; + } + } + + memcpy (path, loc_path, loc_path_len); + + while ((d = readdir64 (dirp)) != NULL) + { + if (strcmp (d->d_name, ".") == 0 || strcmp (d->d_name, "..") == 0) + continue; + if (strchr (d->d_name, '_') == NULL) + continue; + + size_t d_name_len = strlen (d->d_name); + if (loc_path_len + d_name_len + 1 > sizeof (path)) + { + error (0, 0, "too long filename \"%s\"", d->d_name); + continue; + } + + memcpy (path + loc_path_len, d->d_name, d_name_len + 1); + if (stat64 (path, &st) < 0) + { + error (0, errno, "cannot stat \"%s\"", path); + continue; + } + if (! S_ISDIR (st.st_mode)) + continue; + if (cnt == 16384) + { + error (0, 0, "too many directories in \"%s\"", loc_path); + break; + } + list[cnt] = strdup (path); + if (list[cnt] == NULL) + { + error (0, errno, "cannot add file to list \"%s\"", path); + continue; + } + if (primary != NULL && cnt > 0 && strcmp (primary, d->d_name) == 0) + { + char *p = list[0]; + list[0] = list[cnt]; + list[cnt] = p; + } + cnt++; + } + closedir (dirp); + /* Store the archive to the file specified as the second argument on the + command line or the default locale archive. */ + fill_archive (&tmpl_ah, new_locar_fname, + install_langs_count, install_langs_list, + cnt, list, primary); + close_archive (&tmpl_ah); + truncate (tmpl_file, 0); + if (install_langs_count > 0) + { + free (ila_start); + free (install_langs_list); + } + char *tz_argv[] = { "/usr/sbin/tzdata-update", NULL }; + execve (tz_argv[0], (char *const *)tz_argv, (char *const *)&tz_argv[1]); + exit (0); +} diff --git a/SOURCES/glibc-RHEL-10481.patch b/SOURCES/glibc-RHEL-10481.patch new file mode 100644 index 0000000..825f13c --- /dev/null +++ b/SOURCES/glibc-RHEL-10481.patch @@ -0,0 +1,112 @@ +commit 849274d48fc59bfa6db3c713c8ced8026b20f3b7 +Author: Florian Weimer +Date: Thu Nov 16 19:55:35 2023 +0100 + + elf: Fix force_first handling in dlclose (bug 30981) + + The force_first parameter was ineffective because the dlclose'd + object was not necessarily the first in the maps array. Also + enable force_first handling unconditionally, regardless of namespace. + The initial object in a namespace should be destructed first, too. + + The _dl_sort_maps_dfs function had early returns for relocation + dependency processing which broke force_first handling, too, and + this is fixed in this change as well. + + Reviewed-by: Adhemerval Zanella + +diff --git a/elf/dl-close.c b/elf/dl-close.c +index 66524b6708c59f29..8107c2d5f6ad2bc6 100644 +--- a/elf/dl-close.c ++++ b/elf/dl-close.c +@@ -182,6 +182,16 @@ _dl_close_worker (struct link_map *map, bool force) + } + assert (idx == nloaded); + ++ /* Put the dlclose'd map first, so that its destructor runs first. ++ The map variable is NULL after a retry. */ ++ if (map != NULL) ++ { ++ maps[map->l_idx] = maps[0]; ++ maps[map->l_idx]->l_idx = map->l_idx; ++ maps[0] = map; ++ maps[0]->l_idx = 0; ++ } ++ + /* Keep track of the lowest index link map we have covered already. */ + int done_index = -1; + while (++done_index < nloaded) +@@ -255,9 +265,10 @@ _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, nloaded, (nsid == LM_ID_BASE), true); ++ /* Sort the entries. Unless retrying, the maps[0] object (the ++ original argument to dlclose) needs to remain first, so that its ++ destructor runs first. */ ++ _dl_sort_maps (maps, nloaded, /* force_first */ map != NULL, true); + + /* Call all termination functions at once. */ + bool unload_any = false; +@@ -768,7 +779,11 @@ _dl_close_worker (struct link_map *map, bool force) + /* Recheck if we need to retry, release the lock. */ + out: + if (dl_close_state == rerun) +- goto retry; ++ { ++ /* The map may have been deallocated. */ ++ map = NULL; ++ goto retry; ++ } + + dl_close_state = not_pending; + } +diff --git a/elf/dl-sort-maps.c b/elf/dl-sort-maps.c +index aeb79b40b45054c0..c17ac325eca658ef 100644 +--- a/elf/dl-sort-maps.c ++++ b/elf/dl-sort-maps.c +@@ -260,13 +260,12 @@ _dl_sort_maps_dfs (struct link_map **maps, unsigned int nmaps, + 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; ++ break; + } + assert (maps_head == maps); +- return; + } +- +- memcpy (maps, rpo, sizeof (struct link_map *) * nmaps); ++ else ++ 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 +diff --git a/elf/dso-sort-tests-1.def b/elf/dso-sort-tests-1.def +index 4bf9052db16fb352..cf6453e9eb85ac65 100644 +--- a/elf/dso-sort-tests-1.def ++++ b/elf/dso-sort-tests-1.def +@@ -56,14 +56,16 @@ 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 older dynamic_sort=1 algorithm originally did not achieve this, ++# but this was a bug in the way _dl_sort_maps was called from _dl_close_worker, ++# effectively disabling proper force_first handling. ++# The new dynamic_sort=2 algorithm shows the effect of the simpler force_first ++# handling: the a object is simply moved to the front. + # 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 +-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[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[ +Date: Tue Aug 29 08:28:31 2023 +0200 + + nscd: Skip unusable entries in first pass in prune_cache (bug 30800) + + Previously, if an entry was marked unusable for any reason, but had + not timed out yet, the assert would trigger. + + One way to get into such state is if a data change is detected during + re-validation of an entry. This causes the entry to be marked as not + usable. If exits nscd soon after that, then the clock jumps + backwards, and nscd restarted, the cache re-validation run after + startup triggers the removed assert. + + The change is more complicated than just the removal of the assert + because entries marked as not usable should be garbage-collected in + the second pass. To make this happen, it is necessary to update some + book-keeping data. + + Reviewed-by: DJ Delorie + +diff --git a/nscd/cache.c b/nscd/cache.c +index efe4214d953edb30..2fd3f78ebb567bbe 100644 +--- a/nscd/cache.c ++++ b/nscd/cache.c +@@ -371,8 +371,11 @@ prune_cache (struct database_dyn *table, time_t now, int fd) + serv2str[runp->type], str, dh->timeout); + } + +- /* Check whether the entry timed out. */ +- if (dh->timeout < now) ++ /* Check whether the entry timed out. Timed out entries ++ will be revalidated. For unusable records, it is still ++ necessary to record that the bucket needs to be scanned ++ again below. */ ++ if (dh->timeout < now || !dh->usable) + { + /* This hash bucket could contain entries which need to + be looked at. */ +@@ -384,7 +387,7 @@ prune_cache (struct database_dyn *table, time_t now, int fd) + /* We only have to look at the data of the first entries + since the count information is kept in the data part + which is shared. */ +- if (runp->first) ++ if (runp->first && dh->usable) + { + + /* At this point there are two choices: we reload the +@@ -400,9 +403,6 @@ prune_cache (struct database_dyn *table, time_t now, int fd) + { + /* Remove the value. */ + dh->usable = false; +- +- /* We definitely have some garbage entries now. */ +- any = true; + } + else + { +@@ -414,18 +414,15 @@ prune_cache (struct database_dyn *table, time_t now, int fd) + + time_t timeout = readdfcts[runp->type] (table, runp, dh); + next_timeout = MIN (next_timeout, timeout); +- +- /* If the entry has been replaced, we might need +- cleanup. */ +- any |= !dh->usable; + } + } ++ ++ /* If the entry has been replaced, we might need cleanup. */ ++ any |= !dh->usable; + } + else +- { +- assert (dh->usable); +- next_timeout = MIN (next_timeout, dh->timeout); +- } ++ /* Entry has not timed out and is usable. */ ++ next_timeout = MIN (next_timeout, dh->timeout); + + run = runp->next; + } diff --git a/SOURCES/glibc-RHEL-13720-1.patch b/SOURCES/glibc-RHEL-13720-1.patch new file mode 100644 index 0000000..5eab70c --- /dev/null +++ b/SOURCES/glibc-RHEL-13720-1.patch @@ -0,0 +1,72 @@ +commit 2aa0974d2573441bffd596b07bff8698b1f2f18c +Author: Florian Weimer +Date: Fri Oct 20 14:29:50 2023 +0200 + + elf: ldconfig should skip temporary files created by package managers + + This avoids crashes due to partially written files, after a package + update is interrupted. + + Reviewed-by: Adhemerval Zanella + +Conflicts: + elf/ldconfig.c + (missing alloca removal downstream) + +diff --git a/elf/ldconfig.c b/elf/ldconfig.c +index 8c66d7e5426d8cc4..51de08f91fbaf093 100644 +--- a/elf/ldconfig.c ++++ b/elf/ldconfig.c +@@ -771,6 +771,31 @@ struct dlib_entry + struct dlib_entry *next; + }; + ++/* Skip some temporary DSO files. These files may be partially written ++ and lead to ldconfig crashes when examined. */ ++static bool ++skip_dso_based_on_name (const char *name, size_t len) ++{ ++ /* Skip temporary files created by the prelink program. Files with ++ names like these are never really DSOs we want to look at. */ ++ if (len >= sizeof (".#prelink#") - 1) ++ { ++ if (strcmp (name + len - sizeof (".#prelink#") + 1, ++ ".#prelink#") == 0) ++ return true; ++ if (len >= sizeof (".#prelink#.XXXXXX") - 1 ++ && memcmp (name + len - sizeof (".#prelink#.XXXXXX") ++ + 1, ".#prelink#.", sizeof (".#prelink#.") - 1) == 0) ++ return true; ++ } ++ /* Skip temporary files created by RPM. */ ++ if (memchr (name, len, ';') != NULL) ++ return true; ++ /* Skip temporary files created by dpkg. */ ++ if (len > 4 && memcmp (name + len - 4, ".tmp", 4) == 0) ++ return true; ++ return false; ++} + + static void + search_dir (const struct dir_entry *entry) +@@ -849,18 +874,8 @@ search_dir (const struct dir_entry *entry) + continue; + + size_t len = strlen (direntry->d_name); +- /* Skip temporary files created by the prelink program. Files with +- names like these are never really DSOs we want to look at. */ +- if (len >= sizeof (".#prelink#") - 1) +- { +- if (strcmp (direntry->d_name + len - sizeof (".#prelink#") + 1, +- ".#prelink#") == 0) +- continue; +- if (len >= sizeof (".#prelink#.XXXXXX") - 1 +- && memcmp (direntry->d_name + len - sizeof (".#prelink#.XXXXXX") +- + 1, ".#prelink#.", sizeof (".#prelink#.") - 1) == 0) +- continue; +- } ++ if (skip_dso_based_on_name (direntry->d_name, len)) ++ continue; + len += strlen (entry->path) + 2; + if (len > file_name_len) + { diff --git a/SOURCES/glibc-RHEL-13720-2.patch b/SOURCES/glibc-RHEL-13720-2.patch new file mode 100644 index 0000000..69d5a90 --- /dev/null +++ b/SOURCES/glibc-RHEL-13720-2.patch @@ -0,0 +1,61 @@ +commit cfb5a97a93ea656e3b2263e42142a4032986d9ba +Author: Florian Weimer +Date: Mon Oct 23 12:53:16 2023 +0200 + + ldconfig: Fixes for skipping temporary files. + + Arguments to a memchr call were swapped, causing incorrect skipping + of files. + + Files related to dpkg have different names: they actually end in + .dpkg-new and .dpkg-tmp, not .tmp as I mistakenly assumed. + + Fixes commit 2aa0974d2573441bffd59 ("elf: ldconfig should skip + temporary files created by package managers"). + +diff --git a/elf/ldconfig.c b/elf/ldconfig.c +index 51de08f91fbaf093..fb19dd68d41c07a4 100644 +--- a/elf/ldconfig.c ++++ b/elf/ldconfig.c +@@ -771,6 +771,17 @@ struct dlib_entry + struct dlib_entry *next; + }; + ++/* Return true if the N bytes at NAME end with with the characters in ++ the string SUFFIX. (NAME[N + 1] does not have to be a null byte.) ++ Expected to be called with a string literal for SUFFIX. */ ++static inline bool ++endswithn (const char *name, size_t n, const char *suffix) ++{ ++ return (n >= strlen (suffix) ++ && memcmp (name + n - strlen (suffix), suffix, ++ strlen (suffix)) == 0); ++} ++ + /* Skip some temporary DSO files. These files may be partially written + and lead to ldconfig crashes when examined. */ + static bool +@@ -780,8 +791,7 @@ skip_dso_based_on_name (const char *name, size_t len) + names like these are never really DSOs we want to look at. */ + if (len >= sizeof (".#prelink#") - 1) + { +- if (strcmp (name + len - sizeof (".#prelink#") + 1, +- ".#prelink#") == 0) ++ if (endswithn (name, len, ".#prelink#")) + return true; + if (len >= sizeof (".#prelink#.XXXXXX") - 1 + && memcmp (name + len - sizeof (".#prelink#.XXXXXX") +@@ -789,10 +799,11 @@ skip_dso_based_on_name (const char *name, size_t len) + return true; + } + /* Skip temporary files created by RPM. */ +- if (memchr (name, len, ';') != NULL) ++ if (memchr (name, ';', len) != NULL) + return true; + /* Skip temporary files created by dpkg. */ +- if (len > 4 && memcmp (name + len - 4, ".tmp", 4) == 0) ++ if (endswithn (name, len, ".dpkg-new") ++ || endswithn (name, len, ".dpkg-tmp")) + return true; + return false; + } diff --git a/SOURCES/glibc-RHEL-15696-1.patch b/SOURCES/glibc-RHEL-15696-1.patch new file mode 100644 index 0000000..804de54 --- /dev/null +++ b/SOURCES/glibc-RHEL-15696-1.patch @@ -0,0 +1,259 @@ +From 97700a34f36721b11a754cf37a1cc40695ece1fd Mon Sep 17 00:00:00 2001 +From: "H.J. Lu" +Date: Mon, 21 Jan 2019 11:23:59 -0800 +Subject: [PATCH] x86-64 memchr/wmemchr: Properly handle the length parameter + [BZ# 24097] +Content-type: text/plain; charset=UTF-8 + +On x32, the size_t parameter may be passed in the lower 32 bits of a +64-bit register with the non-zero upper 32 bits. The string/memory +functions written in assembly can only use the lower 32 bits of a +64-bit register as length or must clear the upper 32 bits before using +the full 64-bit register for length. + +This pach fixes memchr/wmemchr for x32. Tested on x86-64 and x32. On +x86-64, libc.so is the same with and withou the fix. + + [BZ# 24097] + CVE-2019-6488 + * sysdeps/x86_64/memchr.S: Use RDX_LP for length. Clear the + upper 32 bits of RDX register. + * sysdeps/x86_64/multiarch/memchr-avx2.S: Likewise. + * sysdeps/x86_64/x32/Makefile (tests): Add tst-size_t-memchr and + tst-size_t-wmemchr. + * sysdeps/x86_64/x32/test-size_t.h: New file. + * sysdeps/x86_64/x32/tst-size_t-memchr.c: Likewise. + * sysdeps/x86_64/x32/tst-size_t-wmemchr.c: Likewise. +--- + sysdeps/x86_64/memchr.S | 10 ++-- + sysdeps/x86_64/multiarch/memchr-avx2.S | 8 ++- + sysdeps/x86_64/x32/Makefile | 8 +++ + sysdeps/x86_64/x32/test-size_t.h | 35 ++++++++++++ + sysdeps/x86_64/x32/tst-size_t-memchr.c | 72 +++++++++++++++++++++++++ + sysdeps/x86_64/x32/tst-size_t-wmemchr.c | 20 +++++++ + 6 files changed, 148 insertions(+), 5 deletions(-) + create mode 100644 sysdeps/x86_64/x32/test-size_t.h + create mode 100644 sysdeps/x86_64/x32/tst-size_t-memchr.c + create mode 100644 sysdeps/x86_64/x32/tst-size_t-wmemchr.c + +Conflicts: + ChangeLog + (removed) + NEWS + (removed) + +diff --git a/sysdeps/x86_64/memchr.S b/sysdeps/x86_64/memchr.S +index feef5d4f..cb320257 100644 +--- a/sysdeps/x86_64/memchr.S ++++ b/sysdeps/x86_64/memchr.S +@@ -34,12 +34,16 @@ ENTRY(MEMCHR) + mov %edi, %ecx + + #ifdef USE_AS_WMEMCHR +- test %rdx, %rdx ++ test %RDX_LP, %RDX_LP + jz L(return_null) +- shl $2, %rdx ++ shl $2, %RDX_LP + #else ++# ifdef __ILP32__ ++ /* Clear the upper 32 bits. */ ++ movl %edx, %edx ++# endif + punpcklbw %xmm1, %xmm1 +- test %rdx, %rdx ++ test %RDX_LP, %RDX_LP + jz L(return_null) + punpcklbw %xmm1, %xmm1 + #endif +diff --git a/sysdeps/x86_64/multiarch/memchr-avx2.S b/sysdeps/x86_64/multiarch/memchr-avx2.S +index 5f5e7725..c81da19b 100644 +--- a/sysdeps/x86_64/multiarch/memchr-avx2.S ++++ b/sysdeps/x86_64/multiarch/memchr-avx2.S +@@ -40,16 +40,20 @@ + ENTRY (MEMCHR) + # ifndef USE_AS_RAWMEMCHR + /* Check for zero length. */ +- testq %rdx, %rdx ++ test %RDX_LP, %RDX_LP + jz L(null) + # endif + movl %edi, %ecx + /* Broadcast CHAR to YMM0. */ + vmovd %esi, %xmm0 + # ifdef USE_AS_WMEMCHR +- shl $2, %rdx ++ shl $2, %RDX_LP + vpbroadcastd %xmm0, %ymm0 + # else ++# ifdef __ILP32__ ++ /* Clear the upper 32 bits. */ ++ movl %edx, %edx ++# endif + vpbroadcastb %xmm0, %ymm0 + # endif + /* Check if we may cross page boundary with one vector load. */ +diff --git a/sysdeps/x86_64/x32/Makefile b/sysdeps/x86_64/x32/Makefile +index f2ebc24f..7d528889 100644 +--- a/sysdeps/x86_64/x32/Makefile ++++ b/sysdeps/x86_64/x32/Makefile +@@ -4,3 +4,11 @@ ifeq ($(subdir),math) + # 64-bit llround. Add -fno-builtin-lround to silence the compiler. + CFLAGS-s_llround.c += -fno-builtin-lround + endif ++ ++ifeq ($(subdir),string) ++tests += tst-size_t-memchr ++endif ++ ++ifeq ($(subdir),wcsmbs) ++tests += tst-size_t-wmemchr ++endif +diff --git a/sysdeps/x86_64/x32/test-size_t.h b/sysdeps/x86_64/x32/test-size_t.h +new file mode 100644 +index 00000000..78a94086 +--- /dev/null ++++ b/sysdeps/x86_64/x32/test-size_t.h +@@ -0,0 +1,35 @@ ++/* Test string/memory functions with size_t in the lower 32 bits of ++ 64-bit register. ++ 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, see ++ . */ ++ ++#define TEST_MAIN ++#include ++ ++/* On x32, parameter_t may be passed in a 64-bit register with the LEN ++ field in the lower 32 bits. When the LEN field of 64-bit register ++ is passed to string/memory function as the size_t parameter, only ++ the lower 32 bits can be used. */ ++typedef struct ++{ ++ union ++ { ++ size_t len; ++ void (*fn) (void); ++ }; ++ void *p; ++} parameter_t; +diff --git a/sysdeps/x86_64/x32/tst-size_t-memchr.c b/sysdeps/x86_64/x32/tst-size_t-memchr.c +new file mode 100644 +index 00000000..29a3daf1 +--- /dev/null ++++ b/sysdeps/x86_64/x32/tst-size_t-memchr.c +@@ -0,0 +1,72 @@ ++/* Test memchr with size_t in the lower 32 bits of 64-bit register. ++ 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, see ++ . */ ++ ++#ifndef WIDE ++# define TEST_NAME "memchr" ++#else ++# define TEST_NAME "wmemchr" ++#endif /* WIDE */ ++#include "test-size_t.h" ++ ++#ifndef WIDE ++# define MEMCHR memchr ++# define CHAR char ++# define UCHAR unsigned char ++#else ++# include ++# define MEMCHR wmemchr ++# define CHAR wchar_t ++# define UCHAR wchar_t ++#endif /* WIDE */ ++ ++IMPL (MEMCHR, 1) ++ ++typedef CHAR * (*proto_t) (const CHAR*, int, size_t); ++ ++static CHAR * ++__attribute__ ((noinline, noclone)) ++do_memchr (parameter_t a, parameter_t b) ++{ ++ return CALL (&b, a.p, (uintptr_t) b.p, a.len); ++} ++ ++static int ++test_main (void) ++{ ++ test_init (); ++ ++ parameter_t src = { { page_size / sizeof (CHAR) }, buf2 }; ++ parameter_t c = { { 0 }, (void *) (uintptr_t) 0x12 }; ++ ++ int ret = 0; ++ FOR_EACH_IMPL (impl, 0) ++ { ++ c.fn = impl->fn; ++ CHAR *res = do_memchr (src, c); ++ if (res) ++ { ++ error (0, 0, "Wrong result in function %s: %p != NULL", ++ impl->name, res); ++ ret = 1; ++ } ++ } ++ ++ return ret ? EXIT_FAILURE : EXIT_SUCCESS; ++} ++ ++#include +diff --git a/sysdeps/x86_64/x32/tst-size_t-wmemchr.c b/sysdeps/x86_64/x32/tst-size_t-wmemchr.c +new file mode 100644 +index 00000000..877801d6 +--- /dev/null ++++ b/sysdeps/x86_64/x32/tst-size_t-wmemchr.c +@@ -0,0 +1,20 @@ ++/* Test wmemchr with size_t in the lower 32 bits of 64-bit register. ++ 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, see ++ . */ ++ ++#define WIDE 1 ++#include "tst-size_t-memchr.c" +-- +GitLab + diff --git a/SOURCES/glibc-RHEL-15696-10.patch b/SOURCES/glibc-RHEL-15696-10.patch new file mode 100644 index 0000000..10bd49d --- /dev/null +++ b/SOURCES/glibc-RHEL-15696-10.patch @@ -0,0 +1,41 @@ +From ddf0992cf57a93200e0c782e2a94d0733a5a0b87 Mon Sep 17 00:00:00 2001 +From: Noah Goldstein +Date: Sun, 9 Jan 2022 16:02:21 -0600 +Subject: [PATCH] x86: Fix __wcsncmp_avx2 in strcmp-avx2.S [BZ# 28755] +Content-type: text/plain; charset=UTF-8 + +Fixes [BZ# 28755] for wcsncmp by redirecting length >= 2^56 to +__wcscmp_avx2. For x86_64 this covers the entire address range so any +length larger could not possibly be used to bound `s1` or `s2`. + +test-strcmp, test-strncmp, test-wcscmp, and test-wcsncmp all pass. + +Signed-off-by: Noah Goldstein +--- + sysdeps/x86_64/multiarch/strcmp-avx2.S | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +diff --git a/sysdeps/x86_64/multiarch/strcmp-avx2.S b/sysdeps/x86_64/multiarch/strcmp-avx2.S +index 156c1949..8fb8eedc 100644 +--- a/sysdeps/x86_64/multiarch/strcmp-avx2.S ++++ b/sysdeps/x86_64/multiarch/strcmp-avx2.S +@@ -83,6 +83,16 @@ ENTRY (STRCMP) + je L(char0) + jb L(zero) + # ifdef USE_AS_WCSCMP ++# ifndef __ILP32__ ++ movq %rdx, %rcx ++ /* Check if length could overflow when multiplied by ++ sizeof(wchar_t). Checking top 8 bits will cover all potential ++ overflow cases as well as redirect cases where its impossible to ++ length to bound a valid memory region. In these cases just use ++ 'wcscmp'. */ ++ shrq $56, %rcx ++ jnz __wcscmp_avx2 ++# endif + /* Convert units: from wide to byte char. */ + shl $2, %RDX_LP + # endif +-- +GitLab + diff --git a/SOURCES/glibc-RHEL-15696-100.patch b/SOURCES/glibc-RHEL-15696-100.patch new file mode 100644 index 0000000..0e779e4 --- /dev/null +++ b/SOURCES/glibc-RHEL-15696-100.patch @@ -0,0 +1,257 @@ +From 244b415d386487521882debb845a040a4758cb18 Mon Sep 17 00:00:00 2001 +From: Noah Goldstein +Date: Fri, 25 Mar 2022 17:13:33 -0500 +Subject: [PATCH] x86: Small improvements for wcslen +Content-type: text/plain; charset=UTF-8 + +Just a few QOL changes. + 1. Prefer `add` > `lea` as it has high execution units it can run + on. + 2. Don't break macro-fusion between `test` and `jcc` + 3. Reduce code size by removing gratuitous padding bytes (-90 + bytes). + +geometric_mean(N=20) of all benchmarks New / Original: 0.959 + +All string/memory tests pass. +Reviewed-by: H.J. Lu +--- + sysdeps/x86_64/wcslen.S | 86 ++++++++++++++++++++--------------------- + 1 file changed, 41 insertions(+), 45 deletions(-) + +diff --git a/sysdeps/x86_64/wcslen.S b/sysdeps/x86_64/wcslen.S +index 9f5f7232..254bb030 100644 +--- a/sysdeps/x86_64/wcslen.S ++++ b/sysdeps/x86_64/wcslen.S +@@ -41,82 +41,82 @@ ENTRY (__wcslen) + pxor %xmm0, %xmm0 + + lea 32(%rdi), %rax +- lea 16(%rdi), %rcx ++ addq $16, %rdi + and $-16, %rax + + pcmpeqd (%rax), %xmm0 + pmovmskb %xmm0, %edx + pxor %xmm1, %xmm1 ++ addq $16, %rax + test %edx, %edx +- lea 16(%rax), %rax + jnz L(exit) + + pcmpeqd (%rax), %xmm1 + pmovmskb %xmm1, %edx + pxor %xmm2, %xmm2 ++ addq $16, %rax + test %edx, %edx +- lea 16(%rax), %rax + jnz L(exit) + + pcmpeqd (%rax), %xmm2 + pmovmskb %xmm2, %edx + pxor %xmm3, %xmm3 ++ addq $16, %rax + test %edx, %edx +- lea 16(%rax), %rax + jnz L(exit) + + pcmpeqd (%rax), %xmm3 + pmovmskb %xmm3, %edx ++ addq $16, %rax + test %edx, %edx +- lea 16(%rax), %rax + jnz L(exit) + + pcmpeqd (%rax), %xmm0 + pmovmskb %xmm0, %edx ++ addq $16, %rax + test %edx, %edx +- lea 16(%rax), %rax + jnz L(exit) + + pcmpeqd (%rax), %xmm1 + pmovmskb %xmm1, %edx ++ addq $16, %rax + test %edx, %edx +- lea 16(%rax), %rax + jnz L(exit) + + pcmpeqd (%rax), %xmm2 + pmovmskb %xmm2, %edx ++ addq $16, %rax + test %edx, %edx +- lea 16(%rax), %rax + jnz L(exit) + + pcmpeqd (%rax), %xmm3 + pmovmskb %xmm3, %edx ++ addq $16, %rax + test %edx, %edx +- lea 16(%rax), %rax + jnz L(exit) + + pcmpeqd (%rax), %xmm0 + pmovmskb %xmm0, %edx ++ addq $16, %rax + test %edx, %edx +- lea 16(%rax), %rax + jnz L(exit) + + pcmpeqd (%rax), %xmm1 + pmovmskb %xmm1, %edx ++ addq $16, %rax + test %edx, %edx +- lea 16(%rax), %rax + jnz L(exit) + + pcmpeqd (%rax), %xmm2 + pmovmskb %xmm2, %edx ++ addq $16, %rax + test %edx, %edx +- lea 16(%rax), %rax + jnz L(exit) + + pcmpeqd (%rax), %xmm3 + pmovmskb %xmm3, %edx ++ addq $16, %rax + test %edx, %edx +- lea 16(%rax), %rax + jnz L(exit) + + and $-0x40, %rax +@@ -133,104 +133,100 @@ L(aligned_64_loop): + pminub %xmm0, %xmm2 + pcmpeqd %xmm3, %xmm2 + pmovmskb %xmm2, %edx ++ addq $64, %rax + test %edx, %edx +- lea 64(%rax), %rax + jz L(aligned_64_loop) + + pcmpeqd -64(%rax), %xmm3 + pmovmskb %xmm3, %edx ++ addq $48, %rdi + test %edx, %edx +- lea 48(%rcx), %rcx + jnz L(exit) + + pcmpeqd %xmm1, %xmm3 + pmovmskb %xmm3, %edx ++ addq $-16, %rdi + test %edx, %edx +- lea -16(%rcx), %rcx + jnz L(exit) + + pcmpeqd -32(%rax), %xmm3 + pmovmskb %xmm3, %edx ++ addq $-16, %rdi + test %edx, %edx +- lea -16(%rcx), %rcx + jnz L(exit) + + pcmpeqd %xmm6, %xmm3 + pmovmskb %xmm3, %edx ++ addq $-16, %rdi + test %edx, %edx +- lea -16(%rcx), %rcx +- jnz L(exit) +- +- jmp L(aligned_64_loop) ++ jz L(aligned_64_loop) + + .p2align 4 + L(exit): +- sub %rcx, %rax ++ sub %rdi, %rax + shr $2, %rax + test %dl, %dl + jz L(exit_high) + +- mov %dl, %cl +- and $15, %cl ++ andl $15, %edx + jz L(exit_1) + ret + +- .p2align 4 ++ /* No align here. Naturally aligned % 16 == 1. */ + L(exit_high): +- mov %dh, %ch +- and $15, %ch ++ andl $(15 << 8), %edx + jz L(exit_3) + add $2, %rax + ret + +- .p2align 4 ++ .p2align 3 + L(exit_1): + add $1, %rax + ret + +- .p2align 4 ++ .p2align 3 + L(exit_3): + add $3, %rax + ret + +- .p2align 4 ++ .p2align 3 + L(exit_tail0): +- xor %rax, %rax ++ xorl %eax, %eax + ret + +- .p2align 4 ++ .p2align 3 + L(exit_tail1): +- mov $1, %rax ++ movl $1, %eax + ret + +- .p2align 4 ++ .p2align 3 + L(exit_tail2): +- mov $2, %rax ++ movl $2, %eax + ret + +- .p2align 4 ++ .p2align 3 + L(exit_tail3): +- mov $3, %rax ++ movl $3, %eax + ret + +- .p2align 4 ++ .p2align 3 + L(exit_tail4): +- mov $4, %rax ++ movl $4, %eax + ret + +- .p2align 4 ++ .p2align 3 + L(exit_tail5): +- mov $5, %rax ++ movl $5, %eax + ret + +- .p2align 4 ++ .p2align 3 + L(exit_tail6): +- mov $6, %rax ++ movl $6, %eax + ret + +- .p2align 4 ++ .p2align 3 + L(exit_tail7): +- mov $7, %rax ++ movl $7, %eax + ret + + END (__wcslen) +-- +GitLab + diff --git a/SOURCES/glibc-RHEL-15696-101.patch b/SOURCES/glibc-RHEL-15696-101.patch new file mode 100644 index 0000000..131ea5b --- /dev/null +++ b/SOURCES/glibc-RHEL-15696-101.patch @@ -0,0 +1,964 @@ +From 7cbc03d03091d5664060924789afe46d30a5477e Mon Sep 17 00:00:00 2001 +From: Noah Goldstein +Date: Fri, 15 Apr 2022 12:28:00 -0500 +Subject: [PATCH] x86: Remove memcmp-sse4.S +Content-type: text/plain; charset=UTF-8 + +Code didn't actually use any sse4 instructions since `ptest` was +removed in: + +commit 2f9062d7171850451e6044ef78d91ff8c017b9c0 +Author: Noah Goldstein +Date: Wed Nov 10 16:18:56 2021 -0600 + + x86: Shrink memcmp-sse4.S code size + +The new memcmp-sse2 implementation is also faster. + +geometric_mean(N=20) of page cross cases SSE2 / SSE4: 0.905 + +Note there are two regressions preferring SSE2 for Size = 1 and Size = +65. + +Size = 1: +size, align0, align1, ret, New Time/Old Time + 1, 1, 1, 0, 1.2 + 1, 1, 1, 1, 1.197 + 1, 1, 1, -1, 1.2 + +This is intentional. Size == 1 is significantly less hot based on +profiles of GCC11 and Python3 than sizes [4, 8] (which is made +hotter). + +Python3 Size = 1 -> 13.64% +Python3 Size = [4, 8] -> 60.92% + +GCC11 Size = 1 -> 1.29% +GCC11 Size = [4, 8] -> 33.86% + +size, align0, align1, ret, New Time/Old Time + 4, 4, 4, 0, 0.622 + 4, 4, 4, 1, 0.797 + 4, 4, 4, -1, 0.805 + 5, 5, 5, 0, 0.623 + 5, 5, 5, 1, 0.777 + 5, 5, 5, -1, 0.802 + 6, 6, 6, 0, 0.625 + 6, 6, 6, 1, 0.813 + 6, 6, 6, -1, 0.788 + 7, 7, 7, 0, 0.625 + 7, 7, 7, 1, 0.799 + 7, 7, 7, -1, 0.795 + 8, 8, 8, 0, 0.625 + 8, 8, 8, 1, 0.848 + 8, 8, 8, -1, 0.914 + 9, 9, 9, 0, 0.625 + +Size = 65: +size, align0, align1, ret, New Time/Old Time + 65, 0, 0, 0, 1.103 + 65, 0, 0, 1, 1.216 + 65, 0, 0, -1, 1.227 + 65, 65, 0, 0, 1.091 + 65, 0, 65, 1, 1.19 + 65, 65, 65, -1, 1.215 + +This is because A) the checks in range [65, 96] are now unrolled 2x +and B) because smaller values <= 16 are now given a hotter path. By +contrast the SSE4 version has a branch for Size = 80. The unrolled +version has get better performance for returns which need both +comparisons. + +size, align0, align1, ret, New Time/Old Time + 128, 4, 8, 0, 0.858 + 128, 4, 8, 1, 0.879 + 128, 4, 8, -1, 0.888 + +As well, out of microbenchmark environments that are not full +predictable the branch will have a real-cost. +Reviewed-by: H.J. Lu +--- + sysdeps/x86_64/multiarch/Makefile | 2 - + sysdeps/x86_64/multiarch/ifunc-impl-list.c | 4 - + sysdeps/x86_64/multiarch/ifunc-memcmp.h | 4 - + sysdeps/x86_64/multiarch/memcmp-sse4.S | 804 --------------------- + 4 files changed, 814 deletions(-) + delete mode 100644 sysdeps/x86_64/multiarch/memcmp-sse4.S + +diff --git a/sysdeps/x86_64/multiarch/Makefile b/sysdeps/x86_64/multiarch/Makefile +index bca82e38..b503e4b8 100644 +--- a/sysdeps/x86_64/multiarch/Makefile ++++ b/sysdeps/x86_64/multiarch/Makefile +@@ -11,7 +11,6 @@ sysdep_routines += \ + memcmp-avx2-movbe-rtm \ + memcmp-evex-movbe \ + memcmp-sse2 \ +- memcmp-sse4 \ + memcmp-ssse3 \ + memcpy-ssse3 \ + memcpy-ssse3-back \ +@@ -174,7 +173,6 @@ sysdep_routines += \ + wmemcmp-avx2-movbe-rtm \ + wmemcmp-c \ + wmemcmp-evex-movbe \ +- wmemcmp-sse4 \ + wmemcmp-ssse3 \ + # sysdep_routines + endif +diff --git a/sysdeps/x86_64/multiarch/ifunc-impl-list.c b/sysdeps/x86_64/multiarch/ifunc-impl-list.c +index 14314367..450a2917 100644 +--- a/sysdeps/x86_64/multiarch/ifunc-impl-list.c ++++ b/sysdeps/x86_64/multiarch/ifunc-impl-list.c +@@ -78,8 +78,6 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + && CPU_FEATURE_USABLE (BMI2) + && CPU_FEATURE_USABLE (MOVBE)), + __memcmp_evex_movbe) +- IFUNC_IMPL_ADD (array, i, memcmp, CPU_FEATURE_USABLE (SSE4_1), +- __memcmp_sse4_1) + IFUNC_IMPL_ADD (array, i, memcmp, CPU_FEATURE_USABLE (SSSE3), + __memcmp_ssse3) + IFUNC_IMPL_ADD (array, i, memcmp, 1, __memcmp_sse2)) +@@ -824,8 +822,6 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + && CPU_FEATURE_USABLE (BMI2) + && CPU_FEATURE_USABLE (MOVBE)), + __wmemcmp_evex_movbe) +- IFUNC_IMPL_ADD (array, i, wmemcmp, CPU_FEATURE_USABLE (SSE4_1), +- __wmemcmp_sse4_1) + IFUNC_IMPL_ADD (array, i, wmemcmp, CPU_FEATURE_USABLE (SSSE3), + __wmemcmp_ssse3) + IFUNC_IMPL_ADD (array, i, wmemcmp, 1, __wmemcmp_sse2)) +diff --git a/sysdeps/x86_64/multiarch/ifunc-memcmp.h b/sysdeps/x86_64/multiarch/ifunc-memcmp.h +index 690dffe8..0bc47a7f 100644 +--- a/sysdeps/x86_64/multiarch/ifunc-memcmp.h ++++ b/sysdeps/x86_64/multiarch/ifunc-memcmp.h +@@ -21,7 +21,6 @@ + + extern __typeof (REDIRECT_NAME) OPTIMIZE (sse2) attribute_hidden; + extern __typeof (REDIRECT_NAME) OPTIMIZE (ssse3) attribute_hidden; +-extern __typeof (REDIRECT_NAME) OPTIMIZE (sse4_1) attribute_hidden; + extern __typeof (REDIRECT_NAME) OPTIMIZE (avx2_movbe) attribute_hidden; + extern __typeof (REDIRECT_NAME) OPTIMIZE (avx2_movbe_rtm) attribute_hidden; + extern __typeof (REDIRECT_NAME) OPTIMIZE (evex_movbe) attribute_hidden; +@@ -47,9 +46,6 @@ IFUNC_SELECTOR (void) + return OPTIMIZE (avx2_movbe); + } + +- if (CPU_FEATURE_USABLE_P (cpu_features, SSE4_1)) +- return OPTIMIZE (sse4_1); +- + if (CPU_FEATURE_USABLE_P (cpu_features, SSSE3)) + return OPTIMIZE (ssse3); + +diff --git a/sysdeps/x86_64/multiarch/memcmp-sse4.S b/sysdeps/x86_64/multiarch/memcmp-sse4.S +deleted file mode 100644 +index 50060006..00000000 +--- a/sysdeps/x86_64/multiarch/memcmp-sse4.S ++++ /dev/null +@@ -1,804 +0,0 @@ +-/* memcmp with SSE4.1, wmemcmp with SSE4.1 +- Copyright (C) 2010-2018 Free Software Foundation, Inc. +- Contributed by Intel Corporation. +- This file is part of the GNU C Library. +- +- The GNU C Library is free software; you can redistribute it and/or +- modify it under the terms of the GNU Lesser General Public +- License as published by the Free Software Foundation; either +- version 2.1 of the License, or (at your option) any later version. +- +- The GNU C Library is distributed in the hope that it will be useful, +- but WITHOUT ANY WARRANTY; without even the implied warranty of +- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +- Lesser General Public License for more details. +- +- You should have received a copy of the GNU Lesser General Public +- License along with the GNU C Library; if not, see +- . */ +- +-#if IS_IN (libc) +- +-# include +- +-# ifndef MEMCMP +-# define MEMCMP __memcmp_sse4_1 +-# endif +- +-#ifdef USE_AS_WMEMCMP +-# define CMPEQ pcmpeqd +-# define CHAR_SIZE 4 +-#else +-# define CMPEQ pcmpeqb +-# define CHAR_SIZE 1 +-#endif +- +- +-/* Warning! +- wmemcmp has to use SIGNED comparison for elements. +- memcmp has to use UNSIGNED comparison for elemnts. +-*/ +- +- .section .text.sse4.1,"ax",@progbits +-ENTRY (MEMCMP) +-# ifdef USE_AS_WMEMCMP +- shl $2, %RDX_LP +-# elif defined __ILP32__ +- /* Clear the upper 32 bits. */ +- mov %edx, %edx +-# endif +- cmp $79, %RDX_LP +- ja L(79bytesormore) +- +- cmp $CHAR_SIZE, %RDX_LP +- jbe L(firstbyte) +- +- /* N in (CHAR_SIZE, 79) bytes. */ +- cmpl $32, %edx +- ja L(more_32_bytes) +- +- cmpl $16, %edx +- jae L(16_to_32_bytes) +- +-# ifndef USE_AS_WMEMCMP +- cmpl $8, %edx +- jae L(8_to_16_bytes) +- +- cmpl $4, %edx +- jb L(2_to_3_bytes) +- +- movl (%rdi), %eax +- movl (%rsi), %ecx +- +- bswap %eax +- bswap %ecx +- +- shlq $32, %rax +- shlq $32, %rcx +- +- movl -4(%rdi, %rdx), %edi +- movl -4(%rsi, %rdx), %esi +- +- bswap %edi +- bswap %esi +- +- orq %rdi, %rax +- orq %rsi, %rcx +- subq %rcx, %rax +- cmovne %edx, %eax +- sbbl %ecx, %ecx +- orl %ecx, %eax +- ret +- +- .p2align 4,, 8 +-L(2_to_3_bytes): +- movzwl (%rdi), %eax +- movzwl (%rsi), %ecx +- shll $8, %eax +- shll $8, %ecx +- bswap %eax +- bswap %ecx +- movzbl -1(%rdi, %rdx), %edi +- movzbl -1(%rsi, %rdx), %esi +- orl %edi, %eax +- orl %esi, %ecx +- subl %ecx, %eax +- ret +- +- .p2align 4,, 8 +-L(8_to_16_bytes): +- movq (%rdi), %rax +- movq (%rsi), %rcx +- +- bswap %rax +- bswap %rcx +- +- subq %rcx, %rax +- jne L(8_to_16_bytes_done) +- +- movq -8(%rdi, %rdx), %rax +- movq -8(%rsi, %rdx), %rcx +- +- bswap %rax +- bswap %rcx +- +- subq %rcx, %rax +- +-L(8_to_16_bytes_done): +- cmovne %edx, %eax +- sbbl %ecx, %ecx +- orl %ecx, %eax +- ret +-# else +- xorl %eax, %eax +- movl (%rdi), %ecx +- cmpl (%rsi), %ecx +- jne L(8_to_16_bytes_done) +- movl 4(%rdi), %ecx +- cmpl 4(%rsi), %ecx +- jne L(8_to_16_bytes_done) +- movl -4(%rdi, %rdx), %ecx +- cmpl -4(%rsi, %rdx), %ecx +- jne L(8_to_16_bytes_done) +- ret +-# endif +- +- .p2align 4,, 3 +-L(ret_zero): +- xorl %eax, %eax +-L(zero): +- ret +- +- .p2align 4,, 8 +-L(firstbyte): +- jb L(ret_zero) +-# ifdef USE_AS_WMEMCMP +- xorl %eax, %eax +- movl (%rdi), %ecx +- cmpl (%rsi), %ecx +- je L(zero) +-L(8_to_16_bytes_done): +- setg %al +- leal -1(%rax, %rax), %eax +-# else +- movzbl (%rdi), %eax +- movzbl (%rsi), %ecx +- sub %ecx, %eax +-# endif +- ret +- +- .p2align 4 +-L(vec_return_begin_48): +- addq $16, %rdi +- addq $16, %rsi +-L(vec_return_begin_32): +- bsfl %eax, %eax +-# ifdef USE_AS_WMEMCMP +- movl 32(%rdi, %rax), %ecx +- xorl %edx, %edx +- cmpl 32(%rsi, %rax), %ecx +- setg %dl +- leal -1(%rdx, %rdx), %eax +-# else +- movzbl 32(%rsi, %rax), %ecx +- movzbl 32(%rdi, %rax), %eax +- subl %ecx, %eax +-# endif +- ret +- +- .p2align 4 +-L(vec_return_begin_16): +- addq $16, %rdi +- addq $16, %rsi +-L(vec_return_begin): +- bsfl %eax, %eax +-# ifdef USE_AS_WMEMCMP +- movl (%rdi, %rax), %ecx +- xorl %edx, %edx +- cmpl (%rsi, %rax), %ecx +- setg %dl +- leal -1(%rdx, %rdx), %eax +-# else +- movzbl (%rsi, %rax), %ecx +- movzbl (%rdi, %rax), %eax +- subl %ecx, %eax +-# endif +- ret +- +- .p2align 4 +-L(vec_return_end_16): +- subl $16, %edx +-L(vec_return_end): +- bsfl %eax, %eax +- addl %edx, %eax +-# ifdef USE_AS_WMEMCMP +- movl -16(%rdi, %rax), %ecx +- xorl %edx, %edx +- cmpl -16(%rsi, %rax), %ecx +- setg %dl +- leal -1(%rdx, %rdx), %eax +-# else +- movzbl -16(%rsi, %rax), %ecx +- movzbl -16(%rdi, %rax), %eax +- subl %ecx, %eax +-# endif +- ret +- +- .p2align 4,, 8 +-L(more_32_bytes): +- movdqu (%rdi), %xmm0 +- movdqu (%rsi), %xmm1 +- CMPEQ %xmm0, %xmm1 +- pmovmskb %xmm1, %eax +- incw %ax +- jnz L(vec_return_begin) +- +- movdqu 16(%rdi), %xmm0 +- movdqu 16(%rsi), %xmm1 +- CMPEQ %xmm0, %xmm1 +- pmovmskb %xmm1, %eax +- incw %ax +- jnz L(vec_return_begin_16) +- +- cmpl $64, %edx +- jbe L(32_to_64_bytes) +- movdqu 32(%rdi), %xmm0 +- movdqu 32(%rsi), %xmm1 +- CMPEQ %xmm0, %xmm1 +- pmovmskb %xmm1, %eax +- incw %ax +- jnz L(vec_return_begin_32) +- +- .p2align 4,, 6 +-L(32_to_64_bytes): +- movdqu -32(%rdi, %rdx), %xmm0 +- movdqu -32(%rsi, %rdx), %xmm1 +- CMPEQ %xmm0, %xmm1 +- pmovmskb %xmm1, %eax +- incw %ax +- jnz L(vec_return_end_16) +- +- movdqu -16(%rdi, %rdx), %xmm0 +- movdqu -16(%rsi, %rdx), %xmm1 +- CMPEQ %xmm0, %xmm1 +- pmovmskb %xmm1, %eax +- incw %ax +- jnz L(vec_return_end) +- ret +- +- .p2align 4 +-L(16_to_32_bytes): +- movdqu (%rdi), %xmm0 +- movdqu (%rsi), %xmm1 +- CMPEQ %xmm0, %xmm1 +- pmovmskb %xmm1, %eax +- incw %ax +- jnz L(vec_return_begin) +- +- movdqu -16(%rdi, %rdx), %xmm0 +- movdqu -16(%rsi, %rdx), %xmm1 +- CMPEQ %xmm0, %xmm1 +- pmovmskb %xmm1, %eax +- incw %ax +- jnz L(vec_return_end) +- ret +- +- +- .p2align 4 +-L(79bytesormore): +- movdqu (%rdi), %xmm0 +- movdqu (%rsi), %xmm1 +- CMPEQ %xmm0, %xmm1 +- pmovmskb %xmm1, %eax +- incw %ax +- jnz L(vec_return_begin) +- +- +- mov %rsi, %rcx +- and $-16, %rsi +- add $16, %rsi +- sub %rsi, %rcx +- +- sub %rcx, %rdi +- add %rcx, %rdx +- test $0xf, %rdi +- jz L(2aligned) +- +- cmp $128, %rdx +- ja L(128bytesormore) +- +- .p2align 4,, 6 +-L(less128bytes): +- movdqu (%rdi), %xmm1 +- CMPEQ (%rsi), %xmm1 +- pmovmskb %xmm1, %eax +- incw %ax +- jnz L(vec_return_begin) +- +- movdqu 16(%rdi), %xmm1 +- CMPEQ 16(%rsi), %xmm1 +- pmovmskb %xmm1, %eax +- incw %ax +- jnz L(vec_return_begin_16) +- +- movdqu 32(%rdi), %xmm1 +- CMPEQ 32(%rsi), %xmm1 +- pmovmskb %xmm1, %eax +- incw %ax +- jnz L(vec_return_begin_32) +- +- movdqu 48(%rdi), %xmm1 +- CMPEQ 48(%rsi), %xmm1 +- pmovmskb %xmm1, %eax +- incw %ax +- jnz L(vec_return_begin_48) +- +- cmp $96, %rdx +- jb L(32_to_64_bytes) +- +- addq $64, %rdi +- addq $64, %rsi +- subq $64, %rdx +- +- .p2align 4,, 6 +-L(last_64_bytes): +- movdqu (%rdi), %xmm1 +- CMPEQ (%rsi), %xmm1 +- pmovmskb %xmm1, %eax +- incw %ax +- jnz L(vec_return_begin) +- +- movdqu 16(%rdi), %xmm1 +- CMPEQ 16(%rsi), %xmm1 +- pmovmskb %xmm1, %eax +- incw %ax +- jnz L(vec_return_begin_16) +- +- movdqu -32(%rdi, %rdx), %xmm0 +- movdqu -32(%rsi, %rdx), %xmm1 +- CMPEQ %xmm0, %xmm1 +- pmovmskb %xmm1, %eax +- incw %ax +- jnz L(vec_return_end_16) +- +- movdqu -16(%rdi, %rdx), %xmm0 +- movdqu -16(%rsi, %rdx), %xmm1 +- CMPEQ %xmm0, %xmm1 +- pmovmskb %xmm1, %eax +- incw %ax +- jnz L(vec_return_end) +- ret +- +- .p2align 4 +-L(128bytesormore): +- cmp $256, %rdx +- ja L(unaligned_loop) +-L(less256bytes): +- movdqu (%rdi), %xmm1 +- CMPEQ (%rsi), %xmm1 +- pmovmskb %xmm1, %eax +- incw %ax +- jnz L(vec_return_begin) +- +- movdqu 16(%rdi), %xmm1 +- CMPEQ 16(%rsi), %xmm1 +- pmovmskb %xmm1, %eax +- incw %ax +- jnz L(vec_return_begin_16) +- +- movdqu 32(%rdi), %xmm1 +- CMPEQ 32(%rsi), %xmm1 +- pmovmskb %xmm1, %eax +- incw %ax +- jnz L(vec_return_begin_32) +- +- movdqu 48(%rdi), %xmm1 +- CMPEQ 48(%rsi), %xmm1 +- pmovmskb %xmm1, %eax +- incw %ax +- jnz L(vec_return_begin_48) +- +- addq $64, %rdi +- addq $64, %rsi +- +- movdqu (%rdi), %xmm1 +- CMPEQ (%rsi), %xmm1 +- pmovmskb %xmm1, %eax +- incw %ax +- jnz L(vec_return_begin) +- +- movdqu 16(%rdi), %xmm1 +- CMPEQ 16(%rsi), %xmm1 +- pmovmskb %xmm1, %eax +- incw %ax +- jnz L(vec_return_begin_16) +- +- movdqu 32(%rdi), %xmm1 +- CMPEQ 32(%rsi), %xmm1 +- pmovmskb %xmm1, %eax +- incw %ax +- jnz L(vec_return_begin_32) +- +- movdqu 48(%rdi), %xmm1 +- CMPEQ 48(%rsi), %xmm1 +- pmovmskb %xmm1, %eax +- incw %ax +- jnz L(vec_return_begin_48) +- +- addq $-128, %rdx +- subq $-64, %rsi +- subq $-64, %rdi +- +- cmp $64, %rdx +- ja L(less128bytes) +- +- cmp $32, %rdx +- ja L(last_64_bytes) +- +- movdqu -32(%rdi, %rdx), %xmm0 +- movdqu -32(%rsi, %rdx), %xmm1 +- CMPEQ %xmm0, %xmm1 +- pmovmskb %xmm1, %eax +- incw %ax +- jnz L(vec_return_end_16) +- +- movdqu -16(%rdi, %rdx), %xmm0 +- movdqu -16(%rsi, %rdx), %xmm1 +- CMPEQ %xmm0, %xmm1 +- pmovmskb %xmm1, %eax +- incw %ax +- jnz L(vec_return_end) +- ret +- +- .p2align 4 +-L(unaligned_loop): +-# ifdef DATA_CACHE_SIZE_HALF +- mov $DATA_CACHE_SIZE_HALF, %R8_LP +-# else +- mov __x86_data_cache_size_half(%rip), %R8_LP +-# endif +- movq %r8, %r9 +- addq %r8, %r8 +- addq %r9, %r8 +- cmpq %r8, %rdx +- ja L(L2_L3_cache_unaligned) +- sub $64, %rdx +- .p2align 4 +-L(64bytesormore_loop): +- movdqu (%rdi), %xmm0 +- movdqu 16(%rdi), %xmm1 +- movdqu 32(%rdi), %xmm2 +- movdqu 48(%rdi), %xmm3 +- +- CMPEQ (%rsi), %xmm0 +- CMPEQ 16(%rsi), %xmm1 +- CMPEQ 32(%rsi), %xmm2 +- CMPEQ 48(%rsi), %xmm3 +- +- pand %xmm0, %xmm1 +- pand %xmm2, %xmm3 +- pand %xmm1, %xmm3 +- +- pmovmskb %xmm3, %eax +- incw %ax +- jnz L(64bytesormore_loop_end) +- +- add $64, %rsi +- add $64, %rdi +- sub $64, %rdx +- ja L(64bytesormore_loop) +- +- .p2align 4,, 6 +-L(loop_tail): +- addq %rdx, %rdi +- movdqu (%rdi), %xmm0 +- movdqu 16(%rdi), %xmm1 +- movdqu 32(%rdi), %xmm2 +- movdqu 48(%rdi), %xmm3 +- +- addq %rdx, %rsi +- movdqu (%rsi), %xmm4 +- movdqu 16(%rsi), %xmm5 +- movdqu 32(%rsi), %xmm6 +- movdqu 48(%rsi), %xmm7 +- +- CMPEQ %xmm4, %xmm0 +- CMPEQ %xmm5, %xmm1 +- CMPEQ %xmm6, %xmm2 +- CMPEQ %xmm7, %xmm3 +- +- pand %xmm0, %xmm1 +- pand %xmm2, %xmm3 +- pand %xmm1, %xmm3 +- +- pmovmskb %xmm3, %eax +- incw %ax +- jnz L(64bytesormore_loop_end) +- ret +- +-L(L2_L3_cache_unaligned): +- subq $64, %rdx +- .p2align 4 +-L(L2_L3_unaligned_128bytes_loop): +- prefetchnta 0x1c0(%rdi) +- prefetchnta 0x1c0(%rsi) +- +- movdqu (%rdi), %xmm0 +- movdqu 16(%rdi), %xmm1 +- movdqu 32(%rdi), %xmm2 +- movdqu 48(%rdi), %xmm3 +- +- CMPEQ (%rsi), %xmm0 +- CMPEQ 16(%rsi), %xmm1 +- CMPEQ 32(%rsi), %xmm2 +- CMPEQ 48(%rsi), %xmm3 +- +- pand %xmm0, %xmm1 +- pand %xmm2, %xmm3 +- pand %xmm1, %xmm3 +- +- pmovmskb %xmm3, %eax +- incw %ax +- jnz L(64bytesormore_loop_end) +- +- add $64, %rsi +- add $64, %rdi +- sub $64, %rdx +- ja L(L2_L3_unaligned_128bytes_loop) +- jmp L(loop_tail) +- +- +- /* This case is for machines which are sensitive for unaligned +- * instructions. */ +- .p2align 4 +-L(2aligned): +- cmp $128, %rdx +- ja L(128bytesormorein2aligned) +-L(less128bytesin2aligned): +- movdqa (%rdi), %xmm1 +- CMPEQ (%rsi), %xmm1 +- pmovmskb %xmm1, %eax +- incw %ax +- jnz L(vec_return_begin) +- +- movdqa 16(%rdi), %xmm1 +- CMPEQ 16(%rsi), %xmm1 +- pmovmskb %xmm1, %eax +- incw %ax +- jnz L(vec_return_begin_16) +- +- movdqa 32(%rdi), %xmm1 +- CMPEQ 32(%rsi), %xmm1 +- pmovmskb %xmm1, %eax +- incw %ax +- jnz L(vec_return_begin_32) +- +- movdqa 48(%rdi), %xmm1 +- CMPEQ 48(%rsi), %xmm1 +- pmovmskb %xmm1, %eax +- incw %ax +- jnz L(vec_return_begin_48) +- +- cmp $96, %rdx +- jb L(32_to_64_bytes) +- +- addq $64, %rdi +- addq $64, %rsi +- subq $64, %rdx +- +- .p2align 4,, 6 +-L(aligned_last_64_bytes): +- movdqa (%rdi), %xmm1 +- CMPEQ (%rsi), %xmm1 +- pmovmskb %xmm1, %eax +- incw %ax +- jnz L(vec_return_begin) +- +- movdqa 16(%rdi), %xmm1 +- CMPEQ 16(%rsi), %xmm1 +- pmovmskb %xmm1, %eax +- incw %ax +- jnz L(vec_return_begin_16) +- +- movdqu -32(%rdi, %rdx), %xmm0 +- movdqu -32(%rsi, %rdx), %xmm1 +- CMPEQ %xmm0, %xmm1 +- pmovmskb %xmm1, %eax +- incw %ax +- jnz L(vec_return_end_16) +- +- movdqu -16(%rdi, %rdx), %xmm0 +- movdqu -16(%rsi, %rdx), %xmm1 +- CMPEQ %xmm0, %xmm1 +- pmovmskb %xmm1, %eax +- incw %ax +- jnz L(vec_return_end) +- ret +- +- .p2align 4 +-L(128bytesormorein2aligned): +- cmp $256, %rdx +- ja L(aligned_loop) +-L(less256bytesin2alinged): +- movdqa (%rdi), %xmm1 +- CMPEQ (%rsi), %xmm1 +- pmovmskb %xmm1, %eax +- incw %ax +- jnz L(vec_return_begin) +- +- movdqa 16(%rdi), %xmm1 +- CMPEQ 16(%rsi), %xmm1 +- pmovmskb %xmm1, %eax +- incw %ax +- jnz L(vec_return_begin_16) +- +- movdqa 32(%rdi), %xmm1 +- CMPEQ 32(%rsi), %xmm1 +- pmovmskb %xmm1, %eax +- incw %ax +- jnz L(vec_return_begin_32) +- +- movdqa 48(%rdi), %xmm1 +- CMPEQ 48(%rsi), %xmm1 +- pmovmskb %xmm1, %eax +- incw %ax +- jnz L(vec_return_begin_48) +- +- addq $64, %rdi +- addq $64, %rsi +- +- movdqa (%rdi), %xmm1 +- CMPEQ (%rsi), %xmm1 +- pmovmskb %xmm1, %eax +- incw %ax +- jnz L(vec_return_begin) +- +- movdqa 16(%rdi), %xmm1 +- CMPEQ 16(%rsi), %xmm1 +- pmovmskb %xmm1, %eax +- incw %ax +- jnz L(vec_return_begin_16) +- +- movdqa 32(%rdi), %xmm1 +- CMPEQ 32(%rsi), %xmm1 +- pmovmskb %xmm1, %eax +- incw %ax +- jnz L(vec_return_begin_32) +- +- movdqa 48(%rdi), %xmm1 +- CMPEQ 48(%rsi), %xmm1 +- pmovmskb %xmm1, %eax +- incw %ax +- jnz L(vec_return_begin_48) +- +- addq $-128, %rdx +- subq $-64, %rsi +- subq $-64, %rdi +- +- cmp $64, %rdx +- ja L(less128bytesin2aligned) +- +- cmp $32, %rdx +- ja L(aligned_last_64_bytes) +- +- movdqu -32(%rdi, %rdx), %xmm0 +- movdqu -32(%rsi, %rdx), %xmm1 +- CMPEQ %xmm0, %xmm1 +- pmovmskb %xmm1, %eax +- incw %ax +- jnz L(vec_return_end_16) +- +- movdqu -16(%rdi, %rdx), %xmm0 +- movdqu -16(%rsi, %rdx), %xmm1 +- CMPEQ %xmm0, %xmm1 +- pmovmskb %xmm1, %eax +- incw %ax +- jnz L(vec_return_end) +- ret +- +- .p2align 4 +-L(aligned_loop): +-# ifdef DATA_CACHE_SIZE_HALF +- mov $DATA_CACHE_SIZE_HALF, %R8_LP +-# else +- mov __x86_data_cache_size_half(%rip), %R8_LP +-# endif +- movq %r8, %r9 +- addq %r8, %r8 +- addq %r9, %r8 +- cmpq %r8, %rdx +- ja L(L2_L3_cache_aligned) +- +- sub $64, %rdx +- .p2align 4 +-L(64bytesormore_loopin2aligned): +- movdqa (%rdi), %xmm0 +- movdqa 16(%rdi), %xmm1 +- movdqa 32(%rdi), %xmm2 +- movdqa 48(%rdi), %xmm3 +- +- CMPEQ (%rsi), %xmm0 +- CMPEQ 16(%rsi), %xmm1 +- CMPEQ 32(%rsi), %xmm2 +- CMPEQ 48(%rsi), %xmm3 +- +- pand %xmm0, %xmm1 +- pand %xmm2, %xmm3 +- pand %xmm1, %xmm3 +- +- pmovmskb %xmm3, %eax +- incw %ax +- jnz L(64bytesormore_loop_end) +- add $64, %rsi +- add $64, %rdi +- sub $64, %rdx +- ja L(64bytesormore_loopin2aligned) +- jmp L(loop_tail) +- +-L(L2_L3_cache_aligned): +- subq $64, %rdx +- .p2align 4 +-L(L2_L3_aligned_128bytes_loop): +- prefetchnta 0x1c0(%rdi) +- prefetchnta 0x1c0(%rsi) +- movdqa (%rdi), %xmm0 +- movdqa 16(%rdi), %xmm1 +- movdqa 32(%rdi), %xmm2 +- movdqa 48(%rdi), %xmm3 +- +- CMPEQ (%rsi), %xmm0 +- CMPEQ 16(%rsi), %xmm1 +- CMPEQ 32(%rsi), %xmm2 +- CMPEQ 48(%rsi), %xmm3 +- +- pand %xmm0, %xmm1 +- pand %xmm2, %xmm3 +- pand %xmm1, %xmm3 +- +- pmovmskb %xmm3, %eax +- incw %ax +- jnz L(64bytesormore_loop_end) +- +- addq $64, %rsi +- addq $64, %rdi +- subq $64, %rdx +- ja L(L2_L3_aligned_128bytes_loop) +- jmp L(loop_tail) +- +- .p2align 4 +-L(64bytesormore_loop_end): +- pmovmskb %xmm0, %ecx +- incw %cx +- jnz L(loop_end_ret) +- +- pmovmskb %xmm1, %ecx +- notw %cx +- sall $16, %ecx +- jnz L(loop_end_ret) +- +- pmovmskb %xmm2, %ecx +- notw %cx +- shlq $32, %rcx +- jnz L(loop_end_ret) +- +- addq $48, %rdi +- addq $48, %rsi +- movq %rax, %rcx +- +- .p2align 4,, 6 +-L(loop_end_ret): +- bsfq %rcx, %rcx +-# ifdef USE_AS_WMEMCMP +- movl (%rdi, %rcx), %eax +- xorl %edx, %edx +- cmpl (%rsi, %rcx), %eax +- setg %dl +- leal -1(%rdx, %rdx), %eax +-# else +- movzbl (%rdi, %rcx), %eax +- movzbl (%rsi, %rcx), %ecx +- subl %ecx, %eax +-# endif +- ret +-END (MEMCMP) +-#endif +-- +GitLab + diff --git a/SOURCES/glibc-RHEL-15696-102.patch b/SOURCES/glibc-RHEL-15696-102.patch new file mode 100644 index 0000000..8cb20ad --- /dev/null +++ b/SOURCES/glibc-RHEL-15696-102.patch @@ -0,0 +1,263 @@ +From 23102686ec67b856a2d4fd25ddaa1c0b8d175c4f Mon Sep 17 00:00:00 2001 +From: Noah Goldstein +Date: Fri, 15 Apr 2022 12:28:01 -0500 +Subject: [PATCH] x86: Cleanup page cross code in memcmp-avx2-movbe.S +Content-type: text/plain; charset=UTF-8 + +Old code was both inefficient and wasted code size. New code (-62 +bytes) and comparable or better performance in the page cross case. + +geometric_mean(N=20) of page cross cases New / Original: 0.960 + +size, align0, align1, ret, New Time/Old Time + 1, 4095, 0, 0, 1.001 + 1, 4095, 0, 1, 0.999 + 1, 4095, 0, -1, 1.0 + 2, 4094, 0, 0, 1.0 + 2, 4094, 0, 1, 1.0 + 2, 4094, 0, -1, 1.0 + 3, 4093, 0, 0, 1.0 + 3, 4093, 0, 1, 1.0 + 3, 4093, 0, -1, 1.0 + 4, 4092, 0, 0, 0.987 + 4, 4092, 0, 1, 1.0 + 4, 4092, 0, -1, 1.0 + 5, 4091, 0, 0, 0.984 + 5, 4091, 0, 1, 1.002 + 5, 4091, 0, -1, 1.005 + 6, 4090, 0, 0, 0.993 + 6, 4090, 0, 1, 1.001 + 6, 4090, 0, -1, 1.003 + 7, 4089, 0, 0, 0.991 + 7, 4089, 0, 1, 1.0 + 7, 4089, 0, -1, 1.001 + 8, 4088, 0, 0, 0.875 + 8, 4088, 0, 1, 0.881 + 8, 4088, 0, -1, 0.888 + 9, 4087, 0, 0, 0.872 + 9, 4087, 0, 1, 0.879 + 9, 4087, 0, -1, 0.883 + 10, 4086, 0, 0, 0.878 + 10, 4086, 0, 1, 0.886 + 10, 4086, 0, -1, 0.873 + 11, 4085, 0, 0, 0.878 + 11, 4085, 0, 1, 0.881 + 11, 4085, 0, -1, 0.879 + 12, 4084, 0, 0, 0.873 + 12, 4084, 0, 1, 0.889 + 12, 4084, 0, -1, 0.875 + 13, 4083, 0, 0, 0.873 + 13, 4083, 0, 1, 0.863 + 13, 4083, 0, -1, 0.863 + 14, 4082, 0, 0, 0.838 + 14, 4082, 0, 1, 0.869 + 14, 4082, 0, -1, 0.877 + 15, 4081, 0, 0, 0.841 + 15, 4081, 0, 1, 0.869 + 15, 4081, 0, -1, 0.876 + 16, 4080, 0, 0, 0.988 + 16, 4080, 0, 1, 0.99 + 16, 4080, 0, -1, 0.989 + 17, 4079, 0, 0, 0.978 + 17, 4079, 0, 1, 0.981 + 17, 4079, 0, -1, 0.98 + 18, 4078, 0, 0, 0.981 + 18, 4078, 0, 1, 0.98 + 18, 4078, 0, -1, 0.985 + 19, 4077, 0, 0, 0.977 + 19, 4077, 0, 1, 0.979 + 19, 4077, 0, -1, 0.986 + 20, 4076, 0, 0, 0.977 + 20, 4076, 0, 1, 0.986 + 20, 4076, 0, -1, 0.984 + 21, 4075, 0, 0, 0.977 + 21, 4075, 0, 1, 0.983 + 21, 4075, 0, -1, 0.988 + 22, 4074, 0, 0, 0.983 + 22, 4074, 0, 1, 0.994 + 22, 4074, 0, -1, 0.993 + 23, 4073, 0, 0, 0.98 + 23, 4073, 0, 1, 0.992 + 23, 4073, 0, -1, 0.995 + 24, 4072, 0, 0, 0.989 + 24, 4072, 0, 1, 0.989 + 24, 4072, 0, -1, 0.991 + 25, 4071, 0, 0, 0.99 + 25, 4071, 0, 1, 0.999 + 25, 4071, 0, -1, 0.996 + 26, 4070, 0, 0, 0.993 + 26, 4070, 0, 1, 0.995 + 26, 4070, 0, -1, 0.998 + 27, 4069, 0, 0, 0.993 + 27, 4069, 0, 1, 0.999 + 27, 4069, 0, -1, 1.0 + 28, 4068, 0, 0, 0.997 + 28, 4068, 0, 1, 1.0 + 28, 4068, 0, -1, 0.999 + 29, 4067, 0, 0, 0.996 + 29, 4067, 0, 1, 0.999 + 29, 4067, 0, -1, 0.999 + 30, 4066, 0, 0, 0.991 + 30, 4066, 0, 1, 1.001 + 30, 4066, 0, -1, 0.999 + 31, 4065, 0, 0, 0.988 + 31, 4065, 0, 1, 0.998 + 31, 4065, 0, -1, 0.998 +Reviewed-by: H.J. Lu +--- + sysdeps/x86_64/multiarch/memcmp-avx2-movbe.S | 98 ++++++++++++-------- + 1 file changed, 61 insertions(+), 37 deletions(-) + +diff --git a/sysdeps/x86_64/multiarch/memcmp-avx2-movbe.S b/sysdeps/x86_64/multiarch/memcmp-avx2-movbe.S +index 16fc673e..99258cf5 100644 +--- a/sysdeps/x86_64/multiarch/memcmp-avx2-movbe.S ++++ b/sysdeps/x86_64/multiarch/memcmp-avx2-movbe.S +@@ -429,22 +429,21 @@ L(page_cross_less_vec): + # ifndef USE_AS_WMEMCMP + cmpl $8, %edx + jae L(between_8_15) ++ /* Fall through for [4, 7]. */ + cmpl $4, %edx +- jae L(between_4_7) ++ jb L(between_2_3) + +- /* Load as big endian to avoid branches. */ +- movzwl (%rdi), %eax +- movzwl (%rsi), %ecx +- shll $8, %eax +- shll $8, %ecx +- bswap %eax +- bswap %ecx +- movzbl -1(%rdi, %rdx), %edi +- movzbl -1(%rsi, %rdx), %esi +- orl %edi, %eax +- orl %esi, %ecx +- /* Subtraction is okay because the upper 8 bits are zero. */ +- subl %ecx, %eax ++ movbe (%rdi), %eax ++ movbe (%rsi), %ecx ++ shlq $32, %rax ++ shlq $32, %rcx ++ movbe -4(%rdi, %rdx), %edi ++ movbe -4(%rsi, %rdx), %esi ++ orq %rdi, %rax ++ orq %rsi, %rcx ++ subq %rcx, %rax ++ /* Fast path for return zero. */ ++ jnz L(ret_nonzero) + /* No ymm register was touched. */ + ret + +@@ -457,9 +456,33 @@ L(one_or_less): + /* No ymm register was touched. */ + ret + ++ .p2align 4,, 5 ++L(ret_nonzero): ++ sbbl %eax, %eax ++ orl $1, %eax ++ /* No ymm register was touched. */ ++ ret ++ ++ .p2align 4,, 2 ++L(zero): ++ xorl %eax, %eax ++ /* No ymm register was touched. */ ++ ret ++ + .p2align 4 + L(between_8_15): +-# endif ++ movbe (%rdi), %rax ++ movbe (%rsi), %rcx ++ subq %rcx, %rax ++ jnz L(ret_nonzero) ++ movbe -8(%rdi, %rdx), %rax ++ movbe -8(%rsi, %rdx), %rcx ++ subq %rcx, %rax ++ /* Fast path for return zero. */ ++ jnz L(ret_nonzero) ++ /* No ymm register was touched. */ ++ ret ++# else + /* If USE_AS_WMEMCMP fall through into 8-15 byte case. */ + vmovq (%rdi), %xmm1 + vmovq (%rsi), %xmm2 +@@ -475,16 +498,13 @@ L(between_8_15): + VPCMPEQ %xmm1, %xmm2, %xmm2 + vpmovmskb %xmm2, %eax + subl $0xffff, %eax ++ /* Fast path for return zero. */ + jnz L(return_vec_0) + /* No ymm register was touched. */ + ret ++# endif + +- .p2align 4 +-L(zero): +- xorl %eax, %eax +- ret +- +- .p2align 4 ++ .p2align 4,, 10 + L(between_16_31): + /* From 16 to 31 bytes. No branch when size == 16. */ + vmovdqu (%rsi), %xmm2 +@@ -501,11 +521,17 @@ L(between_16_31): + VPCMPEQ (%rdi), %xmm2, %xmm2 + vpmovmskb %xmm2, %eax + subl $0xffff, %eax ++ /* Fast path for return zero. */ + jnz L(return_vec_0) + /* No ymm register was touched. */ + ret + + # ifdef USE_AS_WMEMCMP ++ .p2align 4,, 2 ++L(zero): ++ xorl %eax, %eax ++ ret ++ + .p2align 4 + L(one_or_less): + jb L(zero) +@@ -520,22 +546,20 @@ L(one_or_less): + # else + + .p2align 4 +-L(between_4_7): +- /* Load as big endian with overlapping movbe to avoid branches. +- */ +- movbe (%rdi), %eax +- movbe (%rsi), %ecx +- shlq $32, %rax +- shlq $32, %rcx +- movbe -4(%rdi, %rdx), %edi +- movbe -4(%rsi, %rdx), %esi +- orq %rdi, %rax +- orq %rsi, %rcx +- subq %rcx, %rax +- jz L(zero_4_7) +- sbbl %eax, %eax +- orl $1, %eax +-L(zero_4_7): ++L(between_2_3): ++ /* Load as big endian to avoid branches. */ ++ movzwl (%rdi), %eax ++ movzwl (%rsi), %ecx ++ bswap %eax ++ bswap %ecx ++ shrl %eax ++ shrl %ecx ++ movzbl -1(%rdi, %rdx), %edi ++ movzbl -1(%rsi, %rdx), %esi ++ orl %edi, %eax ++ orl %esi, %ecx ++ /* Subtraction is okay because the upper bit is zero. */ ++ subl %ecx, %eax + /* No ymm register was touched. */ + ret + # endif +-- +GitLab + diff --git a/SOURCES/glibc-RHEL-15696-103.patch b/SOURCES/glibc-RHEL-15696-103.patch new file mode 100644 index 0000000..c080e54 --- /dev/null +++ b/SOURCES/glibc-RHEL-15696-103.patch @@ -0,0 +1,876 @@ +From 5307aa9c1800f36a64c183c091c9af392c1fa75c Mon Sep 17 00:00:00 2001 +From: Noah Goldstein +Date: Thu, 21 Apr 2022 20:52:28 -0500 +Subject: [PATCH] x86: Optimize {str|wcs}rchr-sse2 +Content-type: text/plain; charset=UTF-8 + +The new code unrolls the main loop slightly without adding too much +overhead and minimizes the comparisons for the search CHAR. + +Geometric Mean of all benchmarks New / Old: 0.741 +See email for all results. + +Full xcheck passes on x86_64 with and without multiarch enabled. +Reviewed-by: H.J. Lu +--- + sysdeps/x86_64/multiarch/strrchr-sse2.S | 2 +- + sysdeps/x86_64/multiarch/wcsrchr-sse2.S | 3 +- + sysdeps/x86_64/strrchr.S | 510 +++++++++++++++--------- + sysdeps/x86_64/wcsrchr.S | 266 +----------- + 4 files changed, 338 insertions(+), 443 deletions(-) + +Conflicts: + sysdeps/x86_64/wcsrchr.S + (copyright header) + +diff --git a/sysdeps/x86_64/multiarch/strrchr-sse2.S b/sysdeps/x86_64/multiarch/strrchr-sse2.S +index 0ec76fe9..6bb1284b 100644 +--- a/sysdeps/x86_64/multiarch/strrchr-sse2.S ++++ b/sysdeps/x86_64/multiarch/strrchr-sse2.S +@@ -17,7 +17,7 @@ + . */ + + #if IS_IN (libc) +-# define strrchr __strrchr_sse2 ++# define STRRCHR __strrchr_sse2 + + # undef weak_alias + # define weak_alias(strrchr, rindex) +diff --git a/sysdeps/x86_64/multiarch/wcsrchr-sse2.S b/sysdeps/x86_64/multiarch/wcsrchr-sse2.S +index d015e953..f26d53b5 100644 +--- a/sysdeps/x86_64/multiarch/wcsrchr-sse2.S ++++ b/sysdeps/x86_64/multiarch/wcsrchr-sse2.S +@@ -17,7 +17,6 @@ + . */ + + #if IS_IN (libc) +-# define wcsrchr __wcsrchr_sse2 ++# define STRRCHR __wcsrchr_sse2 + #endif +- + #include "../wcsrchr.S" +diff --git a/sysdeps/x86_64/strrchr.S b/sysdeps/x86_64/strrchr.S +index aca98e7e..a58cc220 100644 +--- a/sysdeps/x86_64/strrchr.S ++++ b/sysdeps/x86_64/strrchr.S +@@ -19,210 +19,360 @@ + + #include + ++#ifndef STRRCHR ++# define STRRCHR strrchr ++#endif ++ ++#ifdef USE_AS_WCSRCHR ++# define PCMPEQ pcmpeqd ++# define CHAR_SIZE 4 ++# define PMINU pminud ++#else ++# define PCMPEQ pcmpeqb ++# define CHAR_SIZE 1 ++# define PMINU pminub ++#endif ++ ++#define PAGE_SIZE 4096 ++#define VEC_SIZE 16 ++ + .text +-ENTRY (strrchr) +- movd %esi, %xmm1 ++ENTRY(STRRCHR) ++ movd %esi, %xmm0 + movq %rdi, %rax +- andl $4095, %eax +- punpcklbw %xmm1, %xmm1 +- cmpq $4032, %rax +- punpcklwd %xmm1, %xmm1 +- pshufd $0, %xmm1, %xmm1 ++ andl $(PAGE_SIZE - 1), %eax ++#ifndef USE_AS_WCSRCHR ++ punpcklbw %xmm0, %xmm0 ++ punpcklwd %xmm0, %xmm0 ++#endif ++ pshufd $0, %xmm0, %xmm0 ++ cmpl $(PAGE_SIZE - VEC_SIZE), %eax + ja L(cross_page) +- movdqu (%rdi), %xmm0 ++ ++L(cross_page_continue): ++ movups (%rdi), %xmm1 + pxor %xmm2, %xmm2 +- movdqa %xmm0, %xmm3 +- pcmpeqb %xmm1, %xmm0 +- pcmpeqb %xmm2, %xmm3 +- pmovmskb %xmm0, %ecx +- pmovmskb %xmm3, %edx +- testq %rdx, %rdx +- je L(next_48_bytes) +- leaq -1(%rdx), %rax +- xorq %rdx, %rax +- andq %rcx, %rax +- je L(exit) +- bsrq %rax, %rax ++ PCMPEQ %xmm1, %xmm2 ++ pmovmskb %xmm2, %ecx ++ testl %ecx, %ecx ++ jz L(aligned_more) ++ ++ PCMPEQ %xmm0, %xmm1 ++ pmovmskb %xmm1, %eax ++ leal -1(%rcx), %edx ++ xorl %edx, %ecx ++ andl %ecx, %eax ++ jz L(ret0) ++ bsrl %eax, %eax + addq %rdi, %rax ++ /* We are off by 3 for wcsrchr if search CHAR is non-zero. If ++ search CHAR is zero we are correct. Either way `andq ++ -CHAR_SIZE, %rax` gets the correct result. */ ++#ifdef USE_AS_WCSRCHR ++ andq $-CHAR_SIZE, %rax ++#endif ++L(ret0): + ret + ++ /* Returns for first vec x1/x2 have hard coded backward search ++ path for earlier matches. */ + .p2align 4 +-L(next_48_bytes): +- movdqu 16(%rdi), %xmm4 +- movdqa %xmm4, %xmm5 +- movdqu 32(%rdi), %xmm3 +- pcmpeqb %xmm1, %xmm4 +- pcmpeqb %xmm2, %xmm5 +- movdqu 48(%rdi), %xmm0 +- pmovmskb %xmm5, %edx +- movdqa %xmm3, %xmm5 +- pcmpeqb %xmm1, %xmm3 +- pcmpeqb %xmm2, %xmm5 +- pcmpeqb %xmm0, %xmm2 +- salq $16, %rdx +- pmovmskb %xmm3, %r8d +- pmovmskb %xmm5, %eax +- pmovmskb %xmm2, %esi +- salq $32, %r8 +- salq $32, %rax +- pcmpeqb %xmm1, %xmm0 +- orq %rdx, %rax +- movq %rsi, %rdx +- pmovmskb %xmm4, %esi +- salq $48, %rdx +- salq $16, %rsi +- orq %r8, %rsi +- orq %rcx, %rsi +- pmovmskb %xmm0, %ecx +- salq $48, %rcx +- orq %rcx, %rsi +- orq %rdx, %rax +- je L(loop_header2) +- leaq -1(%rax), %rcx +- xorq %rax, %rcx +- andq %rcx, %rsi +- je L(exit) +- bsrq %rsi, %rsi +- leaq (%rdi,%rsi), %rax ++L(first_vec_x0_test): ++ PCMPEQ %xmm0, %xmm1 ++ pmovmskb %xmm1, %eax ++ testl %eax, %eax ++ jz L(ret0) ++ bsrl %eax, %eax ++ addq %r8, %rax ++#ifdef USE_AS_WCSRCHR ++ andq $-CHAR_SIZE, %rax ++#endif + ret + + .p2align 4 +-L(loop_header2): +- testq %rsi, %rsi +- movq %rdi, %rcx +- je L(no_c_found) +-L(loop_header): +- addq $64, %rdi +- pxor %xmm7, %xmm7 +- andq $-64, %rdi +- jmp L(loop_entry) ++L(first_vec_x1): ++ PCMPEQ %xmm0, %xmm2 ++ pmovmskb %xmm2, %eax ++ leal -1(%rcx), %edx ++ xorl %edx, %ecx ++ andl %ecx, %eax ++ jz L(first_vec_x0_test) ++ bsrl %eax, %eax ++ leaq (VEC_SIZE)(%rdi, %rax), %rax ++#ifdef USE_AS_WCSRCHR ++ andq $-CHAR_SIZE, %rax ++#endif ++ ret + + .p2align 4 +-L(loop64): +- testq %rdx, %rdx +- cmovne %rdx, %rsi +- cmovne %rdi, %rcx +- addq $64, %rdi +-L(loop_entry): +- movdqa 32(%rdi), %xmm3 +- pxor %xmm6, %xmm6 +- movdqa 48(%rdi), %xmm2 +- movdqa %xmm3, %xmm0 +- movdqa 16(%rdi), %xmm4 +- pminub %xmm2, %xmm0 +- movdqa (%rdi), %xmm5 +- pminub %xmm4, %xmm0 +- pminub %xmm5, %xmm0 +- pcmpeqb %xmm7, %xmm0 +- pmovmskb %xmm0, %eax +- movdqa %xmm5, %xmm0 +- pcmpeqb %xmm1, %xmm0 +- pmovmskb %xmm0, %r9d +- movdqa %xmm4, %xmm0 +- pcmpeqb %xmm1, %xmm0 +- pmovmskb %xmm0, %edx +- movdqa %xmm3, %xmm0 +- pcmpeqb %xmm1, %xmm0 +- salq $16, %rdx +- pmovmskb %xmm0, %r10d +- movdqa %xmm2, %xmm0 +- pcmpeqb %xmm1, %xmm0 +- salq $32, %r10 +- orq %r10, %rdx +- pmovmskb %xmm0, %r8d +- orq %r9, %rdx +- salq $48, %r8 +- orq %r8, %rdx ++L(first_vec_x1_test): ++ PCMPEQ %xmm0, %xmm2 ++ pmovmskb %xmm2, %eax + testl %eax, %eax +- je L(loop64) +- pcmpeqb %xmm6, %xmm4 +- pcmpeqb %xmm6, %xmm3 +- pcmpeqb %xmm6, %xmm5 +- pmovmskb %xmm4, %eax +- pmovmskb %xmm3, %r10d +- pcmpeqb %xmm6, %xmm2 +- pmovmskb %xmm5, %r9d +- salq $32, %r10 +- salq $16, %rax +- pmovmskb %xmm2, %r8d +- orq %r10, %rax +- orq %r9, %rax +- salq $48, %r8 +- orq %r8, %rax +- leaq -1(%rax), %r8 +- xorq %rax, %r8 +- andq %r8, %rdx +- cmovne %rdi, %rcx +- cmovne %rdx, %rsi +- bsrq %rsi, %rsi +- leaq (%rcx,%rsi), %rax ++ jz L(first_vec_x0_test) ++ bsrl %eax, %eax ++ leaq (VEC_SIZE)(%rdi, %rax), %rax ++#ifdef USE_AS_WCSRCHR ++ andq $-CHAR_SIZE, %rax ++#endif ++ ret ++ ++ .p2align 4 ++L(first_vec_x2): ++ PCMPEQ %xmm0, %xmm3 ++ pmovmskb %xmm3, %eax ++ leal -1(%rcx), %edx ++ xorl %edx, %ecx ++ andl %ecx, %eax ++ jz L(first_vec_x1_test) ++ bsrl %eax, %eax ++ leaq (VEC_SIZE * 2)(%rdi, %rax), %rax ++#ifdef USE_AS_WCSRCHR ++ andq $-CHAR_SIZE, %rax ++#endif ++ ret ++ ++ .p2align 4 ++L(aligned_more): ++ /* Save original pointer if match was in VEC 0. */ ++ movq %rdi, %r8 ++ andq $-VEC_SIZE, %rdi ++ ++ movaps VEC_SIZE(%rdi), %xmm2 ++ pxor %xmm3, %xmm3 ++ PCMPEQ %xmm2, %xmm3 ++ pmovmskb %xmm3, %ecx ++ testl %ecx, %ecx ++ jnz L(first_vec_x1) ++ ++ movaps (VEC_SIZE * 2)(%rdi), %xmm3 ++ pxor %xmm4, %xmm4 ++ PCMPEQ %xmm3, %xmm4 ++ pmovmskb %xmm4, %ecx ++ testl %ecx, %ecx ++ jnz L(first_vec_x2) ++ ++ addq $VEC_SIZE, %rdi ++ /* Save pointer again before realigning. */ ++ movq %rdi, %rsi ++ andq $-(VEC_SIZE * 2), %rdi ++ .p2align 4 ++L(first_loop): ++ /* Do 2x VEC at a time. */ ++ movaps (VEC_SIZE * 2)(%rdi), %xmm4 ++ movaps (VEC_SIZE * 3)(%rdi), %xmm5 ++ /* Since SSE2 no pminud so wcsrchr needs seperate logic for ++ detecting zero. Note if this is found to be a bottleneck it ++ may be worth adding an SSE4.1 wcsrchr implementation. */ ++#ifdef USE_AS_WCSRCHR ++ movaps %xmm5, %xmm6 ++ pxor %xmm8, %xmm8 ++ ++ PCMPEQ %xmm8, %xmm5 ++ PCMPEQ %xmm4, %xmm8 ++ por %xmm5, %xmm8 ++#else ++ movaps %xmm5, %xmm6 ++ PMINU %xmm4, %xmm5 ++#endif ++ ++ movaps %xmm4, %xmm9 ++ PCMPEQ %xmm0, %xmm4 ++ PCMPEQ %xmm0, %xmm6 ++ movaps %xmm6, %xmm7 ++ por %xmm4, %xmm6 ++#ifndef USE_AS_WCSRCHR ++ pxor %xmm8, %xmm8 ++ PCMPEQ %xmm5, %xmm8 ++#endif ++ pmovmskb %xmm8, %ecx ++ pmovmskb %xmm6, %eax ++ ++ addq $(VEC_SIZE * 2), %rdi ++ /* Use `addl` 1) so we can undo it with `subl` and 2) it can ++ macro-fuse with `jz`. */ ++ addl %ecx, %eax ++ jz L(first_loop) ++ ++ /* Check if there is zero match. */ ++ testl %ecx, %ecx ++ jz L(second_loop_match) ++ ++ /* Check if there was a match in last iteration. */ ++ subl %ecx, %eax ++ jnz L(new_match) ++ ++L(first_loop_old_match): ++ PCMPEQ %xmm0, %xmm2 ++ PCMPEQ %xmm0, %xmm3 ++ pmovmskb %xmm2, %ecx ++ pmovmskb %xmm3, %eax ++ addl %eax, %ecx ++ jz L(first_vec_x0_test) ++ /* NB: We could move this shift to before the branch and save a ++ bit of code size / performance on the fall through. The ++ branch leads to the null case which generally seems hotter ++ than char in first 3x VEC. */ ++ sall $16, %eax ++ orl %ecx, %eax ++ ++ bsrl %eax, %eax ++ addq %rsi, %rax ++#ifdef USE_AS_WCSRCHR ++ andq $-CHAR_SIZE, %rax ++#endif ++ ret ++ ++ .p2align 4 ++L(new_match): ++ pxor %xmm6, %xmm6 ++ PCMPEQ %xmm9, %xmm6 ++ pmovmskb %xmm6, %eax ++ sall $16, %ecx ++ orl %eax, %ecx ++ ++ /* We can't reuse either of the old comparisons as since we mask ++ of zeros after first zero (instead of using the full ++ comparison) we can't gurantee no interference between match ++ after end of string and valid match. */ ++ pmovmskb %xmm4, %eax ++ pmovmskb %xmm7, %edx ++ sall $16, %edx ++ orl %edx, %eax ++ ++ leal -1(%ecx), %edx ++ xorl %edx, %ecx ++ andl %ecx, %eax ++ jz L(first_loop_old_match) ++ bsrl %eax, %eax ++ addq %rdi, %rax ++#ifdef USE_AS_WCSRCHR ++ andq $-CHAR_SIZE, %rax ++#endif + ret + ++ /* Save minimum state for getting most recent match. We can ++ throw out all previous work. */ + .p2align 4 +-L(no_c_found): +- movl $1, %esi +- xorl %ecx, %ecx +- jmp L(loop_header) ++L(second_loop_match): ++ movq %rdi, %rsi ++ movaps %xmm4, %xmm2 ++ movaps %xmm7, %xmm3 + + .p2align 4 +-L(exit): +- xorl %eax, %eax ++L(second_loop): ++ movaps (VEC_SIZE * 2)(%rdi), %xmm4 ++ movaps (VEC_SIZE * 3)(%rdi), %xmm5 ++ /* Since SSE2 no pminud so wcsrchr needs seperate logic for ++ detecting zero. Note if this is found to be a bottleneck it ++ may be worth adding an SSE4.1 wcsrchr implementation. */ ++#ifdef USE_AS_WCSRCHR ++ movaps %xmm5, %xmm6 ++ pxor %xmm8, %xmm8 ++ ++ PCMPEQ %xmm8, %xmm5 ++ PCMPEQ %xmm4, %xmm8 ++ por %xmm5, %xmm8 ++#else ++ movaps %xmm5, %xmm6 ++ PMINU %xmm4, %xmm5 ++#endif ++ ++ movaps %xmm4, %xmm9 ++ PCMPEQ %xmm0, %xmm4 ++ PCMPEQ %xmm0, %xmm6 ++ movaps %xmm6, %xmm7 ++ por %xmm4, %xmm6 ++#ifndef USE_AS_WCSRCHR ++ pxor %xmm8, %xmm8 ++ PCMPEQ %xmm5, %xmm8 ++#endif ++ ++ pmovmskb %xmm8, %ecx ++ pmovmskb %xmm6, %eax ++ ++ addq $(VEC_SIZE * 2), %rdi ++ /* Either null term or new occurence of CHAR. */ ++ addl %ecx, %eax ++ jz L(second_loop) ++ ++ /* No null term so much be new occurence of CHAR. */ ++ testl %ecx, %ecx ++ jz L(second_loop_match) ++ ++ ++ subl %ecx, %eax ++ jnz L(second_loop_new_match) ++ ++L(second_loop_old_match): ++ pmovmskb %xmm2, %ecx ++ pmovmskb %xmm3, %eax ++ sall $16, %eax ++ orl %ecx, %eax ++ bsrl %eax, %eax ++ addq %rsi, %rax ++#ifdef USE_AS_WCSRCHR ++ andq $-CHAR_SIZE, %rax ++#endif + ret + + .p2align 4 ++L(second_loop_new_match): ++ pxor %xmm6, %xmm6 ++ PCMPEQ %xmm9, %xmm6 ++ pmovmskb %xmm6, %eax ++ sall $16, %ecx ++ orl %eax, %ecx ++ ++ /* We can't reuse either of the old comparisons as since we mask ++ of zeros after first zero (instead of using the full ++ comparison) we can't gurantee no interference between match ++ after end of string and valid match. */ ++ pmovmskb %xmm4, %eax ++ pmovmskb %xmm7, %edx ++ sall $16, %edx ++ orl %edx, %eax ++ ++ leal -1(%ecx), %edx ++ xorl %edx, %ecx ++ andl %ecx, %eax ++ jz L(second_loop_old_match) ++ bsrl %eax, %eax ++ addq %rdi, %rax ++#ifdef USE_AS_WCSRCHR ++ andq $-CHAR_SIZE, %rax ++#endif ++ ret ++ ++ .p2align 4,, 4 + L(cross_page): +- movq %rdi, %rax +- pxor %xmm0, %xmm0 +- andq $-64, %rax +- movdqu (%rax), %xmm5 +- movdqa %xmm5, %xmm6 +- movdqu 16(%rax), %xmm4 +- pcmpeqb %xmm1, %xmm5 +- pcmpeqb %xmm0, %xmm6 +- movdqu 32(%rax), %xmm3 +- pmovmskb %xmm6, %esi +- movdqa %xmm4, %xmm6 +- movdqu 48(%rax), %xmm2 +- pcmpeqb %xmm1, %xmm4 +- pcmpeqb %xmm0, %xmm6 +- pmovmskb %xmm6, %edx +- movdqa %xmm3, %xmm6 +- pcmpeqb %xmm1, %xmm3 +- pcmpeqb %xmm0, %xmm6 +- pcmpeqb %xmm2, %xmm0 +- salq $16, %rdx +- pmovmskb %xmm3, %r9d +- pmovmskb %xmm6, %r8d +- pmovmskb %xmm0, %ecx +- salq $32, %r9 +- salq $32, %r8 +- pcmpeqb %xmm1, %xmm2 +- orq %r8, %rdx +- salq $48, %rcx +- pmovmskb %xmm5, %r8d +- orq %rsi, %rdx +- pmovmskb %xmm4, %esi +- orq %rcx, %rdx +- pmovmskb %xmm2, %ecx +- salq $16, %rsi +- salq $48, %rcx +- orq %r9, %rsi +- orq %r8, %rsi +- orq %rcx, %rsi ++ movq %rdi, %rsi ++ andq $-VEC_SIZE, %rsi ++ movaps (%rsi), %xmm1 ++ pxor %xmm2, %xmm2 ++ PCMPEQ %xmm1, %xmm2 ++ pmovmskb %xmm2, %edx + movl %edi, %ecx +- subl %eax, %ecx +- shrq %cl, %rdx +- shrq %cl, %rsi +- testq %rdx, %rdx +- je L(loop_header2) +- leaq -1(%rdx), %rax +- xorq %rdx, %rax +- andq %rax, %rsi +- je L(exit) +- bsrq %rsi, %rax ++ andl $(VEC_SIZE - 1), %ecx ++ sarl %cl, %edx ++ jz L(cross_page_continue) ++ PCMPEQ %xmm0, %xmm1 ++ pmovmskb %xmm1, %eax ++ sarl %cl, %eax ++ leal -1(%rdx), %ecx ++ xorl %edx, %ecx ++ andl %ecx, %eax ++ jz L(ret1) ++ bsrl %eax, %eax + addq %rdi, %rax ++#ifdef USE_AS_WCSRCHR ++ andq $-CHAR_SIZE, %rax ++#endif ++L(ret1): + ret +-END (strrchr) ++END(STRRCHR) + +-weak_alias (strrchr, rindex) +-libc_hidden_builtin_def (strrchr) ++#ifndef USE_AS_WCSRCHR ++ weak_alias (STRRCHR, rindex) ++ libc_hidden_builtin_def (STRRCHR) ++#endif +diff --git a/sysdeps/x86_64/wcsrchr.S b/sysdeps/x86_64/wcsrchr.S +index 2f388537..ae3cfa7d 100644 +--- a/sysdeps/x86_64/wcsrchr.S ++++ b/sysdeps/x86_64/wcsrchr.S +@@ -17,266 +17,12 @@ + License along with the GNU C Library; if not, see + . */ + +-#include + +- .text +-ENTRY (wcsrchr) ++#define USE_AS_WCSRCHR 1 ++#define NO_PMINU 1 + +- movd %rsi, %xmm1 +- mov %rdi, %rcx +- punpckldq %xmm1, %xmm1 +- pxor %xmm2, %xmm2 +- punpckldq %xmm1, %xmm1 +- and $63, %rcx +- cmp $48, %rcx +- ja L(crosscache) ++#ifndef STRRCHR ++# define STRRCHR wcsrchr ++#endif + +- movdqu (%rdi), %xmm0 +- pcmpeqd %xmm0, %xmm2 +- pcmpeqd %xmm1, %xmm0 +- pmovmskb %xmm2, %rcx +- pmovmskb %xmm0, %rax +- add $16, %rdi +- +- test %rax, %rax +- jnz L(unaligned_match1) +- +- test %rcx, %rcx +- jnz L(return_null) +- +- and $-16, %rdi +- xor %r8, %r8 +- jmp L(loop) +- +- .p2align 4 +-L(unaligned_match1): +- test %rcx, %rcx +- jnz L(prolog_find_zero_1) +- +- mov %rax, %r8 +- mov %rdi, %rsi +- and $-16, %rdi +- jmp L(loop) +- +- .p2align 4 +-L(crosscache): +- and $15, %rcx +- and $-16, %rdi +- pxor %xmm3, %xmm3 +- movdqa (%rdi), %xmm0 +- pcmpeqd %xmm0, %xmm3 +- pcmpeqd %xmm1, %xmm0 +- pmovmskb %xmm3, %rdx +- pmovmskb %xmm0, %rax +- shr %cl, %rdx +- shr %cl, %rax +- add $16, %rdi +- +- test %rax, %rax +- jnz L(unaligned_match) +- +- test %rdx, %rdx +- jnz L(return_null) +- +- xor %r8, %r8 +- jmp L(loop) +- +- .p2align 4 +-L(unaligned_match): +- test %rdx, %rdx +- jnz L(prolog_find_zero) +- +- mov %rax, %r8 +- lea (%rdi, %rcx), %rsi +- +-/* Loop start on aligned string. */ +- .p2align 4 +-L(loop): +- movdqa (%rdi), %xmm0 +- pcmpeqd %xmm0, %xmm2 +- add $16, %rdi +- pcmpeqd %xmm1, %xmm0 +- pmovmskb %xmm2, %rcx +- pmovmskb %xmm0, %rax +- or %rax, %rcx +- jnz L(matches) +- +- movdqa (%rdi), %xmm3 +- pcmpeqd %xmm3, %xmm2 +- add $16, %rdi +- pcmpeqd %xmm1, %xmm3 +- pmovmskb %xmm2, %rcx +- pmovmskb %xmm3, %rax +- or %rax, %rcx +- jnz L(matches) +- +- movdqa (%rdi), %xmm4 +- pcmpeqd %xmm4, %xmm2 +- add $16, %rdi +- pcmpeqd %xmm1, %xmm4 +- pmovmskb %xmm2, %rcx +- pmovmskb %xmm4, %rax +- or %rax, %rcx +- jnz L(matches) +- +- movdqa (%rdi), %xmm5 +- pcmpeqd %xmm5, %xmm2 +- add $16, %rdi +- pcmpeqd %xmm1, %xmm5 +- pmovmskb %xmm2, %rcx +- pmovmskb %xmm5, %rax +- or %rax, %rcx +- jz L(loop) +- +- .p2align 4 +-L(matches): +- test %rax, %rax +- jnz L(match) +-L(return_value): +- test %r8, %r8 +- jz L(return_null) +- mov %r8, %rax +- mov %rsi, %rdi +- +- test $15 << 4, %ah +- jnz L(match_fourth_wchar) +- test %ah, %ah +- jnz L(match_third_wchar) +- test $15 << 4, %al +- jnz L(match_second_wchar) +- lea -16(%rdi), %rax +- ret +- +- .p2align 4 +-L(match): +- pmovmskb %xmm2, %rcx +- test %rcx, %rcx +- jnz L(find_zero) +- mov %rax, %r8 +- mov %rdi, %rsi +- jmp L(loop) +- +- .p2align 4 +-L(find_zero): +- test $15, %cl +- jnz L(find_zero_in_first_wchar) +- test %cl, %cl +- jnz L(find_zero_in_second_wchar) +- test $15, %ch +- jnz L(find_zero_in_third_wchar) +- +- and $1 << 13 - 1, %rax +- jz L(return_value) +- +- test $15 << 4, %ah +- jnz L(match_fourth_wchar) +- test %ah, %ah +- jnz L(match_third_wchar) +- test $15 << 4, %al +- jnz L(match_second_wchar) +- lea -16(%rdi), %rax +- ret +- +- .p2align 4 +-L(find_zero_in_first_wchar): +- test $1, %rax +- jz L(return_value) +- lea -16(%rdi), %rax +- ret +- +- .p2align 4 +-L(find_zero_in_second_wchar): +- and $1 << 5 - 1, %rax +- jz L(return_value) +- +- test $15 << 4, %al +- jnz L(match_second_wchar) +- lea -16(%rdi), %rax +- ret +- +- .p2align 4 +-L(find_zero_in_third_wchar): +- and $1 << 9 - 1, %rax +- jz L(return_value) +- +- test %ah, %ah +- jnz L(match_third_wchar) +- test $15 << 4, %al +- jnz L(match_second_wchar) +- lea -16(%rdi), %rax +- ret +- +- .p2align 4 +-L(prolog_find_zero): +- add %rcx, %rdi +- mov %rdx, %rcx +-L(prolog_find_zero_1): +- test $15, %cl +- jnz L(prolog_find_zero_in_first_wchar) +- test %cl, %cl +- jnz L(prolog_find_zero_in_second_wchar) +- test $15, %ch +- jnz L(prolog_find_zero_in_third_wchar) +- +- and $1 << 13 - 1, %rax +- jz L(return_null) +- +- test $15 << 4, %ah +- jnz L(match_fourth_wchar) +- test %ah, %ah +- jnz L(match_third_wchar) +- test $15 << 4, %al +- jnz L(match_second_wchar) +- lea -16(%rdi), %rax +- ret +- +- .p2align 4 +-L(prolog_find_zero_in_first_wchar): +- test $1, %rax +- jz L(return_null) +- lea -16(%rdi), %rax +- ret +- +- .p2align 4 +-L(prolog_find_zero_in_second_wchar): +- and $1 << 5 - 1, %rax +- jz L(return_null) +- +- test $15 << 4, %al +- jnz L(match_second_wchar) +- lea -16(%rdi), %rax +- ret +- +- .p2align 4 +-L(prolog_find_zero_in_third_wchar): +- and $1 << 9 - 1, %rax +- jz L(return_null) +- +- test %ah, %ah +- jnz L(match_third_wchar) +- test $15 << 4, %al +- jnz L(match_second_wchar) +- lea -16(%rdi), %rax +- ret +- +- .p2align 4 +-L(match_second_wchar): +- lea -12(%rdi), %rax +- ret +- +- .p2align 4 +-L(match_third_wchar): +- lea -8(%rdi), %rax +- ret +- +- .p2align 4 +-L(match_fourth_wchar): +- lea -4(%rdi), %rax +- ret +- +- .p2align 4 +-L(return_null): +- xor %rax, %rax +- ret +- +-END (wcsrchr) ++#include "../strrchr.S" +-- +GitLab + diff --git a/SOURCES/glibc-RHEL-15696-104.patch b/SOURCES/glibc-RHEL-15696-104.patch new file mode 100644 index 0000000..1cb312a --- /dev/null +++ b/SOURCES/glibc-RHEL-15696-104.patch @@ -0,0 +1,501 @@ +From df7e295d18ffa34f629578c0017a9881af7620f6 Mon Sep 17 00:00:00 2001 +From: Noah Goldstein +Date: Thu, 21 Apr 2022 20:52:29 -0500 +Subject: [PATCH] x86: Optimize {str|wcs}rchr-avx2 +Content-type: text/plain; charset=UTF-8 + +The new code unrolls the main loop slightly without adding too much +overhead and minimizes the comparisons for the search CHAR. + +Geometric Mean of all benchmarks New / Old: 0.832 +See email for all results. + +Full xcheck passes on x86_64 with and without multiarch enabled. +Reviewed-by: H.J. Lu +--- + sysdeps/x86_64/multiarch/strrchr-avx2.S | 426 +++++++++++++++--------- + 1 file changed, 269 insertions(+), 157 deletions(-) + +diff --git a/sysdeps/x86_64/multiarch/strrchr-avx2.S b/sysdeps/x86_64/multiarch/strrchr-avx2.S +index c949410b..3d26fad4 100644 +--- a/sysdeps/x86_64/multiarch/strrchr-avx2.S ++++ b/sysdeps/x86_64/multiarch/strrchr-avx2.S +@@ -27,9 +27,13 @@ + # ifdef USE_AS_WCSRCHR + # define VPBROADCAST vpbroadcastd + # define VPCMPEQ vpcmpeqd ++# define VPMIN vpminud ++# define CHAR_SIZE 4 + # else + # define VPBROADCAST vpbroadcastb + # define VPCMPEQ vpcmpeqb ++# define VPMIN vpminub ++# define CHAR_SIZE 1 + # endif + + # ifndef VZEROUPPER +@@ -41,196 +45,304 @@ + # endif + + # define VEC_SIZE 32 ++# define PAGE_SIZE 4096 + +- .section SECTION(.text),"ax",@progbits +-ENTRY (STRRCHR) +- movd %esi, %xmm4 +- movl %edi, %ecx ++ .section SECTION(.text), "ax", @progbits ++ENTRY(STRRCHR) ++ movd %esi, %xmm7 ++ movl %edi, %eax + /* Broadcast CHAR to YMM4. */ +- VPBROADCAST %xmm4, %ymm4 ++ VPBROADCAST %xmm7, %ymm7 + vpxor %xmm0, %xmm0, %xmm0 + +- /* Check if we may cross page boundary with one vector load. */ +- andl $(2 * VEC_SIZE - 1), %ecx +- cmpl $VEC_SIZE, %ecx +- ja L(cros_page_boundary) ++ /* Shift here instead of `andl` to save code size (saves a fetch ++ block). */ ++ sall $20, %eax ++ cmpl $((PAGE_SIZE - VEC_SIZE) << 20), %eax ++ ja L(cross_page) + ++L(page_cross_continue): + vmovdqu (%rdi), %ymm1 +- VPCMPEQ %ymm1, %ymm0, %ymm2 +- VPCMPEQ %ymm1, %ymm4, %ymm3 +- vpmovmskb %ymm2, %ecx +- vpmovmskb %ymm3, %eax +- addq $VEC_SIZE, %rdi ++ /* Check end of string match. */ ++ VPCMPEQ %ymm1, %ymm0, %ymm6 ++ vpmovmskb %ymm6, %ecx ++ testl %ecx, %ecx ++ jz L(aligned_more) ++ ++ /* Only check match with search CHAR if needed. */ ++ VPCMPEQ %ymm1, %ymm7, %ymm1 ++ vpmovmskb %ymm1, %eax ++ /* Check if match before first zero. */ ++ blsmskl %ecx, %ecx ++ andl %ecx, %eax ++ jz L(ret0) ++ bsrl %eax, %eax ++ addq %rdi, %rax ++ /* We are off by 3 for wcsrchr if search CHAR is non-zero. If ++ search CHAR is zero we are correct. Either way `andq ++ -CHAR_SIZE, %rax` gets the correct result. */ ++# ifdef USE_AS_WCSRCHR ++ andq $-CHAR_SIZE, %rax ++# endif ++L(ret0): ++L(return_vzeroupper): ++ ZERO_UPPER_VEC_REGISTERS_RETURN ++ ++ /* Returns for first vec x1/x2 have hard coded backward search ++ path for earlier matches. */ ++ .p2align 4,, 10 ++L(first_vec_x1): ++ VPCMPEQ %ymm2, %ymm7, %ymm6 ++ vpmovmskb %ymm6, %eax ++ blsmskl %ecx, %ecx ++ andl %ecx, %eax ++ jnz L(first_vec_x1_return) ++ ++ .p2align 4,, 4 ++L(first_vec_x0_test): ++ VPCMPEQ %ymm1, %ymm7, %ymm6 ++ vpmovmskb %ymm6, %eax ++ testl %eax, %eax ++ jz L(ret1) ++ bsrl %eax, %eax ++ addq %r8, %rax ++# ifdef USE_AS_WCSRCHR ++ andq $-CHAR_SIZE, %rax ++# endif ++L(ret1): ++ VZEROUPPER_RETURN + ++ .p2align 4,, 10 ++L(first_vec_x0_x1_test): ++ VPCMPEQ %ymm2, %ymm7, %ymm6 ++ vpmovmskb %ymm6, %eax ++ /* Check ymm2 for search CHAR match. If no match then check ymm1 ++ before returning. */ + testl %eax, %eax +- jnz L(first_vec) ++ jz L(first_vec_x0_test) ++ .p2align 4,, 4 ++L(first_vec_x1_return): ++ bsrl %eax, %eax ++ leaq 1(%rdi, %rax), %rax ++# ifdef USE_AS_WCSRCHR ++ andq $-CHAR_SIZE, %rax ++# endif ++ VZEROUPPER_RETURN + +- testl %ecx, %ecx +- jnz L(return_null) + +- andq $-VEC_SIZE, %rdi +- xorl %edx, %edx +- jmp L(aligned_loop) ++ .p2align 4,, 10 ++L(first_vec_x2): ++ VPCMPEQ %ymm3, %ymm7, %ymm6 ++ vpmovmskb %ymm6, %eax ++ blsmskl %ecx, %ecx ++ /* If no in-range search CHAR match in ymm3 then need to check ++ ymm1/ymm2 for an earlier match (we delay checking search ++ CHAR matches until needed). */ ++ andl %ecx, %eax ++ jz L(first_vec_x0_x1_test) ++ bsrl %eax, %eax ++ leaq (VEC_SIZE + 1)(%rdi, %rax), %rax ++# ifdef USE_AS_WCSRCHR ++ andq $-CHAR_SIZE, %rax ++# endif ++ VZEROUPPER_RETURN ++ + + .p2align 4 +-L(first_vec): +- /* Check if there is a nul CHAR. */ ++L(aligned_more): ++ /* Save original pointer if match was in VEC 0. */ ++ movq %rdi, %r8 ++ ++ /* Align src. */ ++ orq $(VEC_SIZE - 1), %rdi ++ vmovdqu 1(%rdi), %ymm2 ++ VPCMPEQ %ymm2, %ymm0, %ymm6 ++ vpmovmskb %ymm6, %ecx + testl %ecx, %ecx +- jnz L(char_and_nul_in_first_vec) ++ jnz L(first_vec_x1) + +- /* Remember the match and keep searching. */ +- movl %eax, %edx +- movq %rdi, %rsi +- andq $-VEC_SIZE, %rdi +- jmp L(aligned_loop) ++ vmovdqu (VEC_SIZE + 1)(%rdi), %ymm3 ++ VPCMPEQ %ymm3, %ymm0, %ymm6 ++ vpmovmskb %ymm6, %ecx ++ testl %ecx, %ecx ++ jnz L(first_vec_x2) + ++ /* Save pointer again before realigning. */ ++ movq %rdi, %rsi ++ addq $(VEC_SIZE + 1), %rdi ++ andq $-(VEC_SIZE * 2), %rdi + .p2align 4 +-L(cros_page_boundary): +- andl $(VEC_SIZE - 1), %ecx +- andq $-VEC_SIZE, %rdi +- vmovdqa (%rdi), %ymm1 +- VPCMPEQ %ymm1, %ymm0, %ymm2 +- VPCMPEQ %ymm1, %ymm4, %ymm3 +- vpmovmskb %ymm2, %edx +- vpmovmskb %ymm3, %eax +- shrl %cl, %edx +- shrl %cl, %eax +- addq $VEC_SIZE, %rdi +- +- /* Check if there is a CHAR. */ ++L(first_aligned_loop): ++ /* Do 2x VEC at a time. Any more and the cost of finding the ++ match outweights loop benefit. */ ++ vmovdqa (VEC_SIZE * 0)(%rdi), %ymm4 ++ vmovdqa (VEC_SIZE * 1)(%rdi), %ymm5 ++ ++ VPCMPEQ %ymm4, %ymm7, %ymm6 ++ VPMIN %ymm4, %ymm5, %ymm8 ++ VPCMPEQ %ymm5, %ymm7, %ymm10 ++ vpor %ymm6, %ymm10, %ymm5 ++ VPCMPEQ %ymm8, %ymm0, %ymm8 ++ vpor %ymm5, %ymm8, %ymm9 ++ ++ vpmovmskb %ymm9, %eax ++ addq $(VEC_SIZE * 2), %rdi ++ /* No zero or search CHAR. */ + testl %eax, %eax +- jnz L(found_char) +- +- testl %edx, %edx +- jnz L(return_null) ++ jz L(first_aligned_loop) + +- jmp L(aligned_loop) +- +- .p2align 4 +-L(found_char): +- testl %edx, %edx +- jnz L(char_and_nul) ++ /* If no zero CHAR then go to second loop (this allows us to ++ throw away all prior work). */ ++ vpmovmskb %ymm8, %ecx ++ testl %ecx, %ecx ++ jz L(second_aligned_loop_prep) + +- /* Remember the match and keep searching. */ +- movl %eax, %edx +- leaq (%rdi, %rcx), %rsi ++ /* Search char could be zero so we need to get the true match. ++ */ ++ vpmovmskb %ymm5, %eax ++ testl %eax, %eax ++ jnz L(first_aligned_loop_return) + +- .p2align 4 +-L(aligned_loop): +- vmovdqa (%rdi), %ymm1 +- VPCMPEQ %ymm1, %ymm0, %ymm2 +- addq $VEC_SIZE, %rdi +- VPCMPEQ %ymm1, %ymm4, %ymm3 +- vpmovmskb %ymm2, %ecx +- vpmovmskb %ymm3, %eax +- orl %eax, %ecx +- jnz L(char_nor_null) +- +- vmovdqa (%rdi), %ymm1 +- VPCMPEQ %ymm1, %ymm0, %ymm2 +- add $VEC_SIZE, %rdi +- VPCMPEQ %ymm1, %ymm4, %ymm3 +- vpmovmskb %ymm2, %ecx ++ .p2align 4,, 4 ++L(first_vec_x1_or_x2): ++ VPCMPEQ %ymm3, %ymm7, %ymm3 ++ VPCMPEQ %ymm2, %ymm7, %ymm2 + vpmovmskb %ymm3, %eax +- orl %eax, %ecx +- jnz L(char_nor_null) +- +- vmovdqa (%rdi), %ymm1 +- VPCMPEQ %ymm1, %ymm0, %ymm2 +- addq $VEC_SIZE, %rdi +- VPCMPEQ %ymm1, %ymm4, %ymm3 +- vpmovmskb %ymm2, %ecx +- vpmovmskb %ymm3, %eax +- orl %eax, %ecx +- jnz L(char_nor_null) +- +- vmovdqa (%rdi), %ymm1 +- VPCMPEQ %ymm1, %ymm0, %ymm2 +- addq $VEC_SIZE, %rdi +- VPCMPEQ %ymm1, %ymm4, %ymm3 +- vpmovmskb %ymm2, %ecx +- vpmovmskb %ymm3, %eax +- orl %eax, %ecx +- jz L(aligned_loop) +- +- .p2align 4 +-L(char_nor_null): +- /* Find a CHAR or a nul CHAR in a loop. */ +- testl %eax, %eax +- jnz L(match) +-L(return_value): +- testl %edx, %edx +- jz L(return_null) +- movl %edx, %eax +- movq %rsi, %rdi ++ vpmovmskb %ymm2, %edx ++ /* Use add for macro-fusion. */ ++ addq %rax, %rdx ++ jz L(first_vec_x0_test) ++ /* NB: We could move this shift to before the branch and save a ++ bit of code size / performance on the fall through. The ++ branch leads to the null case which generally seems hotter ++ than char in first 3x VEC. */ ++ salq $32, %rax ++ addq %rdx, %rax ++ bsrq %rax, %rax ++ leaq 1(%rsi, %rax), %rax ++# ifdef USE_AS_WCSRCHR ++ andq $-CHAR_SIZE, %rax ++# endif ++ VZEROUPPER_RETURN + ++ .p2align 4,, 8 ++L(first_aligned_loop_return): ++ VPCMPEQ %ymm4, %ymm0, %ymm4 ++ vpmovmskb %ymm4, %edx ++ salq $32, %rcx ++ orq %rdx, %rcx ++ ++ vpmovmskb %ymm10, %eax ++ vpmovmskb %ymm6, %edx ++ salq $32, %rax ++ orq %rdx, %rax ++ blsmskq %rcx, %rcx ++ andq %rcx, %rax ++ jz L(first_vec_x1_or_x2) ++ ++ bsrq %rax, %rax ++ leaq -(VEC_SIZE * 2)(%rdi, %rax), %rax + # ifdef USE_AS_WCSRCHR +- /* Keep the first bit for each matching CHAR for bsr. */ +- andl $0x11111111, %eax ++ andq $-CHAR_SIZE, %rax + # endif +- bsrl %eax, %eax +- leaq -VEC_SIZE(%rdi, %rax), %rax +-L(return_vzeroupper): +- ZERO_UPPER_VEC_REGISTERS_RETURN ++ VZEROUPPER_RETURN + ++ /* Search char cannot be zero. */ + .p2align 4 +-L(match): +- /* Find a CHAR. Check if there is a nul CHAR. */ +- vpmovmskb %ymm2, %ecx +- testl %ecx, %ecx +- jnz L(find_nul) +- +- /* Remember the match and keep searching. */ +- movl %eax, %edx ++L(second_aligned_loop_set_furthest_match): ++ /* Save VEC and pointer from most recent match. */ ++L(second_aligned_loop_prep): + movq %rdi, %rsi +- jmp L(aligned_loop) ++ vmovdqu %ymm6, %ymm2 ++ vmovdqu %ymm10, %ymm3 + + .p2align 4 +-L(find_nul): +-# ifdef USE_AS_WCSRCHR +- /* Keep the first bit for each matching CHAR for bsr. */ +- andl $0x11111111, %ecx +- andl $0x11111111, %eax +-# endif +- /* Mask out any matching bits after the nul CHAR. */ +- movl %ecx, %r8d +- subl $1, %r8d +- xorl %ecx, %r8d +- andl %r8d, %eax ++L(second_aligned_loop): ++ /* Search 2x at at time. */ ++ vmovdqa (VEC_SIZE * 0)(%rdi), %ymm4 ++ vmovdqa (VEC_SIZE * 1)(%rdi), %ymm5 ++ ++ VPCMPEQ %ymm4, %ymm7, %ymm6 ++ VPMIN %ymm4, %ymm5, %ymm1 ++ VPCMPEQ %ymm5, %ymm7, %ymm10 ++ vpor %ymm6, %ymm10, %ymm5 ++ VPCMPEQ %ymm1, %ymm0, %ymm1 ++ vpor %ymm5, %ymm1, %ymm9 ++ ++ vpmovmskb %ymm9, %eax ++ addq $(VEC_SIZE * 2), %rdi + testl %eax, %eax +- /* If there is no CHAR here, return the remembered one. */ +- jz L(return_value) +- bsrl %eax, %eax +- leaq -VEC_SIZE(%rdi, %rax), %rax +- VZEROUPPER_RETURN +- +- .p2align 4 +-L(char_and_nul): +- /* Find both a CHAR and a nul CHAR. */ +- addq %rcx, %rdi +- movl %edx, %ecx +-L(char_and_nul_in_first_vec): +-# ifdef USE_AS_WCSRCHR +- /* Keep the first bit for each matching CHAR for bsr. */ +- andl $0x11111111, %ecx +- andl $0x11111111, %eax +-# endif +- /* Mask out any matching bits after the nul CHAR. */ +- movl %ecx, %r8d +- subl $1, %r8d +- xorl %ecx, %r8d +- andl %r8d, %eax ++ jz L(second_aligned_loop) ++ vpmovmskb %ymm1, %ecx ++ testl %ecx, %ecx ++ jz L(second_aligned_loop_set_furthest_match) ++ vpmovmskb %ymm5, %eax + testl %eax, %eax +- /* Return null pointer if the nul CHAR comes first. */ +- jz L(return_null) +- bsrl %eax, %eax +- leaq -VEC_SIZE(%rdi, %rax), %rax ++ jnz L(return_new_match) ++ ++ /* This is the hot patch. We know CHAR is inbounds and that ++ ymm3/ymm2 have latest match. */ ++ .p2align 4,, 4 ++L(return_old_match): ++ vpmovmskb %ymm3, %eax ++ vpmovmskb %ymm2, %edx ++ salq $32, %rax ++ orq %rdx, %rax ++ bsrq %rax, %rax ++ /* Search char cannot be zero so safe to just use lea for ++ wcsrchr. */ ++ leaq (VEC_SIZE * -2 -(CHAR_SIZE - 1))(%rsi, %rax), %rax + VZEROUPPER_RETURN + +- .p2align 4 +-L(return_null): +- xorl %eax, %eax ++ /* Last iteration also potentially has a match. */ ++ .p2align 4,, 8 ++L(return_new_match): ++ VPCMPEQ %ymm4, %ymm0, %ymm4 ++ vpmovmskb %ymm4, %edx ++ salq $32, %rcx ++ orq %rdx, %rcx ++ ++ vpmovmskb %ymm10, %eax ++ vpmovmskb %ymm6, %edx ++ salq $32, %rax ++ orq %rdx, %rax ++ blsmskq %rcx, %rcx ++ andq %rcx, %rax ++ jz L(return_old_match) ++ bsrq %rax, %rax ++ /* Search char cannot be zero so safe to just use lea for ++ wcsrchr. */ ++ leaq (VEC_SIZE * -2 -(CHAR_SIZE - 1))(%rdi, %rax), %rax + VZEROUPPER_RETURN + +-END (STRRCHR) ++ .p2align 4,, 4 ++L(cross_page): ++ movq %rdi, %rsi ++ andq $-VEC_SIZE, %rsi ++ vmovdqu (%rsi), %ymm1 ++ VPCMPEQ %ymm1, %ymm0, %ymm6 ++ vpmovmskb %ymm6, %ecx ++ /* Shift out zero CHAR matches that are before the begining of ++ src (rdi). */ ++ shrxl %edi, %ecx, %ecx ++ testl %ecx, %ecx ++ jz L(page_cross_continue) ++ VPCMPEQ %ymm1, %ymm7, %ymm1 ++ vpmovmskb %ymm1, %eax ++ ++ /* Shift out search CHAR matches that are before the begining of ++ src (rdi). */ ++ shrxl %edi, %eax, %eax ++ blsmskl %ecx, %ecx ++ /* Check if any search CHAR match in range. */ ++ andl %ecx, %eax ++ jz L(ret2) ++ bsrl %eax, %eax ++ addq %rdi, %rax ++# ifdef USE_AS_WCSRCHR ++ andq $-CHAR_SIZE, %rax ++# endif ++L(ret2): ++ VZEROUPPER_RETURN ++END(STRRCHR) + #endif +-- +GitLab + diff --git a/SOURCES/glibc-RHEL-15696-105.patch b/SOURCES/glibc-RHEL-15696-105.patch new file mode 100644 index 0000000..e0a157f --- /dev/null +++ b/SOURCES/glibc-RHEL-15696-105.patch @@ -0,0 +1,558 @@ +From c966099cdc3e0fdf92f63eac09b22fa7e5f5f02d Mon Sep 17 00:00:00 2001 +From: Noah Goldstein +Date: Thu, 21 Apr 2022 20:52:30 -0500 +Subject: [PATCH] x86: Optimize {str|wcs}rchr-evex +Content-type: text/plain; charset=UTF-8 + +The new code unrolls the main loop slightly without adding too much +overhead and minimizes the comparisons for the search CHAR. + +Geometric Mean of all benchmarks New / Old: 0.755 +See email for all results. + +Full xcheck passes on x86_64 with and without multiarch enabled. +Reviewed-by: H.J. Lu +--- + sysdeps/x86_64/multiarch/strrchr-evex.S | 471 +++++++++++++++--------- + 1 file changed, 290 insertions(+), 181 deletions(-) + +diff --git a/sysdeps/x86_64/multiarch/strrchr-evex.S b/sysdeps/x86_64/multiarch/strrchr-evex.S +index f920b5a5..f5b6d755 100644 +--- a/sysdeps/x86_64/multiarch/strrchr-evex.S ++++ b/sysdeps/x86_64/multiarch/strrchr-evex.S +@@ -24,242 +24,351 @@ + # define STRRCHR __strrchr_evex + # endif + +-# define VMOVU vmovdqu64 +-# define VMOVA vmovdqa64 ++# define VMOVU vmovdqu64 ++# define VMOVA vmovdqa64 + + # ifdef USE_AS_WCSRCHR ++# define SHIFT_REG esi ++ ++# define kunpck kunpckbw ++# define kmov_2x kmovd ++# define maskz_2x ecx ++# define maskm_2x eax ++# define CHAR_SIZE 4 ++# define VPMIN vpminud ++# define VPTESTN vptestnmd + # define VPBROADCAST vpbroadcastd +-# define VPCMP vpcmpd +-# define SHIFT_REG r8d ++# define VPCMP vpcmpd + # else ++# define SHIFT_REG edi ++ ++# define kunpck kunpckdq ++# define kmov_2x kmovq ++# define maskz_2x rcx ++# define maskm_2x rax ++ ++# define CHAR_SIZE 1 ++# define VPMIN vpminub ++# define VPTESTN vptestnmb + # define VPBROADCAST vpbroadcastb +-# define VPCMP vpcmpb +-# define SHIFT_REG ecx ++# define VPCMP vpcmpb + # endif + + # define XMMZERO xmm16 + # define YMMZERO ymm16 + # define YMMMATCH ymm17 +-# define YMM1 ymm18 ++# define YMMSAVE ymm18 ++ ++# define YMM1 ymm19 ++# define YMM2 ymm20 ++# define YMM3 ymm21 ++# define YMM4 ymm22 ++# define YMM5 ymm23 ++# define YMM6 ymm24 ++# define YMM7 ymm25 ++# define YMM8 ymm26 + +-# define VEC_SIZE 32 + +- .section .text.evex,"ax",@progbits +-ENTRY (STRRCHR) +- movl %edi, %ecx ++# define VEC_SIZE 32 ++# define PAGE_SIZE 4096 ++ .section .text.evex, "ax", @progbits ++ENTRY(STRRCHR) ++ movl %edi, %eax + /* Broadcast CHAR to YMMMATCH. */ + VPBROADCAST %esi, %YMMMATCH + +- vpxorq %XMMZERO, %XMMZERO, %XMMZERO +- +- /* Check if we may cross page boundary with one vector load. */ +- andl $(2 * VEC_SIZE - 1), %ecx +- cmpl $VEC_SIZE, %ecx +- ja L(cros_page_boundary) ++ andl $(PAGE_SIZE - 1), %eax ++ cmpl $(PAGE_SIZE - VEC_SIZE), %eax ++ jg L(cross_page_boundary) + ++L(page_cross_continue): + VMOVU (%rdi), %YMM1 +- +- /* Each bit in K0 represents a null byte in YMM1. */ +- VPCMP $0, %YMMZERO, %YMM1, %k0 +- /* Each bit in K1 represents a CHAR in YMM1. */ +- VPCMP $0, %YMMMATCH, %YMM1, %k1 ++ /* k0 has a 1 for each zero CHAR in YMM1. */ ++ VPTESTN %YMM1, %YMM1, %k0 + kmovd %k0, %ecx +- kmovd %k1, %eax +- +- addq $VEC_SIZE, %rdi +- +- testl %eax, %eax +- jnz L(first_vec) +- + testl %ecx, %ecx +- jnz L(return_null) +- +- andq $-VEC_SIZE, %rdi +- xorl %edx, %edx +- jmp L(aligned_loop) +- +- .p2align 4 +-L(first_vec): +- /* Check if there is a null byte. */ +- testl %ecx, %ecx +- jnz L(char_and_nul_in_first_vec) +- +- /* Remember the match and keep searching. */ +- movl %eax, %edx +- movq %rdi, %rsi +- andq $-VEC_SIZE, %rdi +- jmp L(aligned_loop) +- +- .p2align 4 +-L(cros_page_boundary): +- andl $(VEC_SIZE - 1), %ecx +- andq $-VEC_SIZE, %rdi ++ jz L(aligned_more) ++ /* fallthrough: zero CHAR in first VEC. */ + ++ /* K1 has a 1 for each search CHAR match in YMM1. */ ++ VPCMP $0, %YMMMATCH, %YMM1, %k1 ++ kmovd %k1, %eax ++ /* Build mask up until first zero CHAR (used to mask of ++ potential search CHAR matches past the end of the string). ++ */ ++ blsmskl %ecx, %ecx ++ andl %ecx, %eax ++ jz L(ret0) ++ /* Get last match (the `andl` removed any out of bounds ++ matches). */ ++ bsrl %eax, %eax + # ifdef USE_AS_WCSRCHR +- /* NB: Divide shift count by 4 since each bit in K1 represent 4 +- bytes. */ +- movl %ecx, %SHIFT_REG +- sarl $2, %SHIFT_REG ++ leaq (%rdi, %rax, CHAR_SIZE), %rax ++# else ++ addq %rdi, %rax + # endif ++L(ret0): ++ ret + +- VMOVA (%rdi), %YMM1 +- +- /* Each bit in K0 represents a null byte in YMM1. */ +- VPCMP $0, %YMMZERO, %YMM1, %k0 +- /* Each bit in K1 represents a CHAR in YMM1. */ ++ /* Returns for first vec x1/x2/x3 have hard coded backward ++ search path for earlier matches. */ ++ .p2align 4,, 6 ++L(first_vec_x1): ++ VPCMP $0, %YMMMATCH, %YMM2, %k1 ++ kmovd %k1, %eax ++ blsmskl %ecx, %ecx ++ /* eax non-zero if search CHAR in range. */ ++ andl %ecx, %eax ++ jnz L(first_vec_x1_return) ++ ++ /* fallthrough: no match in YMM2 then need to check for earlier ++ matches (in YMM1). */ ++ .p2align 4,, 4 ++L(first_vec_x0_test): + VPCMP $0, %YMMMATCH, %YMM1, %k1 +- kmovd %k0, %edx + kmovd %k1, %eax +- +- shrxl %SHIFT_REG, %edx, %edx +- shrxl %SHIFT_REG, %eax, %eax +- addq $VEC_SIZE, %rdi +- +- /* Check if there is a CHAR. */ + testl %eax, %eax +- jnz L(found_char) +- +- testl %edx, %edx +- jnz L(return_null) +- +- jmp L(aligned_loop) +- +- .p2align 4 +-L(found_char): +- testl %edx, %edx +- jnz L(char_and_nul) +- +- /* Remember the match and keep searching. */ +- movl %eax, %edx +- leaq (%rdi, %rcx), %rsi ++ jz L(ret1) ++ bsrl %eax, %eax ++# ifdef USE_AS_WCSRCHR ++ leaq (%rsi, %rax, CHAR_SIZE), %rax ++# else ++ addq %rsi, %rax ++# endif ++L(ret1): ++ ret + +- .p2align 4 +-L(aligned_loop): +- VMOVA (%rdi), %YMM1 +- addq $VEC_SIZE, %rdi ++ .p2align 4,, 10 ++L(first_vec_x1_or_x2): ++ VPCMP $0, %YMM3, %YMMMATCH, %k3 ++ VPCMP $0, %YMM2, %YMMMATCH, %k2 ++ /* K2 and K3 have 1 for any search CHAR match. Test if any ++ matches between either of them. Otherwise check YMM1. */ ++ kortestd %k2, %k3 ++ jz L(first_vec_x0_test) ++ ++ /* Guranteed that YMM2 and YMM3 are within range so merge the ++ two bitmasks then get last result. */ ++ kunpck %k2, %k3, %k3 ++ kmovq %k3, %rax ++ bsrq %rax, %rax ++ leaq (VEC_SIZE)(%r8, %rax, CHAR_SIZE), %rax ++ ret + +- /* Each bit in K0 represents a null byte in YMM1. */ +- VPCMP $0, %YMMZERO, %YMM1, %k0 +- /* Each bit in K1 represents a CHAR in YMM1. */ +- VPCMP $0, %YMMMATCH, %YMM1, %k1 +- kmovd %k0, %ecx ++ .p2align 4,, 6 ++L(first_vec_x3): ++ VPCMP $0, %YMMMATCH, %YMM4, %k1 + kmovd %k1, %eax +- orl %eax, %ecx +- jnz L(char_nor_null) ++ blsmskl %ecx, %ecx ++ /* If no search CHAR match in range check YMM1/YMM2/YMM3. */ ++ andl %ecx, %eax ++ jz L(first_vec_x1_or_x2) ++ bsrl %eax, %eax ++ leaq (VEC_SIZE * 3)(%rdi, %rax, CHAR_SIZE), %rax ++ ret + +- VMOVA (%rdi), %YMM1 +- add $VEC_SIZE, %rdi ++ .p2align 4,, 6 ++L(first_vec_x0_x1_test): ++ VPCMP $0, %YMMMATCH, %YMM2, %k1 ++ kmovd %k1, %eax ++ /* Check YMM2 for last match first. If no match try YMM1. */ ++ testl %eax, %eax ++ jz L(first_vec_x0_test) ++ .p2align 4,, 4 ++L(first_vec_x1_return): ++ bsrl %eax, %eax ++ leaq (VEC_SIZE)(%rdi, %rax, CHAR_SIZE), %rax ++ ret + +- /* Each bit in K0 represents a null byte in YMM1. */ +- VPCMP $0, %YMMZERO, %YMM1, %k0 +- /* Each bit in K1 represents a CHAR in YMM1. */ +- VPCMP $0, %YMMMATCH, %YMM1, %k1 +- kmovd %k0, %ecx ++ .p2align 4,, 10 ++L(first_vec_x2): ++ VPCMP $0, %YMMMATCH, %YMM3, %k1 + kmovd %k1, %eax +- orl %eax, %ecx +- jnz L(char_nor_null) ++ blsmskl %ecx, %ecx ++ /* Check YMM3 for last match first. If no match try YMM2/YMM1. ++ */ ++ andl %ecx, %eax ++ jz L(first_vec_x0_x1_test) ++ bsrl %eax, %eax ++ leaq (VEC_SIZE * 2)(%rdi, %rax, CHAR_SIZE), %rax ++ ret + +- VMOVA (%rdi), %YMM1 +- addq $VEC_SIZE, %rdi + +- /* Each bit in K0 represents a null byte in YMM1. */ +- VPCMP $0, %YMMZERO, %YMM1, %k0 +- /* Each bit in K1 represents a CHAR in YMM1. */ +- VPCMP $0, %YMMMATCH, %YMM1, %k1 ++ .p2align 4 ++L(aligned_more): ++ /* Need to keep original pointer incase YMM1 has last match. */ ++ movq %rdi, %rsi ++ andq $-VEC_SIZE, %rdi ++ VMOVU VEC_SIZE(%rdi), %YMM2 ++ VPTESTN %YMM2, %YMM2, %k0 + kmovd %k0, %ecx +- kmovd %k1, %eax +- orl %eax, %ecx +- jnz L(char_nor_null) ++ testl %ecx, %ecx ++ jnz L(first_vec_x1) + +- VMOVA (%rdi), %YMM1 +- addq $VEC_SIZE, %rdi ++ VMOVU (VEC_SIZE * 2)(%rdi), %YMM3 ++ VPTESTN %YMM3, %YMM3, %k0 ++ kmovd %k0, %ecx ++ testl %ecx, %ecx ++ jnz L(first_vec_x2) + +- /* Each bit in K0 represents a null byte in YMM1. */ +- VPCMP $0, %YMMZERO, %YMM1, %k0 +- /* Each bit in K1 represents a CHAR in YMM1. */ +- VPCMP $0, %YMMMATCH, %YMM1, %k1 ++ VMOVU (VEC_SIZE * 3)(%rdi), %YMM4 ++ VPTESTN %YMM4, %YMM4, %k0 + kmovd %k0, %ecx +- kmovd %k1, %eax +- orl %eax, %ecx +- jz L(aligned_loop) ++ movq %rdi, %r8 ++ testl %ecx, %ecx ++ jnz L(first_vec_x3) + ++ andq $-(VEC_SIZE * 2), %rdi + .p2align 4 +-L(char_nor_null): +- /* Find a CHAR or a null byte in a loop. */ ++L(first_aligned_loop): ++ /* Preserve YMM1, YMM2, YMM3, and YMM4 until we can gurantee ++ they don't store a match. */ ++ VMOVA (VEC_SIZE * 4)(%rdi), %YMM5 ++ VMOVA (VEC_SIZE * 5)(%rdi), %YMM6 ++ ++ VPCMP $0, %YMM5, %YMMMATCH, %k2 ++ vpxord %YMM6, %YMMMATCH, %YMM7 ++ ++ VPMIN %YMM5, %YMM6, %YMM8 ++ VPMIN %YMM8, %YMM7, %YMM7 ++ ++ VPTESTN %YMM7, %YMM7, %k1 ++ subq $(VEC_SIZE * -2), %rdi ++ kortestd %k1, %k2 ++ jz L(first_aligned_loop) ++ ++ VPCMP $0, %YMM6, %YMMMATCH, %k3 ++ VPTESTN %YMM8, %YMM8, %k1 ++ ktestd %k1, %k1 ++ jz L(second_aligned_loop_prep) ++ ++ kortestd %k2, %k3 ++ jnz L(return_first_aligned_loop) ++ ++ .p2align 4,, 6 ++L(first_vec_x1_or_x2_or_x3): ++ VPCMP $0, %YMM4, %YMMMATCH, %k4 ++ kmovd %k4, %eax + testl %eax, %eax +- jnz L(match) +-L(return_value): +- testl %edx, %edx +- jz L(return_null) +- movl %edx, %eax +- movq %rsi, %rdi ++ jz L(first_vec_x1_or_x2) + bsrl %eax, %eax +-# ifdef USE_AS_WCSRCHR +- /* NB: Multiply wchar_t count by 4 to get the number of bytes. */ +- leaq -VEC_SIZE(%rdi, %rax, 4), %rax +-# else +- leaq -VEC_SIZE(%rdi, %rax), %rax +-# endif ++ leaq (VEC_SIZE * 3)(%r8, %rax, CHAR_SIZE), %rax + ret + +- .p2align 4 +-L(match): +- /* Find a CHAR. Check if there is a null byte. */ +- kmovd %k0, %ecx +- testl %ecx, %ecx +- jnz L(find_nul) ++ .p2align 4,, 8 ++L(return_first_aligned_loop): ++ VPTESTN %YMM5, %YMM5, %k0 ++ kunpck %k0, %k1, %k0 ++ kmov_2x %k0, %maskz_2x ++ ++ blsmsk %maskz_2x, %maskz_2x ++ kunpck %k2, %k3, %k3 ++ kmov_2x %k3, %maskm_2x ++ and %maskz_2x, %maskm_2x ++ jz L(first_vec_x1_or_x2_or_x3) + +- /* Remember the match and keep searching. */ +- movl %eax, %edx ++ bsr %maskm_2x, %maskm_2x ++ leaq (VEC_SIZE * 2)(%rdi, %rax, CHAR_SIZE), %rax ++ ret ++ ++ .p2align 4 ++ /* We can throw away the work done for the first 4x checks here ++ as we have a later match. This is the 'fast' path persay. ++ */ ++L(second_aligned_loop_prep): ++L(second_aligned_loop_set_furthest_match): + movq %rdi, %rsi +- jmp L(aligned_loop) ++ kunpck %k2, %k3, %k4 + + .p2align 4 +-L(find_nul): +- /* Mask out any matching bits after the null byte. */ +- movl %ecx, %r8d +- subl $1, %r8d +- xorl %ecx, %r8d +- andl %r8d, %eax +- testl %eax, %eax +- /* If there is no CHAR here, return the remembered one. */ +- jz L(return_value) +- bsrl %eax, %eax ++L(second_aligned_loop): ++ VMOVU (VEC_SIZE * 4)(%rdi), %YMM1 ++ VMOVU (VEC_SIZE * 5)(%rdi), %YMM2 ++ ++ VPCMP $0, %YMM1, %YMMMATCH, %k2 ++ vpxord %YMM2, %YMMMATCH, %YMM3 ++ ++ VPMIN %YMM1, %YMM2, %YMM4 ++ VPMIN %YMM3, %YMM4, %YMM3 ++ ++ VPTESTN %YMM3, %YMM3, %k1 ++ subq $(VEC_SIZE * -2), %rdi ++ kortestd %k1, %k2 ++ jz L(second_aligned_loop) ++ ++ VPCMP $0, %YMM2, %YMMMATCH, %k3 ++ VPTESTN %YMM4, %YMM4, %k1 ++ ktestd %k1, %k1 ++ jz L(second_aligned_loop_set_furthest_match) ++ ++ kortestd %k2, %k3 ++ /* branch here because there is a significant advantage interms ++ of output dependency chance in using edx. */ ++ jnz L(return_new_match) ++L(return_old_match): ++ kmovq %k4, %rax ++ bsrq %rax, %rax ++ leaq (VEC_SIZE * 2)(%rsi, %rax, CHAR_SIZE), %rax ++ ret ++ ++L(return_new_match): ++ VPTESTN %YMM1, %YMM1, %k0 ++ kunpck %k0, %k1, %k0 ++ kmov_2x %k0, %maskz_2x ++ ++ blsmsk %maskz_2x, %maskz_2x ++ kunpck %k2, %k3, %k3 ++ kmov_2x %k3, %maskm_2x ++ and %maskz_2x, %maskm_2x ++ jz L(return_old_match) ++ ++ bsr %maskm_2x, %maskm_2x ++ leaq (VEC_SIZE * 2)(%rdi, %rax, CHAR_SIZE), %rax ++ ret ++ ++L(cross_page_boundary): ++ /* eax contains all the page offset bits of src (rdi). `xor rdi, ++ rax` sets pointer will all page offset bits cleared so ++ offset of (PAGE_SIZE - VEC_SIZE) will get last aligned VEC ++ before page cross (guranteed to be safe to read). Doing this ++ as opposed to `movq %rdi, %rax; andq $-VEC_SIZE, %rax` saves ++ a bit of code size. */ ++ xorq %rdi, %rax ++ VMOVU (PAGE_SIZE - VEC_SIZE)(%rax), %YMM1 ++ VPTESTN %YMM1, %YMM1, %k0 ++ kmovd %k0, %ecx ++ ++ /* Shift out zero CHAR matches that are before the begining of ++ src (rdi). */ + # ifdef USE_AS_WCSRCHR +- /* NB: Multiply wchar_t count by 4 to get the number of bytes. */ +- leaq -VEC_SIZE(%rdi, %rax, 4), %rax +-# else +- leaq -VEC_SIZE(%rdi, %rax), %rax ++ movl %edi, %esi ++ andl $(VEC_SIZE - 1), %esi ++ shrl $2, %esi + # endif +- ret ++ shrxl %SHIFT_REG, %ecx, %ecx + +- .p2align 4 +-L(char_and_nul): +- /* Find both a CHAR and a null byte. */ +- addq %rcx, %rdi +- movl %edx, %ecx +-L(char_and_nul_in_first_vec): +- /* Mask out any matching bits after the null byte. */ +- movl %ecx, %r8d +- subl $1, %r8d +- xorl %ecx, %r8d +- andl %r8d, %eax +- testl %eax, %eax +- /* Return null pointer if the null byte comes first. */ +- jz L(return_null) ++ testl %ecx, %ecx ++ jz L(page_cross_continue) ++ ++ /* Found zero CHAR so need to test for search CHAR. */ ++ VPCMP $0, %YMMMATCH, %YMM1, %k1 ++ kmovd %k1, %eax ++ /* Shift out search CHAR matches that are before the begining of ++ src (rdi). */ ++ shrxl %SHIFT_REG, %eax, %eax ++ ++ /* Check if any search CHAR match in range. */ ++ blsmskl %ecx, %ecx ++ andl %ecx, %eax ++ jz L(ret3) + bsrl %eax, %eax + # ifdef USE_AS_WCSRCHR +- /* NB: Multiply wchar_t count by 4 to get the number of bytes. */ +- leaq -VEC_SIZE(%rdi, %rax, 4), %rax ++ leaq (%rdi, %rax, CHAR_SIZE), %rax + # else +- leaq -VEC_SIZE(%rdi, %rax), %rax ++ addq %rdi, %rax + # endif ++L(ret3): + ret + +- .p2align 4 +-L(return_null): +- xorl %eax, %eax +- ret +- +-END (STRRCHR) ++END(STRRCHR) + #endif +-- +GitLab + diff --git a/SOURCES/glibc-RHEL-15696-106.patch b/SOURCES/glibc-RHEL-15696-106.patch new file mode 100644 index 0000000..f3bdb17 --- /dev/null +++ b/SOURCES/glibc-RHEL-15696-106.patch @@ -0,0 +1,73 @@ +From 911c63a51c690dd1a97dfc587097277029baf00f Mon Sep 17 00:00:00 2001 +From: Noah Goldstein +Date: Wed, 27 Apr 2022 15:13:02 -0500 +Subject: [PATCH] sysdeps: Add 'get_fast_jitter' interace in fast-jitter.h +Content-type: text/plain; charset=UTF-8 + +'get_fast_jitter' is meant to be used purely for performance +purposes. In all cases it's used it should be acceptable to get no +randomness (see default case). An example use case is in setting +jitter for retries between threads at a lock. There is a +performance benefit to having jitter, but only if the jitter can +be generated very quickly and ultimately there is no serious issue +if no jitter is generated. + +The implementation generally uses 'HP_TIMING_NOW' iff it is +inlined (avoid any potential syscall paths). +Reviewed-by: H.J. Lu +--- + sysdeps/generic/fast-jitter.h | 42 +++++++++++++++++++++++++++++++++++ + 1 file changed, 42 insertions(+) + create mode 100644 sysdeps/generic/fast-jitter.h + +diff --git a/sysdeps/generic/fast-jitter.h b/sysdeps/generic/fast-jitter.h +new file mode 100644 +index 00000000..4dd53e34 +--- /dev/null ++++ b/sysdeps/generic/fast-jitter.h +@@ -0,0 +1,42 @@ ++/* Fallback for fast jitter just return 0. ++ 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 ++ . */ ++ ++#ifndef _FAST_JITTER_H ++# define _FAST_JITTER_H ++ ++# include ++# include ++ ++/* Baseline just return 0. We could create jitter using a clock or ++ 'random_bits' but that may imply a syscall and the goal of ++ 'get_fast_jitter' is minimal overhead "randomness" when such ++ randomness helps performance. Adding high overhead the function ++ defeats the purpose. */ ++static inline uint32_t ++get_fast_jitter (void) ++{ ++# if HP_TIMING_INLINE ++ hp_timing_t jitter; ++ HP_TIMING_NOW (jitter); ++ return (uint32_t) jitter; ++# else ++ return 0; ++# endif ++} ++ ++#endif +-- +GitLab + diff --git a/SOURCES/glibc-RHEL-15696-107.patch b/SOURCES/glibc-RHEL-15696-107.patch new file mode 100644 index 0000000..738cc23 --- /dev/null +++ b/SOURCES/glibc-RHEL-15696-107.patch @@ -0,0 +1,226 @@ +From 8162147872491bb5b48e91543b19c49a29ae6b6d Mon Sep 17 00:00:00 2001 +From: Wangyang Guo +Date: Fri, 6 May 2022 01:50:10 +0000 +Subject: [PATCH] nptl: Add backoff mechanism to spinlock loop +Content-type: text/plain; charset=UTF-8 + +When mutiple threads waiting for lock at the same time, once lock owner +releases the lock, waiters will see lock available and all try to lock, +which may cause an expensive CAS storm. + +Binary exponential backoff with random jitter is introduced. As try-lock +attempt increases, there is more likely that a larger number threads +compete for adaptive mutex lock, so increase wait time in exponential. +A random jitter is also added to avoid synchronous try-lock from other +threads. + +v2: Remove read-check before try-lock for performance. + +v3: +1. Restore read-check since it works well in some platform. +2. Make backoff arch dependent, and enable it for x86_64. +3. Limit max backoff to reduce latency in large critical section. + +v4: Fix strict-prototypes error in sysdeps/nptl/pthread_mutex_backoff.h + +v5: Commit log updated for regression in large critical section. + +Result of pthread-mutex-locks bench + +Test Platform: Xeon 8280L (2 socket, 112 CPUs in total) +First Row: thread number +First Col: critical section length +Values: backoff vs upstream, time based, low is better + +non-critical-length: 1 + 1 2 4 8 16 32 64 112 140 +0 0.99 0.58 0.52 0.49 0.43 0.44 0.46 0.52 0.54 +1 0.98 0.43 0.56 0.50 0.44 0.45 0.50 0.56 0.57 +2 0.99 0.41 0.57 0.51 0.45 0.47 0.48 0.60 0.61 +4 0.99 0.45 0.59 0.53 0.48 0.49 0.52 0.64 0.65 +8 1.00 0.66 0.71 0.63 0.56 0.59 0.66 0.72 0.71 +16 0.97 0.78 0.91 0.73 0.67 0.70 0.79 0.80 0.80 +32 0.95 1.17 0.98 0.87 0.82 0.86 0.89 0.90 0.90 +64 0.96 0.95 1.01 1.01 0.98 1.00 1.03 0.99 0.99 +128 0.99 1.01 1.01 1.17 1.08 1.12 1.02 0.97 1.02 + +non-critical-length: 32 + 1 2 4 8 16 32 64 112 140 +0 1.03 0.97 0.75 0.65 0.58 0.58 0.56 0.70 0.70 +1 0.94 0.95 0.76 0.65 0.58 0.58 0.61 0.71 0.72 +2 0.97 0.96 0.77 0.66 0.58 0.59 0.62 0.74 0.74 +4 0.99 0.96 0.78 0.66 0.60 0.61 0.66 0.76 0.77 +8 0.99 0.99 0.84 0.70 0.64 0.66 0.71 0.80 0.80 +16 0.98 0.97 0.95 0.76 0.70 0.73 0.81 0.85 0.84 +32 1.04 1.12 1.04 0.89 0.82 0.86 0.93 0.91 0.91 +64 0.99 1.15 1.07 1.00 0.99 1.01 1.05 0.99 0.99 +128 1.00 1.21 1.20 1.22 1.25 1.31 1.12 1.10 0.99 + +non-critical-length: 128 + 1 2 4 8 16 32 64 112 140 +0 1.02 1.00 0.99 0.67 0.61 0.61 0.61 0.74 0.73 +1 0.95 0.99 1.00 0.68 0.61 0.60 0.60 0.74 0.74 +2 1.00 1.04 1.00 0.68 0.59 0.61 0.65 0.76 0.76 +4 1.00 0.96 0.98 0.70 0.63 0.63 0.67 0.78 0.77 +8 1.01 1.02 0.89 0.73 0.65 0.67 0.71 0.81 0.80 +16 0.99 0.96 0.96 0.79 0.71 0.73 0.80 0.84 0.84 +32 0.99 0.95 1.05 0.89 0.84 0.85 0.94 0.92 0.91 +64 1.00 0.99 1.16 1.04 1.00 1.02 1.06 0.99 0.99 +128 1.00 1.06 0.98 1.14 1.39 1.26 1.08 1.02 0.98 + +There is regression in large critical section. But adaptive mutex is +aimed for "quick" locks. Small critical section is more common when +users choose to use adaptive pthread_mutex. + +Signed-off-by: Wangyang Guo +Reviewed-by: H.J. Lu + +Conflicts: + pthreadP.h + (had been moved) + nptl/pthread_mutex_lock.c + (max_adaptive_count renamed) + +--- + nptl/pthreadP.h | 1 + + nptl/pthread_mutex_lock.c | 16 +++++++-- + sysdeps/nptl/pthread_mutex_backoff.h | 35 ++++++++++++++++++ + sysdeps/x86_64/nptl/pthread_mutex_backoff.h | 39 +++++++++++++++++++++ + 4 files changed, 89 insertions(+), 2 deletions(-) + create mode 100644 sysdeps/nptl/pthread_mutex_backoff.h + create mode 100644 sysdeps/x86_64/nptl/pthread_mutex_backoff.h + +diff --git a/nptl/pthreadP.h b/nptl/pthreadP.h +index 7ddc166c..1550e3b6 100644 +--- a/nptl/pthreadP.h ++++ b/nptl/pthreadP.h +@@ -33,6 +33,7 @@ + #include + #include + #include ++#include + + + /* Atomic operations on TLS memory. */ +diff --git a/nptl/pthread_mutex_lock.c b/nptl/pthread_mutex_lock.c +index d96a9933..c7770fc9 100644 +--- a/nptl/pthread_mutex_lock.c ++++ b/nptl/pthread_mutex_lock.c +@@ -133,14 +133,26 @@ __pthread_mutex_lock (pthread_mutex_t *mutex) + int cnt = 0; + int max_cnt = MIN (MAX_ADAPTIVE_COUNT, + mutex->__data.__spins * 2 + 10); ++ int spin_count, exp_backoff = 1; ++ unsigned int jitter = get_jitter (); + do + { +- if (cnt++ >= max_cnt) ++ /* In each loop, spin count is exponential backoff plus ++ random jitter, random range is [0, exp_backoff-1]. */ ++ spin_count = exp_backoff + (jitter & (exp_backoff - 1)); ++ cnt += spin_count; ++ if (cnt >= max_cnt) + { ++ /* If cnt exceeds max spin count, just go to wait ++ queue. */ + LLL_MUTEX_LOCK (mutex); + break; + } +- atomic_spin_nop (); ++ do ++ atomic_spin_nop (); ++ while (--spin_count > 0); ++ /* Prepare for next loop. */ ++ exp_backoff = get_next_backoff (exp_backoff); + } + while (LLL_MUTEX_READ_LOCK (mutex) != 0 + || LLL_MUTEX_TRYLOCK (mutex) != 0); +diff --git a/sysdeps/nptl/pthread_mutex_backoff.h b/sysdeps/nptl/pthread_mutex_backoff.h +new file mode 100644 +index 00000000..5b26c22a +--- /dev/null ++++ b/sysdeps/nptl/pthread_mutex_backoff.h +@@ -0,0 +1,35 @@ ++/* Pthread mutex backoff configuration. ++ 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 _PTHREAD_MUTEX_BACKOFF_H ++#define _PTHREAD_MUTEX_BACKOFF_H 1 ++ ++static inline unsigned int ++get_jitter (void) ++{ ++ /* Arch dependent random jitter, return 0 disables random. */ ++ return 0; ++} ++ ++static inline int ++get_next_backoff (int backoff) ++{ ++ /* Next backoff, return 1 disables mutex backoff. */ ++ return 1; ++} ++ ++#endif +diff --git a/sysdeps/x86_64/nptl/pthread_mutex_backoff.h b/sysdeps/x86_64/nptl/pthread_mutex_backoff.h +new file mode 100644 +index 00000000..ec74c3d9 +--- /dev/null ++++ b/sysdeps/x86_64/nptl/pthread_mutex_backoff.h +@@ -0,0 +1,39 @@ ++/* Pthread mutex backoff configuration. ++ 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 _PTHREAD_MUTEX_BACKOFF_H ++#define _PTHREAD_MUTEX_BACKOFF_H 1 ++ ++#include ++ ++static inline unsigned int ++get_jitter (void) ++{ ++ return get_fast_jitter (); ++} ++ ++#define MAX_BACKOFF 16 ++ ++static inline int ++get_next_backoff (int backoff) ++{ ++ /* Binary expontial backoff. Limiting max backoff ++ can reduce latency in large critical section. */ ++ return (backoff < MAX_BACKOFF) ? backoff << 1 : backoff; ++} ++ ++#endif +-- +GitLab + diff --git a/SOURCES/glibc-RHEL-15696-108.patch b/SOURCES/glibc-RHEL-15696-108.patch new file mode 100644 index 0000000..17bf7d8 --- /dev/null +++ b/SOURCES/glibc-RHEL-15696-108.patch @@ -0,0 +1,55 @@ +From c6272098323153db373f2986c67786ea8c85f1cf Mon Sep 17 00:00:00 2001 +From: Noah Goldstein +Date: Tue, 15 Feb 2022 08:18:15 -0600 +Subject: [PATCH] x86: Fallback {str|wcs}cmp RTM in the ncmp overflow case [BZ + #28896] +Content-type: text/plain; charset=UTF-8 + +In the overflow fallback strncmp-avx2-rtm and wcsncmp-avx2-rtm would +call strcmp-avx2 and wcscmp-avx2 respectively. This would have +not checks around vzeroupper and would trigger spurious +aborts. This commit fixes that. + +test-strcmp, test-strncmp, test-wcscmp, and test-wcsncmp all pass on +AVX2 machines with and without RTM. + +Co-authored-by: H.J. Lu +--- + sysdeps/x86_64/multiarch/strcmp-avx2.S | 8 ++------ + 1 file changed, 2 insertions(+), 6 deletions(-) + +Conflicts: + sysdeps/x86_64/multiarch/strcmp-avx2.S + (split into two patches due to upstream bug differences) + +diff --git a/sysdeps/x86_64/multiarch/strcmp-avx2.S b/sysdeps/x86_64/multiarch/strcmp-avx2.S +index 28cc98b6..e267c6cb 100644 +--- a/sysdeps/x86_64/multiarch/strcmp-avx2.S ++++ b/sysdeps/x86_64/multiarch/strcmp-avx2.S +@@ -345,10 +345,10 @@ L(one_or_less): + movq %LOCALE_REG, %rdx + # endif + jb L(ret_zero) +-# ifdef USE_AS_WCSCMP + /* 'nbe' covers the case where length is negative (large + unsigned). */ +- jnbe __wcscmp_avx2 ++ jnbe OVERFLOW_STRCMP ++# ifdef USE_AS_WCSCMP + movl (%rdi), %edx + xorl %eax, %eax + cmpl (%rsi), %edx +@@ -357,10 +357,6 @@ L(one_or_less): + negl %eax + orl $1, %eax + # else +- /* 'nbe' covers the case where length is negative (large +- unsigned). */ +- +- jnbe __strcmp_avx2 + movzbl (%rdi), %eax + movzbl (%rsi), %ecx + TOLOWER_gpr (%rax, %eax) +-- +GitLab + diff --git a/SOURCES/glibc-RHEL-15696-109.patch b/SOURCES/glibc-RHEL-15696-109.patch new file mode 100644 index 0000000..8aaa314 --- /dev/null +++ b/SOURCES/glibc-RHEL-15696-109.patch @@ -0,0 +1,60 @@ +From 259a17cc98058d2576511201f85d28cb5d9de2a2 Mon Sep 17 00:00:00 2001 +From: Stefan Liebler +Date: Mon, 28 Jun 2021 13:01:07 +0200 +Subject: s390x: Update math: redirect roundeven function + +After recent commit +447954a206837b5f153869cfeeeab44631c3fac9 +"math: redirect roundeven function", building on +s390x fails with: +Error: symbol `__roundevenl' is already defined + +Similar to aarch64/riscv fix, this patch redirects target +specific functions for s390x: +commit 3213ed770cbc5821920d16caa93c85e92dd7b9f6 +"Update math: redirect roundeven function" + +diff --git a/sysdeps/s390/fpu/s_roundeven.c b/sysdeps/s390/fpu/s_roundeven.c +index 40b07e054b..0773adfed0 100644 +--- a/sysdeps/s390/fpu/s_roundeven.c ++++ b/sysdeps/s390/fpu/s_roundeven.c +@@ -18,6 +18,7 @@ + . */ + + #ifdef HAVE_S390_MIN_Z196_ZARCH_ASM_SUPPORT ++# define NO_MATH_REDIRECT + # include + # include + +@@ -31,7 +32,6 @@ __roundeven (double x) + __asm__ ("fidbra %0,4,%1,4" : "=f" (y) : "f" (x)); + return y; + } +-hidden_def (__roundeven) + libm_alias_double (__roundeven, roundeven) + + #else +diff --git a/sysdeps/s390/fpu/s_roundevenf.c b/sysdeps/s390/fpu/s_roundevenf.c +index d2fbf3d2b6..289785bc4a 100644 +--- a/sysdeps/s390/fpu/s_roundevenf.c ++++ b/sysdeps/s390/fpu/s_roundevenf.c +@@ -18,6 +18,7 @@ + . */ + + #ifdef HAVE_S390_MIN_Z196_ZARCH_ASM_SUPPORT ++# define NO_MATH_REDIRECT + # include + # include + +diff --git a/sysdeps/s390/fpu/s_roundevenl.c b/sysdeps/s390/fpu/s_roundevenl.c +index 29ab7a8616..94b6459ab4 100644 +--- a/sysdeps/s390/fpu/s_roundevenl.c ++++ b/sysdeps/s390/fpu/s_roundevenl.c +@@ -18,6 +18,7 @@ + . */ + + #ifdef HAVE_S390_MIN_Z196_ZARCH_ASM_SUPPORT ++# define NO_MATH_REDIRECT + # include + # include + # include diff --git a/SOURCES/glibc-RHEL-15696-11.patch b/SOURCES/glibc-RHEL-15696-11.patch new file mode 100644 index 0000000..54d7eff --- /dev/null +++ b/SOURCES/glibc-RHEL-15696-11.patch @@ -0,0 +1,74 @@ +From 1da50d4bda07f04135dca39f40e79fc9eabed1f8 Mon Sep 17 00:00:00 2001 +From: "H.J. Lu" +Date: Fri, 26 Feb 2021 05:36:59 -0800 +Subject: [PATCH] x86: Set Prefer_No_VZEROUPPER and add Prefer_AVX2_STRCMP +Content-type: text/plain; charset=UTF-8 + +1. Set Prefer_No_VZEROUPPER if RTM is usable to avoid RTM abort triggered +by VZEROUPPER inside a transactionally executing RTM region. +2. Since to compare 2 32-byte strings, 256-bit EVEX strcmp requires 2 +loads, 3 VPCMPs and 2 KORDs while AVX2 strcmp requires 1 load, 2 VPCMPEQs, +1 VPMINU and 1 VPMOVMSKB, AVX2 strcmp is faster than EVEX strcmp. Add +Prefer_AVX2_STRCMP to prefer AVX2 strcmp family functions. +--- + sysdeps/x86/cpu-features.c | 20 +++++++++++++++++-- + sysdeps/x86/cpu-tunables.c | 2 ++ + ...cpu-features-preferred_feature_index_1.def | 1 + + 3 files changed, 21 insertions(+), 2 deletions(-) + +diff --git a/sysdeps/x86/cpu-features.c b/sysdeps/x86/cpu-features.c +index 91042505..3610ee5c 100644 +--- a/sysdeps/x86/cpu-features.c ++++ b/sysdeps/x86/cpu-features.c +@@ -524,8 +524,24 @@ init_cpu_features (struct cpu_features *cpu_features) + cpu_features->preferred[index_arch_Prefer_No_VZEROUPPER] + |= bit_arch_Prefer_No_VZEROUPPER; + else +- cpu_features->preferred[index_arch_Prefer_No_AVX512] +- |= bit_arch_Prefer_No_AVX512; ++ { ++ cpu_features->preferred[index_arch_Prefer_No_AVX512] ++ |= bit_arch_Prefer_No_AVX512; ++ ++ /* Avoid RTM abort triggered by VZEROUPPER inside a ++ transactionally executing RTM region. */ ++ if (CPU_FEATURE_USABLE_P (cpu_features, RTM)) ++ cpu_features->preferred[index_arch_Prefer_No_VZEROUPPER] ++ |= bit_arch_Prefer_No_VZEROUPPER; ++ ++ /* Since to compare 2 32-byte strings, 256-bit EVEX strcmp ++ requires 2 loads, 3 VPCMPs and 2 KORDs while AVX2 strcmp ++ requires 1 load, 2 VPCMPEQs, 1 VPMINU and 1 VPMOVMSKB, ++ AVX2 strcmp is faster than EVEX strcmp. */ ++ if (CPU_FEATURE_USABLE_P (cpu_features, AVX2)) ++ cpu_features->preferred[index_arch_Prefer_AVX2_STRCMP] ++ |= bit_arch_Prefer_AVX2_STRCMP; ++ } + } + /* This spells out "AuthenticAMD". */ + else if (ebx == 0x68747541 && ecx == 0x444d4163 && edx == 0x69746e65) +diff --git a/sysdeps/x86/cpu-tunables.c b/sysdeps/x86/cpu-tunables.c +index 3173b2b9..73adbaba 100644 +--- a/sysdeps/x86/cpu-tunables.c ++++ b/sysdeps/x86/cpu-tunables.c +@@ -239,6 +239,8 @@ TUNABLE_CALLBACK (set_hwcaps) (tunable_val_t *valp) + CHECK_GLIBC_IFUNC_PREFERRED_BOTH (n, cpu_features, + Fast_Copy_Backward, + disable, 18); ++ CHECK_GLIBC_IFUNC_PREFERRED_NEED_BOTH ++ (n, cpu_features, Prefer_AVX2_STRCMP, AVX2, disable, 18); + } + break; + case 19: +diff --git a/sysdeps/x86/include/cpu-features-preferred_feature_index_1.def b/sysdeps/x86/include/cpu-features-preferred_feature_index_1.def +index 17a5cc42..4ca70b40 100644 +--- a/sysdeps/x86/include/cpu-features-preferred_feature_index_1.def ++++ b/sysdeps/x86/include/cpu-features-preferred_feature_index_1.def +@@ -32,3 +32,4 @@ BIT (Prefer_ERMS) + BIT (Prefer_FSRM) + BIT (Prefer_No_AVX512) + BIT (MathVec_Prefer_No_AVX512) ++BIT (Prefer_AVX2_STRCMP) +-- +GitLab + diff --git a/SOURCES/glibc-RHEL-15696-110.patch b/SOURCES/glibc-RHEL-15696-110.patch new file mode 100644 index 0000000..c499761 --- /dev/null +++ b/SOURCES/glibc-RHEL-15696-110.patch @@ -0,0 +1,26 @@ +From 3213ed770cbc5821920d16caa93c85e92dd7b9f6 Mon Sep 17 00:00:00 2001 +From: "H.J. Lu" +Date: Wed, 23 Jun 2021 13:29:41 -0700 +Subject: Update math: redirect roundeven function + +Redirect target specific roundeven functions for aarch64, ldbl-128ibm +and riscv. + +Conflicts: + sysdeps/aarch64/* + (not needed) + sysdeps/riscv/* + (not supported) + +diff --git a/sysdeps/ieee754/ldbl-128ibm/s_roundevenl.c b/sysdeps/ieee754/ldbl-128ibm/s_roundevenl.c +index 6701970f4a..90eecf496b 100644 +--- a/sysdeps/ieee754/ldbl-128ibm/s_roundevenl.c ++++ b/sysdeps/ieee754/ldbl-128ibm/s_roundevenl.c +@@ -17,6 +17,7 @@ + License along with the GNU C Library; if not, see + . */ + ++#define NO_MATH_REDIRECT + #include + #include + diff --git a/SOURCES/glibc-RHEL-15696-12.patch b/SOURCES/glibc-RHEL-15696-12.patch new file mode 100644 index 0000000..85b568e --- /dev/null +++ b/SOURCES/glibc-RHEL-15696-12.patch @@ -0,0 +1,3410 @@ +From 1fd8c163a83d96ace1ff78fa6bac7aee084f6f77 Mon Sep 17 00:00:00 2001 +From: "H.J. Lu" +Date: Fri, 5 Mar 2021 06:24:52 -0800 +Subject: [PATCH] x86-64: Add ifunc-avx2.h functions with 256-bit EVEX +Content-type: text/plain; charset=UTF-8 + +Update ifunc-avx2.h, strchr.c, strcmp.c, strncmp.c and wcsnlen.c to +select the function optimized with 256-bit EVEX instructions using +YMM16-YMM31 registers to avoid RTM abort with usable AVX512VL, AVX512BW +and BMI2 since VZEROUPPER isn't needed at function exit. + +For strcmp/strncmp, prefer AVX2 strcmp/strncmp if Prefer_AVX2_STRCMP +is set. +--- + sysdeps/x86_64/multiarch/Makefile | 21 +- + sysdeps/x86_64/multiarch/ifunc-avx2.h | 14 +- + sysdeps/x86_64/multiarch/ifunc-impl-list.c | 81 ++ + sysdeps/x86_64/multiarch/memchr-evex.S | 381 +++++++ + sysdeps/x86_64/multiarch/memrchr-evex.S | 337 +++++++ + sysdeps/x86_64/multiarch/rawmemchr-evex.S | 4 + + sysdeps/x86_64/multiarch/strchr-evex.S | 335 +++++++ + sysdeps/x86_64/multiarch/strchr.c | 14 +- + sysdeps/x86_64/multiarch/strchrnul-evex.S | 3 + + sysdeps/x86_64/multiarch/strcmp-evex.S | 1043 ++++++++++++++++++++ + sysdeps/x86_64/multiarch/strcmp.c | 15 +- + sysdeps/x86_64/multiarch/strlen-evex.S | 436 ++++++++ + sysdeps/x86_64/multiarch/strncmp-evex.S | 3 + + sysdeps/x86_64/multiarch/strncmp.c | 15 +- + sysdeps/x86_64/multiarch/strnlen-evex.S | 4 + + sysdeps/x86_64/multiarch/strrchr-evex.S | 265 +++++ + sysdeps/x86_64/multiarch/wcschr-evex.S | 3 + + sysdeps/x86_64/multiarch/wcscmp-evex.S | 4 + + sysdeps/x86_64/multiarch/wcslen-evex.S | 4 + + sysdeps/x86_64/multiarch/wcsncmp-evex.S | 5 + + sysdeps/x86_64/multiarch/wcsnlen-evex.S | 5 + + sysdeps/x86_64/multiarch/wcsnlen.c | 14 +- + sysdeps/x86_64/multiarch/wcsrchr-evex.S | 3 + + sysdeps/x86_64/multiarch/wmemchr-evex.S | 4 + + 24 files changed, 2996 insertions(+), 17 deletions(-) + create mode 100644 sysdeps/x86_64/multiarch/memchr-evex.S + create mode 100644 sysdeps/x86_64/multiarch/memrchr-evex.S + create mode 100644 sysdeps/x86_64/multiarch/rawmemchr-evex.S + create mode 100644 sysdeps/x86_64/multiarch/strchr-evex.S + create mode 100644 sysdeps/x86_64/multiarch/strchrnul-evex.S + create mode 100644 sysdeps/x86_64/multiarch/strcmp-evex.S + create mode 100644 sysdeps/x86_64/multiarch/strlen-evex.S + create mode 100644 sysdeps/x86_64/multiarch/strncmp-evex.S + create mode 100644 sysdeps/x86_64/multiarch/strnlen-evex.S + create mode 100644 sysdeps/x86_64/multiarch/strrchr-evex.S + create mode 100644 sysdeps/x86_64/multiarch/wcschr-evex.S + create mode 100644 sysdeps/x86_64/multiarch/wcscmp-evex.S + create mode 100644 sysdeps/x86_64/multiarch/wcslen-evex.S + create mode 100644 sysdeps/x86_64/multiarch/wcsncmp-evex.S + create mode 100644 sysdeps/x86_64/multiarch/wcsnlen-evex.S + create mode 100644 sysdeps/x86_64/multiarch/wcsrchr-evex.S + create mode 100644 sysdeps/x86_64/multiarch/wmemchr-evex.S + +Conflicts: + sysdeps/x86_64/multiarch/wcsnlen.c + (account for missing upstream macros) + +diff --git a/sysdeps/x86_64/multiarch/Makefile b/sysdeps/x86_64/multiarch/Makefile +index 9477538a..5ce85882 100644 +--- a/sysdeps/x86_64/multiarch/Makefile ++++ b/sysdeps/x86_64/multiarch/Makefile +@@ -39,7 +39,17 @@ sysdep_routines += strncat-c stpncpy-c strncpy-c \ + memmove-avx512-unaligned-erms \ + memset-sse2-unaligned-erms \ + memset-avx2-unaligned-erms \ +- memset-avx512-unaligned-erms ++ memset-avx512-unaligned-erms \ ++ memchr-evex \ ++ memrchr-evex \ ++ rawmemchr-evex \ ++ strchr-evex \ ++ strchrnul-evex \ ++ strcmp-evex \ ++ strlen-evex \ ++ strncmp-evex \ ++ strnlen-evex \ ++ strrchr-evex + CFLAGS-varshift.c += -msse4 + CFLAGS-strcspn-c.c += -msse4 + CFLAGS-strpbrk-c.c += -msse4 +@@ -56,7 +66,14 @@ sysdep_routines += wmemcmp-sse4 wmemcmp-ssse3 wmemcmp-c \ + wcschr-sse2 wcschr-avx2 \ + wcsrchr-sse2 wcsrchr-avx2 \ + wcsnlen-sse4_1 wcsnlen-c \ +- wcslen-sse2 wcslen-avx2 wcsnlen-avx2 ++ wcslen-sse2 wcslen-avx2 wcsnlen-avx2 \ ++ wcschr-evex \ ++ wcscmp-evex \ ++ wcslen-evex \ ++ wcsncmp-evex \ ++ wcsnlen-evex \ ++ wcsrchr-evex \ ++ wmemchr-evex + endif + + ifeq ($(subdir),debug) +diff --git a/sysdeps/x86_64/multiarch/ifunc-avx2.h b/sysdeps/x86_64/multiarch/ifunc-avx2.h +index 5c88640a..7081b0c9 100644 +--- a/sysdeps/x86_64/multiarch/ifunc-avx2.h ++++ b/sysdeps/x86_64/multiarch/ifunc-avx2.h +@@ -21,16 +21,24 @@ + + extern __typeof (REDIRECT_NAME) OPTIMIZE (sse2) attribute_hidden; + extern __typeof (REDIRECT_NAME) OPTIMIZE (avx2) attribute_hidden; ++extern __typeof (REDIRECT_NAME) OPTIMIZE (evex) attribute_hidden; + + static inline void * + IFUNC_SELECTOR (void) + { + const struct cpu_features* cpu_features = __get_cpu_features (); + +- if (!CPU_FEATURES_ARCH_P (cpu_features, Prefer_No_VZEROUPPER) +- && CPU_FEATURE_USABLE_P (cpu_features, AVX2) ++ if (CPU_FEATURE_USABLE_P (cpu_features, AVX2) + && CPU_FEATURES_ARCH_P (cpu_features, AVX_Fast_Unaligned_Load)) +- return OPTIMIZE (avx2); ++ { ++ if (CPU_FEATURE_USABLE_P (cpu_features, AVX512VL) ++ && CPU_FEATURE_USABLE_P (cpu_features, AVX512BW) ++ && CPU_FEATURE_USABLE_P (cpu_features, BMI2)) ++ return OPTIMIZE (evex); ++ ++ if (!CPU_FEATURES_ARCH_P (cpu_features, Prefer_No_VZEROUPPER)) ++ return OPTIMIZE (avx2); ++ } + + return OPTIMIZE (sse2); + } +diff --git a/sysdeps/x86_64/multiarch/ifunc-impl-list.c b/sysdeps/x86_64/multiarch/ifunc-impl-list.c +index fe13505c..bd7d9f19 100644 +--- a/sysdeps/x86_64/multiarch/ifunc-impl-list.c ++++ b/sysdeps/x86_64/multiarch/ifunc-impl-list.c +@@ -43,6 +43,11 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + IFUNC_IMPL_ADD (array, i, memchr, + CPU_FEATURE_USABLE (AVX2), + __memchr_avx2) ++ IFUNC_IMPL_ADD (array, i, memchr, ++ (CPU_FEATURE_USABLE (AVX512VL) ++ && CPU_FEATURE_USABLE (AVX512BW) ++ && CPU_FEATURE_USABLE (BMI2)), ++ __memchr_evex) + IFUNC_IMPL_ADD (array, i, memchr, 1, __memchr_sse2)) + + /* Support sysdeps/x86_64/multiarch/memcmp.c. */ +@@ -121,6 +126,11 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + IFUNC_IMPL_ADD (array, i, memrchr, + CPU_FEATURE_USABLE (AVX2), + __memrchr_avx2) ++ IFUNC_IMPL_ADD (array, i, memrchr, ++ (CPU_FEATURE_USABLE (AVX512VL) ++ && CPU_FEATURE_USABLE (AVX512BW)), ++ __memrchr_evex) ++ + IFUNC_IMPL_ADD (array, i, memrchr, 1, __memrchr_sse2)) + + #ifdef SHARED +@@ -179,6 +189,11 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + IFUNC_IMPL_ADD (array, i, rawmemchr, + CPU_FEATURE_USABLE (AVX2), + __rawmemchr_avx2) ++ IFUNC_IMPL_ADD (array, i, rawmemchr, ++ (CPU_FEATURE_USABLE (AVX512VL) ++ && CPU_FEATURE_USABLE (AVX512BW) ++ && CPU_FEATURE_USABLE (BMI2)), ++ __rawmemchr_evex) + IFUNC_IMPL_ADD (array, i, rawmemchr, 1, __rawmemchr_sse2)) + + /* Support sysdeps/x86_64/multiarch/strlen.c. */ +@@ -186,6 +201,10 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + IFUNC_IMPL_ADD (array, i, strlen, + CPU_FEATURE_USABLE (AVX2), + __strlen_avx2) ++ IFUNC_IMPL_ADD (array, i, strlen, ++ (CPU_FEATURE_USABLE (AVX512VL) ++ && CPU_FEATURE_USABLE (AVX512BW)), ++ __strlen_evex) + IFUNC_IMPL_ADD (array, i, strlen, 1, __strlen_sse2)) + + /* Support sysdeps/x86_64/multiarch/strnlen.c. */ +@@ -193,6 +212,10 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + IFUNC_IMPL_ADD (array, i, strnlen, + CPU_FEATURE_USABLE (AVX2), + __strnlen_avx2) ++ IFUNC_IMPL_ADD (array, i, strnlen, ++ (CPU_FEATURE_USABLE (AVX512VL) ++ && CPU_FEATURE_USABLE (AVX512BW)), ++ __strnlen_evex) + IFUNC_IMPL_ADD (array, i, strnlen, 1, __strnlen_sse2)) + + /* Support sysdeps/x86_64/multiarch/stpncpy.c. */ +@@ -255,6 +278,11 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + IFUNC_IMPL_ADD (array, i, strchr, + CPU_FEATURE_USABLE (AVX2), + __strchr_avx2) ++ IFUNC_IMPL_ADD (array, i, strchr, ++ (CPU_FEATURE_USABLE (AVX512VL) ++ && CPU_FEATURE_USABLE (AVX512BW) ++ && CPU_FEATURE_USABLE (BMI2)), ++ __strchr_evex) + IFUNC_IMPL_ADD (array, i, strchr, 1, __strchr_sse2_no_bsf) + IFUNC_IMPL_ADD (array, i, strchr, 1, __strchr_sse2)) + +@@ -263,6 +291,11 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + IFUNC_IMPL_ADD (array, i, strchrnul, + CPU_FEATURE_USABLE (AVX2), + __strchrnul_avx2) ++ IFUNC_IMPL_ADD (array, i, strchrnul, ++ (CPU_FEATURE_USABLE (AVX512VL) ++ && CPU_FEATURE_USABLE (AVX512BW) ++ && CPU_FEATURE_USABLE (BMI2)), ++ __strchrnul_evex) + IFUNC_IMPL_ADD (array, i, strchrnul, 1, __strchrnul_sse2)) + + /* Support sysdeps/x86_64/multiarch/strrchr.c. */ +@@ -270,6 +303,10 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + IFUNC_IMPL_ADD (array, i, strrchr, + CPU_FEATURE_USABLE (AVX2), + __strrchr_avx2) ++ IFUNC_IMPL_ADD (array, i, strrchr, ++ (CPU_FEATURE_USABLE (AVX512VL) ++ && CPU_FEATURE_USABLE (AVX512BW)), ++ __strrchr_evex) + IFUNC_IMPL_ADD (array, i, strrchr, 1, __strrchr_sse2)) + + /* Support sysdeps/x86_64/multiarch/strcmp.c. */ +@@ -277,6 +314,11 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + IFUNC_IMPL_ADD (array, i, strcmp, + CPU_FEATURE_USABLE (AVX2), + __strcmp_avx2) ++ IFUNC_IMPL_ADD (array, i, strcmp, ++ (CPU_FEATURE_USABLE (AVX512VL) ++ && CPU_FEATURE_USABLE (AVX512BW) ++ && CPU_FEATURE_USABLE (BMI2)), ++ __strcmp_evex) + IFUNC_IMPL_ADD (array, i, strcmp, CPU_FEATURE_USABLE (SSE4_2), + __strcmp_sse42) + IFUNC_IMPL_ADD (array, i, strcmp, CPU_FEATURE_USABLE (SSSE3), +@@ -370,6 +412,11 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + IFUNC_IMPL_ADD (array, i, wcschr, + CPU_FEATURE_USABLE (AVX2), + __wcschr_avx2) ++ IFUNC_IMPL_ADD (array, i, wcschr, ++ (CPU_FEATURE_USABLE (AVX512VL) ++ && CPU_FEATURE_USABLE (AVX512BW) ++ && CPU_FEATURE_USABLE (BMI2)), ++ __wcschr_evex) + IFUNC_IMPL_ADD (array, i, wcschr, 1, __wcschr_sse2)) + + /* Support sysdeps/x86_64/multiarch/wcsrchr.c. */ +@@ -377,6 +424,11 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + IFUNC_IMPL_ADD (array, i, wcsrchr, + CPU_FEATURE_USABLE (AVX2), + __wcsrchr_avx2) ++ IFUNC_IMPL_ADD (array, i, wcsrchr, ++ (CPU_FEATURE_USABLE (AVX512VL) ++ && CPU_FEATURE_USABLE (AVX512BW) ++ && CPU_FEATURE_USABLE (BMI2)), ++ __wcsrchr_evex) + IFUNC_IMPL_ADD (array, i, wcsrchr, 1, __wcsrchr_sse2)) + + /* Support sysdeps/x86_64/multiarch/wcscmp.c. */ +@@ -384,6 +436,11 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + IFUNC_IMPL_ADD (array, i, wcscmp, + CPU_FEATURE_USABLE (AVX2), + __wcscmp_avx2) ++ IFUNC_IMPL_ADD (array, i, wcscmp, ++ (CPU_FEATURE_USABLE (AVX512VL) ++ && CPU_FEATURE_USABLE (AVX512BW) ++ && CPU_FEATURE_USABLE (BMI2)), ++ __wcscmp_evex) + IFUNC_IMPL_ADD (array, i, wcscmp, 1, __wcscmp_sse2)) + + /* Support sysdeps/x86_64/multiarch/wcsncmp.c. */ +@@ -391,6 +448,11 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + IFUNC_IMPL_ADD (array, i, wcsncmp, + CPU_FEATURE_USABLE (AVX2), + __wcsncmp_avx2) ++ IFUNC_IMPL_ADD (array, i, wcsncmp, ++ (CPU_FEATURE_USABLE (AVX512VL) ++ && CPU_FEATURE_USABLE (AVX512BW) ++ && CPU_FEATURE_USABLE (BMI2)), ++ __wcsncmp_evex) + IFUNC_IMPL_ADD (array, i, wcsncmp, 1, __wcsncmp_sse2)) + + /* Support sysdeps/x86_64/multiarch/wcscpy.c. */ +@@ -404,6 +466,11 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + IFUNC_IMPL_ADD (array, i, wcslen, + CPU_FEATURE_USABLE (AVX2), + __wcslen_avx2) ++ IFUNC_IMPL_ADD (array, i, wcslen, ++ (CPU_FEATURE_USABLE (AVX512VL) ++ && CPU_FEATURE_USABLE (AVX512BW) ++ && CPU_FEATURE_USABLE (BMI2)), ++ __wcslen_evex) + IFUNC_IMPL_ADD (array, i, wcslen, 1, __wcslen_sse2)) + + /* Support sysdeps/x86_64/multiarch/wcsnlen.c. */ +@@ -411,6 +478,11 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + IFUNC_IMPL_ADD (array, i, wcsnlen, + CPU_FEATURE_USABLE (AVX2), + __wcsnlen_avx2) ++ IFUNC_IMPL_ADD (array, i, wcsnlen, ++ (CPU_FEATURE_USABLE (AVX512VL) ++ && CPU_FEATURE_USABLE (AVX512BW) ++ && CPU_FEATURE_USABLE (BMI2)), ++ __wcsnlen_evex) + IFUNC_IMPL_ADD (array, i, wcsnlen, + CPU_FEATURE_USABLE (SSE4_1), + __wcsnlen_sse4_1) +@@ -421,6 +493,11 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + IFUNC_IMPL_ADD (array, i, wmemchr, + CPU_FEATURE_USABLE (AVX2), + __wmemchr_avx2) ++ IFUNC_IMPL_ADD (array, i, wmemchr, ++ (CPU_FEATURE_USABLE (AVX512VL) ++ && CPU_FEATURE_USABLE (AVX512BW) ++ && CPU_FEATURE_USABLE (BMI2)), ++ __wmemchr_evex) + IFUNC_IMPL_ADD (array, i, wmemchr, 1, __wmemchr_sse2)) + + /* Support sysdeps/x86_64/multiarch/wmemcmp.c. */ +@@ -568,6 +645,10 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + IFUNC_IMPL_ADD (array, i, strncmp, + CPU_FEATURE_USABLE (AVX2), + __strncmp_avx2) ++ IFUNC_IMPL_ADD (array, i, strncmp, ++ (CPU_FEATURE_USABLE (AVX512VL) ++ && CPU_FEATURE_USABLE (AVX512BW)), ++ __strncmp_evex) + IFUNC_IMPL_ADD (array, i, strncmp, CPU_FEATURE_USABLE (SSE4_2), + __strncmp_sse42) + IFUNC_IMPL_ADD (array, i, strncmp, CPU_FEATURE_USABLE (SSSE3), +diff --git a/sysdeps/x86_64/multiarch/memchr-evex.S b/sysdeps/x86_64/multiarch/memchr-evex.S +new file mode 100644 +index 00000000..6dd5d67b +--- /dev/null ++++ b/sysdeps/x86_64/multiarch/memchr-evex.S +@@ -0,0 +1,381 @@ ++/* memchr/wmemchr optimized with 256-bit EVEX instructions. ++ 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 ++ . */ ++ ++#if IS_IN (libc) ++ ++# include ++ ++# ifndef MEMCHR ++# define MEMCHR __memchr_evex ++# endif ++ ++# ifdef USE_AS_WMEMCHR ++# define VPBROADCAST vpbroadcastd ++# define VPCMP vpcmpd ++# define SHIFT_REG r8d ++# else ++# define VPBROADCAST vpbroadcastb ++# define VPCMP vpcmpb ++# define SHIFT_REG ecx ++# endif ++ ++# define XMMMATCH xmm16 ++# define YMMMATCH ymm16 ++# define YMM1 ymm17 ++# define YMM2 ymm18 ++# define YMM3 ymm19 ++# define YMM4 ymm20 ++# define YMM5 ymm21 ++# define YMM6 ymm22 ++ ++# define VEC_SIZE 32 ++ ++ .section .text.evex,"ax",@progbits ++ENTRY (MEMCHR) ++# ifndef USE_AS_RAWMEMCHR ++ /* Check for zero length. */ ++ test %RDX_LP, %RDX_LP ++ jz L(zero) ++# endif ++ movl %edi, %ecx ++# ifdef USE_AS_WMEMCHR ++ shl $2, %RDX_LP ++# else ++# ifdef __ILP32__ ++ /* Clear the upper 32 bits. */ ++ movl %edx, %edx ++# endif ++# endif ++ /* Broadcast CHAR to YMMMATCH. */ ++ VPBROADCAST %esi, %YMMMATCH ++ /* Check if we may cross page boundary with one vector load. */ ++ andl $(2 * VEC_SIZE - 1), %ecx ++ cmpl $VEC_SIZE, %ecx ++ ja L(cros_page_boundary) ++ ++ /* Check the first VEC_SIZE bytes. */ ++ VPCMP $0, (%rdi), %YMMMATCH, %k1 ++ kmovd %k1, %eax ++ testl %eax, %eax ++ ++# ifndef USE_AS_RAWMEMCHR ++ jnz L(first_vec_x0_check) ++ /* Adjust length and check the end of data. */ ++ subq $VEC_SIZE, %rdx ++ jbe L(zero) ++# else ++ jnz L(first_vec_x0) ++# endif ++ ++ /* Align data for aligned loads in the loop. */ ++ addq $VEC_SIZE, %rdi ++ andl $(VEC_SIZE - 1), %ecx ++ andq $-VEC_SIZE, %rdi ++ ++# ifndef USE_AS_RAWMEMCHR ++ /* Adjust length. */ ++ addq %rcx, %rdx ++ ++ subq $(VEC_SIZE * 4), %rdx ++ jbe L(last_4x_vec_or_less) ++# endif ++ jmp L(more_4x_vec) ++ ++ .p2align 4 ++L(cros_page_boundary): ++ andl $(VEC_SIZE - 1), %ecx ++# ifdef USE_AS_WMEMCHR ++ /* NB: Divide shift count by 4 since each bit in K1 represent 4 ++ bytes. */ ++ movl %ecx, %SHIFT_REG ++ sarl $2, %SHIFT_REG ++# endif ++ andq $-VEC_SIZE, %rdi ++ VPCMP $0, (%rdi), %YMMMATCH, %k1 ++ kmovd %k1, %eax ++ /* Remove the leading bytes. */ ++ sarxl %SHIFT_REG, %eax, %eax ++ testl %eax, %eax ++ jz L(aligned_more) ++ tzcntl %eax, %eax ++# ifdef USE_AS_WMEMCHR ++ /* NB: Multiply wchar_t count by 4 to get the number of bytes. */ ++ sall $2, %eax ++# endif ++# ifndef USE_AS_RAWMEMCHR ++ /* Check the end of data. */ ++ cmpq %rax, %rdx ++ jbe L(zero) ++# endif ++ addq %rdi, %rax ++ addq %rcx, %rax ++ ret ++ ++ .p2align 4 ++L(aligned_more): ++# ifndef USE_AS_RAWMEMCHR ++ /* Calculate "rdx + rcx - VEC_SIZE" with "rdx - (VEC_SIZE - rcx)" ++ instead of "(rdx + rcx) - VEC_SIZE" to void possible addition ++ overflow. */ ++ negq %rcx ++ addq $VEC_SIZE, %rcx ++ ++ /* Check the end of data. */ ++ subq %rcx, %rdx ++ jbe L(zero) ++# endif ++ ++ addq $VEC_SIZE, %rdi ++ ++# ifndef USE_AS_RAWMEMCHR ++ subq $(VEC_SIZE * 4), %rdx ++ jbe L(last_4x_vec_or_less) ++# endif ++ ++L(more_4x_vec): ++ /* Check the first 4 * VEC_SIZE. Only one VEC_SIZE at a time ++ since data is only aligned to VEC_SIZE. */ ++ VPCMP $0, (%rdi), %YMMMATCH, %k1 ++ kmovd %k1, %eax ++ testl %eax, %eax ++ jnz L(first_vec_x0) ++ ++ VPCMP $0, VEC_SIZE(%rdi), %YMMMATCH, %k1 ++ kmovd %k1, %eax ++ testl %eax, %eax ++ jnz L(first_vec_x1) ++ ++ VPCMP $0, (VEC_SIZE * 2)(%rdi), %YMMMATCH, %k1 ++ kmovd %k1, %eax ++ testl %eax, %eax ++ jnz L(first_vec_x2) ++ ++ VPCMP $0, (VEC_SIZE * 3)(%rdi), %YMMMATCH, %k1 ++ kmovd %k1, %eax ++ testl %eax, %eax ++ jnz L(first_vec_x3) ++ ++ addq $(VEC_SIZE * 4), %rdi ++ ++# ifndef USE_AS_RAWMEMCHR ++ subq $(VEC_SIZE * 4), %rdx ++ jbe L(last_4x_vec_or_less) ++# endif ++ ++ /* Align data to 4 * VEC_SIZE. */ ++ movq %rdi, %rcx ++ andl $(4 * VEC_SIZE - 1), %ecx ++ andq $-(4 * VEC_SIZE), %rdi ++ ++# ifndef USE_AS_RAWMEMCHR ++ /* Adjust length. */ ++ addq %rcx, %rdx ++# endif ++ ++ .p2align 4 ++L(loop_4x_vec): ++ /* Compare 4 * VEC at a time forward. */ ++ VPCMP $0, (%rdi), %YMMMATCH, %k1 ++ VPCMP $0, VEC_SIZE(%rdi), %YMMMATCH, %k2 ++ kord %k1, %k2, %k5 ++ VPCMP $0, (VEC_SIZE * 2)(%rdi), %YMMMATCH, %k3 ++ VPCMP $0, (VEC_SIZE * 3)(%rdi), %YMMMATCH, %k4 ++ ++ kord %k3, %k4, %k6 ++ kortestd %k5, %k6 ++ jnz L(4x_vec_end) ++ ++ addq $(VEC_SIZE * 4), %rdi ++ ++# ifdef USE_AS_RAWMEMCHR ++ jmp L(loop_4x_vec) ++# else ++ subq $(VEC_SIZE * 4), %rdx ++ ja L(loop_4x_vec) ++ ++L(last_4x_vec_or_less): ++ /* Less than 4 * VEC and aligned to VEC_SIZE. */ ++ addl $(VEC_SIZE * 2), %edx ++ jle L(last_2x_vec) ++ ++ VPCMP $0, (%rdi), %YMMMATCH, %k1 ++ kmovd %k1, %eax ++ testl %eax, %eax ++ jnz L(first_vec_x0) ++ ++ VPCMP $0, VEC_SIZE(%rdi), %YMMMATCH, %k1 ++ kmovd %k1, %eax ++ testl %eax, %eax ++ jnz L(first_vec_x1) ++ ++ VPCMP $0, (VEC_SIZE * 2)(%rdi), %YMMMATCH, %k1 ++ kmovd %k1, %eax ++ testl %eax, %eax ++ ++ jnz L(first_vec_x2_check) ++ subl $VEC_SIZE, %edx ++ jle L(zero) ++ ++ VPCMP $0, (VEC_SIZE * 3)(%rdi), %YMMMATCH, %k1 ++ kmovd %k1, %eax ++ testl %eax, %eax ++ ++ jnz L(first_vec_x3_check) ++ xorl %eax, %eax ++ ret ++ ++ .p2align 4 ++L(last_2x_vec): ++ addl $(VEC_SIZE * 2), %edx ++ VPCMP $0, (%rdi), %YMMMATCH, %k1 ++ kmovd %k1, %eax ++ testl %eax, %eax ++ ++ jnz L(first_vec_x0_check) ++ subl $VEC_SIZE, %edx ++ jle L(zero) ++ ++ VPCMP $0, VEC_SIZE(%rdi), %YMMMATCH, %k1 ++ kmovd %k1, %eax ++ testl %eax, %eax ++ jnz L(first_vec_x1_check) ++ xorl %eax, %eax ++ ret ++ ++ .p2align 4 ++L(first_vec_x0_check): ++ tzcntl %eax, %eax ++# ifdef USE_AS_WMEMCHR ++ /* NB: Multiply wchar_t count by 4 to get the number of bytes. */ ++ sall $2, %eax ++# endif ++ /* Check the end of data. */ ++ cmpq %rax, %rdx ++ jbe L(zero) ++ addq %rdi, %rax ++ ret ++ ++ .p2align 4 ++L(first_vec_x1_check): ++ tzcntl %eax, %eax ++# ifdef USE_AS_WMEMCHR ++ /* NB: Multiply wchar_t count by 4 to get the number of bytes. */ ++ sall $2, %eax ++# endif ++ /* Check the end of data. */ ++ cmpq %rax, %rdx ++ jbe L(zero) ++ addq $VEC_SIZE, %rax ++ addq %rdi, %rax ++ ret ++ ++ .p2align 4 ++L(first_vec_x2_check): ++ tzcntl %eax, %eax ++# ifdef USE_AS_WMEMCHR ++ /* NB: Multiply wchar_t count by 4 to get the number of bytes. */ ++ sall $2, %eax ++# endif ++ /* Check the end of data. */ ++ cmpq %rax, %rdx ++ jbe L(zero) ++ addq $(VEC_SIZE * 2), %rax ++ addq %rdi, %rax ++ ret ++ ++ .p2align 4 ++L(first_vec_x3_check): ++ tzcntl %eax, %eax ++# ifdef USE_AS_WMEMCHR ++ /* NB: Multiply wchar_t count by 4 to get the number of bytes. */ ++ sall $2, %eax ++# endif ++ /* Check the end of data. */ ++ cmpq %rax, %rdx ++ jbe L(zero) ++ addq $(VEC_SIZE * 3), %rax ++ addq %rdi, %rax ++ ret ++ ++ .p2align 4 ++L(zero): ++ xorl %eax, %eax ++ ret ++# endif ++ ++ .p2align 4 ++L(first_vec_x0): ++ tzcntl %eax, %eax ++# ifdef USE_AS_WMEMCHR ++ /* NB: Multiply wchar_t count by 4 to get the number of bytes. */ ++ leaq (%rdi, %rax, 4), %rax ++# else ++ addq %rdi, %rax ++# endif ++ ret ++ ++ .p2align 4 ++L(first_vec_x1): ++ tzcntl %eax, %eax ++# ifdef USE_AS_WMEMCHR ++ /* NB: Multiply wchar_t count by 4 to get the number of bytes. */ ++ leaq VEC_SIZE(%rdi, %rax, 4), %rax ++# else ++ addq $VEC_SIZE, %rax ++ addq %rdi, %rax ++# endif ++ ret ++ ++ .p2align 4 ++L(first_vec_x2): ++ tzcntl %eax, %eax ++# ifdef USE_AS_WMEMCHR ++ /* NB: Multiply wchar_t count by 4 to get the number of bytes. */ ++ leaq (VEC_SIZE * 2)(%rdi, %rax, 4), %rax ++# else ++ addq $(VEC_SIZE * 2), %rax ++ addq %rdi, %rax ++# endif ++ ret ++ ++ .p2align 4 ++L(4x_vec_end): ++ kmovd %k1, %eax ++ testl %eax, %eax ++ jnz L(first_vec_x0) ++ kmovd %k2, %eax ++ testl %eax, %eax ++ jnz L(first_vec_x1) ++ kmovd %k3, %eax ++ testl %eax, %eax ++ jnz L(first_vec_x2) ++ kmovd %k4, %eax ++ testl %eax, %eax ++L(first_vec_x3): ++ tzcntl %eax, %eax ++# ifdef USE_AS_WMEMCHR ++ /* NB: Multiply wchar_t count by 4 to get the number of bytes. */ ++ leaq (VEC_SIZE * 3)(%rdi, %rax, 4), %rax ++# else ++ addq $(VEC_SIZE * 3), %rax ++ addq %rdi, %rax ++# endif ++ ret ++ ++END (MEMCHR) ++#endif +diff --git a/sysdeps/x86_64/multiarch/memrchr-evex.S b/sysdeps/x86_64/multiarch/memrchr-evex.S +new file mode 100644 +index 00000000..16bf8e02 +--- /dev/null ++++ b/sysdeps/x86_64/multiarch/memrchr-evex.S +@@ -0,0 +1,337 @@ ++/* memrchr optimized with 256-bit EVEX instructions. ++ 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 ++ . */ ++ ++#if IS_IN (libc) ++ ++# include ++ ++# define VMOVA vmovdqa64 ++ ++# define YMMMATCH ymm16 ++ ++# define VEC_SIZE 32 ++ ++ .section .text.evex,"ax",@progbits ++ENTRY (__memrchr_evex) ++ /* Broadcast CHAR to YMMMATCH. */ ++ vpbroadcastb %esi, %YMMMATCH ++ ++ sub $VEC_SIZE, %RDX_LP ++ jbe L(last_vec_or_less) ++ ++ add %RDX_LP, %RDI_LP ++ ++ /* Check the last VEC_SIZE bytes. */ ++ vpcmpb $0, (%rdi), %YMMMATCH, %k1 ++ kmovd %k1, %eax ++ testl %eax, %eax ++ jnz L(last_vec_x0) ++ ++ subq $(VEC_SIZE * 4), %rdi ++ movl %edi, %ecx ++ andl $(VEC_SIZE - 1), %ecx ++ jz L(aligned_more) ++ ++ /* Align data for aligned loads in the loop. */ ++ addq $VEC_SIZE, %rdi ++ addq $VEC_SIZE, %rdx ++ andq $-VEC_SIZE, %rdi ++ subq %rcx, %rdx ++ ++ .p2align 4 ++L(aligned_more): ++ subq $(VEC_SIZE * 4), %rdx ++ jbe L(last_4x_vec_or_less) ++ ++ /* Check the last 4 * VEC_SIZE. Only one VEC_SIZE at a time ++ since data is only aligned to VEC_SIZE. */ ++ vpcmpb $0, (VEC_SIZE * 3)(%rdi), %YMMMATCH, %k1 ++ kmovd %k1, %eax ++ testl %eax, %eax ++ jnz L(last_vec_x3) ++ ++ vpcmpb $0, (VEC_SIZE * 2)(%rdi), %YMMMATCH, %k2 ++ kmovd %k2, %eax ++ testl %eax, %eax ++ jnz L(last_vec_x2) ++ ++ vpcmpb $0, VEC_SIZE(%rdi), %YMMMATCH, %k3 ++ kmovd %k3, %eax ++ testl %eax, %eax ++ jnz L(last_vec_x1) ++ ++ vpcmpb $0, (%rdi), %YMMMATCH, %k4 ++ kmovd %k4, %eax ++ testl %eax, %eax ++ jnz L(last_vec_x0) ++ ++ /* Align data to 4 * VEC_SIZE for loop with fewer branches. ++ There are some overlaps with above if data isn't aligned ++ to 4 * VEC_SIZE. */ ++ movl %edi, %ecx ++ andl $(VEC_SIZE * 4 - 1), %ecx ++ jz L(loop_4x_vec) ++ ++ addq $(VEC_SIZE * 4), %rdi ++ addq $(VEC_SIZE * 4), %rdx ++ andq $-(VEC_SIZE * 4), %rdi ++ subq %rcx, %rdx ++ ++ .p2align 4 ++L(loop_4x_vec): ++ /* Compare 4 * VEC at a time forward. */ ++ subq $(VEC_SIZE * 4), %rdi ++ subq $(VEC_SIZE * 4), %rdx ++ jbe L(last_4x_vec_or_less) ++ ++ vpcmpb $0, (%rdi), %YMMMATCH, %k1 ++ vpcmpb $0, VEC_SIZE(%rdi), %YMMMATCH, %k2 ++ kord %k1, %k2, %k5 ++ vpcmpb $0, (VEC_SIZE * 2)(%rdi), %YMMMATCH, %k3 ++ vpcmpb $0, (VEC_SIZE * 3)(%rdi), %YMMMATCH, %k4 ++ ++ kord %k3, %k4, %k6 ++ kortestd %k5, %k6 ++ jz L(loop_4x_vec) ++ ++ /* There is a match. */ ++ kmovd %k4, %eax ++ testl %eax, %eax ++ jnz L(last_vec_x3) ++ ++ kmovd %k3, %eax ++ testl %eax, %eax ++ jnz L(last_vec_x2) ++ ++ kmovd %k2, %eax ++ testl %eax, %eax ++ jnz L(last_vec_x1) ++ ++ kmovd %k1, %eax ++ bsrl %eax, %eax ++ addq %rdi, %rax ++ ret ++ ++ .p2align 4 ++L(last_4x_vec_or_less): ++ addl $(VEC_SIZE * 4), %edx ++ cmpl $(VEC_SIZE * 2), %edx ++ jbe L(last_2x_vec) ++ ++ vpcmpb $0, (VEC_SIZE * 3)(%rdi), %YMMMATCH, %k1 ++ kmovd %k1, %eax ++ testl %eax, %eax ++ jnz L(last_vec_x3) ++ ++ vpcmpb $0, (VEC_SIZE * 2)(%rdi), %YMMMATCH, %k2 ++ kmovd %k2, %eax ++ testl %eax, %eax ++ jnz L(last_vec_x2) ++ ++ vpcmpb $0, VEC_SIZE(%rdi), %YMMMATCH, %k3 ++ kmovd %k3, %eax ++ testl %eax, %eax ++ jnz L(last_vec_x1_check) ++ cmpl $(VEC_SIZE * 3), %edx ++ jbe L(zero) ++ ++ vpcmpb $0, (%rdi), %YMMMATCH, %k4 ++ kmovd %k4, %eax ++ testl %eax, %eax ++ jz L(zero) ++ bsrl %eax, %eax ++ subq $(VEC_SIZE * 4), %rdx ++ addq %rax, %rdx ++ jl L(zero) ++ addq %rdi, %rax ++ ret ++ ++ .p2align 4 ++L(last_2x_vec): ++ vpcmpb $0, (VEC_SIZE * 3)(%rdi), %YMMMATCH, %k1 ++ kmovd %k1, %eax ++ testl %eax, %eax ++ jnz L(last_vec_x3_check) ++ cmpl $VEC_SIZE, %edx ++ jbe L(zero) ++ ++ vpcmpb $0, (VEC_SIZE * 2)(%rdi), %YMMMATCH, %k1 ++ kmovd %k1, %eax ++ testl %eax, %eax ++ jz L(zero) ++ bsrl %eax, %eax ++ subq $(VEC_SIZE * 2), %rdx ++ addq %rax, %rdx ++ jl L(zero) ++ addl $(VEC_SIZE * 2), %eax ++ addq %rdi, %rax ++ ret ++ ++ .p2align 4 ++L(last_vec_x0): ++ bsrl %eax, %eax ++ addq %rdi, %rax ++ ret ++ ++ .p2align 4 ++L(last_vec_x1): ++ bsrl %eax, %eax ++ addl $VEC_SIZE, %eax ++ addq %rdi, %rax ++ ret ++ ++ .p2align 4 ++L(last_vec_x2): ++ bsrl %eax, %eax ++ addl $(VEC_SIZE * 2), %eax ++ addq %rdi, %rax ++ ret ++ ++ .p2align 4 ++L(last_vec_x3): ++ bsrl %eax, %eax ++ addl $(VEC_SIZE * 3), %eax ++ addq %rdi, %rax ++ ret ++ ++ .p2align 4 ++L(last_vec_x1_check): ++ bsrl %eax, %eax ++ subq $(VEC_SIZE * 3), %rdx ++ addq %rax, %rdx ++ jl L(zero) ++ addl $VEC_SIZE, %eax ++ addq %rdi, %rax ++ ret ++ ++ .p2align 4 ++L(last_vec_x3_check): ++ bsrl %eax, %eax ++ subq $VEC_SIZE, %rdx ++ addq %rax, %rdx ++ jl L(zero) ++ addl $(VEC_SIZE * 3), %eax ++ addq %rdi, %rax ++ ret ++ ++ .p2align 4 ++L(zero): ++ xorl %eax, %eax ++ ret ++ ++ .p2align 4 ++L(last_vec_or_less_aligned): ++ movl %edx, %ecx ++ ++ vpcmpb $0, (%rdi), %YMMMATCH, %k1 ++ ++ movl $1, %edx ++ /* Support rdx << 32. */ ++ salq %cl, %rdx ++ subq $1, %rdx ++ ++ kmovd %k1, %eax ++ ++ /* Remove the trailing bytes. */ ++ andl %edx, %eax ++ testl %eax, %eax ++ jz L(zero) ++ ++ bsrl %eax, %eax ++ addq %rdi, %rax ++ ret ++ ++ .p2align 4 ++L(last_vec_or_less): ++ addl $VEC_SIZE, %edx ++ ++ /* Check for zero length. */ ++ testl %edx, %edx ++ jz L(zero) ++ ++ movl %edi, %ecx ++ andl $(VEC_SIZE - 1), %ecx ++ jz L(last_vec_or_less_aligned) ++ ++ movl %ecx, %esi ++ movl %ecx, %r8d ++ addl %edx, %esi ++ andq $-VEC_SIZE, %rdi ++ ++ subl $VEC_SIZE, %esi ++ ja L(last_vec_2x_aligned) ++ ++ /* Check the last VEC. */ ++ vpcmpb $0, (%rdi), %YMMMATCH, %k1 ++ kmovd %k1, %eax ++ ++ /* Remove the leading and trailing bytes. */ ++ sarl %cl, %eax ++ movl %edx, %ecx ++ ++ movl $1, %edx ++ sall %cl, %edx ++ subl $1, %edx ++ ++ andl %edx, %eax ++ testl %eax, %eax ++ jz L(zero) ++ ++ bsrl %eax, %eax ++ addq %rdi, %rax ++ addq %r8, %rax ++ ret ++ ++ .p2align 4 ++L(last_vec_2x_aligned): ++ movl %esi, %ecx ++ ++ /* Check the last VEC. */ ++ vpcmpb $0, VEC_SIZE(%rdi), %YMMMATCH, %k1 ++ ++ movl $1, %edx ++ sall %cl, %edx ++ subl $1, %edx ++ ++ kmovd %k1, %eax ++ ++ /* Remove the trailing bytes. */ ++ andl %edx, %eax ++ ++ testl %eax, %eax ++ jnz L(last_vec_x1) ++ ++ /* Check the second last VEC. */ ++ vpcmpb $0, (%rdi), %YMMMATCH, %k1 ++ ++ movl %r8d, %ecx ++ ++ kmovd %k1, %eax ++ ++ /* Remove the leading bytes. Must use unsigned right shift for ++ bsrl below. */ ++ shrl %cl, %eax ++ testl %eax, %eax ++ jz L(zero) ++ ++ bsrl %eax, %eax ++ addq %rdi, %rax ++ addq %r8, %rax ++ ret ++END (__memrchr_evex) ++#endif +diff --git a/sysdeps/x86_64/multiarch/rawmemchr-evex.S b/sysdeps/x86_64/multiarch/rawmemchr-evex.S +new file mode 100644 +index 00000000..ec942b77 +--- /dev/null ++++ b/sysdeps/x86_64/multiarch/rawmemchr-evex.S +@@ -0,0 +1,4 @@ ++#define MEMCHR __rawmemchr_evex ++#define USE_AS_RAWMEMCHR 1 ++ ++#include "memchr-evex.S" +diff --git a/sysdeps/x86_64/multiarch/strchr-evex.S b/sysdeps/x86_64/multiarch/strchr-evex.S +new file mode 100644 +index 00000000..ddc86a70 +--- /dev/null ++++ b/sysdeps/x86_64/multiarch/strchr-evex.S +@@ -0,0 +1,335 @@ ++/* strchr/strchrnul optimized with 256-bit EVEX instructions. ++ 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 ++ . */ ++ ++#if IS_IN (libc) ++ ++# include ++ ++# ifndef STRCHR ++# define STRCHR __strchr_evex ++# endif ++ ++# define VMOVU vmovdqu64 ++# define VMOVA vmovdqa64 ++ ++# ifdef USE_AS_WCSCHR ++# define VPBROADCAST vpbroadcastd ++# define VPCMP vpcmpd ++# define VPMINU vpminud ++# define CHAR_REG esi ++# define SHIFT_REG r8d ++# else ++# define VPBROADCAST vpbroadcastb ++# define VPCMP vpcmpb ++# define VPMINU vpminub ++# define CHAR_REG sil ++# define SHIFT_REG ecx ++# endif ++ ++# define XMMZERO xmm16 ++ ++# define YMMZERO ymm16 ++# define YMM0 ymm17 ++# define YMM1 ymm18 ++# define YMM2 ymm19 ++# define YMM3 ymm20 ++# define YMM4 ymm21 ++# define YMM5 ymm22 ++# define YMM6 ymm23 ++# define YMM7 ymm24 ++# define YMM8 ymm25 ++ ++# define VEC_SIZE 32 ++# define PAGE_SIZE 4096 ++ ++ .section .text.evex,"ax",@progbits ++ENTRY (STRCHR) ++ movl %edi, %ecx ++# ifndef USE_AS_STRCHRNUL ++ xorl %edx, %edx ++# endif ++ ++ /* Broadcast CHAR to YMM0. */ ++ VPBROADCAST %esi, %YMM0 ++ ++ vpxorq %XMMZERO, %XMMZERO, %XMMZERO ++ ++ /* Check if we cross page boundary with one vector load. */ ++ andl $(PAGE_SIZE - 1), %ecx ++ cmpl $(PAGE_SIZE - VEC_SIZE), %ecx ++ ja L(cross_page_boundary) ++ ++ /* Check the first VEC_SIZE bytes. Search for both CHAR and the ++ null bytes. */ ++ VMOVU (%rdi), %YMM1 ++ ++ /* Leaves only CHARS matching esi as 0. */ ++ vpxorq %YMM1, %YMM0, %YMM2 ++ VPMINU %YMM2, %YMM1, %YMM2 ++ /* Each bit in K0 represents a CHAR or a null byte in YMM1. */ ++ VPCMP $0, %YMMZERO, %YMM2, %k0 ++ ktestd %k0, %k0 ++ jz L(more_vecs) ++ kmovd %k0, %eax ++ tzcntl %eax, %eax ++ /* Found CHAR or the null byte. */ ++# ifdef USE_AS_WCSCHR ++ /* NB: Multiply wchar_t count by 4 to get the number of bytes. */ ++ leaq (%rdi, %rax, 4), %rax ++# else ++ addq %rdi, %rax ++# endif ++# ifndef USE_AS_STRCHRNUL ++ cmp (%rax), %CHAR_REG ++ cmovne %rdx, %rax ++# endif ++ ret ++ ++ .p2align 4 ++L(more_vecs): ++ /* Align data for aligned loads in the loop. */ ++ andq $-VEC_SIZE, %rdi ++L(aligned_more): ++ ++ /* Check the next 4 * VEC_SIZE. Only one VEC_SIZE at a time ++ since data is only aligned to VEC_SIZE. */ ++ VMOVA VEC_SIZE(%rdi), %YMM1 ++ addq $VEC_SIZE, %rdi ++ ++ /* Leaves only CHARS matching esi as 0. */ ++ vpxorq %YMM1, %YMM0, %YMM2 ++ VPMINU %YMM2, %YMM1, %YMM2 ++ /* Each bit in K0 represents a CHAR or a null byte in YMM1. */ ++ VPCMP $0, %YMMZERO, %YMM2, %k0 ++ kmovd %k0, %eax ++ testl %eax, %eax ++ jnz L(first_vec_x0) ++ ++ VMOVA VEC_SIZE(%rdi), %YMM1 ++ /* Leaves only CHARS matching esi as 0. */ ++ vpxorq %YMM1, %YMM0, %YMM2 ++ VPMINU %YMM2, %YMM1, %YMM2 ++ /* Each bit in K0 represents a CHAR or a null byte in YMM1. */ ++ VPCMP $0, %YMMZERO, %YMM2, %k0 ++ kmovd %k0, %eax ++ testl %eax, %eax ++ jnz L(first_vec_x1) ++ ++ VMOVA (VEC_SIZE * 2)(%rdi), %YMM1 ++ /* Leaves only CHARS matching esi as 0. */ ++ vpxorq %YMM1, %YMM0, %YMM2 ++ VPMINU %YMM2, %YMM1, %YMM2 ++ /* Each bit in K0 represents a CHAR or a null byte in YMM1. */ ++ VPCMP $0, %YMMZERO, %YMM2, %k0 ++ kmovd %k0, %eax ++ testl %eax, %eax ++ jnz L(first_vec_x2) ++ ++ VMOVA (VEC_SIZE * 3)(%rdi), %YMM1 ++ /* Leaves only CHARS matching esi as 0. */ ++ vpxorq %YMM1, %YMM0, %YMM2 ++ VPMINU %YMM2, %YMM1, %YMM2 ++ /* Each bit in K0 represents a CHAR or a null byte in YMM1. */ ++ VPCMP $0, %YMMZERO, %YMM2, %k0 ++ ktestd %k0, %k0 ++ jz L(prep_loop_4x) ++ ++ kmovd %k0, %eax ++ tzcntl %eax, %eax ++ /* Found CHAR or the null byte. */ ++# ifdef USE_AS_WCSCHR ++ /* NB: Multiply wchar_t count by 4 to get the number of bytes. */ ++ leaq (VEC_SIZE * 3)(%rdi, %rax, 4), %rax ++# else ++ leaq (VEC_SIZE * 3)(%rdi, %rax), %rax ++# endif ++# ifndef USE_AS_STRCHRNUL ++ cmp (%rax), %CHAR_REG ++ cmovne %rdx, %rax ++# endif ++ ret ++ ++ .p2align 4 ++L(first_vec_x0): ++ tzcntl %eax, %eax ++ /* Found CHAR or the null byte. */ ++# ifdef USE_AS_WCSCHR ++ /* NB: Multiply wchar_t count by 4 to get the number of bytes. */ ++ leaq (%rdi, %rax, 4), %rax ++# else ++ addq %rdi, %rax ++# endif ++# ifndef USE_AS_STRCHRNUL ++ cmp (%rax), %CHAR_REG ++ cmovne %rdx, %rax ++# endif ++ ret ++ ++ .p2align 4 ++L(first_vec_x1): ++ tzcntl %eax, %eax ++ /* Found CHAR or the null byte. */ ++# ifdef USE_AS_WCSCHR ++ /* NB: Multiply wchar_t count by 4 to get the number of bytes. */ ++ leaq VEC_SIZE(%rdi, %rax, 4), %rax ++# else ++ leaq VEC_SIZE(%rdi, %rax), %rax ++# endif ++# ifndef USE_AS_STRCHRNUL ++ cmp (%rax), %CHAR_REG ++ cmovne %rdx, %rax ++# endif ++ ret ++ ++ .p2align 4 ++L(first_vec_x2): ++ tzcntl %eax, %eax ++ /* Found CHAR or the null byte. */ ++# ifdef USE_AS_WCSCHR ++ /* NB: Multiply wchar_t count by 4 to get the number of bytes. */ ++ leaq (VEC_SIZE * 2)(%rdi, %rax, 4), %rax ++# else ++ leaq (VEC_SIZE * 2)(%rdi, %rax), %rax ++# endif ++# ifndef USE_AS_STRCHRNUL ++ cmp (%rax), %CHAR_REG ++ cmovne %rdx, %rax ++# endif ++ ret ++ ++L(prep_loop_4x): ++ /* Align data to 4 * VEC_SIZE. */ ++ andq $-(VEC_SIZE * 4), %rdi ++ ++ .p2align 4 ++L(loop_4x_vec): ++ /* Compare 4 * VEC at a time forward. */ ++ VMOVA (VEC_SIZE * 4)(%rdi), %YMM1 ++ VMOVA (VEC_SIZE * 5)(%rdi), %YMM2 ++ VMOVA (VEC_SIZE * 6)(%rdi), %YMM3 ++ VMOVA (VEC_SIZE * 7)(%rdi), %YMM4 ++ ++ /* Leaves only CHARS matching esi as 0. */ ++ vpxorq %YMM1, %YMM0, %YMM5 ++ vpxorq %YMM2, %YMM0, %YMM6 ++ vpxorq %YMM3, %YMM0, %YMM7 ++ vpxorq %YMM4, %YMM0, %YMM8 ++ ++ VPMINU %YMM5, %YMM1, %YMM5 ++ VPMINU %YMM6, %YMM2, %YMM6 ++ VPMINU %YMM7, %YMM3, %YMM7 ++ VPMINU %YMM8, %YMM4, %YMM8 ++ ++ VPMINU %YMM5, %YMM6, %YMM1 ++ VPMINU %YMM7, %YMM8, %YMM2 ++ ++ VPMINU %YMM1, %YMM2, %YMM1 ++ ++ /* Each bit in K0 represents a CHAR or a null byte. */ ++ VPCMP $0, %YMMZERO, %YMM1, %k0 ++ ++ addq $(VEC_SIZE * 4), %rdi ++ ++ ktestd %k0, %k0 ++ jz L(loop_4x_vec) ++ ++ /* Each bit in K0 represents a CHAR or a null byte in YMM1. */ ++ VPCMP $0, %YMMZERO, %YMM5, %k0 ++ kmovd %k0, %eax ++ testl %eax, %eax ++ jnz L(first_vec_x0) ++ ++ /* Each bit in K1 represents a CHAR or a null byte in YMM2. */ ++ VPCMP $0, %YMMZERO, %YMM6, %k1 ++ kmovd %k1, %eax ++ testl %eax, %eax ++ jnz L(first_vec_x1) ++ ++ /* Each bit in K2 represents a CHAR or a null byte in YMM3. */ ++ VPCMP $0, %YMMZERO, %YMM7, %k2 ++ /* Each bit in K3 represents a CHAR or a null byte in YMM4. */ ++ VPCMP $0, %YMMZERO, %YMM8, %k3 ++ ++# ifdef USE_AS_WCSCHR ++ /* NB: Each bit in K2/K3 represents 4-byte element. */ ++ kshiftlw $8, %k3, %k1 ++# else ++ kshiftlq $32, %k3, %k1 ++# endif ++ ++ /* Each bit in K1 represents a NULL or a mismatch. */ ++ korq %k1, %k2, %k1 ++ kmovq %k1, %rax ++ ++ tzcntq %rax, %rax ++# ifdef USE_AS_WCSCHR ++ /* NB: Multiply wchar_t count by 4 to get the number of bytes. */ ++ leaq (VEC_SIZE * 2)(%rdi, %rax, 4), %rax ++# else ++ leaq (VEC_SIZE * 2)(%rdi, %rax), %rax ++# endif ++# ifndef USE_AS_STRCHRNUL ++ cmp (%rax), %CHAR_REG ++ cmovne %rdx, %rax ++# endif ++ ret ++ ++ /* Cold case for crossing page with first load. */ ++ .p2align 4 ++L(cross_page_boundary): ++ andq $-VEC_SIZE, %rdi ++ andl $(VEC_SIZE - 1), %ecx ++ ++ VMOVA (%rdi), %YMM1 ++ ++ /* Leaves only CHARS matching esi as 0. */ ++ vpxorq %YMM1, %YMM0, %YMM2 ++ VPMINU %YMM2, %YMM1, %YMM2 ++ /* Each bit in K0 represents a CHAR or a null byte in YMM1. */ ++ VPCMP $0, %YMMZERO, %YMM2, %k0 ++ kmovd %k0, %eax ++ testl %eax, %eax ++ ++# ifdef USE_AS_WCSCHR ++ /* NB: Divide shift count by 4 since each bit in K1 represent 4 ++ bytes. */ ++ movl %ecx, %SHIFT_REG ++ sarl $2, %SHIFT_REG ++# endif ++ ++ /* Remove the leading bits. */ ++ sarxl %SHIFT_REG, %eax, %eax ++ testl %eax, %eax ++ ++ jz L(aligned_more) ++ tzcntl %eax, %eax ++ addq %rcx, %rdi ++# ifdef USE_AS_WCSCHR ++ /* NB: Multiply wchar_t count by 4 to get the number of bytes. */ ++ leaq (%rdi, %rax, 4), %rax ++# else ++ addq %rdi, %rax ++# endif ++# ifndef USE_AS_STRCHRNUL ++ cmp (%rax), %CHAR_REG ++ cmovne %rdx, %rax ++# endif ++ ret ++ ++END (STRCHR) ++# endif +diff --git a/sysdeps/x86_64/multiarch/strchr.c b/sysdeps/x86_64/multiarch/strchr.c +index 32954713..be05e197 100644 +--- a/sysdeps/x86_64/multiarch/strchr.c ++++ b/sysdeps/x86_64/multiarch/strchr.c +@@ -29,16 +29,24 @@ + extern __typeof (REDIRECT_NAME) OPTIMIZE (sse2) attribute_hidden; + extern __typeof (REDIRECT_NAME) OPTIMIZE (sse2_no_bsf) attribute_hidden; + extern __typeof (REDIRECT_NAME) OPTIMIZE (avx2) attribute_hidden; ++extern __typeof (REDIRECT_NAME) OPTIMIZE (evex) attribute_hidden; + + static inline void * + IFUNC_SELECTOR (void) + { + const struct cpu_features* cpu_features = __get_cpu_features (); + +- if (!CPU_FEATURES_ARCH_P (cpu_features, Prefer_No_VZEROUPPER) +- && CPU_FEATURE_USABLE_P (cpu_features, AVX2) ++ if (CPU_FEATURE_USABLE_P (cpu_features, AVX2) + && CPU_FEATURES_ARCH_P (cpu_features, AVX_Fast_Unaligned_Load)) +- return OPTIMIZE (avx2); ++ { ++ if (CPU_FEATURE_USABLE_P (cpu_features, AVX512VL) ++ && CPU_FEATURE_USABLE_P (cpu_features, AVX512BW) ++ && CPU_FEATURE_USABLE_P (cpu_features, BMI2)) ++ return OPTIMIZE (evex); ++ ++ if (!CPU_FEATURES_ARCH_P (cpu_features, Prefer_No_VZEROUPPER)) ++ return OPTIMIZE (avx2); ++ } + + if (CPU_FEATURES_ARCH_P (cpu_features, Slow_BSF)) + return OPTIMIZE (sse2_no_bsf); +diff --git a/sysdeps/x86_64/multiarch/strchrnul-evex.S b/sysdeps/x86_64/multiarch/strchrnul-evex.S +new file mode 100644 +index 00000000..064fe7ca +--- /dev/null ++++ b/sysdeps/x86_64/multiarch/strchrnul-evex.S +@@ -0,0 +1,3 @@ ++#define STRCHR __strchrnul_evex ++#define USE_AS_STRCHRNUL 1 ++#include "strchr-evex.S" +diff --git a/sysdeps/x86_64/multiarch/strcmp-evex.S b/sysdeps/x86_64/multiarch/strcmp-evex.S +new file mode 100644 +index 00000000..459eeed0 +--- /dev/null ++++ b/sysdeps/x86_64/multiarch/strcmp-evex.S +@@ -0,0 +1,1043 @@ ++/* strcmp/wcscmp/strncmp/wcsncmp optimized with 256-bit EVEX instructions. ++ 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 ++ . */ ++ ++#if IS_IN (libc) ++ ++# include ++ ++# ifndef STRCMP ++# define STRCMP __strcmp_evex ++# endif ++ ++# define PAGE_SIZE 4096 ++ ++/* VEC_SIZE = Number of bytes in a ymm register */ ++# define VEC_SIZE 32 ++ ++/* Shift for dividing by (VEC_SIZE * 4). */ ++# define DIVIDE_BY_VEC_4_SHIFT 7 ++# if (VEC_SIZE * 4) != (1 << DIVIDE_BY_VEC_4_SHIFT) ++# error (VEC_SIZE * 4) != (1 << DIVIDE_BY_VEC_4_SHIFT) ++# endif ++ ++# define VMOVU vmovdqu64 ++# define VMOVA vmovdqa64 ++ ++# ifdef USE_AS_WCSCMP ++/* Compare packed dwords. */ ++# define VPCMP vpcmpd ++# define SHIFT_REG32 r8d ++# define SHIFT_REG64 r8 ++/* 1 dword char == 4 bytes. */ ++# define SIZE_OF_CHAR 4 ++# else ++/* Compare packed bytes. */ ++# define VPCMP vpcmpb ++# define SHIFT_REG32 ecx ++# define SHIFT_REG64 rcx ++/* 1 byte char == 1 byte. */ ++# define SIZE_OF_CHAR 1 ++# endif ++ ++# define XMMZERO xmm16 ++# define XMM0 xmm17 ++# define XMM1 xmm18 ++ ++# define YMMZERO ymm16 ++# define YMM0 ymm17 ++# define YMM1 ymm18 ++# define YMM2 ymm19 ++# define YMM3 ymm20 ++# define YMM4 ymm21 ++# define YMM5 ymm22 ++# define YMM6 ymm23 ++# define YMM7 ymm24 ++ ++/* Warning! ++ wcscmp/wcsncmp have to use SIGNED comparison for elements. ++ strcmp/strncmp have to use UNSIGNED comparison for elements. ++*/ ++ ++/* The main idea of the string comparison (byte or dword) using 256-bit ++ EVEX instructions consists of comparing (VPCMP) two ymm vectors. The ++ latter can be on either packed bytes or dwords depending on ++ USE_AS_WCSCMP. In order to check the null char, algorithm keeps the ++ matched bytes/dwords, requiring 5 EVEX instructions (3 VPCMP and 2 ++ KORD). In general, the costs of comparing VEC_SIZE bytes (32-bytes) ++ are 3 VPCMP and 2 KORD instructions, together with VMOVU and ktestd ++ instructions. Main loop (away from from page boundary) compares 4 ++ vectors are a time, effectively comparing 4 x VEC_SIZE bytes (128 ++ bytes) on each loop. ++ ++ The routine strncmp/wcsncmp (enabled by defining USE_AS_STRNCMP) logic ++ is the same as strcmp, except that an a maximum offset is tracked. If ++ the maximum offset is reached before a difference is found, zero is ++ returned. */ ++ ++ .section .text.evex,"ax",@progbits ++ENTRY (STRCMP) ++# ifdef USE_AS_STRNCMP ++ /* Check for simple cases (0 or 1) in offset. */ ++ cmp $1, %RDX_LP ++ je L(char0) ++ jb L(zero) ++# ifdef USE_AS_WCSCMP ++ /* Convert units: from wide to byte char. */ ++ shl $2, %RDX_LP ++# endif ++ /* Register %r11 tracks the maximum offset. */ ++ mov %RDX_LP, %R11_LP ++# endif ++ movl %edi, %eax ++ xorl %edx, %edx ++ /* Make %XMMZERO (%YMMZERO) all zeros in this function. */ ++ vpxorq %XMMZERO, %XMMZERO, %XMMZERO ++ orl %esi, %eax ++ andl $(PAGE_SIZE - 1), %eax ++ cmpl $(PAGE_SIZE - (VEC_SIZE * 4)), %eax ++ jg L(cross_page) ++ /* Start comparing 4 vectors. */ ++ VMOVU (%rdi), %YMM0 ++ VMOVU (%rsi), %YMM1 ++ ++ /* Each bit in K0 represents a mismatch in YMM0 and YMM1. */ ++ VPCMP $4, %YMM0, %YMM1, %k0 ++ ++ /* Check for NULL in YMM0. */ ++ VPCMP $0, %YMMZERO, %YMM0, %k1 ++ /* Check for NULL in YMM1. */ ++ VPCMP $0, %YMMZERO, %YMM1, %k2 ++ /* Each bit in K1 represents a NULL in YMM0 or YMM1. */ ++ kord %k1, %k2, %k1 ++ ++ /* Each bit in K1 represents: ++ 1. A mismatch in YMM0 and YMM1. Or ++ 2. A NULL in YMM0 or YMM1. ++ */ ++ kord %k0, %k1, %k1 ++ ++ ktestd %k1, %k1 ++ je L(next_3_vectors) ++ kmovd %k1, %ecx ++ tzcntl %ecx, %edx ++# ifdef USE_AS_WCSCMP ++ /* NB: Multiply wchar_t count by 4 to get the number of bytes. */ ++ sall $2, %edx ++# endif ++# ifdef USE_AS_STRNCMP ++ /* Return 0 if the mismatched index (%rdx) is after the maximum ++ offset (%r11). */ ++ cmpq %r11, %rdx ++ jae L(zero) ++# endif ++# ifdef USE_AS_WCSCMP ++ xorl %eax, %eax ++ movl (%rdi, %rdx), %ecx ++ cmpl (%rsi, %rdx), %ecx ++ je L(return) ++L(wcscmp_return): ++ setl %al ++ negl %eax ++ orl $1, %eax ++L(return): ++# else ++ movzbl (%rdi, %rdx), %eax ++ movzbl (%rsi, %rdx), %edx ++ subl %edx, %eax ++# endif ++ ret ++ ++ .p2align 4 ++L(return_vec_size): ++ kmovd %k1, %ecx ++ tzcntl %ecx, %edx ++# ifdef USE_AS_WCSCMP ++ /* NB: Multiply wchar_t count by 4 to get the number of bytes. */ ++ sall $2, %edx ++# endif ++# ifdef USE_AS_STRNCMP ++ /* Return 0 if the mismatched index (%rdx + VEC_SIZE) is after ++ the maximum offset (%r11). */ ++ addq $VEC_SIZE, %rdx ++ cmpq %r11, %rdx ++ jae L(zero) ++# ifdef USE_AS_WCSCMP ++ xorl %eax, %eax ++ movl (%rdi, %rdx), %ecx ++ cmpl (%rsi, %rdx), %ecx ++ jne L(wcscmp_return) ++# else ++ movzbl (%rdi, %rdx), %eax ++ movzbl (%rsi, %rdx), %edx ++ subl %edx, %eax ++# endif ++# else ++# ifdef USE_AS_WCSCMP ++ xorl %eax, %eax ++ movl VEC_SIZE(%rdi, %rdx), %ecx ++ cmpl VEC_SIZE(%rsi, %rdx), %ecx ++ jne L(wcscmp_return) ++# else ++ movzbl VEC_SIZE(%rdi, %rdx), %eax ++ movzbl VEC_SIZE(%rsi, %rdx), %edx ++ subl %edx, %eax ++# endif ++# endif ++ ret ++ ++ .p2align 4 ++L(return_2_vec_size): ++ kmovd %k1, %ecx ++ tzcntl %ecx, %edx ++# ifdef USE_AS_WCSCMP ++ /* NB: Multiply wchar_t count by 4 to get the number of bytes. */ ++ sall $2, %edx ++# endif ++# ifdef USE_AS_STRNCMP ++ /* Return 0 if the mismatched index (%rdx + 2 * VEC_SIZE) is ++ after the maximum offset (%r11). */ ++ addq $(VEC_SIZE * 2), %rdx ++ cmpq %r11, %rdx ++ jae L(zero) ++# ifdef USE_AS_WCSCMP ++ xorl %eax, %eax ++ movl (%rdi, %rdx), %ecx ++ cmpl (%rsi, %rdx), %ecx ++ jne L(wcscmp_return) ++# else ++ movzbl (%rdi, %rdx), %eax ++ movzbl (%rsi, %rdx), %edx ++ subl %edx, %eax ++# endif ++# else ++# ifdef USE_AS_WCSCMP ++ xorl %eax, %eax ++ movl (VEC_SIZE * 2)(%rdi, %rdx), %ecx ++ cmpl (VEC_SIZE * 2)(%rsi, %rdx), %ecx ++ jne L(wcscmp_return) ++# else ++ movzbl (VEC_SIZE * 2)(%rdi, %rdx), %eax ++ movzbl (VEC_SIZE * 2)(%rsi, %rdx), %edx ++ subl %edx, %eax ++# endif ++# endif ++ ret ++ ++ .p2align 4 ++L(return_3_vec_size): ++ kmovd %k1, %ecx ++ tzcntl %ecx, %edx ++# ifdef USE_AS_WCSCMP ++ /* NB: Multiply wchar_t count by 4 to get the number of bytes. */ ++ sall $2, %edx ++# endif ++# ifdef USE_AS_STRNCMP ++ /* Return 0 if the mismatched index (%rdx + 3 * VEC_SIZE) is ++ after the maximum offset (%r11). */ ++ addq $(VEC_SIZE * 3), %rdx ++ cmpq %r11, %rdx ++ jae L(zero) ++# ifdef USE_AS_WCSCMP ++ xorl %eax, %eax ++ movl (%rdi, %rdx), %ecx ++ cmpl (%rsi, %rdx), %ecx ++ jne L(wcscmp_return) ++# else ++ movzbl (%rdi, %rdx), %eax ++ movzbl (%rsi, %rdx), %edx ++ subl %edx, %eax ++# endif ++# else ++# ifdef USE_AS_WCSCMP ++ xorl %eax, %eax ++ movl (VEC_SIZE * 3)(%rdi, %rdx), %ecx ++ cmpl (VEC_SIZE * 3)(%rsi, %rdx), %ecx ++ jne L(wcscmp_return) ++# else ++ movzbl (VEC_SIZE * 3)(%rdi, %rdx), %eax ++ movzbl (VEC_SIZE * 3)(%rsi, %rdx), %edx ++ subl %edx, %eax ++# endif ++# endif ++ ret ++ ++ .p2align 4 ++L(next_3_vectors): ++ VMOVU VEC_SIZE(%rdi), %YMM0 ++ VMOVU VEC_SIZE(%rsi), %YMM1 ++ /* Each bit in K0 represents a mismatch in YMM0 and YMM1. */ ++ VPCMP $4, %YMM0, %YMM1, %k0 ++ VPCMP $0, %YMMZERO, %YMM0, %k1 ++ VPCMP $0, %YMMZERO, %YMM1, %k2 ++ /* Each bit in K1 represents a NULL in YMM0 or YMM1. */ ++ kord %k1, %k2, %k1 ++ /* Each bit in K1 represents a NULL or a mismatch. */ ++ kord %k0, %k1, %k1 ++ ktestd %k1, %k1 ++ jne L(return_vec_size) ++ ++ VMOVU (VEC_SIZE * 2)(%rdi), %YMM2 ++ VMOVU (VEC_SIZE * 3)(%rdi), %YMM3 ++ VMOVU (VEC_SIZE * 2)(%rsi), %YMM4 ++ VMOVU (VEC_SIZE * 3)(%rsi), %YMM5 ++ ++ /* Each bit in K0 represents a mismatch in YMM2 and YMM4. */ ++ VPCMP $4, %YMM2, %YMM4, %k0 ++ VPCMP $0, %YMMZERO, %YMM2, %k1 ++ VPCMP $0, %YMMZERO, %YMM4, %k2 ++ /* Each bit in K1 represents a NULL in YMM2 or YMM4. */ ++ kord %k1, %k2, %k1 ++ /* Each bit in K1 represents a NULL or a mismatch. */ ++ kord %k0, %k1, %k1 ++ ktestd %k1, %k1 ++ jne L(return_2_vec_size) ++ ++ /* Each bit in K0 represents a mismatch in YMM3 and YMM5. */ ++ VPCMP $4, %YMM3, %YMM5, %k0 ++ VPCMP $0, %YMMZERO, %YMM3, %k1 ++ VPCMP $0, %YMMZERO, %YMM5, %k2 ++ /* Each bit in K1 represents a NULL in YMM3 or YMM5. */ ++ kord %k1, %k2, %k1 ++ /* Each bit in K1 represents a NULL or a mismatch. */ ++ kord %k0, %k1, %k1 ++ ktestd %k1, %k1 ++ jne L(return_3_vec_size) ++L(main_loop_header): ++ leaq (VEC_SIZE * 4)(%rdi), %rdx ++ movl $PAGE_SIZE, %ecx ++ /* Align load via RAX. */ ++ andq $-(VEC_SIZE * 4), %rdx ++ subq %rdi, %rdx ++ leaq (%rdi, %rdx), %rax ++# ifdef USE_AS_STRNCMP ++ /* Starting from this point, the maximum offset, or simply the ++ 'offset', DECREASES by the same amount when base pointers are ++ moved forward. Return 0 when: ++ 1) On match: offset <= the matched vector index. ++ 2) On mistmach, offset is before the mistmatched index. ++ */ ++ subq %rdx, %r11 ++ jbe L(zero) ++# endif ++ addq %rsi, %rdx ++ movq %rdx, %rsi ++ andl $(PAGE_SIZE - 1), %esi ++ /* Number of bytes before page crossing. */ ++ subq %rsi, %rcx ++ /* Number of VEC_SIZE * 4 blocks before page crossing. */ ++ shrq $DIVIDE_BY_VEC_4_SHIFT, %rcx ++ /* ESI: Number of VEC_SIZE * 4 blocks before page crossing. */ ++ movl %ecx, %esi ++ jmp L(loop_start) ++ ++ .p2align 4 ++L(loop): ++# ifdef USE_AS_STRNCMP ++ /* Base pointers are moved forward by 4 * VEC_SIZE. Decrease ++ the maximum offset (%r11) by the same amount. */ ++ subq $(VEC_SIZE * 4), %r11 ++ jbe L(zero) ++# endif ++ addq $(VEC_SIZE * 4), %rax ++ addq $(VEC_SIZE * 4), %rdx ++L(loop_start): ++ testl %esi, %esi ++ leal -1(%esi), %esi ++ je L(loop_cross_page) ++L(back_to_loop): ++ /* Main loop, comparing 4 vectors are a time. */ ++ VMOVA (%rax), %YMM0 ++ VMOVA VEC_SIZE(%rax), %YMM2 ++ VMOVA (VEC_SIZE * 2)(%rax), %YMM4 ++ VMOVA (VEC_SIZE * 3)(%rax), %YMM6 ++ VMOVU (%rdx), %YMM1 ++ VMOVU VEC_SIZE(%rdx), %YMM3 ++ VMOVU (VEC_SIZE * 2)(%rdx), %YMM5 ++ VMOVU (VEC_SIZE * 3)(%rdx), %YMM7 ++ ++ VPCMP $4, %YMM0, %YMM1, %k0 ++ VPCMP $0, %YMMZERO, %YMM0, %k1 ++ VPCMP $0, %YMMZERO, %YMM1, %k2 ++ kord %k1, %k2, %k1 ++ /* Each bit in K4 represents a NULL or a mismatch in YMM0 and ++ YMM1. */ ++ kord %k0, %k1, %k4 ++ ++ VPCMP $4, %YMM2, %YMM3, %k0 ++ VPCMP $0, %YMMZERO, %YMM2, %k1 ++ VPCMP $0, %YMMZERO, %YMM3, %k2 ++ kord %k1, %k2, %k1 ++ /* Each bit in K5 represents a NULL or a mismatch in YMM2 and ++ YMM3. */ ++ kord %k0, %k1, %k5 ++ ++ VPCMP $4, %YMM4, %YMM5, %k0 ++ VPCMP $0, %YMMZERO, %YMM4, %k1 ++ VPCMP $0, %YMMZERO, %YMM5, %k2 ++ kord %k1, %k2, %k1 ++ /* Each bit in K6 represents a NULL or a mismatch in YMM4 and ++ YMM5. */ ++ kord %k0, %k1, %k6 ++ ++ VPCMP $4, %YMM6, %YMM7, %k0 ++ VPCMP $0, %YMMZERO, %YMM6, %k1 ++ VPCMP $0, %YMMZERO, %YMM7, %k2 ++ kord %k1, %k2, %k1 ++ /* Each bit in K7 represents a NULL or a mismatch in YMM6 and ++ YMM7. */ ++ kord %k0, %k1, %k7 ++ ++ kord %k4, %k5, %k0 ++ kord %k6, %k7, %k1 ++ ++ /* Test each mask (32 bits) individually because for VEC_SIZE ++ == 32 is not possible to OR the four masks and keep all bits ++ in a 64-bit integer register, differing from SSE2 strcmp ++ where ORing is possible. */ ++ kortestd %k0, %k1 ++ je L(loop) ++ ktestd %k4, %k4 ++ je L(test_vec) ++ kmovd %k4, %edi ++ tzcntl %edi, %ecx ++# ifdef USE_AS_WCSCMP ++ /* NB: Multiply wchar_t count by 4 to get the number of bytes. */ ++ sall $2, %ecx ++# endif ++# ifdef USE_AS_STRNCMP ++ cmpq %rcx, %r11 ++ jbe L(zero) ++# ifdef USE_AS_WCSCMP ++ movq %rax, %rsi ++ xorl %eax, %eax ++ movl (%rsi, %rcx), %edi ++ cmpl (%rdx, %rcx), %edi ++ jne L(wcscmp_return) ++# else ++ movzbl (%rax, %rcx), %eax ++ movzbl (%rdx, %rcx), %edx ++ subl %edx, %eax ++# endif ++# else ++# ifdef USE_AS_WCSCMP ++ movq %rax, %rsi ++ xorl %eax, %eax ++ movl (%rsi, %rcx), %edi ++ cmpl (%rdx, %rcx), %edi ++ jne L(wcscmp_return) ++# else ++ movzbl (%rax, %rcx), %eax ++ movzbl (%rdx, %rcx), %edx ++ subl %edx, %eax ++# endif ++# endif ++ ret ++ ++ .p2align 4 ++L(test_vec): ++# ifdef USE_AS_STRNCMP ++ /* The first vector matched. Return 0 if the maximum offset ++ (%r11) <= VEC_SIZE. */ ++ cmpq $VEC_SIZE, %r11 ++ jbe L(zero) ++# endif ++ ktestd %k5, %k5 ++ je L(test_2_vec) ++ kmovd %k5, %ecx ++ tzcntl %ecx, %edi ++# ifdef USE_AS_WCSCMP ++ /* NB: Multiply wchar_t count by 4 to get the number of bytes. */ ++ sall $2, %edi ++# endif ++# ifdef USE_AS_STRNCMP ++ addq $VEC_SIZE, %rdi ++ cmpq %rdi, %r11 ++ jbe L(zero) ++# ifdef USE_AS_WCSCMP ++ movq %rax, %rsi ++ xorl %eax, %eax ++ movl (%rsi, %rdi), %ecx ++ cmpl (%rdx, %rdi), %ecx ++ jne L(wcscmp_return) ++# else ++ movzbl (%rax, %rdi), %eax ++ movzbl (%rdx, %rdi), %edx ++ subl %edx, %eax ++# endif ++# else ++# ifdef USE_AS_WCSCMP ++ movq %rax, %rsi ++ xorl %eax, %eax ++ movl VEC_SIZE(%rsi, %rdi), %ecx ++ cmpl VEC_SIZE(%rdx, %rdi), %ecx ++ jne L(wcscmp_return) ++# else ++ movzbl VEC_SIZE(%rax, %rdi), %eax ++ movzbl VEC_SIZE(%rdx, %rdi), %edx ++ subl %edx, %eax ++# endif ++# endif ++ ret ++ ++ .p2align 4 ++L(test_2_vec): ++# ifdef USE_AS_STRNCMP ++ /* The first 2 vectors matched. Return 0 if the maximum offset ++ (%r11) <= 2 * VEC_SIZE. */ ++ cmpq $(VEC_SIZE * 2), %r11 ++ jbe L(zero) ++# endif ++ ktestd %k6, %k6 ++ je L(test_3_vec) ++ kmovd %k6, %ecx ++ tzcntl %ecx, %edi ++# ifdef USE_AS_WCSCMP ++ /* NB: Multiply wchar_t count by 4 to get the number of bytes. */ ++ sall $2, %edi ++# endif ++# ifdef USE_AS_STRNCMP ++ addq $(VEC_SIZE * 2), %rdi ++ cmpq %rdi, %r11 ++ jbe L(zero) ++# ifdef USE_AS_WCSCMP ++ movq %rax, %rsi ++ xorl %eax, %eax ++ movl (%rsi, %rdi), %ecx ++ cmpl (%rdx, %rdi), %ecx ++ jne L(wcscmp_return) ++# else ++ movzbl (%rax, %rdi), %eax ++ movzbl (%rdx, %rdi), %edx ++ subl %edx, %eax ++# endif ++# else ++# ifdef USE_AS_WCSCMP ++ movq %rax, %rsi ++ xorl %eax, %eax ++ movl (VEC_SIZE * 2)(%rsi, %rdi), %ecx ++ cmpl (VEC_SIZE * 2)(%rdx, %rdi), %ecx ++ jne L(wcscmp_return) ++# else ++ movzbl (VEC_SIZE * 2)(%rax, %rdi), %eax ++ movzbl (VEC_SIZE * 2)(%rdx, %rdi), %edx ++ subl %edx, %eax ++# endif ++# endif ++ ret ++ ++ .p2align 4 ++L(test_3_vec): ++# ifdef USE_AS_STRNCMP ++ /* The first 3 vectors matched. Return 0 if the maximum offset ++ (%r11) <= 3 * VEC_SIZE. */ ++ cmpq $(VEC_SIZE * 3), %r11 ++ jbe L(zero) ++# endif ++ kmovd %k7, %esi ++ tzcntl %esi, %ecx ++# ifdef USE_AS_WCSCMP ++ /* NB: Multiply wchar_t count by 4 to get the number of bytes. */ ++ sall $2, %ecx ++# endif ++# ifdef USE_AS_STRNCMP ++ addq $(VEC_SIZE * 3), %rcx ++ cmpq %rcx, %r11 ++ jbe L(zero) ++# ifdef USE_AS_WCSCMP ++ movq %rax, %rsi ++ xorl %eax, %eax ++ movl (%rsi, %rcx), %esi ++ cmpl (%rdx, %rcx), %esi ++ jne L(wcscmp_return) ++# else ++ movzbl (%rax, %rcx), %eax ++ movzbl (%rdx, %rcx), %edx ++ subl %edx, %eax ++# endif ++# else ++# ifdef USE_AS_WCSCMP ++ movq %rax, %rsi ++ xorl %eax, %eax ++ movl (VEC_SIZE * 3)(%rsi, %rcx), %esi ++ cmpl (VEC_SIZE * 3)(%rdx, %rcx), %esi ++ jne L(wcscmp_return) ++# else ++ movzbl (VEC_SIZE * 3)(%rax, %rcx), %eax ++ movzbl (VEC_SIZE * 3)(%rdx, %rcx), %edx ++ subl %edx, %eax ++# endif ++# endif ++ ret ++ ++ .p2align 4 ++L(loop_cross_page): ++ xorl %r10d, %r10d ++ movq %rdx, %rcx ++ /* Align load via RDX. We load the extra ECX bytes which should ++ be ignored. */ ++ andl $((VEC_SIZE * 4) - 1), %ecx ++ /* R10 is -RCX. */ ++ subq %rcx, %r10 ++ ++ /* This works only if VEC_SIZE * 2 == 64. */ ++# if (VEC_SIZE * 2) != 64 ++# error (VEC_SIZE * 2) != 64 ++# endif ++ ++ /* Check if the first VEC_SIZE * 2 bytes should be ignored. */ ++ cmpl $(VEC_SIZE * 2), %ecx ++ jge L(loop_cross_page_2_vec) ++ ++ VMOVU (%rax, %r10), %YMM2 ++ VMOVU VEC_SIZE(%rax, %r10), %YMM3 ++ VMOVU (%rdx, %r10), %YMM4 ++ VMOVU VEC_SIZE(%rdx, %r10), %YMM5 ++ ++ VPCMP $4, %YMM4, %YMM2, %k0 ++ VPCMP $0, %YMMZERO, %YMM2, %k1 ++ VPCMP $0, %YMMZERO, %YMM4, %k2 ++ kord %k1, %k2, %k1 ++ /* Each bit in K1 represents a NULL or a mismatch in YMM2 and ++ YMM4. */ ++ kord %k0, %k1, %k1 ++ ++ VPCMP $4, %YMM5, %YMM3, %k3 ++ VPCMP $0, %YMMZERO, %YMM3, %k4 ++ VPCMP $0, %YMMZERO, %YMM5, %k5 ++ kord %k4, %k5, %k4 ++ /* Each bit in K3 represents a NULL or a mismatch in YMM3 and ++ YMM5. */ ++ kord %k3, %k4, %k3 ++ ++# ifdef USE_AS_WCSCMP ++ /* NB: Each bit in K1/K3 represents 4-byte element. */ ++ kshiftlw $8, %k3, %k2 ++ /* NB: Divide shift count by 4 since each bit in K1 represent 4 ++ bytes. */ ++ movl %ecx, %SHIFT_REG32 ++ sarl $2, %SHIFT_REG32 ++# else ++ kshiftlq $32, %k3, %k2 ++# endif ++ ++ /* Each bit in K1 represents a NULL or a mismatch. */ ++ korq %k1, %k2, %k1 ++ kmovq %k1, %rdi ++ ++ /* Since ECX < VEC_SIZE * 2, simply skip the first ECX bytes. */ ++ shrxq %SHIFT_REG64, %rdi, %rdi ++ testq %rdi, %rdi ++ je L(loop_cross_page_2_vec) ++ tzcntq %rdi, %rcx ++# ifdef USE_AS_WCSCMP ++ /* NB: Multiply wchar_t count by 4 to get the number of bytes. */ ++ sall $2, %ecx ++# endif ++# ifdef USE_AS_STRNCMP ++ cmpq %rcx, %r11 ++ jbe L(zero) ++# ifdef USE_AS_WCSCMP ++ movq %rax, %rsi ++ xorl %eax, %eax ++ movl (%rsi, %rcx), %edi ++ cmpl (%rdx, %rcx), %edi ++ jne L(wcscmp_return) ++# else ++ movzbl (%rax, %rcx), %eax ++ movzbl (%rdx, %rcx), %edx ++ subl %edx, %eax ++# endif ++# else ++# ifdef USE_AS_WCSCMP ++ movq %rax, %rsi ++ xorl %eax, %eax ++ movl (%rsi, %rcx), %edi ++ cmpl (%rdx, %rcx), %edi ++ jne L(wcscmp_return) ++# else ++ movzbl (%rax, %rcx), %eax ++ movzbl (%rdx, %rcx), %edx ++ subl %edx, %eax ++# endif ++# endif ++ ret ++ ++ .p2align 4 ++L(loop_cross_page_2_vec): ++ /* The first VEC_SIZE * 2 bytes match or are ignored. */ ++ VMOVU (VEC_SIZE * 2)(%rax, %r10), %YMM0 ++ VMOVU (VEC_SIZE * 3)(%rax, %r10), %YMM1 ++ VMOVU (VEC_SIZE * 2)(%rdx, %r10), %YMM2 ++ VMOVU (VEC_SIZE * 3)(%rdx, %r10), %YMM3 ++ ++ VPCMP $4, %YMM0, %YMM2, %k0 ++ VPCMP $0, %YMMZERO, %YMM0, %k1 ++ VPCMP $0, %YMMZERO, %YMM2, %k2 ++ kord %k1, %k2, %k1 ++ /* Each bit in K1 represents a NULL or a mismatch in YMM0 and ++ YMM2. */ ++ kord %k0, %k1, %k1 ++ ++ VPCMP $4, %YMM1, %YMM3, %k3 ++ VPCMP $0, %YMMZERO, %YMM1, %k4 ++ VPCMP $0, %YMMZERO, %YMM3, %k5 ++ kord %k4, %k5, %k4 ++ /* Each bit in K3 represents a NULL or a mismatch in YMM1 and ++ YMM3. */ ++ kord %k3, %k4, %k3 ++ ++# ifdef USE_AS_WCSCMP ++ /* NB: Each bit in K1/K3 represents 4-byte element. */ ++ kshiftlw $8, %k3, %k2 ++# else ++ kshiftlq $32, %k3, %k2 ++# endif ++ ++ /* Each bit in K1 represents a NULL or a mismatch. */ ++ korq %k1, %k2, %k1 ++ kmovq %k1, %rdi ++ ++ xorl %r8d, %r8d ++ /* If ECX > VEC_SIZE * 2, skip ECX - (VEC_SIZE * 2) bytes. */ ++ subl $(VEC_SIZE * 2), %ecx ++ jle 1f ++ /* R8 has number of bytes skipped. */ ++ movl %ecx, %r8d ++# ifdef USE_AS_WCSCMP ++ /* NB: Divide shift count by 4 since each bit in K1 represent 4 ++ bytes. */ ++ sarl $2, %ecx ++# endif ++ /* Skip ECX bytes. */ ++ shrq %cl, %rdi ++1: ++ /* Before jumping back to the loop, set ESI to the number of ++ VEC_SIZE * 4 blocks before page crossing. */ ++ movl $(PAGE_SIZE / (VEC_SIZE * 4) - 1), %esi ++ ++ testq %rdi, %rdi ++# ifdef USE_AS_STRNCMP ++ /* At this point, if %rdi value is 0, it already tested ++ VEC_SIZE*4+%r10 byte starting from %rax. This label ++ checks whether strncmp maximum offset reached or not. */ ++ je L(string_nbyte_offset_check) ++# else ++ je L(back_to_loop) ++# endif ++ tzcntq %rdi, %rcx ++# ifdef USE_AS_WCSCMP ++ /* NB: Multiply wchar_t count by 4 to get the number of bytes. */ ++ sall $2, %ecx ++# endif ++ addq %r10, %rcx ++ /* Adjust for number of bytes skipped. */ ++ addq %r8, %rcx ++# ifdef USE_AS_STRNCMP ++ addq $(VEC_SIZE * 2), %rcx ++ subq %rcx, %r11 ++ jbe L(zero) ++# ifdef USE_AS_WCSCMP ++ movq %rax, %rsi ++ xorl %eax, %eax ++ movl (%rsi, %rcx), %edi ++ cmpl (%rdx, %rcx), %edi ++ jne L(wcscmp_return) ++# else ++ movzbl (%rax, %rcx), %eax ++ movzbl (%rdx, %rcx), %edx ++ subl %edx, %eax ++# endif ++# else ++# ifdef USE_AS_WCSCMP ++ movq %rax, %rsi ++ xorl %eax, %eax ++ movl (VEC_SIZE * 2)(%rsi, %rcx), %edi ++ cmpl (VEC_SIZE * 2)(%rdx, %rcx), %edi ++ jne L(wcscmp_return) ++# else ++ movzbl (VEC_SIZE * 2)(%rax, %rcx), %eax ++ movzbl (VEC_SIZE * 2)(%rdx, %rcx), %edx ++ subl %edx, %eax ++# endif ++# endif ++ ret ++ ++# ifdef USE_AS_STRNCMP ++L(string_nbyte_offset_check): ++ leaq (VEC_SIZE * 4)(%r10), %r10 ++ cmpq %r10, %r11 ++ jbe L(zero) ++ jmp L(back_to_loop) ++# endif ++ ++ .p2align 4 ++L(cross_page_loop): ++ /* Check one byte/dword at a time. */ ++# ifdef USE_AS_WCSCMP ++ cmpl %ecx, %eax ++# else ++ subl %ecx, %eax ++# endif ++ jne L(different) ++ addl $SIZE_OF_CHAR, %edx ++ cmpl $(VEC_SIZE * 4), %edx ++ je L(main_loop_header) ++# ifdef USE_AS_STRNCMP ++ cmpq %r11, %rdx ++ jae L(zero) ++# endif ++# ifdef USE_AS_WCSCMP ++ movl (%rdi, %rdx), %eax ++ movl (%rsi, %rdx), %ecx ++# else ++ movzbl (%rdi, %rdx), %eax ++ movzbl (%rsi, %rdx), %ecx ++# endif ++ /* Check null char. */ ++ testl %eax, %eax ++ jne L(cross_page_loop) ++ /* Since %eax == 0, subtract is OK for both SIGNED and UNSIGNED ++ comparisons. */ ++ subl %ecx, %eax ++# ifndef USE_AS_WCSCMP ++L(different): ++# endif ++ ret ++ ++# ifdef USE_AS_WCSCMP ++ .p2align 4 ++L(different): ++ /* Use movl to avoid modifying EFLAGS. */ ++ movl $0, %eax ++ setl %al ++ negl %eax ++ orl $1, %eax ++ ret ++# endif ++ ++# ifdef USE_AS_STRNCMP ++ .p2align 4 ++L(zero): ++ xorl %eax, %eax ++ ret ++ ++ .p2align 4 ++L(char0): ++# ifdef USE_AS_WCSCMP ++ xorl %eax, %eax ++ movl (%rdi), %ecx ++ cmpl (%rsi), %ecx ++ jne L(wcscmp_return) ++# else ++ movzbl (%rsi), %ecx ++ movzbl (%rdi), %eax ++ subl %ecx, %eax ++# endif ++ ret ++# endif ++ ++ .p2align 4 ++L(last_vector): ++ addq %rdx, %rdi ++ addq %rdx, %rsi ++# ifdef USE_AS_STRNCMP ++ subq %rdx, %r11 ++# endif ++ tzcntl %ecx, %edx ++# ifdef USE_AS_WCSCMP ++ /* NB: Multiply wchar_t count by 4 to get the number of bytes. */ ++ sall $2, %edx ++# endif ++# ifdef USE_AS_STRNCMP ++ cmpq %r11, %rdx ++ jae L(zero) ++# endif ++# ifdef USE_AS_WCSCMP ++ xorl %eax, %eax ++ movl (%rdi, %rdx), %ecx ++ cmpl (%rsi, %rdx), %ecx ++ jne L(wcscmp_return) ++# else ++ movzbl (%rdi, %rdx), %eax ++ movzbl (%rsi, %rdx), %edx ++ subl %edx, %eax ++# endif ++ ret ++ ++ /* Comparing on page boundary region requires special treatment: ++ It must done one vector at the time, starting with the wider ++ ymm vector if possible, if not, with xmm. If fetching 16 bytes ++ (xmm) still passes the boundary, byte comparison must be done. ++ */ ++ .p2align 4 ++L(cross_page): ++ /* Try one ymm vector at a time. */ ++ cmpl $(PAGE_SIZE - VEC_SIZE), %eax ++ jg L(cross_page_1_vector) ++L(loop_1_vector): ++ VMOVU (%rdi, %rdx), %YMM0 ++ VMOVU (%rsi, %rdx), %YMM1 ++ ++ /* Each bit in K0 represents a mismatch in YMM0 and YMM1. */ ++ VPCMP $4, %YMM0, %YMM1, %k0 ++ VPCMP $0, %YMMZERO, %YMM0, %k1 ++ VPCMP $0, %YMMZERO, %YMM1, %k2 ++ /* Each bit in K1 represents a NULL in YMM0 or YMM1. */ ++ kord %k1, %k2, %k1 ++ /* Each bit in K1 represents a NULL or a mismatch. */ ++ kord %k0, %k1, %k1 ++ kmovd %k1, %ecx ++ testl %ecx, %ecx ++ jne L(last_vector) ++ ++ addl $VEC_SIZE, %edx ++ ++ addl $VEC_SIZE, %eax ++# ifdef USE_AS_STRNCMP ++ /* Return 0 if the current offset (%rdx) >= the maximum offset ++ (%r11). */ ++ cmpq %r11, %rdx ++ jae L(zero) ++# endif ++ cmpl $(PAGE_SIZE - VEC_SIZE), %eax ++ jle L(loop_1_vector) ++L(cross_page_1_vector): ++ /* Less than 32 bytes to check, try one xmm vector. */ ++ cmpl $(PAGE_SIZE - 16), %eax ++ jg L(cross_page_1_xmm) ++ VMOVU (%rdi, %rdx), %XMM0 ++ VMOVU (%rsi, %rdx), %XMM1 ++ ++ /* Each bit in K0 represents a mismatch in XMM0 and XMM1. */ ++ VPCMP $4, %XMM0, %XMM1, %k0 ++ VPCMP $0, %XMMZERO, %XMM0, %k1 ++ VPCMP $0, %XMMZERO, %XMM1, %k2 ++ /* Each bit in K1 represents a NULL in XMM0 or XMM1. */ ++ korw %k1, %k2, %k1 ++ /* Each bit in K1 represents a NULL or a mismatch. */ ++ korw %k0, %k1, %k1 ++ kmovw %k1, %ecx ++ testl %ecx, %ecx ++ jne L(last_vector) ++ ++ addl $16, %edx ++# ifndef USE_AS_WCSCMP ++ addl $16, %eax ++# endif ++# ifdef USE_AS_STRNCMP ++ /* Return 0 if the current offset (%rdx) >= the maximum offset ++ (%r11). */ ++ cmpq %r11, %rdx ++ jae L(zero) ++# endif ++ ++L(cross_page_1_xmm): ++# ifndef USE_AS_WCSCMP ++ /* Less than 16 bytes to check, try 8 byte vector. NB: No need ++ for wcscmp nor wcsncmp since wide char is 4 bytes. */ ++ cmpl $(PAGE_SIZE - 8), %eax ++ jg L(cross_page_8bytes) ++ vmovq (%rdi, %rdx), %XMM0 ++ vmovq (%rsi, %rdx), %XMM1 ++ ++ /* Each bit in K0 represents a mismatch in XMM0 and XMM1. */ ++ VPCMP $4, %XMM0, %XMM1, %k0 ++ VPCMP $0, %XMMZERO, %XMM0, %k1 ++ VPCMP $0, %XMMZERO, %XMM1, %k2 ++ /* Each bit in K1 represents a NULL in XMM0 or XMM1. */ ++ kord %k1, %k2, %k1 ++ /* Each bit in K1 represents a NULL or a mismatch. */ ++ kord %k0, %k1, %k1 ++ kmovd %k1, %ecx ++ ++# ifdef USE_AS_WCSCMP ++ /* Only last 2 bits are valid. */ ++ andl $0x3, %ecx ++# else ++ /* Only last 8 bits are valid. */ ++ andl $0xff, %ecx ++# endif ++ ++ testl %ecx, %ecx ++ jne L(last_vector) ++ ++ addl $8, %edx ++ addl $8, %eax ++# ifdef USE_AS_STRNCMP ++ /* Return 0 if the current offset (%rdx) >= the maximum offset ++ (%r11). */ ++ cmpq %r11, %rdx ++ jae L(zero) ++# endif ++ ++L(cross_page_8bytes): ++ /* Less than 8 bytes to check, try 4 byte vector. */ ++ cmpl $(PAGE_SIZE - 4), %eax ++ jg L(cross_page_4bytes) ++ vmovd (%rdi, %rdx), %XMM0 ++ vmovd (%rsi, %rdx), %XMM1 ++ ++ /* Each bit in K0 represents a mismatch in XMM0 and XMM1. */ ++ VPCMP $4, %XMM0, %XMM1, %k0 ++ VPCMP $0, %XMMZERO, %XMM0, %k1 ++ VPCMP $0, %XMMZERO, %XMM1, %k2 ++ /* Each bit in K1 represents a NULL in XMM0 or XMM1. */ ++ kord %k1, %k2, %k1 ++ /* Each bit in K1 represents a NULL or a mismatch. */ ++ kord %k0, %k1, %k1 ++ kmovd %k1, %ecx ++ ++# ifdef USE_AS_WCSCMP ++ /* Only the last bit is valid. */ ++ andl $0x1, %ecx ++# else ++ /* Only last 4 bits are valid. */ ++ andl $0xf, %ecx ++# endif ++ ++ testl %ecx, %ecx ++ jne L(last_vector) ++ ++ addl $4, %edx ++# ifdef USE_AS_STRNCMP ++ /* Return 0 if the current offset (%rdx) >= the maximum offset ++ (%r11). */ ++ cmpq %r11, %rdx ++ jae L(zero) ++# endif ++ ++L(cross_page_4bytes): ++# endif ++ /* Less than 4 bytes to check, try one byte/dword at a time. */ ++# ifdef USE_AS_STRNCMP ++ cmpq %r11, %rdx ++ jae L(zero) ++# endif ++# ifdef USE_AS_WCSCMP ++ movl (%rdi, %rdx), %eax ++ movl (%rsi, %rdx), %ecx ++# else ++ movzbl (%rdi, %rdx), %eax ++ movzbl (%rsi, %rdx), %ecx ++# endif ++ testl %eax, %eax ++ jne L(cross_page_loop) ++ subl %ecx, %eax ++ ret ++END (STRCMP) ++#endif +diff --git a/sysdeps/x86_64/multiarch/strcmp.c b/sysdeps/x86_64/multiarch/strcmp.c +index 3f433fbc..c5f38510 100644 +--- a/sysdeps/x86_64/multiarch/strcmp.c ++++ b/sysdeps/x86_64/multiarch/strcmp.c +@@ -30,16 +30,25 @@ extern __typeof (REDIRECT_NAME) OPTIMIZE (sse2) attribute_hidden; + extern __typeof (REDIRECT_NAME) OPTIMIZE (sse2_unaligned) attribute_hidden; + extern __typeof (REDIRECT_NAME) OPTIMIZE (ssse3) attribute_hidden; + extern __typeof (REDIRECT_NAME) OPTIMIZE (avx2) attribute_hidden; ++extern __typeof (REDIRECT_NAME) OPTIMIZE (evex) attribute_hidden; + + static inline void * + IFUNC_SELECTOR (void) + { + const struct cpu_features* cpu_features = __get_cpu_features (); + +- if (!CPU_FEATURES_ARCH_P (cpu_features, Prefer_No_VZEROUPPER) +- && CPU_FEATURE_USABLE_P (cpu_features, AVX2) ++ if (CPU_FEATURE_USABLE_P (cpu_features, AVX2) + && CPU_FEATURES_ARCH_P (cpu_features, AVX_Fast_Unaligned_Load)) +- return OPTIMIZE (avx2); ++ { ++ if (CPU_FEATURE_USABLE_P (cpu_features, AVX512VL) ++ && CPU_FEATURE_USABLE_P (cpu_features, AVX512BW) ++ && CPU_FEATURE_USABLE_P (cpu_features, BMI2) ++ && !CPU_FEATURES_ARCH_P (cpu_features, Prefer_AVX2_STRCMP)) ++ return OPTIMIZE (evex); ++ ++ if (!CPU_FEATURES_ARCH_P (cpu_features, Prefer_No_VZEROUPPER)) ++ return OPTIMIZE (avx2); ++ } + + if (CPU_FEATURES_ARCH_P (cpu_features, Fast_Unaligned_Load)) + return OPTIMIZE (sse2_unaligned); +diff --git a/sysdeps/x86_64/multiarch/strlen-evex.S b/sysdeps/x86_64/multiarch/strlen-evex.S +new file mode 100644 +index 00000000..cd022509 +--- /dev/null ++++ b/sysdeps/x86_64/multiarch/strlen-evex.S +@@ -0,0 +1,436 @@ ++/* strlen/strnlen/wcslen/wcsnlen optimized with 256-bit EVEX instructions. ++ 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 ++ . */ ++ ++#if IS_IN (libc) ++ ++# include ++ ++# ifndef STRLEN ++# define STRLEN __strlen_evex ++# endif ++ ++# define VMOVA vmovdqa64 ++ ++# ifdef USE_AS_WCSLEN ++# define VPCMP vpcmpd ++# define VPMINU vpminud ++# define SHIFT_REG r9d ++# else ++# define VPCMP vpcmpb ++# define VPMINU vpminub ++# define SHIFT_REG ecx ++# endif ++ ++# define XMMZERO xmm16 ++# define YMMZERO ymm16 ++# define YMM1 ymm17 ++# define YMM2 ymm18 ++# define YMM3 ymm19 ++# define YMM4 ymm20 ++# define YMM5 ymm21 ++# define YMM6 ymm22 ++ ++# define VEC_SIZE 32 ++ ++ .section .text.evex,"ax",@progbits ++ENTRY (STRLEN) ++# ifdef USE_AS_STRNLEN ++ /* Check for zero length. */ ++ test %RSI_LP, %RSI_LP ++ jz L(zero) ++# ifdef USE_AS_WCSLEN ++ shl $2, %RSI_LP ++# elif defined __ILP32__ ++ /* Clear the upper 32 bits. */ ++ movl %esi, %esi ++# endif ++ mov %RSI_LP, %R8_LP ++# endif ++ movl %edi, %ecx ++ movq %rdi, %rdx ++ vpxorq %XMMZERO, %XMMZERO, %XMMZERO ++ ++ /* Check if we may cross page boundary with one vector load. */ ++ andl $(2 * VEC_SIZE - 1), %ecx ++ cmpl $VEC_SIZE, %ecx ++ ja L(cros_page_boundary) ++ ++ /* Check the first VEC_SIZE bytes. Each bit in K0 represents a ++ null byte. */ ++ VPCMP $0, (%rdi), %YMMZERO, %k0 ++ kmovd %k0, %eax ++ testl %eax, %eax ++ ++# ifdef USE_AS_STRNLEN ++ jnz L(first_vec_x0_check) ++ /* Adjust length and check the end of data. */ ++ subq $VEC_SIZE, %rsi ++ jbe L(max) ++# else ++ jnz L(first_vec_x0) ++# endif ++ ++ /* Align data for aligned loads in the loop. */ ++ addq $VEC_SIZE, %rdi ++ andl $(VEC_SIZE - 1), %ecx ++ andq $-VEC_SIZE, %rdi ++ ++# ifdef USE_AS_STRNLEN ++ /* Adjust length. */ ++ addq %rcx, %rsi ++ ++ subq $(VEC_SIZE * 4), %rsi ++ jbe L(last_4x_vec_or_less) ++# endif ++ jmp L(more_4x_vec) ++ ++ .p2align 4 ++L(cros_page_boundary): ++ andl $(VEC_SIZE - 1), %ecx ++ andq $-VEC_SIZE, %rdi ++ ++# ifdef USE_AS_WCSLEN ++ /* NB: Divide shift count by 4 since each bit in K0 represent 4 ++ bytes. */ ++ movl %ecx, %SHIFT_REG ++ sarl $2, %SHIFT_REG ++# endif ++ VPCMP $0, (%rdi), %YMMZERO, %k0 ++ kmovd %k0, %eax ++ ++ /* Remove the leading bytes. */ ++ sarxl %SHIFT_REG, %eax, %eax ++ testl %eax, %eax ++ jz L(aligned_more) ++ tzcntl %eax, %eax ++# ifdef USE_AS_WCSLEN ++ /* NB: Multiply wchar_t count by 4 to get the number of bytes. */ ++ sall $2, %eax ++# endif ++# ifdef USE_AS_STRNLEN ++ /* Check the end of data. */ ++ cmpq %rax, %rsi ++ jbe L(max) ++# endif ++ addq %rdi, %rax ++ addq %rcx, %rax ++ subq %rdx, %rax ++# ifdef USE_AS_WCSLEN ++ shrq $2, %rax ++# endif ++ ret ++ ++ .p2align 4 ++L(aligned_more): ++# ifdef USE_AS_STRNLEN ++ /* "rcx" is less than VEC_SIZE. Calculate "rdx + rcx - VEC_SIZE" ++ with "rdx - (VEC_SIZE - rcx)" instead of "(rdx + rcx) - VEC_SIZE" ++ to void possible addition overflow. */ ++ negq %rcx ++ addq $VEC_SIZE, %rcx ++ ++ /* Check the end of data. */ ++ subq %rcx, %rsi ++ jbe L(max) ++# endif ++ ++ addq $VEC_SIZE, %rdi ++ ++# ifdef USE_AS_STRNLEN ++ subq $(VEC_SIZE * 4), %rsi ++ jbe L(last_4x_vec_or_less) ++# endif ++ ++L(more_4x_vec): ++ /* Check the first 4 * VEC_SIZE. Only one VEC_SIZE at a time ++ since data is only aligned to VEC_SIZE. */ ++ VPCMP $0, (%rdi), %YMMZERO, %k0 ++ kmovd %k0, %eax ++ testl %eax, %eax ++ jnz L(first_vec_x0) ++ ++ VPCMP $0, VEC_SIZE(%rdi), %YMMZERO, %k0 ++ kmovd %k0, %eax ++ testl %eax, %eax ++ jnz L(first_vec_x1) ++ ++ VPCMP $0, (VEC_SIZE * 2)(%rdi), %YMMZERO, %k0 ++ kmovd %k0, %eax ++ testl %eax, %eax ++ jnz L(first_vec_x2) ++ ++ VPCMP $0, (VEC_SIZE * 3)(%rdi), %YMMZERO, %k0 ++ kmovd %k0, %eax ++ testl %eax, %eax ++ jnz L(first_vec_x3) ++ ++ addq $(VEC_SIZE * 4), %rdi ++ ++# ifdef USE_AS_STRNLEN ++ subq $(VEC_SIZE * 4), %rsi ++ jbe L(last_4x_vec_or_less) ++# endif ++ ++ /* Align data to 4 * VEC_SIZE. */ ++ movq %rdi, %rcx ++ andl $(4 * VEC_SIZE - 1), %ecx ++ andq $-(4 * VEC_SIZE), %rdi ++ ++# ifdef USE_AS_STRNLEN ++ /* Adjust length. */ ++ addq %rcx, %rsi ++# endif ++ ++ .p2align 4 ++L(loop_4x_vec): ++ /* Compare 4 * VEC at a time forward. */ ++ VMOVA (%rdi), %YMM1 ++ VMOVA VEC_SIZE(%rdi), %YMM2 ++ VMOVA (VEC_SIZE * 2)(%rdi), %YMM3 ++ VMOVA (VEC_SIZE * 3)(%rdi), %YMM4 ++ ++ VPMINU %YMM1, %YMM2, %YMM5 ++ VPMINU %YMM3, %YMM4, %YMM6 ++ ++ VPMINU %YMM5, %YMM6, %YMM5 ++ VPCMP $0, %YMM5, %YMMZERO, %k0 ++ ktestd %k0, %k0 ++ jnz L(4x_vec_end) ++ ++ addq $(VEC_SIZE * 4), %rdi ++ ++# ifndef USE_AS_STRNLEN ++ jmp L(loop_4x_vec) ++# else ++ subq $(VEC_SIZE * 4), %rsi ++ ja L(loop_4x_vec) ++ ++L(last_4x_vec_or_less): ++ /* Less than 4 * VEC and aligned to VEC_SIZE. */ ++ addl $(VEC_SIZE * 2), %esi ++ jle L(last_2x_vec) ++ ++ VPCMP $0, (%rdi), %YMMZERO, %k0 ++ kmovd %k0, %eax ++ testl %eax, %eax ++ jnz L(first_vec_x0) ++ ++ VPCMP $0, VEC_SIZE(%rdi), %YMMZERO, %k0 ++ kmovd %k0, %eax ++ testl %eax, %eax ++ jnz L(first_vec_x1) ++ ++ VPCMP $0, (VEC_SIZE * 2)(%rdi), %YMMZERO, %k0 ++ kmovd %k0, %eax ++ testl %eax, %eax ++ jnz L(first_vec_x2_check) ++ subl $VEC_SIZE, %esi ++ jle L(max) ++ ++ VPCMP $0, (VEC_SIZE * 3)(%rdi), %YMMZERO, %k0 ++ kmovd %k0, %eax ++ testl %eax, %eax ++ jnz L(first_vec_x3_check) ++ movq %r8, %rax ++# ifdef USE_AS_WCSLEN ++ shrq $2, %rax ++# endif ++ ret ++ ++ .p2align 4 ++L(last_2x_vec): ++ addl $(VEC_SIZE * 2), %esi ++ ++ VPCMP $0, (%rdi), %YMMZERO, %k0 ++ kmovd %k0, %eax ++ testl %eax, %eax ++ jnz L(first_vec_x0_check) ++ subl $VEC_SIZE, %esi ++ jle L(max) ++ ++ VPCMP $0, VEC_SIZE(%rdi), %YMMZERO, %k0 ++ kmovd %k0, %eax ++ testl %eax, %eax ++ jnz L(first_vec_x1_check) ++ movq %r8, %rax ++# ifdef USE_AS_WCSLEN ++ shrq $2, %rax ++# endif ++ ret ++ ++ .p2align 4 ++L(first_vec_x0_check): ++ tzcntl %eax, %eax ++# ifdef USE_AS_WCSLEN ++ /* NB: Multiply wchar_t count by 4 to get the number of bytes. */ ++ sall $2, %eax ++# endif ++ /* Check the end of data. */ ++ cmpq %rax, %rsi ++ jbe L(max) ++ addq %rdi, %rax ++ subq %rdx, %rax ++# ifdef USE_AS_WCSLEN ++ shrq $2, %rax ++# endif ++ ret ++ ++ .p2align 4 ++L(first_vec_x1_check): ++ tzcntl %eax, %eax ++# ifdef USE_AS_WCSLEN ++ /* NB: Multiply wchar_t count by 4 to get the number of bytes. */ ++ sall $2, %eax ++# endif ++ /* Check the end of data. */ ++ cmpq %rax, %rsi ++ jbe L(max) ++ addq $VEC_SIZE, %rax ++ addq %rdi, %rax ++ subq %rdx, %rax ++# ifdef USE_AS_WCSLEN ++ shrq $2, %rax ++# endif ++ ret ++ ++ .p2align 4 ++L(first_vec_x2_check): ++ tzcntl %eax, %eax ++# ifdef USE_AS_WCSLEN ++ /* NB: Multiply wchar_t count by 4 to get the number of bytes. */ ++ sall $2, %eax ++# endif ++ /* Check the end of data. */ ++ cmpq %rax, %rsi ++ jbe L(max) ++ addq $(VEC_SIZE * 2), %rax ++ addq %rdi, %rax ++ subq %rdx, %rax ++# ifdef USE_AS_WCSLEN ++ shrq $2, %rax ++# endif ++ ret ++ ++ .p2align 4 ++L(first_vec_x3_check): ++ tzcntl %eax, %eax ++# ifdef USE_AS_WCSLEN ++ /* NB: Multiply wchar_t count by 4 to get the number of bytes. */ ++ sall $2, %eax ++# endif ++ /* Check the end of data. */ ++ cmpq %rax, %rsi ++ jbe L(max) ++ addq $(VEC_SIZE * 3), %rax ++ addq %rdi, %rax ++ subq %rdx, %rax ++# ifdef USE_AS_WCSLEN ++ shrq $2, %rax ++# endif ++ ret ++ ++ .p2align 4 ++L(max): ++ movq %r8, %rax ++# ifdef USE_AS_WCSLEN ++ shrq $2, %rax ++# endif ++ ret ++ ++ .p2align 4 ++L(zero): ++ xorl %eax, %eax ++ ret ++# endif ++ ++ .p2align 4 ++L(first_vec_x0): ++ tzcntl %eax, %eax ++# ifdef USE_AS_WCSLEN ++ /* NB: Multiply wchar_t count by 4 to get the number of bytes. */ ++ sall $2, %eax ++# endif ++ addq %rdi, %rax ++ subq %rdx, %rax ++# ifdef USE_AS_WCSLEN ++ shrq $2, %rax ++# endif ++ ret ++ ++ .p2align 4 ++L(first_vec_x1): ++ tzcntl %eax, %eax ++# ifdef USE_AS_WCSLEN ++ /* NB: Multiply wchar_t count by 4 to get the number of bytes. */ ++ sall $2, %eax ++# endif ++ addq $VEC_SIZE, %rax ++ addq %rdi, %rax ++ subq %rdx, %rax ++# ifdef USE_AS_WCSLEN ++ shrq $2, %rax ++# endif ++ ret ++ ++ .p2align 4 ++L(first_vec_x2): ++ tzcntl %eax, %eax ++# ifdef USE_AS_WCSLEN ++ /* NB: Multiply wchar_t count by 4 to get the number of bytes. */ ++ sall $2, %eax ++# endif ++ addq $(VEC_SIZE * 2), %rax ++ addq %rdi, %rax ++ subq %rdx, %rax ++# ifdef USE_AS_WCSLEN ++ shrq $2, %rax ++# endif ++ ret ++ ++ .p2align 4 ++L(4x_vec_end): ++ VPCMP $0, %YMM1, %YMMZERO, %k0 ++ kmovd %k0, %eax ++ testl %eax, %eax ++ jnz L(first_vec_x0) ++ VPCMP $0, %YMM2, %YMMZERO, %k1 ++ kmovd %k1, %eax ++ testl %eax, %eax ++ jnz L(first_vec_x1) ++ VPCMP $0, %YMM3, %YMMZERO, %k2 ++ kmovd %k2, %eax ++ testl %eax, %eax ++ jnz L(first_vec_x2) ++ VPCMP $0, %YMM4, %YMMZERO, %k3 ++ kmovd %k3, %eax ++L(first_vec_x3): ++ tzcntl %eax, %eax ++# ifdef USE_AS_WCSLEN ++ /* NB: Multiply wchar_t count by 4 to get the number of bytes. */ ++ sall $2, %eax ++# endif ++ addq $(VEC_SIZE * 3), %rax ++ addq %rdi, %rax ++ subq %rdx, %rax ++# ifdef USE_AS_WCSLEN ++ shrq $2, %rax ++# endif ++ ret ++ ++END (STRLEN) ++#endif +diff --git a/sysdeps/x86_64/multiarch/strncmp-evex.S b/sysdeps/x86_64/multiarch/strncmp-evex.S +new file mode 100644 +index 00000000..a1d53e8c +--- /dev/null ++++ b/sysdeps/x86_64/multiarch/strncmp-evex.S +@@ -0,0 +1,3 @@ ++#define STRCMP __strncmp_evex ++#define USE_AS_STRNCMP 1 ++#include "strcmp-evex.S" +diff --git a/sysdeps/x86_64/multiarch/strncmp.c b/sysdeps/x86_64/multiarch/strncmp.c +index 686d654f..4c15542f 100644 +--- a/sysdeps/x86_64/multiarch/strncmp.c ++++ b/sysdeps/x86_64/multiarch/strncmp.c +@@ -30,16 +30,25 @@ extern __typeof (REDIRECT_NAME) OPTIMIZE (sse2) attribute_hidden; + extern __typeof (REDIRECT_NAME) OPTIMIZE (ssse3) attribute_hidden; + extern __typeof (REDIRECT_NAME) OPTIMIZE (sse42) attribute_hidden; + extern __typeof (REDIRECT_NAME) OPTIMIZE (avx2) attribute_hidden; ++extern __typeof (REDIRECT_NAME) OPTIMIZE (evex) attribute_hidden; + + static inline void * + IFUNC_SELECTOR (void) + { + const struct cpu_features* cpu_features = __get_cpu_features (); + +- if (!CPU_FEATURES_ARCH_P (cpu_features, Prefer_No_VZEROUPPER) +- && CPU_FEATURE_USABLE_P (cpu_features, AVX2) ++ if (CPU_FEATURE_USABLE_P (cpu_features, AVX2) + && CPU_FEATURES_ARCH_P (cpu_features, AVX_Fast_Unaligned_Load)) +- return OPTIMIZE (avx2); ++ { ++ if (CPU_FEATURE_USABLE_P (cpu_features, AVX512VL) ++ && CPU_FEATURE_USABLE_P (cpu_features, AVX512BW) ++ && CPU_FEATURE_USABLE_P (cpu_features, BMI2) ++ && !CPU_FEATURES_ARCH_P (cpu_features, Prefer_AVX2_STRCMP)) ++ return OPTIMIZE (evex); ++ ++ if (!CPU_FEATURES_ARCH_P (cpu_features, Prefer_No_VZEROUPPER)) ++ return OPTIMIZE (avx2); ++ } + + if (CPU_FEATURE_USABLE_P (cpu_features, SSE4_2) + && !CPU_FEATURES_ARCH_P (cpu_features, Slow_SSE4_2)) +diff --git a/sysdeps/x86_64/multiarch/strnlen-evex.S b/sysdeps/x86_64/multiarch/strnlen-evex.S +new file mode 100644 +index 00000000..722022f3 +--- /dev/null ++++ b/sysdeps/x86_64/multiarch/strnlen-evex.S +@@ -0,0 +1,4 @@ ++#define STRLEN __strnlen_evex ++#define USE_AS_STRNLEN 1 ++ ++#include "strlen-evex.S" +diff --git a/sysdeps/x86_64/multiarch/strrchr-evex.S b/sysdeps/x86_64/multiarch/strrchr-evex.S +new file mode 100644 +index 00000000..f920b5a5 +--- /dev/null ++++ b/sysdeps/x86_64/multiarch/strrchr-evex.S +@@ -0,0 +1,265 @@ ++/* strrchr/wcsrchr optimized with 256-bit EVEX instructions. ++ 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 ++ . */ ++ ++#if IS_IN (libc) ++ ++# include ++ ++# ifndef STRRCHR ++# define STRRCHR __strrchr_evex ++# endif ++ ++# define VMOVU vmovdqu64 ++# define VMOVA vmovdqa64 ++ ++# ifdef USE_AS_WCSRCHR ++# define VPBROADCAST vpbroadcastd ++# define VPCMP vpcmpd ++# define SHIFT_REG r8d ++# else ++# define VPBROADCAST vpbroadcastb ++# define VPCMP vpcmpb ++# define SHIFT_REG ecx ++# endif ++ ++# define XMMZERO xmm16 ++# define YMMZERO ymm16 ++# define YMMMATCH ymm17 ++# define YMM1 ymm18 ++ ++# define VEC_SIZE 32 ++ ++ .section .text.evex,"ax",@progbits ++ENTRY (STRRCHR) ++ movl %edi, %ecx ++ /* Broadcast CHAR to YMMMATCH. */ ++ VPBROADCAST %esi, %YMMMATCH ++ ++ vpxorq %XMMZERO, %XMMZERO, %XMMZERO ++ ++ /* Check if we may cross page boundary with one vector load. */ ++ andl $(2 * VEC_SIZE - 1), %ecx ++ cmpl $VEC_SIZE, %ecx ++ ja L(cros_page_boundary) ++ ++ VMOVU (%rdi), %YMM1 ++ ++ /* Each bit in K0 represents a null byte in YMM1. */ ++ VPCMP $0, %YMMZERO, %YMM1, %k0 ++ /* Each bit in K1 represents a CHAR in YMM1. */ ++ VPCMP $0, %YMMMATCH, %YMM1, %k1 ++ kmovd %k0, %ecx ++ kmovd %k1, %eax ++ ++ addq $VEC_SIZE, %rdi ++ ++ testl %eax, %eax ++ jnz L(first_vec) ++ ++ testl %ecx, %ecx ++ jnz L(return_null) ++ ++ andq $-VEC_SIZE, %rdi ++ xorl %edx, %edx ++ jmp L(aligned_loop) ++ ++ .p2align 4 ++L(first_vec): ++ /* Check if there is a null byte. */ ++ testl %ecx, %ecx ++ jnz L(char_and_nul_in_first_vec) ++ ++ /* Remember the match and keep searching. */ ++ movl %eax, %edx ++ movq %rdi, %rsi ++ andq $-VEC_SIZE, %rdi ++ jmp L(aligned_loop) ++ ++ .p2align 4 ++L(cros_page_boundary): ++ andl $(VEC_SIZE - 1), %ecx ++ andq $-VEC_SIZE, %rdi ++ ++# ifdef USE_AS_WCSRCHR ++ /* NB: Divide shift count by 4 since each bit in K1 represent 4 ++ bytes. */ ++ movl %ecx, %SHIFT_REG ++ sarl $2, %SHIFT_REG ++# endif ++ ++ VMOVA (%rdi), %YMM1 ++ ++ /* Each bit in K0 represents a null byte in YMM1. */ ++ VPCMP $0, %YMMZERO, %YMM1, %k0 ++ /* Each bit in K1 represents a CHAR in YMM1. */ ++ VPCMP $0, %YMMMATCH, %YMM1, %k1 ++ kmovd %k0, %edx ++ kmovd %k1, %eax ++ ++ shrxl %SHIFT_REG, %edx, %edx ++ shrxl %SHIFT_REG, %eax, %eax ++ addq $VEC_SIZE, %rdi ++ ++ /* Check if there is a CHAR. */ ++ testl %eax, %eax ++ jnz L(found_char) ++ ++ testl %edx, %edx ++ jnz L(return_null) ++ ++ jmp L(aligned_loop) ++ ++ .p2align 4 ++L(found_char): ++ testl %edx, %edx ++ jnz L(char_and_nul) ++ ++ /* Remember the match and keep searching. */ ++ movl %eax, %edx ++ leaq (%rdi, %rcx), %rsi ++ ++ .p2align 4 ++L(aligned_loop): ++ VMOVA (%rdi), %YMM1 ++ addq $VEC_SIZE, %rdi ++ ++ /* Each bit in K0 represents a null byte in YMM1. */ ++ VPCMP $0, %YMMZERO, %YMM1, %k0 ++ /* Each bit in K1 represents a CHAR in YMM1. */ ++ VPCMP $0, %YMMMATCH, %YMM1, %k1 ++ kmovd %k0, %ecx ++ kmovd %k1, %eax ++ orl %eax, %ecx ++ jnz L(char_nor_null) ++ ++ VMOVA (%rdi), %YMM1 ++ add $VEC_SIZE, %rdi ++ ++ /* Each bit in K0 represents a null byte in YMM1. */ ++ VPCMP $0, %YMMZERO, %YMM1, %k0 ++ /* Each bit in K1 represents a CHAR in YMM1. */ ++ VPCMP $0, %YMMMATCH, %YMM1, %k1 ++ kmovd %k0, %ecx ++ kmovd %k1, %eax ++ orl %eax, %ecx ++ jnz L(char_nor_null) ++ ++ VMOVA (%rdi), %YMM1 ++ addq $VEC_SIZE, %rdi ++ ++ /* Each bit in K0 represents a null byte in YMM1. */ ++ VPCMP $0, %YMMZERO, %YMM1, %k0 ++ /* Each bit in K1 represents a CHAR in YMM1. */ ++ VPCMP $0, %YMMMATCH, %YMM1, %k1 ++ kmovd %k0, %ecx ++ kmovd %k1, %eax ++ orl %eax, %ecx ++ jnz L(char_nor_null) ++ ++ VMOVA (%rdi), %YMM1 ++ addq $VEC_SIZE, %rdi ++ ++ /* Each bit in K0 represents a null byte in YMM1. */ ++ VPCMP $0, %YMMZERO, %YMM1, %k0 ++ /* Each bit in K1 represents a CHAR in YMM1. */ ++ VPCMP $0, %YMMMATCH, %YMM1, %k1 ++ kmovd %k0, %ecx ++ kmovd %k1, %eax ++ orl %eax, %ecx ++ jz L(aligned_loop) ++ ++ .p2align 4 ++L(char_nor_null): ++ /* Find a CHAR or a null byte in a loop. */ ++ testl %eax, %eax ++ jnz L(match) ++L(return_value): ++ testl %edx, %edx ++ jz L(return_null) ++ movl %edx, %eax ++ movq %rsi, %rdi ++ bsrl %eax, %eax ++# ifdef USE_AS_WCSRCHR ++ /* NB: Multiply wchar_t count by 4 to get the number of bytes. */ ++ leaq -VEC_SIZE(%rdi, %rax, 4), %rax ++# else ++ leaq -VEC_SIZE(%rdi, %rax), %rax ++# endif ++ ret ++ ++ .p2align 4 ++L(match): ++ /* Find a CHAR. Check if there is a null byte. */ ++ kmovd %k0, %ecx ++ testl %ecx, %ecx ++ jnz L(find_nul) ++ ++ /* Remember the match and keep searching. */ ++ movl %eax, %edx ++ movq %rdi, %rsi ++ jmp L(aligned_loop) ++ ++ .p2align 4 ++L(find_nul): ++ /* Mask out any matching bits after the null byte. */ ++ movl %ecx, %r8d ++ subl $1, %r8d ++ xorl %ecx, %r8d ++ andl %r8d, %eax ++ testl %eax, %eax ++ /* If there is no CHAR here, return the remembered one. */ ++ jz L(return_value) ++ bsrl %eax, %eax ++# ifdef USE_AS_WCSRCHR ++ /* NB: Multiply wchar_t count by 4 to get the number of bytes. */ ++ leaq -VEC_SIZE(%rdi, %rax, 4), %rax ++# else ++ leaq -VEC_SIZE(%rdi, %rax), %rax ++# endif ++ ret ++ ++ .p2align 4 ++L(char_and_nul): ++ /* Find both a CHAR and a null byte. */ ++ addq %rcx, %rdi ++ movl %edx, %ecx ++L(char_and_nul_in_first_vec): ++ /* Mask out any matching bits after the null byte. */ ++ movl %ecx, %r8d ++ subl $1, %r8d ++ xorl %ecx, %r8d ++ andl %r8d, %eax ++ testl %eax, %eax ++ /* Return null pointer if the null byte comes first. */ ++ jz L(return_null) ++ bsrl %eax, %eax ++# ifdef USE_AS_WCSRCHR ++ /* NB: Multiply wchar_t count by 4 to get the number of bytes. */ ++ leaq -VEC_SIZE(%rdi, %rax, 4), %rax ++# else ++ leaq -VEC_SIZE(%rdi, %rax), %rax ++# endif ++ ret ++ ++ .p2align 4 ++L(return_null): ++ xorl %eax, %eax ++ ret ++ ++END (STRRCHR) ++#endif +diff --git a/sysdeps/x86_64/multiarch/wcschr-evex.S b/sysdeps/x86_64/multiarch/wcschr-evex.S +new file mode 100644 +index 00000000..7cb8f1e4 +--- /dev/null ++++ b/sysdeps/x86_64/multiarch/wcschr-evex.S +@@ -0,0 +1,3 @@ ++#define STRCHR __wcschr_evex ++#define USE_AS_WCSCHR 1 ++#include "strchr-evex.S" +diff --git a/sysdeps/x86_64/multiarch/wcscmp-evex.S b/sysdeps/x86_64/multiarch/wcscmp-evex.S +new file mode 100644 +index 00000000..42e73e51 +--- /dev/null ++++ b/sysdeps/x86_64/multiarch/wcscmp-evex.S +@@ -0,0 +1,4 @@ ++#define STRCMP __wcscmp_evex ++#define USE_AS_WCSCMP 1 ++ ++#include "strcmp-evex.S" +diff --git a/sysdeps/x86_64/multiarch/wcslen-evex.S b/sysdeps/x86_64/multiarch/wcslen-evex.S +new file mode 100644 +index 00000000..bdafa83b +--- /dev/null ++++ b/sysdeps/x86_64/multiarch/wcslen-evex.S +@@ -0,0 +1,4 @@ ++#define STRLEN __wcslen_evex ++#define USE_AS_WCSLEN 1 ++ ++#include "strlen-evex.S" +diff --git a/sysdeps/x86_64/multiarch/wcsncmp-evex.S b/sysdeps/x86_64/multiarch/wcsncmp-evex.S +new file mode 100644 +index 00000000..8a8e3107 +--- /dev/null ++++ b/sysdeps/x86_64/multiarch/wcsncmp-evex.S +@@ -0,0 +1,5 @@ ++#define STRCMP __wcsncmp_evex ++#define USE_AS_STRNCMP 1 ++#define USE_AS_WCSCMP 1 ++ ++#include "strcmp-evex.S" +diff --git a/sysdeps/x86_64/multiarch/wcsnlen-evex.S b/sysdeps/x86_64/multiarch/wcsnlen-evex.S +new file mode 100644 +index 00000000..24773bb4 +--- /dev/null ++++ b/sysdeps/x86_64/multiarch/wcsnlen-evex.S +@@ -0,0 +1,5 @@ ++#define STRLEN __wcsnlen_evex ++#define USE_AS_WCSLEN 1 ++#define USE_AS_STRNLEN 1 ++ ++#include "strlen-evex.S" +diff --git a/sysdeps/x86_64/multiarch/wcsnlen.c b/sysdeps/x86_64/multiarch/wcsnlen.c +index b3144c93..84254b83 100644 +--- a/sysdeps/x86_64/multiarch/wcsnlen.c ++++ b/sysdeps/x86_64/multiarch/wcsnlen.c +@@ -29,16 +29,24 @@ + extern __typeof (REDIRECT_NAME) OPTIMIZE (sse2) attribute_hidden; + extern __typeof (REDIRECT_NAME) OPTIMIZE (sse4_1) attribute_hidden; + extern __typeof (REDIRECT_NAME) OPTIMIZE (avx2) attribute_hidden; ++extern __typeof (REDIRECT_NAME) OPTIMIZE (evex) attribute_hidden; + + static inline void * + IFUNC_SELECTOR (void) + { + const struct cpu_features* cpu_features = __get_cpu_features (); + +- if (!CPU_FEATURES_ARCH_P (cpu_features, Prefer_No_VZEROUPPER) +- && CPU_FEATURE_USABLE_P (cpu_features, AVX2) ++ if (CPU_FEATURE_USABLE_P (cpu_features, AVX2) + && CPU_FEATURES_ARCH_P (cpu_features, AVX_Fast_Unaligned_Load)) +- return OPTIMIZE (avx2); ++ { ++ if (CPU_FEATURE_USABLE_P (cpu_features, AVX512VL) ++ && CPU_FEATURE_USABLE_P (cpu_features, AVX512BW) ++ && CPU_FEATURE_USABLE_P (cpu_features, BMI2)) ++ return OPTIMIZE (evex); ++ ++ if (!CPU_FEATURES_ARCH_P (cpu_features, Prefer_No_VZEROUPPER)) ++ return OPTIMIZE (avx2); ++ } + + if (CPU_FEATURE_USABLE_P (cpu_features, SSE4_1)) + return OPTIMIZE (sse4_1); +diff --git a/sysdeps/x86_64/multiarch/wcsrchr-evex.S b/sysdeps/x86_64/multiarch/wcsrchr-evex.S +new file mode 100644 +index 00000000..c64602f7 +--- /dev/null ++++ b/sysdeps/x86_64/multiarch/wcsrchr-evex.S +@@ -0,0 +1,3 @@ ++#define STRRCHR __wcsrchr_evex ++#define USE_AS_WCSRCHR 1 ++#include "strrchr-evex.S" +diff --git a/sysdeps/x86_64/multiarch/wmemchr-evex.S b/sysdeps/x86_64/multiarch/wmemchr-evex.S +new file mode 100644 +index 00000000..06cd0f9f +--- /dev/null ++++ b/sysdeps/x86_64/multiarch/wmemchr-evex.S +@@ -0,0 +1,4 @@ ++#define MEMCHR __wmemchr_evex ++#define USE_AS_WMEMCHR 1 ++ ++#include "memchr-evex.S" +-- +GitLab + diff --git a/SOURCES/glibc-RHEL-15696-13.patch b/SOURCES/glibc-RHEL-15696-13.patch new file mode 100644 index 0000000..a88a3bc --- /dev/null +++ b/SOURCES/glibc-RHEL-15696-13.patch @@ -0,0 +1,1488 @@ +From 525bc2a32c9710df40371f951217c6ae7a923aee Mon Sep 17 00:00:00 2001 +From: "H.J. Lu" +Date: Fri, 5 Mar 2021 06:36:50 -0800 +Subject: [PATCH] x86-64: Add strcpy family functions with 256-bit EVEX +Content-type: text/plain; charset=UTF-8 + +Update ifunc-strcpy.h to select the function optimized with 256-bit EVEX +instructions using YMM16-YMM31 registers to avoid RTM abort with usable +AVX512VL and AVX512BW since VZEROUPPER isn't needed at function exit. +--- + sysdeps/x86_64/multiarch/Makefile | 6 + + sysdeps/x86_64/multiarch/ifunc-impl-list.c | 24 + + sysdeps/x86_64/multiarch/ifunc-strcpy.h | 13 +- + sysdeps/x86_64/multiarch/stpcpy-evex.S | 3 + + sysdeps/x86_64/multiarch/stpncpy-evex.S | 4 + + sysdeps/x86_64/multiarch/strcat-evex.S | 283 ++++++ + sysdeps/x86_64/multiarch/strcpy-evex.S | 1003 ++++++++++++++++++++ + sysdeps/x86_64/multiarch/strncat-evex.S | 3 + + sysdeps/x86_64/multiarch/strncpy-evex.S | 3 + + 9 files changed, 1339 insertions(+), 3 deletions(-) + create mode 100644 sysdeps/x86_64/multiarch/stpcpy-evex.S + create mode 100644 sysdeps/x86_64/multiarch/stpncpy-evex.S + create mode 100644 sysdeps/x86_64/multiarch/strcat-evex.S + create mode 100644 sysdeps/x86_64/multiarch/strcpy-evex.S + create mode 100644 sysdeps/x86_64/multiarch/strncat-evex.S + create mode 100644 sysdeps/x86_64/multiarch/strncpy-evex.S + +diff --git a/sysdeps/x86_64/multiarch/Makefile b/sysdeps/x86_64/multiarch/Makefile +index 5ce85882..46783cd1 100644 +--- a/sysdeps/x86_64/multiarch/Makefile ++++ b/sysdeps/x86_64/multiarch/Makefile +@@ -43,11 +43,17 @@ sysdep_routines += strncat-c stpncpy-c strncpy-c \ + memchr-evex \ + memrchr-evex \ + rawmemchr-evex \ ++ stpcpy-evex \ ++ stpncpy-evex \ ++ strcat-evex \ + strchr-evex \ + strchrnul-evex \ + strcmp-evex \ ++ strcpy-evex \ + strlen-evex \ ++ strncat-evex \ + strncmp-evex \ ++ strncpy-evex \ + strnlen-evex \ + strrchr-evex + CFLAGS-varshift.c += -msse4 +diff --git a/sysdeps/x86_64/multiarch/ifunc-impl-list.c b/sysdeps/x86_64/multiarch/ifunc-impl-list.c +index bd7d9f19..082e4da3 100644 +--- a/sysdeps/x86_64/multiarch/ifunc-impl-list.c ++++ b/sysdeps/x86_64/multiarch/ifunc-impl-list.c +@@ -224,6 +224,10 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + __stpncpy_ssse3) + IFUNC_IMPL_ADD (array, i, stpncpy, CPU_FEATURE_USABLE (AVX2), + __stpncpy_avx2) ++ IFUNC_IMPL_ADD (array, i, stpncpy, ++ (CPU_FEATURE_USABLE (AVX512VL) ++ && CPU_FEATURE_USABLE (AVX512BW)), ++ __stpncpy_evex) + IFUNC_IMPL_ADD (array, i, stpncpy, 1, + __stpncpy_sse2_unaligned) + IFUNC_IMPL_ADD (array, i, stpncpy, 1, __stpncpy_sse2)) +@@ -234,6 +238,10 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + __stpcpy_ssse3) + IFUNC_IMPL_ADD (array, i, stpcpy, CPU_FEATURE_USABLE (AVX2), + __stpcpy_avx2) ++ IFUNC_IMPL_ADD (array, i, stpcpy, ++ (CPU_FEATURE_USABLE (AVX512VL) ++ && CPU_FEATURE_USABLE (AVX512BW)), ++ __stpcpy_evex) + IFUNC_IMPL_ADD (array, i, stpcpy, 1, __stpcpy_sse2_unaligned) + IFUNC_IMPL_ADD (array, i, stpcpy, 1, __stpcpy_sse2)) + +@@ -268,6 +276,10 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + IFUNC_IMPL (i, name, strcat, + IFUNC_IMPL_ADD (array, i, strcat, CPU_FEATURE_USABLE (AVX2), + __strcat_avx2) ++ IFUNC_IMPL_ADD (array, i, strcat, ++ (CPU_FEATURE_USABLE (AVX512VL) ++ && CPU_FEATURE_USABLE (AVX512BW)), ++ __strcat_evex) + IFUNC_IMPL_ADD (array, i, strcat, CPU_FEATURE_USABLE (SSSE3), + __strcat_ssse3) + IFUNC_IMPL_ADD (array, i, strcat, 1, __strcat_sse2_unaligned) +@@ -330,6 +342,10 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + IFUNC_IMPL (i, name, strcpy, + IFUNC_IMPL_ADD (array, i, strcpy, CPU_FEATURE_USABLE (AVX2), + __strcpy_avx2) ++ IFUNC_IMPL_ADD (array, i, strcpy, ++ (CPU_FEATURE_USABLE (AVX512VL) ++ && CPU_FEATURE_USABLE (AVX512BW)), ++ __strcpy_evex) + IFUNC_IMPL_ADD (array, i, strcpy, CPU_FEATURE_USABLE (SSSE3), + __strcpy_ssse3) + IFUNC_IMPL_ADD (array, i, strcpy, 1, __strcpy_sse2_unaligned) +@@ -373,6 +389,10 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + IFUNC_IMPL (i, name, strncat, + IFUNC_IMPL_ADD (array, i, strncat, CPU_FEATURE_USABLE (AVX2), + __strncat_avx2) ++ IFUNC_IMPL_ADD (array, i, strncat, ++ (CPU_FEATURE_USABLE (AVX512VL) ++ && CPU_FEATURE_USABLE (AVX512BW)), ++ __strncat_evex) + IFUNC_IMPL_ADD (array, i, strncat, CPU_FEATURE_USABLE (SSSE3), + __strncat_ssse3) + IFUNC_IMPL_ADD (array, i, strncat, 1, +@@ -383,6 +403,10 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + IFUNC_IMPL (i, name, strncpy, + IFUNC_IMPL_ADD (array, i, strncpy, CPU_FEATURE_USABLE (AVX2), + __strncpy_avx2) ++ IFUNC_IMPL_ADD (array, i, strncpy, ++ (CPU_FEATURE_USABLE (AVX512VL) ++ && CPU_FEATURE_USABLE (AVX512BW)), ++ __strncpy_evex) + IFUNC_IMPL_ADD (array, i, strncpy, CPU_FEATURE_USABLE (SSSE3), + __strncpy_ssse3) + IFUNC_IMPL_ADD (array, i, strncpy, 1, +diff --git a/sysdeps/x86_64/multiarch/ifunc-strcpy.h b/sysdeps/x86_64/multiarch/ifunc-strcpy.h +index 100dca5c..deae6348 100644 +--- a/sysdeps/x86_64/multiarch/ifunc-strcpy.h ++++ b/sysdeps/x86_64/multiarch/ifunc-strcpy.h +@@ -25,16 +25,23 @@ extern __typeof (REDIRECT_NAME) OPTIMIZE (sse2_unaligned) + attribute_hidden; + extern __typeof (REDIRECT_NAME) OPTIMIZE (ssse3) attribute_hidden; + extern __typeof (REDIRECT_NAME) OPTIMIZE (avx2) attribute_hidden; ++extern __typeof (REDIRECT_NAME) OPTIMIZE (evex) attribute_hidden; + + static inline void * + IFUNC_SELECTOR (void) + { + const struct cpu_features* cpu_features = __get_cpu_features (); + +- if (!CPU_FEATURES_ARCH_P (cpu_features, Prefer_No_VZEROUPPER) +- && CPU_FEATURE_USABLE_P (cpu_features, AVX2) ++ if (CPU_FEATURE_USABLE_P (cpu_features, AVX2) + && CPU_FEATURES_ARCH_P (cpu_features, AVX_Fast_Unaligned_Load)) +- return OPTIMIZE (avx2); ++ { ++ if (CPU_FEATURE_USABLE_P (cpu_features, AVX512VL) ++ && CPU_FEATURE_USABLE_P (cpu_features, AVX512BW)) ++ return OPTIMIZE (evex); ++ ++ if (!CPU_FEATURES_ARCH_P (cpu_features, Prefer_No_VZEROUPPER)) ++ return OPTIMIZE (avx2); ++ } + + if (CPU_FEATURES_ARCH_P (cpu_features, Fast_Unaligned_Load)) + return OPTIMIZE (sse2_unaligned); +diff --git a/sysdeps/x86_64/multiarch/stpcpy-evex.S b/sysdeps/x86_64/multiarch/stpcpy-evex.S +new file mode 100644 +index 00000000..7c6f26cd +--- /dev/null ++++ b/sysdeps/x86_64/multiarch/stpcpy-evex.S +@@ -0,0 +1,3 @@ ++#define USE_AS_STPCPY ++#define STRCPY __stpcpy_evex ++#include "strcpy-evex.S" +diff --git a/sysdeps/x86_64/multiarch/stpncpy-evex.S b/sysdeps/x86_64/multiarch/stpncpy-evex.S +new file mode 100644 +index 00000000..1570014d +--- /dev/null ++++ b/sysdeps/x86_64/multiarch/stpncpy-evex.S +@@ -0,0 +1,4 @@ ++#define USE_AS_STPCPY ++#define USE_AS_STRNCPY ++#define STRCPY __stpncpy_evex ++#include "strcpy-evex.S" +diff --git a/sysdeps/x86_64/multiarch/strcat-evex.S b/sysdeps/x86_64/multiarch/strcat-evex.S +new file mode 100644 +index 00000000..97c3d85b +--- /dev/null ++++ b/sysdeps/x86_64/multiarch/strcat-evex.S +@@ -0,0 +1,283 @@ ++/* strcat with 256-bit EVEX instructions. ++ 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 ++ . */ ++ ++#if IS_IN (libc) ++ ++# include ++ ++# ifndef STRCAT ++# define STRCAT __strcat_evex ++# endif ++ ++# define VMOVU vmovdqu64 ++# define VMOVA vmovdqa64 ++ ++/* zero register */ ++# define XMMZERO xmm16 ++# define YMMZERO ymm16 ++# define YMM0 ymm17 ++# define YMM1 ymm18 ++ ++# define USE_AS_STRCAT ++ ++/* Number of bytes in a vector register */ ++# define VEC_SIZE 32 ++ ++ .section .text.evex,"ax",@progbits ++ENTRY (STRCAT) ++ mov %rdi, %r9 ++# ifdef USE_AS_STRNCAT ++ mov %rdx, %r8 ++# endif ++ ++ xor %eax, %eax ++ mov %edi, %ecx ++ and $((VEC_SIZE * 4) - 1), %ecx ++ vpxorq %XMMZERO, %XMMZERO, %XMMZERO ++ cmp $(VEC_SIZE * 3), %ecx ++ ja L(fourth_vector_boundary) ++ vpcmpb $0, (%rdi), %YMMZERO, %k0 ++ kmovd %k0, %edx ++ test %edx, %edx ++ jnz L(exit_null_on_first_vector) ++ mov %rdi, %rax ++ and $-VEC_SIZE, %rax ++ jmp L(align_vec_size_start) ++L(fourth_vector_boundary): ++ mov %rdi, %rax ++ and $-VEC_SIZE, %rax ++ vpcmpb $0, (%rax), %YMMZERO, %k0 ++ mov $-1, %r10d ++ sub %rax, %rcx ++ shl %cl, %r10d ++ kmovd %k0, %edx ++ and %r10d, %edx ++ jnz L(exit) ++ ++L(align_vec_size_start): ++ vpcmpb $0, VEC_SIZE(%rax), %YMMZERO, %k0 ++ kmovd %k0, %edx ++ test %edx, %edx ++ jnz L(exit_null_on_second_vector) ++ ++ vpcmpb $0, (VEC_SIZE * 2)(%rax), %YMMZERO, %k1 ++ kmovd %k1, %edx ++ test %edx, %edx ++ jnz L(exit_null_on_third_vector) ++ ++ vpcmpb $0, (VEC_SIZE * 3)(%rax), %YMMZERO, %k2 ++ kmovd %k2, %edx ++ test %edx, %edx ++ jnz L(exit_null_on_fourth_vector) ++ ++ vpcmpb $0, (VEC_SIZE * 4)(%rax), %YMMZERO, %k3 ++ kmovd %k3, %edx ++ test %edx, %edx ++ jnz L(exit_null_on_fifth_vector) ++ ++ vpcmpb $0, (VEC_SIZE * 5)(%rax), %YMMZERO, %k4 ++ add $(VEC_SIZE * 4), %rax ++ kmovd %k4, %edx ++ test %edx, %edx ++ jnz L(exit_null_on_second_vector) ++ ++ vpcmpb $0, (VEC_SIZE * 2)(%rax), %YMMZERO, %k1 ++ kmovd %k1, %edx ++ test %edx, %edx ++ jnz L(exit_null_on_third_vector) ++ ++ vpcmpb $0, (VEC_SIZE * 3)(%rax), %YMMZERO, %k2 ++ kmovd %k2, %edx ++ test %edx, %edx ++ jnz L(exit_null_on_fourth_vector) ++ ++ vpcmpb $0, (VEC_SIZE * 4)(%rax), %YMMZERO, %k3 ++ kmovd %k3, %edx ++ test %edx, %edx ++ jnz L(exit_null_on_fifth_vector) ++ ++ vpcmpb $0, (VEC_SIZE * 5)(%rax), %YMMZERO, %k4 ++ kmovd %k4, %edx ++ add $(VEC_SIZE * 4), %rax ++ test %edx, %edx ++ jnz L(exit_null_on_second_vector) ++ ++ vpcmpb $0, (VEC_SIZE * 2)(%rax), %YMMZERO, %k1 ++ kmovd %k1, %edx ++ test %edx, %edx ++ jnz L(exit_null_on_third_vector) ++ ++ vpcmpb $0, (VEC_SIZE * 3)(%rax), %YMMZERO, %k2 ++ kmovd %k2, %edx ++ test %edx, %edx ++ jnz L(exit_null_on_fourth_vector) ++ ++ vpcmpb $0, (VEC_SIZE * 4)(%rax), %YMMZERO, %k3 ++ kmovd %k3, %edx ++ test %edx, %edx ++ jnz L(exit_null_on_fifth_vector) ++ ++ vpcmpb $0, (VEC_SIZE * 5)(%rax), %YMMZERO, %k4 ++ add $(VEC_SIZE * 4), %rax ++ kmovd %k4, %edx ++ test %edx, %edx ++ jnz L(exit_null_on_second_vector) ++ ++ vpcmpb $0, (VEC_SIZE * 2)(%rax), %YMMZERO, %k1 ++ kmovd %k1, %edx ++ test %edx, %edx ++ jnz L(exit_null_on_third_vector) ++ ++ vpcmpb $0, (VEC_SIZE * 3)(%rax), %YMMZERO, %k2 ++ kmovd %k2, %edx ++ test %edx, %edx ++ jnz L(exit_null_on_fourth_vector) ++ ++ vpcmpb $0, (VEC_SIZE * 4)(%rax), %YMMZERO, %k3 ++ kmovd %k3, %edx ++ test %edx, %edx ++ jnz L(exit_null_on_fifth_vector) ++ ++ test $((VEC_SIZE * 4) - 1), %rax ++ jz L(align_four_vec_loop) ++ ++ vpcmpb $0, (VEC_SIZE * 5)(%rax), %YMMZERO, %k4 ++ add $(VEC_SIZE * 5), %rax ++ kmovd %k4, %edx ++ test %edx, %edx ++ jnz L(exit) ++ ++ test $((VEC_SIZE * 4) - 1), %rax ++ jz L(align_four_vec_loop) ++ ++ vpcmpb $0, VEC_SIZE(%rax), %YMMZERO, %k0 ++ add $VEC_SIZE, %rax ++ kmovd %k0, %edx ++ test %edx, %edx ++ jnz L(exit) ++ ++ test $((VEC_SIZE * 4) - 1), %rax ++ jz L(align_four_vec_loop) ++ ++ vpcmpb $0, VEC_SIZE(%rax), %YMMZERO, %k0 ++ add $VEC_SIZE, %rax ++ kmovd %k0, %edx ++ test %edx, %edx ++ jnz L(exit) ++ ++ test $((VEC_SIZE * 4) - 1), %rax ++ jz L(align_four_vec_loop) ++ ++ vpcmpb $0, VEC_SIZE(%rax), %YMMZERO, %k1 ++ add $VEC_SIZE, %rax ++ kmovd %k1, %edx ++ test %edx, %edx ++ jnz L(exit) ++ ++ add $VEC_SIZE, %rax ++ ++ .p2align 4 ++L(align_four_vec_loop): ++ VMOVA (%rax), %YMM0 ++ VMOVA (VEC_SIZE * 2)(%rax), %YMM1 ++ vpminub VEC_SIZE(%rax), %YMM0, %YMM0 ++ vpminub (VEC_SIZE * 3)(%rax), %YMM1, %YMM1 ++ vpminub %YMM0, %YMM1, %YMM0 ++ /* If K0 != 0, there is a null byte. */ ++ vpcmpb $0, %YMM0, %YMMZERO, %k0 ++ add $(VEC_SIZE * 4), %rax ++ ktestd %k0, %k0 ++ jz L(align_four_vec_loop) ++ ++ vpcmpb $0, -(VEC_SIZE * 4)(%rax), %YMMZERO, %k0 ++ sub $(VEC_SIZE * 5), %rax ++ kmovd %k0, %edx ++ test %edx, %edx ++ jnz L(exit_null_on_second_vector) ++ ++ vpcmpb $0, (VEC_SIZE * 2)(%rax), %YMMZERO, %k1 ++ kmovd %k1, %edx ++ test %edx, %edx ++ jnz L(exit_null_on_third_vector) ++ ++ vpcmpb $0, (VEC_SIZE * 3)(%rax), %YMMZERO, %k2 ++ kmovd %k2, %edx ++ test %edx, %edx ++ jnz L(exit_null_on_fourth_vector) ++ ++ vpcmpb $0, (VEC_SIZE * 4)(%rax), %YMMZERO, %k3 ++ kmovd %k3, %edx ++ sub %rdi, %rax ++ bsf %rdx, %rdx ++ add %rdx, %rax ++ add $(VEC_SIZE * 4), %rax ++ jmp L(StartStrcpyPart) ++ ++ .p2align 4 ++L(exit): ++ sub %rdi, %rax ++L(exit_null_on_first_vector): ++ bsf %rdx, %rdx ++ add %rdx, %rax ++ jmp L(StartStrcpyPart) ++ ++ .p2align 4 ++L(exit_null_on_second_vector): ++ sub %rdi, %rax ++ bsf %rdx, %rdx ++ add %rdx, %rax ++ add $VEC_SIZE, %rax ++ jmp L(StartStrcpyPart) ++ ++ .p2align 4 ++L(exit_null_on_third_vector): ++ sub %rdi, %rax ++ bsf %rdx, %rdx ++ add %rdx, %rax ++ add $(VEC_SIZE * 2), %rax ++ jmp L(StartStrcpyPart) ++ ++ .p2align 4 ++L(exit_null_on_fourth_vector): ++ sub %rdi, %rax ++ bsf %rdx, %rdx ++ add %rdx, %rax ++ add $(VEC_SIZE * 3), %rax ++ jmp L(StartStrcpyPart) ++ ++ .p2align 4 ++L(exit_null_on_fifth_vector): ++ sub %rdi, %rax ++ bsf %rdx, %rdx ++ add %rdx, %rax ++ add $(VEC_SIZE * 4), %rax ++ ++ .p2align 4 ++L(StartStrcpyPart): ++ lea (%r9, %rax), %rdi ++ mov %rsi, %rcx ++ mov %r9, %rax /* save result */ ++ ++# ifdef USE_AS_STRNCAT ++ test %r8, %r8 ++ jz L(ExitZero) ++# define USE_AS_STRNCPY ++# endif ++ ++# include "strcpy-evex.S" ++#endif +diff --git a/sysdeps/x86_64/multiarch/strcpy-evex.S b/sysdeps/x86_64/multiarch/strcpy-evex.S +new file mode 100644 +index 00000000..a343a1a6 +--- /dev/null ++++ b/sysdeps/x86_64/multiarch/strcpy-evex.S +@@ -0,0 +1,1003 @@ ++/* strcpy with 256-bit EVEX instructions. ++ 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 ++ . */ ++ ++#if IS_IN (libc) ++ ++# ifndef USE_AS_STRCAT ++# include ++ ++# ifndef STRCPY ++# define STRCPY __strcpy_evex ++# endif ++ ++# endif ++ ++# define VMOVU vmovdqu64 ++# define VMOVA vmovdqa64 ++ ++/* Number of bytes in a vector register */ ++# ifndef VEC_SIZE ++# define VEC_SIZE 32 ++# endif ++ ++# define XMM2 xmm18 ++# define XMM3 xmm19 ++ ++# define YMM2 ymm18 ++# define YMM3 ymm19 ++# define YMM4 ymm20 ++# define YMM5 ymm21 ++# define YMM6 ymm22 ++# define YMM7 ymm23 ++ ++# ifndef USE_AS_STRCAT ++ ++/* zero register */ ++# define XMMZERO xmm16 ++# define YMMZERO ymm16 ++# define YMM1 ymm17 ++ ++ .section .text.evex,"ax",@progbits ++ENTRY (STRCPY) ++# ifdef USE_AS_STRNCPY ++ mov %RDX_LP, %R8_LP ++ test %R8_LP, %R8_LP ++ jz L(ExitZero) ++# endif ++ mov %rsi, %rcx ++# ifndef USE_AS_STPCPY ++ mov %rdi, %rax /* save result */ ++# endif ++ ++ vpxorq %XMMZERO, %XMMZERO, %XMMZERO ++# endif ++ ++ and $((VEC_SIZE * 4) - 1), %ecx ++ cmp $(VEC_SIZE * 2), %ecx ++ jbe L(SourceStringAlignmentLessTwoVecSize) ++ ++ and $-VEC_SIZE, %rsi ++ and $(VEC_SIZE - 1), %ecx ++ ++ vpcmpb $0, (%rsi), %YMMZERO, %k0 ++ kmovd %k0, %edx ++ shr %cl, %rdx ++ ++# ifdef USE_AS_STRNCPY ++# if defined USE_AS_STPCPY || defined USE_AS_STRCAT ++ mov $VEC_SIZE, %r10 ++ sub %rcx, %r10 ++ cmp %r10, %r8 ++# else ++ mov $(VEC_SIZE + 1), %r10 ++ sub %rcx, %r10 ++ cmp %r10, %r8 ++# endif ++ jbe L(CopyVecSizeTailCase2OrCase3) ++# endif ++ test %edx, %edx ++ jnz L(CopyVecSizeTail) ++ ++ vpcmpb $0, VEC_SIZE(%rsi), %YMMZERO, %k1 ++ kmovd %k1, %edx ++ ++# ifdef USE_AS_STRNCPY ++ add $VEC_SIZE, %r10 ++ cmp %r10, %r8 ++ jbe L(CopyTwoVecSizeCase2OrCase3) ++# endif ++ test %edx, %edx ++ jnz L(CopyTwoVecSize) ++ ++ VMOVU (%rsi, %rcx), %YMM2 /* copy VEC_SIZE bytes */ ++ VMOVU %YMM2, (%rdi) ++ ++/* If source address alignment != destination address alignment */ ++ .p2align 4 ++L(UnalignVecSizeBoth): ++ sub %rcx, %rdi ++# ifdef USE_AS_STRNCPY ++ add %rcx, %r8 ++ sbb %rcx, %rcx ++ or %rcx, %r8 ++# endif ++ mov $VEC_SIZE, %rcx ++ VMOVA (%rsi, %rcx), %YMM2 ++ VMOVU %YMM2, (%rdi, %rcx) ++ VMOVA VEC_SIZE(%rsi, %rcx), %YMM2 ++ vpcmpb $0, %YMM2, %YMMZERO, %k0 ++ kmovd %k0, %edx ++ add $VEC_SIZE, %rcx ++# ifdef USE_AS_STRNCPY ++ sub $(VEC_SIZE * 3), %r8 ++ jbe L(CopyVecSizeCase2OrCase3) ++# endif ++ test %edx, %edx ++# if defined USE_AS_STRNCPY && !defined USE_AS_STRCAT ++ jnz L(CopyVecSizeUnalignedVec2) ++# else ++ jnz L(CopyVecSize) ++# endif ++ ++ VMOVU %YMM2, (%rdi, %rcx) ++ VMOVA VEC_SIZE(%rsi, %rcx), %YMM3 ++ vpcmpb $0, %YMM3, %YMMZERO, %k0 ++ kmovd %k0, %edx ++ add $VEC_SIZE, %rcx ++# ifdef USE_AS_STRNCPY ++ sub $VEC_SIZE, %r8 ++ jbe L(CopyVecSizeCase2OrCase3) ++# endif ++ test %edx, %edx ++# if defined USE_AS_STRNCPY && !defined USE_AS_STRCAT ++ jnz L(CopyVecSizeUnalignedVec3) ++# else ++ jnz L(CopyVecSize) ++# endif ++ ++ VMOVU %YMM3, (%rdi, %rcx) ++ VMOVA VEC_SIZE(%rsi, %rcx), %YMM4 ++ vpcmpb $0, %YMM4, %YMMZERO, %k0 ++ kmovd %k0, %edx ++ add $VEC_SIZE, %rcx ++# ifdef USE_AS_STRNCPY ++ sub $VEC_SIZE, %r8 ++ jbe L(CopyVecSizeCase2OrCase3) ++# endif ++ test %edx, %edx ++# if defined USE_AS_STRNCPY && !defined USE_AS_STRCAT ++ jnz L(CopyVecSizeUnalignedVec4) ++# else ++ jnz L(CopyVecSize) ++# endif ++ ++ VMOVU %YMM4, (%rdi, %rcx) ++ VMOVA VEC_SIZE(%rsi, %rcx), %YMM2 ++ vpcmpb $0, %YMM2, %YMMZERO, %k0 ++ kmovd %k0, %edx ++ add $VEC_SIZE, %rcx ++# ifdef USE_AS_STRNCPY ++ sub $VEC_SIZE, %r8 ++ jbe L(CopyVecSizeCase2OrCase3) ++# endif ++ test %edx, %edx ++# if defined USE_AS_STRNCPY && !defined USE_AS_STRCAT ++ jnz L(CopyVecSizeUnalignedVec2) ++# else ++ jnz L(CopyVecSize) ++# endif ++ ++ VMOVU %YMM2, (%rdi, %rcx) ++ VMOVA VEC_SIZE(%rsi, %rcx), %YMM2 ++ vpcmpb $0, %YMM2, %YMMZERO, %k0 ++ kmovd %k0, %edx ++ add $VEC_SIZE, %rcx ++# ifdef USE_AS_STRNCPY ++ sub $VEC_SIZE, %r8 ++ jbe L(CopyVecSizeCase2OrCase3) ++# endif ++ test %edx, %edx ++# if defined USE_AS_STRNCPY && !defined USE_AS_STRCAT ++ jnz L(CopyVecSizeUnalignedVec2) ++# else ++ jnz L(CopyVecSize) ++# endif ++ ++ VMOVA VEC_SIZE(%rsi, %rcx), %YMM3 ++ VMOVU %YMM2, (%rdi, %rcx) ++ vpcmpb $0, %YMM3, %YMMZERO, %k0 ++ kmovd %k0, %edx ++ add $VEC_SIZE, %rcx ++# ifdef USE_AS_STRNCPY ++ sub $VEC_SIZE, %r8 ++ jbe L(CopyVecSizeCase2OrCase3) ++# endif ++ test %edx, %edx ++# if defined USE_AS_STRNCPY && !defined USE_AS_STRCAT ++ jnz L(CopyVecSizeUnalignedVec3) ++# else ++ jnz L(CopyVecSize) ++# endif ++ ++ VMOVU %YMM3, (%rdi, %rcx) ++ mov %rsi, %rdx ++ lea VEC_SIZE(%rsi, %rcx), %rsi ++ and $-(VEC_SIZE * 4), %rsi ++ sub %rsi, %rdx ++ sub %rdx, %rdi ++# ifdef USE_AS_STRNCPY ++ lea (VEC_SIZE * 8)(%r8, %rdx), %r8 ++# endif ++L(UnalignedFourVecSizeLoop): ++ VMOVA (%rsi), %YMM4 ++ VMOVA VEC_SIZE(%rsi), %YMM5 ++ VMOVA (VEC_SIZE * 2)(%rsi), %YMM6 ++ VMOVA (VEC_SIZE * 3)(%rsi), %YMM7 ++ vpminub %YMM5, %YMM4, %YMM2 ++ vpminub %YMM7, %YMM6, %YMM3 ++ vpminub %YMM2, %YMM3, %YMM2 ++ /* If K7 != 0, there is a null byte. */ ++ vpcmpb $0, %YMM2, %YMMZERO, %k7 ++ kmovd %k7, %edx ++# ifdef USE_AS_STRNCPY ++ sub $(VEC_SIZE * 4), %r8 ++ jbe L(UnalignedLeaveCase2OrCase3) ++# endif ++ test %edx, %edx ++ jnz L(UnalignedFourVecSizeLeave) ++ ++L(UnalignedFourVecSizeLoop_start): ++ add $(VEC_SIZE * 4), %rdi ++ add $(VEC_SIZE * 4), %rsi ++ VMOVU %YMM4, -(VEC_SIZE * 4)(%rdi) ++ VMOVA (%rsi), %YMM4 ++ VMOVU %YMM5, -(VEC_SIZE * 3)(%rdi) ++ VMOVA VEC_SIZE(%rsi), %YMM5 ++ vpminub %YMM5, %YMM4, %YMM2 ++ VMOVU %YMM6, -(VEC_SIZE * 2)(%rdi) ++ VMOVA (VEC_SIZE * 2)(%rsi), %YMM6 ++ VMOVU %YMM7, -VEC_SIZE(%rdi) ++ VMOVA (VEC_SIZE * 3)(%rsi), %YMM7 ++ vpminub %YMM7, %YMM6, %YMM3 ++ vpminub %YMM2, %YMM3, %YMM2 ++ /* If K7 != 0, there is a null byte. */ ++ vpcmpb $0, %YMM2, %YMMZERO, %k7 ++ kmovd %k7, %edx ++# ifdef USE_AS_STRNCPY ++ sub $(VEC_SIZE * 4), %r8 ++ jbe L(UnalignedLeaveCase2OrCase3) ++# endif ++ test %edx, %edx ++ jz L(UnalignedFourVecSizeLoop_start) ++ ++L(UnalignedFourVecSizeLeave): ++ vpcmpb $0, %YMM4, %YMMZERO, %k1 ++ kmovd %k1, %edx ++ test %edx, %edx ++ jnz L(CopyVecSizeUnaligned_0) ++ ++ vpcmpb $0, %YMM5, %YMMZERO, %k2 ++ kmovd %k2, %ecx ++ test %ecx, %ecx ++ jnz L(CopyVecSizeUnaligned_16) ++ ++ vpcmpb $0, %YMM6, %YMMZERO, %k3 ++ kmovd %k3, %edx ++ test %edx, %edx ++ jnz L(CopyVecSizeUnaligned_32) ++ ++ vpcmpb $0, %YMM7, %YMMZERO, %k4 ++ kmovd %k4, %ecx ++ bsf %ecx, %edx ++ VMOVU %YMM4, (%rdi) ++ VMOVU %YMM5, VEC_SIZE(%rdi) ++ VMOVU %YMM6, (VEC_SIZE * 2)(%rdi) ++# if defined USE_AS_STRNCPY && !defined USE_AS_STRCAT ++# ifdef USE_AS_STPCPY ++ lea (VEC_SIZE * 3)(%rdi, %rdx), %rax ++# endif ++ VMOVU %YMM7, (VEC_SIZE * 3)(%rdi) ++ add $(VEC_SIZE - 1), %r8 ++ sub %rdx, %r8 ++ lea ((VEC_SIZE * 3) + 1)(%rdi, %rdx), %rdi ++ jmp L(StrncpyFillTailWithZero) ++# else ++ add $(VEC_SIZE * 3), %rsi ++ add $(VEC_SIZE * 3), %rdi ++ jmp L(CopyVecSizeExit) ++# endif ++ ++/* If source address alignment == destination address alignment */ ++ ++L(SourceStringAlignmentLessTwoVecSize): ++ VMOVU (%rsi), %YMM3 ++ VMOVU VEC_SIZE(%rsi), %YMM2 ++ vpcmpb $0, %YMM3, %YMMZERO, %k0 ++ kmovd %k0, %edx ++ ++# ifdef USE_AS_STRNCPY ++# if defined USE_AS_STPCPY || defined USE_AS_STRCAT ++ cmp $VEC_SIZE, %r8 ++# else ++ cmp $(VEC_SIZE + 1), %r8 ++# endif ++ jbe L(CopyVecSizeTail1Case2OrCase3) ++# endif ++ test %edx, %edx ++ jnz L(CopyVecSizeTail1) ++ ++ VMOVU %YMM3, (%rdi) ++ vpcmpb $0, %YMM2, %YMMZERO, %k0 ++ kmovd %k0, %edx ++ ++# ifdef USE_AS_STRNCPY ++# if defined USE_AS_STPCPY || defined USE_AS_STRCAT ++ cmp $(VEC_SIZE * 2), %r8 ++# else ++ cmp $((VEC_SIZE * 2) + 1), %r8 ++# endif ++ jbe L(CopyTwoVecSize1Case2OrCase3) ++# endif ++ test %edx, %edx ++ jnz L(CopyTwoVecSize1) ++ ++ and $-VEC_SIZE, %rsi ++ and $(VEC_SIZE - 1), %ecx ++ jmp L(UnalignVecSizeBoth) ++ ++/*------End of main part with loops---------------------*/ ++ ++/* Case1 */ ++ ++# if (!defined USE_AS_STRNCPY) || (defined USE_AS_STRCAT) ++ .p2align 4 ++L(CopyVecSize): ++ add %rcx, %rdi ++# endif ++L(CopyVecSizeTail): ++ add %rcx, %rsi ++L(CopyVecSizeTail1): ++ bsf %edx, %edx ++L(CopyVecSizeExit): ++ cmp $32, %edx ++ jae L(Exit32_63) ++ cmp $16, %edx ++ jae L(Exit16_31) ++ cmp $8, %edx ++ jae L(Exit8_15) ++ cmp $4, %edx ++ jae L(Exit4_7) ++ cmp $3, %edx ++ je L(Exit3) ++ cmp $1, %edx ++ ja L(Exit2) ++ je L(Exit1) ++ movb $0, (%rdi) ++# ifdef USE_AS_STPCPY ++ lea (%rdi), %rax ++# endif ++# if defined USE_AS_STRNCPY && !defined USE_AS_STRCAT ++ sub $1, %r8 ++ lea 1(%rdi), %rdi ++ jnz L(StrncpyFillTailWithZero) ++# endif ++ ret ++ ++ .p2align 4 ++L(CopyTwoVecSize1): ++ add $VEC_SIZE, %rsi ++ add $VEC_SIZE, %rdi ++# if defined USE_AS_STRNCPY && !defined USE_AS_STRCAT ++ sub $VEC_SIZE, %r8 ++# endif ++ jmp L(CopyVecSizeTail1) ++ ++ .p2align 4 ++L(CopyTwoVecSize): ++ bsf %edx, %edx ++ add %rcx, %rsi ++ add $VEC_SIZE, %edx ++ sub %ecx, %edx ++ jmp L(CopyVecSizeExit) ++ ++ .p2align 4 ++L(CopyVecSizeUnaligned_0): ++ bsf %edx, %edx ++# if defined USE_AS_STRNCPY && !defined USE_AS_STRCAT ++# ifdef USE_AS_STPCPY ++ lea (%rdi, %rdx), %rax ++# endif ++ VMOVU %YMM4, (%rdi) ++ add $((VEC_SIZE * 4) - 1), %r8 ++ sub %rdx, %r8 ++ lea 1(%rdi, %rdx), %rdi ++ jmp L(StrncpyFillTailWithZero) ++# else ++ jmp L(CopyVecSizeExit) ++# endif ++ ++ .p2align 4 ++L(CopyVecSizeUnaligned_16): ++ bsf %ecx, %edx ++ VMOVU %YMM4, (%rdi) ++# if defined USE_AS_STRNCPY && !defined USE_AS_STRCAT ++# ifdef USE_AS_STPCPY ++ lea VEC_SIZE(%rdi, %rdx), %rax ++# endif ++ VMOVU %YMM5, VEC_SIZE(%rdi) ++ add $((VEC_SIZE * 3) - 1), %r8 ++ sub %rdx, %r8 ++ lea (VEC_SIZE + 1)(%rdi, %rdx), %rdi ++ jmp L(StrncpyFillTailWithZero) ++# else ++ add $VEC_SIZE, %rsi ++ add $VEC_SIZE, %rdi ++ jmp L(CopyVecSizeExit) ++# endif ++ ++ .p2align 4 ++L(CopyVecSizeUnaligned_32): ++ bsf %edx, %edx ++ VMOVU %YMM4, (%rdi) ++ VMOVU %YMM5, VEC_SIZE(%rdi) ++# if defined USE_AS_STRNCPY && !defined USE_AS_STRCAT ++# ifdef USE_AS_STPCPY ++ lea (VEC_SIZE * 2)(%rdi, %rdx), %rax ++# endif ++ VMOVU %YMM6, (VEC_SIZE * 2)(%rdi) ++ add $((VEC_SIZE * 2) - 1), %r8 ++ sub %rdx, %r8 ++ lea ((VEC_SIZE * 2) + 1)(%rdi, %rdx), %rdi ++ jmp L(StrncpyFillTailWithZero) ++# else ++ add $(VEC_SIZE * 2), %rsi ++ add $(VEC_SIZE * 2), %rdi ++ jmp L(CopyVecSizeExit) ++# endif ++ ++# ifdef USE_AS_STRNCPY ++# ifndef USE_AS_STRCAT ++ .p2align 4 ++L(CopyVecSizeUnalignedVec6): ++ VMOVU %YMM6, (%rdi, %rcx) ++ jmp L(CopyVecSizeVecExit) ++ ++ .p2align 4 ++L(CopyVecSizeUnalignedVec5): ++ VMOVU %YMM5, (%rdi, %rcx) ++ jmp L(CopyVecSizeVecExit) ++ ++ .p2align 4 ++L(CopyVecSizeUnalignedVec4): ++ VMOVU %YMM4, (%rdi, %rcx) ++ jmp L(CopyVecSizeVecExit) ++ ++ .p2align 4 ++L(CopyVecSizeUnalignedVec3): ++ VMOVU %YMM3, (%rdi, %rcx) ++ jmp L(CopyVecSizeVecExit) ++# endif ++ ++/* Case2 */ ++ ++ .p2align 4 ++L(CopyVecSizeCase2): ++ add $VEC_SIZE, %r8 ++ add %rcx, %rdi ++ add %rcx, %rsi ++ bsf %edx, %edx ++ cmp %r8d, %edx ++ jb L(CopyVecSizeExit) ++ jmp L(StrncpyExit) ++ ++ .p2align 4 ++L(CopyTwoVecSizeCase2): ++ add %rcx, %rsi ++ bsf %edx, %edx ++ add $VEC_SIZE, %edx ++ sub %ecx, %edx ++ cmp %r8d, %edx ++ jb L(CopyVecSizeExit) ++ jmp L(StrncpyExit) ++ ++L(CopyVecSizeTailCase2): ++ add %rcx, %rsi ++ bsf %edx, %edx ++ cmp %r8d, %edx ++ jb L(CopyVecSizeExit) ++ jmp L(StrncpyExit) ++ ++L(CopyVecSizeTail1Case2): ++ bsf %edx, %edx ++ cmp %r8d, %edx ++ jb L(CopyVecSizeExit) ++ jmp L(StrncpyExit) ++ ++/* Case2 or Case3, Case3 */ ++ ++ .p2align 4 ++L(CopyVecSizeCase2OrCase3): ++ test %rdx, %rdx ++ jnz L(CopyVecSizeCase2) ++L(CopyVecSizeCase3): ++ add $VEC_SIZE, %r8 ++ add %rcx, %rdi ++ add %rcx, %rsi ++ jmp L(StrncpyExit) ++ ++ .p2align 4 ++L(CopyTwoVecSizeCase2OrCase3): ++ test %rdx, %rdx ++ jnz L(CopyTwoVecSizeCase2) ++ add %rcx, %rsi ++ jmp L(StrncpyExit) ++ ++ .p2align 4 ++L(CopyVecSizeTailCase2OrCase3): ++ test %rdx, %rdx ++ jnz L(CopyVecSizeTailCase2) ++ add %rcx, %rsi ++ jmp L(StrncpyExit) ++ ++ .p2align 4 ++L(CopyTwoVecSize1Case2OrCase3): ++ add $VEC_SIZE, %rdi ++ add $VEC_SIZE, %rsi ++ sub $VEC_SIZE, %r8 ++L(CopyVecSizeTail1Case2OrCase3): ++ test %rdx, %rdx ++ jnz L(CopyVecSizeTail1Case2) ++ jmp L(StrncpyExit) ++# endif ++ ++/*------------End labels regarding with copying 1-VEC_SIZE bytes--and 1-(VEC_SIZE*2) bytes----*/ ++ ++ .p2align 4 ++L(Exit1): ++ movzwl (%rsi), %edx ++ mov %dx, (%rdi) ++# ifdef USE_AS_STPCPY ++ lea 1(%rdi), %rax ++# endif ++# if defined USE_AS_STRNCPY && !defined USE_AS_STRCAT ++ sub $2, %r8 ++ lea 2(%rdi), %rdi ++ jnz L(StrncpyFillTailWithZero) ++# endif ++ ret ++ ++ .p2align 4 ++L(Exit2): ++ movzwl (%rsi), %ecx ++ mov %cx, (%rdi) ++ movb $0, 2(%rdi) ++# ifdef USE_AS_STPCPY ++ lea 2(%rdi), %rax ++# endif ++# if defined USE_AS_STRNCPY && !defined USE_AS_STRCAT ++ sub $3, %r8 ++ lea 3(%rdi), %rdi ++ jnz L(StrncpyFillTailWithZero) ++# endif ++ ret ++ ++ .p2align 4 ++L(Exit3): ++ mov (%rsi), %edx ++ mov %edx, (%rdi) ++# ifdef USE_AS_STPCPY ++ lea 3(%rdi), %rax ++# endif ++# if defined USE_AS_STRNCPY && !defined USE_AS_STRCAT ++ sub $4, %r8 ++ lea 4(%rdi), %rdi ++ jnz L(StrncpyFillTailWithZero) ++# endif ++ ret ++ ++ .p2align 4 ++L(Exit4_7): ++ mov (%rsi), %ecx ++ mov %ecx, (%rdi) ++ mov -3(%rsi, %rdx), %ecx ++ mov %ecx, -3(%rdi, %rdx) ++# ifdef USE_AS_STPCPY ++ lea (%rdi, %rdx), %rax ++# endif ++# if defined USE_AS_STRNCPY && !defined USE_AS_STRCAT ++ sub %rdx, %r8 ++ sub $1, %r8 ++ lea 1(%rdi, %rdx), %rdi ++ jnz L(StrncpyFillTailWithZero) ++# endif ++ ret ++ ++ .p2align 4 ++L(Exit8_15): ++ mov (%rsi), %rcx ++ mov -7(%rsi, %rdx), %r9 ++ mov %rcx, (%rdi) ++ mov %r9, -7(%rdi, %rdx) ++# ifdef USE_AS_STPCPY ++ lea (%rdi, %rdx), %rax ++# endif ++# if defined USE_AS_STRNCPY && !defined USE_AS_STRCAT ++ sub %rdx, %r8 ++ sub $1, %r8 ++ lea 1(%rdi, %rdx), %rdi ++ jnz L(StrncpyFillTailWithZero) ++# endif ++ ret ++ ++ .p2align 4 ++L(Exit16_31): ++ VMOVU (%rsi), %XMM2 ++ VMOVU -15(%rsi, %rdx), %XMM3 ++ VMOVU %XMM2, (%rdi) ++ VMOVU %XMM3, -15(%rdi, %rdx) ++# ifdef USE_AS_STPCPY ++ lea (%rdi, %rdx), %rax ++# endif ++# if defined USE_AS_STRNCPY && !defined USE_AS_STRCAT ++ sub %rdx, %r8 ++ sub $1, %r8 ++ lea 1(%rdi, %rdx), %rdi ++ jnz L(StrncpyFillTailWithZero) ++# endif ++ ret ++ ++ .p2align 4 ++L(Exit32_63): ++ VMOVU (%rsi), %YMM2 ++ VMOVU -31(%rsi, %rdx), %YMM3 ++ VMOVU %YMM2, (%rdi) ++ VMOVU %YMM3, -31(%rdi, %rdx) ++# ifdef USE_AS_STPCPY ++ lea (%rdi, %rdx), %rax ++# endif ++# if defined USE_AS_STRNCPY && !defined USE_AS_STRCAT ++ sub %rdx, %r8 ++ sub $1, %r8 ++ lea 1(%rdi, %rdx), %rdi ++ jnz L(StrncpyFillTailWithZero) ++# endif ++ ret ++ ++# ifdef USE_AS_STRNCPY ++ ++ .p2align 4 ++L(StrncpyExit1): ++ movzbl (%rsi), %edx ++ mov %dl, (%rdi) ++# ifdef USE_AS_STPCPY ++ lea 1(%rdi), %rax ++# endif ++# ifdef USE_AS_STRCAT ++ movb $0, 1(%rdi) ++# endif ++ ret ++ ++ .p2align 4 ++L(StrncpyExit2): ++ movzwl (%rsi), %edx ++ mov %dx, (%rdi) ++# ifdef USE_AS_STPCPY ++ lea 2(%rdi), %rax ++# endif ++# ifdef USE_AS_STRCAT ++ movb $0, 2(%rdi) ++# endif ++ ret ++ ++ .p2align 4 ++L(StrncpyExit3_4): ++ movzwl (%rsi), %ecx ++ movzwl -2(%rsi, %r8), %edx ++ mov %cx, (%rdi) ++ mov %dx, -2(%rdi, %r8) ++# ifdef USE_AS_STPCPY ++ lea (%rdi, %r8), %rax ++# endif ++# ifdef USE_AS_STRCAT ++ movb $0, (%rdi, %r8) ++# endif ++ ret ++ ++ .p2align 4 ++L(StrncpyExit5_8): ++ mov (%rsi), %ecx ++ mov -4(%rsi, %r8), %edx ++ mov %ecx, (%rdi) ++ mov %edx, -4(%rdi, %r8) ++# ifdef USE_AS_STPCPY ++ lea (%rdi, %r8), %rax ++# endif ++# ifdef USE_AS_STRCAT ++ movb $0, (%rdi, %r8) ++# endif ++ ret ++ ++ .p2align 4 ++L(StrncpyExit9_16): ++ mov (%rsi), %rcx ++ mov -8(%rsi, %r8), %rdx ++ mov %rcx, (%rdi) ++ mov %rdx, -8(%rdi, %r8) ++# ifdef USE_AS_STPCPY ++ lea (%rdi, %r8), %rax ++# endif ++# ifdef USE_AS_STRCAT ++ movb $0, (%rdi, %r8) ++# endif ++ ret ++ ++ .p2align 4 ++L(StrncpyExit17_32): ++ VMOVU (%rsi), %XMM2 ++ VMOVU -16(%rsi, %r8), %XMM3 ++ VMOVU %XMM2, (%rdi) ++ VMOVU %XMM3, -16(%rdi, %r8) ++# ifdef USE_AS_STPCPY ++ lea (%rdi, %r8), %rax ++# endif ++# ifdef USE_AS_STRCAT ++ movb $0, (%rdi, %r8) ++# endif ++ ret ++ ++ .p2align 4 ++L(StrncpyExit33_64): ++ /* 0/32, 31/16 */ ++ VMOVU (%rsi), %YMM2 ++ VMOVU -VEC_SIZE(%rsi, %r8), %YMM3 ++ VMOVU %YMM2, (%rdi) ++ VMOVU %YMM3, -VEC_SIZE(%rdi, %r8) ++# ifdef USE_AS_STPCPY ++ lea (%rdi, %r8), %rax ++# endif ++# ifdef USE_AS_STRCAT ++ movb $0, (%rdi, %r8) ++# endif ++ ret ++ ++ .p2align 4 ++L(StrncpyExit65): ++ /* 0/32, 32/32, 64/1 */ ++ VMOVU (%rsi), %YMM2 ++ VMOVU 32(%rsi), %YMM3 ++ mov 64(%rsi), %cl ++ VMOVU %YMM2, (%rdi) ++ VMOVU %YMM3, 32(%rdi) ++ mov %cl, 64(%rdi) ++# ifdef USE_AS_STPCPY ++ lea 65(%rdi), %rax ++# endif ++# ifdef USE_AS_STRCAT ++ movb $0, 65(%rdi) ++# endif ++ ret ++ ++# ifndef USE_AS_STRCAT ++ ++ .p2align 4 ++L(Fill1): ++ mov %dl, (%rdi) ++ ret ++ ++ .p2align 4 ++L(Fill2): ++ mov %dx, (%rdi) ++ ret ++ ++ .p2align 4 ++L(Fill3_4): ++ mov %dx, (%rdi) ++ mov %dx, -2(%rdi, %r8) ++ ret ++ ++ .p2align 4 ++L(Fill5_8): ++ mov %edx, (%rdi) ++ mov %edx, -4(%rdi, %r8) ++ ret ++ ++ .p2align 4 ++L(Fill9_16): ++ mov %rdx, (%rdi) ++ mov %rdx, -8(%rdi, %r8) ++ ret ++ ++ .p2align 4 ++L(Fill17_32): ++ VMOVU %XMMZERO, (%rdi) ++ VMOVU %XMMZERO, -16(%rdi, %r8) ++ ret ++ ++ .p2align 4 ++L(CopyVecSizeUnalignedVec2): ++ VMOVU %YMM2, (%rdi, %rcx) ++ ++ .p2align 4 ++L(CopyVecSizeVecExit): ++ bsf %edx, %edx ++ add $(VEC_SIZE - 1), %r8 ++ add %rcx, %rdi ++# ifdef USE_AS_STPCPY ++ lea (%rdi, %rdx), %rax ++# endif ++ sub %rdx, %r8 ++ lea 1(%rdi, %rdx), %rdi ++ ++ .p2align 4 ++L(StrncpyFillTailWithZero): ++ xor %edx, %edx ++ sub $VEC_SIZE, %r8 ++ jbe L(StrncpyFillExit) ++ ++ VMOVU %YMMZERO, (%rdi) ++ add $VEC_SIZE, %rdi ++ ++ mov %rdi, %rsi ++ and $(VEC_SIZE - 1), %esi ++ sub %rsi, %rdi ++ add %rsi, %r8 ++ sub $(VEC_SIZE * 4), %r8 ++ jb L(StrncpyFillLessFourVecSize) ++ ++L(StrncpyFillLoopVmovdqa): ++ VMOVA %YMMZERO, (%rdi) ++ VMOVA %YMMZERO, VEC_SIZE(%rdi) ++ VMOVA %YMMZERO, (VEC_SIZE * 2)(%rdi) ++ VMOVA %YMMZERO, (VEC_SIZE * 3)(%rdi) ++ add $(VEC_SIZE * 4), %rdi ++ sub $(VEC_SIZE * 4), %r8 ++ jae L(StrncpyFillLoopVmovdqa) ++ ++L(StrncpyFillLessFourVecSize): ++ add $(VEC_SIZE * 2), %r8 ++ jl L(StrncpyFillLessTwoVecSize) ++ VMOVA %YMMZERO, (%rdi) ++ VMOVA %YMMZERO, VEC_SIZE(%rdi) ++ add $(VEC_SIZE * 2), %rdi ++ sub $VEC_SIZE, %r8 ++ jl L(StrncpyFillExit) ++ VMOVA %YMMZERO, (%rdi) ++ add $VEC_SIZE, %rdi ++ jmp L(Fill) ++ ++ .p2align 4 ++L(StrncpyFillLessTwoVecSize): ++ add $VEC_SIZE, %r8 ++ jl L(StrncpyFillExit) ++ VMOVA %YMMZERO, (%rdi) ++ add $VEC_SIZE, %rdi ++ jmp L(Fill) ++ ++ .p2align 4 ++L(StrncpyFillExit): ++ add $VEC_SIZE, %r8 ++L(Fill): ++ cmp $17, %r8d ++ jae L(Fill17_32) ++ cmp $9, %r8d ++ jae L(Fill9_16) ++ cmp $5, %r8d ++ jae L(Fill5_8) ++ cmp $3, %r8d ++ jae L(Fill3_4) ++ cmp $1, %r8d ++ ja L(Fill2) ++ je L(Fill1) ++ ret ++ ++/* end of ifndef USE_AS_STRCAT */ ++# endif ++ ++ .p2align 4 ++L(UnalignedLeaveCase2OrCase3): ++ test %rdx, %rdx ++ jnz L(UnalignedFourVecSizeLeaveCase2) ++L(UnalignedFourVecSizeLeaveCase3): ++ lea (VEC_SIZE * 4)(%r8), %rcx ++ and $-VEC_SIZE, %rcx ++ add $(VEC_SIZE * 3), %r8 ++ jl L(CopyVecSizeCase3) ++ VMOVU %YMM4, (%rdi) ++ sub $VEC_SIZE, %r8 ++ jb L(CopyVecSizeCase3) ++ VMOVU %YMM5, VEC_SIZE(%rdi) ++ sub $VEC_SIZE, %r8 ++ jb L(CopyVecSizeCase3) ++ VMOVU %YMM6, (VEC_SIZE * 2)(%rdi) ++ sub $VEC_SIZE, %r8 ++ jb L(CopyVecSizeCase3) ++ VMOVU %YMM7, (VEC_SIZE * 3)(%rdi) ++# ifdef USE_AS_STPCPY ++ lea (VEC_SIZE * 4)(%rdi), %rax ++# endif ++# ifdef USE_AS_STRCAT ++ movb $0, (VEC_SIZE * 4)(%rdi) ++# endif ++ ret ++ ++ .p2align 4 ++L(UnalignedFourVecSizeLeaveCase2): ++ xor %ecx, %ecx ++ vpcmpb $0, %YMM4, %YMMZERO, %k1 ++ kmovd %k1, %edx ++ add $(VEC_SIZE * 3), %r8 ++ jle L(CopyVecSizeCase2OrCase3) ++ test %edx, %edx ++# ifndef USE_AS_STRCAT ++ jnz L(CopyVecSizeUnalignedVec4) ++# else ++ jnz L(CopyVecSize) ++# endif ++ vpcmpb $0, %YMM5, %YMMZERO, %k2 ++ kmovd %k2, %edx ++ VMOVU %YMM4, (%rdi) ++ add $VEC_SIZE, %rcx ++ sub $VEC_SIZE, %r8 ++ jbe L(CopyVecSizeCase2OrCase3) ++ test %edx, %edx ++# ifndef USE_AS_STRCAT ++ jnz L(CopyVecSizeUnalignedVec5) ++# else ++ jnz L(CopyVecSize) ++# endif ++ ++ vpcmpb $0, %YMM6, %YMMZERO, %k3 ++ kmovd %k3, %edx ++ VMOVU %YMM5, VEC_SIZE(%rdi) ++ add $VEC_SIZE, %rcx ++ sub $VEC_SIZE, %r8 ++ jbe L(CopyVecSizeCase2OrCase3) ++ test %edx, %edx ++# ifndef USE_AS_STRCAT ++ jnz L(CopyVecSizeUnalignedVec6) ++# else ++ jnz L(CopyVecSize) ++# endif ++ ++ vpcmpb $0, %YMM7, %YMMZERO, %k4 ++ kmovd %k4, %edx ++ VMOVU %YMM6, (VEC_SIZE * 2)(%rdi) ++ lea VEC_SIZE(%rdi, %rcx), %rdi ++ lea VEC_SIZE(%rsi, %rcx), %rsi ++ bsf %edx, %edx ++ cmp %r8d, %edx ++ jb L(CopyVecSizeExit) ++L(StrncpyExit): ++ cmp $65, %r8d ++ je L(StrncpyExit65) ++ cmp $33, %r8d ++ jae L(StrncpyExit33_64) ++ cmp $17, %r8d ++ jae L(StrncpyExit17_32) ++ cmp $9, %r8d ++ jae L(StrncpyExit9_16) ++ cmp $5, %r8d ++ jae L(StrncpyExit5_8) ++ cmp $3, %r8d ++ jae L(StrncpyExit3_4) ++ cmp $1, %r8d ++ ja L(StrncpyExit2) ++ je L(StrncpyExit1) ++# ifdef USE_AS_STPCPY ++ mov %rdi, %rax ++# endif ++# ifdef USE_AS_STRCAT ++ movb $0, (%rdi) ++# endif ++ ret ++ ++ .p2align 4 ++L(ExitZero): ++# ifndef USE_AS_STRCAT ++ mov %rdi, %rax ++# endif ++ ret ++ ++# endif ++ ++# ifndef USE_AS_STRCAT ++END (STRCPY) ++# else ++END (STRCAT) ++# endif ++#endif +diff --git a/sysdeps/x86_64/multiarch/strncat-evex.S b/sysdeps/x86_64/multiarch/strncat-evex.S +new file mode 100644 +index 00000000..8884f023 +--- /dev/null ++++ b/sysdeps/x86_64/multiarch/strncat-evex.S +@@ -0,0 +1,3 @@ ++#define USE_AS_STRNCAT ++#define STRCAT __strncat_evex ++#include "strcat-evex.S" +diff --git a/sysdeps/x86_64/multiarch/strncpy-evex.S b/sysdeps/x86_64/multiarch/strncpy-evex.S +new file mode 100644 +index 00000000..40e391f0 +--- /dev/null ++++ b/sysdeps/x86_64/multiarch/strncpy-evex.S +@@ -0,0 +1,3 @@ ++#define USE_AS_STRNCPY ++#define STRCPY __strncpy_evex ++#include "strcpy-evex.S" +-- +GitLab + diff --git a/SOURCES/glibc-RHEL-15696-14.patch b/SOURCES/glibc-RHEL-15696-14.patch new file mode 100644 index 0000000..84a4593 --- /dev/null +++ b/SOURCES/glibc-RHEL-15696-14.patch @@ -0,0 +1,242 @@ +From 63ad43566f7a25d140dc723598aeb441ad657eed Mon Sep 17 00:00:00 2001 +From: "H.J. Lu" +Date: Fri, 5 Mar 2021 06:46:08 -0800 +Subject: [PATCH] x86-64: Add memmove family functions with 256-bit EVEX +Content-type: text/plain; charset=UTF-8 + +Update ifunc-memmove.h to select the function optimized with 256-bit EVEX +instructions using YMM16-YMM31 registers to avoid RTM abort with usable +AVX512VL since VZEROUPPER isn't needed at function exit. +--- + sysdeps/x86_64/multiarch/Makefile | 1 + + sysdeps/x86_64/multiarch/ifunc-impl-list.c | 36 +++++++++++++++++++ + sysdeps/x86_64/multiarch/ifunc-memmove.h | 21 +++++++++-- + .../multiarch/memmove-evex-unaligned-erms.S | 33 +++++++++++++++++ + .../multiarch/memmove-vec-unaligned-erms.S | 24 ++++++++----- + 5 files changed, 104 insertions(+), 11 deletions(-) + create mode 100644 sysdeps/x86_64/multiarch/memmove-evex-unaligned-erms.S + +diff --git a/sysdeps/x86_64/multiarch/Makefile b/sysdeps/x86_64/multiarch/Makefile +index 46783cd1..4563fc56 100644 +--- a/sysdeps/x86_64/multiarch/Makefile ++++ b/sysdeps/x86_64/multiarch/Makefile +@@ -41,6 +41,7 @@ sysdep_routines += strncat-c stpncpy-c strncpy-c \ + memset-avx2-unaligned-erms \ + memset-avx512-unaligned-erms \ + memchr-evex \ ++ memmove-evex-unaligned-erms \ + memrchr-evex \ + rawmemchr-evex \ + stpcpy-evex \ +diff --git a/sysdeps/x86_64/multiarch/ifunc-impl-list.c b/sysdeps/x86_64/multiarch/ifunc-impl-list.c +index 082e4da3..6bd3abfc 100644 +--- a/sysdeps/x86_64/multiarch/ifunc-impl-list.c ++++ b/sysdeps/x86_64/multiarch/ifunc-impl-list.c +@@ -80,6 +80,12 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + IFUNC_IMPL_ADD (array, i, __memmove_chk, + CPU_FEATURE_USABLE (AVX), + __memmove_chk_avx_unaligned_erms) ++ IFUNC_IMPL_ADD (array, i, __memmove_chk, ++ CPU_FEATURE_USABLE (AVX512VL), ++ __memmove_chk_evex_unaligned) ++ IFUNC_IMPL_ADD (array, i, __memmove_chk, ++ CPU_FEATURE_USABLE (AVX512VL), ++ __memmove_chk_evex_unaligned_erms) + IFUNC_IMPL_ADD (array, i, __memmove_chk, + CPU_FEATURE_USABLE (SSSE3), + __memmove_chk_ssse3_back) +@@ -102,6 +108,12 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + IFUNC_IMPL_ADD (array, i, memmove, + CPU_FEATURE_USABLE (AVX), + __memmove_avx_unaligned_erms) ++ IFUNC_IMPL_ADD (array, i, memmove, ++ CPU_FEATURE_USABLE (AVX512VL), ++ __memmove_evex_unaligned) ++ IFUNC_IMPL_ADD (array, i, memmove, ++ CPU_FEATURE_USABLE (AVX512VL), ++ __memmove_evex_unaligned_erms) + IFUNC_IMPL_ADD (array, i, memmove, + CPU_FEATURE_USABLE (AVX512F), + __memmove_avx512_no_vzeroupper) +@@ -565,6 +577,12 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + IFUNC_IMPL_ADD (array, i, __memcpy_chk, + CPU_FEATURE_USABLE (AVX), + __memcpy_chk_avx_unaligned_erms) ++ IFUNC_IMPL_ADD (array, i, __memcpy_chk, ++ CPU_FEATURE_USABLE (AVX512VL), ++ __memcpy_chk_evex_unaligned) ++ IFUNC_IMPL_ADD (array, i, __memcpy_chk, ++ CPU_FEATURE_USABLE (AVX512VL), ++ __memcpy_chk_evex_unaligned_erms) + IFUNC_IMPL_ADD (array, i, __memcpy_chk, + CPU_FEATURE_USABLE (SSSE3), + __memcpy_chk_ssse3_back) +@@ -587,6 +605,12 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + IFUNC_IMPL_ADD (array, i, memcpy, + CPU_FEATURE_USABLE (AVX), + __memcpy_avx_unaligned_erms) ++ IFUNC_IMPL_ADD (array, i, memcpy, ++ CPU_FEATURE_USABLE (AVX512VL), ++ __memcpy_evex_unaligned) ++ IFUNC_IMPL_ADD (array, i, memcpy, ++ CPU_FEATURE_USABLE (AVX512VL), ++ __memcpy_evex_unaligned_erms) + IFUNC_IMPL_ADD (array, i, memcpy, CPU_FEATURE_USABLE (SSSE3), + __memcpy_ssse3_back) + IFUNC_IMPL_ADD (array, i, memcpy, CPU_FEATURE_USABLE (SSSE3), +@@ -623,6 +647,12 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + IFUNC_IMPL_ADD (array, i, __mempcpy_chk, + CPU_FEATURE_USABLE (AVX), + __mempcpy_chk_avx_unaligned_erms) ++ IFUNC_IMPL_ADD (array, i, __mempcpy_chk, ++ CPU_FEATURE_USABLE (AVX512VL), ++ __mempcpy_chk_evex_unaligned) ++ IFUNC_IMPL_ADD (array, i, __mempcpy_chk, ++ CPU_FEATURE_USABLE (AVX512VL), ++ __mempcpy_chk_evex_unaligned_erms) + IFUNC_IMPL_ADD (array, i, __mempcpy_chk, + CPU_FEATURE_USABLE (SSSE3), + __mempcpy_chk_ssse3_back) +@@ -654,6 +684,12 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + IFUNC_IMPL_ADD (array, i, mempcpy, + CPU_FEATURE_USABLE (AVX), + __mempcpy_avx_unaligned_erms) ++ IFUNC_IMPL_ADD (array, i, mempcpy, ++ CPU_FEATURE_USABLE (AVX512VL), ++ __mempcpy_evex_unaligned) ++ IFUNC_IMPL_ADD (array, i, mempcpy, ++ CPU_FEATURE_USABLE (AVX512VL), ++ __mempcpy_evex_unaligned_erms) + IFUNC_IMPL_ADD (array, i, mempcpy, CPU_FEATURE_USABLE (SSSE3), + __mempcpy_ssse3_back) + IFUNC_IMPL_ADD (array, i, mempcpy, CPU_FEATURE_USABLE (SSSE3), +diff --git a/sysdeps/x86_64/multiarch/ifunc-memmove.h b/sysdeps/x86_64/multiarch/ifunc-memmove.h +index 5e5f0299..6f8bce5f 100644 +--- a/sysdeps/x86_64/multiarch/ifunc-memmove.h ++++ b/sysdeps/x86_64/multiarch/ifunc-memmove.h +@@ -29,6 +29,10 @@ extern __typeof (REDIRECT_NAME) OPTIMIZE (ssse3_back) attribute_hidden; + extern __typeof (REDIRECT_NAME) OPTIMIZE (avx_unaligned) attribute_hidden; + extern __typeof (REDIRECT_NAME) OPTIMIZE (avx_unaligned_erms) + attribute_hidden; ++extern __typeof (REDIRECT_NAME) OPTIMIZE (evex_unaligned) ++ attribute_hidden; ++extern __typeof (REDIRECT_NAME) OPTIMIZE (evex_unaligned_erms) ++ attribute_hidden; + extern __typeof (REDIRECT_NAME) OPTIMIZE (avx512_unaligned) + attribute_hidden; + extern __typeof (REDIRECT_NAME) OPTIMIZE (avx512_unaligned_erms) +@@ -59,10 +63,21 @@ IFUNC_SELECTOR (void) + + if (CPU_FEATURES_ARCH_P (cpu_features, AVX_Fast_Unaligned_Load)) + { +- if (CPU_FEATURE_USABLE_P (cpu_features, ERMS)) +- return OPTIMIZE (avx_unaligned_erms); ++ if (CPU_FEATURE_USABLE_P (cpu_features, AVX512VL)) ++ { ++ if (CPU_FEATURE_USABLE_P (cpu_features, ERMS)) ++ return OPTIMIZE (evex_unaligned_erms); ++ ++ return OPTIMIZE (evex_unaligned); ++ } ++ ++ if (!CPU_FEATURES_ARCH_P (cpu_features, Prefer_No_VZEROUPPER)) ++ { ++ if (CPU_FEATURE_USABLE_P (cpu_features, ERMS)) ++ return OPTIMIZE (avx_unaligned_erms); + +- return OPTIMIZE (avx_unaligned); ++ return OPTIMIZE (avx_unaligned); ++ } + } + + if (!CPU_FEATURE_USABLE_P (cpu_features, SSSE3) +diff --git a/sysdeps/x86_64/multiarch/memmove-evex-unaligned-erms.S b/sysdeps/x86_64/multiarch/memmove-evex-unaligned-erms.S +new file mode 100644 +index 00000000..0cbce8f9 +--- /dev/null ++++ b/sysdeps/x86_64/multiarch/memmove-evex-unaligned-erms.S +@@ -0,0 +1,33 @@ ++#if IS_IN (libc) ++# define VEC_SIZE 32 ++# define XMM0 xmm16 ++# define XMM1 xmm17 ++# define YMM0 ymm16 ++# define YMM1 ymm17 ++# define VEC0 ymm16 ++# define VEC1 ymm17 ++# define VEC2 ymm18 ++# define VEC3 ymm19 ++# define VEC4 ymm20 ++# define VEC5 ymm21 ++# define VEC6 ymm22 ++# define VEC7 ymm23 ++# define VEC8 ymm24 ++# define VEC9 ymm25 ++# define VEC10 ymm26 ++# define VEC11 ymm27 ++# define VEC12 ymm28 ++# define VEC13 ymm29 ++# define VEC14 ymm30 ++# define VEC15 ymm31 ++# define VEC(i) VEC##i ++# define VMOVNT vmovntdq ++# define VMOVU vmovdqu64 ++# define VMOVA vmovdqa64 ++# define VZEROUPPER ++ ++# define SECTION(p) p##.evex ++# define MEMMOVE_SYMBOL(p,s) p##_evex_##s ++ ++# include "memmove-vec-unaligned-erms.S" ++#endif +diff --git a/sysdeps/x86_64/multiarch/memmove-vec-unaligned-erms.S b/sysdeps/x86_64/multiarch/memmove-vec-unaligned-erms.S +index 274aa1c7..08e21692 100644 +--- a/sysdeps/x86_64/multiarch/memmove-vec-unaligned-erms.S ++++ b/sysdeps/x86_64/multiarch/memmove-vec-unaligned-erms.S +@@ -48,6 +48,14 @@ + # define MEMMOVE_CHK_SYMBOL(p,s) MEMMOVE_SYMBOL(p, s) + #endif + ++#ifndef XMM0 ++# define XMM0 xmm0 ++#endif ++ ++#ifndef YMM0 ++# define YMM0 ymm0 ++#endif ++ + #ifndef VZEROUPPER + # if VEC_SIZE > 16 + # define VZEROUPPER vzeroupper +@@ -277,20 +285,20 @@ L(less_vec): + #if VEC_SIZE > 32 + L(between_32_63): + /* From 32 to 63. No branch when size == 32. */ +- vmovdqu (%rsi), %ymm0 +- vmovdqu -32(%rsi,%rdx), %ymm1 +- vmovdqu %ymm0, (%rdi) +- vmovdqu %ymm1, -32(%rdi,%rdx) ++ VMOVU (%rsi), %YMM0 ++ VMOVU -32(%rsi,%rdx), %YMM1 ++ VMOVU %YMM0, (%rdi) ++ VMOVU %YMM1, -32(%rdi,%rdx) + VZEROUPPER + ret + #endif + #if VEC_SIZE > 16 + /* From 16 to 31. No branch when size == 16. */ + L(between_16_31): +- vmovdqu (%rsi), %xmm0 +- vmovdqu -16(%rsi,%rdx), %xmm1 +- vmovdqu %xmm0, (%rdi) +- vmovdqu %xmm1, -16(%rdi,%rdx) ++ VMOVU (%rsi), %XMM0 ++ VMOVU -16(%rsi,%rdx), %XMM1 ++ VMOVU %XMM0, (%rdi) ++ VMOVU %XMM1, -16(%rdi,%rdx) + ret + #endif + L(between_8_15): +-- +GitLab + diff --git a/SOURCES/glibc-RHEL-15696-15.patch b/SOURCES/glibc-RHEL-15696-15.patch new file mode 100644 index 0000000..72cd8cf --- /dev/null +++ b/SOURCES/glibc-RHEL-15696-15.patch @@ -0,0 +1,254 @@ +From 1b968b6b9b3aac702ac2f133e0dd16cfdbb415ee Mon Sep 17 00:00:00 2001 +From: "H.J. Lu" +Date: Fri, 5 Mar 2021 07:15:03 -0800 +Subject: [PATCH] x86-64: Add memset family functions with 256-bit EVEX +Content-type: text/plain; charset=UTF-8 + +Update ifunc-memset.h/ifunc-wmemset.h to select the function optimized +with 256-bit EVEX instructions using YMM16-YMM31 registers to avoid RTM +abort with usable AVX512VL and AVX512BW since VZEROUPPER isn't needed at +function exit. +--- + sysdeps/x86_64/multiarch/Makefile | 1 + + sysdeps/x86_64/multiarch/ifunc-impl-list.c | 22 +++++++++++++++++ + sysdeps/x86_64/multiarch/ifunc-memset.h | 24 +++++++++++++++---- + sysdeps/x86_64/multiarch/ifunc-wmemset.h | 13 ++++++---- + .../multiarch/memset-evex-unaligned-erms.S | 24 +++++++++++++++++++ + .../multiarch/memset-vec-unaligned-erms.S | 20 +++++++++++----- + 6 files changed, 90 insertions(+), 14 deletions(-) + create mode 100644 sysdeps/x86_64/multiarch/memset-evex-unaligned-erms.S + +diff --git a/sysdeps/x86_64/multiarch/Makefile b/sysdeps/x86_64/multiarch/Makefile +index 4563fc56..1cc0a10e 100644 +--- a/sysdeps/x86_64/multiarch/Makefile ++++ b/sysdeps/x86_64/multiarch/Makefile +@@ -43,6 +43,7 @@ sysdep_routines += strncat-c stpncpy-c strncpy-c \ + memchr-evex \ + memmove-evex-unaligned-erms \ + memrchr-evex \ ++ memset-evex-unaligned-erms \ + rawmemchr-evex \ + stpcpy-evex \ + stpncpy-evex \ +diff --git a/sysdeps/x86_64/multiarch/ifunc-impl-list.c b/sysdeps/x86_64/multiarch/ifunc-impl-list.c +index 6bd3abfc..7cf83485 100644 +--- a/sysdeps/x86_64/multiarch/ifunc-impl-list.c ++++ b/sysdeps/x86_64/multiarch/ifunc-impl-list.c +@@ -160,6 +160,14 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + IFUNC_IMPL_ADD (array, i, __memset_chk, + CPU_FEATURE_USABLE (AVX2), + __memset_chk_avx2_unaligned_erms) ++ IFUNC_IMPL_ADD (array, i, __memset_chk, ++ (CPU_FEATURE_USABLE (AVX512VL) ++ && CPU_FEATURE_USABLE (AVX512BW)), ++ __memset_chk_evex_unaligned) ++ IFUNC_IMPL_ADD (array, i, __memset_chk, ++ (CPU_FEATURE_USABLE (AVX512VL) ++ && CPU_FEATURE_USABLE (AVX512BW)), ++ __memset_chk_evex_unaligned_erms) + IFUNC_IMPL_ADD (array, i, __memset_chk, + CPU_FEATURE_USABLE (AVX512F), + __memset_chk_avx512_unaligned_erms) +@@ -185,6 +193,14 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + IFUNC_IMPL_ADD (array, i, memset, + CPU_FEATURE_USABLE (AVX2), + __memset_avx2_unaligned_erms) ++ IFUNC_IMPL_ADD (array, i, memset, ++ (CPU_FEATURE_USABLE (AVX512VL) ++ && CPU_FEATURE_USABLE (AVX512BW)), ++ __memset_evex_unaligned) ++ IFUNC_IMPL_ADD (array, i, memset, ++ (CPU_FEATURE_USABLE (AVX512VL) ++ && CPU_FEATURE_USABLE (AVX512BW)), ++ __memset_evex_unaligned_erms) + IFUNC_IMPL_ADD (array, i, memset, + CPU_FEATURE_USABLE (AVX512F), + __memset_avx512_unaligned_erms) +@@ -555,6 +571,9 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + IFUNC_IMPL_ADD (array, i, wmemset, + CPU_FEATURE_USABLE (AVX2), + __wmemset_avx2_unaligned) ++ IFUNC_IMPL_ADD (array, i, wmemset, ++ CPU_FEATURE_USABLE (AVX512VL), ++ __wmemset_evex_unaligned) + IFUNC_IMPL_ADD (array, i, wmemset, + CPU_FEATURE_USABLE (AVX512F), + __wmemset_avx512_unaligned)) +@@ -723,6 +742,9 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + IFUNC_IMPL_ADD (array, i, __wmemset_chk, + CPU_FEATURE_USABLE (AVX2), + __wmemset_chk_avx2_unaligned) ++ IFUNC_IMPL_ADD (array, i, __wmemset_chk, ++ CPU_FEATURE_USABLE (AVX512VL), ++ __wmemset_chk_evex_unaligned) + IFUNC_IMPL_ADD (array, i, __wmemset_chk, + CPU_FEATURE_USABLE (AVX512F), + __wmemset_chk_avx512_unaligned)) +diff --git a/sysdeps/x86_64/multiarch/ifunc-memset.h b/sysdeps/x86_64/multiarch/ifunc-memset.h +index 708bd72e..6f31f4dc 100644 +--- a/sysdeps/x86_64/multiarch/ifunc-memset.h ++++ b/sysdeps/x86_64/multiarch/ifunc-memset.h +@@ -27,6 +27,10 @@ extern __typeof (REDIRECT_NAME) OPTIMIZE (sse2_unaligned_erms) + extern __typeof (REDIRECT_NAME) OPTIMIZE (avx2_unaligned) attribute_hidden; + extern __typeof (REDIRECT_NAME) OPTIMIZE (avx2_unaligned_erms) + attribute_hidden; ++extern __typeof (REDIRECT_NAME) OPTIMIZE (evex_unaligned) ++ attribute_hidden; ++extern __typeof (REDIRECT_NAME) OPTIMIZE (evex_unaligned_erms) ++ attribute_hidden; + extern __typeof (REDIRECT_NAME) OPTIMIZE (avx512_unaligned) + attribute_hidden; + extern __typeof (REDIRECT_NAME) OPTIMIZE (avx512_unaligned_erms) +@@ -56,10 +60,22 @@ IFUNC_SELECTOR (void) + + if (CPU_FEATURE_USABLE_P (cpu_features, AVX2)) + { +- if (CPU_FEATURE_USABLE_P (cpu_features, ERMS)) +- return OPTIMIZE (avx2_unaligned_erms); +- else +- return OPTIMIZE (avx2_unaligned); ++ if (CPU_FEATURE_USABLE_P (cpu_features, AVX512VL) ++ && CPU_FEATURE_USABLE_P (cpu_features, AVX512BW)) ++ { ++ if (CPU_FEATURE_USABLE_P (cpu_features, ERMS)) ++ return OPTIMIZE (evex_unaligned_erms); ++ ++ return OPTIMIZE (evex_unaligned); ++ } ++ ++ if (!CPU_FEATURES_ARCH_P (cpu_features, Prefer_No_VZEROUPPER)) ++ { ++ if (CPU_FEATURE_USABLE_P (cpu_features, ERMS)) ++ return OPTIMIZE (avx2_unaligned_erms); ++ ++ return OPTIMIZE (avx2_unaligned); ++ } + } + + if (CPU_FEATURE_USABLE_P (cpu_features, ERMS)) +diff --git a/sysdeps/x86_64/multiarch/ifunc-wmemset.h b/sysdeps/x86_64/multiarch/ifunc-wmemset.h +index eb242210..9290c4bf 100644 +--- a/sysdeps/x86_64/multiarch/ifunc-wmemset.h ++++ b/sysdeps/x86_64/multiarch/ifunc-wmemset.h +@@ -20,6 +20,7 @@ + + extern __typeof (REDIRECT_NAME) OPTIMIZE (sse2_unaligned) attribute_hidden; + extern __typeof (REDIRECT_NAME) OPTIMIZE (avx2_unaligned) attribute_hidden; ++extern __typeof (REDIRECT_NAME) OPTIMIZE (evex_unaligned) attribute_hidden; + extern __typeof (REDIRECT_NAME) OPTIMIZE (avx512_unaligned) attribute_hidden; + + static inline void * +@@ -27,14 +28,18 @@ IFUNC_SELECTOR (void) + { + const struct cpu_features* cpu_features = __get_cpu_features (); + +- if (!CPU_FEATURES_ARCH_P (cpu_features, Prefer_No_VZEROUPPER) +- && CPU_FEATURE_USABLE_P (cpu_features, AVX2) ++ if (CPU_FEATURE_USABLE_P (cpu_features, AVX2) + && CPU_FEATURES_ARCH_P (cpu_features, AVX_Fast_Unaligned_Load)) + { + if (CPU_FEATURE_USABLE_P (cpu_features, AVX512F) +- && !CPU_FEATURES_ARCH_P (cpu_features, Prefer_No_AVX512)) ++ && !CPU_FEATURES_ARCH_P (cpu_features, Prefer_No_AVX512) ++ && !CPU_FEATURES_ARCH_P (cpu_features, Prefer_No_VZEROUPPER)) + return OPTIMIZE (avx512_unaligned); +- else ++ ++ if (CPU_FEATURE_USABLE_P (cpu_features, AVX512VL)) ++ return OPTIMIZE (evex_unaligned); ++ ++ if (!CPU_FEATURES_ARCH_P (cpu_features, Prefer_No_VZEROUPPER)) + return OPTIMIZE (avx2_unaligned); + } + +diff --git a/sysdeps/x86_64/multiarch/memset-evex-unaligned-erms.S b/sysdeps/x86_64/multiarch/memset-evex-unaligned-erms.S +new file mode 100644 +index 00000000..ae0a4d6e +--- /dev/null ++++ b/sysdeps/x86_64/multiarch/memset-evex-unaligned-erms.S +@@ -0,0 +1,24 @@ ++#if IS_IN (libc) ++# define VEC_SIZE 32 ++# define XMM0 xmm16 ++# define YMM0 ymm16 ++# define VEC0 ymm16 ++# define VEC(i) VEC##i ++# define VMOVU vmovdqu64 ++# define VMOVA vmovdqa64 ++# define VZEROUPPER ++ ++# define MEMSET_VDUP_TO_VEC0_AND_SET_RETURN(d, r) \ ++ movq r, %rax; \ ++ vpbroadcastb d, %VEC0 ++ ++# define WMEMSET_VDUP_TO_VEC0_AND_SET_RETURN(d, r) \ ++ movq r, %rax; \ ++ vpbroadcastd d, %VEC0 ++ ++# define SECTION(p) p##.evex ++# define MEMSET_SYMBOL(p,s) p##_evex_##s ++# define WMEMSET_SYMBOL(p,s) p##_evex_##s ++ ++# include "memset-vec-unaligned-erms.S" ++#endif +diff --git a/sysdeps/x86_64/multiarch/memset-vec-unaligned-erms.S b/sysdeps/x86_64/multiarch/memset-vec-unaligned-erms.S +index 9a0fd818..71e91a8f 100644 +--- a/sysdeps/x86_64/multiarch/memset-vec-unaligned-erms.S ++++ b/sysdeps/x86_64/multiarch/memset-vec-unaligned-erms.S +@@ -34,6 +34,14 @@ + # define WMEMSET_CHK_SYMBOL(p,s) WMEMSET_SYMBOL(p, s) + #endif + ++#ifndef XMM0 ++# define XMM0 xmm0 ++#endif ++ ++#ifndef YMM0 ++# define YMM0 ymm0 ++#endif ++ + #ifndef VZEROUPPER + # if VEC_SIZE > 16 + # define VZEROUPPER vzeroupper +@@ -67,7 +75,7 @@ + ENTRY (__bzero) + mov %RDI_LP, %RAX_LP /* Set return value. */ + mov %RSI_LP, %RDX_LP /* Set n. */ +- pxor %xmm0, %xmm0 ++ pxor %XMM0, %XMM0 + jmp L(entry_from_bzero) + END (__bzero) + weak_alias (__bzero, bzero) +@@ -223,7 +231,7 @@ L(less_vec): + cmpb $16, %dl + jae L(between_16_31) + # endif +- MOVQ %xmm0, %rcx ++ MOVQ %XMM0, %rcx + cmpb $8, %dl + jae L(between_8_15) + cmpb $4, %dl +@@ -238,16 +246,16 @@ L(less_vec): + # if VEC_SIZE > 32 + /* From 32 to 63. No branch when size == 32. */ + L(between_32_63): +- vmovdqu %ymm0, -32(%rdi,%rdx) +- vmovdqu %ymm0, (%rdi) ++ VMOVU %YMM0, -32(%rdi,%rdx) ++ VMOVU %YMM0, (%rdi) + VZEROUPPER + ret + # endif + # if VEC_SIZE > 16 + /* From 16 to 31. No branch when size == 16. */ + L(between_16_31): +- vmovdqu %xmm0, -16(%rdi,%rdx) +- vmovdqu %xmm0, (%rdi) ++ VMOVU %XMM0, -16(%rdi,%rdx) ++ VMOVU %XMM0, (%rdi) + VZEROUPPER + ret + # endif +-- +GitLab + diff --git a/SOURCES/glibc-RHEL-15696-16.patch b/SOURCES/glibc-RHEL-15696-16.patch new file mode 100644 index 0000000..b3f443d --- /dev/null +++ b/SOURCES/glibc-RHEL-15696-16.patch @@ -0,0 +1,561 @@ +From 91264fe3577fe887b4860923fa6142b5274c8965 Mon Sep 17 00:00:00 2001 +From: "H.J. Lu" +Date: Fri, 5 Mar 2021 07:20:28 -0800 +Subject: [PATCH] x86-64: Add memcmp family functions with 256-bit EVEX +Content-type: text/plain; charset=UTF-8 + +Update ifunc-memcmp.h to select the function optimized with 256-bit EVEX +instructions using YMM16-YMM31 registers to avoid RTM abort with usable +AVX512VL, AVX512BW and MOVBE since VZEROUPPER isn't needed at function +exit. +--- + sysdeps/x86_64/multiarch/Makefile | 4 +- + sysdeps/x86_64/multiarch/ifunc-impl-list.c | 10 + + sysdeps/x86_64/multiarch/ifunc-memcmp.h | 13 +- + sysdeps/x86_64/multiarch/memcmp-evex-movbe.S | 440 ++++++++++++++++++ + sysdeps/x86_64/multiarch/wmemcmp-evex-movbe.S | 4 + + 5 files changed, 467 insertions(+), 4 deletions(-) + create mode 100644 sysdeps/x86_64/multiarch/memcmp-evex-movbe.S + create mode 100644 sysdeps/x86_64/multiarch/wmemcmp-evex-movbe.S + +diff --git a/sysdeps/x86_64/multiarch/Makefile b/sysdeps/x86_64/multiarch/Makefile +index 1cc0a10e..9d79b138 100644 +--- a/sysdeps/x86_64/multiarch/Makefile ++++ b/sysdeps/x86_64/multiarch/Makefile +@@ -41,6 +41,7 @@ sysdep_routines += strncat-c stpncpy-c strncpy-c \ + memset-avx2-unaligned-erms \ + memset-avx512-unaligned-erms \ + memchr-evex \ ++ memcmp-evex-movbe \ + memmove-evex-unaligned-erms \ + memrchr-evex \ + memset-evex-unaligned-erms \ +@@ -81,7 +82,8 @@ sysdep_routines += wmemcmp-sse4 wmemcmp-ssse3 wmemcmp-c \ + wcsncmp-evex \ + wcsnlen-evex \ + wcsrchr-evex \ +- wmemchr-evex ++ wmemchr-evex \ ++ wmemcmp-evex-movbe + endif + + ifeq ($(subdir),debug) +diff --git a/sysdeps/x86_64/multiarch/ifunc-impl-list.c b/sysdeps/x86_64/multiarch/ifunc-impl-list.c +index 7cf83485..c8da910e 100644 +--- a/sysdeps/x86_64/multiarch/ifunc-impl-list.c ++++ b/sysdeps/x86_64/multiarch/ifunc-impl-list.c +@@ -56,6 +56,11 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + (CPU_FEATURE_USABLE (AVX2) + && CPU_FEATURE_USABLE (MOVBE)), + __memcmp_avx2_movbe) ++ IFUNC_IMPL_ADD (array, i, memcmp, ++ (CPU_FEATURE_USABLE (AVX512VL) ++ && CPU_FEATURE_USABLE (AVX512BW) ++ && CPU_FEATURE_USABLE (MOVBE)), ++ __memcmp_evex_movbe) + IFUNC_IMPL_ADD (array, i, memcmp, CPU_FEATURE_USABLE (SSE4_1), + __memcmp_sse4_1) + IFUNC_IMPL_ADD (array, i, memcmp, CPU_FEATURE_USABLE (SSSE3), +@@ -558,6 +563,11 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + (CPU_FEATURE_USABLE (AVX2) + && CPU_FEATURE_USABLE (MOVBE)), + __wmemcmp_avx2_movbe) ++ IFUNC_IMPL_ADD (array, i, wmemcmp, ++ (CPU_FEATURE_USABLE (AVX512VL) ++ && CPU_FEATURE_USABLE (AVX512BW) ++ && CPU_FEATURE_USABLE (MOVBE)), ++ __wmemcmp_evex_movbe) + IFUNC_IMPL_ADD (array, i, wmemcmp, CPU_FEATURE_USABLE (SSE4_1), + __wmemcmp_sse4_1) + IFUNC_IMPL_ADD (array, i, wmemcmp, CPU_FEATURE_USABLE (SSSE3), +diff --git a/sysdeps/x86_64/multiarch/ifunc-memcmp.h b/sysdeps/x86_64/multiarch/ifunc-memcmp.h +index 6c1f3153..3ca1f0a6 100644 +--- a/sysdeps/x86_64/multiarch/ifunc-memcmp.h ++++ b/sysdeps/x86_64/multiarch/ifunc-memcmp.h +@@ -23,17 +23,24 @@ extern __typeof (REDIRECT_NAME) OPTIMIZE (sse2) attribute_hidden; + extern __typeof (REDIRECT_NAME) OPTIMIZE (ssse3) attribute_hidden; + extern __typeof (REDIRECT_NAME) OPTIMIZE (sse4_1) attribute_hidden; + extern __typeof (REDIRECT_NAME) OPTIMIZE (avx2_movbe) attribute_hidden; ++extern __typeof (REDIRECT_NAME) OPTIMIZE (evex_movbe) attribute_hidden; + + static inline void * + IFUNC_SELECTOR (void) + { + const struct cpu_features* cpu_features = __get_cpu_features (); + +- if (!CPU_FEATURES_ARCH_P (cpu_features, Prefer_No_VZEROUPPER) +- && CPU_FEATURE_USABLE_P (cpu_features, AVX2) ++ if (CPU_FEATURE_USABLE_P (cpu_features, AVX2) + && CPU_FEATURE_USABLE_P (cpu_features, MOVBE) + && CPU_FEATURES_ARCH_P (cpu_features, AVX_Fast_Unaligned_Load)) +- return OPTIMIZE (avx2_movbe); ++ { ++ if (CPU_FEATURE_USABLE_P (cpu_features, AVX512VL) ++ && CPU_FEATURE_USABLE_P (cpu_features, AVX512BW)) ++ return OPTIMIZE (evex_movbe); ++ ++ if (!CPU_FEATURES_ARCH_P (cpu_features, Prefer_No_VZEROUPPER)) ++ return OPTIMIZE (avx2_movbe); ++ } + + if (CPU_FEATURE_USABLE_P (cpu_features, SSE4_1)) + return OPTIMIZE (sse4_1); +diff --git a/sysdeps/x86_64/multiarch/memcmp-evex-movbe.S b/sysdeps/x86_64/multiarch/memcmp-evex-movbe.S +new file mode 100644 +index 00000000..9c093972 +--- /dev/null ++++ b/sysdeps/x86_64/multiarch/memcmp-evex-movbe.S +@@ -0,0 +1,440 @@ ++/* memcmp/wmemcmp optimized with 256-bit EVEX instructions. ++ 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 ++ . */ ++ ++#if IS_IN (libc) ++ ++/* memcmp/wmemcmp is implemented as: ++ 1. For size from 2 to 7 bytes, load as big endian with movbe and bswap ++ to avoid branches. ++ 2. Use overlapping compare to avoid branch. ++ 3. Use vector compare when size >= 4 bytes for memcmp or size >= 8 ++ bytes for wmemcmp. ++ 4. If size is 8 * VEC_SIZE or less, unroll the loop. ++ 5. Compare 4 * VEC_SIZE at a time with the aligned first memory ++ area. ++ 6. Use 2 vector compares when size is 2 * VEC_SIZE or less. ++ 7. Use 4 vector compares when size is 4 * VEC_SIZE or less. ++ 8. Use 8 vector compares when size is 8 * VEC_SIZE or less. */ ++ ++# include ++ ++# ifndef MEMCMP ++# define MEMCMP __memcmp_evex_movbe ++# endif ++ ++# define VMOVU vmovdqu64 ++ ++# ifdef USE_AS_WMEMCMP ++# define VPCMPEQ vpcmpeqd ++# else ++# define VPCMPEQ vpcmpeqb ++# endif ++ ++# define XMM1 xmm17 ++# define XMM2 xmm18 ++# define YMM1 ymm17 ++# define YMM2 ymm18 ++# define YMM3 ymm19 ++# define YMM4 ymm20 ++# define YMM5 ymm21 ++# define YMM6 ymm22 ++ ++# define VEC_SIZE 32 ++# ifdef USE_AS_WMEMCMP ++# define VEC_MASK 0xff ++# define XMM_MASK 0xf ++# else ++# define VEC_MASK 0xffffffff ++# define XMM_MASK 0xffff ++# endif ++ ++/* Warning! ++ wmemcmp has to use SIGNED comparison for elements. ++ memcmp has to use UNSIGNED comparison for elemnts. ++*/ ++ ++ .section .text.evex,"ax",@progbits ++ENTRY (MEMCMP) ++# ifdef USE_AS_WMEMCMP ++ shl $2, %RDX_LP ++# elif defined __ILP32__ ++ /* Clear the upper 32 bits. */ ++ movl %edx, %edx ++# endif ++ cmp $VEC_SIZE, %RDX_LP ++ jb L(less_vec) ++ ++ /* From VEC to 2 * VEC. No branch when size == VEC_SIZE. */ ++ VMOVU (%rsi), %YMM2 ++ VPCMPEQ (%rdi), %YMM2, %k1 ++ kmovd %k1, %eax ++ subl $VEC_MASK, %eax ++ jnz L(first_vec) ++ ++ cmpq $(VEC_SIZE * 2), %rdx ++ jbe L(last_vec) ++ ++ /* More than 2 * VEC. */ ++ cmpq $(VEC_SIZE * 8), %rdx ++ ja L(more_8x_vec) ++ cmpq $(VEC_SIZE * 4), %rdx ++ jb L(last_4x_vec) ++ ++ /* From 4 * VEC to 8 * VEC, inclusively. */ ++ VMOVU (%rsi), %YMM1 ++ VPCMPEQ (%rdi), %YMM1, %k1 ++ ++ VMOVU VEC_SIZE(%rsi), %YMM2 ++ VPCMPEQ VEC_SIZE(%rdi), %YMM2, %k2 ++ ++ VMOVU (VEC_SIZE * 2)(%rsi), %YMM3 ++ VPCMPEQ (VEC_SIZE * 2)(%rdi), %YMM3, %k3 ++ ++ VMOVU (VEC_SIZE * 3)(%rsi), %YMM4 ++ VPCMPEQ (VEC_SIZE * 3)(%rdi), %YMM4, %k4 ++ ++ kandd %k1, %k2, %k5 ++ kandd %k3, %k4, %k6 ++ kandd %k5, %k6, %k6 ++ ++ kmovd %k6, %eax ++ cmpl $VEC_MASK, %eax ++ jne L(4x_vec_end) ++ ++ leaq -(4 * VEC_SIZE)(%rdi, %rdx), %rdi ++ leaq -(4 * VEC_SIZE)(%rsi, %rdx), %rsi ++ VMOVU (%rsi), %YMM1 ++ VPCMPEQ (%rdi), %YMM1, %k1 ++ ++ VMOVU VEC_SIZE(%rsi), %YMM2 ++ VPCMPEQ VEC_SIZE(%rdi), %YMM2, %k2 ++ kandd %k1, %k2, %k5 ++ ++ VMOVU (VEC_SIZE * 2)(%rsi), %YMM3 ++ VPCMPEQ (VEC_SIZE * 2)(%rdi), %YMM3, %k3 ++ kandd %k3, %k5, %k5 ++ ++ VMOVU (VEC_SIZE * 3)(%rsi), %YMM4 ++ VPCMPEQ (VEC_SIZE * 3)(%rdi), %YMM4, %k4 ++ kandd %k4, %k5, %k5 ++ ++ kmovd %k5, %eax ++ cmpl $VEC_MASK, %eax ++ jne L(4x_vec_end) ++ xorl %eax, %eax ++ ret ++ ++ .p2align 4 ++L(last_2x_vec): ++ /* From VEC to 2 * VEC. No branch when size == VEC_SIZE. */ ++ VMOVU (%rsi), %YMM2 ++ VPCMPEQ (%rdi), %YMM2, %k2 ++ kmovd %k2, %eax ++ subl $VEC_MASK, %eax ++ jnz L(first_vec) ++ ++L(last_vec): ++ /* Use overlapping loads to avoid branches. */ ++ leaq -VEC_SIZE(%rdi, %rdx), %rdi ++ leaq -VEC_SIZE(%rsi, %rdx), %rsi ++ VMOVU (%rsi), %YMM2 ++ VPCMPEQ (%rdi), %YMM2, %k2 ++ kmovd %k2, %eax ++ subl $VEC_MASK, %eax ++ jnz L(first_vec) ++ ret ++ ++ .p2align 4 ++L(first_vec): ++ /* A byte or int32 is different within 16 or 32 bytes. */ ++ tzcntl %eax, %ecx ++# ifdef USE_AS_WMEMCMP ++ xorl %eax, %eax ++ movl (%rdi, %rcx, 4), %edx ++ cmpl (%rsi, %rcx, 4), %edx ++L(wmemcmp_return): ++ setl %al ++ negl %eax ++ orl $1, %eax ++# else ++ movzbl (%rdi, %rcx), %eax ++ movzbl (%rsi, %rcx), %edx ++ sub %edx, %eax ++# endif ++ ret ++ ++# ifdef USE_AS_WMEMCMP ++ .p2align 4 ++L(4): ++ xorl %eax, %eax ++ movl (%rdi), %edx ++ cmpl (%rsi), %edx ++ jne L(wmemcmp_return) ++ ret ++# else ++ .p2align 4 ++L(between_4_7): ++ /* Load as big endian with overlapping movbe to avoid branches. */ ++ movbe (%rdi), %eax ++ movbe (%rsi), %ecx ++ shlq $32, %rax ++ shlq $32, %rcx ++ movbe -4(%rdi, %rdx), %edi ++ movbe -4(%rsi, %rdx), %esi ++ orq %rdi, %rax ++ orq %rsi, %rcx ++ subq %rcx, %rax ++ je L(exit) ++ sbbl %eax, %eax ++ orl $1, %eax ++ ret ++ ++ .p2align 4 ++L(exit): ++ ret ++ ++ .p2align 4 ++L(between_2_3): ++ /* Load as big endian to avoid branches. */ ++ movzwl (%rdi), %eax ++ movzwl (%rsi), %ecx ++ shll $8, %eax ++ shll $8, %ecx ++ bswap %eax ++ bswap %ecx ++ movb -1(%rdi, %rdx), %al ++ movb -1(%rsi, %rdx), %cl ++ /* Subtraction is okay because the upper 8 bits are zero. */ ++ subl %ecx, %eax ++ ret ++ ++ .p2align 4 ++L(1): ++ movzbl (%rdi), %eax ++ movzbl (%rsi), %ecx ++ subl %ecx, %eax ++ ret ++# endif ++ ++ .p2align 4 ++L(zero): ++ xorl %eax, %eax ++ ret ++ ++ .p2align 4 ++L(less_vec): ++# ifdef USE_AS_WMEMCMP ++ /* It can only be 0, 4, 8, 12, 16, 20, 24, 28 bytes. */ ++ cmpb $4, %dl ++ je L(4) ++ jb L(zero) ++# else ++ cmpb $1, %dl ++ je L(1) ++ jb L(zero) ++ cmpb $4, %dl ++ jb L(between_2_3) ++ cmpb $8, %dl ++ jb L(between_4_7) ++# endif ++ cmpb $16, %dl ++ jae L(between_16_31) ++ /* It is between 8 and 15 bytes. */ ++ vmovq (%rdi), %XMM1 ++ vmovq (%rsi), %XMM2 ++ VPCMPEQ %XMM1, %XMM2, %k2 ++ kmovw %k2, %eax ++ subl $XMM_MASK, %eax ++ jnz L(first_vec) ++ /* Use overlapping loads to avoid branches. */ ++ leaq -8(%rdi, %rdx), %rdi ++ leaq -8(%rsi, %rdx), %rsi ++ vmovq (%rdi), %XMM1 ++ vmovq (%rsi), %XMM2 ++ VPCMPEQ %XMM1, %XMM2, %k2 ++ kmovw %k2, %eax ++ subl $XMM_MASK, %eax ++ jnz L(first_vec) ++ ret ++ ++ .p2align 4 ++L(between_16_31): ++ /* From 16 to 31 bytes. No branch when size == 16. */ ++ VMOVU (%rsi), %XMM2 ++ VPCMPEQ (%rdi), %XMM2, %k2 ++ kmovw %k2, %eax ++ subl $XMM_MASK, %eax ++ jnz L(first_vec) ++ ++ /* Use overlapping loads to avoid branches. */ ++ leaq -16(%rdi, %rdx), %rdi ++ leaq -16(%rsi, %rdx), %rsi ++ VMOVU (%rsi), %XMM2 ++ VPCMPEQ (%rdi), %XMM2, %k2 ++ kmovw %k2, %eax ++ subl $XMM_MASK, %eax ++ jnz L(first_vec) ++ ret ++ ++ .p2align 4 ++L(more_8x_vec): ++ /* More than 8 * VEC. Check the first VEC. */ ++ VMOVU (%rsi), %YMM2 ++ VPCMPEQ (%rdi), %YMM2, %k2 ++ kmovd %k2, %eax ++ subl $VEC_MASK, %eax ++ jnz L(first_vec) ++ ++ /* Align the first memory area for aligned loads in the loop. ++ Compute how much the first memory area is misaligned. */ ++ movq %rdi, %rcx ++ andl $(VEC_SIZE - 1), %ecx ++ /* Get the negative of offset for alignment. */ ++ subq $VEC_SIZE, %rcx ++ /* Adjust the second memory area. */ ++ subq %rcx, %rsi ++ /* Adjust the first memory area which should be aligned now. */ ++ subq %rcx, %rdi ++ /* Adjust length. */ ++ addq %rcx, %rdx ++ ++L(loop_4x_vec): ++ /* Compare 4 * VEC at a time forward. */ ++ VMOVU (%rsi), %YMM1 ++ VPCMPEQ (%rdi), %YMM1, %k1 ++ ++ VMOVU VEC_SIZE(%rsi), %YMM2 ++ VPCMPEQ VEC_SIZE(%rdi), %YMM2, %k2 ++ kandd %k2, %k1, %k5 ++ ++ VMOVU (VEC_SIZE * 2)(%rsi), %YMM3 ++ VPCMPEQ (VEC_SIZE * 2)(%rdi), %YMM3, %k3 ++ kandd %k3, %k5, %k5 ++ ++ VMOVU (VEC_SIZE * 3)(%rsi), %YMM4 ++ VPCMPEQ (VEC_SIZE * 3)(%rdi), %YMM4, %k4 ++ kandd %k4, %k5, %k5 ++ ++ kmovd %k5, %eax ++ cmpl $VEC_MASK, %eax ++ jne L(4x_vec_end) ++ ++ addq $(VEC_SIZE * 4), %rdi ++ addq $(VEC_SIZE * 4), %rsi ++ ++ subq $(VEC_SIZE * 4), %rdx ++ cmpq $(VEC_SIZE * 4), %rdx ++ jae L(loop_4x_vec) ++ ++ /* Less than 4 * VEC. */ ++ cmpq $VEC_SIZE, %rdx ++ jbe L(last_vec) ++ cmpq $(VEC_SIZE * 2), %rdx ++ jbe L(last_2x_vec) ++ ++L(last_4x_vec): ++ /* From 2 * VEC to 4 * VEC. */ ++ VMOVU (%rsi), %YMM2 ++ VPCMPEQ (%rdi), %YMM2, %k2 ++ kmovd %k2, %eax ++ subl $VEC_MASK, %eax ++ jnz L(first_vec) ++ ++ addq $VEC_SIZE, %rdi ++ addq $VEC_SIZE, %rsi ++ VMOVU (%rsi), %YMM2 ++ VPCMPEQ (%rdi), %YMM2, %k2 ++ kmovd %k2, %eax ++ subl $VEC_MASK, %eax ++ jnz L(first_vec) ++ ++ /* Use overlapping loads to avoid branches. */ ++ leaq -(3 * VEC_SIZE)(%rdi, %rdx), %rdi ++ leaq -(3 * VEC_SIZE)(%rsi, %rdx), %rsi ++ VMOVU (%rsi), %YMM2 ++ VPCMPEQ (%rdi), %YMM2, %k2 ++ kmovd %k2, %eax ++ subl $VEC_MASK, %eax ++ jnz L(first_vec) ++ ++ addq $VEC_SIZE, %rdi ++ addq $VEC_SIZE, %rsi ++ VMOVU (%rsi), %YMM2 ++ VPCMPEQ (%rdi), %YMM2, %k2 ++ kmovd %k2, %eax ++ subl $VEC_MASK, %eax ++ jnz L(first_vec) ++ ret ++ ++ .p2align 4 ++L(4x_vec_end): ++ kmovd %k1, %eax ++ subl $VEC_MASK, %eax ++ jnz L(first_vec) ++ kmovd %k2, %eax ++ subl $VEC_MASK, %eax ++ jnz L(first_vec_x1) ++ kmovd %k3, %eax ++ subl $VEC_MASK, %eax ++ jnz L(first_vec_x2) ++ kmovd %k4, %eax ++ subl $VEC_MASK, %eax ++ tzcntl %eax, %ecx ++# ifdef USE_AS_WMEMCMP ++ xorl %eax, %eax ++ movl (VEC_SIZE * 3)(%rdi, %rcx, 4), %edx ++ cmpl (VEC_SIZE * 3)(%rsi, %rcx, 4), %edx ++ jmp L(wmemcmp_return) ++# else ++ movzbl (VEC_SIZE * 3)(%rdi, %rcx), %eax ++ movzbl (VEC_SIZE * 3)(%rsi, %rcx), %edx ++ sub %edx, %eax ++# endif ++ ret ++ ++ .p2align 4 ++L(first_vec_x1): ++ tzcntl %eax, %ecx ++# ifdef USE_AS_WMEMCMP ++ xorl %eax, %eax ++ movl VEC_SIZE(%rdi, %rcx, 4), %edx ++ cmpl VEC_SIZE(%rsi, %rcx, 4), %edx ++ jmp L(wmemcmp_return) ++# else ++ movzbl VEC_SIZE(%rdi, %rcx), %eax ++ movzbl VEC_SIZE(%rsi, %rcx), %edx ++ sub %edx, %eax ++# endif ++ ret ++ ++ .p2align 4 ++L(first_vec_x2): ++ tzcntl %eax, %ecx ++# ifdef USE_AS_WMEMCMP ++ xorl %eax, %eax ++ movl (VEC_SIZE * 2)(%rdi, %rcx, 4), %edx ++ cmpl (VEC_SIZE * 2)(%rsi, %rcx, 4), %edx ++ jmp L(wmemcmp_return) ++# else ++ movzbl (VEC_SIZE * 2)(%rdi, %rcx), %eax ++ movzbl (VEC_SIZE * 2)(%rsi, %rcx), %edx ++ sub %edx, %eax ++# endif ++ ret ++END (MEMCMP) ++#endif +diff --git a/sysdeps/x86_64/multiarch/wmemcmp-evex-movbe.S b/sysdeps/x86_64/multiarch/wmemcmp-evex-movbe.S +new file mode 100644 +index 00000000..4726d74a +--- /dev/null ++++ b/sysdeps/x86_64/multiarch/wmemcmp-evex-movbe.S +@@ -0,0 +1,4 @@ ++#define MEMCMP __wmemcmp_evex_movbe ++#define USE_AS_WMEMCMP 1 ++ ++#include "memcmp-evex-movbe.S" +-- +GitLab + diff --git a/SOURCES/glibc-RHEL-15696-17.patch b/SOURCES/glibc-RHEL-15696-17.patch new file mode 100644 index 0000000..3176514 --- /dev/null +++ b/SOURCES/glibc-RHEL-15696-17.patch @@ -0,0 +1,2568 @@ +From 7ebba91361badf7531d4e75050627a88d424872f Mon Sep 17 00:00:00 2001 +From: "H.J. Lu" +Date: Fri, 5 Mar 2021 07:26:42 -0800 +Subject: [PATCH] x86-64: Add AVX optimized string/memory functions for RTM +Content-type: text/plain; charset=UTF-8 + +Since VZEROUPPER triggers RTM abort while VZEROALL won't, select AVX +optimized string/memory functions with + + xtest + jz 1f + vzeroall + ret +1: + vzeroupper + ret + +at function exit on processors with usable RTM, but without 256-bit EVEX +instructions to avoid VZEROUPPER inside a transactionally executing RTM +region. +--- + sysdeps/x86_64/multiarch/Makefile | 27 +++ + sysdeps/x86_64/multiarch/ifunc-avx2.h | 4 + + sysdeps/x86_64/multiarch/ifunc-impl-list.c | 170 ++++++++++++++++++ + sysdeps/x86_64/multiarch/ifunc-memcmp.h | 4 + + sysdeps/x86_64/multiarch/ifunc-memmove.h | 12 ++ + sysdeps/x86_64/multiarch/ifunc-memset.h | 12 ++ + sysdeps/x86_64/multiarch/ifunc-strcpy.h | 4 + + sysdeps/x86_64/multiarch/ifunc-wmemset.h | 5 + + sysdeps/x86_64/multiarch/memchr-avx2-rtm.S | 12 ++ + sysdeps/x86_64/multiarch/memchr-avx2.S | 45 +++-- + .../x86_64/multiarch/memcmp-avx2-movbe-rtm.S | 12 ++ + sysdeps/x86_64/multiarch/memcmp-avx2-movbe.S | 28 ++- + .../memmove-avx-unaligned-erms-rtm.S | 17 ++ + .../multiarch/memmove-vec-unaligned-erms.S | 33 ++-- + sysdeps/x86_64/multiarch/memrchr-avx2-rtm.S | 12 ++ + sysdeps/x86_64/multiarch/memrchr-avx2.S | 53 +++--- + .../memset-avx2-unaligned-erms-rtm.S | 10 ++ + .../multiarch/memset-avx2-unaligned-erms.S | 12 +- + .../multiarch/memset-vec-unaligned-erms.S | 41 ++--- + sysdeps/x86_64/multiarch/rawmemchr-avx2-rtm.S | 4 + + sysdeps/x86_64/multiarch/stpcpy-avx2-rtm.S | 3 + + sysdeps/x86_64/multiarch/stpncpy-avx2-rtm.S | 4 + + sysdeps/x86_64/multiarch/strcat-avx2-rtm.S | 12 ++ + sysdeps/x86_64/multiarch/strcat-avx2.S | 6 +- + sysdeps/x86_64/multiarch/strchr-avx2-rtm.S | 12 ++ + sysdeps/x86_64/multiarch/strchr-avx2.S | 22 +-- + sysdeps/x86_64/multiarch/strchr.c | 4 + + sysdeps/x86_64/multiarch/strchrnul-avx2-rtm.S | 3 + + sysdeps/x86_64/multiarch/strcmp-avx2-rtm.S | 12 ++ + sysdeps/x86_64/multiarch/strcmp-avx2.S | 55 +++--- + sysdeps/x86_64/multiarch/strcmp.c | 4 + + sysdeps/x86_64/multiarch/strcpy-avx2-rtm.S | 12 ++ + sysdeps/x86_64/multiarch/strcpy-avx2.S | 85 ++++----- + sysdeps/x86_64/multiarch/strlen-avx2-rtm.S | 12 ++ + sysdeps/x86_64/multiarch/strlen-avx2.S | 43 ++--- + sysdeps/x86_64/multiarch/strncat-avx2-rtm.S | 3 + + sysdeps/x86_64/multiarch/strncmp-avx2-rtm.S | 3 + + sysdeps/x86_64/multiarch/strncmp.c | 4 + + sysdeps/x86_64/multiarch/strncpy-avx2-rtm.S | 3 + + sysdeps/x86_64/multiarch/strnlen-avx2-rtm.S | 4 + + sysdeps/x86_64/multiarch/strrchr-avx2-rtm.S | 12 ++ + sysdeps/x86_64/multiarch/strrchr-avx2.S | 19 +- + sysdeps/x86_64/multiarch/wcschr-avx2-rtm.S | 3 + + sysdeps/x86_64/multiarch/wcscmp-avx2-rtm.S | 4 + + sysdeps/x86_64/multiarch/wcslen-avx2-rtm.S | 4 + + sysdeps/x86_64/multiarch/wcsncmp-avx2-rtm.S | 5 + + sysdeps/x86_64/multiarch/wcsnlen-avx2-rtm.S | 5 + + sysdeps/x86_64/multiarch/wcsnlen.c | 4 + + sysdeps/x86_64/multiarch/wcsrchr-avx2-rtm.S | 3 + + sysdeps/x86_64/multiarch/wmemchr-avx2-rtm.S | 4 + + .../x86_64/multiarch/wmemcmp-avx2-movbe-rtm.S | 4 + + sysdeps/x86_64/sysdep.h | 22 +++ + 52 files changed, 668 insertions(+), 244 deletions(-) + create mode 100644 sysdeps/x86_64/multiarch/memchr-avx2-rtm.S + create mode 100644 sysdeps/x86_64/multiarch/memcmp-avx2-movbe-rtm.S + create mode 100644 sysdeps/x86_64/multiarch/memmove-avx-unaligned-erms-rtm.S + create mode 100644 sysdeps/x86_64/multiarch/memrchr-avx2-rtm.S + create mode 100644 sysdeps/x86_64/multiarch/memset-avx2-unaligned-erms-rtm.S + create mode 100644 sysdeps/x86_64/multiarch/rawmemchr-avx2-rtm.S + create mode 100644 sysdeps/x86_64/multiarch/stpcpy-avx2-rtm.S + create mode 100644 sysdeps/x86_64/multiarch/stpncpy-avx2-rtm.S + create mode 100644 sysdeps/x86_64/multiarch/strcat-avx2-rtm.S + create mode 100644 sysdeps/x86_64/multiarch/strchr-avx2-rtm.S + create mode 100644 sysdeps/x86_64/multiarch/strchrnul-avx2-rtm.S + create mode 100644 sysdeps/x86_64/multiarch/strcmp-avx2-rtm.S + create mode 100644 sysdeps/x86_64/multiarch/strcpy-avx2-rtm.S + create mode 100644 sysdeps/x86_64/multiarch/strlen-avx2-rtm.S + create mode 100644 sysdeps/x86_64/multiarch/strncat-avx2-rtm.S + create mode 100644 sysdeps/x86_64/multiarch/strncmp-avx2-rtm.S + create mode 100644 sysdeps/x86_64/multiarch/strncpy-avx2-rtm.S + create mode 100644 sysdeps/x86_64/multiarch/strnlen-avx2-rtm.S + create mode 100644 sysdeps/x86_64/multiarch/strrchr-avx2-rtm.S + create mode 100644 sysdeps/x86_64/multiarch/wcschr-avx2-rtm.S + create mode 100644 sysdeps/x86_64/multiarch/wcscmp-avx2-rtm.S + create mode 100644 sysdeps/x86_64/multiarch/wcslen-avx2-rtm.S + create mode 100644 sysdeps/x86_64/multiarch/wcsncmp-avx2-rtm.S + create mode 100644 sysdeps/x86_64/multiarch/wcsnlen-avx2-rtm.S + create mode 100644 sysdeps/x86_64/multiarch/wcsrchr-avx2-rtm.S + create mode 100644 sysdeps/x86_64/multiarch/wmemchr-avx2-rtm.S + create mode 100644 sysdeps/x86_64/multiarch/wmemcmp-avx2-movbe-rtm.S + +Conflicts: + sysdeps/x86_64/multiarch/strchr-avx2.S + (same fix, different location) + + +diff --git a/sysdeps/x86_64/multiarch/Makefile b/sysdeps/x86_64/multiarch/Makefile +index 9d79b138..491c7698 100644 +--- a/sysdeps/x86_64/multiarch/Makefile ++++ b/sysdeps/x86_64/multiarch/Makefile +@@ -40,6 +40,25 @@ sysdep_routines += strncat-c stpncpy-c strncpy-c \ + memset-sse2-unaligned-erms \ + memset-avx2-unaligned-erms \ + memset-avx512-unaligned-erms \ ++ memchr-avx2-rtm \ ++ memcmp-avx2-movbe-rtm \ ++ memmove-avx-unaligned-erms-rtm \ ++ memrchr-avx2-rtm \ ++ memset-avx2-unaligned-erms-rtm \ ++ rawmemchr-avx2-rtm \ ++ strchr-avx2-rtm \ ++ strcmp-avx2-rtm \ ++ strchrnul-avx2-rtm \ ++ stpcpy-avx2-rtm \ ++ stpncpy-avx2-rtm \ ++ strcat-avx2-rtm \ ++ strcpy-avx2-rtm \ ++ strlen-avx2-rtm \ ++ strncat-avx2-rtm \ ++ strncmp-avx2-rtm \ ++ strncpy-avx2-rtm \ ++ strnlen-avx2-rtm \ ++ strrchr-avx2-rtm \ + memchr-evex \ + memcmp-evex-movbe \ + memmove-evex-unaligned-erms \ +@@ -76,6 +95,14 @@ sysdep_routines += wmemcmp-sse4 wmemcmp-ssse3 wmemcmp-c \ + wcsrchr-sse2 wcsrchr-avx2 \ + wcsnlen-sse4_1 wcsnlen-c \ + wcslen-sse2 wcslen-avx2 wcsnlen-avx2 \ ++ wcschr-avx2-rtm \ ++ wcscmp-avx2-rtm \ ++ wcslen-avx2-rtm \ ++ wcsncmp-avx2-rtm \ ++ wcsnlen-avx2-rtm \ ++ wcsrchr-avx2-rtm \ ++ wmemchr-avx2-rtm \ ++ wmemcmp-avx2-movbe-rtm \ + wcschr-evex \ + wcscmp-evex \ + wcslen-evex \ +diff --git a/sysdeps/x86_64/multiarch/ifunc-avx2.h b/sysdeps/x86_64/multiarch/ifunc-avx2.h +index 7081b0c9..e0f30e61 100644 +--- a/sysdeps/x86_64/multiarch/ifunc-avx2.h ++++ b/sysdeps/x86_64/multiarch/ifunc-avx2.h +@@ -21,6 +21,7 @@ + + extern __typeof (REDIRECT_NAME) OPTIMIZE (sse2) attribute_hidden; + extern __typeof (REDIRECT_NAME) OPTIMIZE (avx2) attribute_hidden; ++extern __typeof (REDIRECT_NAME) OPTIMIZE (avx2_rtm) attribute_hidden; + extern __typeof (REDIRECT_NAME) OPTIMIZE (evex) attribute_hidden; + + static inline void * +@@ -36,6 +37,9 @@ IFUNC_SELECTOR (void) + && CPU_FEATURE_USABLE_P (cpu_features, BMI2)) + return OPTIMIZE (evex); + ++ if (CPU_FEATURE_USABLE_P (cpu_features, RTM)) ++ return OPTIMIZE (avx2_rtm); ++ + if (!CPU_FEATURES_ARCH_P (cpu_features, Prefer_No_VZEROUPPER)) + return OPTIMIZE (avx2); + } +diff --git a/sysdeps/x86_64/multiarch/ifunc-impl-list.c b/sysdeps/x86_64/multiarch/ifunc-impl-list.c +index c8da910e..c1efeec0 100644 +--- a/sysdeps/x86_64/multiarch/ifunc-impl-list.c ++++ b/sysdeps/x86_64/multiarch/ifunc-impl-list.c +@@ -43,6 +43,10 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + IFUNC_IMPL_ADD (array, i, memchr, + CPU_FEATURE_USABLE (AVX2), + __memchr_avx2) ++ IFUNC_IMPL_ADD (array, i, memchr, ++ (CPU_FEATURE_USABLE (AVX2) ++ && CPU_FEATURE_USABLE (RTM)), ++ __memchr_avx2_rtm) + IFUNC_IMPL_ADD (array, i, memchr, + (CPU_FEATURE_USABLE (AVX512VL) + && CPU_FEATURE_USABLE (AVX512BW) +@@ -56,6 +60,11 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + (CPU_FEATURE_USABLE (AVX2) + && CPU_FEATURE_USABLE (MOVBE)), + __memcmp_avx2_movbe) ++ IFUNC_IMPL_ADD (array, i, memcmp, ++ (CPU_FEATURE_USABLE (AVX2) ++ && CPU_FEATURE_USABLE (MOVBE) ++ && CPU_FEATURE_USABLE (RTM)), ++ __memcmp_avx2_movbe_rtm) + IFUNC_IMPL_ADD (array, i, memcmp, + (CPU_FEATURE_USABLE (AVX512VL) + && CPU_FEATURE_USABLE (AVX512BW) +@@ -85,6 +94,14 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + IFUNC_IMPL_ADD (array, i, __memmove_chk, + CPU_FEATURE_USABLE (AVX), + __memmove_chk_avx_unaligned_erms) ++ IFUNC_IMPL_ADD (array, i, __memmove_chk, ++ (CPU_FEATURE_USABLE (AVX) ++ && CPU_FEATURE_USABLE (RTM)), ++ __memmove_chk_avx_unaligned_rtm) ++ IFUNC_IMPL_ADD (array, i, __memmove_chk, ++ (CPU_FEATURE_USABLE (AVX) ++ && CPU_FEATURE_USABLE (RTM)), ++ __memmove_chk_avx_unaligned_erms_rtm) + IFUNC_IMPL_ADD (array, i, __memmove_chk, + CPU_FEATURE_USABLE (AVX512VL), + __memmove_chk_evex_unaligned) +@@ -113,6 +130,14 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + IFUNC_IMPL_ADD (array, i, memmove, + CPU_FEATURE_USABLE (AVX), + __memmove_avx_unaligned_erms) ++ IFUNC_IMPL_ADD (array, i, memmove, ++ (CPU_FEATURE_USABLE (AVX) ++ && CPU_FEATURE_USABLE (RTM)), ++ __memmove_avx_unaligned_rtm) ++ IFUNC_IMPL_ADD (array, i, memmove, ++ (CPU_FEATURE_USABLE (AVX) ++ && CPU_FEATURE_USABLE (RTM)), ++ __memmove_avx_unaligned_erms_rtm) + IFUNC_IMPL_ADD (array, i, memmove, + CPU_FEATURE_USABLE (AVX512VL), + __memmove_evex_unaligned) +@@ -143,6 +168,10 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + IFUNC_IMPL_ADD (array, i, memrchr, + CPU_FEATURE_USABLE (AVX2), + __memrchr_avx2) ++ IFUNC_IMPL_ADD (array, i, memrchr, ++ (CPU_FEATURE_USABLE (AVX2) ++ && CPU_FEATURE_USABLE (RTM)), ++ __memrchr_avx2_rtm) + IFUNC_IMPL_ADD (array, i, memrchr, + (CPU_FEATURE_USABLE (AVX512VL) + && CPU_FEATURE_USABLE (AVX512BW)), +@@ -165,6 +194,14 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + IFUNC_IMPL_ADD (array, i, __memset_chk, + CPU_FEATURE_USABLE (AVX2), + __memset_chk_avx2_unaligned_erms) ++ IFUNC_IMPL_ADD (array, i, __memset_chk, ++ (CPU_FEATURE_USABLE (AVX2) ++ && CPU_FEATURE_USABLE (RTM)), ++ __memset_chk_avx2_unaligned_rtm) ++ IFUNC_IMPL_ADD (array, i, __memset_chk, ++ (CPU_FEATURE_USABLE (AVX2) ++ && CPU_FEATURE_USABLE (RTM)), ++ __memset_chk_avx2_unaligned_erms_rtm) + IFUNC_IMPL_ADD (array, i, __memset_chk, + (CPU_FEATURE_USABLE (AVX512VL) + && CPU_FEATURE_USABLE (AVX512BW)), +@@ -198,6 +235,14 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + IFUNC_IMPL_ADD (array, i, memset, + CPU_FEATURE_USABLE (AVX2), + __memset_avx2_unaligned_erms) ++ IFUNC_IMPL_ADD (array, i, memset, ++ (CPU_FEATURE_USABLE (AVX2) ++ && CPU_FEATURE_USABLE (RTM)), ++ __memset_avx2_unaligned_rtm) ++ IFUNC_IMPL_ADD (array, i, memset, ++ (CPU_FEATURE_USABLE (AVX2) ++ && CPU_FEATURE_USABLE (RTM)), ++ __memset_avx2_unaligned_erms_rtm) + IFUNC_IMPL_ADD (array, i, memset, + (CPU_FEATURE_USABLE (AVX512VL) + && CPU_FEATURE_USABLE (AVX512BW)), +@@ -222,6 +267,10 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + IFUNC_IMPL_ADD (array, i, rawmemchr, + CPU_FEATURE_USABLE (AVX2), + __rawmemchr_avx2) ++ IFUNC_IMPL_ADD (array, i, rawmemchr, ++ (CPU_FEATURE_USABLE (AVX2) ++ && CPU_FEATURE_USABLE (RTM)), ++ __rawmemchr_avx2_rtm) + IFUNC_IMPL_ADD (array, i, rawmemchr, + (CPU_FEATURE_USABLE (AVX512VL) + && CPU_FEATURE_USABLE (AVX512BW) +@@ -234,6 +283,10 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + IFUNC_IMPL_ADD (array, i, strlen, + CPU_FEATURE_USABLE (AVX2), + __strlen_avx2) ++ IFUNC_IMPL_ADD (array, i, strlen, ++ (CPU_FEATURE_USABLE (AVX2) ++ && CPU_FEATURE_USABLE (RTM)), ++ __strlen_avx2_rtm) + IFUNC_IMPL_ADD (array, i, strlen, + (CPU_FEATURE_USABLE (AVX512VL) + && CPU_FEATURE_USABLE (AVX512BW)), +@@ -245,6 +298,10 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + IFUNC_IMPL_ADD (array, i, strnlen, + CPU_FEATURE_USABLE (AVX2), + __strnlen_avx2) ++ IFUNC_IMPL_ADD (array, i, strnlen, ++ (CPU_FEATURE_USABLE (AVX2) ++ && CPU_FEATURE_USABLE (RTM)), ++ __strnlen_avx2_rtm) + IFUNC_IMPL_ADD (array, i, strnlen, + (CPU_FEATURE_USABLE (AVX512VL) + && CPU_FEATURE_USABLE (AVX512BW)), +@@ -257,6 +314,10 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + __stpncpy_ssse3) + IFUNC_IMPL_ADD (array, i, stpncpy, CPU_FEATURE_USABLE (AVX2), + __stpncpy_avx2) ++ IFUNC_IMPL_ADD (array, i, stpncpy, ++ (CPU_FEATURE_USABLE (AVX2) ++ && CPU_FEATURE_USABLE (RTM)), ++ __stpncpy_avx2_rtm) + IFUNC_IMPL_ADD (array, i, stpncpy, + (CPU_FEATURE_USABLE (AVX512VL) + && CPU_FEATURE_USABLE (AVX512BW)), +@@ -271,6 +332,10 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + __stpcpy_ssse3) + IFUNC_IMPL_ADD (array, i, stpcpy, CPU_FEATURE_USABLE (AVX2), + __stpcpy_avx2) ++ IFUNC_IMPL_ADD (array, i, stpcpy, ++ (CPU_FEATURE_USABLE (AVX2) ++ && CPU_FEATURE_USABLE (RTM)), ++ __stpcpy_avx2_rtm) + IFUNC_IMPL_ADD (array, i, stpcpy, + (CPU_FEATURE_USABLE (AVX512VL) + && CPU_FEATURE_USABLE (AVX512BW)), +@@ -309,6 +374,10 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + IFUNC_IMPL (i, name, strcat, + IFUNC_IMPL_ADD (array, i, strcat, CPU_FEATURE_USABLE (AVX2), + __strcat_avx2) ++ IFUNC_IMPL_ADD (array, i, strcat, ++ (CPU_FEATURE_USABLE (AVX2) ++ && CPU_FEATURE_USABLE (RTM)), ++ __strcat_avx2_rtm) + IFUNC_IMPL_ADD (array, i, strcat, + (CPU_FEATURE_USABLE (AVX512VL) + && CPU_FEATURE_USABLE (AVX512BW)), +@@ -323,6 +392,10 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + IFUNC_IMPL_ADD (array, i, strchr, + CPU_FEATURE_USABLE (AVX2), + __strchr_avx2) ++ IFUNC_IMPL_ADD (array, i, strchr, ++ (CPU_FEATURE_USABLE (AVX2) ++ && CPU_FEATURE_USABLE (RTM)), ++ __strchr_avx2_rtm) + IFUNC_IMPL_ADD (array, i, strchr, + (CPU_FEATURE_USABLE (AVX512VL) + && CPU_FEATURE_USABLE (AVX512BW) +@@ -336,6 +409,10 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + IFUNC_IMPL_ADD (array, i, strchrnul, + CPU_FEATURE_USABLE (AVX2), + __strchrnul_avx2) ++ IFUNC_IMPL_ADD (array, i, strchrnul, ++ (CPU_FEATURE_USABLE (AVX2) ++ && CPU_FEATURE_USABLE (RTM)), ++ __strchrnul_avx2_rtm) + IFUNC_IMPL_ADD (array, i, strchrnul, + (CPU_FEATURE_USABLE (AVX512VL) + && CPU_FEATURE_USABLE (AVX512BW) +@@ -348,6 +425,10 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + IFUNC_IMPL_ADD (array, i, strrchr, + CPU_FEATURE_USABLE (AVX2), + __strrchr_avx2) ++ IFUNC_IMPL_ADD (array, i, strrchr, ++ (CPU_FEATURE_USABLE (AVX2) ++ && CPU_FEATURE_USABLE (RTM)), ++ __strrchr_avx2_rtm) + IFUNC_IMPL_ADD (array, i, strrchr, + (CPU_FEATURE_USABLE (AVX512VL) + && CPU_FEATURE_USABLE (AVX512BW)), +@@ -359,6 +440,10 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + IFUNC_IMPL_ADD (array, i, strcmp, + CPU_FEATURE_USABLE (AVX2), + __strcmp_avx2) ++ IFUNC_IMPL_ADD (array, i, strcmp, ++ (CPU_FEATURE_USABLE (AVX2) ++ && CPU_FEATURE_USABLE (RTM)), ++ __strcmp_avx2_rtm) + IFUNC_IMPL_ADD (array, i, strcmp, + (CPU_FEATURE_USABLE (AVX512VL) + && CPU_FEATURE_USABLE (AVX512BW) +@@ -375,6 +460,10 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + IFUNC_IMPL (i, name, strcpy, + IFUNC_IMPL_ADD (array, i, strcpy, CPU_FEATURE_USABLE (AVX2), + __strcpy_avx2) ++ IFUNC_IMPL_ADD (array, i, strcpy, ++ (CPU_FEATURE_USABLE (AVX2) ++ && CPU_FEATURE_USABLE (RTM)), ++ __strcpy_avx2_rtm) + IFUNC_IMPL_ADD (array, i, strcpy, + (CPU_FEATURE_USABLE (AVX512VL) + && CPU_FEATURE_USABLE (AVX512BW)), +@@ -422,6 +511,10 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + IFUNC_IMPL (i, name, strncat, + IFUNC_IMPL_ADD (array, i, strncat, CPU_FEATURE_USABLE (AVX2), + __strncat_avx2) ++ IFUNC_IMPL_ADD (array, i, strncat, ++ (CPU_FEATURE_USABLE (AVX2) ++ && CPU_FEATURE_USABLE (RTM)), ++ __strncat_avx2_rtm) + IFUNC_IMPL_ADD (array, i, strncat, + (CPU_FEATURE_USABLE (AVX512VL) + && CPU_FEATURE_USABLE (AVX512BW)), +@@ -436,6 +529,10 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + IFUNC_IMPL (i, name, strncpy, + IFUNC_IMPL_ADD (array, i, strncpy, CPU_FEATURE_USABLE (AVX2), + __strncpy_avx2) ++ IFUNC_IMPL_ADD (array, i, strncpy, ++ (CPU_FEATURE_USABLE (AVX2) ++ && CPU_FEATURE_USABLE (RTM)), ++ __strncpy_avx2_rtm) + IFUNC_IMPL_ADD (array, i, strncpy, + (CPU_FEATURE_USABLE (AVX512VL) + && CPU_FEATURE_USABLE (AVX512BW)), +@@ -469,6 +566,10 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + IFUNC_IMPL_ADD (array, i, wcschr, + CPU_FEATURE_USABLE (AVX2), + __wcschr_avx2) ++ IFUNC_IMPL_ADD (array, i, wcschr, ++ (CPU_FEATURE_USABLE (AVX2) ++ && CPU_FEATURE_USABLE (RTM)), ++ __wcschr_avx2_rtm) + IFUNC_IMPL_ADD (array, i, wcschr, + (CPU_FEATURE_USABLE (AVX512VL) + && CPU_FEATURE_USABLE (AVX512BW) +@@ -481,6 +582,10 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + IFUNC_IMPL_ADD (array, i, wcsrchr, + CPU_FEATURE_USABLE (AVX2), + __wcsrchr_avx2) ++ IFUNC_IMPL_ADD (array, i, wcsrchr, ++ (CPU_FEATURE_USABLE (AVX2) ++ && CPU_FEATURE_USABLE (RTM)), ++ __wcsrchr_avx2_rtm) + IFUNC_IMPL_ADD (array, i, wcsrchr, + (CPU_FEATURE_USABLE (AVX512VL) + && CPU_FEATURE_USABLE (AVX512BW) +@@ -493,6 +598,10 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + IFUNC_IMPL_ADD (array, i, wcscmp, + CPU_FEATURE_USABLE (AVX2), + __wcscmp_avx2) ++ IFUNC_IMPL_ADD (array, i, wcscmp, ++ (CPU_FEATURE_USABLE (AVX2) ++ && CPU_FEATURE_USABLE (RTM)), ++ __wcscmp_avx2_rtm) + IFUNC_IMPL_ADD (array, i, wcscmp, + (CPU_FEATURE_USABLE (AVX512VL) + && CPU_FEATURE_USABLE (AVX512BW) +@@ -505,6 +614,10 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + IFUNC_IMPL_ADD (array, i, wcsncmp, + CPU_FEATURE_USABLE (AVX2), + __wcsncmp_avx2) ++ IFUNC_IMPL_ADD (array, i, wcsncmp, ++ (CPU_FEATURE_USABLE (AVX2) ++ && CPU_FEATURE_USABLE (RTM)), ++ __wcsncmp_avx2_rtm) + IFUNC_IMPL_ADD (array, i, wcsncmp, + (CPU_FEATURE_USABLE (AVX512VL) + && CPU_FEATURE_USABLE (AVX512BW) +@@ -523,6 +636,10 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + IFUNC_IMPL_ADD (array, i, wcslen, + CPU_FEATURE_USABLE (AVX2), + __wcslen_avx2) ++ IFUNC_IMPL_ADD (array, i, wcslen, ++ (CPU_FEATURE_USABLE (AVX2) ++ && CPU_FEATURE_USABLE (RTM)), ++ __wcslen_avx2_rtm) + IFUNC_IMPL_ADD (array, i, wcslen, + (CPU_FEATURE_USABLE (AVX512VL) + && CPU_FEATURE_USABLE (AVX512BW) +@@ -535,6 +652,10 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + IFUNC_IMPL_ADD (array, i, wcsnlen, + CPU_FEATURE_USABLE (AVX2), + __wcsnlen_avx2) ++ IFUNC_IMPL_ADD (array, i, wcsnlen, ++ (CPU_FEATURE_USABLE (AVX2) ++ && CPU_FEATURE_USABLE (RTM)), ++ __wcsnlen_avx2_rtm) + IFUNC_IMPL_ADD (array, i, wcsnlen, + (CPU_FEATURE_USABLE (AVX512VL) + && CPU_FEATURE_USABLE (AVX512BW) +@@ -550,6 +671,10 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + IFUNC_IMPL_ADD (array, i, wmemchr, + CPU_FEATURE_USABLE (AVX2), + __wmemchr_avx2) ++ IFUNC_IMPL_ADD (array, i, wmemchr, ++ (CPU_FEATURE_USABLE (AVX2) ++ && CPU_FEATURE_USABLE (RTM)), ++ __wmemchr_avx2_rtm) + IFUNC_IMPL_ADD (array, i, wmemchr, + (CPU_FEATURE_USABLE (AVX512VL) + && CPU_FEATURE_USABLE (AVX512BW) +@@ -563,6 +688,11 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + (CPU_FEATURE_USABLE (AVX2) + && CPU_FEATURE_USABLE (MOVBE)), + __wmemcmp_avx2_movbe) ++ IFUNC_IMPL_ADD (array, i, wmemcmp, ++ (CPU_FEATURE_USABLE (AVX2) ++ && CPU_FEATURE_USABLE (MOVBE) ++ && CPU_FEATURE_USABLE (RTM)), ++ __wmemcmp_avx2_movbe_rtm) + IFUNC_IMPL_ADD (array, i, wmemcmp, + (CPU_FEATURE_USABLE (AVX512VL) + && CPU_FEATURE_USABLE (AVX512BW) +@@ -581,6 +711,10 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + IFUNC_IMPL_ADD (array, i, wmemset, + CPU_FEATURE_USABLE (AVX2), + __wmemset_avx2_unaligned) ++ IFUNC_IMPL_ADD (array, i, wmemset, ++ (CPU_FEATURE_USABLE (AVX2) ++ && CPU_FEATURE_USABLE (RTM)), ++ __wmemset_avx2_unaligned_rtm) + IFUNC_IMPL_ADD (array, i, wmemset, + CPU_FEATURE_USABLE (AVX512VL), + __wmemset_evex_unaligned) +@@ -606,6 +740,14 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + IFUNC_IMPL_ADD (array, i, __memcpy_chk, + CPU_FEATURE_USABLE (AVX), + __memcpy_chk_avx_unaligned_erms) ++ IFUNC_IMPL_ADD (array, i, __memcpy_chk, ++ (CPU_FEATURE_USABLE (AVX) ++ && CPU_FEATURE_USABLE (RTM)), ++ __memcpy_chk_avx_unaligned_rtm) ++ IFUNC_IMPL_ADD (array, i, __memcpy_chk, ++ (CPU_FEATURE_USABLE (AVX) ++ && CPU_FEATURE_USABLE (RTM)), ++ __memcpy_chk_avx_unaligned_erms_rtm) + IFUNC_IMPL_ADD (array, i, __memcpy_chk, + CPU_FEATURE_USABLE (AVX512VL), + __memcpy_chk_evex_unaligned) +@@ -634,6 +776,14 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + IFUNC_IMPL_ADD (array, i, memcpy, + CPU_FEATURE_USABLE (AVX), + __memcpy_avx_unaligned_erms) ++ IFUNC_IMPL_ADD (array, i, memcpy, ++ (CPU_FEATURE_USABLE (AVX) ++ && CPU_FEATURE_USABLE (RTM)), ++ __memcpy_avx_unaligned_rtm) ++ IFUNC_IMPL_ADD (array, i, memcpy, ++ (CPU_FEATURE_USABLE (AVX) ++ && CPU_FEATURE_USABLE (RTM)), ++ __memcpy_avx_unaligned_erms_rtm) + IFUNC_IMPL_ADD (array, i, memcpy, + CPU_FEATURE_USABLE (AVX512VL), + __memcpy_evex_unaligned) +@@ -676,6 +826,14 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + IFUNC_IMPL_ADD (array, i, __mempcpy_chk, + CPU_FEATURE_USABLE (AVX), + __mempcpy_chk_avx_unaligned_erms) ++ IFUNC_IMPL_ADD (array, i, __mempcpy_chk, ++ (CPU_FEATURE_USABLE (AVX) ++ && CPU_FEATURE_USABLE (RTM)), ++ __mempcpy_chk_avx_unaligned_rtm) ++ IFUNC_IMPL_ADD (array, i, __mempcpy_chk, ++ (CPU_FEATURE_USABLE (AVX) ++ && CPU_FEATURE_USABLE (RTM)), ++ __mempcpy_chk_avx_unaligned_erms_rtm) + IFUNC_IMPL_ADD (array, i, __mempcpy_chk, + CPU_FEATURE_USABLE (AVX512VL), + __mempcpy_chk_evex_unaligned) +@@ -713,6 +871,14 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + IFUNC_IMPL_ADD (array, i, mempcpy, + CPU_FEATURE_USABLE (AVX), + __mempcpy_avx_unaligned_erms) ++ IFUNC_IMPL_ADD (array, i, mempcpy, ++ (CPU_FEATURE_USABLE (AVX) ++ && CPU_FEATURE_USABLE (RTM)), ++ __mempcpy_avx_unaligned_rtm) ++ IFUNC_IMPL_ADD (array, i, mempcpy, ++ (CPU_FEATURE_USABLE (AVX) ++ && CPU_FEATURE_USABLE (RTM)), ++ __mempcpy_avx_unaligned_erms_rtm) + IFUNC_IMPL_ADD (array, i, mempcpy, + CPU_FEATURE_USABLE (AVX512VL), + __mempcpy_evex_unaligned) +@@ -734,6 +900,10 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + IFUNC_IMPL_ADD (array, i, strncmp, + CPU_FEATURE_USABLE (AVX2), + __strncmp_avx2) ++ IFUNC_IMPL_ADD (array, i, strncmp, ++ (CPU_FEATURE_USABLE (AVX2) ++ && CPU_FEATURE_USABLE (RTM)), ++ __strncmp_avx2_rtm) + IFUNC_IMPL_ADD (array, i, strncmp, + (CPU_FEATURE_USABLE (AVX512VL) + && CPU_FEATURE_USABLE (AVX512BW)), +diff --git a/sysdeps/x86_64/multiarch/ifunc-memcmp.h b/sysdeps/x86_64/multiarch/ifunc-memcmp.h +index 3ca1f0a6..8043c635 100644 +--- a/sysdeps/x86_64/multiarch/ifunc-memcmp.h ++++ b/sysdeps/x86_64/multiarch/ifunc-memcmp.h +@@ -23,6 +23,7 @@ extern __typeof (REDIRECT_NAME) OPTIMIZE (sse2) attribute_hidden; + extern __typeof (REDIRECT_NAME) OPTIMIZE (ssse3) attribute_hidden; + extern __typeof (REDIRECT_NAME) OPTIMIZE (sse4_1) attribute_hidden; + extern __typeof (REDIRECT_NAME) OPTIMIZE (avx2_movbe) attribute_hidden; ++extern __typeof (REDIRECT_NAME) OPTIMIZE (avx2_movbe_rtm) attribute_hidden; + extern __typeof (REDIRECT_NAME) OPTIMIZE (evex_movbe) attribute_hidden; + + static inline void * +@@ -38,6 +39,9 @@ IFUNC_SELECTOR (void) + && CPU_FEATURE_USABLE_P (cpu_features, AVX512BW)) + return OPTIMIZE (evex_movbe); + ++ if (CPU_FEATURE_USABLE_P (cpu_features, RTM)) ++ return OPTIMIZE (avx2_movbe_rtm); ++ + if (!CPU_FEATURES_ARCH_P (cpu_features, Prefer_No_VZEROUPPER)) + return OPTIMIZE (avx2_movbe); + } +diff --git a/sysdeps/x86_64/multiarch/ifunc-memmove.h b/sysdeps/x86_64/multiarch/ifunc-memmove.h +index 6f8bce5f..fa09b9fb 100644 +--- a/sysdeps/x86_64/multiarch/ifunc-memmove.h ++++ b/sysdeps/x86_64/multiarch/ifunc-memmove.h +@@ -29,6 +29,10 @@ extern __typeof (REDIRECT_NAME) OPTIMIZE (ssse3_back) attribute_hidden; + extern __typeof (REDIRECT_NAME) OPTIMIZE (avx_unaligned) attribute_hidden; + extern __typeof (REDIRECT_NAME) OPTIMIZE (avx_unaligned_erms) + attribute_hidden; ++extern __typeof (REDIRECT_NAME) OPTIMIZE (avx_unaligned_rtm) ++ attribute_hidden; ++extern __typeof (REDIRECT_NAME) OPTIMIZE (avx_unaligned_erms_rtm) ++ attribute_hidden; + extern __typeof (REDIRECT_NAME) OPTIMIZE (evex_unaligned) + attribute_hidden; + extern __typeof (REDIRECT_NAME) OPTIMIZE (evex_unaligned_erms) +@@ -71,6 +75,14 @@ IFUNC_SELECTOR (void) + return OPTIMIZE (evex_unaligned); + } + ++ if (CPU_FEATURE_USABLE_P (cpu_features, RTM)) ++ { ++ if (CPU_FEATURE_USABLE_P (cpu_features, ERMS)) ++ return OPTIMIZE (avx_unaligned_erms_rtm); ++ ++ return OPTIMIZE (avx_unaligned_rtm); ++ } ++ + if (!CPU_FEATURES_ARCH_P (cpu_features, Prefer_No_VZEROUPPER)) + { + if (CPU_FEATURE_USABLE_P (cpu_features, ERMS)) +diff --git a/sysdeps/x86_64/multiarch/ifunc-memset.h b/sysdeps/x86_64/multiarch/ifunc-memset.h +index 6f31f4dc..6f3375cc 100644 +--- a/sysdeps/x86_64/multiarch/ifunc-memset.h ++++ b/sysdeps/x86_64/multiarch/ifunc-memset.h +@@ -27,6 +27,10 @@ extern __typeof (REDIRECT_NAME) OPTIMIZE (sse2_unaligned_erms) + extern __typeof (REDIRECT_NAME) OPTIMIZE (avx2_unaligned) attribute_hidden; + extern __typeof (REDIRECT_NAME) OPTIMIZE (avx2_unaligned_erms) + attribute_hidden; ++extern __typeof (REDIRECT_NAME) OPTIMIZE (avx2_unaligned_rtm) ++ attribute_hidden; ++extern __typeof (REDIRECT_NAME) OPTIMIZE (avx2_unaligned_erms_rtm) ++ attribute_hidden; + extern __typeof (REDIRECT_NAME) OPTIMIZE (evex_unaligned) + attribute_hidden; + extern __typeof (REDIRECT_NAME) OPTIMIZE (evex_unaligned_erms) +@@ -69,6 +73,14 @@ IFUNC_SELECTOR (void) + return OPTIMIZE (evex_unaligned); + } + ++ if (CPU_FEATURE_USABLE_P (cpu_features, RTM)) ++ { ++ if (CPU_FEATURE_USABLE_P (cpu_features, ERMS)) ++ return OPTIMIZE (avx2_unaligned_erms_rtm); ++ ++ return OPTIMIZE (avx2_unaligned_rtm); ++ } ++ + if (!CPU_FEATURES_ARCH_P (cpu_features, Prefer_No_VZEROUPPER)) + { + if (CPU_FEATURE_USABLE_P (cpu_features, ERMS)) +diff --git a/sysdeps/x86_64/multiarch/ifunc-strcpy.h b/sysdeps/x86_64/multiarch/ifunc-strcpy.h +index deae6348..a924762e 100644 +--- a/sysdeps/x86_64/multiarch/ifunc-strcpy.h ++++ b/sysdeps/x86_64/multiarch/ifunc-strcpy.h +@@ -25,6 +25,7 @@ extern __typeof (REDIRECT_NAME) OPTIMIZE (sse2_unaligned) + attribute_hidden; + extern __typeof (REDIRECT_NAME) OPTIMIZE (ssse3) attribute_hidden; + extern __typeof (REDIRECT_NAME) OPTIMIZE (avx2) attribute_hidden; ++extern __typeof (REDIRECT_NAME) OPTIMIZE (avx2_rtm) attribute_hidden; + extern __typeof (REDIRECT_NAME) OPTIMIZE (evex) attribute_hidden; + + static inline void * +@@ -39,6 +40,9 @@ IFUNC_SELECTOR (void) + && CPU_FEATURE_USABLE_P (cpu_features, AVX512BW)) + return OPTIMIZE (evex); + ++ if (CPU_FEATURE_USABLE_P (cpu_features, RTM)) ++ return OPTIMIZE (avx2_rtm); ++ + if (!CPU_FEATURES_ARCH_P (cpu_features, Prefer_No_VZEROUPPER)) + return OPTIMIZE (avx2); + } +diff --git a/sysdeps/x86_64/multiarch/ifunc-wmemset.h b/sysdeps/x86_64/multiarch/ifunc-wmemset.h +index 9290c4bf..bdc94c6c 100644 +--- a/sysdeps/x86_64/multiarch/ifunc-wmemset.h ++++ b/sysdeps/x86_64/multiarch/ifunc-wmemset.h +@@ -20,6 +20,8 @@ + + extern __typeof (REDIRECT_NAME) OPTIMIZE (sse2_unaligned) attribute_hidden; + extern __typeof (REDIRECT_NAME) OPTIMIZE (avx2_unaligned) attribute_hidden; ++extern __typeof (REDIRECT_NAME) OPTIMIZE (avx2_unaligned_rtm) ++ attribute_hidden; + extern __typeof (REDIRECT_NAME) OPTIMIZE (evex_unaligned) attribute_hidden; + extern __typeof (REDIRECT_NAME) OPTIMIZE (avx512_unaligned) attribute_hidden; + +@@ -39,6 +41,9 @@ IFUNC_SELECTOR (void) + if (CPU_FEATURE_USABLE_P (cpu_features, AVX512VL)) + return OPTIMIZE (evex_unaligned); + ++ if (CPU_FEATURE_USABLE_P (cpu_features, RTM)) ++ return OPTIMIZE (avx2_unaligned_rtm); ++ + if (!CPU_FEATURES_ARCH_P (cpu_features, Prefer_No_VZEROUPPER)) + return OPTIMIZE (avx2_unaligned); + } +diff --git a/sysdeps/x86_64/multiarch/memchr-avx2-rtm.S b/sysdeps/x86_64/multiarch/memchr-avx2-rtm.S +new file mode 100644 +index 00000000..87b076c7 +--- /dev/null ++++ b/sysdeps/x86_64/multiarch/memchr-avx2-rtm.S +@@ -0,0 +1,12 @@ ++#ifndef MEMCHR ++# define MEMCHR __memchr_avx2_rtm ++#endif ++ ++#define ZERO_UPPER_VEC_REGISTERS_RETURN \ ++ ZERO_UPPER_VEC_REGISTERS_RETURN_XTEST ++ ++#define VZEROUPPER_RETURN jmp L(return_vzeroupper) ++ ++#define SECTION(p) p##.avx.rtm ++ ++#include "memchr-avx2.S" +diff --git a/sysdeps/x86_64/multiarch/memchr-avx2.S b/sysdeps/x86_64/multiarch/memchr-avx2.S +index c81da19b..cf893e77 100644 +--- a/sysdeps/x86_64/multiarch/memchr-avx2.S ++++ b/sysdeps/x86_64/multiarch/memchr-avx2.S +@@ -34,9 +34,13 @@ + # define VZEROUPPER vzeroupper + # endif + ++# ifndef SECTION ++# define SECTION(p) p##.avx ++# endif ++ + # define VEC_SIZE 32 + +- .section .text.avx,"ax",@progbits ++ .section SECTION(.text),"ax",@progbits + ENTRY (MEMCHR) + # ifndef USE_AS_RAWMEMCHR + /* Check for zero length. */ +@@ -107,8 +111,8 @@ L(cros_page_boundary): + # endif + addq %rdi, %rax + addq %rcx, %rax +- VZEROUPPER +- ret ++L(return_vzeroupper): ++ ZERO_UPPER_VEC_REGISTERS_RETURN + + .p2align 4 + L(aligned_more): +@@ -224,8 +228,7 @@ L(last_4x_vec_or_less): + + jnz L(first_vec_x3_check) + xorl %eax, %eax +- VZEROUPPER +- ret ++ VZEROUPPER_RETURN + + .p2align 4 + L(last_2x_vec): +@@ -243,8 +246,7 @@ L(last_2x_vec): + testl %eax, %eax + jnz L(first_vec_x1_check) + xorl %eax, %eax +- VZEROUPPER +- ret ++ VZEROUPPER_RETURN + + .p2align 4 + L(first_vec_x0_check): +@@ -253,8 +255,7 @@ L(first_vec_x0_check): + cmpq %rax, %rdx + jbe L(zero) + addq %rdi, %rax +- VZEROUPPER +- ret ++ VZEROUPPER_RETURN + + .p2align 4 + L(first_vec_x1_check): +@@ -264,8 +265,7 @@ L(first_vec_x1_check): + jbe L(zero) + addq $VEC_SIZE, %rax + addq %rdi, %rax +- VZEROUPPER +- ret ++ VZEROUPPER_RETURN + + .p2align 4 + L(first_vec_x2_check): +@@ -275,8 +275,7 @@ L(first_vec_x2_check): + jbe L(zero) + addq $(VEC_SIZE * 2), %rax + addq %rdi, %rax +- VZEROUPPER +- ret ++ VZEROUPPER_RETURN + + .p2align 4 + L(first_vec_x3_check): +@@ -286,12 +285,14 @@ L(first_vec_x3_check): + jbe L(zero) + addq $(VEC_SIZE * 3), %rax + addq %rdi, %rax +- VZEROUPPER +- ret ++ VZEROUPPER_RETURN + + .p2align 4 + L(zero): +- VZEROUPPER ++ xorl %eax, %eax ++ jmp L(return_vzeroupper) ++ ++ .p2align 4 + L(null): + xorl %eax, %eax + ret +@@ -301,24 +302,21 @@ L(null): + L(first_vec_x0): + tzcntl %eax, %eax + addq %rdi, %rax +- VZEROUPPER +- ret ++ VZEROUPPER_RETURN + + .p2align 4 + L(first_vec_x1): + tzcntl %eax, %eax + addq $VEC_SIZE, %rax + addq %rdi, %rax +- VZEROUPPER +- ret ++ VZEROUPPER_RETURN + + .p2align 4 + L(first_vec_x2): + tzcntl %eax, %eax + addq $(VEC_SIZE * 2), %rax + addq %rdi, %rax +- VZEROUPPER +- ret ++ VZEROUPPER_RETURN + + .p2align 4 + L(4x_vec_end): +@@ -337,8 +335,7 @@ L(first_vec_x3): + tzcntl %eax, %eax + addq $(VEC_SIZE * 3), %rax + addq %rdi, %rax +- VZEROUPPER +- ret ++ VZEROUPPER_RETURN + + END (MEMCHR) + #endif +diff --git a/sysdeps/x86_64/multiarch/memcmp-avx2-movbe-rtm.S b/sysdeps/x86_64/multiarch/memcmp-avx2-movbe-rtm.S +new file mode 100644 +index 00000000..cf4eff5d +--- /dev/null ++++ b/sysdeps/x86_64/multiarch/memcmp-avx2-movbe-rtm.S +@@ -0,0 +1,12 @@ ++#ifndef MEMCMP ++# define MEMCMP __memcmp_avx2_movbe_rtm ++#endif ++ ++#define ZERO_UPPER_VEC_REGISTERS_RETURN \ ++ ZERO_UPPER_VEC_REGISTERS_RETURN_XTEST ++ ++#define VZEROUPPER_RETURN jmp L(return_vzeroupper) ++ ++#define SECTION(p) p##.avx.rtm ++ ++#include "memcmp-avx2-movbe.S" +diff --git a/sysdeps/x86_64/multiarch/memcmp-avx2-movbe.S b/sysdeps/x86_64/multiarch/memcmp-avx2-movbe.S +index e3a35b89..9d5c9c72 100644 +--- a/sysdeps/x86_64/multiarch/memcmp-avx2-movbe.S ++++ b/sysdeps/x86_64/multiarch/memcmp-avx2-movbe.S +@@ -47,6 +47,10 @@ + # define VZEROUPPER vzeroupper + # endif + ++# ifndef SECTION ++# define SECTION(p) p##.avx ++# endif ++ + # define VEC_SIZE 32 + # define VEC_MASK ((1 << VEC_SIZE) - 1) + +@@ -55,7 +59,7 @@ + memcmp has to use UNSIGNED comparison for elemnts. + */ + +- .section .text.avx,"ax",@progbits ++ .section SECTION(.text),"ax",@progbits + ENTRY (MEMCMP) + # ifdef USE_AS_WMEMCMP + shl $2, %RDX_LP +@@ -123,8 +127,8 @@ ENTRY (MEMCMP) + vptest %ymm0, %ymm5 + jnc L(4x_vec_end) + xorl %eax, %eax +- VZEROUPPER +- ret ++L(return_vzeroupper): ++ ZERO_UPPER_VEC_REGISTERS_RETURN + + .p2align 4 + L(last_2x_vec): +@@ -144,8 +148,7 @@ L(last_vec): + vpmovmskb %ymm2, %eax + subl $VEC_MASK, %eax + jnz L(first_vec) +- VZEROUPPER +- ret ++ VZEROUPPER_RETURN + + .p2align 4 + L(first_vec): +@@ -164,8 +167,7 @@ L(wmemcmp_return): + movzbl (%rsi, %rcx), %edx + sub %edx, %eax + # endif +- VZEROUPPER +- ret ++ VZEROUPPER_RETURN + + # ifdef USE_AS_WMEMCMP + .p2align 4 +@@ -367,8 +369,7 @@ L(last_4x_vec): + vpmovmskb %ymm2, %eax + subl $VEC_MASK, %eax + jnz L(first_vec) +- VZEROUPPER +- ret ++ VZEROUPPER_RETURN + + .p2align 4 + L(4x_vec_end): +@@ -394,8 +395,7 @@ L(4x_vec_end): + movzbl (VEC_SIZE * 3)(%rsi, %rcx), %edx + sub %edx, %eax + # endif +- VZEROUPPER +- ret ++ VZEROUPPER_RETURN + + .p2align 4 + L(first_vec_x1): +@@ -410,8 +410,7 @@ L(first_vec_x1): + movzbl VEC_SIZE(%rsi, %rcx), %edx + sub %edx, %eax + # endif +- VZEROUPPER +- ret ++ VZEROUPPER_RETURN + + .p2align 4 + L(first_vec_x2): +@@ -426,7 +425,6 @@ L(first_vec_x2): + movzbl (VEC_SIZE * 2)(%rsi, %rcx), %edx + sub %edx, %eax + # endif +- VZEROUPPER +- ret ++ VZEROUPPER_RETURN + END (MEMCMP) + #endif +diff --git a/sysdeps/x86_64/multiarch/memmove-avx-unaligned-erms-rtm.S b/sysdeps/x86_64/multiarch/memmove-avx-unaligned-erms-rtm.S +new file mode 100644 +index 00000000..1ec1962e +--- /dev/null ++++ b/sysdeps/x86_64/multiarch/memmove-avx-unaligned-erms-rtm.S +@@ -0,0 +1,17 @@ ++#if IS_IN (libc) ++# define VEC_SIZE 32 ++# define VEC(i) ymm##i ++# define VMOVNT vmovntdq ++# define VMOVU vmovdqu ++# define VMOVA vmovdqa ++ ++# define ZERO_UPPER_VEC_REGISTERS_RETURN \ ++ ZERO_UPPER_VEC_REGISTERS_RETURN_XTEST ++ ++# define VZEROUPPER_RETURN jmp L(return) ++ ++# define SECTION(p) p##.avx.rtm ++# define MEMMOVE_SYMBOL(p,s) p##_avx_##s##_rtm ++ ++# include "memmove-vec-unaligned-erms.S" ++#endif +diff --git a/sysdeps/x86_64/multiarch/memmove-vec-unaligned-erms.S b/sysdeps/x86_64/multiarch/memmove-vec-unaligned-erms.S +index 08e21692..71f5954d 100644 +--- a/sysdeps/x86_64/multiarch/memmove-vec-unaligned-erms.S ++++ b/sysdeps/x86_64/multiarch/memmove-vec-unaligned-erms.S +@@ -140,11 +140,12 @@ L(last_2x_vec): + VMOVU -VEC_SIZE(%rsi,%rdx), %VEC(1) + VMOVU %VEC(0), (%rdi) + VMOVU %VEC(1), -VEC_SIZE(%rdi,%rdx) +- VZEROUPPER + #if !defined USE_MULTIARCH || !IS_IN (libc) + L(nop): +-#endif + ret ++#else ++ VZEROUPPER_RETURN ++#endif + #if defined USE_MULTIARCH && IS_IN (libc) + END (MEMMOVE_SYMBOL (__memmove, unaligned)) + +@@ -237,8 +238,11 @@ L(last_2x_vec): + VMOVU %VEC(0), (%rdi) + VMOVU %VEC(1), -VEC_SIZE(%rdi,%rdx) + L(return): +- VZEROUPPER ++#if VEC_SIZE > 16 ++ ZERO_UPPER_VEC_REGISTERS_RETURN ++#else + ret ++#endif + + L(movsb): + cmpq __x86_shared_non_temporal_threshold(%rip), %rdx +@@ -289,8 +293,7 @@ L(between_32_63): + VMOVU -32(%rsi,%rdx), %YMM1 + VMOVU %YMM0, (%rdi) + VMOVU %YMM1, -32(%rdi,%rdx) +- VZEROUPPER +- ret ++ VZEROUPPER_RETURN + #endif + #if VEC_SIZE > 16 + /* From 16 to 31. No branch when size == 16. */ +@@ -299,7 +302,7 @@ L(between_16_31): + VMOVU -16(%rsi,%rdx), %XMM1 + VMOVU %XMM0, (%rdi) + VMOVU %XMM1, -16(%rdi,%rdx) +- ret ++ VZEROUPPER_RETURN + #endif + L(between_8_15): + /* From 8 to 15. No branch when size == 8. */ +@@ -352,8 +355,7 @@ L(more_2x_vec): + VMOVU %VEC(5), -(VEC_SIZE * 2)(%rdi,%rdx) + VMOVU %VEC(6), -(VEC_SIZE * 3)(%rdi,%rdx) + VMOVU %VEC(7), -(VEC_SIZE * 4)(%rdi,%rdx) +- VZEROUPPER +- ret ++ VZEROUPPER_RETURN + L(last_4x_vec): + /* Copy from 2 * VEC to 4 * VEC. */ + VMOVU (%rsi), %VEC(0) +@@ -364,8 +366,7 @@ L(last_4x_vec): + VMOVU %VEC(1), VEC_SIZE(%rdi) + VMOVU %VEC(2), -VEC_SIZE(%rdi,%rdx) + VMOVU %VEC(3), -(VEC_SIZE * 2)(%rdi,%rdx) +- VZEROUPPER +- ret ++ VZEROUPPER_RETURN + + L(more_8x_vec): + cmpq %rsi, %rdi +@@ -421,8 +422,7 @@ L(loop_4x_vec_forward): + VMOVU %VEC(8), -(VEC_SIZE * 3)(%rcx) + /* Store the first VEC. */ + VMOVU %VEC(4), (%r11) +- VZEROUPPER +- ret ++ VZEROUPPER_RETURN + + L(more_8x_vec_backward): + /* Load the first 4 * VEC and last VEC to support overlapping +@@ -473,8 +473,7 @@ L(loop_4x_vec_backward): + VMOVU %VEC(7), (VEC_SIZE * 3)(%rdi) + /* Store the last VEC. */ + VMOVU %VEC(8), (%r11) +- VZEROUPPER +- ret ++ VZEROUPPER_RETURN + + #if (defined USE_MULTIARCH || VEC_SIZE == 16) && IS_IN (libc) + L(large_forward): +@@ -509,8 +508,7 @@ L(loop_large_forward): + VMOVU %VEC(8), -(VEC_SIZE * 3)(%rcx) + /* Store the first VEC. */ + VMOVU %VEC(4), (%r11) +- VZEROUPPER +- ret ++ VZEROUPPER_RETURN + + L(large_backward): + /* Don't use non-temporal store if there is overlap between +@@ -544,8 +542,7 @@ L(loop_large_backward): + VMOVU %VEC(7), (VEC_SIZE * 3)(%rdi) + /* Store the last VEC. */ + VMOVU %VEC(8), (%r11) +- VZEROUPPER +- ret ++ VZEROUPPER_RETURN + #endif + END (MEMMOVE_SYMBOL (__memmove, unaligned_erms)) + +diff --git a/sysdeps/x86_64/multiarch/memrchr-avx2-rtm.S b/sysdeps/x86_64/multiarch/memrchr-avx2-rtm.S +new file mode 100644 +index 00000000..cea2d2a7 +--- /dev/null ++++ b/sysdeps/x86_64/multiarch/memrchr-avx2-rtm.S +@@ -0,0 +1,12 @@ ++#ifndef MEMRCHR ++# define MEMRCHR __memrchr_avx2_rtm ++#endif ++ ++#define ZERO_UPPER_VEC_REGISTERS_RETURN \ ++ ZERO_UPPER_VEC_REGISTERS_RETURN_XTEST ++ ++#define VZEROUPPER_RETURN jmp L(return_vzeroupper) ++ ++#define SECTION(p) p##.avx.rtm ++ ++#include "memrchr-avx2.S" +diff --git a/sysdeps/x86_64/multiarch/memrchr-avx2.S b/sysdeps/x86_64/multiarch/memrchr-avx2.S +index ce488dd9..20efe7ac 100644 +--- a/sysdeps/x86_64/multiarch/memrchr-avx2.S ++++ b/sysdeps/x86_64/multiarch/memrchr-avx2.S +@@ -20,14 +20,22 @@ + + # include + ++# ifndef MEMRCHR ++# define MEMRCHR __memrchr_avx2 ++# endif ++ + # ifndef VZEROUPPER + # define VZEROUPPER vzeroupper + # endif + ++# ifndef SECTION ++# define SECTION(p) p##.avx ++# endif ++ + # define VEC_SIZE 32 + +- .section .text.avx,"ax",@progbits +-ENTRY (__memrchr_avx2) ++ .section SECTION(.text),"ax",@progbits ++ENTRY (MEMRCHR) + /* Broadcast CHAR to YMM0. */ + vmovd %esi, %xmm0 + vpbroadcastb %xmm0, %ymm0 +@@ -134,8 +142,8 @@ L(loop_4x_vec): + vpmovmskb %ymm1, %eax + bsrl %eax, %eax + addq %rdi, %rax +- VZEROUPPER +- ret ++L(return_vzeroupper): ++ ZERO_UPPER_VEC_REGISTERS_RETURN + + .p2align 4 + L(last_4x_vec_or_less): +@@ -169,8 +177,7 @@ L(last_4x_vec_or_less): + addq %rax, %rdx + jl L(zero) + addq %rdi, %rax +- VZEROUPPER +- ret ++ VZEROUPPER_RETURN + + .p2align 4 + L(last_2x_vec): +@@ -191,31 +198,27 @@ L(last_2x_vec): + jl L(zero) + addl $(VEC_SIZE * 2), %eax + addq %rdi, %rax +- VZEROUPPER +- ret ++ VZEROUPPER_RETURN + + .p2align 4 + L(last_vec_x0): + bsrl %eax, %eax + addq %rdi, %rax +- VZEROUPPER +- ret ++ VZEROUPPER_RETURN + + .p2align 4 + L(last_vec_x1): + bsrl %eax, %eax + addl $VEC_SIZE, %eax + addq %rdi, %rax +- VZEROUPPER +- ret ++ VZEROUPPER_RETURN + + .p2align 4 + L(last_vec_x2): + bsrl %eax, %eax + addl $(VEC_SIZE * 2), %eax + addq %rdi, %rax +- VZEROUPPER +- ret ++ VZEROUPPER_RETURN + + .p2align 4 + L(last_vec_x3): +@@ -232,8 +235,7 @@ L(last_vec_x1_check): + jl L(zero) + addl $VEC_SIZE, %eax + addq %rdi, %rax +- VZEROUPPER +- ret ++ VZEROUPPER_RETURN + + .p2align 4 + L(last_vec_x3_check): +@@ -243,12 +245,14 @@ L(last_vec_x3_check): + jl L(zero) + addl $(VEC_SIZE * 3), %eax + addq %rdi, %rax +- VZEROUPPER +- ret ++ VZEROUPPER_RETURN + + .p2align 4 + L(zero): +- VZEROUPPER ++ xorl %eax, %eax ++ VZEROUPPER_RETURN ++ ++ .p2align 4 + L(null): + xorl %eax, %eax + ret +@@ -273,8 +277,7 @@ L(last_vec_or_less_aligned): + + bsrl %eax, %eax + addq %rdi, %rax +- VZEROUPPER +- ret ++ VZEROUPPER_RETURN + + .p2align 4 + L(last_vec_or_less): +@@ -315,8 +318,7 @@ L(last_vec_or_less): + bsrl %eax, %eax + addq %rdi, %rax + addq %r8, %rax +- VZEROUPPER +- ret ++ VZEROUPPER_RETURN + + .p2align 4 + L(last_vec_2x_aligned): +@@ -353,7 +355,6 @@ L(last_vec_2x_aligned): + bsrl %eax, %eax + addq %rdi, %rax + addq %r8, %rax +- VZEROUPPER +- ret +-END (__memrchr_avx2) ++ VZEROUPPER_RETURN ++END (MEMRCHR) + #endif +diff --git a/sysdeps/x86_64/multiarch/memset-avx2-unaligned-erms-rtm.S b/sysdeps/x86_64/multiarch/memset-avx2-unaligned-erms-rtm.S +new file mode 100644 +index 00000000..8ac3e479 +--- /dev/null ++++ b/sysdeps/x86_64/multiarch/memset-avx2-unaligned-erms-rtm.S +@@ -0,0 +1,10 @@ ++#define ZERO_UPPER_VEC_REGISTERS_RETURN \ ++ ZERO_UPPER_VEC_REGISTERS_RETURN_XTEST ++ ++#define VZEROUPPER_RETURN jmp L(return) ++ ++#define SECTION(p) p##.avx.rtm ++#define MEMSET_SYMBOL(p,s) p##_avx2_##s##_rtm ++#define WMEMSET_SYMBOL(p,s) p##_avx2_##s##_rtm ++ ++#include "memset-avx2-unaligned-erms.S" +diff --git a/sysdeps/x86_64/multiarch/memset-avx2-unaligned-erms.S b/sysdeps/x86_64/multiarch/memset-avx2-unaligned-erms.S +index 7ab3d898..ae0860f3 100644 +--- a/sysdeps/x86_64/multiarch/memset-avx2-unaligned-erms.S ++++ b/sysdeps/x86_64/multiarch/memset-avx2-unaligned-erms.S +@@ -14,9 +14,15 @@ + movq r, %rax; \ + vpbroadcastd %xmm0, %ymm0 + +-# define SECTION(p) p##.avx +-# define MEMSET_SYMBOL(p,s) p##_avx2_##s +-# define WMEMSET_SYMBOL(p,s) p##_avx2_##s ++# ifndef SECTION ++# define SECTION(p) p##.avx ++# endif ++# ifndef MEMSET_SYMBOL ++# define MEMSET_SYMBOL(p,s) p##_avx2_##s ++# endif ++# ifndef WMEMSET_SYMBOL ++# define WMEMSET_SYMBOL(p,s) p##_avx2_##s ++# endif + + # include "memset-vec-unaligned-erms.S" + #endif +diff --git a/sysdeps/x86_64/multiarch/memset-vec-unaligned-erms.S b/sysdeps/x86_64/multiarch/memset-vec-unaligned-erms.S +index 71e91a8f..bae5cba4 100644 +--- a/sysdeps/x86_64/multiarch/memset-vec-unaligned-erms.S ++++ b/sysdeps/x86_64/multiarch/memset-vec-unaligned-erms.S +@@ -45,17 +45,14 @@ + #ifndef VZEROUPPER + # if VEC_SIZE > 16 + # define VZEROUPPER vzeroupper ++# define VZEROUPPER_SHORT_RETURN vzeroupper; ret + # else + # define VZEROUPPER + # endif + #endif + + #ifndef VZEROUPPER_SHORT_RETURN +-# if VEC_SIZE > 16 +-# define VZEROUPPER_SHORT_RETURN vzeroupper +-# else +-# define VZEROUPPER_SHORT_RETURN rep +-# endif ++# define VZEROUPPER_SHORT_RETURN rep; ret + #endif + + #ifndef MOVQ +@@ -117,8 +114,7 @@ L(entry_from_bzero): + /* From VEC and to 2 * VEC. No branch when size == VEC_SIZE. */ + VMOVU %VEC(0), -VEC_SIZE(%rdi,%rdx) + VMOVU %VEC(0), (%rdi) +- VZEROUPPER +- ret ++ VZEROUPPER_RETURN + #if defined USE_MULTIARCH && IS_IN (libc) + END (MEMSET_SYMBOL (__memset, unaligned)) + +@@ -141,14 +137,12 @@ ENTRY (__memset_erms) + ENTRY (MEMSET_SYMBOL (__memset, erms)) + # endif + L(stosb): +- /* Issue vzeroupper before rep stosb. */ +- VZEROUPPER + mov %RDX_LP, %RCX_LP + movzbl %sil, %eax + mov %RDI_LP, %RDX_LP + rep stosb + mov %RDX_LP, %RAX_LP +- ret ++ VZEROUPPER_RETURN + # if VEC_SIZE == 16 + END (__memset_erms) + # else +@@ -175,8 +169,7 @@ ENTRY (MEMSET_SYMBOL (__memset, unaligned_erms)) + /* From VEC and to 2 * VEC. No branch when size == VEC_SIZE. */ + VMOVU %VEC(0), -VEC_SIZE(%rdi,%rdx) + VMOVU %VEC(0), (%rdi) +- VZEROUPPER +- ret ++ VZEROUPPER_RETURN + + L(stosb_more_2x_vec): + cmp __x86_rep_stosb_threshold(%rip), %RDX_LP +@@ -190,8 +183,11 @@ L(more_2x_vec): + VMOVU %VEC(0), -VEC_SIZE(%rdi,%rdx) + VMOVU %VEC(0), -(VEC_SIZE * 2)(%rdi,%rdx) + L(return): +- VZEROUPPER ++#if VEC_SIZE > 16 ++ ZERO_UPPER_VEC_REGISTERS_RETURN ++#else + ret ++#endif + + L(loop_start): + leaq (VEC_SIZE * 4)(%rdi), %rcx +@@ -217,7 +213,6 @@ L(loop): + cmpq %rcx, %rdx + jne L(loop) + VZEROUPPER_SHORT_RETURN +- ret + L(less_vec): + /* Less than 1 VEC. */ + # if VEC_SIZE != 16 && VEC_SIZE != 32 && VEC_SIZE != 64 +@@ -241,40 +236,34 @@ L(less_vec): + jb 1f + movb %cl, (%rdi) + 1: +- VZEROUPPER +- ret ++ VZEROUPPER_RETURN + # if VEC_SIZE > 32 + /* From 32 to 63. No branch when size == 32. */ + L(between_32_63): + VMOVU %YMM0, -32(%rdi,%rdx) + VMOVU %YMM0, (%rdi) +- VZEROUPPER +- ret ++ VZEROUPPER_RETURN + # endif + # if VEC_SIZE > 16 + /* From 16 to 31. No branch when size == 16. */ + L(between_16_31): + VMOVU %XMM0, -16(%rdi,%rdx) + VMOVU %XMM0, (%rdi) +- VZEROUPPER +- ret ++ VZEROUPPER_RETURN + # endif + /* From 8 to 15. No branch when size == 8. */ + L(between_8_15): + movq %rcx, -8(%rdi,%rdx) + movq %rcx, (%rdi) +- VZEROUPPER +- ret ++ VZEROUPPER_RETURN + L(between_4_7): + /* From 4 to 7. No branch when size == 4. */ + movl %ecx, -4(%rdi,%rdx) + movl %ecx, (%rdi) +- VZEROUPPER +- ret ++ VZEROUPPER_RETURN + L(between_2_3): + /* From 2 to 3. No branch when size == 2. */ + movw %cx, -2(%rdi,%rdx) + movw %cx, (%rdi) +- VZEROUPPER +- ret ++ VZEROUPPER_RETURN + END (MEMSET_SYMBOL (__memset, unaligned_erms)) +diff --git a/sysdeps/x86_64/multiarch/rawmemchr-avx2-rtm.S b/sysdeps/x86_64/multiarch/rawmemchr-avx2-rtm.S +new file mode 100644 +index 00000000..acc5f6e2 +--- /dev/null ++++ b/sysdeps/x86_64/multiarch/rawmemchr-avx2-rtm.S +@@ -0,0 +1,4 @@ ++#define MEMCHR __rawmemchr_avx2_rtm ++#define USE_AS_RAWMEMCHR 1 ++ ++#include "memchr-avx2-rtm.S" +diff --git a/sysdeps/x86_64/multiarch/stpcpy-avx2-rtm.S b/sysdeps/x86_64/multiarch/stpcpy-avx2-rtm.S +new file mode 100644 +index 00000000..2b9c07a5 +--- /dev/null ++++ b/sysdeps/x86_64/multiarch/stpcpy-avx2-rtm.S +@@ -0,0 +1,3 @@ ++#define USE_AS_STPCPY ++#define STRCPY __stpcpy_avx2_rtm ++#include "strcpy-avx2-rtm.S" +diff --git a/sysdeps/x86_64/multiarch/stpncpy-avx2-rtm.S b/sysdeps/x86_64/multiarch/stpncpy-avx2-rtm.S +new file mode 100644 +index 00000000..60a2ccfe +--- /dev/null ++++ b/sysdeps/x86_64/multiarch/stpncpy-avx2-rtm.S +@@ -0,0 +1,4 @@ ++#define USE_AS_STPCPY ++#define USE_AS_STRNCPY ++#define STRCPY __stpncpy_avx2_rtm ++#include "strcpy-avx2-rtm.S" +diff --git a/sysdeps/x86_64/multiarch/strcat-avx2-rtm.S b/sysdeps/x86_64/multiarch/strcat-avx2-rtm.S +new file mode 100644 +index 00000000..637fb557 +--- /dev/null ++++ b/sysdeps/x86_64/multiarch/strcat-avx2-rtm.S +@@ -0,0 +1,12 @@ ++#ifndef STRCAT ++# define STRCAT __strcat_avx2_rtm ++#endif ++ ++#define ZERO_UPPER_VEC_REGISTERS_RETURN \ ++ ZERO_UPPER_VEC_REGISTERS_RETURN_XTEST ++ ++#define VZEROUPPER_RETURN jmp L(return_vzeroupper) ++ ++#define SECTION(p) p##.avx.rtm ++ ++#include "strcat-avx2.S" +diff --git a/sysdeps/x86_64/multiarch/strcat-avx2.S b/sysdeps/x86_64/multiarch/strcat-avx2.S +index b0623564..aa48c058 100644 +--- a/sysdeps/x86_64/multiarch/strcat-avx2.S ++++ b/sysdeps/x86_64/multiarch/strcat-avx2.S +@@ -30,7 +30,11 @@ + /* Number of bytes in a vector register */ + # define VEC_SIZE 32 + +- .section .text.avx,"ax",@progbits ++# ifndef SECTION ++# define SECTION(p) p##.avx ++# endif ++ ++ .section SECTION(.text),"ax",@progbits + ENTRY (STRCAT) + mov %rdi, %r9 + # ifdef USE_AS_STRNCAT +diff --git a/sysdeps/x86_64/multiarch/strchr-avx2-rtm.S b/sysdeps/x86_64/multiarch/strchr-avx2-rtm.S +new file mode 100644 +index 00000000..81f20d1d +--- /dev/null ++++ b/sysdeps/x86_64/multiarch/strchr-avx2-rtm.S +@@ -0,0 +1,12 @@ ++#ifndef STRCHR ++# define STRCHR __strchr_avx2_rtm ++#endif ++ ++#define ZERO_UPPER_VEC_REGISTERS_RETURN \ ++ ZERO_UPPER_VEC_REGISTERS_RETURN_XTEST ++ ++#define VZEROUPPER_RETURN jmp L(return_vzeroupper) ++ ++#define SECTION(p) p##.avx.rtm ++ ++#include "strchr-avx2.S" +diff --git a/sysdeps/x86_64/multiarch/strchr-avx2.S b/sysdeps/x86_64/multiarch/strchr-avx2.S +index 47bc3c99..da7d2620 100644 +--- a/sysdeps/x86_64/multiarch/strchr-avx2.S ++++ b/sysdeps/x86_64/multiarch/strchr-avx2.S +@@ -38,9 +38,13 @@ + # define VZEROUPPER vzeroupper + # endif + ++# ifndef SECTION ++# define SECTION(p) p##.avx ++# endif ++ + # define VEC_SIZE 32 + +- .section .text.avx,"ax",@progbits ++ .section SECTION(.text),"ax",@progbits + ENTRY (STRCHR) + movl %edi, %ecx + /* Broadcast CHAR to YMM0. */ +@@ -93,8 +97,8 @@ L(cros_page_boundary): + cmp (%rax), %CHAR_REG + cmovne %rdx, %rax + # endif +- VZEROUPPER +- ret ++L(return_vzeroupper): ++ ZERO_UPPER_VEC_REGISTERS_RETURN + + .p2align 4 + L(aligned_more): +@@ -190,8 +194,7 @@ L(first_vec_x0): + cmp (%rax), %CHAR_REG + cmovne %rdx, %rax + # endif +- VZEROUPPER +- ret ++ VZEROUPPER_RETURN + + .p2align 4 + L(first_vec_x1): +@@ -205,8 +208,7 @@ L(first_vec_x1): + cmp (%rax), %CHAR_REG + cmovne %rdx, %rax + # endif +- VZEROUPPER +- ret ++ VZEROUPPER_RETURN + + .p2align 4 + L(first_vec_x2): +@@ -220,8 +222,7 @@ L(first_vec_x2): + cmp (%rax), %CHAR_REG + cmovne %rdx, %rax + # endif +- VZEROUPPER +- ret ++ VZEROUPPER_RETURN + + .p2align 4 + L(4x_vec_end): +@@ -247,8 +248,7 @@ L(first_vec_x3): + cmp (%rax), %CHAR_REG + cmovne %rdx, %rax + # endif +- VZEROUPPER +- ret ++ VZEROUPPER_RETURN + + END (STRCHR) + #endif +diff --git a/sysdeps/x86_64/multiarch/strchr.c b/sysdeps/x86_64/multiarch/strchr.c +index be05e197..7e582f02 100644 +--- a/sysdeps/x86_64/multiarch/strchr.c ++++ b/sysdeps/x86_64/multiarch/strchr.c +@@ -29,6 +29,7 @@ + extern __typeof (REDIRECT_NAME) OPTIMIZE (sse2) attribute_hidden; + extern __typeof (REDIRECT_NAME) OPTIMIZE (sse2_no_bsf) attribute_hidden; + extern __typeof (REDIRECT_NAME) OPTIMIZE (avx2) attribute_hidden; ++extern __typeof (REDIRECT_NAME) OPTIMIZE (avx2_rtm) attribute_hidden; + extern __typeof (REDIRECT_NAME) OPTIMIZE (evex) attribute_hidden; + + static inline void * +@@ -44,6 +45,9 @@ IFUNC_SELECTOR (void) + && CPU_FEATURE_USABLE_P (cpu_features, BMI2)) + return OPTIMIZE (evex); + ++ if (CPU_FEATURE_USABLE_P (cpu_features, RTM)) ++ return OPTIMIZE (avx2_rtm); ++ + if (!CPU_FEATURES_ARCH_P (cpu_features, Prefer_No_VZEROUPPER)) + return OPTIMIZE (avx2); + } +diff --git a/sysdeps/x86_64/multiarch/strchrnul-avx2-rtm.S b/sysdeps/x86_64/multiarch/strchrnul-avx2-rtm.S +new file mode 100644 +index 00000000..cdcf818b +--- /dev/null ++++ b/sysdeps/x86_64/multiarch/strchrnul-avx2-rtm.S +@@ -0,0 +1,3 @@ ++#define STRCHR __strchrnul_avx2_rtm ++#define USE_AS_STRCHRNUL 1 ++#include "strchr-avx2-rtm.S" +diff --git a/sysdeps/x86_64/multiarch/strcmp-avx2-rtm.S b/sysdeps/x86_64/multiarch/strcmp-avx2-rtm.S +new file mode 100644 +index 00000000..aecd30d9 +--- /dev/null ++++ b/sysdeps/x86_64/multiarch/strcmp-avx2-rtm.S +@@ -0,0 +1,12 @@ ++#ifndef STRCMP ++# define STRCMP __strcmp_avx2_rtm ++#endif ++ ++#define ZERO_UPPER_VEC_REGISTERS_RETURN \ ++ ZERO_UPPER_VEC_REGISTERS_RETURN_XTEST ++ ++#define VZEROUPPER_RETURN jmp L(return_vzeroupper) ++ ++#define SECTION(p) p##.avx.rtm ++ ++#include "strcmp-avx2.S" +diff --git a/sysdeps/x86_64/multiarch/strcmp-avx2.S b/sysdeps/x86_64/multiarch/strcmp-avx2.S +index 8fb8eedc..5d1c9d90 100644 +--- a/sysdeps/x86_64/multiarch/strcmp-avx2.S ++++ b/sysdeps/x86_64/multiarch/strcmp-avx2.S +@@ -55,6 +55,10 @@ + # define VZEROUPPER vzeroupper + # endif + ++# ifndef SECTION ++# define SECTION(p) p##.avx ++# endif ++ + /* Warning! + wcscmp/wcsncmp have to use SIGNED comparison for elements. + strcmp/strncmp have to use UNSIGNED comparison for elements. +@@ -75,7 +79,7 @@ + the maximum offset is reached before a difference is found, zero is + returned. */ + +- .section .text.avx,"ax",@progbits ++ .section SECTION(.text),"ax",@progbits + ENTRY (STRCMP) + # ifdef USE_AS_STRNCMP + /* Check for simple cases (0 or 1) in offset. */ +@@ -137,8 +141,8 @@ L(return): + movzbl (%rsi, %rdx), %edx + subl %edx, %eax + # endif +- VZEROUPPER +- ret ++L(return_vzeroupper): ++ ZERO_UPPER_VEC_REGISTERS_RETURN + + .p2align 4 + L(return_vec_size): +@@ -171,8 +175,7 @@ L(return_vec_size): + subl %edx, %eax + # endif + # endif +- VZEROUPPER +- ret ++ VZEROUPPER_RETURN + + .p2align 4 + L(return_2_vec_size): +@@ -205,8 +208,7 @@ L(return_2_vec_size): + subl %edx, %eax + # endif + # endif +- VZEROUPPER +- ret ++ VZEROUPPER_RETURN + + .p2align 4 + L(return_3_vec_size): +@@ -239,8 +241,7 @@ L(return_3_vec_size): + subl %edx, %eax + # endif + # endif +- VZEROUPPER +- ret ++ VZEROUPPER_RETURN + + .p2align 4 + L(next_3_vectors): +@@ -366,8 +367,7 @@ L(back_to_loop): + subl %edx, %eax + # endif + # endif +- VZEROUPPER +- ret ++ VZEROUPPER_RETURN + + .p2align 4 + L(test_vec): +@@ -410,8 +410,7 @@ L(test_vec): + subl %edx, %eax + # endif + # endif +- VZEROUPPER +- ret ++ VZEROUPPER_RETURN + + .p2align 4 + L(test_2_vec): +@@ -454,8 +453,7 @@ L(test_2_vec): + subl %edx, %eax + # endif + # endif +- VZEROUPPER +- ret ++ VZEROUPPER_RETURN + + .p2align 4 + L(test_3_vec): +@@ -496,8 +494,7 @@ L(test_3_vec): + subl %edx, %eax + # endif + # endif +- VZEROUPPER +- ret ++ VZEROUPPER_RETURN + + .p2align 4 + L(loop_cross_page): +@@ -566,8 +563,7 @@ L(loop_cross_page): + subl %edx, %eax + # endif + # endif +- VZEROUPPER +- ret ++ VZEROUPPER_RETURN + + .p2align 4 + L(loop_cross_page_2_vec): +@@ -641,8 +637,7 @@ L(loop_cross_page_2_vec): + subl %edx, %eax + # endif + # endif +- VZEROUPPER +- ret ++ VZEROUPPER_RETURN + + # ifdef USE_AS_STRNCMP + L(string_nbyte_offset_check): +@@ -684,8 +679,7 @@ L(cross_page_loop): + # ifndef USE_AS_WCSCMP + L(different): + # endif +- VZEROUPPER +- ret ++ VZEROUPPER_RETURN + + # ifdef USE_AS_WCSCMP + .p2align 4 +@@ -695,16 +689,14 @@ L(different): + setl %al + negl %eax + orl $1, %eax +- VZEROUPPER +- ret ++ VZEROUPPER_RETURN + # endif + + # ifdef USE_AS_STRNCMP + .p2align 4 + L(zero): + xorl %eax, %eax +- VZEROUPPER +- ret ++ VZEROUPPER_RETURN + + .p2align 4 + L(char0): +@@ -718,8 +710,7 @@ L(char0): + movzbl (%rdi), %eax + subl %ecx, %eax + # endif +- VZEROUPPER +- ret ++ VZEROUPPER_RETURN + # endif + + .p2align 4 +@@ -744,8 +735,7 @@ L(last_vector): + movzbl (%rsi, %rdx), %edx + subl %edx, %eax + # endif +- VZEROUPPER +- ret ++ VZEROUPPER_RETURN + + /* Comparing on page boundary region requires special treatment: + It must done one vector at the time, starting with the wider +@@ -866,7 +856,6 @@ L(cross_page_4bytes): + testl %eax, %eax + jne L(cross_page_loop) + subl %ecx, %eax +- VZEROUPPER +- ret ++ VZEROUPPER_RETURN + END (STRCMP) + #endif +diff --git a/sysdeps/x86_64/multiarch/strcmp.c b/sysdeps/x86_64/multiarch/strcmp.c +index c5f38510..11bbea2b 100644 +--- a/sysdeps/x86_64/multiarch/strcmp.c ++++ b/sysdeps/x86_64/multiarch/strcmp.c +@@ -30,6 +30,7 @@ extern __typeof (REDIRECT_NAME) OPTIMIZE (sse2) attribute_hidden; + extern __typeof (REDIRECT_NAME) OPTIMIZE (sse2_unaligned) attribute_hidden; + extern __typeof (REDIRECT_NAME) OPTIMIZE (ssse3) attribute_hidden; + extern __typeof (REDIRECT_NAME) OPTIMIZE (avx2) attribute_hidden; ++extern __typeof (REDIRECT_NAME) OPTIMIZE (avx2_rtm) attribute_hidden; + extern __typeof (REDIRECT_NAME) OPTIMIZE (evex) attribute_hidden; + + static inline void * +@@ -46,6 +47,9 @@ IFUNC_SELECTOR (void) + && !CPU_FEATURES_ARCH_P (cpu_features, Prefer_AVX2_STRCMP)) + return OPTIMIZE (evex); + ++ if (CPU_FEATURE_USABLE_P (cpu_features, RTM)) ++ return OPTIMIZE (avx2_rtm); ++ + if (!CPU_FEATURES_ARCH_P (cpu_features, Prefer_No_VZEROUPPER)) + return OPTIMIZE (avx2); + } +diff --git a/sysdeps/x86_64/multiarch/strcpy-avx2-rtm.S b/sysdeps/x86_64/multiarch/strcpy-avx2-rtm.S +new file mode 100644 +index 00000000..c2c581ec +--- /dev/null ++++ b/sysdeps/x86_64/multiarch/strcpy-avx2-rtm.S +@@ -0,0 +1,12 @@ ++#ifndef STRCPY ++# define STRCPY __strcpy_avx2_rtm ++#endif ++ ++#define ZERO_UPPER_VEC_REGISTERS_RETURN \ ++ ZERO_UPPER_VEC_REGISTERS_RETURN_XTEST ++ ++#define VZEROUPPER_RETURN jmp L(return_vzeroupper) ++ ++#define SECTION(p) p##.avx.rtm ++ ++#include "strcpy-avx2.S" +diff --git a/sysdeps/x86_64/multiarch/strcpy-avx2.S b/sysdeps/x86_64/multiarch/strcpy-avx2.S +index 81677f90..613c59aa 100644 +--- a/sysdeps/x86_64/multiarch/strcpy-avx2.S ++++ b/sysdeps/x86_64/multiarch/strcpy-avx2.S +@@ -37,6 +37,10 @@ + # define VZEROUPPER vzeroupper + # endif + ++# ifndef SECTION ++# define SECTION(p) p##.avx ++# endif ++ + /* zero register */ + #define xmmZ xmm0 + #define ymmZ ymm0 +@@ -46,7 +50,7 @@ + + # ifndef USE_AS_STRCAT + +- .section .text.avx,"ax",@progbits ++ .section SECTION(.text),"ax",@progbits + ENTRY (STRCPY) + # ifdef USE_AS_STRNCPY + mov %rdx, %r8 +@@ -369,8 +373,8 @@ L(CopyVecSizeExit): + lea 1(%rdi), %rdi + jnz L(StrncpyFillTailWithZero) + # endif +- VZEROUPPER +- ret ++L(return_vzeroupper): ++ ZERO_UPPER_VEC_REGISTERS_RETURN + + .p2align 4 + L(CopyTwoVecSize1): +@@ -553,8 +557,7 @@ L(Exit1): + lea 2(%rdi), %rdi + jnz L(StrncpyFillTailWithZero) + # endif +- VZEROUPPER +- ret ++ VZEROUPPER_RETURN + + .p2align 4 + L(Exit2): +@@ -569,8 +572,7 @@ L(Exit2): + lea 3(%rdi), %rdi + jnz L(StrncpyFillTailWithZero) + # endif +- VZEROUPPER +- ret ++ VZEROUPPER_RETURN + + .p2align 4 + L(Exit3): +@@ -584,8 +586,7 @@ L(Exit3): + lea 4(%rdi), %rdi + jnz L(StrncpyFillTailWithZero) + # endif +- VZEROUPPER +- ret ++ VZEROUPPER_RETURN + + .p2align 4 + L(Exit4_7): +@@ -602,8 +603,7 @@ L(Exit4_7): + lea 1(%rdi, %rdx), %rdi + jnz L(StrncpyFillTailWithZero) + # endif +- VZEROUPPER +- ret ++ VZEROUPPER_RETURN + + .p2align 4 + L(Exit8_15): +@@ -620,8 +620,7 @@ L(Exit8_15): + lea 1(%rdi, %rdx), %rdi + jnz L(StrncpyFillTailWithZero) + # endif +- VZEROUPPER +- ret ++ VZEROUPPER_RETURN + + .p2align 4 + L(Exit16_31): +@@ -638,8 +637,7 @@ L(Exit16_31): + lea 1(%rdi, %rdx), %rdi + jnz L(StrncpyFillTailWithZero) + # endif +- VZEROUPPER +- ret ++ VZEROUPPER_RETURN + + .p2align 4 + L(Exit32_63): +@@ -656,8 +654,7 @@ L(Exit32_63): + lea 1(%rdi, %rdx), %rdi + jnz L(StrncpyFillTailWithZero) + # endif +- VZEROUPPER +- ret ++ VZEROUPPER_RETURN + + # ifdef USE_AS_STRNCPY + +@@ -671,8 +668,7 @@ L(StrncpyExit1): + # ifdef USE_AS_STRCAT + movb $0, 1(%rdi) + # endif +- VZEROUPPER +- ret ++ VZEROUPPER_RETURN + + .p2align 4 + L(StrncpyExit2): +@@ -684,8 +680,7 @@ L(StrncpyExit2): + # ifdef USE_AS_STRCAT + movb $0, 2(%rdi) + # endif +- VZEROUPPER +- ret ++ VZEROUPPER_RETURN + + .p2align 4 + L(StrncpyExit3_4): +@@ -699,8 +694,7 @@ L(StrncpyExit3_4): + # ifdef USE_AS_STRCAT + movb $0, (%rdi, %r8) + # endif +- VZEROUPPER +- ret ++ VZEROUPPER_RETURN + + .p2align 4 + L(StrncpyExit5_8): +@@ -714,8 +708,7 @@ L(StrncpyExit5_8): + # ifdef USE_AS_STRCAT + movb $0, (%rdi, %r8) + # endif +- VZEROUPPER +- ret ++ VZEROUPPER_RETURN + + .p2align 4 + L(StrncpyExit9_16): +@@ -729,8 +722,7 @@ L(StrncpyExit9_16): + # ifdef USE_AS_STRCAT + movb $0, (%rdi, %r8) + # endif +- VZEROUPPER +- ret ++ VZEROUPPER_RETURN + + .p2align 4 + L(StrncpyExit17_32): +@@ -744,8 +736,7 @@ L(StrncpyExit17_32): + # ifdef USE_AS_STRCAT + movb $0, (%rdi, %r8) + # endif +- VZEROUPPER +- ret ++ VZEROUPPER_RETURN + + .p2align 4 + L(StrncpyExit33_64): +@@ -760,8 +751,7 @@ L(StrncpyExit33_64): + # ifdef USE_AS_STRCAT + movb $0, (%rdi, %r8) + # endif +- VZEROUPPER +- ret ++ VZEROUPPER_RETURN + + .p2align 4 + L(StrncpyExit65): +@@ -778,50 +768,43 @@ L(StrncpyExit65): + # ifdef USE_AS_STRCAT + movb $0, 65(%rdi) + # endif +- VZEROUPPER +- ret ++ VZEROUPPER_RETURN + + # ifndef USE_AS_STRCAT + + .p2align 4 + L(Fill1): + mov %dl, (%rdi) +- VZEROUPPER +- ret ++ VZEROUPPER_RETURN + + .p2align 4 + L(Fill2): + mov %dx, (%rdi) +- VZEROUPPER +- ret ++ VZEROUPPER_RETURN + + .p2align 4 + L(Fill3_4): + mov %dx, (%rdi) + mov %dx, -2(%rdi, %r8) +- VZEROUPPER +- ret ++ VZEROUPPER_RETURN + + .p2align 4 + L(Fill5_8): + mov %edx, (%rdi) + mov %edx, -4(%rdi, %r8) +- VZEROUPPER +- ret ++ VZEROUPPER_RETURN + + .p2align 4 + L(Fill9_16): + mov %rdx, (%rdi) + mov %rdx, -8(%rdi, %r8) +- VZEROUPPER +- ret ++ VZEROUPPER_RETURN + + .p2align 4 + L(Fill17_32): + vmovdqu %xmmZ, (%rdi) + vmovdqu %xmmZ, -16(%rdi, %r8) +- VZEROUPPER +- ret ++ VZEROUPPER_RETURN + + .p2align 4 + L(CopyVecSizeUnalignedVec2): +@@ -898,8 +881,7 @@ L(Fill): + cmp $1, %r8d + ja L(Fill2) + je L(Fill1) +- VZEROUPPER +- ret ++ VZEROUPPER_RETURN + + /* end of ifndef USE_AS_STRCAT */ + # endif +@@ -929,8 +911,7 @@ L(UnalignedFourVecSizeLeaveCase3): + # ifdef USE_AS_STRCAT + movb $0, (VEC_SIZE * 4)(%rdi) + # endif +- VZEROUPPER +- ret ++ VZEROUPPER_RETURN + + .p2align 4 + L(UnalignedFourVecSizeLeaveCase2): +@@ -1001,16 +982,14 @@ L(StrncpyExit): + # ifdef USE_AS_STRCAT + movb $0, (%rdi) + # endif +- VZEROUPPER +- ret ++ VZEROUPPER_RETURN + + .p2align 4 + L(ExitZero): + # ifndef USE_AS_STRCAT + mov %rdi, %rax + # endif +- VZEROUPPER +- ret ++ VZEROUPPER_RETURN + + # endif + +diff --git a/sysdeps/x86_64/multiarch/strlen-avx2-rtm.S b/sysdeps/x86_64/multiarch/strlen-avx2-rtm.S +new file mode 100644 +index 00000000..75b4b761 +--- /dev/null ++++ b/sysdeps/x86_64/multiarch/strlen-avx2-rtm.S +@@ -0,0 +1,12 @@ ++#ifndef STRLEN ++# define STRLEN __strlen_avx2_rtm ++#endif ++ ++#define ZERO_UPPER_VEC_REGISTERS_RETURN \ ++ ZERO_UPPER_VEC_REGISTERS_RETURN_XTEST ++ ++#define VZEROUPPER_RETURN jmp L(return_vzeroupper) ++ ++#define SECTION(p) p##.avx.rtm ++ ++#include "strlen-avx2.S" +diff --git a/sysdeps/x86_64/multiarch/strlen-avx2.S b/sysdeps/x86_64/multiarch/strlen-avx2.S +index 645e0446..82826e10 100644 +--- a/sysdeps/x86_64/multiarch/strlen-avx2.S ++++ b/sysdeps/x86_64/multiarch/strlen-avx2.S +@@ -36,9 +36,13 @@ + # define VZEROUPPER vzeroupper + # endif + ++# ifndef SECTION ++# define SECTION(p) p##.avx ++# endif ++ + # define VEC_SIZE 32 + +- .section .text.avx,"ax",@progbits ++ .section SECTION(.text),"ax",@progbits + ENTRY (STRLEN) + # ifdef USE_AS_STRNLEN + /* Check for zero length. */ +@@ -111,8 +115,8 @@ L(cros_page_boundary): + # ifdef USE_AS_WCSLEN + shrq $2, %rax + # endif +- VZEROUPPER +- ret ++L(return_vzeroupper): ++ ZERO_UPPER_VEC_REGISTERS_RETURN + + .p2align 4 + L(aligned_more): +@@ -231,8 +235,7 @@ L(last_4x_vec_or_less): + # ifdef USE_AS_WCSLEN + shrq $2, %rax + # endif +- VZEROUPPER +- ret ++ VZEROUPPER_RETURN + + .p2align 4 + L(last_2x_vec): +@@ -253,8 +256,7 @@ L(last_2x_vec): + # ifdef USE_AS_WCSLEN + shrq $2, %rax + # endif +- VZEROUPPER +- ret ++ VZEROUPPER_RETURN + + .p2align 4 + L(first_vec_x0_check): +@@ -267,8 +269,7 @@ L(first_vec_x0_check): + # ifdef USE_AS_WCSLEN + shrq $2, %rax + # endif +- VZEROUPPER +- ret ++ VZEROUPPER_RETURN + + .p2align 4 + L(first_vec_x1_check): +@@ -282,8 +283,7 @@ L(first_vec_x1_check): + # ifdef USE_AS_WCSLEN + shrq $2, %rax + # endif +- VZEROUPPER +- ret ++ VZEROUPPER_RETURN + + .p2align 4 + L(first_vec_x2_check): +@@ -297,8 +297,7 @@ L(first_vec_x2_check): + # ifdef USE_AS_WCSLEN + shrq $2, %rax + # endif +- VZEROUPPER +- ret ++ VZEROUPPER_RETURN + + .p2align 4 + L(first_vec_x3_check): +@@ -312,8 +311,7 @@ L(first_vec_x3_check): + # ifdef USE_AS_WCSLEN + shrq $2, %rax + # endif +- VZEROUPPER +- ret ++ VZEROUPPER_RETURN + + .p2align 4 + L(max): +@@ -321,8 +319,7 @@ L(max): + # ifdef USE_AS_WCSLEN + shrq $2, %rax + # endif +- VZEROUPPER +- ret ++ VZEROUPPER_RETURN + + .p2align 4 + L(zero): +@@ -338,8 +335,7 @@ L(first_vec_x0): + # ifdef USE_AS_WCSLEN + shrq $2, %rax + # endif +- VZEROUPPER +- ret ++ VZEROUPPER_RETURN + + .p2align 4 + L(first_vec_x1): +@@ -350,8 +346,7 @@ L(first_vec_x1): + # ifdef USE_AS_WCSLEN + shrq $2, %rax + # endif +- VZEROUPPER +- ret ++ VZEROUPPER_RETURN + + .p2align 4 + L(first_vec_x2): +@@ -362,8 +357,7 @@ L(first_vec_x2): + # ifdef USE_AS_WCSLEN + shrq $2, %rax + # endif +- VZEROUPPER +- ret ++ VZEROUPPER_RETURN + + .p2align 4 + L(4x_vec_end): +@@ -389,8 +383,7 @@ L(first_vec_x3): + # ifdef USE_AS_WCSLEN + shrq $2, %rax + # endif +- VZEROUPPER +- ret ++ VZEROUPPER_RETURN + + END (STRLEN) + #endif +diff --git a/sysdeps/x86_64/multiarch/strncat-avx2-rtm.S b/sysdeps/x86_64/multiarch/strncat-avx2-rtm.S +new file mode 100644 +index 00000000..0dcea18d +--- /dev/null ++++ b/sysdeps/x86_64/multiarch/strncat-avx2-rtm.S +@@ -0,0 +1,3 @@ ++#define USE_AS_STRNCAT ++#define STRCAT __strncat_avx2_rtm ++#include "strcat-avx2-rtm.S" +diff --git a/sysdeps/x86_64/multiarch/strncmp-avx2-rtm.S b/sysdeps/x86_64/multiarch/strncmp-avx2-rtm.S +new file mode 100644 +index 00000000..37d1224b +--- /dev/null ++++ b/sysdeps/x86_64/multiarch/strncmp-avx2-rtm.S +@@ -0,0 +1,3 @@ ++#define STRCMP __strncmp_avx2_rtm ++#define USE_AS_STRNCMP 1 ++#include "strcmp-avx2-rtm.S" +diff --git a/sysdeps/x86_64/multiarch/strncmp.c b/sysdeps/x86_64/multiarch/strncmp.c +index 4c15542f..44c85116 100644 +--- a/sysdeps/x86_64/multiarch/strncmp.c ++++ b/sysdeps/x86_64/multiarch/strncmp.c +@@ -30,6 +30,7 @@ extern __typeof (REDIRECT_NAME) OPTIMIZE (sse2) attribute_hidden; + extern __typeof (REDIRECT_NAME) OPTIMIZE (ssse3) attribute_hidden; + extern __typeof (REDIRECT_NAME) OPTIMIZE (sse42) attribute_hidden; + extern __typeof (REDIRECT_NAME) OPTIMIZE (avx2) attribute_hidden; ++extern __typeof (REDIRECT_NAME) OPTIMIZE (avx2_rtm) attribute_hidden; + extern __typeof (REDIRECT_NAME) OPTIMIZE (evex) attribute_hidden; + + static inline void * +@@ -46,6 +47,9 @@ IFUNC_SELECTOR (void) + && !CPU_FEATURES_ARCH_P (cpu_features, Prefer_AVX2_STRCMP)) + return OPTIMIZE (evex); + ++ if (CPU_FEATURE_USABLE_P (cpu_features, RTM)) ++ return OPTIMIZE (avx2_rtm); ++ + if (!CPU_FEATURES_ARCH_P (cpu_features, Prefer_No_VZEROUPPER)) + return OPTIMIZE (avx2); + } +diff --git a/sysdeps/x86_64/multiarch/strncpy-avx2-rtm.S b/sysdeps/x86_64/multiarch/strncpy-avx2-rtm.S +new file mode 100644 +index 00000000..79e70832 +--- /dev/null ++++ b/sysdeps/x86_64/multiarch/strncpy-avx2-rtm.S +@@ -0,0 +1,3 @@ ++#define USE_AS_STRNCPY ++#define STRCPY __strncpy_avx2_rtm ++#include "strcpy-avx2-rtm.S" +diff --git a/sysdeps/x86_64/multiarch/strnlen-avx2-rtm.S b/sysdeps/x86_64/multiarch/strnlen-avx2-rtm.S +new file mode 100644 +index 00000000..04f1626a +--- /dev/null ++++ b/sysdeps/x86_64/multiarch/strnlen-avx2-rtm.S +@@ -0,0 +1,4 @@ ++#define STRLEN __strnlen_avx2_rtm ++#define USE_AS_STRNLEN 1 ++ ++#include "strlen-avx2-rtm.S" +diff --git a/sysdeps/x86_64/multiarch/strrchr-avx2-rtm.S b/sysdeps/x86_64/multiarch/strrchr-avx2-rtm.S +new file mode 100644 +index 00000000..5def14ec +--- /dev/null ++++ b/sysdeps/x86_64/multiarch/strrchr-avx2-rtm.S +@@ -0,0 +1,12 @@ ++#ifndef STRRCHR ++# define STRRCHR __strrchr_avx2_rtm ++#endif ++ ++#define ZERO_UPPER_VEC_REGISTERS_RETURN \ ++ ZERO_UPPER_VEC_REGISTERS_RETURN_XTEST ++ ++#define VZEROUPPER_RETURN jmp L(return_vzeroupper) ++ ++#define SECTION(p) p##.avx.rtm ++ ++#include "strrchr-avx2.S" +diff --git a/sysdeps/x86_64/multiarch/strrchr-avx2.S b/sysdeps/x86_64/multiarch/strrchr-avx2.S +index 4381e6ab..9f22a15e 100644 +--- a/sysdeps/x86_64/multiarch/strrchr-avx2.S ++++ b/sysdeps/x86_64/multiarch/strrchr-avx2.S +@@ -36,9 +36,13 @@ + # define VZEROUPPER vzeroupper + # endif + ++# ifndef SECTION ++# define SECTION(p) p##.avx ++# endif ++ + # define VEC_SIZE 32 + +- .section .text.avx,"ax",@progbits ++ .section SECTION(.text),"ax",@progbits + ENTRY (STRRCHR) + movd %esi, %xmm4 + movl %edi, %ecx +@@ -166,8 +170,8 @@ L(return_value): + # endif + bsrl %eax, %eax + leaq -VEC_SIZE(%rdi, %rax), %rax +- VZEROUPPER +- ret ++L(return_vzeroupper): ++ ZERO_UPPER_VEC_REGISTERS_RETURN + + .p2align 4 + L(match): +@@ -198,8 +202,7 @@ L(find_nul): + jz L(return_value) + bsrl %eax, %eax + leaq -VEC_SIZE(%rdi, %rax), %rax +- VZEROUPPER +- ret ++ VZEROUPPER_RETURN + + .p2align 4 + L(char_and_nul): +@@ -222,14 +225,12 @@ L(char_and_nul_in_first_vec): + jz L(return_null) + bsrl %eax, %eax + leaq -VEC_SIZE(%rdi, %rax), %rax +- VZEROUPPER +- ret ++ VZEROUPPER_RETURN + + .p2align 4 + L(return_null): + xorl %eax, %eax +- VZEROUPPER +- ret ++ VZEROUPPER_RETURN + + END (STRRCHR) + #endif +diff --git a/sysdeps/x86_64/multiarch/wcschr-avx2-rtm.S b/sysdeps/x86_64/multiarch/wcschr-avx2-rtm.S +new file mode 100644 +index 00000000..d49dbbf0 +--- /dev/null ++++ b/sysdeps/x86_64/multiarch/wcschr-avx2-rtm.S +@@ -0,0 +1,3 @@ ++#define STRCHR __wcschr_avx2_rtm ++#define USE_AS_WCSCHR 1 ++#include "strchr-avx2-rtm.S" +diff --git a/sysdeps/x86_64/multiarch/wcscmp-avx2-rtm.S b/sysdeps/x86_64/multiarch/wcscmp-avx2-rtm.S +new file mode 100644 +index 00000000..d6ca2b80 +--- /dev/null ++++ b/sysdeps/x86_64/multiarch/wcscmp-avx2-rtm.S +@@ -0,0 +1,4 @@ ++#define STRCMP __wcscmp_avx2_rtm ++#define USE_AS_WCSCMP 1 ++ ++#include "strcmp-avx2-rtm.S" +diff --git a/sysdeps/x86_64/multiarch/wcslen-avx2-rtm.S b/sysdeps/x86_64/multiarch/wcslen-avx2-rtm.S +new file mode 100644 +index 00000000..35658d73 +--- /dev/null ++++ b/sysdeps/x86_64/multiarch/wcslen-avx2-rtm.S +@@ -0,0 +1,4 @@ ++#define STRLEN __wcslen_avx2_rtm ++#define USE_AS_WCSLEN 1 ++ ++#include "strlen-avx2-rtm.S" +diff --git a/sysdeps/x86_64/multiarch/wcsncmp-avx2-rtm.S b/sysdeps/x86_64/multiarch/wcsncmp-avx2-rtm.S +new file mode 100644 +index 00000000..4e88c70c +--- /dev/null ++++ b/sysdeps/x86_64/multiarch/wcsncmp-avx2-rtm.S +@@ -0,0 +1,5 @@ ++#define STRCMP __wcsncmp_avx2_rtm ++#define USE_AS_STRNCMP 1 ++#define USE_AS_WCSCMP 1 ++ ++#include "strcmp-avx2-rtm.S" +diff --git a/sysdeps/x86_64/multiarch/wcsnlen-avx2-rtm.S b/sysdeps/x86_64/multiarch/wcsnlen-avx2-rtm.S +new file mode 100644 +index 00000000..7437ebee +--- /dev/null ++++ b/sysdeps/x86_64/multiarch/wcsnlen-avx2-rtm.S +@@ -0,0 +1,5 @@ ++#define STRLEN __wcsnlen_avx2_rtm ++#define USE_AS_WCSLEN 1 ++#define USE_AS_STRNLEN 1 ++ ++#include "strlen-avx2-rtm.S" +diff --git a/sysdeps/x86_64/multiarch/wcsnlen.c b/sysdeps/x86_64/multiarch/wcsnlen.c +index 84254b83..20b731ae 100644 +--- a/sysdeps/x86_64/multiarch/wcsnlen.c ++++ b/sysdeps/x86_64/multiarch/wcsnlen.c +@@ -29,6 +29,7 @@ + extern __typeof (REDIRECT_NAME) OPTIMIZE (sse2) attribute_hidden; + extern __typeof (REDIRECT_NAME) OPTIMIZE (sse4_1) attribute_hidden; + extern __typeof (REDIRECT_NAME) OPTIMIZE (avx2) attribute_hidden; ++extern __typeof (REDIRECT_NAME) OPTIMIZE (avx2_rtm) attribute_hidden; + extern __typeof (REDIRECT_NAME) OPTIMIZE (evex) attribute_hidden; + + static inline void * +@@ -44,6 +45,9 @@ IFUNC_SELECTOR (void) + && CPU_FEATURE_USABLE_P (cpu_features, BMI2)) + return OPTIMIZE (evex); + ++ if (CPU_FEATURE_USABLE_P (cpu_features, RTM)) ++ return OPTIMIZE (avx2_rtm); ++ + if (!CPU_FEATURES_ARCH_P (cpu_features, Prefer_No_VZEROUPPER)) + return OPTIMIZE (avx2); + } +diff --git a/sysdeps/x86_64/multiarch/wcsrchr-avx2-rtm.S b/sysdeps/x86_64/multiarch/wcsrchr-avx2-rtm.S +new file mode 100644 +index 00000000..9bf76083 +--- /dev/null ++++ b/sysdeps/x86_64/multiarch/wcsrchr-avx2-rtm.S +@@ -0,0 +1,3 @@ ++#define STRRCHR __wcsrchr_avx2_rtm ++#define USE_AS_WCSRCHR 1 ++#include "strrchr-avx2-rtm.S" +diff --git a/sysdeps/x86_64/multiarch/wmemchr-avx2-rtm.S b/sysdeps/x86_64/multiarch/wmemchr-avx2-rtm.S +new file mode 100644 +index 00000000..58ed21db +--- /dev/null ++++ b/sysdeps/x86_64/multiarch/wmemchr-avx2-rtm.S +@@ -0,0 +1,4 @@ ++#define MEMCHR __wmemchr_avx2_rtm ++#define USE_AS_WMEMCHR 1 ++ ++#include "memchr-avx2-rtm.S" +diff --git a/sysdeps/x86_64/multiarch/wmemcmp-avx2-movbe-rtm.S b/sysdeps/x86_64/multiarch/wmemcmp-avx2-movbe-rtm.S +new file mode 100644 +index 00000000..31104d12 +--- /dev/null ++++ b/sysdeps/x86_64/multiarch/wmemcmp-avx2-movbe-rtm.S +@@ -0,0 +1,4 @@ ++#define MEMCMP __wmemcmp_avx2_movbe_rtm ++#define USE_AS_WMEMCMP 1 ++ ++#include "memcmp-avx2-movbe-rtm.S" +diff --git a/sysdeps/x86_64/sysdep.h b/sysdeps/x86_64/sysdep.h +index 1738d7f9..223f1a59 100644 +--- a/sysdeps/x86_64/sysdep.h ++++ b/sysdeps/x86_64/sysdep.h +@@ -95,6 +95,28 @@ lose: \ + #define R14_LP r14 + #define R15_LP r15 + ++/* Zero upper vector registers and return with xtest. NB: Use VZEROALL ++ to avoid RTM abort triggered by VZEROUPPER inside transactionally. */ ++#define ZERO_UPPER_VEC_REGISTERS_RETURN_XTEST \ ++ xtest; \ ++ jz 1f; \ ++ vzeroall; \ ++ ret; \ ++1: \ ++ vzeroupper; \ ++ ret ++ ++/* Zero upper vector registers and return. */ ++#ifndef ZERO_UPPER_VEC_REGISTERS_RETURN ++# define ZERO_UPPER_VEC_REGISTERS_RETURN \ ++ VZEROUPPER; \ ++ ret ++#endif ++ ++#ifndef VZEROUPPER_RETURN ++# define VZEROUPPER_RETURN VZEROUPPER; ret ++#endif ++ + #else /* __ASSEMBLER__ */ + + /* Long and pointer size in bytes. */ +-- +GitLab + diff --git a/SOURCES/glibc-RHEL-15696-18.patch b/SOURCES/glibc-RHEL-15696-18.patch new file mode 100644 index 0000000..2cf0e45 --- /dev/null +++ b/SOURCES/glibc-RHEL-15696-18.patch @@ -0,0 +1,735 @@ +From 4bd660be40967cd69072f69ebc2ad32bfcc1f206 Mon Sep 17 00:00:00 2001 +From: "H.J. Lu" +Date: Tue, 23 Feb 2021 06:33:10 -0800 +Subject: [PATCH] x86: Add string/memory function tests in RTM region +Content-type: text/plain; charset=UTF-8 + +At function exit, AVX optimized string/memory functions have VZEROUPPER +which triggers RTM abort. When such functions are called inside a +transactionally executing RTM region, RTM abort causes severe performance +degradation. Add tests to verify that string/memory functions won't +cause RTM abort in RTM region. +--- + sysdeps/x86/Makefile | 23 +++++++++++ + sysdeps/x86/tst-memchr-rtm.c | 54 ++++++++++++++++++++++++++ + sysdeps/x86/tst-memcmp-rtm.c | 52 +++++++++++++++++++++++++ + sysdeps/x86/tst-memmove-rtm.c | 53 ++++++++++++++++++++++++++ + sysdeps/x86/tst-memrchr-rtm.c | 54 ++++++++++++++++++++++++++ + sysdeps/x86/tst-memset-rtm.c | 45 ++++++++++++++++++++++ + sysdeps/x86/tst-strchr-rtm.c | 54 ++++++++++++++++++++++++++ + sysdeps/x86/tst-strcpy-rtm.c | 53 ++++++++++++++++++++++++++ + sysdeps/x86/tst-string-rtm.h | 72 +++++++++++++++++++++++++++++++++++ + sysdeps/x86/tst-strlen-rtm.c | 53 ++++++++++++++++++++++++++ + sysdeps/x86/tst-strncmp-rtm.c | 52 +++++++++++++++++++++++++ + sysdeps/x86/tst-strrchr-rtm.c | 53 ++++++++++++++++++++++++++ + 12 files changed, 618 insertions(+) + create mode 100644 sysdeps/x86/tst-memchr-rtm.c + create mode 100644 sysdeps/x86/tst-memcmp-rtm.c + create mode 100644 sysdeps/x86/tst-memmove-rtm.c + create mode 100644 sysdeps/x86/tst-memrchr-rtm.c + create mode 100644 sysdeps/x86/tst-memset-rtm.c + create mode 100644 sysdeps/x86/tst-strchr-rtm.c + create mode 100644 sysdeps/x86/tst-strcpy-rtm.c + create mode 100644 sysdeps/x86/tst-string-rtm.h + create mode 100644 sysdeps/x86/tst-strlen-rtm.c + create mode 100644 sysdeps/x86/tst-strncmp-rtm.c + create mode 100644 sysdeps/x86/tst-strrchr-rtm.c + +diff --git a/sysdeps/x86/Makefile b/sysdeps/x86/Makefile +index 59e928e9..5be71ada 100644 +--- a/sysdeps/x86/Makefile ++++ b/sysdeps/x86/Makefile +@@ -17,6 +17,29 @@ endif + + ifeq ($(subdir),string) + sysdep_routines += cacheinfo ++ ++tests += \ ++ tst-memchr-rtm \ ++ tst-memcmp-rtm \ ++ tst-memmove-rtm \ ++ tst-memrchr-rtm \ ++ tst-memset-rtm \ ++ tst-strchr-rtm \ ++ tst-strcpy-rtm \ ++ tst-strlen-rtm \ ++ tst-strncmp-rtm \ ++ tst-strrchr-rtm ++ ++CFLAGS-tst-memchr-rtm.c += -mrtm ++CFLAGS-tst-memcmp-rtm.c += -mrtm ++CFLAGS-tst-memmove-rtm.c += -mrtm ++CFLAGS-tst-memrchr-rtm.c += -mrtm ++CFLAGS-tst-memset-rtm.c += -mrtm ++CFLAGS-tst-strchr-rtm.c += -mrtm ++CFLAGS-tst-strcpy-rtm.c += -mrtm ++CFLAGS-tst-strlen-rtm.c += -mrtm ++CFLAGS-tst-strncmp-rtm.c += -mrtm ++CFLAGS-tst-strrchr-rtm.c += -mrtm + endif + + ifneq ($(enable-cet),no) +diff --git a/sysdeps/x86/tst-memchr-rtm.c b/sysdeps/x86/tst-memchr-rtm.c +new file mode 100644 +index 00000000..e4749401 +--- /dev/null ++++ b/sysdeps/x86/tst-memchr-rtm.c +@@ -0,0 +1,54 @@ ++/* Test case for memchr inside a transactionally executing RTM region. ++ 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 ++ ++#define LOOP 3000 ++#define STRING_SIZE 1024 ++char string1[STRING_SIZE]; ++ ++__attribute__ ((noinline, noclone)) ++static int ++prepare (void) ++{ ++ memset (string1, 'a', STRING_SIZE); ++ string1[100] = 'c'; ++ string1[STRING_SIZE - 100] = 'c'; ++ char *p = memchr (string1, 'c', STRING_SIZE); ++ if (p == &string1[100]) ++ return EXIT_SUCCESS; ++ else ++ return EXIT_FAILURE; ++} ++ ++__attribute__ ((noinline, noclone)) ++static int ++function (void) ++{ ++ char *p = memchr (string1, 'c', STRING_SIZE); ++ if (p == &string1[100]) ++ return 0; ++ else ++ return 1; ++} ++ ++static int ++do_test (void) ++{ ++ return do_test_1 ("memchr", LOOP, prepare, function); ++} +diff --git a/sysdeps/x86/tst-memcmp-rtm.c b/sysdeps/x86/tst-memcmp-rtm.c +new file mode 100644 +index 00000000..e4c8a623 +--- /dev/null ++++ b/sysdeps/x86/tst-memcmp-rtm.c +@@ -0,0 +1,52 @@ ++/* Test case for memcmp inside a transactionally executing RTM region. ++ 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 ++ ++#define LOOP 3000 ++#define STRING_SIZE 1024 ++char string1[STRING_SIZE]; ++char string2[STRING_SIZE]; ++ ++__attribute__ ((noinline, noclone)) ++static int ++prepare (void) ++{ ++ memset (string1, 'a', STRING_SIZE); ++ memset (string2, 'a', STRING_SIZE); ++ if (memcmp (string1, string2, STRING_SIZE) == 0) ++ return EXIT_SUCCESS; ++ else ++ return EXIT_FAILURE; ++} ++ ++__attribute__ ((noinline, noclone)) ++static int ++function (void) ++{ ++ if (memcmp (string1, string2, STRING_SIZE) == 0) ++ return 0; ++ else ++ return 1; ++} ++ ++static int ++do_test (void) ++{ ++ return do_test_1 ("memcmp", LOOP, prepare, function); ++} +diff --git a/sysdeps/x86/tst-memmove-rtm.c b/sysdeps/x86/tst-memmove-rtm.c +new file mode 100644 +index 00000000..4bf97ef1 +--- /dev/null ++++ b/sysdeps/x86/tst-memmove-rtm.c +@@ -0,0 +1,53 @@ ++/* Test case for memmove inside a transactionally executing RTM region. ++ 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 ++ ++#define LOOP 3000 ++#define STRING_SIZE 1024 ++char string1[STRING_SIZE]; ++char string2[STRING_SIZE]; ++ ++__attribute__ ((noinline, noclone)) ++static int ++prepare (void) ++{ ++ memset (string1, 'a', STRING_SIZE); ++ if (memmove (string2, string1, STRING_SIZE) == string2 ++ && memcmp (string2, string1, STRING_SIZE) == 0) ++ return EXIT_SUCCESS; ++ else ++ return EXIT_FAILURE; ++} ++ ++__attribute__ ((noinline, noclone)) ++static int ++function (void) ++{ ++ if (memmove (string2, string1, STRING_SIZE) == string2 ++ && memcmp (string2, string1, STRING_SIZE) == 0) ++ return 0; ++ else ++ return 1; ++} ++ ++static int ++do_test (void) ++{ ++ return do_test_1 ("memmove", LOOP, prepare, function); ++} +diff --git a/sysdeps/x86/tst-memrchr-rtm.c b/sysdeps/x86/tst-memrchr-rtm.c +new file mode 100644 +index 00000000..a57a5a8e +--- /dev/null ++++ b/sysdeps/x86/tst-memrchr-rtm.c +@@ -0,0 +1,54 @@ ++/* Test case for memrchr inside a transactionally executing RTM region. ++ 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 ++ ++#define LOOP 3000 ++#define STRING_SIZE 1024 ++char string1[STRING_SIZE]; ++ ++__attribute__ ((noinline, noclone)) ++static int ++prepare (void) ++{ ++ memset (string1, 'a', STRING_SIZE); ++ string1[100] = 'c'; ++ string1[STRING_SIZE - 100] = 'c'; ++ char *p = memrchr (string1, 'c', STRING_SIZE); ++ if (p == &string1[STRING_SIZE - 100]) ++ return EXIT_SUCCESS; ++ else ++ return EXIT_FAILURE; ++} ++ ++__attribute__ ((noinline, noclone)) ++static int ++function (void) ++{ ++ char *p = memrchr (string1, 'c', STRING_SIZE); ++ if (p == &string1[STRING_SIZE - 100]) ++ return 0; ++ else ++ return 1; ++} ++ ++static int ++do_test (void) ++{ ++ return do_test_1 ("memrchr", LOOP, prepare, function); ++} +diff --git a/sysdeps/x86/tst-memset-rtm.c b/sysdeps/x86/tst-memset-rtm.c +new file mode 100644 +index 00000000..bf343a4d +--- /dev/null ++++ b/sysdeps/x86/tst-memset-rtm.c +@@ -0,0 +1,45 @@ ++/* Test case for memset inside a transactionally executing RTM region. ++ 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 ++ ++#define LOOP 3000 ++#define STRING_SIZE 1024 ++char string1[STRING_SIZE]; ++ ++__attribute__ ((noinline, noclone)) ++static int ++prepare (void) ++{ ++ memset (string1, 'a', STRING_SIZE); ++ return EXIT_SUCCESS; ++} ++ ++__attribute__ ((noinline, noclone)) ++static int ++function (void) ++{ ++ memset (string1, 'a', STRING_SIZE); ++ return 0; ++} ++ ++static int ++do_test (void) ++{ ++ return do_test_1 ("memset", LOOP, prepare, function); ++} +diff --git a/sysdeps/x86/tst-strchr-rtm.c b/sysdeps/x86/tst-strchr-rtm.c +new file mode 100644 +index 00000000..a82e29c0 +--- /dev/null ++++ b/sysdeps/x86/tst-strchr-rtm.c +@@ -0,0 +1,54 @@ ++/* Test case for strchr inside a transactionally executing RTM region. ++ 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 ++ ++#define LOOP 3000 ++#define STRING_SIZE 1024 ++char string1[STRING_SIZE]; ++ ++__attribute__ ((noinline, noclone)) ++static int ++prepare (void) ++{ ++ memset (string1, 'a', STRING_SIZE - 1); ++ string1[100] = 'c'; ++ string1[STRING_SIZE - 100] = 'c'; ++ char *p = strchr (string1, 'c'); ++ if (p == &string1[100]) ++ return EXIT_SUCCESS; ++ else ++ return EXIT_FAILURE; ++} ++ ++__attribute__ ((noinline, noclone)) ++static int ++function (void) ++{ ++ char *p = strchr (string1, 'c'); ++ if (p == &string1[100]) ++ return 0; ++ else ++ return 1; ++} ++ ++static int ++do_test (void) ++{ ++ return do_test_1 ("strchr", LOOP, prepare, function); ++} +diff --git a/sysdeps/x86/tst-strcpy-rtm.c b/sysdeps/x86/tst-strcpy-rtm.c +new file mode 100644 +index 00000000..2b2a583f +--- /dev/null ++++ b/sysdeps/x86/tst-strcpy-rtm.c +@@ -0,0 +1,53 @@ ++/* Test case for strcpy inside a transactionally executing RTM region. ++ 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 ++ ++#define LOOP 3000 ++#define STRING_SIZE 1024 ++char string1[STRING_SIZE]; ++char string2[STRING_SIZE]; ++ ++__attribute__ ((noinline, noclone)) ++static int ++prepare (void) ++{ ++ memset (string1, 'a', STRING_SIZE - 1); ++ if (strcpy (string2, string1) == string2 ++ && strcmp (string2, string1) == 0) ++ return EXIT_SUCCESS; ++ else ++ return EXIT_FAILURE; ++} ++ ++__attribute__ ((noinline, noclone)) ++static int ++function (void) ++{ ++ if (strcpy (string2, string1) == string2 ++ && strcmp (string2, string1) == 0) ++ return 0; ++ else ++ return 1; ++} ++ ++static int ++do_test (void) ++{ ++ return do_test_1 ("strcpy", LOOP, prepare, function); ++} +diff --git a/sysdeps/x86/tst-string-rtm.h b/sysdeps/x86/tst-string-rtm.h +new file mode 100644 +index 00000000..d2470afa +--- /dev/null ++++ b/sysdeps/x86/tst-string-rtm.h +@@ -0,0 +1,72 @@ ++/* Test string function in a transactionally executing RTM region. ++ 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 ++ ++static int ++do_test_1 (const char *name, unsigned int loop, int (*prepare) (void), ++ int (*function) (void)) ++{ ++ if (!CPU_FEATURE_USABLE (RTM)) ++ return EXIT_UNSUPPORTED; ++ ++ int status = prepare (); ++ if (status != EXIT_SUCCESS) ++ return status; ++ ++ unsigned int i; ++ unsigned int naborts = 0; ++ unsigned int failed = 0; ++ for (i = 0; i < loop; i++) ++ { ++ failed |= function (); ++ if (_xbegin() == _XBEGIN_STARTED) ++ { ++ failed |= function (); ++ _xend(); ++ } ++ else ++ { ++ failed |= function (); ++ ++naborts; ++ } ++ } ++ ++ if (failed) ++ FAIL_EXIT1 ("%s() failed", name); ++ ++ if (naborts) ++ { ++ /* NB: Low single digit (<= 5%) noise-level aborts are normal for ++ TSX. */ ++ double rate = 100 * ((double) naborts) / ((double) loop); ++ if (rate > 5) ++ FAIL_EXIT1 ("TSX abort rate: %.2f%% (%d out of %d)", ++ rate, naborts, loop); ++ } ++ ++ return EXIT_SUCCESS; ++} ++ ++static int do_test (void); ++ ++#include +diff --git a/sysdeps/x86/tst-strlen-rtm.c b/sysdeps/x86/tst-strlen-rtm.c +new file mode 100644 +index 00000000..0dcf14db +--- /dev/null ++++ b/sysdeps/x86/tst-strlen-rtm.c +@@ -0,0 +1,53 @@ ++/* Test case for strlen inside a transactionally executing RTM region. ++ 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 ++ ++#define LOOP 3000 ++#define STRING_SIZE 1024 ++char string1[STRING_SIZE]; ++ ++__attribute__ ((noinline, noclone)) ++static int ++prepare (void) ++{ ++ memset (string1, 'a', STRING_SIZE - 1); ++ string1[STRING_SIZE - 100] = '\0'; ++ size_t len = strlen (string1); ++ if (len == STRING_SIZE - 100) ++ return EXIT_SUCCESS; ++ else ++ return EXIT_FAILURE; ++} ++ ++__attribute__ ((noinline, noclone)) ++static int ++function (void) ++{ ++ size_t len = strlen (string1); ++ if (len == STRING_SIZE - 100) ++ return 0; ++ else ++ return 1; ++} ++ ++static int ++do_test (void) ++{ ++ return do_test_1 ("strlen", LOOP, prepare, function); ++} +diff --git a/sysdeps/x86/tst-strncmp-rtm.c b/sysdeps/x86/tst-strncmp-rtm.c +new file mode 100644 +index 00000000..236ad951 +--- /dev/null ++++ b/sysdeps/x86/tst-strncmp-rtm.c +@@ -0,0 +1,52 @@ ++/* Test case for strncmp inside a transactionally executing RTM region. ++ 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 ++ ++#define LOOP 3000 ++#define STRING_SIZE 1024 ++char string1[STRING_SIZE]; ++char string2[STRING_SIZE]; ++ ++__attribute__ ((noinline, noclone)) ++static int ++prepare (void) ++{ ++ memset (string1, 'a', STRING_SIZE - 1); ++ memset (string2, 'a', STRING_SIZE - 1); ++ if (strncmp (string1, string2, STRING_SIZE) == 0) ++ return EXIT_SUCCESS; ++ else ++ return EXIT_FAILURE; ++} ++ ++__attribute__ ((noinline, noclone)) ++static int ++function (void) ++{ ++ if (strncmp (string1, string2, STRING_SIZE) == 0) ++ return 0; ++ else ++ return 1; ++} ++ ++static int ++do_test (void) ++{ ++ return do_test_1 ("strncmp", LOOP, prepare, function); ++} +diff --git a/sysdeps/x86/tst-strrchr-rtm.c b/sysdeps/x86/tst-strrchr-rtm.c +new file mode 100644 +index 00000000..e32bfaf5 +--- /dev/null ++++ b/sysdeps/x86/tst-strrchr-rtm.c +@@ -0,0 +1,53 @@ ++/* Test case for strrchr inside a transactionally executing RTM region. ++ 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 ++ ++#define LOOP 3000 ++#define STRING_SIZE 1024 ++char string1[STRING_SIZE]; ++ ++__attribute__ ((noinline, noclone)) ++static int ++prepare (void) ++{ ++ memset (string1, 'a', STRING_SIZE - 1); ++ string1[STRING_SIZE - 100] = 'c'; ++ char *p = strrchr (string1, 'c'); ++ if (p == &string1[STRING_SIZE - 100]) ++ return EXIT_SUCCESS; ++ else ++ return EXIT_FAILURE; ++} ++ ++__attribute__ ((noinline, noclone)) ++static int ++function (void) ++{ ++ char *p = strrchr (string1, 'c'); ++ if (p == &string1[STRING_SIZE - 100]) ++ return 0; ++ else ++ return 1; ++} ++ ++static int ++do_test (void) ++{ ++ return do_test_1 ("strrchr", LOOP, prepare, function); ++} +-- +GitLab + diff --git a/SOURCES/glibc-RHEL-15696-19.patch b/SOURCES/glibc-RHEL-15696-19.patch new file mode 100644 index 0000000..0500875 --- /dev/null +++ b/SOURCES/glibc-RHEL-15696-19.patch @@ -0,0 +1,148 @@ +From 4e2d8f352774b56078c34648b14a2412c38384f4 Mon Sep 17 00:00:00 2001 +From: "H.J. Lu" +Date: Sun, 7 Mar 2021 09:44:18 -0800 +Subject: [PATCH] x86-64: Use ZMM16-ZMM31 in AVX512 memset family functions +Content-type: text/plain; charset=UTF-8 + +Update ifunc-memset.h/ifunc-wmemset.h to select the function optimized +with AVX512 instructions using ZMM16-ZMM31 registers to avoid RTM abort +with usable AVX512VL and AVX512BW since VZEROUPPER isn't needed at +function exit. +--- + sysdeps/x86_64/multiarch/ifunc-impl-list.c | 14 +++++++++----- + sysdeps/x86_64/multiarch/ifunc-memset.h | 13 ++++++++----- + sysdeps/x86_64/multiarch/ifunc-wmemset.h | 12 ++++++------ + .../multiarch/memset-avx512-unaligned-erms.S | 16 ++++++++-------- + 4 files changed, 31 insertions(+), 24 deletions(-) + +diff --git a/sysdeps/x86_64/multiarch/ifunc-impl-list.c b/sysdeps/x86_64/multiarch/ifunc-impl-list.c +index c1efeec0..d969a156 100644 +--- a/sysdeps/x86_64/multiarch/ifunc-impl-list.c ++++ b/sysdeps/x86_64/multiarch/ifunc-impl-list.c +@@ -211,10 +211,12 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + && CPU_FEATURE_USABLE (AVX512BW)), + __memset_chk_evex_unaligned_erms) + IFUNC_IMPL_ADD (array, i, __memset_chk, +- CPU_FEATURE_USABLE (AVX512F), ++ (CPU_FEATURE_USABLE (AVX512VL) ++ && CPU_FEATURE_USABLE (AVX512BW)), + __memset_chk_avx512_unaligned_erms) + IFUNC_IMPL_ADD (array, i, __memset_chk, +- CPU_FEATURE_USABLE (AVX512F), ++ (CPU_FEATURE_USABLE (AVX512VL) ++ && CPU_FEATURE_USABLE (AVX512BW)), + __memset_chk_avx512_unaligned) + IFUNC_IMPL_ADD (array, i, __memset_chk, + CPU_FEATURE_USABLE (AVX512F), +@@ -252,10 +254,12 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + && CPU_FEATURE_USABLE (AVX512BW)), + __memset_evex_unaligned_erms) + IFUNC_IMPL_ADD (array, i, memset, +- CPU_FEATURE_USABLE (AVX512F), ++ (CPU_FEATURE_USABLE (AVX512VL) ++ && CPU_FEATURE_USABLE (AVX512BW)), + __memset_avx512_unaligned_erms) + IFUNC_IMPL_ADD (array, i, memset, +- CPU_FEATURE_USABLE (AVX512F), ++ (CPU_FEATURE_USABLE (AVX512VL) ++ && CPU_FEATURE_USABLE (AVX512BW)), + __memset_avx512_unaligned) + IFUNC_IMPL_ADD (array, i, memset, + CPU_FEATURE_USABLE (AVX512F), +@@ -719,7 +723,7 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + CPU_FEATURE_USABLE (AVX512VL), + __wmemset_evex_unaligned) + IFUNC_IMPL_ADD (array, i, wmemset, +- CPU_FEATURE_USABLE (AVX512F), ++ CPU_FEATURE_USABLE (AVX512VL), + __wmemset_avx512_unaligned)) + + #ifdef SHARED +diff --git a/sysdeps/x86_64/multiarch/ifunc-memset.h b/sysdeps/x86_64/multiarch/ifunc-memset.h +index 6f3375cc..19795938 100644 +--- a/sysdeps/x86_64/multiarch/ifunc-memset.h ++++ b/sysdeps/x86_64/multiarch/ifunc-memset.h +@@ -53,13 +53,16 @@ IFUNC_SELECTOR (void) + if (CPU_FEATURE_USABLE_P (cpu_features, AVX512F) + && !CPU_FEATURES_ARCH_P (cpu_features, Prefer_No_AVX512)) + { +- if (CPU_FEATURES_ARCH_P (cpu_features, Prefer_No_VZEROUPPER)) +- return OPTIMIZE (avx512_no_vzeroupper); ++ if (CPU_FEATURE_USABLE_P (cpu_features, AVX512VL) ++ && CPU_FEATURE_USABLE_P (cpu_features, AVX512BW)) ++ { ++ if (CPU_FEATURE_USABLE_P (cpu_features, ERMS)) ++ return OPTIMIZE (avx512_unaligned_erms); + +- if (CPU_FEATURE_USABLE_P (cpu_features, ERMS)) +- return OPTIMIZE (avx512_unaligned_erms); ++ return OPTIMIZE (avx512_unaligned); ++ } + +- return OPTIMIZE (avx512_unaligned); ++ return OPTIMIZE (avx512_no_vzeroupper); + } + + if (CPU_FEATURE_USABLE_P (cpu_features, AVX2)) +diff --git a/sysdeps/x86_64/multiarch/ifunc-wmemset.h b/sysdeps/x86_64/multiarch/ifunc-wmemset.h +index bdc94c6c..98c5d406 100644 +--- a/sysdeps/x86_64/multiarch/ifunc-wmemset.h ++++ b/sysdeps/x86_64/multiarch/ifunc-wmemset.h +@@ -33,13 +33,13 @@ IFUNC_SELECTOR (void) + if (CPU_FEATURE_USABLE_P (cpu_features, AVX2) + && CPU_FEATURES_ARCH_P (cpu_features, AVX_Fast_Unaligned_Load)) + { +- if (CPU_FEATURE_USABLE_P (cpu_features, AVX512F) +- && !CPU_FEATURES_ARCH_P (cpu_features, Prefer_No_AVX512) +- && !CPU_FEATURES_ARCH_P (cpu_features, Prefer_No_VZEROUPPER)) +- return OPTIMIZE (avx512_unaligned); +- + if (CPU_FEATURE_USABLE_P (cpu_features, AVX512VL)) +- return OPTIMIZE (evex_unaligned); ++ { ++ if (!CPU_FEATURES_ARCH_P (cpu_features, Prefer_No_AVX512)) ++ return OPTIMIZE (avx512_unaligned); ++ ++ return OPTIMIZE (evex_unaligned); ++ } + + if (CPU_FEATURE_USABLE_P (cpu_features, RTM)) + return OPTIMIZE (avx2_unaligned_rtm); +diff --git a/sysdeps/x86_64/multiarch/memset-avx512-unaligned-erms.S b/sysdeps/x86_64/multiarch/memset-avx512-unaligned-erms.S +index 0783979c..22e7b187 100644 +--- a/sysdeps/x86_64/multiarch/memset-avx512-unaligned-erms.S ++++ b/sysdeps/x86_64/multiarch/memset-avx512-unaligned-erms.S +@@ -1,22 +1,22 @@ + #if IS_IN (libc) + # define VEC_SIZE 64 +-# define VEC(i) zmm##i ++# define XMM0 xmm16 ++# define YMM0 ymm16 ++# define VEC0 zmm16 ++# define VEC(i) VEC##i + # define VMOVU vmovdqu64 + # define VMOVA vmovdqa64 ++# define VZEROUPPER + + # define MEMSET_VDUP_TO_VEC0_AND_SET_RETURN(d, r) \ +- vmovd d, %xmm0; \ + movq r, %rax; \ +- vpbroadcastb %xmm0, %xmm0; \ +- vpbroadcastq %xmm0, %zmm0 ++ vpbroadcastb d, %VEC0 + + # define WMEMSET_VDUP_TO_VEC0_AND_SET_RETURN(d, r) \ +- vmovd d, %xmm0; \ + movq r, %rax; \ +- vpbroadcastd %xmm0, %xmm0; \ +- vpbroadcastq %xmm0, %zmm0 ++ vpbroadcastd d, %VEC0 + +-# define SECTION(p) p##.avx512 ++# define SECTION(p) p##.evex512 + # define MEMSET_SYMBOL(p,s) p##_avx512_##s + # define WMEMSET_SYMBOL(p,s) p##_avx512_##s + +-- +GitLab + diff --git a/SOURCES/glibc-RHEL-15696-2.patch b/SOURCES/glibc-RHEL-15696-2.patch new file mode 100644 index 0000000..54f3ac3 --- /dev/null +++ b/SOURCES/glibc-RHEL-15696-2.patch @@ -0,0 +1,230 @@ +From b304fc201d2f6baf52ea790df8643e99772243cd Mon Sep 17 00:00:00 2001 +From: "H.J. Lu" +Date: Mon, 21 Jan 2019 11:25:56 -0800 +Subject: [PATCH] x86-64 memcmp/wmemcmp: Properly handle the length parameter + [BZ# 24097] +Content-type: text/plain; charset=UTF-8 + +On x32, the size_t parameter may be passed in the lower 32 bits of a +64-bit register with the non-zero upper 32 bits. The string/memory +functions written in assembly can only use the lower 32 bits of a +64-bit register as length or must clear the upper 32 bits before using +the full 64-bit register for length. + +This pach fixes memcmp/wmemcmp for x32. Tested on x86-64 and x32. On +x86-64, libc.so is the same with and withou the fix. + + [BZ# 24097] + CVE-2019-6488 + * sysdeps/x86_64/multiarch/memcmp-avx2-movbe.S: Use RDX_LP for + length. Clear the upper 32 bits of RDX register. + * sysdeps/x86_64/multiarch/memcmp-sse4.S: Likewise. + * sysdeps/x86_64/multiarch/memcmp-ssse3.S: Likewise. + * sysdeps/x86_64/x32/Makefile (tests): Add tst-size_t-memcmp and + tst-size_t-wmemcmp. + * sysdeps/x86_64/x32/tst-size_t-memcmp.c: New file. + * sysdeps/x86_64/x32/tst-size_t-wmemcmp.c: Likewise. +--- + sysdeps/x86_64/multiarch/memcmp-avx2-movbe.S | 7 +- + sysdeps/x86_64/multiarch/memcmp-sse4.S | 9 ++- + sysdeps/x86_64/multiarch/memcmp-ssse3.S | 7 +- + sysdeps/x86_64/x32/Makefile | 4 +- + sysdeps/x86_64/x32/tst-size_t-memcmp.c | 76 ++++++++++++++++++++ + sysdeps/x86_64/x32/tst-size_t-wmemcmp.c | 20 ++++++ + 6 files changed, 114 insertions(+), 9 deletions(-) + create mode 100644 sysdeps/x86_64/x32/tst-size_t-memcmp.c + create mode 100644 sysdeps/x86_64/x32/tst-size_t-wmemcmp.c + +Conflicts: + ChangeLog + (removed) + +diff --git a/sysdeps/x86_64/multiarch/memcmp-avx2-movbe.S b/sysdeps/x86_64/multiarch/memcmp-avx2-movbe.S +index 30f764c3..e3a35b89 100644 +--- a/sysdeps/x86_64/multiarch/memcmp-avx2-movbe.S ++++ b/sysdeps/x86_64/multiarch/memcmp-avx2-movbe.S +@@ -58,9 +58,12 @@ + .section .text.avx,"ax",@progbits + ENTRY (MEMCMP) + # ifdef USE_AS_WMEMCMP +- shl $2, %rdx ++ shl $2, %RDX_LP ++# elif defined __ILP32__ ++ /* Clear the upper 32 bits. */ ++ movl %edx, %edx + # endif +- cmpq $VEC_SIZE, %rdx ++ cmp $VEC_SIZE, %RDX_LP + jb L(less_vec) + + /* From VEC to 2 * VEC. No branch when size == VEC_SIZE. */ +diff --git a/sysdeps/x86_64/multiarch/memcmp-sse4.S b/sysdeps/x86_64/multiarch/memcmp-sse4.S +index 8e164f2c..302900f5 100644 +--- a/sysdeps/x86_64/multiarch/memcmp-sse4.S ++++ b/sysdeps/x86_64/multiarch/memcmp-sse4.S +@@ -42,13 +42,16 @@ + .section .text.sse4.1,"ax",@progbits + ENTRY (MEMCMP) + # ifdef USE_AS_WMEMCMP +- shl $2, %rdx ++ shl $2, %RDX_LP ++# elif defined __ILP32__ ++ /* Clear the upper 32 bits. */ ++ mov %edx, %edx + # endif + pxor %xmm0, %xmm0 +- cmp $79, %rdx ++ cmp $79, %RDX_LP + ja L(79bytesormore) + # ifndef USE_AS_WMEMCMP +- cmp $1, %rdx ++ cmp $1, %RDX_LP + je L(firstbyte) + # endif + add %rdx, %rsi +diff --git a/sysdeps/x86_64/multiarch/memcmp-ssse3.S b/sysdeps/x86_64/multiarch/memcmp-ssse3.S +index 6f76c641..69d030fc 100644 +--- a/sysdeps/x86_64/multiarch/memcmp-ssse3.S ++++ b/sysdeps/x86_64/multiarch/memcmp-ssse3.S +@@ -33,9 +33,12 @@ + atom_text_section + ENTRY (MEMCMP) + # ifdef USE_AS_WMEMCMP +- shl $2, %rdx +- test %rdx, %rdx ++ shl $2, %RDX_LP ++ test %RDX_LP, %RDX_LP + jz L(equal) ++# elif defined __ILP32__ ++ /* Clear the upper 32 bits. */ ++ mov %edx, %edx + # endif + mov %rdx, %rcx + mov %rdi, %rdx +diff --git a/sysdeps/x86_64/x32/Makefile b/sysdeps/x86_64/x32/Makefile +index 7d528889..ddec7f04 100644 +--- a/sysdeps/x86_64/x32/Makefile ++++ b/sysdeps/x86_64/x32/Makefile +@@ -6,9 +6,9 @@ CFLAGS-s_llround.c += -fno-builtin-lround + endif + + ifeq ($(subdir),string) +-tests += tst-size_t-memchr ++tests += tst-size_t-memchr tst-size_t-memcmp + endif + + ifeq ($(subdir),wcsmbs) +-tests += tst-size_t-wmemchr ++tests += tst-size_t-wmemchr tst-size_t-wmemcmp + endif +diff --git a/sysdeps/x86_64/x32/tst-size_t-memcmp.c b/sysdeps/x86_64/x32/tst-size_t-memcmp.c +new file mode 100644 +index 00000000..9bd6fdb4 +--- /dev/null ++++ b/sysdeps/x86_64/x32/tst-size_t-memcmp.c +@@ -0,0 +1,76 @@ ++/* Test memcmp with size_t in the lower 32 bits of 64-bit register. ++ 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, see ++ . */ ++ ++#define TEST_MAIN ++#ifdef WIDE ++# define TEST_NAME "wmemcmp" ++#else ++# define TEST_NAME "memcmp" ++#endif ++ ++#include "test-size_t.h" ++ ++#ifdef WIDE ++# include ++# include ++ ++# define MEMCMP wmemcmp ++# define CHAR wchar_t ++#else ++# define MEMCMP memcmp ++# define CHAR char ++#endif ++ ++IMPL (MEMCMP, 1) ++ ++typedef int (*proto_t) (const CHAR *, const CHAR *, size_t); ++ ++static int ++__attribute__ ((noinline, noclone)) ++do_memcmp (parameter_t a, parameter_t b) ++{ ++ return CALL (&b, a.p, b.p, a.len); ++} ++ ++static int ++test_main (void) ++{ ++ test_init (); ++ ++ parameter_t dest = { { page_size / sizeof (CHAR) }, buf1 }; ++ parameter_t src = { { 0 }, buf2 }; ++ ++ memcpy (buf1, buf2, page_size); ++ ++ int ret = 0; ++ FOR_EACH_IMPL (impl, 0) ++ { ++ src.fn = impl->fn; ++ int res = do_memcmp (dest, src); ++ if (res) ++ { ++ error (0, 0, "Wrong result in function %s: %i != 0", ++ impl->name, res); ++ ret = 1; ++ } ++ } ++ ++ return ret ? EXIT_FAILURE : EXIT_SUCCESS; ++} ++ ++#include +diff --git a/sysdeps/x86_64/x32/tst-size_t-wmemcmp.c b/sysdeps/x86_64/x32/tst-size_t-wmemcmp.c +new file mode 100644 +index 00000000..e8b5ffd0 +--- /dev/null ++++ b/sysdeps/x86_64/x32/tst-size_t-wmemcmp.c +@@ -0,0 +1,20 @@ ++/* Test wmemcmp with size_t in the lower 32 bits of 64-bit register. ++ 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, see ++ . */ ++ ++#define WIDE 1 ++#include "tst-size_t-memcmp.c" +-- +GitLab + diff --git a/SOURCES/glibc-RHEL-15696-20.patch b/SOURCES/glibc-RHEL-15696-20.patch new file mode 100644 index 0000000..c63b3fb --- /dev/null +++ b/SOURCES/glibc-RHEL-15696-20.patch @@ -0,0 +1,164 @@ +From e4fda4631017e49d4ee5a2755db34289b6860fa4 Mon Sep 17 00:00:00 2001 +From: "H.J. Lu" +Date: Sun, 7 Mar 2021 09:45:23 -0800 +Subject: [PATCH] x86-64: Use ZMM16-ZMM31 in AVX512 memmove family functions +Content-type: text/plain; charset=UTF-8 + +Update ifunc-memmove.h to select the function optimized with AVX512 +instructions using ZMM16-ZMM31 registers to avoid RTM abort with usable +AVX512VL since VZEROUPPER isn't needed at function exit. +--- + sysdeps/x86_64/multiarch/ifunc-impl-list.c | 24 +++++++++--------- + sysdeps/x86_64/multiarch/ifunc-memmove.h | 12 +++++---- + .../multiarch/memmove-avx512-unaligned-erms.S | 25 +++++++++++++++++-- + 3 files changed, 42 insertions(+), 19 deletions(-) + +diff --git a/sysdeps/x86_64/multiarch/ifunc-impl-list.c b/sysdeps/x86_64/multiarch/ifunc-impl-list.c +index d969a156..fec384f6 100644 +--- a/sysdeps/x86_64/multiarch/ifunc-impl-list.c ++++ b/sysdeps/x86_64/multiarch/ifunc-impl-list.c +@@ -83,10 +83,10 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + CPU_FEATURE_USABLE (AVX512F), + __memmove_chk_avx512_no_vzeroupper) + IFUNC_IMPL_ADD (array, i, __memmove_chk, +- CPU_FEATURE_USABLE (AVX512F), ++ CPU_FEATURE_USABLE (AVX512VL), + __memmove_chk_avx512_unaligned) + IFUNC_IMPL_ADD (array, i, __memmove_chk, +- CPU_FEATURE_USABLE (AVX512F), ++ CPU_FEATURE_USABLE (AVX512VL), + __memmove_chk_avx512_unaligned_erms) + IFUNC_IMPL_ADD (array, i, __memmove_chk, + CPU_FEATURE_USABLE (AVX), +@@ -148,10 +148,10 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + CPU_FEATURE_USABLE (AVX512F), + __memmove_avx512_no_vzeroupper) + IFUNC_IMPL_ADD (array, i, memmove, +- CPU_FEATURE_USABLE (AVX512F), ++ CPU_FEATURE_USABLE (AVX512VL), + __memmove_avx512_unaligned) + IFUNC_IMPL_ADD (array, i, memmove, +- CPU_FEATURE_USABLE (AVX512F), ++ CPU_FEATURE_USABLE (AVX512VL), + __memmove_avx512_unaligned_erms) + IFUNC_IMPL_ADD (array, i, memmove, CPU_FEATURE_USABLE (SSSE3), + __memmove_ssse3_back) +@@ -733,10 +733,10 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + CPU_FEATURE_USABLE (AVX512F), + __memcpy_chk_avx512_no_vzeroupper) + IFUNC_IMPL_ADD (array, i, __memcpy_chk, +- CPU_FEATURE_USABLE (AVX512F), ++ CPU_FEATURE_USABLE (AVX512VL), + __memcpy_chk_avx512_unaligned) + IFUNC_IMPL_ADD (array, i, __memcpy_chk, +- CPU_FEATURE_USABLE (AVX512F), ++ CPU_FEATURE_USABLE (AVX512VL), + __memcpy_chk_avx512_unaligned_erms) + IFUNC_IMPL_ADD (array, i, __memcpy_chk, + CPU_FEATURE_USABLE (AVX), +@@ -802,10 +802,10 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + CPU_FEATURE_USABLE (AVX512F), + __memcpy_avx512_no_vzeroupper) + IFUNC_IMPL_ADD (array, i, memcpy, +- CPU_FEATURE_USABLE (AVX512F), ++ CPU_FEATURE_USABLE (AVX512VL), + __memcpy_avx512_unaligned) + IFUNC_IMPL_ADD (array, i, memcpy, +- CPU_FEATURE_USABLE (AVX512F), ++ CPU_FEATURE_USABLE (AVX512VL), + __memcpy_avx512_unaligned_erms) + IFUNC_IMPL_ADD (array, i, memcpy, 1, __memcpy_sse2_unaligned) + IFUNC_IMPL_ADD (array, i, memcpy, 1, +@@ -819,10 +819,10 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + CPU_FEATURE_USABLE (AVX512F), + __mempcpy_chk_avx512_no_vzeroupper) + IFUNC_IMPL_ADD (array, i, __mempcpy_chk, +- CPU_FEATURE_USABLE (AVX512F), ++ CPU_FEATURE_USABLE (AVX512VL), + __mempcpy_chk_avx512_unaligned) + IFUNC_IMPL_ADD (array, i, __mempcpy_chk, +- CPU_FEATURE_USABLE (AVX512F), ++ CPU_FEATURE_USABLE (AVX512VL), + __mempcpy_chk_avx512_unaligned_erms) + IFUNC_IMPL_ADD (array, i, __mempcpy_chk, + CPU_FEATURE_USABLE (AVX), +@@ -864,10 +864,10 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + CPU_FEATURE_USABLE (AVX512F), + __mempcpy_avx512_no_vzeroupper) + IFUNC_IMPL_ADD (array, i, mempcpy, +- CPU_FEATURE_USABLE (AVX512F), ++ CPU_FEATURE_USABLE (AVX512VL), + __mempcpy_avx512_unaligned) + IFUNC_IMPL_ADD (array, i, mempcpy, +- CPU_FEATURE_USABLE (AVX512F), ++ CPU_FEATURE_USABLE (AVX512VL), + __mempcpy_avx512_unaligned_erms) + IFUNC_IMPL_ADD (array, i, mempcpy, + CPU_FEATURE_USABLE (AVX), +diff --git a/sysdeps/x86_64/multiarch/ifunc-memmove.h b/sysdeps/x86_64/multiarch/ifunc-memmove.h +index fa09b9fb..014e95c7 100644 +--- a/sysdeps/x86_64/multiarch/ifunc-memmove.h ++++ b/sysdeps/x86_64/multiarch/ifunc-memmove.h +@@ -56,13 +56,15 @@ IFUNC_SELECTOR (void) + if (CPU_FEATURE_USABLE_P (cpu_features, AVX512F) + && !CPU_FEATURES_ARCH_P (cpu_features, Prefer_No_AVX512)) + { +- if (CPU_FEATURES_ARCH_P (cpu_features, Prefer_No_VZEROUPPER)) +- return OPTIMIZE (avx512_no_vzeroupper); ++ if (CPU_FEATURE_USABLE_P (cpu_features, AVX512VL)) ++ { ++ if (CPU_FEATURE_USABLE_P (cpu_features, ERMS)) ++ return OPTIMIZE (avx512_unaligned_erms); + +- if (CPU_FEATURE_USABLE_P (cpu_features, ERMS)) +- return OPTIMIZE (avx512_unaligned_erms); ++ return OPTIMIZE (avx512_unaligned); ++ } + +- return OPTIMIZE (avx512_unaligned); ++ return OPTIMIZE (avx512_no_vzeroupper); + } + + if (CPU_FEATURES_ARCH_P (cpu_features, AVX_Fast_Unaligned_Load)) +diff --git a/sysdeps/x86_64/multiarch/memmove-avx512-unaligned-erms.S b/sysdeps/x86_64/multiarch/memmove-avx512-unaligned-erms.S +index aac1515c..848848ab 100644 +--- a/sysdeps/x86_64/multiarch/memmove-avx512-unaligned-erms.S ++++ b/sysdeps/x86_64/multiarch/memmove-avx512-unaligned-erms.S +@@ -1,11 +1,32 @@ + #if IS_IN (libc) + # define VEC_SIZE 64 +-# define VEC(i) zmm##i ++# define XMM0 xmm16 ++# define XMM1 xmm17 ++# define YMM0 ymm16 ++# define YMM1 ymm17 ++# define VEC0 zmm16 ++# define VEC1 zmm17 ++# define VEC2 zmm18 ++# define VEC3 zmm19 ++# define VEC4 zmm20 ++# define VEC5 zmm21 ++# define VEC6 zmm22 ++# define VEC7 zmm23 ++# define VEC8 zmm24 ++# define VEC9 zmm25 ++# define VEC10 zmm26 ++# define VEC11 zmm27 ++# define VEC12 zmm28 ++# define VEC13 zmm29 ++# define VEC14 zmm30 ++# define VEC15 zmm31 ++# define VEC(i) VEC##i + # define VMOVNT vmovntdq + # define VMOVU vmovdqu64 + # define VMOVA vmovdqa64 ++# define VZEROUPPER + +-# define SECTION(p) p##.avx512 ++# define SECTION(p) p##.evex512 + # define MEMMOVE_SYMBOL(p,s) p##_avx512_##s + + # include "memmove-vec-unaligned-erms.S" +-- +GitLab + diff --git a/SOURCES/glibc-RHEL-15696-21.patch b/SOURCES/glibc-RHEL-15696-21.patch new file mode 100644 index 0000000..319c08d --- /dev/null +++ b/SOURCES/glibc-RHEL-15696-21.patch @@ -0,0 +1,71 @@ +From 595c22ecd8e87a27fd19270ed30fdbae9ad25426 Mon Sep 17 00:00:00 2001 +From: Sunil K Pandey +Date: Thu, 1 Apr 2021 15:47:04 -0700 +Subject: [PATCH] x86-64: Fix ifdef indentation in strlen-evex.S +Content-type: text/plain; charset=UTF-8 + +Fix some indentations of ifdef in file strlen-evex.S which are off by 1 +and confusing to read. +--- + sysdeps/x86_64/multiarch/strlen-evex.S | 16 ++++++++-------- + 1 file changed, 8 insertions(+), 8 deletions(-) + +diff --git a/sysdeps/x86_64/multiarch/strlen-evex.S b/sysdeps/x86_64/multiarch/strlen-evex.S +index cd022509..05838190 100644 +--- a/sysdeps/x86_64/multiarch/strlen-evex.S ++++ b/sysdeps/x86_64/multiarch/strlen-evex.S +@@ -276,10 +276,10 @@ L(last_2x_vec): + .p2align 4 + L(first_vec_x0_check): + tzcntl %eax, %eax +-# ifdef USE_AS_WCSLEN ++# ifdef USE_AS_WCSLEN + /* NB: Multiply wchar_t count by 4 to get the number of bytes. */ + sall $2, %eax +-# endif ++# endif + /* Check the end of data. */ + cmpq %rax, %rsi + jbe L(max) +@@ -293,10 +293,10 @@ L(first_vec_x0_check): + .p2align 4 + L(first_vec_x1_check): + tzcntl %eax, %eax +-# ifdef USE_AS_WCSLEN ++# ifdef USE_AS_WCSLEN + /* NB: Multiply wchar_t count by 4 to get the number of bytes. */ + sall $2, %eax +-# endif ++# endif + /* Check the end of data. */ + cmpq %rax, %rsi + jbe L(max) +@@ -311,10 +311,10 @@ L(first_vec_x1_check): + .p2align 4 + L(first_vec_x2_check): + tzcntl %eax, %eax +-# ifdef USE_AS_WCSLEN ++# ifdef USE_AS_WCSLEN + /* NB: Multiply wchar_t count by 4 to get the number of bytes. */ + sall $2, %eax +-# endif ++# endif + /* Check the end of data. */ + cmpq %rax, %rsi + jbe L(max) +@@ -329,10 +329,10 @@ L(first_vec_x2_check): + .p2align 4 + L(first_vec_x3_check): + tzcntl %eax, %eax +-# ifdef USE_AS_WCSLEN ++# ifdef USE_AS_WCSLEN + /* NB: Multiply wchar_t count by 4 to get the number of bytes. */ + sall $2, %eax +-# endif ++# endif + /* Check the end of data. */ + cmpq %rax, %rsi + jbe L(max) +-- +GitLab + diff --git a/SOURCES/glibc-RHEL-15696-22.patch b/SOURCES/glibc-RHEL-15696-22.patch new file mode 100644 index 0000000..c20557b --- /dev/null +++ b/SOURCES/glibc-RHEL-15696-22.patch @@ -0,0 +1,51 @@ +From 55bf411b451c13f0fb7ff3d3bf9a820020b45df1 Mon Sep 17 00:00:00 2001 +From: "H.J. Lu" +Date: Mon, 19 Apr 2021 07:07:21 -0700 +Subject: [PATCH] x86-64: Require BMI2 for __strlen_evex and __strnlen_evex +Content-type: text/plain; charset=UTF-8 + +Since __strlen_evex and __strnlen_evex added by + +commit 1fd8c163a83d96ace1ff78fa6bac7aee084f6f77 +Author: H.J. Lu +Date: Fri Mar 5 06:24:52 2021 -0800 + + x86-64: Add ifunc-avx2.h functions with 256-bit EVEX + +use sarx: + +c4 e2 6a f7 c0 sarx %edx,%eax,%eax + +require BMI2 for __strlen_evex and __strnlen_evex in ifunc-impl-list.c. +ifunc-avx2.h already requires BMI2 for EVEX implementation. +--- + sysdeps/x86_64/multiarch/ifunc-impl-list.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/sysdeps/x86_64/multiarch/ifunc-impl-list.c b/sysdeps/x86_64/multiarch/ifunc-impl-list.c +index fec384f6..cbfc1a5d 100644 +--- a/sysdeps/x86_64/multiarch/ifunc-impl-list.c ++++ b/sysdeps/x86_64/multiarch/ifunc-impl-list.c +@@ -293,7 +293,8 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + __strlen_avx2_rtm) + IFUNC_IMPL_ADD (array, i, strlen, + (CPU_FEATURE_USABLE (AVX512VL) +- && CPU_FEATURE_USABLE (AVX512BW)), ++ && CPU_FEATURE_USABLE (AVX512BW) ++ && CPU_FEATURE_USABLE (BMI2)), + __strlen_evex) + IFUNC_IMPL_ADD (array, i, strlen, 1, __strlen_sse2)) + +@@ -308,7 +309,8 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + __strnlen_avx2_rtm) + IFUNC_IMPL_ADD (array, i, strnlen, + (CPU_FEATURE_USABLE (AVX512VL) +- && CPU_FEATURE_USABLE (AVX512BW)), ++ && CPU_FEATURE_USABLE (AVX512BW) ++ && CPU_FEATURE_USABLE (BMI2)), + __strnlen_evex) + IFUNC_IMPL_ADD (array, i, strnlen, 1, __strnlen_sse2)) + +-- +GitLab + diff --git a/SOURCES/glibc-RHEL-15696-23.patch b/SOURCES/glibc-RHEL-15696-23.patch new file mode 100644 index 0000000..ffde3d7 --- /dev/null +++ b/SOURCES/glibc-RHEL-15696-23.patch @@ -0,0 +1,584 @@ +From acfd088a1963ba51cd83c78f95c0ab25ead79e04 Mon Sep 17 00:00:00 2001 +From: Noah Goldstein +Date: Mon, 3 May 2021 03:01:58 -0400 +Subject: [PATCH] x86: Optimize memchr-avx2.S +Content-type: text/plain; charset=UTF-8 + +No bug. This commit optimizes memchr-avx2.S. The optimizations include +replacing some branches with cmovcc, avoiding some branches entirely +in the less_4x_vec case, making the page cross logic less strict, +asaving a few instructions the in loop return loop. test-memchr, +test-rawmemchr, and test-wmemchr are all passing. + +Signed-off-by: Noah Goldstein +Reviewed-by: H.J. Lu +--- + sysdeps/x86_64/multiarch/memchr-avx2.S | 425 ++++++++++++++----------- + 1 file changed, 247 insertions(+), 178 deletions(-) + +diff --git a/sysdeps/x86_64/multiarch/memchr-avx2.S b/sysdeps/x86_64/multiarch/memchr-avx2.S +index cf893e77..b377f22e 100644 +--- a/sysdeps/x86_64/multiarch/memchr-avx2.S ++++ b/sysdeps/x86_64/multiarch/memchr-avx2.S +@@ -26,8 +26,22 @@ + + # ifdef USE_AS_WMEMCHR + # define VPCMPEQ vpcmpeqd ++# define VPBROADCAST vpbroadcastd ++# define CHAR_SIZE 4 + # else + # define VPCMPEQ vpcmpeqb ++# define VPBROADCAST vpbroadcastb ++# define CHAR_SIZE 1 ++# endif ++ ++# ifdef USE_AS_RAWMEMCHR ++# define ERAW_PTR_REG ecx ++# define RRAW_PTR_REG rcx ++# define ALGN_PTR_REG rdi ++# else ++# define ERAW_PTR_REG edi ++# define RRAW_PTR_REG rdi ++# define ALGN_PTR_REG rcx + # endif + + # ifndef VZEROUPPER +@@ -39,6 +53,7 @@ + # endif + + # define VEC_SIZE 32 ++# define PAGE_SIZE 4096 + + .section SECTION(.text),"ax",@progbits + ENTRY (MEMCHR) +@@ -47,295 +62,349 @@ ENTRY (MEMCHR) + test %RDX_LP, %RDX_LP + jz L(null) + # endif +- movl %edi, %ecx +- /* Broadcast CHAR to YMM0. */ +- vmovd %esi, %xmm0 + # ifdef USE_AS_WMEMCHR + shl $2, %RDX_LP +- vpbroadcastd %xmm0, %ymm0 + # else + # ifdef __ILP32__ + /* Clear the upper 32 bits. */ + movl %edx, %edx + # endif +- vpbroadcastb %xmm0, %ymm0 + # endif ++ /* Broadcast CHAR to YMMMATCH. */ ++ vmovd %esi, %xmm0 ++ VPBROADCAST %xmm0, %ymm0 + /* Check if we may cross page boundary with one vector load. */ +- andl $(2 * VEC_SIZE - 1), %ecx +- cmpl $VEC_SIZE, %ecx +- ja L(cros_page_boundary) ++ movl %edi, %eax ++ andl $(PAGE_SIZE - 1), %eax ++ cmpl $(PAGE_SIZE - VEC_SIZE), %eax ++ ja L(cross_page_boundary) + + /* Check the first VEC_SIZE bytes. */ +- VPCMPEQ (%rdi), %ymm0, %ymm1 ++ VPCMPEQ (%rdi), %ymm0, %ymm1 + vpmovmskb %ymm1, %eax +- testl %eax, %eax +- + # ifndef USE_AS_RAWMEMCHR +- jnz L(first_vec_x0_check) +- /* Adjust length and check the end of data. */ +- subq $VEC_SIZE, %rdx +- jbe L(zero) +-# else +- jnz L(first_vec_x0) ++ /* If length < CHAR_PER_VEC handle special. */ ++ cmpq $VEC_SIZE, %rdx ++ jbe L(first_vec_x0) + # endif +- +- /* Align data for aligned loads in the loop. */ +- addq $VEC_SIZE, %rdi +- andl $(VEC_SIZE - 1), %ecx +- andq $-VEC_SIZE, %rdi ++ testl %eax, %eax ++ jz L(aligned_more) ++ tzcntl %eax, %eax ++ addq %rdi, %rax ++ VZEROUPPER_RETURN + + # ifndef USE_AS_RAWMEMCHR +- /* Adjust length. */ +- addq %rcx, %rdx ++ .p2align 5 ++L(first_vec_x0): ++ /* Check if first match was before length. */ ++ tzcntl %eax, %eax ++ xorl %ecx, %ecx ++ cmpl %eax, %edx ++ leaq (%rdi, %rax), %rax ++ cmovle %rcx, %rax ++ VZEROUPPER_RETURN + +- subq $(VEC_SIZE * 4), %rdx +- jbe L(last_4x_vec_or_less) ++L(null): ++ xorl %eax, %eax ++ ret + # endif +- jmp L(more_4x_vec) +- + .p2align 4 +-L(cros_page_boundary): +- andl $(VEC_SIZE - 1), %ecx +- andq $-VEC_SIZE, %rdi +- VPCMPEQ (%rdi), %ymm0, %ymm1 ++L(cross_page_boundary): ++ /* Save pointer before aligning as its original value is necessary ++ for computer return address if byte is found or adjusting length ++ if it is not and this is memchr. */ ++ movq %rdi, %rcx ++ /* Align data to VEC_SIZE - 1. ALGN_PTR_REG is rcx for memchr and ++ rdi for rawmemchr. */ ++ orq $(VEC_SIZE - 1), %ALGN_PTR_REG ++ VPCMPEQ -(VEC_SIZE - 1)(%ALGN_PTR_REG), %ymm0, %ymm1 + vpmovmskb %ymm1, %eax ++# ifndef USE_AS_RAWMEMCHR ++ /* Calculate length until end of page (length checked for a ++ match). */ ++ leaq 1(%ALGN_PTR_REG), %rsi ++ subq %RRAW_PTR_REG, %rsi ++# endif + /* Remove the leading bytes. */ +- sarl %cl, %eax +- testl %eax, %eax +- jz L(aligned_more) +- tzcntl %eax, %eax ++ sarxl %ERAW_PTR_REG, %eax, %eax + # ifndef USE_AS_RAWMEMCHR + /* Check the end of data. */ +- cmpq %rax, %rdx +- jbe L(zero) ++ cmpq %rsi, %rdx ++ jbe L(first_vec_x0) + # endif +- addq %rdi, %rax +- addq %rcx, %rax ++ testl %eax, %eax ++ jz L(cross_page_continue) ++ tzcntl %eax, %eax ++ addq %RRAW_PTR_REG, %rax + L(return_vzeroupper): + ZERO_UPPER_VEC_REGISTERS_RETURN + + .p2align 4 +-L(aligned_more): +-# ifndef USE_AS_RAWMEMCHR +- /* Calculate "rdx + rcx - VEC_SIZE" with "rdx - (VEC_SIZE - rcx)" +- instead of "(rdx + rcx) - VEC_SIZE" to void possible addition +- overflow. */ +- negq %rcx +- addq $VEC_SIZE, %rcx ++L(first_vec_x1): ++ tzcntl %eax, %eax ++ incq %rdi ++ addq %rdi, %rax ++ VZEROUPPER_RETURN + +- /* Check the end of data. */ +- subq %rcx, %rdx +- jbe L(zero) +-# endif ++ .p2align 4 ++L(first_vec_x2): ++ tzcntl %eax, %eax ++ addq $(VEC_SIZE + 1), %rdi ++ addq %rdi, %rax ++ VZEROUPPER_RETURN ++ ++ .p2align 4 ++L(first_vec_x3): ++ tzcntl %eax, %eax ++ addq $(VEC_SIZE * 2 + 1), %rdi ++ addq %rdi, %rax ++ VZEROUPPER_RETURN + +- addq $VEC_SIZE, %rdi + +-# ifndef USE_AS_RAWMEMCHR +- subq $(VEC_SIZE * 4), %rdx +- jbe L(last_4x_vec_or_less) +-# endif ++ .p2align 4 ++L(first_vec_x4): ++ tzcntl %eax, %eax ++ addq $(VEC_SIZE * 3 + 1), %rdi ++ addq %rdi, %rax ++ VZEROUPPER_RETURN + +-L(more_4x_vec): ++ .p2align 4 ++L(aligned_more): + /* Check the first 4 * VEC_SIZE. Only one VEC_SIZE at a time + since data is only aligned to VEC_SIZE. */ +- VPCMPEQ (%rdi), %ymm0, %ymm1 +- vpmovmskb %ymm1, %eax +- testl %eax, %eax +- jnz L(first_vec_x0) + +- VPCMPEQ VEC_SIZE(%rdi), %ymm0, %ymm1 ++# ifndef USE_AS_RAWMEMCHR ++L(cross_page_continue): ++ /* Align data to VEC_SIZE - 1. */ ++ xorl %ecx, %ecx ++ subl %edi, %ecx ++ orq $(VEC_SIZE - 1), %rdi ++ /* esi is for adjusting length to see if near the end. */ ++ leal (VEC_SIZE * 4 + 1)(%rdi, %rcx), %esi ++# else ++ orq $(VEC_SIZE - 1), %rdi ++L(cross_page_continue): ++# endif ++ /* Load first VEC regardless. */ ++ VPCMPEQ 1(%rdi), %ymm0, %ymm1 + vpmovmskb %ymm1, %eax ++# ifndef USE_AS_RAWMEMCHR ++ /* Adjust length. If near end handle specially. */ ++ subq %rsi, %rdx ++ jbe L(last_4x_vec_or_less) ++# endif + testl %eax, %eax + jnz L(first_vec_x1) + +- VPCMPEQ (VEC_SIZE * 2)(%rdi), %ymm0, %ymm1 ++ VPCMPEQ (VEC_SIZE + 1)(%rdi), %ymm0, %ymm1 + vpmovmskb %ymm1, %eax + testl %eax, %eax + jnz L(first_vec_x2) + +- VPCMPEQ (VEC_SIZE * 3)(%rdi), %ymm0, %ymm1 ++ VPCMPEQ (VEC_SIZE * 2 + 1)(%rdi), %ymm0, %ymm1 + vpmovmskb %ymm1, %eax + testl %eax, %eax + jnz L(first_vec_x3) + +- addq $(VEC_SIZE * 4), %rdi ++ VPCMPEQ (VEC_SIZE * 3 + 1)(%rdi), %ymm0, %ymm1 ++ vpmovmskb %ymm1, %eax ++ testl %eax, %eax ++ jnz L(first_vec_x4) + + # ifndef USE_AS_RAWMEMCHR ++ /* Check if at last VEC_SIZE * 4 length. */ + subq $(VEC_SIZE * 4), %rdx +- jbe L(last_4x_vec_or_less) +-# endif +- +- /* Align data to 4 * VEC_SIZE. */ +- movq %rdi, %rcx +- andl $(4 * VEC_SIZE - 1), %ecx +- andq $-(4 * VEC_SIZE), %rdi +- +-# ifndef USE_AS_RAWMEMCHR +- /* Adjust length. */ ++ jbe L(last_4x_vec_or_less_cmpeq) ++ /* Align data to VEC_SIZE * 4 - 1 for the loop and readjust ++ length. */ ++ incq %rdi ++ movl %edi, %ecx ++ orq $(VEC_SIZE * 4 - 1), %rdi ++ andl $(VEC_SIZE * 4 - 1), %ecx + addq %rcx, %rdx ++# else ++ /* Align data to VEC_SIZE * 4 - 1 for loop. */ ++ incq %rdi ++ orq $(VEC_SIZE * 4 - 1), %rdi + # endif + ++ /* Compare 4 * VEC at a time forward. */ + .p2align 4 + L(loop_4x_vec): +- /* Compare 4 * VEC at a time forward. */ +- VPCMPEQ (%rdi), %ymm0, %ymm1 +- VPCMPEQ VEC_SIZE(%rdi), %ymm0, %ymm2 +- VPCMPEQ (VEC_SIZE * 2)(%rdi), %ymm0, %ymm3 +- VPCMPEQ (VEC_SIZE * 3)(%rdi), %ymm0, %ymm4 +- ++ VPCMPEQ 1(%rdi), %ymm0, %ymm1 ++ VPCMPEQ (VEC_SIZE + 1)(%rdi), %ymm0, %ymm2 ++ VPCMPEQ (VEC_SIZE * 2 + 1)(%rdi), %ymm0, %ymm3 ++ VPCMPEQ (VEC_SIZE * 3 + 1)(%rdi), %ymm0, %ymm4 + vpor %ymm1, %ymm2, %ymm5 + vpor %ymm3, %ymm4, %ymm6 + vpor %ymm5, %ymm6, %ymm5 + +- vpmovmskb %ymm5, %eax +- testl %eax, %eax +- jnz L(4x_vec_end) +- +- addq $(VEC_SIZE * 4), %rdi +- ++ vpmovmskb %ymm5, %ecx + # ifdef USE_AS_RAWMEMCHR +- jmp L(loop_4x_vec) ++ subq $-(VEC_SIZE * 4), %rdi ++ testl %ecx, %ecx ++ jz L(loop_4x_vec) + # else +- subq $(VEC_SIZE * 4), %rdx +- ja L(loop_4x_vec) ++ testl %ecx, %ecx ++ jnz L(loop_4x_vec_end) + +-L(last_4x_vec_or_less): +- /* Less than 4 * VEC and aligned to VEC_SIZE. */ +- addl $(VEC_SIZE * 2), %edx +- jle L(last_2x_vec) ++ subq $-(VEC_SIZE * 4), %rdi + +- VPCMPEQ (%rdi), %ymm0, %ymm1 +- vpmovmskb %ymm1, %eax +- testl %eax, %eax +- jnz L(first_vec_x0) ++ subq $(VEC_SIZE * 4), %rdx ++ ja L(loop_4x_vec) + +- VPCMPEQ VEC_SIZE(%rdi), %ymm0, %ymm1 ++ /* Fall through into less than 4 remaining vectors of length case. ++ */ ++ VPCMPEQ (VEC_SIZE * 0 + 1)(%rdi), %ymm0, %ymm1 + vpmovmskb %ymm1, %eax ++ .p2align 4 ++L(last_4x_vec_or_less): ++ /* Check if first VEC contained match. */ + testl %eax, %eax +- jnz L(first_vec_x1) ++ jnz L(first_vec_x1_check) + +- VPCMPEQ (VEC_SIZE * 2)(%rdi), %ymm0, %ymm1 +- vpmovmskb %ymm1, %eax +- testl %eax, %eax ++ /* If remaining length > VEC_SIZE * 2. */ ++ addl $(VEC_SIZE * 2), %edx ++ jg L(last_4x_vec) + +- jnz L(first_vec_x2_check) +- subl $VEC_SIZE, %edx +- jle L(zero) ++L(last_2x_vec): ++ /* If remaining length < VEC_SIZE. */ ++ addl $VEC_SIZE, %edx ++ jle L(zero_end) + +- VPCMPEQ (VEC_SIZE * 3)(%rdi), %ymm0, %ymm1 ++ /* Check VEC2 and compare any match with remaining length. */ ++ VPCMPEQ (VEC_SIZE + 1)(%rdi), %ymm0, %ymm1 + vpmovmskb %ymm1, %eax +- testl %eax, %eax +- +- jnz L(first_vec_x3_check) +- xorl %eax, %eax ++ tzcntl %eax, %eax ++ cmpl %eax, %edx ++ jbe L(set_zero_end) ++ addq $(VEC_SIZE + 1), %rdi ++ addq %rdi, %rax ++L(zero_end): + VZEROUPPER_RETURN + + .p2align 4 +-L(last_2x_vec): +- addl $(VEC_SIZE * 2), %edx +- VPCMPEQ (%rdi), %ymm0, %ymm1 ++L(loop_4x_vec_end): ++# endif ++ /* rawmemchr will fall through into this if match was found in ++ loop. */ ++ + vpmovmskb %ymm1, %eax + testl %eax, %eax ++ jnz L(last_vec_x1_return) + +- jnz L(first_vec_x0_check) +- subl $VEC_SIZE, %edx +- jle L(zero) +- +- VPCMPEQ VEC_SIZE(%rdi), %ymm0, %ymm1 +- vpmovmskb %ymm1, %eax ++ vpmovmskb %ymm2, %eax + testl %eax, %eax +- jnz L(first_vec_x1_check) +- xorl %eax, %eax +- VZEROUPPER_RETURN ++ jnz L(last_vec_x2_return) + +- .p2align 4 +-L(first_vec_x0_check): +- tzcntl %eax, %eax +- /* Check the end of data. */ +- cmpq %rax, %rdx +- jbe L(zero) ++ vpmovmskb %ymm3, %eax ++ /* Combine VEC3 matches (eax) with VEC4 matches (ecx). */ ++ salq $32, %rcx ++ orq %rcx, %rax ++ tzcntq %rax, %rax ++# ifdef USE_AS_RAWMEMCHR ++ subq $(VEC_SIZE * 2 - 1), %rdi ++# else ++ subq $-(VEC_SIZE * 2 + 1), %rdi ++# endif + addq %rdi, %rax + VZEROUPPER_RETURN ++# ifndef USE_AS_RAWMEMCHR + + .p2align 4 + L(first_vec_x1_check): + tzcntl %eax, %eax +- /* Check the end of data. */ +- cmpq %rax, %rdx +- jbe L(zero) +- addq $VEC_SIZE, %rax ++ /* Adjust length. */ ++ subl $-(VEC_SIZE * 4), %edx ++ /* Check if match within remaining length. */ ++ cmpl %eax, %edx ++ jbe L(set_zero_end) ++ incq %rdi + addq %rdi, %rax + VZEROUPPER_RETURN ++ .p2align 4 ++L(set_zero_end): ++ xorl %eax, %eax ++ VZEROUPPER_RETURN ++# endif + + .p2align 4 +-L(first_vec_x2_check): ++L(last_vec_x1_return): + tzcntl %eax, %eax +- /* Check the end of data. */ +- cmpq %rax, %rdx +- jbe L(zero) +- addq $(VEC_SIZE * 2), %rax ++# ifdef USE_AS_RAWMEMCHR ++ subq $(VEC_SIZE * 4 - 1), %rdi ++# else ++ incq %rdi ++# endif + addq %rdi, %rax + VZEROUPPER_RETURN + + .p2align 4 +-L(first_vec_x3_check): ++L(last_vec_x2_return): + tzcntl %eax, %eax +- /* Check the end of data. */ +- cmpq %rax, %rdx +- jbe L(zero) +- addq $(VEC_SIZE * 3), %rax ++# ifdef USE_AS_RAWMEMCHR ++ subq $(VEC_SIZE * 3 - 1), %rdi ++# else ++ subq $-(VEC_SIZE + 1), %rdi ++# endif + addq %rdi, %rax + VZEROUPPER_RETURN + ++# ifndef USE_AS_RAWMEMCHR + .p2align 4 +-L(zero): +- xorl %eax, %eax +- jmp L(return_vzeroupper) ++L(last_4x_vec_or_less_cmpeq): ++ VPCMPEQ (VEC_SIZE * 4 + 1)(%rdi), %ymm0, %ymm1 ++ vpmovmskb %ymm1, %eax ++ subq $-(VEC_SIZE * 4), %rdi ++ /* Check first VEC regardless. */ ++ testl %eax, %eax ++ jnz L(first_vec_x1_check) + ++ /* If remaining length <= CHAR_PER_VEC * 2. */ ++ addl $(VEC_SIZE * 2), %edx ++ jle L(last_2x_vec) + .p2align 4 +-L(null): +- xorl %eax, %eax +- ret +-# endif ++L(last_4x_vec): ++ VPCMPEQ (VEC_SIZE + 1)(%rdi), %ymm0, %ymm1 ++ vpmovmskb %ymm1, %eax ++ testl %eax, %eax ++ jnz L(last_vec_x2_return) + +- .p2align 4 +-L(first_vec_x0): +- tzcntl %eax, %eax +- addq %rdi, %rax +- VZEROUPPER_RETURN ++ VPCMPEQ (VEC_SIZE * 2 + 1)(%rdi), %ymm0, %ymm1 ++ vpmovmskb %ymm1, %eax + +- .p2align 4 +-L(first_vec_x1): +- tzcntl %eax, %eax +- addq $VEC_SIZE, %rax +- addq %rdi, %rax +- VZEROUPPER_RETURN ++ /* Create mask for possible matches within remaining length. */ ++ movq $-1, %rcx ++ bzhiq %rdx, %rcx, %rcx + +- .p2align 4 +-L(first_vec_x2): ++ /* Test matches in data against length match. */ ++ andl %ecx, %eax ++ jnz L(last_vec_x3) ++ ++ /* if remaining length <= VEC_SIZE * 3 (Note this is after ++ remaining length was found to be > VEC_SIZE * 2. */ ++ subl $VEC_SIZE, %edx ++ jbe L(zero_end2) ++ ++ VPCMPEQ (VEC_SIZE * 3 + 1)(%rdi), %ymm0, %ymm1 ++ vpmovmskb %ymm1, %eax ++ /* Shift remaining length mask for last VEC. */ ++ shrq $32, %rcx ++ andl %ecx, %eax ++ jz L(zero_end2) + tzcntl %eax, %eax +- addq $(VEC_SIZE * 2), %rax ++ addq $(VEC_SIZE * 3 + 1), %rdi + addq %rdi, %rax ++L(zero_end2): + VZEROUPPER_RETURN + + .p2align 4 +-L(4x_vec_end): +- vpmovmskb %ymm1, %eax +- testl %eax, %eax +- jnz L(first_vec_x0) +- vpmovmskb %ymm2, %eax +- testl %eax, %eax +- jnz L(first_vec_x1) +- vpmovmskb %ymm3, %eax +- testl %eax, %eax +- jnz L(first_vec_x2) +- vpmovmskb %ymm4, %eax +- testl %eax, %eax +-L(first_vec_x3): ++L(last_vec_x3): + tzcntl %eax, %eax +- addq $(VEC_SIZE * 3), %rax ++ subq $-(VEC_SIZE * 2 + 1), %rdi + addq %rdi, %rax + VZEROUPPER_RETURN ++# endif + + END (MEMCHR) + #endif +-- +GitLab + diff --git a/SOURCES/glibc-RHEL-15696-24.patch b/SOURCES/glibc-RHEL-15696-24.patch new file mode 100644 index 0000000..c4f24ff --- /dev/null +++ b/SOURCES/glibc-RHEL-15696-24.patch @@ -0,0 +1,388 @@ +From 645a158978f9520e74074e8c14047503be4db0f0 Mon Sep 17 00:00:00 2001 +From: Noah Goldstein +Date: Wed, 9 Jun 2021 16:25:32 -0400 +Subject: [PATCH] x86: Fix overflow bug with wmemchr-sse2 and wmemchr-avx2 [BZ + #27974] +Content-type: text/plain; charset=UTF-8 + +This commit fixes the bug mentioned in the previous commit. + +The previous implementations of wmemchr in these files relied +on n * sizeof(wchar_t) which was not guranteed by the standard. + +The new overflow tests added in the previous commit now +pass (As well as all the other tests). + +Signed-off-by: Noah Goldstein +Reviewed-by: H.J. Lu +--- + sysdeps/x86_64/memchr.S | 77 +++++++++++++++++++------- + sysdeps/x86_64/multiarch/memchr-avx2.S | 58 +++++++++++++------ + 2 files changed, 98 insertions(+), 37 deletions(-) + +diff --git a/sysdeps/x86_64/memchr.S b/sysdeps/x86_64/memchr.S +index cb320257..24f9a0c5 100644 +--- a/sysdeps/x86_64/memchr.S ++++ b/sysdeps/x86_64/memchr.S +@@ -21,9 +21,11 @@ + #ifdef USE_AS_WMEMCHR + # define MEMCHR wmemchr + # define PCMPEQ pcmpeqd ++# define CHAR_PER_VEC 4 + #else + # define MEMCHR memchr + # define PCMPEQ pcmpeqb ++# define CHAR_PER_VEC 16 + #endif + + /* fast SSE2 version with using pmaxub and 64 byte loop */ +@@ -33,15 +35,14 @@ ENTRY(MEMCHR) + movd %esi, %xmm1 + mov %edi, %ecx + ++#ifdef __ILP32__ ++ /* Clear the upper 32 bits. */ ++ movl %edx, %edx ++#endif + #ifdef USE_AS_WMEMCHR + test %RDX_LP, %RDX_LP + jz L(return_null) +- shl $2, %RDX_LP + #else +-# ifdef __ILP32__ +- /* Clear the upper 32 bits. */ +- movl %edx, %edx +-# endif + punpcklbw %xmm1, %xmm1 + test %RDX_LP, %RDX_LP + jz L(return_null) +@@ -60,13 +61,16 @@ ENTRY(MEMCHR) + test %eax, %eax + + jnz L(matches_1) +- sub $16, %rdx ++ sub $CHAR_PER_VEC, %rdx + jbe L(return_null) + add $16, %rdi + and $15, %ecx + and $-16, %rdi ++#ifdef USE_AS_WMEMCHR ++ shr $2, %ecx ++#endif + add %rcx, %rdx +- sub $64, %rdx ++ sub $(CHAR_PER_VEC * 4), %rdx + jbe L(exit_loop) + jmp L(loop_prolog) + +@@ -77,16 +81,21 @@ L(crosscache): + movdqa (%rdi), %xmm0 + + PCMPEQ %xmm1, %xmm0 +-/* Check if there is a match. */ ++ /* Check if there is a match. */ + pmovmskb %xmm0, %eax +-/* Remove the leading bytes. */ ++ /* Remove the leading bytes. */ + sar %cl, %eax + test %eax, %eax + je L(unaligned_no_match) +-/* Check which byte is a match. */ ++ /* Check which byte is a match. */ + bsf %eax, %eax +- ++#ifdef USE_AS_WMEMCHR ++ mov %eax, %esi ++ shr $2, %esi ++ sub %rsi, %rdx ++#else + sub %rax, %rdx ++#endif + jbe L(return_null) + add %rdi, %rax + add %rcx, %rax +@@ -94,15 +103,18 @@ L(crosscache): + + .p2align 4 + L(unaligned_no_match): +- /* "rcx" is less than 16. Calculate "rdx + rcx - 16" by using ++ /* "rcx" is less than 16. Calculate "rdx + rcx - 16" by using + "rdx - (16 - rcx)" instead of "(rdx + rcx) - 16" to void + possible addition overflow. */ + neg %rcx + add $16, %rcx ++#ifdef USE_AS_WMEMCHR ++ shr $2, %ecx ++#endif + sub %rcx, %rdx + jbe L(return_null) + add $16, %rdi +- sub $64, %rdx ++ sub $(CHAR_PER_VEC * 4), %rdx + jbe L(exit_loop) + + .p2align 4 +@@ -135,7 +147,7 @@ L(loop_prolog): + test $0x3f, %rdi + jz L(align64_loop) + +- sub $64, %rdx ++ sub $(CHAR_PER_VEC * 4), %rdx + jbe L(exit_loop) + + movdqa (%rdi), %xmm0 +@@ -167,11 +179,14 @@ L(loop_prolog): + mov %rdi, %rcx + and $-64, %rdi + and $63, %ecx ++#ifdef USE_AS_WMEMCHR ++ shr $2, %ecx ++#endif + add %rcx, %rdx + + .p2align 4 + L(align64_loop): +- sub $64, %rdx ++ sub $(CHAR_PER_VEC * 4), %rdx + jbe L(exit_loop) + movdqa (%rdi), %xmm0 + movdqa 16(%rdi), %xmm2 +@@ -218,7 +233,7 @@ L(align64_loop): + + .p2align 4 + L(exit_loop): +- add $32, %edx ++ add $(CHAR_PER_VEC * 2), %edx + jle L(exit_loop_32) + + movdqa (%rdi), %xmm0 +@@ -238,7 +253,7 @@ L(exit_loop): + pmovmskb %xmm3, %eax + test %eax, %eax + jnz L(matches32_1) +- sub $16, %edx ++ sub $CHAR_PER_VEC, %edx + jle L(return_null) + + PCMPEQ 48(%rdi), %xmm1 +@@ -250,13 +265,13 @@ L(exit_loop): + + .p2align 4 + L(exit_loop_32): +- add $32, %edx ++ add $(CHAR_PER_VEC * 2), %edx + movdqa (%rdi), %xmm0 + PCMPEQ %xmm1, %xmm0 + pmovmskb %xmm0, %eax + test %eax, %eax + jnz L(matches_1) +- sub $16, %edx ++ sub $CHAR_PER_VEC, %edx + jbe L(return_null) + + PCMPEQ 16(%rdi), %xmm1 +@@ -293,7 +308,13 @@ L(matches32): + .p2align 4 + L(matches_1): + bsf %eax, %eax ++#ifdef USE_AS_WMEMCHR ++ mov %eax, %esi ++ shr $2, %esi ++ sub %rsi, %rdx ++#else + sub %rax, %rdx ++#endif + jbe L(return_null) + add %rdi, %rax + ret +@@ -301,7 +322,13 @@ L(matches_1): + .p2align 4 + L(matches16_1): + bsf %eax, %eax ++#ifdef USE_AS_WMEMCHR ++ mov %eax, %esi ++ shr $2, %esi ++ sub %rsi, %rdx ++#else + sub %rax, %rdx ++#endif + jbe L(return_null) + lea 16(%rdi, %rax), %rax + ret +@@ -309,7 +336,13 @@ L(matches16_1): + .p2align 4 + L(matches32_1): + bsf %eax, %eax ++#ifdef USE_AS_WMEMCHR ++ mov %eax, %esi ++ shr $2, %esi ++ sub %rsi, %rdx ++#else + sub %rax, %rdx ++#endif + jbe L(return_null) + lea 32(%rdi, %rax), %rax + ret +@@ -317,7 +350,13 @@ L(matches32_1): + .p2align 4 + L(matches48_1): + bsf %eax, %eax ++#ifdef USE_AS_WMEMCHR ++ mov %eax, %esi ++ shr $2, %esi ++ sub %rsi, %rdx ++#else + sub %rax, %rdx ++#endif + jbe L(return_null) + lea 48(%rdi, %rax), %rax + ret +diff --git a/sysdeps/x86_64/multiarch/memchr-avx2.S b/sysdeps/x86_64/multiarch/memchr-avx2.S +index b377f22e..16027abb 100644 +--- a/sysdeps/x86_64/multiarch/memchr-avx2.S ++++ b/sysdeps/x86_64/multiarch/memchr-avx2.S +@@ -54,21 +54,19 @@ + + # define VEC_SIZE 32 + # define PAGE_SIZE 4096 ++# define CHAR_PER_VEC (VEC_SIZE / CHAR_SIZE) + + .section SECTION(.text),"ax",@progbits + ENTRY (MEMCHR) + # ifndef USE_AS_RAWMEMCHR + /* Check for zero length. */ +- test %RDX_LP, %RDX_LP +- jz L(null) +-# endif +-# ifdef USE_AS_WMEMCHR +- shl $2, %RDX_LP +-# else + # ifdef __ILP32__ +- /* Clear the upper 32 bits. */ +- movl %edx, %edx ++ /* Clear upper bits. */ ++ and %RDX_LP, %RDX_LP ++# else ++ test %RDX_LP, %RDX_LP + # endif ++ jz L(null) + # endif + /* Broadcast CHAR to YMMMATCH. */ + vmovd %esi, %xmm0 +@@ -84,7 +82,7 @@ ENTRY (MEMCHR) + vpmovmskb %ymm1, %eax + # ifndef USE_AS_RAWMEMCHR + /* If length < CHAR_PER_VEC handle special. */ +- cmpq $VEC_SIZE, %rdx ++ cmpq $CHAR_PER_VEC, %rdx + jbe L(first_vec_x0) + # endif + testl %eax, %eax +@@ -98,6 +96,10 @@ ENTRY (MEMCHR) + L(first_vec_x0): + /* Check if first match was before length. */ + tzcntl %eax, %eax ++# ifdef USE_AS_WMEMCHR ++ /* NB: Multiply length by 4 to get byte count. */ ++ sall $2, %edx ++# endif + xorl %ecx, %ecx + cmpl %eax, %edx + leaq (%rdi, %rax), %rax +@@ -110,12 +112,12 @@ L(null): + # endif + .p2align 4 + L(cross_page_boundary): +- /* Save pointer before aligning as its original value is necessary +- for computer return address if byte is found or adjusting length +- if it is not and this is memchr. */ ++ /* Save pointer before aligning as its original value is ++ necessary for computer return address if byte is found or ++ adjusting length if it is not and this is memchr. */ + movq %rdi, %rcx +- /* Align data to VEC_SIZE - 1. ALGN_PTR_REG is rcx for memchr and +- rdi for rawmemchr. */ ++ /* Align data to VEC_SIZE - 1. ALGN_PTR_REG is rcx for memchr ++ and rdi for rawmemchr. */ + orq $(VEC_SIZE - 1), %ALGN_PTR_REG + VPCMPEQ -(VEC_SIZE - 1)(%ALGN_PTR_REG), %ymm0, %ymm1 + vpmovmskb %ymm1, %eax +@@ -124,6 +126,10 @@ L(cross_page_boundary): + match). */ + leaq 1(%ALGN_PTR_REG), %rsi + subq %RRAW_PTR_REG, %rsi ++# ifdef USE_AS_WMEMCHR ++ /* NB: Divide bytes by 4 to get wchar_t count. */ ++ shrl $2, %esi ++# endif + # endif + /* Remove the leading bytes. */ + sarxl %ERAW_PTR_REG, %eax, %eax +@@ -181,6 +187,10 @@ L(cross_page_continue): + orq $(VEC_SIZE - 1), %rdi + /* esi is for adjusting length to see if near the end. */ + leal (VEC_SIZE * 4 + 1)(%rdi, %rcx), %esi ++# ifdef USE_AS_WMEMCHR ++ /* NB: Divide bytes by 4 to get the wchar_t count. */ ++ sarl $2, %esi ++# endif + # else + orq $(VEC_SIZE - 1), %rdi + L(cross_page_continue): +@@ -213,7 +223,7 @@ L(cross_page_continue): + + # ifndef USE_AS_RAWMEMCHR + /* Check if at last VEC_SIZE * 4 length. */ +- subq $(VEC_SIZE * 4), %rdx ++ subq $(CHAR_PER_VEC * 4), %rdx + jbe L(last_4x_vec_or_less_cmpeq) + /* Align data to VEC_SIZE * 4 - 1 for the loop and readjust + length. */ +@@ -221,6 +231,10 @@ L(cross_page_continue): + movl %edi, %ecx + orq $(VEC_SIZE * 4 - 1), %rdi + andl $(VEC_SIZE * 4 - 1), %ecx ++# ifdef USE_AS_WMEMCHR ++ /* NB: Divide bytes by 4 to get the wchar_t count. */ ++ sarl $2, %ecx ++# endif + addq %rcx, %rdx + # else + /* Align data to VEC_SIZE * 4 - 1 for loop. */ +@@ -250,15 +264,19 @@ L(loop_4x_vec): + + subq $-(VEC_SIZE * 4), %rdi + +- subq $(VEC_SIZE * 4), %rdx ++ subq $(CHAR_PER_VEC * 4), %rdx + ja L(loop_4x_vec) + +- /* Fall through into less than 4 remaining vectors of length case. +- */ ++ /* Fall through into less than 4 remaining vectors of length ++ case. */ + VPCMPEQ (VEC_SIZE * 0 + 1)(%rdi), %ymm0, %ymm1 + vpmovmskb %ymm1, %eax + .p2align 4 + L(last_4x_vec_or_less): ++# ifdef USE_AS_WMEMCHR ++ /* NB: Multiply length by 4 to get byte count. */ ++ sall $2, %edx ++# endif + /* Check if first VEC contained match. */ + testl %eax, %eax + jnz L(first_vec_x1_check) +@@ -355,6 +373,10 @@ L(last_vec_x2_return): + L(last_4x_vec_or_less_cmpeq): + VPCMPEQ (VEC_SIZE * 4 + 1)(%rdi), %ymm0, %ymm1 + vpmovmskb %ymm1, %eax ++# ifdef USE_AS_WMEMCHR ++ /* NB: Multiply length by 4 to get byte count. */ ++ sall $2, %edx ++# endif + subq $-(VEC_SIZE * 4), %rdi + /* Check first VEC regardless. */ + testl %eax, %eax +-- +GitLab + diff --git a/SOURCES/glibc-RHEL-15696-25.patch b/SOURCES/glibc-RHEL-15696-25.patch new file mode 100644 index 0000000..e0ed8ea --- /dev/null +++ b/SOURCES/glibc-RHEL-15696-25.patch @@ -0,0 +1,767 @@ +From aaa23c35071537e2dcf5807e956802ed215210aa Mon Sep 17 00:00:00 2001 +From: Noah Goldstein +Date: Mon, 19 Apr 2021 19:36:07 -0400 +Subject: [PATCH] x86: Optimize strlen-avx2.S +Content-type: text/plain; charset=UTF-8 + +No bug. This commit optimizes strlen-avx2.S. The optimizations are +mostly small things but they add up to roughly 10-30% performance +improvement for strlen. The results for strnlen are bit more +ambiguous. test-strlen, test-strnlen, test-wcslen, and test-wcsnlen +are all passing. + +Signed-off-by: Noah Goldstein +--- + sysdeps/x86_64/multiarch/ifunc-impl-list.c | 16 +- + sysdeps/x86_64/multiarch/strlen-avx2.S | 532 +++++++++++++-------- + 2 files changed, 334 insertions(+), 214 deletions(-) + +diff --git a/sysdeps/x86_64/multiarch/ifunc-impl-list.c b/sysdeps/x86_64/multiarch/ifunc-impl-list.c +index cbfc1a5d..f1a6460a 100644 +--- a/sysdeps/x86_64/multiarch/ifunc-impl-list.c ++++ b/sysdeps/x86_64/multiarch/ifunc-impl-list.c +@@ -285,10 +285,12 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + /* Support sysdeps/x86_64/multiarch/strlen.c. */ + IFUNC_IMPL (i, name, strlen, + IFUNC_IMPL_ADD (array, i, strlen, +- CPU_FEATURE_USABLE (AVX2), ++ (CPU_FEATURE_USABLE (AVX2) ++ && CPU_FEATURE_USABLE (BMI2)), + __strlen_avx2) + IFUNC_IMPL_ADD (array, i, strlen, + (CPU_FEATURE_USABLE (AVX2) ++ && CPU_FEATURE_USABLE (BMI2) + && CPU_FEATURE_USABLE (RTM)), + __strlen_avx2_rtm) + IFUNC_IMPL_ADD (array, i, strlen, +@@ -301,10 +303,12 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + /* Support sysdeps/x86_64/multiarch/strnlen.c. */ + IFUNC_IMPL (i, name, strnlen, + IFUNC_IMPL_ADD (array, i, strnlen, +- CPU_FEATURE_USABLE (AVX2), ++ (CPU_FEATURE_USABLE (AVX2) ++ && CPU_FEATURE_USABLE (BMI2)), + __strnlen_avx2) + IFUNC_IMPL_ADD (array, i, strnlen, + (CPU_FEATURE_USABLE (AVX2) ++ && CPU_FEATURE_USABLE (BMI2) + && CPU_FEATURE_USABLE (RTM)), + __strnlen_avx2_rtm) + IFUNC_IMPL_ADD (array, i, strnlen, +@@ -640,10 +644,12 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + /* Support sysdeps/x86_64/multiarch/wcslen.c. */ + IFUNC_IMPL (i, name, wcslen, + IFUNC_IMPL_ADD (array, i, wcslen, +- CPU_FEATURE_USABLE (AVX2), ++ (CPU_FEATURE_USABLE (AVX2) ++ && CPU_FEATURE_USABLE (BMI2)), + __wcslen_avx2) + IFUNC_IMPL_ADD (array, i, wcslen, + (CPU_FEATURE_USABLE (AVX2) ++ && CPU_FEATURE_USABLE (BMI2) + && CPU_FEATURE_USABLE (RTM)), + __wcslen_avx2_rtm) + IFUNC_IMPL_ADD (array, i, wcslen, +@@ -656,10 +662,12 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + /* Support sysdeps/x86_64/multiarch/wcsnlen.c. */ + IFUNC_IMPL (i, name, wcsnlen, + IFUNC_IMPL_ADD (array, i, wcsnlen, +- CPU_FEATURE_USABLE (AVX2), ++ (CPU_FEATURE_USABLE (AVX2) ++ && CPU_FEATURE_USABLE (BMI2)), + __wcsnlen_avx2) + IFUNC_IMPL_ADD (array, i, wcsnlen, + (CPU_FEATURE_USABLE (AVX2) ++ && CPU_FEATURE_USABLE (BMI2) + && CPU_FEATURE_USABLE (RTM)), + __wcsnlen_avx2_rtm) + IFUNC_IMPL_ADD (array, i, wcsnlen, +diff --git a/sysdeps/x86_64/multiarch/strlen-avx2.S b/sysdeps/x86_64/multiarch/strlen-avx2.S +index 82826e10..be8a5db5 100644 +--- a/sysdeps/x86_64/multiarch/strlen-avx2.S ++++ b/sysdeps/x86_64/multiarch/strlen-avx2.S +@@ -27,9 +27,11 @@ + # ifdef USE_AS_WCSLEN + # define VPCMPEQ vpcmpeqd + # define VPMINU vpminud ++# define CHAR_SIZE 4 + # else + # define VPCMPEQ vpcmpeqb + # define VPMINU vpminub ++# define CHAR_SIZE 1 + # endif + + # ifndef VZEROUPPER +@@ -41,349 +43,459 @@ + # endif + + # define VEC_SIZE 32 ++# define PAGE_SIZE 4096 + + .section SECTION(.text),"ax",@progbits + ENTRY (STRLEN) + # ifdef USE_AS_STRNLEN +- /* Check for zero length. */ ++ /* Check zero length. */ + test %RSI_LP, %RSI_LP + jz L(zero) ++ /* Store max len in R8_LP before adjusting if using WCSLEN. */ ++ mov %RSI_LP, %R8_LP + # ifdef USE_AS_WCSLEN + shl $2, %RSI_LP + # elif defined __ILP32__ + /* Clear the upper 32 bits. */ + movl %esi, %esi + # endif +- mov %RSI_LP, %R8_LP + # endif +- movl %edi, %ecx ++ movl %edi, %eax + movq %rdi, %rdx + vpxor %xmm0, %xmm0, %xmm0 +- ++ /* Clear high bits from edi. Only keeping bits relevant to page ++ cross check. */ ++ andl $(PAGE_SIZE - 1), %eax + /* Check if we may cross page boundary with one vector load. */ +- andl $(2 * VEC_SIZE - 1), %ecx +- cmpl $VEC_SIZE, %ecx +- ja L(cros_page_boundary) ++ cmpl $(PAGE_SIZE - VEC_SIZE), %eax ++ ja L(cross_page_boundary) + + /* Check the first VEC_SIZE bytes. */ +- VPCMPEQ (%rdi), %ymm0, %ymm1 +- vpmovmskb %ymm1, %eax +- testl %eax, %eax +- ++ VPCMPEQ (%rdi), %ymm0, %ymm1 ++ vpmovmskb %ymm1, %eax + # ifdef USE_AS_STRNLEN +- jnz L(first_vec_x0_check) +- /* Adjust length and check the end of data. */ +- subq $VEC_SIZE, %rsi +- jbe L(max) +-# else +- jnz L(first_vec_x0) ++ /* If length < VEC_SIZE handle special. */ ++ cmpq $VEC_SIZE, %rsi ++ jbe L(first_vec_x0) + # endif +- +- /* Align data for aligned loads in the loop. */ +- addq $VEC_SIZE, %rdi +- andl $(VEC_SIZE - 1), %ecx +- andq $-VEC_SIZE, %rdi ++ /* If empty continue to aligned_more. Otherwise return bit ++ position of first match. */ ++ testl %eax, %eax ++ jz L(aligned_more) ++ tzcntl %eax, %eax ++# ifdef USE_AS_WCSLEN ++ shrl $2, %eax ++# endif ++ VZEROUPPER_RETURN + + # ifdef USE_AS_STRNLEN +- /* Adjust length. */ +- addq %rcx, %rsi ++L(zero): ++ xorl %eax, %eax ++ ret + +- subq $(VEC_SIZE * 4), %rsi +- jbe L(last_4x_vec_or_less) ++ .p2align 4 ++L(first_vec_x0): ++ /* Set bit for max len so that tzcnt will return min of max len ++ and position of first match. */ ++ btsq %rsi, %rax ++ tzcntl %eax, %eax ++# ifdef USE_AS_WCSLEN ++ shrl $2, %eax ++# endif ++ VZEROUPPER_RETURN + # endif +- jmp L(more_4x_vec) + + .p2align 4 +-L(cros_page_boundary): +- andl $(VEC_SIZE - 1), %ecx +- andq $-VEC_SIZE, %rdi +- VPCMPEQ (%rdi), %ymm0, %ymm1 +- vpmovmskb %ymm1, %eax +- /* Remove the leading bytes. */ +- sarl %cl, %eax +- testl %eax, %eax +- jz L(aligned_more) ++L(first_vec_x1): + tzcntl %eax, %eax ++ /* Safe to use 32 bit instructions as these are only called for ++ size = [1, 159]. */ + # ifdef USE_AS_STRNLEN +- /* Check the end of data. */ +- cmpq %rax, %rsi +- jbe L(max) ++ /* Use ecx which was computed earlier to compute correct value. ++ */ ++ subl $(VEC_SIZE * 4 + 1), %ecx ++ addl %ecx, %eax ++# else ++ subl %edx, %edi ++ incl %edi ++ addl %edi, %eax + # endif +- addq %rdi, %rax +- addq %rcx, %rax +- subq %rdx, %rax + # ifdef USE_AS_WCSLEN +- shrq $2, %rax ++ shrl $2, %eax + # endif +-L(return_vzeroupper): +- ZERO_UPPER_VEC_REGISTERS_RETURN ++ VZEROUPPER_RETURN + + .p2align 4 +-L(aligned_more): ++L(first_vec_x2): ++ tzcntl %eax, %eax ++ /* Safe to use 32 bit instructions as these are only called for ++ size = [1, 159]. */ + # ifdef USE_AS_STRNLEN +- /* "rcx" is less than VEC_SIZE. Calculate "rdx + rcx - VEC_SIZE" +- with "rdx - (VEC_SIZE - rcx)" instead of "(rdx + rcx) - VEC_SIZE" +- to void possible addition overflow. */ +- negq %rcx +- addq $VEC_SIZE, %rcx +- +- /* Check the end of data. */ +- subq %rcx, %rsi +- jbe L(max) ++ /* Use ecx which was computed earlier to compute correct value. ++ */ ++ subl $(VEC_SIZE * 3 + 1), %ecx ++ addl %ecx, %eax ++# else ++ subl %edx, %edi ++ addl $(VEC_SIZE + 1), %edi ++ addl %edi, %eax + # endif ++# ifdef USE_AS_WCSLEN ++ shrl $2, %eax ++# endif ++ VZEROUPPER_RETURN + +- addq $VEC_SIZE, %rdi ++ .p2align 4 ++L(first_vec_x3): ++ tzcntl %eax, %eax ++ /* Safe to use 32 bit instructions as these are only called for ++ size = [1, 159]. */ ++# ifdef USE_AS_STRNLEN ++ /* Use ecx which was computed earlier to compute correct value. ++ */ ++ subl $(VEC_SIZE * 2 + 1), %ecx ++ addl %ecx, %eax ++# else ++ subl %edx, %edi ++ addl $(VEC_SIZE * 2 + 1), %edi ++ addl %edi, %eax ++# endif ++# ifdef USE_AS_WCSLEN ++ shrl $2, %eax ++# endif ++ VZEROUPPER_RETURN + ++ .p2align 4 ++L(first_vec_x4): ++ tzcntl %eax, %eax ++ /* Safe to use 32 bit instructions as these are only called for ++ size = [1, 159]. */ + # ifdef USE_AS_STRNLEN +- subq $(VEC_SIZE * 4), %rsi +- jbe L(last_4x_vec_or_less) ++ /* Use ecx which was computed earlier to compute correct value. ++ */ ++ subl $(VEC_SIZE + 1), %ecx ++ addl %ecx, %eax ++# else ++ subl %edx, %edi ++ addl $(VEC_SIZE * 3 + 1), %edi ++ addl %edi, %eax + # endif ++# ifdef USE_AS_WCSLEN ++ shrl $2, %eax ++# endif ++ VZEROUPPER_RETURN + +-L(more_4x_vec): ++ .p2align 5 ++L(aligned_more): ++ /* Align data to VEC_SIZE - 1. This is the same number of ++ instructions as using andq with -VEC_SIZE but saves 4 bytes of ++ code on the x4 check. */ ++ orq $(VEC_SIZE - 1), %rdi ++L(cross_page_continue): + /* Check the first 4 * VEC_SIZE. Only one VEC_SIZE at a time + since data is only aligned to VEC_SIZE. */ +- VPCMPEQ (%rdi), %ymm0, %ymm1 +- vpmovmskb %ymm1, %eax +- testl %eax, %eax +- jnz L(first_vec_x0) +- +- VPCMPEQ VEC_SIZE(%rdi), %ymm0, %ymm1 +- vpmovmskb %ymm1, %eax ++# ifdef USE_AS_STRNLEN ++ /* + 1 because rdi is aligned to VEC_SIZE - 1. + CHAR_SIZE because ++ it simplies the logic in last_4x_vec_or_less. */ ++ leaq (VEC_SIZE * 4 + CHAR_SIZE + 1)(%rdi), %rcx ++ subq %rdx, %rcx ++# endif ++ /* Load first VEC regardless. */ ++ VPCMPEQ 1(%rdi), %ymm0, %ymm1 ++# ifdef USE_AS_STRNLEN ++ /* Adjust length. If near end handle specially. */ ++ subq %rcx, %rsi ++ jb L(last_4x_vec_or_less) ++# endif ++ vpmovmskb %ymm1, %eax + testl %eax, %eax + jnz L(first_vec_x1) + +- VPCMPEQ (VEC_SIZE * 2)(%rdi), %ymm0, %ymm1 +- vpmovmskb %ymm1, %eax ++ VPCMPEQ (VEC_SIZE + 1)(%rdi), %ymm0, %ymm1 ++ vpmovmskb %ymm1, %eax + testl %eax, %eax + jnz L(first_vec_x2) + +- VPCMPEQ (VEC_SIZE * 3)(%rdi), %ymm0, %ymm1 +- vpmovmskb %ymm1, %eax ++ VPCMPEQ (VEC_SIZE * 2 + 1)(%rdi), %ymm0, %ymm1 ++ vpmovmskb %ymm1, %eax + testl %eax, %eax + jnz L(first_vec_x3) + +- addq $(VEC_SIZE * 4), %rdi +- +-# ifdef USE_AS_STRNLEN +- subq $(VEC_SIZE * 4), %rsi +- jbe L(last_4x_vec_or_less) +-# endif +- +- /* Align data to 4 * VEC_SIZE. */ +- movq %rdi, %rcx +- andl $(4 * VEC_SIZE - 1), %ecx +- andq $-(4 * VEC_SIZE), %rdi ++ VPCMPEQ (VEC_SIZE * 3 + 1)(%rdi), %ymm0, %ymm1 ++ vpmovmskb %ymm1, %eax ++ testl %eax, %eax ++ jnz L(first_vec_x4) + ++ /* Align data to VEC_SIZE * 4 - 1. */ + # ifdef USE_AS_STRNLEN +- /* Adjust length. */ ++ /* Before adjusting length check if at last VEC_SIZE * 4. */ ++ cmpq $(VEC_SIZE * 4 - 1), %rsi ++ jbe L(last_4x_vec_or_less_load) ++ incq %rdi ++ movl %edi, %ecx ++ orq $(VEC_SIZE * 4 - 1), %rdi ++ andl $(VEC_SIZE * 4 - 1), %ecx ++ /* Readjust length. */ + addq %rcx, %rsi ++# else ++ incq %rdi ++ orq $(VEC_SIZE * 4 - 1), %rdi + # endif +- ++ /* Compare 4 * VEC at a time forward. */ + .p2align 4 + L(loop_4x_vec): +- /* Compare 4 * VEC at a time forward. */ +- vmovdqa (%rdi), %ymm1 +- vmovdqa VEC_SIZE(%rdi), %ymm2 +- vmovdqa (VEC_SIZE * 2)(%rdi), %ymm3 +- vmovdqa (VEC_SIZE * 3)(%rdi), %ymm4 +- VPMINU %ymm1, %ymm2, %ymm5 +- VPMINU %ymm3, %ymm4, %ymm6 +- VPMINU %ymm5, %ymm6, %ymm5 +- +- VPCMPEQ %ymm5, %ymm0, %ymm5 +- vpmovmskb %ymm5, %eax +- testl %eax, %eax +- jnz L(4x_vec_end) +- +- addq $(VEC_SIZE * 4), %rdi +- +-# ifndef USE_AS_STRNLEN +- jmp L(loop_4x_vec) +-# else ++# ifdef USE_AS_STRNLEN ++ /* Break if at end of length. */ + subq $(VEC_SIZE * 4), %rsi +- ja L(loop_4x_vec) +- +-L(last_4x_vec_or_less): +- /* Less than 4 * VEC and aligned to VEC_SIZE. */ +- addl $(VEC_SIZE * 2), %esi +- jle L(last_2x_vec) ++ jb L(last_4x_vec_or_less_cmpeq) ++# endif ++ /* Save some code size by microfusing VPMINU with the load. Since ++ the matches in ymm2/ymm4 can only be returned if there where no ++ matches in ymm1/ymm3 respectively there is no issue with overlap. ++ */ ++ vmovdqa 1(%rdi), %ymm1 ++ VPMINU (VEC_SIZE + 1)(%rdi), %ymm1, %ymm2 ++ vmovdqa (VEC_SIZE * 2 + 1)(%rdi), %ymm3 ++ VPMINU (VEC_SIZE * 3 + 1)(%rdi), %ymm3, %ymm4 ++ ++ VPMINU %ymm2, %ymm4, %ymm5 ++ VPCMPEQ %ymm5, %ymm0, %ymm5 ++ vpmovmskb %ymm5, %ecx + +- VPCMPEQ (%rdi), %ymm0, %ymm1 +- vpmovmskb %ymm1, %eax +- testl %eax, %eax +- jnz L(first_vec_x0) ++ subq $-(VEC_SIZE * 4), %rdi ++ testl %ecx, %ecx ++ jz L(loop_4x_vec) + +- VPCMPEQ VEC_SIZE(%rdi), %ymm0, %ymm1 +- vpmovmskb %ymm1, %eax +- testl %eax, %eax +- jnz L(first_vec_x1) + +- VPCMPEQ (VEC_SIZE * 2)(%rdi), %ymm0, %ymm1 +- vpmovmskb %ymm1, %eax ++ VPCMPEQ %ymm1, %ymm0, %ymm1 ++ vpmovmskb %ymm1, %eax ++ subq %rdx, %rdi + testl %eax, %eax ++ jnz L(last_vec_return_x0) + +- jnz L(first_vec_x2_check) +- subl $VEC_SIZE, %esi +- jle L(max) +- +- VPCMPEQ (VEC_SIZE * 3)(%rdi), %ymm0, %ymm1 +- vpmovmskb %ymm1, %eax ++ VPCMPEQ %ymm2, %ymm0, %ymm2 ++ vpmovmskb %ymm2, %eax + testl %eax, %eax +- +- jnz L(first_vec_x3_check) +- movq %r8, %rax +-# ifdef USE_AS_WCSLEN ++ jnz L(last_vec_return_x1) ++ ++ /* Combine last 2 VEC. */ ++ VPCMPEQ %ymm3, %ymm0, %ymm3 ++ vpmovmskb %ymm3, %eax ++ /* rcx has combined result from all 4 VEC. It will only be used if ++ the first 3 other VEC all did not contain a match. */ ++ salq $32, %rcx ++ orq %rcx, %rax ++ tzcntq %rax, %rax ++ subq $(VEC_SIZE * 2 - 1), %rdi ++ addq %rdi, %rax ++# ifdef USE_AS_WCSLEN + shrq $2, %rax +-# endif ++# endif + VZEROUPPER_RETURN + ++ ++# ifdef USE_AS_STRNLEN + .p2align 4 +-L(last_2x_vec): +- addl $(VEC_SIZE * 2), %esi +- VPCMPEQ (%rdi), %ymm0, %ymm1 +- vpmovmskb %ymm1, %eax +- testl %eax, %eax ++L(last_4x_vec_or_less_load): ++ /* Depending on entry adjust rdi / prepare first VEC in ymm1. */ ++ subq $-(VEC_SIZE * 4), %rdi ++L(last_4x_vec_or_less_cmpeq): ++ VPCMPEQ 1(%rdi), %ymm0, %ymm1 ++L(last_4x_vec_or_less): + +- jnz L(first_vec_x0_check) +- subl $VEC_SIZE, %esi +- jle L(max) ++ vpmovmskb %ymm1, %eax ++ /* If remaining length > VEC_SIZE * 2. This works if esi is off by ++ VEC_SIZE * 4. */ ++ testl $(VEC_SIZE * 2), %esi ++ jnz L(last_4x_vec) + +- VPCMPEQ VEC_SIZE(%rdi), %ymm0, %ymm1 +- vpmovmskb %ymm1, %eax ++ /* length may have been negative or positive by an offset of ++ VEC_SIZE * 4 depending on where this was called from. This fixes ++ that. */ ++ andl $(VEC_SIZE * 4 - 1), %esi + testl %eax, %eax +- jnz L(first_vec_x1_check) +- movq %r8, %rax +-# ifdef USE_AS_WCSLEN +- shrq $2, %rax +-# endif +- VZEROUPPER_RETURN ++ jnz L(last_vec_x1_check) + +- .p2align 4 +-L(first_vec_x0_check): ++ subl $VEC_SIZE, %esi ++ jb L(max) ++ ++ VPCMPEQ (VEC_SIZE + 1)(%rdi), %ymm0, %ymm1 ++ vpmovmskb %ymm1, %eax + tzcntl %eax, %eax + /* Check the end of data. */ +- cmpq %rax, %rsi +- jbe L(max) ++ cmpl %eax, %esi ++ jb L(max) ++ subq %rdx, %rdi ++ addl $(VEC_SIZE + 1), %eax + addq %rdi, %rax +- subq %rdx, %rax + # ifdef USE_AS_WCSLEN + shrq $2, %rax + # endif + VZEROUPPER_RETURN ++# endif + + .p2align 4 +-L(first_vec_x1_check): ++L(last_vec_return_x0): + tzcntl %eax, %eax +- /* Check the end of data. */ +- cmpq %rax, %rsi +- jbe L(max) +- addq $VEC_SIZE, %rax ++ subq $(VEC_SIZE * 4 - 1), %rdi + addq %rdi, %rax +- subq %rdx, %rax +-# ifdef USE_AS_WCSLEN ++# ifdef USE_AS_WCSLEN + shrq $2, %rax +-# endif ++# endif + VZEROUPPER_RETURN + + .p2align 4 +-L(first_vec_x2_check): ++L(last_vec_return_x1): + tzcntl %eax, %eax +- /* Check the end of data. */ +- cmpq %rax, %rsi +- jbe L(max) +- addq $(VEC_SIZE * 2), %rax ++ subq $(VEC_SIZE * 3 - 1), %rdi + addq %rdi, %rax +- subq %rdx, %rax +-# ifdef USE_AS_WCSLEN ++# ifdef USE_AS_WCSLEN + shrq $2, %rax +-# endif ++# endif + VZEROUPPER_RETURN + ++# ifdef USE_AS_STRNLEN + .p2align 4 +-L(first_vec_x3_check): ++L(last_vec_x1_check): ++ + tzcntl %eax, %eax + /* Check the end of data. */ +- cmpq %rax, %rsi +- jbe L(max) +- addq $(VEC_SIZE * 3), %rax ++ cmpl %eax, %esi ++ jb L(max) ++ subq %rdx, %rdi ++ incl %eax + addq %rdi, %rax +- subq %rdx, %rax + # ifdef USE_AS_WCSLEN + shrq $2, %rax + # endif + VZEROUPPER_RETURN + +- .p2align 4 + L(max): + movq %r8, %rax ++ VZEROUPPER_RETURN ++ ++ .p2align 4 ++L(last_4x_vec): ++ /* Test first 2x VEC normally. */ ++ testl %eax, %eax ++ jnz L(last_vec_x1) ++ ++ VPCMPEQ (VEC_SIZE + 1)(%rdi), %ymm0, %ymm1 ++ vpmovmskb %ymm1, %eax ++ testl %eax, %eax ++ jnz L(last_vec_x2) ++ ++ /* Normalize length. */ ++ andl $(VEC_SIZE * 4 - 1), %esi ++ VPCMPEQ (VEC_SIZE * 2 + 1)(%rdi), %ymm0, %ymm1 ++ vpmovmskb %ymm1, %eax ++ testl %eax, %eax ++ jnz L(last_vec_x3) ++ ++ subl $(VEC_SIZE * 3), %esi ++ jb L(max) ++ ++ VPCMPEQ (VEC_SIZE * 3 + 1)(%rdi), %ymm0, %ymm1 ++ vpmovmskb %ymm1, %eax ++ tzcntl %eax, %eax ++ /* Check the end of data. */ ++ cmpl %eax, %esi ++ jb L(max) ++ subq %rdx, %rdi ++ addl $(VEC_SIZE * 3 + 1), %eax ++ addq %rdi, %rax + # ifdef USE_AS_WCSLEN + shrq $2, %rax + # endif + VZEROUPPER_RETURN + +- .p2align 4 +-L(zero): +- xorl %eax, %eax +- ret +-# endif + + .p2align 4 +-L(first_vec_x0): ++L(last_vec_x1): ++ /* essentially duplicates of first_vec_x1 but use 64 bit ++ instructions. */ + tzcntl %eax, %eax ++ subq %rdx, %rdi ++ incl %eax + addq %rdi, %rax +- subq %rdx, %rax +-# ifdef USE_AS_WCSLEN ++# ifdef USE_AS_WCSLEN + shrq $2, %rax +-# endif ++# endif + VZEROUPPER_RETURN + + .p2align 4 +-L(first_vec_x1): ++L(last_vec_x2): ++ /* essentially duplicates of first_vec_x1 but use 64 bit ++ instructions. */ + tzcntl %eax, %eax +- addq $VEC_SIZE, %rax ++ subq %rdx, %rdi ++ addl $(VEC_SIZE + 1), %eax + addq %rdi, %rax +- subq %rdx, %rax +-# ifdef USE_AS_WCSLEN ++# ifdef USE_AS_WCSLEN + shrq $2, %rax +-# endif ++# endif + VZEROUPPER_RETURN + + .p2align 4 +-L(first_vec_x2): ++L(last_vec_x3): + tzcntl %eax, %eax +- addq $(VEC_SIZE * 2), %rax ++ subl $(VEC_SIZE * 2), %esi ++ /* Check the end of data. */ ++ cmpl %eax, %esi ++ jb L(max_end) ++ subq %rdx, %rdi ++ addl $(VEC_SIZE * 2 + 1), %eax + addq %rdi, %rax +- subq %rdx, %rax +-# ifdef USE_AS_WCSLEN ++# ifdef USE_AS_WCSLEN + shrq $2, %rax +-# endif ++# endif ++ VZEROUPPER_RETURN ++L(max_end): ++ movq %r8, %rax + VZEROUPPER_RETURN ++# endif + ++ /* Cold case for crossing page with first load. */ + .p2align 4 +-L(4x_vec_end): +- VPCMPEQ %ymm1, %ymm0, %ymm1 +- vpmovmskb %ymm1, %eax +- testl %eax, %eax +- jnz L(first_vec_x0) +- VPCMPEQ %ymm2, %ymm0, %ymm2 +- vpmovmskb %ymm2, %eax ++L(cross_page_boundary): ++ /* Align data to VEC_SIZE - 1. */ ++ orq $(VEC_SIZE - 1), %rdi ++ VPCMPEQ -(VEC_SIZE - 1)(%rdi), %ymm0, %ymm1 ++ vpmovmskb %ymm1, %eax ++ /* Remove the leading bytes. sarxl only uses bits [5:0] of COUNT ++ so no need to manually mod rdx. */ ++ sarxl %edx, %eax, %eax ++# ifdef USE_AS_STRNLEN + testl %eax, %eax +- jnz L(first_vec_x1) +- VPCMPEQ %ymm3, %ymm0, %ymm3 +- vpmovmskb %ymm3, %eax ++ jnz L(cross_page_less_vec) ++ leaq 1(%rdi), %rcx ++ subq %rdx, %rcx ++ /* Check length. */ ++ cmpq %rsi, %rcx ++ jb L(cross_page_continue) ++ movq %r8, %rax ++# else + testl %eax, %eax +- jnz L(first_vec_x2) +- VPCMPEQ %ymm4, %ymm0, %ymm4 +- vpmovmskb %ymm4, %eax +-L(first_vec_x3): ++ jz L(cross_page_continue) + tzcntl %eax, %eax +- addq $(VEC_SIZE * 3), %rax +- addq %rdi, %rax +- subq %rdx, %rax +-# ifdef USE_AS_WCSLEN +- shrq $2, %rax ++# ifdef USE_AS_WCSLEN ++ shrl $2, %eax ++# endif + # endif ++L(return_vzeroupper): ++ ZERO_UPPER_VEC_REGISTERS_RETURN ++ ++# ifdef USE_AS_STRNLEN ++ .p2align 4 ++L(cross_page_less_vec): ++ tzcntl %eax, %eax ++ cmpq %rax, %rsi ++ cmovb %esi, %eax ++# ifdef USE_AS_WCSLEN ++ shrl $2, %eax ++# endif + VZEROUPPER_RETURN ++# endif + + END (STRLEN) + #endif +-- +GitLab + diff --git a/SOURCES/glibc-RHEL-15696-26.patch b/SOURCES/glibc-RHEL-15696-26.patch new file mode 100644 index 0000000..d46fe6e --- /dev/null +++ b/SOURCES/glibc-RHEL-15696-26.patch @@ -0,0 +1,701 @@ +From 2a76821c3081d2c0231ecd2618f52662cb48fccd Mon Sep 17 00:00:00 2001 +From: Noah Goldstein +Date: Mon, 3 May 2021 03:03:19 -0400 +Subject: [PATCH] x86: Optimize memchr-evex.S +Content-type: text/plain; charset=UTF-8 + +No bug. This commit optimizes memchr-evex.S. The optimizations include +replacing some branches with cmovcc, avoiding some branches entirely +in the less_4x_vec case, making the page cross logic less strict, +saving some ALU in the alignment process, and most importantly +increasing ILP in the 4x loop. test-memchr, test-rawmemchr, and +test-wmemchr are all passing. + +Signed-off-by: Noah Goldstein +Reviewed-by: H.J. Lu +--- + sysdeps/x86_64/multiarch/memchr-evex.S | 547 +++++++++++++++---------- + 1 file changed, 322 insertions(+), 225 deletions(-) + +diff --git a/sysdeps/x86_64/multiarch/memchr-evex.S b/sysdeps/x86_64/multiarch/memchr-evex.S +index 6dd5d67b..81d5cd64 100644 +--- a/sysdeps/x86_64/multiarch/memchr-evex.S ++++ b/sysdeps/x86_64/multiarch/memchr-evex.S +@@ -26,14 +26,28 @@ + + # ifdef USE_AS_WMEMCHR + # define VPBROADCAST vpbroadcastd +-# define VPCMP vpcmpd +-# define SHIFT_REG r8d ++# define VPMINU vpminud ++# define VPCMP vpcmpd ++# define VPCMPEQ vpcmpeqd ++# define CHAR_SIZE 4 + # else + # define VPBROADCAST vpbroadcastb +-# define VPCMP vpcmpb +-# define SHIFT_REG ecx ++# define VPMINU vpminub ++# define VPCMP vpcmpb ++# define VPCMPEQ vpcmpeqb ++# define CHAR_SIZE 1 + # endif + ++# ifdef USE_AS_RAWMEMCHR ++# define RAW_PTR_REG rcx ++# define ALGN_PTR_REG rdi ++# else ++# define RAW_PTR_REG rdi ++# define ALGN_PTR_REG rcx ++# endif ++ ++# define XMMZERO xmm23 ++# define YMMZERO ymm23 + # define XMMMATCH xmm16 + # define YMMMATCH ymm16 + # define YMM1 ymm17 +@@ -44,6 +58,8 @@ + # define YMM6 ymm22 + + # define VEC_SIZE 32 ++# define CHAR_PER_VEC (VEC_SIZE / CHAR_SIZE) ++# define PAGE_SIZE 4096 + + .section .text.evex,"ax",@progbits + ENTRY (MEMCHR) +@@ -51,11 +67,7 @@ ENTRY (MEMCHR) + /* Check for zero length. */ + test %RDX_LP, %RDX_LP + jz L(zero) +-# endif +- movl %edi, %ecx +-# ifdef USE_AS_WMEMCHR +- shl $2, %RDX_LP +-# else ++ + # ifdef __ILP32__ + /* Clear the upper 32 bits. */ + movl %edx, %edx +@@ -64,318 +76,403 @@ ENTRY (MEMCHR) + /* Broadcast CHAR to YMMMATCH. */ + VPBROADCAST %esi, %YMMMATCH + /* Check if we may cross page boundary with one vector load. */ +- andl $(2 * VEC_SIZE - 1), %ecx +- cmpl $VEC_SIZE, %ecx +- ja L(cros_page_boundary) ++ movl %edi, %eax ++ andl $(PAGE_SIZE - 1), %eax ++ cmpl $(PAGE_SIZE - VEC_SIZE), %eax ++ ja L(cross_page_boundary) + + /* Check the first VEC_SIZE bytes. */ +- VPCMP $0, (%rdi), %YMMMATCH, %k1 +- kmovd %k1, %eax +- testl %eax, %eax +- ++ VPCMP $0, (%rdi), %YMMMATCH, %k0 ++ kmovd %k0, %eax + # ifndef USE_AS_RAWMEMCHR +- jnz L(first_vec_x0_check) +- /* Adjust length and check the end of data. */ +- subq $VEC_SIZE, %rdx +- jbe L(zero) ++ /* If length < CHAR_PER_VEC handle special. */ ++ cmpq $CHAR_PER_VEC, %rdx ++ jbe L(first_vec_x0) ++# endif ++ testl %eax, %eax ++ jz L(aligned_more) ++ tzcntl %eax, %eax ++# ifdef USE_AS_WMEMCHR ++ /* NB: Multiply bytes by CHAR_SIZE to get the wchar_t count. */ ++ leaq (%rdi, %rax, CHAR_SIZE), %rax + # else +- jnz L(first_vec_x0) ++ addq %rdi, %rax + # endif +- +- /* Align data for aligned loads in the loop. */ +- addq $VEC_SIZE, %rdi +- andl $(VEC_SIZE - 1), %ecx +- andq $-VEC_SIZE, %rdi ++ ret + + # ifndef USE_AS_RAWMEMCHR +- /* Adjust length. */ +- addq %rcx, %rdx +- +- subq $(VEC_SIZE * 4), %rdx +- jbe L(last_4x_vec_or_less) +-# endif +- jmp L(more_4x_vec) ++L(zero): ++ xorl %eax, %eax ++ ret + ++ .p2align 5 ++L(first_vec_x0): ++ /* Check if first match was before length. */ ++ tzcntl %eax, %eax ++ xorl %ecx, %ecx ++ cmpl %eax, %edx ++ leaq (%rdi, %rax, CHAR_SIZE), %rax ++ cmovle %rcx, %rax ++ ret ++# else ++ /* NB: first_vec_x0 is 17 bytes which will leave ++ cross_page_boundary (which is relatively cold) close enough ++ to ideal alignment. So only realign L(cross_page_boundary) if ++ rawmemchr. */ + .p2align 4 +-L(cros_page_boundary): +- andl $(VEC_SIZE - 1), %ecx ++# endif ++L(cross_page_boundary): ++ /* Save pointer before aligning as its original value is ++ necessary for computer return address if byte is found or ++ adjusting length if it is not and this is memchr. */ ++ movq %rdi, %rcx ++ /* Align data to VEC_SIZE. ALGN_PTR_REG is rcx for memchr and rdi ++ for rawmemchr. */ ++ andq $-VEC_SIZE, %ALGN_PTR_REG ++ VPCMP $0, (%ALGN_PTR_REG), %YMMMATCH, %k0 ++ kmovd %k0, %r8d + # ifdef USE_AS_WMEMCHR +- /* NB: Divide shift count by 4 since each bit in K1 represent 4 ++ /* NB: Divide shift count by 4 since each bit in K0 represent 4 + bytes. */ +- movl %ecx, %SHIFT_REG +- sarl $2, %SHIFT_REG ++ sarl $2, %eax ++# endif ++# ifndef USE_AS_RAWMEMCHR ++ movl $(PAGE_SIZE / CHAR_SIZE), %esi ++ subl %eax, %esi + # endif +- andq $-VEC_SIZE, %rdi +- VPCMP $0, (%rdi), %YMMMATCH, %k1 +- kmovd %k1, %eax +- /* Remove the leading bytes. */ +- sarxl %SHIFT_REG, %eax, %eax +- testl %eax, %eax +- jz L(aligned_more) +- tzcntl %eax, %eax + # ifdef USE_AS_WMEMCHR +- /* NB: Multiply wchar_t count by 4 to get the number of bytes. */ +- sall $2, %eax ++ andl $(CHAR_PER_VEC - 1), %eax + # endif ++ /* Remove the leading bytes. */ ++ sarxl %eax, %r8d, %eax + # ifndef USE_AS_RAWMEMCHR + /* Check the end of data. */ +- cmpq %rax, %rdx +- jbe L(zero) ++ cmpq %rsi, %rdx ++ jbe L(first_vec_x0) ++# endif ++ testl %eax, %eax ++ jz L(cross_page_continue) ++ tzcntl %eax, %eax ++# ifdef USE_AS_WMEMCHR ++ /* NB: Multiply bytes by CHAR_SIZE to get the wchar_t count. */ ++ leaq (%RAW_PTR_REG, %rax, CHAR_SIZE), %rax ++# else ++ addq %RAW_PTR_REG, %rax + # endif +- addq %rdi, %rax +- addq %rcx, %rax + ret + + .p2align 4 +-L(aligned_more): +-# ifndef USE_AS_RAWMEMCHR +- /* Calculate "rdx + rcx - VEC_SIZE" with "rdx - (VEC_SIZE - rcx)" +- instead of "(rdx + rcx) - VEC_SIZE" to void possible addition +- overflow. */ +- negq %rcx +- addq $VEC_SIZE, %rcx ++L(first_vec_x1): ++ tzcntl %eax, %eax ++ leaq VEC_SIZE(%rdi, %rax, CHAR_SIZE), %rax ++ ret + +- /* Check the end of data. */ +- subq %rcx, %rdx +- jbe L(zero) +-# endif ++ .p2align 4 ++L(first_vec_x2): ++ tzcntl %eax, %eax ++ leaq (VEC_SIZE * 2)(%rdi, %rax, CHAR_SIZE), %rax ++ ret + +- addq $VEC_SIZE, %rdi ++ .p2align 4 ++L(first_vec_x3): ++ tzcntl %eax, %eax ++ leaq (VEC_SIZE * 3)(%rdi, %rax, CHAR_SIZE), %rax ++ ret + +-# ifndef USE_AS_RAWMEMCHR +- subq $(VEC_SIZE * 4), %rdx +- jbe L(last_4x_vec_or_less) +-# endif ++ .p2align 4 ++L(first_vec_x4): ++ tzcntl %eax, %eax ++ leaq (VEC_SIZE * 4)(%rdi, %rax, CHAR_SIZE), %rax ++ ret + +-L(more_4x_vec): ++ .p2align 5 ++L(aligned_more): + /* Check the first 4 * VEC_SIZE. Only one VEC_SIZE at a time + since data is only aligned to VEC_SIZE. */ +- VPCMP $0, (%rdi), %YMMMATCH, %k1 +- kmovd %k1, %eax +- testl %eax, %eax +- jnz L(first_vec_x0) + +- VPCMP $0, VEC_SIZE(%rdi), %YMMMATCH, %k1 +- kmovd %k1, %eax ++# ifndef USE_AS_RAWMEMCHR ++ /* Align data to VEC_SIZE. */ ++L(cross_page_continue): ++ xorl %ecx, %ecx ++ subl %edi, %ecx ++ andq $-VEC_SIZE, %rdi ++ /* esi is for adjusting length to see if near the end. */ ++ leal (VEC_SIZE * 5)(%rdi, %rcx), %esi ++# ifdef USE_AS_WMEMCHR ++ /* NB: Divide bytes by 4 to get the wchar_t count. */ ++ sarl $2, %esi ++# endif ++# else ++ andq $-VEC_SIZE, %rdi ++L(cross_page_continue): ++# endif ++ /* Load first VEC regardless. */ ++ VPCMP $0, (VEC_SIZE)(%rdi), %YMMMATCH, %k0 ++ kmovd %k0, %eax ++# ifndef USE_AS_RAWMEMCHR ++ /* Adjust length. If near end handle specially. */ ++ subq %rsi, %rdx ++ jbe L(last_4x_vec_or_less) ++# endif + testl %eax, %eax + jnz L(first_vec_x1) + +- VPCMP $0, (VEC_SIZE * 2)(%rdi), %YMMMATCH, %k1 +- kmovd %k1, %eax ++ VPCMP $0, (VEC_SIZE * 2)(%rdi), %YMMMATCH, %k0 ++ kmovd %k0, %eax + testl %eax, %eax + jnz L(first_vec_x2) + +- VPCMP $0, (VEC_SIZE * 3)(%rdi), %YMMMATCH, %k1 +- kmovd %k1, %eax ++ VPCMP $0, (VEC_SIZE * 3)(%rdi), %YMMMATCH, %k0 ++ kmovd %k0, %eax + testl %eax, %eax + jnz L(first_vec_x3) + +- addq $(VEC_SIZE * 4), %rdi ++ VPCMP $0, (VEC_SIZE * 4)(%rdi), %YMMMATCH, %k0 ++ kmovd %k0, %eax ++ testl %eax, %eax ++ jnz L(first_vec_x4) ++ + + # ifndef USE_AS_RAWMEMCHR +- subq $(VEC_SIZE * 4), %rdx +- jbe L(last_4x_vec_or_less) +-# endif ++ /* Check if at last CHAR_PER_VEC * 4 length. */ ++ subq $(CHAR_PER_VEC * 4), %rdx ++ jbe L(last_4x_vec_or_less_cmpeq) ++ addq $VEC_SIZE, %rdi + +- /* Align data to 4 * VEC_SIZE. */ +- movq %rdi, %rcx +- andl $(4 * VEC_SIZE - 1), %ecx ++ /* Align data to VEC_SIZE * 4 for the loop and readjust length. ++ */ ++# ifdef USE_AS_WMEMCHR ++ movl %edi, %ecx + andq $-(4 * VEC_SIZE), %rdi +- +-# ifndef USE_AS_RAWMEMCHR +- /* Adjust length. */ ++ andl $(VEC_SIZE * 4 - 1), %ecx ++ /* NB: Divide bytes by 4 to get the wchar_t count. */ ++ sarl $2, %ecx + addq %rcx, %rdx ++# else ++ addq %rdi, %rdx ++ andq $-(4 * VEC_SIZE), %rdi ++ subq %rdi, %rdx ++# endif ++# else ++ addq $VEC_SIZE, %rdi ++ andq $-(4 * VEC_SIZE), %rdi + # endif + ++ vpxorq %XMMZERO, %XMMZERO, %XMMZERO ++ ++ /* Compare 4 * VEC at a time forward. */ + .p2align 4 + L(loop_4x_vec): +- /* Compare 4 * VEC at a time forward. */ +- VPCMP $0, (%rdi), %YMMMATCH, %k1 +- VPCMP $0, VEC_SIZE(%rdi), %YMMMATCH, %k2 +- kord %k1, %k2, %k5 +- VPCMP $0, (VEC_SIZE * 2)(%rdi), %YMMMATCH, %k3 +- VPCMP $0, (VEC_SIZE * 3)(%rdi), %YMMMATCH, %k4 +- +- kord %k3, %k4, %k6 +- kortestd %k5, %k6 +- jnz L(4x_vec_end) +- +- addq $(VEC_SIZE * 4), %rdi +- ++ /* It would be possible to save some instructions using 4x VPCMP ++ but bottleneck on port 5 makes it not woth it. */ ++ VPCMP $4, (VEC_SIZE * 4)(%rdi), %YMMMATCH, %k1 ++ /* xor will set bytes match esi to zero. */ ++ vpxorq (VEC_SIZE * 5)(%rdi), %YMMMATCH, %YMM2 ++ vpxorq (VEC_SIZE * 6)(%rdi), %YMMMATCH, %YMM3 ++ VPCMP $0, (VEC_SIZE * 7)(%rdi), %YMMMATCH, %k3 ++ /* Reduce VEC2 / VEC3 with min and VEC1 with zero mask. */ ++ VPMINU %YMM2, %YMM3, %YMM3 {%k1} {z} ++ VPCMP $0, %YMM3, %YMMZERO, %k2 + # ifdef USE_AS_RAWMEMCHR +- jmp L(loop_4x_vec) ++ subq $-(VEC_SIZE * 4), %rdi ++ kortestd %k2, %k3 ++ jz L(loop_4x_vec) + # else +- subq $(VEC_SIZE * 4), %rdx ++ kortestd %k2, %k3 ++ jnz L(loop_4x_vec_end) ++ ++ subq $-(VEC_SIZE * 4), %rdi ++ ++ subq $(CHAR_PER_VEC * 4), %rdx + ja L(loop_4x_vec) + ++ /* Fall through into less than 4 remaining vectors of length case. ++ */ ++ VPCMP $0, (VEC_SIZE * 4)(%rdi), %YMMMATCH, %k0 ++ kmovd %k0, %eax ++ addq $(VEC_SIZE * 3), %rdi ++ .p2align 4 + L(last_4x_vec_or_less): +- /* Less than 4 * VEC and aligned to VEC_SIZE. */ +- addl $(VEC_SIZE * 2), %edx +- jle L(last_2x_vec) +- +- VPCMP $0, (%rdi), %YMMMATCH, %k1 +- kmovd %k1, %eax ++ /* Check if first VEC contained match. */ + testl %eax, %eax +- jnz L(first_vec_x0) ++ jnz L(first_vec_x1_check) + +- VPCMP $0, VEC_SIZE(%rdi), %YMMMATCH, %k1 +- kmovd %k1, %eax +- testl %eax, %eax +- jnz L(first_vec_x1) ++ /* If remaining length > CHAR_PER_VEC * 2. */ ++ addl $(CHAR_PER_VEC * 2), %edx ++ jg L(last_4x_vec) + +- VPCMP $0, (VEC_SIZE * 2)(%rdi), %YMMMATCH, %k1 +- kmovd %k1, %eax +- testl %eax, %eax ++L(last_2x_vec): ++ /* If remaining length < CHAR_PER_VEC. */ ++ addl $CHAR_PER_VEC, %edx ++ jle L(zero_end) + +- jnz L(first_vec_x2_check) +- subl $VEC_SIZE, %edx +- jle L(zero) ++ /* Check VEC2 and compare any match with remaining length. */ ++ VPCMP $0, (VEC_SIZE * 2)(%rdi), %YMMMATCH, %k0 ++ kmovd %k0, %eax ++ tzcntl %eax, %eax ++ cmpl %eax, %edx ++ jbe L(set_zero_end) ++ leaq (VEC_SIZE * 2)(%rdi, %rax, CHAR_SIZE), %rax ++L(zero_end): ++ ret + +- VPCMP $0, (VEC_SIZE * 3)(%rdi), %YMMMATCH, %k1 +- kmovd %k1, %eax +- testl %eax, %eax + +- jnz L(first_vec_x3_check) ++ .p2align 4 ++L(first_vec_x1_check): ++ tzcntl %eax, %eax ++ /* Adjust length. */ ++ subl $-(CHAR_PER_VEC * 4), %edx ++ /* Check if match within remaining length. */ ++ cmpl %eax, %edx ++ jbe L(set_zero_end) ++ /* NB: Multiply bytes by CHAR_SIZE to get the wchar_t count. */ ++ leaq VEC_SIZE(%rdi, %rax, CHAR_SIZE), %rax ++ ret ++L(set_zero_end): + xorl %eax, %eax + ret + + .p2align 4 +-L(last_2x_vec): +- addl $(VEC_SIZE * 2), %edx +- VPCMP $0, (%rdi), %YMMMATCH, %k1 ++L(loop_4x_vec_end): ++# endif ++ /* rawmemchr will fall through into this if match was found in ++ loop. */ ++ ++ /* k1 has not of matches with VEC1. */ + kmovd %k1, %eax +- testl %eax, %eax ++# ifdef USE_AS_WMEMCHR ++ subl $((1 << CHAR_PER_VEC) - 1), %eax ++# else ++ incl %eax ++# endif ++ jnz L(last_vec_x1_return) + +- jnz L(first_vec_x0_check) +- subl $VEC_SIZE, %edx +- jle L(zero) ++ VPCMP $0, %YMM2, %YMMZERO, %k0 ++ kmovd %k0, %eax ++ testl %eax, %eax ++ jnz L(last_vec_x2_return) + +- VPCMP $0, VEC_SIZE(%rdi), %YMMMATCH, %k1 +- kmovd %k1, %eax ++ kmovd %k2, %eax + testl %eax, %eax +- jnz L(first_vec_x1_check) +- xorl %eax, %eax +- ret ++ jnz L(last_vec_x3_return) + +- .p2align 4 +-L(first_vec_x0_check): ++ kmovd %k3, %eax + tzcntl %eax, %eax +-# ifdef USE_AS_WMEMCHR +- /* NB: Multiply wchar_t count by 4 to get the number of bytes. */ +- sall $2, %eax ++# ifdef USE_AS_RAWMEMCHR ++ leaq (VEC_SIZE * 3)(%rdi, %rax, CHAR_SIZE), %rax ++# else ++ leaq (VEC_SIZE * 7)(%rdi, %rax, CHAR_SIZE), %rax + # endif +- /* Check the end of data. */ +- cmpq %rax, %rdx +- jbe L(zero) +- addq %rdi, %rax + ret + + .p2align 4 +-L(first_vec_x1_check): ++L(last_vec_x1_return): + tzcntl %eax, %eax +-# ifdef USE_AS_WMEMCHR +- /* NB: Multiply wchar_t count by 4 to get the number of bytes. */ +- sall $2, %eax +-# endif +- /* Check the end of data. */ +- cmpq %rax, %rdx +- jbe L(zero) +- addq $VEC_SIZE, %rax ++# ifdef USE_AS_RAWMEMCHR ++# ifdef USE_AS_WMEMCHR ++ /* NB: Multiply bytes by CHAR_SIZE to get the wchar_t count. */ ++ leaq (%rdi, %rax, CHAR_SIZE), %rax ++# else + addq %rdi, %rax +- ret +- +- .p2align 4 +-L(first_vec_x2_check): +- tzcntl %eax, %eax +-# ifdef USE_AS_WMEMCHR +- /* NB: Multiply wchar_t count by 4 to get the number of bytes. */ +- sall $2, %eax ++# endif ++# else ++ /* NB: Multiply bytes by CHAR_SIZE to get the wchar_t count. */ ++ leaq (VEC_SIZE * 4)(%rdi, %rax, CHAR_SIZE), %rax + # endif +- /* Check the end of data. */ +- cmpq %rax, %rdx +- jbe L(zero) +- addq $(VEC_SIZE * 2), %rax +- addq %rdi, %rax + ret + + .p2align 4 +-L(first_vec_x3_check): ++L(last_vec_x2_return): + tzcntl %eax, %eax +-# ifdef USE_AS_WMEMCHR +- /* NB: Multiply wchar_t count by 4 to get the number of bytes. */ +- sall $2, %eax ++# ifdef USE_AS_RAWMEMCHR ++ /* NB: Multiply bytes by CHAR_SIZE to get the wchar_t count. */ ++ leaq VEC_SIZE(%rdi, %rax, CHAR_SIZE), %rax ++# else ++ /* NB: Multiply bytes by CHAR_SIZE to get the wchar_t count. */ ++ leaq (VEC_SIZE * 5)(%rdi, %rax, CHAR_SIZE), %rax + # endif +- /* Check the end of data. */ +- cmpq %rax, %rdx +- jbe L(zero) +- addq $(VEC_SIZE * 3), %rax +- addq %rdi, %rax + ret + + .p2align 4 +-L(zero): +- xorl %eax, %eax +- ret +-# endif +- +- .p2align 4 +-L(first_vec_x0): ++L(last_vec_x3_return): + tzcntl %eax, %eax +-# ifdef USE_AS_WMEMCHR +- /* NB: Multiply wchar_t count by 4 to get the number of bytes. */ +- leaq (%rdi, %rax, 4), %rax ++# ifdef USE_AS_RAWMEMCHR ++ /* NB: Multiply bytes by CHAR_SIZE to get the wchar_t count. */ ++ leaq (VEC_SIZE * 2)(%rdi, %rax, CHAR_SIZE), %rax + # else +- addq %rdi, %rax ++ /* NB: Multiply bytes by CHAR_SIZE to get the wchar_t count. */ ++ leaq (VEC_SIZE * 6)(%rdi, %rax, CHAR_SIZE), %rax + # endif + ret + ++ ++# ifndef USE_AS_RAWMEMCHR ++L(last_4x_vec_or_less_cmpeq): ++ VPCMP $0, (VEC_SIZE * 5)(%rdi), %YMMMATCH, %k0 ++ kmovd %k0, %eax ++ subq $-(VEC_SIZE * 4), %rdi ++ /* Check first VEC regardless. */ ++ testl %eax, %eax ++ jnz L(first_vec_x1_check) ++ ++ /* If remaining length <= CHAR_PER_VEC * 2. */ ++ addl $(CHAR_PER_VEC * 2), %edx ++ jle L(last_2x_vec) ++ + .p2align 4 +-L(first_vec_x1): ++L(last_4x_vec): ++ VPCMP $0, (VEC_SIZE * 2)(%rdi), %YMMMATCH, %k0 ++ kmovd %k0, %eax ++ testl %eax, %eax ++ jnz L(last_vec_x2) ++ ++ ++ VPCMP $0, (VEC_SIZE * 3)(%rdi), %YMMMATCH, %k0 ++ kmovd %k0, %eax ++ /* Create mask for possible matches within remaining length. */ ++# ifdef USE_AS_WMEMCHR ++ movl $((1 << (CHAR_PER_VEC * 2)) - 1), %ecx ++ bzhil %edx, %ecx, %ecx ++# else ++ movq $-1, %rcx ++ bzhiq %rdx, %rcx, %rcx ++# endif ++ /* Test matches in data against length match. */ ++ andl %ecx, %eax ++ jnz L(last_vec_x3) ++ ++ /* if remaining length <= CHAR_PER_VEC * 3 (Note this is after ++ remaining length was found to be > CHAR_PER_VEC * 2. */ ++ subl $CHAR_PER_VEC, %edx ++ jbe L(zero_end2) ++ ++ ++ VPCMP $0, (VEC_SIZE * 4)(%rdi), %YMMMATCH, %k0 ++ kmovd %k0, %eax ++ /* Shift remaining length mask for last VEC. */ ++# ifdef USE_AS_WMEMCHR ++ shrl $CHAR_PER_VEC, %ecx ++# else ++ shrq $CHAR_PER_VEC, %rcx ++# endif ++ andl %ecx, %eax ++ jz L(zero_end2) + tzcntl %eax, %eax +-# ifdef USE_AS_WMEMCHR +- /* NB: Multiply wchar_t count by 4 to get the number of bytes. */ +- leaq VEC_SIZE(%rdi, %rax, 4), %rax +-# else +- addq $VEC_SIZE, %rax +- addq %rdi, %rax +-# endif ++ leaq (VEC_SIZE * 4)(%rdi, %rax, CHAR_SIZE), %rax ++L(zero_end2): + ret + +- .p2align 4 +-L(first_vec_x2): ++L(last_vec_x2): + tzcntl %eax, %eax +-# ifdef USE_AS_WMEMCHR +- /* NB: Multiply wchar_t count by 4 to get the number of bytes. */ +- leaq (VEC_SIZE * 2)(%rdi, %rax, 4), %rax +-# else +- addq $(VEC_SIZE * 2), %rax +- addq %rdi, %rax +-# endif ++ leaq (VEC_SIZE * 2)(%rdi, %rax, CHAR_SIZE), %rax + ret + + .p2align 4 +-L(4x_vec_end): +- kmovd %k1, %eax +- testl %eax, %eax +- jnz L(first_vec_x0) +- kmovd %k2, %eax +- testl %eax, %eax +- jnz L(first_vec_x1) +- kmovd %k3, %eax +- testl %eax, %eax +- jnz L(first_vec_x2) +- kmovd %k4, %eax +- testl %eax, %eax +-L(first_vec_x3): ++L(last_vec_x3): + tzcntl %eax, %eax +-# ifdef USE_AS_WMEMCHR +- /* NB: Multiply wchar_t count by 4 to get the number of bytes. */ +- leaq (VEC_SIZE * 3)(%rdi, %rax, 4), %rax +-# else +- addq $(VEC_SIZE * 3), %rax +- addq %rdi, %rax +-# endif ++ leaq (VEC_SIZE * 3)(%rdi, %rax, CHAR_SIZE), %rax + ret ++# endif + + END (MEMCHR) + #endif +-- +GitLab + diff --git a/SOURCES/glibc-RHEL-15696-27.patch b/SOURCES/glibc-RHEL-15696-27.patch new file mode 100644 index 0000000..9dcf16d --- /dev/null +++ b/SOURCES/glibc-RHEL-15696-27.patch @@ -0,0 +1,30 @@ +From 6ea916adfa0ab9af6e7dc6adcf6f977dfe017835 Mon Sep 17 00:00:00 2001 +From: Alice Xu +Date: Fri, 7 May 2021 19:03:21 -0700 +Subject: [PATCH] x86-64: Fix an unknown vector operation in memchr-evex.S +Content-type: text/plain; charset=UTF-8 + +An unknown vector operation occurred in commit 2a76821c308. Fixed it +by using "ymm{k1}{z}" but not "ymm {k1} {z}". + +Reviewed-by: H.J. Lu +--- + sysdeps/x86_64/multiarch/memchr-evex.S | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/sysdeps/x86_64/multiarch/memchr-evex.S b/sysdeps/x86_64/multiarch/memchr-evex.S +index 81d5cd64..f3fdad4f 100644 +--- a/sysdeps/x86_64/multiarch/memchr-evex.S ++++ b/sysdeps/x86_64/multiarch/memchr-evex.S +@@ -271,7 +271,7 @@ L(loop_4x_vec): + vpxorq (VEC_SIZE * 6)(%rdi), %YMMMATCH, %YMM3 + VPCMP $0, (VEC_SIZE * 7)(%rdi), %YMMMATCH, %k3 + /* Reduce VEC2 / VEC3 with min and VEC1 with zero mask. */ +- VPMINU %YMM2, %YMM3, %YMM3 {%k1} {z} ++ VPMINU %YMM2, %YMM3, %YMM3{%k1}{z} + VPCMP $0, %YMM3, %YMMZERO, %k2 + # ifdef USE_AS_RAWMEMCHR + subq $-(VEC_SIZE * 4), %rdi +-- +GitLab + diff --git a/SOURCES/glibc-RHEL-15696-28.patch b/SOURCES/glibc-RHEL-15696-28.patch new file mode 100644 index 0000000..3063d4d --- /dev/null +++ b/SOURCES/glibc-RHEL-15696-28.patch @@ -0,0 +1,566 @@ +From a0db678071c60b6c47c468d231dd0b3694ba7a98 Mon Sep 17 00:00:00 2001 +From: "H.J. Lu" +Date: Tue, 22 Jun 2021 20:42:10 -0700 +Subject: [PATCH] x86-64: Move strlen.S to multiarch/strlen-vec.S +Content-type: text/plain; charset=UTF-8 + +Since strlen.S contains SSE2 version of strlen/strnlen and SSE4.1 +version of wcslen/wcsnlen, move strlen.S to multiarch/strlen-vec.S +and include multiarch/strlen-vec.S from SSE2 and SSE4.1 variants. +This also removes the unused symbols, __GI___strlen_sse2 and +__GI___wcsnlen_sse4_1. +--- + sysdeps/x86_64/multiarch/strlen-sse2.S | 2 +- + sysdeps/x86_64/multiarch/strlen-vec.S | 257 ++++++++++++++++++++++ + sysdeps/x86_64/multiarch/wcsnlen-sse4_1.S | 2 +- + sysdeps/x86_64/strlen.S | 243 +------------------- + 4 files changed, 262 insertions(+), 242 deletions(-) + create mode 100644 sysdeps/x86_64/multiarch/strlen-vec.S + +Conflicts: + sysdeps/x86_64/strlen.S b/sysdeps/x86_64/strlen.S + (Copyright dates, URL) + +diff --git a/sysdeps/x86_64/multiarch/strlen-sse2.S b/sysdeps/x86_64/multiarch/strlen-sse2.S +index 7bc57b8d..449c8a7f 100644 +--- a/sysdeps/x86_64/multiarch/strlen-sse2.S ++++ b/sysdeps/x86_64/multiarch/strlen-sse2.S +@@ -20,4 +20,4 @@ + # define strlen __strlen_sse2 + #endif + +-#include "../strlen.S" ++#include "strlen-vec.S" +diff --git a/sysdeps/x86_64/multiarch/strlen-vec.S b/sysdeps/x86_64/multiarch/strlen-vec.S +new file mode 100644 +index 00000000..8f660bb9 +--- /dev/null ++++ b/sysdeps/x86_64/multiarch/strlen-vec.S +@@ -0,0 +1,257 @@ ++/* SSE2 version of strlen and SSE4.1 version of wcslen. ++ Copyright (C) 2012-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 AS_WCSLEN ++# define PMINU pminud ++# define PCMPEQ pcmpeqd ++# define SHIFT_RETURN shrq $2, %rax ++#else ++# define PMINU pminub ++# define PCMPEQ pcmpeqb ++# define SHIFT_RETURN ++#endif ++ ++/* Long lived register in strlen(s), strnlen(s, n) are: ++ ++ %xmm3 - zero ++ %rdi - s ++ %r10 (s+n) & (~(64-1)) ++ %r11 s+n ++*/ ++ ++ ++.text ++ENTRY(strlen) ++ ++/* Test 64 bytes from %rax for zero. Save result as bitmask in %rdx. */ ++#define FIND_ZERO \ ++ PCMPEQ (%rax), %xmm0; \ ++ PCMPEQ 16(%rax), %xmm1; \ ++ PCMPEQ 32(%rax), %xmm2; \ ++ PCMPEQ 48(%rax), %xmm3; \ ++ pmovmskb %xmm0, %esi; \ ++ pmovmskb %xmm1, %edx; \ ++ pmovmskb %xmm2, %r8d; \ ++ pmovmskb %xmm3, %ecx; \ ++ salq $16, %rdx; \ ++ salq $16, %rcx; \ ++ orq %rsi, %rdx; \ ++ orq %r8, %rcx; \ ++ salq $32, %rcx; \ ++ orq %rcx, %rdx; ++ ++#ifdef AS_STRNLEN ++/* Do not read anything when n==0. */ ++ test %RSI_LP, %RSI_LP ++ jne L(n_nonzero) ++ xor %rax, %rax ++ ret ++L(n_nonzero): ++# ifdef AS_WCSLEN ++ shl $2, %RSI_LP ++# endif ++ ++/* Initialize long lived registers. */ ++ ++ add %RDI_LP, %RSI_LP ++ mov %RSI_LP, %R10_LP ++ and $-64, %R10_LP ++ mov %RSI_LP, %R11_LP ++#endif ++ ++ pxor %xmm0, %xmm0 ++ pxor %xmm1, %xmm1 ++ pxor %xmm2, %xmm2 ++ pxor %xmm3, %xmm3 ++ movq %rdi, %rax ++ movq %rdi, %rcx ++ andq $4095, %rcx ++/* Offsets 4032-4047 will be aligned into 4032 thus fit into page. */ ++ cmpq $4047, %rcx ++/* We cannot unify this branching as it would be ~6 cycles slower. */ ++ ja L(cross_page) ++ ++#ifdef AS_STRNLEN ++/* Test if end is among first 64 bytes. */ ++# define STRNLEN_PROLOG \ ++ mov %r11, %rsi; \ ++ subq %rax, %rsi; \ ++ andq $-64, %rax; \ ++ testq $-64, %rsi; \ ++ je L(strnlen_ret) ++#else ++# define STRNLEN_PROLOG andq $-64, %rax; ++#endif ++ ++/* Ignore bits in mask that come before start of string. */ ++#define PROLOG(lab) \ ++ movq %rdi, %rcx; \ ++ xorq %rax, %rcx; \ ++ STRNLEN_PROLOG; \ ++ sarq %cl, %rdx; \ ++ test %rdx, %rdx; \ ++ je L(lab); \ ++ bsfq %rdx, %rax; \ ++ SHIFT_RETURN; \ ++ ret ++ ++#ifdef AS_STRNLEN ++ andq $-16, %rax ++ FIND_ZERO ++#else ++ /* Test first 16 bytes unaligned. */ ++ movdqu (%rax), %xmm4 ++ PCMPEQ %xmm0, %xmm4 ++ pmovmskb %xmm4, %edx ++ test %edx, %edx ++ je L(next48_bytes) ++ bsf %edx, %eax /* If eax is zeroed 16bit bsf can be used. */ ++ SHIFT_RETURN ++ ret ++ ++L(next48_bytes): ++/* Same as FIND_ZERO except we do not check first 16 bytes. */ ++ andq $-16, %rax ++ PCMPEQ 16(%rax), %xmm1 ++ PCMPEQ 32(%rax), %xmm2 ++ PCMPEQ 48(%rax), %xmm3 ++ pmovmskb %xmm1, %edx ++ pmovmskb %xmm2, %r8d ++ pmovmskb %xmm3, %ecx ++ salq $16, %rdx ++ salq $16, %rcx ++ orq %r8, %rcx ++ salq $32, %rcx ++ orq %rcx, %rdx ++#endif ++ ++ /* When no zero byte is found xmm1-3 are zero so we do not have to ++ zero them. */ ++ PROLOG(loop) ++ ++ .p2align 4 ++L(cross_page): ++ andq $-64, %rax ++ FIND_ZERO ++ PROLOG(loop_init) ++ ++#ifdef AS_STRNLEN ++/* We must do this check to correctly handle strnlen (s, -1). */ ++L(strnlen_ret): ++ bts %rsi, %rdx ++ sarq %cl, %rdx ++ test %rdx, %rdx ++ je L(loop_init) ++ bsfq %rdx, %rax ++ SHIFT_RETURN ++ ret ++#endif ++ .p2align 4 ++L(loop_init): ++ pxor %xmm1, %xmm1 ++ pxor %xmm2, %xmm2 ++ pxor %xmm3, %xmm3 ++#ifdef AS_STRNLEN ++ .p2align 4 ++L(loop): ++ ++ addq $64, %rax ++ cmpq %rax, %r10 ++ je L(exit_end) ++ ++ movdqa (%rax), %xmm0 ++ PMINU 16(%rax), %xmm0 ++ PMINU 32(%rax), %xmm0 ++ PMINU 48(%rax), %xmm0 ++ PCMPEQ %xmm3, %xmm0 ++ pmovmskb %xmm0, %edx ++ testl %edx, %edx ++ jne L(exit) ++ jmp L(loop) ++ ++ .p2align 4 ++L(exit_end): ++ cmp %rax, %r11 ++ je L(first) /* Do not read when end is at page boundary. */ ++ pxor %xmm0, %xmm0 ++ FIND_ZERO ++ ++L(first): ++ bts %r11, %rdx ++ bsfq %rdx, %rdx ++ addq %rdx, %rax ++ subq %rdi, %rax ++ SHIFT_RETURN ++ ret ++ ++ .p2align 4 ++L(exit): ++ pxor %xmm0, %xmm0 ++ FIND_ZERO ++ ++ bsfq %rdx, %rdx ++ addq %rdx, %rax ++ subq %rdi, %rax ++ SHIFT_RETURN ++ ret ++ ++#else ++ ++ /* Main loop. Unrolled twice to improve L2 cache performance on core2. */ ++ .p2align 4 ++L(loop): ++ ++ movdqa 64(%rax), %xmm0 ++ PMINU 80(%rax), %xmm0 ++ PMINU 96(%rax), %xmm0 ++ PMINU 112(%rax), %xmm0 ++ PCMPEQ %xmm3, %xmm0 ++ pmovmskb %xmm0, %edx ++ testl %edx, %edx ++ jne L(exit64) ++ ++ subq $-128, %rax ++ ++ movdqa (%rax), %xmm0 ++ PMINU 16(%rax), %xmm0 ++ PMINU 32(%rax), %xmm0 ++ PMINU 48(%rax), %xmm0 ++ PCMPEQ %xmm3, %xmm0 ++ pmovmskb %xmm0, %edx ++ testl %edx, %edx ++ jne L(exit0) ++ jmp L(loop) ++ ++ .p2align 4 ++L(exit64): ++ addq $64, %rax ++L(exit0): ++ pxor %xmm0, %xmm0 ++ FIND_ZERO ++ ++ bsfq %rdx, %rdx ++ addq %rdx, %rax ++ subq %rdi, %rax ++ SHIFT_RETURN ++ ret ++ ++#endif ++ ++END(strlen) +diff --git a/sysdeps/x86_64/multiarch/wcsnlen-sse4_1.S b/sysdeps/x86_64/multiarch/wcsnlen-sse4_1.S +index a8cab0cb..5fa51fe0 100644 +--- a/sysdeps/x86_64/multiarch/wcsnlen-sse4_1.S ++++ b/sysdeps/x86_64/multiarch/wcsnlen-sse4_1.S +@@ -2,4 +2,4 @@ + #define AS_STRNLEN + #define strlen __wcsnlen_sse4_1 + +-#include "../strlen.S" ++#include "strlen-vec.S" +diff --git a/sysdeps/x86_64/strlen.S b/sysdeps/x86_64/strlen.S +index f845f3d4..ad047d84 100644 +--- a/sysdeps/x86_64/strlen.S ++++ b/sysdeps/x86_64/strlen.S +@@ -1,5 +1,5 @@ +-/* SSE2 version of strlen/wcslen. +- Copyright (C) 2012-2018 Free Software Foundation, Inc. ++/* SSE2 version of strlen. ++ 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 +@@ -16,243 +16,6 @@ + License along with the GNU C Library; if not, see + . */ + +-#include ++#include "multiarch/strlen-vec.S" + +-#ifdef AS_WCSLEN +-# define PMINU pminud +-# define PCMPEQ pcmpeqd +-# define SHIFT_RETURN shrq $2, %rax +-#else +-# define PMINU pminub +-# define PCMPEQ pcmpeqb +-# define SHIFT_RETURN +-#endif +- +-/* Long lived register in strlen(s), strnlen(s, n) are: +- +- %xmm3 - zero +- %rdi - s +- %r10 (s+n) & (~(64-1)) +- %r11 s+n +-*/ +- +- +-.text +-ENTRY(strlen) +- +-/* Test 64 bytes from %rax for zero. Save result as bitmask in %rdx. */ +-#define FIND_ZERO \ +- PCMPEQ (%rax), %xmm0; \ +- PCMPEQ 16(%rax), %xmm1; \ +- PCMPEQ 32(%rax), %xmm2; \ +- PCMPEQ 48(%rax), %xmm3; \ +- pmovmskb %xmm0, %esi; \ +- pmovmskb %xmm1, %edx; \ +- pmovmskb %xmm2, %r8d; \ +- pmovmskb %xmm3, %ecx; \ +- salq $16, %rdx; \ +- salq $16, %rcx; \ +- orq %rsi, %rdx; \ +- orq %r8, %rcx; \ +- salq $32, %rcx; \ +- orq %rcx, %rdx; +- +-#ifdef AS_STRNLEN +-/* Do not read anything when n==0. */ +- test %RSI_LP, %RSI_LP +- jne L(n_nonzero) +- xor %rax, %rax +- ret +-L(n_nonzero): +-# ifdef AS_WCSLEN +- shl $2, %RSI_LP +-# endif +- +-/* Initialize long lived registers. */ +- +- add %RDI_LP, %RSI_LP +- mov %RSI_LP, %R10_LP +- and $-64, %R10_LP +- mov %RSI_LP, %R11_LP +-#endif +- +- pxor %xmm0, %xmm0 +- pxor %xmm1, %xmm1 +- pxor %xmm2, %xmm2 +- pxor %xmm3, %xmm3 +- movq %rdi, %rax +- movq %rdi, %rcx +- andq $4095, %rcx +-/* Offsets 4032-4047 will be aligned into 4032 thus fit into page. */ +- cmpq $4047, %rcx +-/* We cannot unify this branching as it would be ~6 cycles slower. */ +- ja L(cross_page) +- +-#ifdef AS_STRNLEN +-/* Test if end is among first 64 bytes. */ +-# define STRNLEN_PROLOG \ +- mov %r11, %rsi; \ +- subq %rax, %rsi; \ +- andq $-64, %rax; \ +- testq $-64, %rsi; \ +- je L(strnlen_ret) +-#else +-# define STRNLEN_PROLOG andq $-64, %rax; +-#endif +- +-/* Ignore bits in mask that come before start of string. */ +-#define PROLOG(lab) \ +- movq %rdi, %rcx; \ +- xorq %rax, %rcx; \ +- STRNLEN_PROLOG; \ +- sarq %cl, %rdx; \ +- test %rdx, %rdx; \ +- je L(lab); \ +- bsfq %rdx, %rax; \ +- SHIFT_RETURN; \ +- ret +- +-#ifdef AS_STRNLEN +- andq $-16, %rax +- FIND_ZERO +-#else +- /* Test first 16 bytes unaligned. */ +- movdqu (%rax), %xmm4 +- PCMPEQ %xmm0, %xmm4 +- pmovmskb %xmm4, %edx +- test %edx, %edx +- je L(next48_bytes) +- bsf %edx, %eax /* If eax is zeroed 16bit bsf can be used. */ +- SHIFT_RETURN +- ret +- +-L(next48_bytes): +-/* Same as FIND_ZERO except we do not check first 16 bytes. */ +- andq $-16, %rax +- PCMPEQ 16(%rax), %xmm1 +- PCMPEQ 32(%rax), %xmm2 +- PCMPEQ 48(%rax), %xmm3 +- pmovmskb %xmm1, %edx +- pmovmskb %xmm2, %r8d +- pmovmskb %xmm3, %ecx +- salq $16, %rdx +- salq $16, %rcx +- orq %r8, %rcx +- salq $32, %rcx +- orq %rcx, %rdx +-#endif +- +- /* When no zero byte is found xmm1-3 are zero so we do not have to +- zero them. */ +- PROLOG(loop) +- +- .p2align 4 +-L(cross_page): +- andq $-64, %rax +- FIND_ZERO +- PROLOG(loop_init) +- +-#ifdef AS_STRNLEN +-/* We must do this check to correctly handle strnlen (s, -1). */ +-L(strnlen_ret): +- bts %rsi, %rdx +- sarq %cl, %rdx +- test %rdx, %rdx +- je L(loop_init) +- bsfq %rdx, %rax +- SHIFT_RETURN +- ret +-#endif +- .p2align 4 +-L(loop_init): +- pxor %xmm1, %xmm1 +- pxor %xmm2, %xmm2 +- pxor %xmm3, %xmm3 +-#ifdef AS_STRNLEN +- .p2align 4 +-L(loop): +- +- addq $64, %rax +- cmpq %rax, %r10 +- je L(exit_end) +- +- movdqa (%rax), %xmm0 +- PMINU 16(%rax), %xmm0 +- PMINU 32(%rax), %xmm0 +- PMINU 48(%rax), %xmm0 +- PCMPEQ %xmm3, %xmm0 +- pmovmskb %xmm0, %edx +- testl %edx, %edx +- jne L(exit) +- jmp L(loop) +- +- .p2align 4 +-L(exit_end): +- cmp %rax, %r11 +- je L(first) /* Do not read when end is at page boundary. */ +- pxor %xmm0, %xmm0 +- FIND_ZERO +- +-L(first): +- bts %r11, %rdx +- bsfq %rdx, %rdx +- addq %rdx, %rax +- subq %rdi, %rax +- SHIFT_RETURN +- ret +- +- .p2align 4 +-L(exit): +- pxor %xmm0, %xmm0 +- FIND_ZERO +- +- bsfq %rdx, %rdx +- addq %rdx, %rax +- subq %rdi, %rax +- SHIFT_RETURN +- ret +- +-#else +- +- /* Main loop. Unrolled twice to improve L2 cache performance on core2. */ +- .p2align 4 +-L(loop): +- +- movdqa 64(%rax), %xmm0 +- PMINU 80(%rax), %xmm0 +- PMINU 96(%rax), %xmm0 +- PMINU 112(%rax), %xmm0 +- PCMPEQ %xmm3, %xmm0 +- pmovmskb %xmm0, %edx +- testl %edx, %edx +- jne L(exit64) +- +- subq $-128, %rax +- +- movdqa (%rax), %xmm0 +- PMINU 16(%rax), %xmm0 +- PMINU 32(%rax), %xmm0 +- PMINU 48(%rax), %xmm0 +- PCMPEQ %xmm3, %xmm0 +- pmovmskb %xmm0, %edx +- testl %edx, %edx +- jne L(exit0) +- jmp L(loop) +- +- .p2align 4 +-L(exit64): +- addq $64, %rax +-L(exit0): +- pxor %xmm0, %xmm0 +- FIND_ZERO +- +- bsfq %rdx, %rdx +- addq %rdx, %rax +- subq %rdi, %rax +- SHIFT_RETURN +- ret +- +-#endif +- +-END(strlen) + libc_hidden_builtin_def (strlen) +-- +GitLab + diff --git a/SOURCES/glibc-RHEL-15696-29.patch b/SOURCES/glibc-RHEL-15696-29.patch new file mode 100644 index 0000000..112821a --- /dev/null +++ b/SOURCES/glibc-RHEL-15696-29.patch @@ -0,0 +1,181 @@ +From 6f573a27b6c8b4236445810a44660612323f5a73 Mon Sep 17 00:00:00 2001 +From: Noah Goldstein +Date: Wed, 23 Jun 2021 01:19:34 -0400 +Subject: [PATCH] x86-64: Add wcslen optimize for sse4.1 +Content-type: text/plain; charset=UTF-8 + +No bug. This comment adds the ifunc / build infrastructure +necessary for wcslen to prefer the sse4.1 implementation +in strlen-vec.S. test-wcslen.c is passing. + +Signed-off-by: Noah Goldstein +Reviewed-by: H.J. Lu +--- + sysdeps/x86_64/multiarch/Makefile | 4 +- + sysdeps/x86_64/multiarch/ifunc-impl-list.c | 3 ++ + sysdeps/x86_64/multiarch/ifunc-wcslen.h | 52 ++++++++++++++++++++++ + sysdeps/x86_64/multiarch/wcslen-sse4_1.S | 4 ++ + sysdeps/x86_64/multiarch/wcslen.c | 2 +- + sysdeps/x86_64/multiarch/wcsnlen.c | 34 +------------- + 6 files changed, 63 insertions(+), 36 deletions(-) + create mode 100644 sysdeps/x86_64/multiarch/ifunc-wcslen.h + create mode 100644 sysdeps/x86_64/multiarch/wcslen-sse4_1.S + +diff --git a/sysdeps/x86_64/multiarch/Makefile b/sysdeps/x86_64/multiarch/Makefile +index 491c7698..65fde4eb 100644 +--- a/sysdeps/x86_64/multiarch/Makefile ++++ b/sysdeps/x86_64/multiarch/Makefile +@@ -93,8 +93,8 @@ sysdep_routines += wmemcmp-sse4 wmemcmp-ssse3 wmemcmp-c \ + wcscpy-ssse3 wcscpy-c \ + wcschr-sse2 wcschr-avx2 \ + wcsrchr-sse2 wcsrchr-avx2 \ +- wcsnlen-sse4_1 wcsnlen-c \ +- wcslen-sse2 wcslen-avx2 wcsnlen-avx2 \ ++ wcslen-sse2 wcslen-sse4_1 wcslen-avx2 \ ++ wcsnlen-c wcsnlen-sse4_1 wcsnlen-avx2 \ + wcschr-avx2-rtm \ + wcscmp-avx2-rtm \ + wcslen-avx2-rtm \ +diff --git a/sysdeps/x86_64/multiarch/ifunc-impl-list.c b/sysdeps/x86_64/multiarch/ifunc-impl-list.c +index f1a6460a..580913ca 100644 +--- a/sysdeps/x86_64/multiarch/ifunc-impl-list.c ++++ b/sysdeps/x86_64/multiarch/ifunc-impl-list.c +@@ -657,6 +657,9 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + && CPU_FEATURE_USABLE (AVX512BW) + && CPU_FEATURE_USABLE (BMI2)), + __wcslen_evex) ++ IFUNC_IMPL_ADD (array, i, wcsnlen, ++ CPU_FEATURE_USABLE (SSE4_1), ++ __wcsnlen_sse4_1) + IFUNC_IMPL_ADD (array, i, wcslen, 1, __wcslen_sse2)) + + /* Support sysdeps/x86_64/multiarch/wcsnlen.c. */ +diff --git a/sysdeps/x86_64/multiarch/ifunc-wcslen.h b/sysdeps/x86_64/multiarch/ifunc-wcslen.h +new file mode 100644 +index 00000000..39e33473 +--- /dev/null ++++ b/sysdeps/x86_64/multiarch/ifunc-wcslen.h +@@ -0,0 +1,52 @@ ++/* Common definition for ifunc selections for wcslen and wcsnlen ++ All versions must be listed in ifunc-impl-list.c. ++ Copyright (C) 2017-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 ++ ++extern __typeof (REDIRECT_NAME) OPTIMIZE (sse2) attribute_hidden; ++extern __typeof (REDIRECT_NAME) OPTIMIZE (sse4_1) attribute_hidden; ++extern __typeof (REDIRECT_NAME) OPTIMIZE (avx2) attribute_hidden; ++extern __typeof (REDIRECT_NAME) OPTIMIZE (avx2_rtm) attribute_hidden; ++extern __typeof (REDIRECT_NAME) OPTIMIZE (evex) attribute_hidden; ++ ++static inline void * ++IFUNC_SELECTOR (void) ++{ ++ const struct cpu_features* cpu_features = __get_cpu_features (); ++ ++ if (CPU_FEATURE_USABLE_P (cpu_features, AVX2) ++ && CPU_FEATURE_USABLE_P (cpu_features, BMI2) ++ && CPU_FEATURES_ARCH_P (cpu_features, AVX_Fast_Unaligned_Load)) ++ { ++ if (CPU_FEATURE_USABLE_P (cpu_features, AVX512VL) ++ && CPU_FEATURE_USABLE_P (cpu_features, AVX512BW)) ++ return OPTIMIZE (evex); ++ ++ if (CPU_FEATURE_USABLE_P (cpu_features, RTM)) ++ return OPTIMIZE (avx2_rtm); ++ ++ if (!CPU_FEATURES_ARCH_P (cpu_features, Prefer_No_VZEROUPPER)) ++ return OPTIMIZE (avx2); ++ } ++ ++ if (CPU_FEATURE_USABLE_P (cpu_features, SSE4_1)) ++ return OPTIMIZE (sse4_1); ++ ++ return OPTIMIZE (sse2); ++} +diff --git a/sysdeps/x86_64/multiarch/wcslen-sse4_1.S b/sysdeps/x86_64/multiarch/wcslen-sse4_1.S +new file mode 100644 +index 00000000..7e62621a +--- /dev/null ++++ b/sysdeps/x86_64/multiarch/wcslen-sse4_1.S +@@ -0,0 +1,4 @@ ++#define AS_WCSLEN ++#define strlen __wcslen_sse4_1 ++ ++#include "strlen-vec.S" +diff --git a/sysdeps/x86_64/multiarch/wcslen.c b/sysdeps/x86_64/multiarch/wcslen.c +index 6d06e47c..3b04b75b 100644 +--- a/sysdeps/x86_64/multiarch/wcslen.c ++++ b/sysdeps/x86_64/multiarch/wcslen.c +@@ -24,7 +24,7 @@ + # undef __wcslen + + # define SYMBOL_NAME wcslen +-# include "ifunc-avx2.h" ++# include "ifunc-wcslen.h" + + libc_ifunc_redirected (__redirect_wcslen, __wcslen, IFUNC_SELECTOR ()); + weak_alias (__wcslen, wcslen); +diff --git a/sysdeps/x86_64/multiarch/wcsnlen.c b/sysdeps/x86_64/multiarch/wcsnlen.c +index 20b731ae..06736410 100644 +--- a/sysdeps/x86_64/multiarch/wcsnlen.c ++++ b/sysdeps/x86_64/multiarch/wcsnlen.c +@@ -24,39 +24,7 @@ + # undef __wcsnlen + + # define SYMBOL_NAME wcsnlen +-# include +- +-extern __typeof (REDIRECT_NAME) OPTIMIZE (sse2) attribute_hidden; +-extern __typeof (REDIRECT_NAME) OPTIMIZE (sse4_1) attribute_hidden; +-extern __typeof (REDIRECT_NAME) OPTIMIZE (avx2) attribute_hidden; +-extern __typeof (REDIRECT_NAME) OPTIMIZE (avx2_rtm) attribute_hidden; +-extern __typeof (REDIRECT_NAME) OPTIMIZE (evex) attribute_hidden; +- +-static inline void * +-IFUNC_SELECTOR (void) +-{ +- const struct cpu_features* cpu_features = __get_cpu_features (); +- +- if (CPU_FEATURE_USABLE_P (cpu_features, AVX2) +- && CPU_FEATURES_ARCH_P (cpu_features, AVX_Fast_Unaligned_Load)) +- { +- if (CPU_FEATURE_USABLE_P (cpu_features, AVX512VL) +- && CPU_FEATURE_USABLE_P (cpu_features, AVX512BW) +- && CPU_FEATURE_USABLE_P (cpu_features, BMI2)) +- return OPTIMIZE (evex); +- +- if (CPU_FEATURE_USABLE_P (cpu_features, RTM)) +- return OPTIMIZE (avx2_rtm); +- +- if (!CPU_FEATURES_ARCH_P (cpu_features, Prefer_No_VZEROUPPER)) +- return OPTIMIZE (avx2); +- } +- +- if (CPU_FEATURE_USABLE_P (cpu_features, SSE4_1)) +- return OPTIMIZE (sse4_1); +- +- return OPTIMIZE (sse2); +-} ++# include "ifunc-wcslen.h" + + libc_ifunc_redirected (__redirect_wcsnlen, __wcsnlen, IFUNC_SELECTOR ()); + weak_alias (__wcsnlen, wcsnlen); +-- +GitLab + diff --git a/SOURCES/glibc-RHEL-15696-3.patch b/SOURCES/glibc-RHEL-15696-3.patch new file mode 100644 index 0000000..8f5093c --- /dev/null +++ b/SOURCES/glibc-RHEL-15696-3.patch @@ -0,0 +1,396 @@ +From 231c56760c1e2ded21ad96bbb860b1f08c556c7a Mon Sep 17 00:00:00 2001 +From: "H.J. Lu" +Date: Mon, 21 Jan 2019 11:27:25 -0800 +Subject: [PATCH] x86-64 memcpy: Properly handle the length parameter [BZ# + 24097] +Content-type: text/plain; charset=UTF-8 + +On x32, the size_t parameter may be passed in the lower 32 bits of a +64-bit register with the non-zero upper 32 bits. The string/memory +functions written in assembly can only use the lower 32 bits of a +64-bit register as length or must clear the upper 32 bits before using +the full 64-bit register for length. + +This pach fixes memcpy for x32. Tested on x86-64 and x32. On x86-64, +libc.so is the same with and withou the fix. + + [BZ# 24097] + CVE-2019-6488 + * sysdeps/x86_64/multiarch/memcpy-ssse3-back.S: Use RDX_LP for + length. Clear the upper 32 bits of RDX register. + * sysdeps/x86_64/multiarch/memcpy-ssse3.S: Likewise. + * sysdeps/x86_64/multiarch/memmove-avx512-no-vzeroupper.S: + Likewise. + * sysdeps/x86_64/multiarch/memmove-vec-unaligned-erms.S: + Likewise. + * sysdeps/x86_64/x32/Makefile (tests): Add tst-size_t-memcpy. + tst-size_t-wmemchr. + * sysdeps/x86_64/x32/tst-size_t-memcpy.c: New file. +--- + sysdeps/x86_64/multiarch/memcpy-ssse3-back.S | 17 ++++-- + sysdeps/x86_64/multiarch/memcpy-ssse3.S | 17 ++++-- + .../multiarch/memmove-avx512-no-vzeroupper.S | 16 +++-- + .../multiarch/memmove-vec-unaligned-erms.S | 54 +++++++++-------- + sysdeps/x86_64/x32/Makefile | 2 +- + sysdeps/x86_64/x32/tst-size_t-memcpy.c | 58 +++++++++++++++++++ + 6 files changed, 122 insertions(+), 42 deletions(-) + create mode 100644 sysdeps/x86_64/x32/tst-size_t-memcpy.c + +Conflicts: + ChangeLog + (removed) + +diff --git a/sysdeps/x86_64/multiarch/memcpy-ssse3-back.S b/sysdeps/x86_64/multiarch/memcpy-ssse3-back.S +index 3cd11233..568eebd3 100644 +--- a/sysdeps/x86_64/multiarch/memcpy-ssse3-back.S ++++ b/sysdeps/x86_64/multiarch/memcpy-ssse3-back.S +@@ -45,28 +45,33 @@ + .section .text.ssse3,"ax",@progbits + #if !defined USE_AS_MEMPCPY && !defined USE_AS_MEMMOVE + ENTRY (MEMPCPY_CHK) +- cmpq %rdx, %rcx ++ cmp %RDX_LP, %RCX_LP + jb HIDDEN_JUMPTARGET (__chk_fail) + END (MEMPCPY_CHK) + + ENTRY (MEMPCPY) +- movq %rdi, %rax +- addq %rdx, %rax ++ mov %RDI_LP, %RAX_LP ++ add %RDX_LP, %RAX_LP + jmp L(start) + END (MEMPCPY) + #endif + + #if !defined USE_AS_BCOPY + ENTRY (MEMCPY_CHK) +- cmpq %rdx, %rcx ++ cmp %RDX_LP, %RCX_LP + jb HIDDEN_JUMPTARGET (__chk_fail) + END (MEMCPY_CHK) + #endif + + ENTRY (MEMCPY) +- mov %rdi, %rax ++ mov %RDI_LP, %RAX_LP + #ifdef USE_AS_MEMPCPY +- add %rdx, %rax ++ add %RDX_LP, %RAX_LP ++#endif ++ ++#ifdef __ILP32__ ++ /* Clear the upper 32 bits. */ ++ mov %edx, %edx + #endif + + #ifdef USE_AS_MEMMOVE +diff --git a/sysdeps/x86_64/multiarch/memcpy-ssse3.S b/sysdeps/x86_64/multiarch/memcpy-ssse3.S +index 0240bfa3..0bd5ee99 100644 +--- a/sysdeps/x86_64/multiarch/memcpy-ssse3.S ++++ b/sysdeps/x86_64/multiarch/memcpy-ssse3.S +@@ -45,28 +45,33 @@ + .section .text.ssse3,"ax",@progbits + #if !defined USE_AS_MEMPCPY && !defined USE_AS_MEMMOVE + ENTRY (MEMPCPY_CHK) +- cmpq %rdx, %rcx ++ cmp %RDX_LP, %RCX_LP + jb HIDDEN_JUMPTARGET (__chk_fail) + END (MEMPCPY_CHK) + + ENTRY (MEMPCPY) +- movq %rdi, %rax +- addq %rdx, %rax ++ mov %RDI_LP, %RAX_LP ++ add %RDX_LP, %RAX_LP + jmp L(start) + END (MEMPCPY) + #endif + + #if !defined USE_AS_BCOPY + ENTRY (MEMCPY_CHK) +- cmpq %rdx, %rcx ++ cmp %RDX_LP, %RCX_LP + jb HIDDEN_JUMPTARGET (__chk_fail) + END (MEMCPY_CHK) + #endif + + ENTRY (MEMCPY) +- mov %rdi, %rax ++ mov %RDI_LP, %RAX_LP + #ifdef USE_AS_MEMPCPY +- add %rdx, %rax ++ add %RDX_LP, %RAX_LP ++#endif ++ ++#ifdef __ILP32__ ++ /* Clear the upper 32 bits. */ ++ mov %edx, %edx + #endif + + #ifdef USE_AS_MEMMOVE +diff --git a/sysdeps/x86_64/multiarch/memmove-avx512-no-vzeroupper.S b/sysdeps/x86_64/multiarch/memmove-avx512-no-vzeroupper.S +index effc3ac2..6ca2bbc9 100644 +--- a/sysdeps/x86_64/multiarch/memmove-avx512-no-vzeroupper.S ++++ b/sysdeps/x86_64/multiarch/memmove-avx512-no-vzeroupper.S +@@ -24,27 +24,31 @@ + + .section .text.avx512,"ax",@progbits + ENTRY (__mempcpy_chk_avx512_no_vzeroupper) +- cmpq %rdx, %rcx ++ cmp %RDX_LP, %RCX_LP + jb HIDDEN_JUMPTARGET (__chk_fail) + END (__mempcpy_chk_avx512_no_vzeroupper) + + ENTRY (__mempcpy_avx512_no_vzeroupper) +- movq %rdi, %rax +- addq %rdx, %rax ++ mov %RDI_LP, %RAX_LP ++ add %RDX_LP, %RAX_LP + jmp L(start) + END (__mempcpy_avx512_no_vzeroupper) + + ENTRY (__memmove_chk_avx512_no_vzeroupper) +- cmpq %rdx, %rcx ++ cmp %RDX_LP, %RCX_LP + jb HIDDEN_JUMPTARGET (__chk_fail) + END (__memmove_chk_avx512_no_vzeroupper) + + ENTRY (__memmove_avx512_no_vzeroupper) +- mov %rdi, %rax ++ mov %RDI_LP, %RAX_LP + # ifdef USE_AS_MEMPCPY +- add %rdx, %rax ++ add %RDX_LP, %RAX_LP + # endif + L(start): ++# ifdef __ILP32__ ++ /* Clear the upper 32 bits. */ ++ mov %edx, %edx ++# endif + lea (%rsi, %rdx), %rcx + lea (%rdi, %rdx), %r9 + cmp $512, %rdx +diff --git a/sysdeps/x86_64/multiarch/memmove-vec-unaligned-erms.S b/sysdeps/x86_64/multiarch/memmove-vec-unaligned-erms.S +index c952576c..274aa1c7 100644 +--- a/sysdeps/x86_64/multiarch/memmove-vec-unaligned-erms.S ++++ b/sysdeps/x86_64/multiarch/memmove-vec-unaligned-erms.S +@@ -95,20 +95,20 @@ + .section SECTION(.text),"ax",@progbits + #if defined SHARED && IS_IN (libc) + ENTRY (MEMMOVE_CHK_SYMBOL (__mempcpy_chk, unaligned)) +- cmpq %rdx, %rcx ++ cmp %RDX_LP, %RCX_LP + jb HIDDEN_JUMPTARGET (__chk_fail) + END (MEMMOVE_CHK_SYMBOL (__mempcpy_chk, unaligned)) + #endif + + ENTRY (MEMPCPY_SYMBOL (__mempcpy, unaligned)) +- movq %rdi, %rax +- addq %rdx, %rax ++ mov %RDI_LP, %RAX_LP ++ add %RDX_LP, %RAX_LP + jmp L(start) + END (MEMPCPY_SYMBOL (__mempcpy, unaligned)) + + #if defined SHARED && IS_IN (libc) + ENTRY (MEMMOVE_CHK_SYMBOL (__memmove_chk, unaligned)) +- cmpq %rdx, %rcx ++ cmp %RDX_LP, %RCX_LP + jb HIDDEN_JUMPTARGET (__chk_fail) + END (MEMMOVE_CHK_SYMBOL (__memmove_chk, unaligned)) + #endif +@@ -116,9 +116,13 @@ END (MEMMOVE_CHK_SYMBOL (__memmove_chk, unaligned)) + ENTRY (MEMMOVE_SYMBOL (__memmove, unaligned)) + movq %rdi, %rax + L(start): +- cmpq $VEC_SIZE, %rdx ++# ifdef __ILP32__ ++ /* Clear the upper 32 bits. */ ++ movl %edx, %edx ++# endif ++ cmp $VEC_SIZE, %RDX_LP + jb L(less_vec) +- cmpq $(VEC_SIZE * 2), %rdx ++ cmp $(VEC_SIZE * 2), %RDX_LP + ja L(more_2x_vec) + #if !defined USE_MULTIARCH || !IS_IN (libc) + L(last_2x_vec): +@@ -138,38 +142,38 @@ END (MEMMOVE_SYMBOL (__memmove, unaligned)) + + # if VEC_SIZE == 16 + ENTRY (__mempcpy_chk_erms) +- cmpq %rdx, %rcx ++ cmp %RDX_LP, %RCX_LP + jb HIDDEN_JUMPTARGET (__chk_fail) + END (__mempcpy_chk_erms) + + /* Only used to measure performance of REP MOVSB. */ + ENTRY (__mempcpy_erms) +- movq %rdi, %rax ++ mov %RDI_LP, %RAX_LP + /* Skip zero length. */ +- testq %rdx, %rdx ++ test %RDX_LP, %RDX_LP + jz 2f +- addq %rdx, %rax ++ add %RDX_LP, %RAX_LP + jmp L(start_movsb) + END (__mempcpy_erms) + + ENTRY (__memmove_chk_erms) +- cmpq %rdx, %rcx ++ cmp %RDX_LP, %RCX_LP + jb HIDDEN_JUMPTARGET (__chk_fail) + END (__memmove_chk_erms) + + ENTRY (__memmove_erms) + movq %rdi, %rax + /* Skip zero length. */ +- testq %rdx, %rdx ++ test %RDX_LP, %RDX_LP + jz 2f + L(start_movsb): +- movq %rdx, %rcx +- cmpq %rsi, %rdi ++ mov %RDX_LP, %RCX_LP ++ cmp %RSI_LP, %RDI_LP + jb 1f + /* Source == destination is less common. */ + je 2f +- leaq (%rsi,%rcx), %rdx +- cmpq %rdx, %rdi ++ lea (%rsi,%rcx), %RDX_LP ++ cmp %RDX_LP, %RDI_LP + jb L(movsb_backward) + 1: + rep movsb +@@ -189,20 +193,20 @@ strong_alias (__memmove_chk_erms, __memcpy_chk_erms) + + # ifdef SHARED + ENTRY (MEMMOVE_CHK_SYMBOL (__mempcpy_chk, unaligned_erms)) +- cmpq %rdx, %rcx ++ cmp %RDX_LP, %RCX_LP + jb HIDDEN_JUMPTARGET (__chk_fail) + END (MEMMOVE_CHK_SYMBOL (__mempcpy_chk, unaligned_erms)) + # endif + + ENTRY (MEMMOVE_SYMBOL (__mempcpy, unaligned_erms)) +- movq %rdi, %rax +- addq %rdx, %rax ++ mov %RDI_LP, %RAX_LP ++ add %RDX_LP, %RAX_LP + jmp L(start_erms) + END (MEMMOVE_SYMBOL (__mempcpy, unaligned_erms)) + + # ifdef SHARED + ENTRY (MEMMOVE_CHK_SYMBOL (__memmove_chk, unaligned_erms)) +- cmpq %rdx, %rcx ++ cmp %RDX_LP, %RCX_LP + jb HIDDEN_JUMPTARGET (__chk_fail) + END (MEMMOVE_CHK_SYMBOL (__memmove_chk, unaligned_erms)) + # endif +@@ -210,9 +214,13 @@ END (MEMMOVE_CHK_SYMBOL (__memmove_chk, unaligned_erms)) + ENTRY (MEMMOVE_SYMBOL (__memmove, unaligned_erms)) + movq %rdi, %rax + L(start_erms): +- cmpq $VEC_SIZE, %rdx ++# ifdef __ILP32__ ++ /* Clear the upper 32 bits. */ ++ movl %edx, %edx ++# endif ++ cmp $VEC_SIZE, %RDX_LP + jb L(less_vec) +- cmpq $(VEC_SIZE * 2), %rdx ++ cmp $(VEC_SIZE * 2), %RDX_LP + ja L(movsb_more_2x_vec) + L(last_2x_vec): + /* From VEC and to 2 * VEC. No branch when size == VEC_SIZE. */ +@@ -236,7 +244,7 @@ L(movsb): + /* Avoid slow backward REP MOVSB. */ + jb L(more_8x_vec_backward) + 1: +- movq %rdx, %rcx ++ mov %RDX_LP, %RCX_LP + rep movsb + L(nop): + ret +diff --git a/sysdeps/x86_64/x32/Makefile b/sysdeps/x86_64/x32/Makefile +index ddec7f04..2fe1e5ac 100644 +--- a/sysdeps/x86_64/x32/Makefile ++++ b/sysdeps/x86_64/x32/Makefile +@@ -6,7 +6,7 @@ CFLAGS-s_llround.c += -fno-builtin-lround + endif + + ifeq ($(subdir),string) +-tests += tst-size_t-memchr tst-size_t-memcmp ++tests += tst-size_t-memchr tst-size_t-memcmp tst-size_t-memcpy + endif + + ifeq ($(subdir),wcsmbs) +diff --git a/sysdeps/x86_64/x32/tst-size_t-memcpy.c b/sysdeps/x86_64/x32/tst-size_t-memcpy.c +new file mode 100644 +index 00000000..66b71e17 +--- /dev/null ++++ b/sysdeps/x86_64/x32/tst-size_t-memcpy.c +@@ -0,0 +1,58 @@ ++/* Test memcpy with size_t in the lower 32 bits of 64-bit register. ++ 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, see ++ . */ ++ ++#define TEST_NAME "memcpy" ++#include "test-size_t.h" ++ ++IMPL (memcpy, 1) ++ ++typedef void *(*proto_t) (void *, const void *, size_t); ++ ++static void * ++__attribute__ ((noinline, noclone)) ++do_memcpy (parameter_t a, parameter_t b) ++{ ++ return CALL (&b, a.p, b.p, a.len); ++} ++ ++static int ++test_main (void) ++{ ++ test_init (); ++ ++ parameter_t dest = { { page_size }, buf1 }; ++ parameter_t src = { { 0 }, buf2 }; ++ ++ int ret = 0; ++ FOR_EACH_IMPL (impl, 0) ++ { ++ src.fn = impl->fn; ++ do_memcpy (dest, src); ++ int res = memcmp (dest.p, src.p, dest.len); ++ if (res) ++ { ++ error (0, 0, "Wrong result in function %s: %i != 0", ++ impl->name, res); ++ ret = 1; ++ } ++ } ++ ++ return ret ? EXIT_FAILURE : EXIT_SUCCESS; ++} ++ ++#include +-- +GitLab + diff --git a/SOURCES/glibc-RHEL-15696-30.patch b/SOURCES/glibc-RHEL-15696-30.patch new file mode 100644 index 0000000..0b16f0f --- /dev/null +++ b/SOURCES/glibc-RHEL-15696-30.patch @@ -0,0 +1,497 @@ +From a775a7a3eb1e85b54af0b4ee5ff4dcf66772a1fb Mon Sep 17 00:00:00 2001 +From: Noah Goldstein +Date: Wed, 23 Jun 2021 01:56:29 -0400 +Subject: [PATCH] x86: Fix overflow bug in wcsnlen-sse4_1 and wcsnlen-avx2 [BZ + #27974] +Content-type: text/plain; charset=UTF-8 + +This commit fixes the bug mentioned in the previous commit. + +The previous implementations of wmemchr in these files relied +on maxlen * sizeof(wchar_t) which was not guranteed by the standard. + +The new overflow tests added in the previous commit now +pass (As well as all the other tests). + +Signed-off-by: Noah Goldstein +Reviewed-by: H.J. Lu +--- + sysdeps/x86_64/multiarch/strlen-avx2.S | 130 ++++++++++++++++++------- + sysdeps/x86_64/multiarch/strlen-vec.S | 15 ++- + 2 files changed, 107 insertions(+), 38 deletions(-) + +diff --git a/sysdeps/x86_64/multiarch/strlen-avx2.S b/sysdeps/x86_64/multiarch/strlen-avx2.S +index be8a5db5..37688966 100644 +--- a/sysdeps/x86_64/multiarch/strlen-avx2.S ++++ b/sysdeps/x86_64/multiarch/strlen-avx2.S +@@ -44,21 +44,21 @@ + + # define VEC_SIZE 32 + # define PAGE_SIZE 4096 ++# define CHAR_PER_VEC (VEC_SIZE / CHAR_SIZE) + + .section SECTION(.text),"ax",@progbits + ENTRY (STRLEN) + # ifdef USE_AS_STRNLEN + /* Check zero length. */ ++# ifdef __ILP32__ ++ /* Clear upper bits. */ ++ and %RSI_LP, %RSI_LP ++# else + test %RSI_LP, %RSI_LP ++# endif + jz L(zero) + /* Store max len in R8_LP before adjusting if using WCSLEN. */ + mov %RSI_LP, %R8_LP +-# ifdef USE_AS_WCSLEN +- shl $2, %RSI_LP +-# elif defined __ILP32__ +- /* Clear the upper 32 bits. */ +- movl %esi, %esi +-# endif + # endif + movl %edi, %eax + movq %rdi, %rdx +@@ -72,10 +72,10 @@ ENTRY (STRLEN) + + /* Check the first VEC_SIZE bytes. */ + VPCMPEQ (%rdi), %ymm0, %ymm1 +- vpmovmskb %ymm1, %eax ++ vpmovmskb %ymm1, %eax + # ifdef USE_AS_STRNLEN + /* If length < VEC_SIZE handle special. */ +- cmpq $VEC_SIZE, %rsi ++ cmpq $CHAR_PER_VEC, %rsi + jbe L(first_vec_x0) + # endif + /* If empty continue to aligned_more. Otherwise return bit +@@ -84,6 +84,7 @@ ENTRY (STRLEN) + jz L(aligned_more) + tzcntl %eax, %eax + # ifdef USE_AS_WCSLEN ++ /* NB: Divide bytes by 4 to get wchar_t count. */ + shrl $2, %eax + # endif + VZEROUPPER_RETURN +@@ -97,9 +98,14 @@ L(zero): + L(first_vec_x0): + /* Set bit for max len so that tzcnt will return min of max len + and position of first match. */ ++# ifdef USE_AS_WCSLEN ++ /* NB: Multiply length by 4 to get byte count. */ ++ sall $2, %esi ++# endif + btsq %rsi, %rax + tzcntl %eax, %eax + # ifdef USE_AS_WCSLEN ++ /* NB: Divide bytes by 4 to get wchar_t count. */ + shrl $2, %eax + # endif + VZEROUPPER_RETURN +@@ -113,14 +119,19 @@ L(first_vec_x1): + # ifdef USE_AS_STRNLEN + /* Use ecx which was computed earlier to compute correct value. + */ ++# ifdef USE_AS_WCSLEN ++ leal -(VEC_SIZE * 4 + 1)(%rax, %rcx, 4), %eax ++# else + subl $(VEC_SIZE * 4 + 1), %ecx + addl %ecx, %eax ++# endif + # else + subl %edx, %edi + incl %edi + addl %edi, %eax + # endif + # ifdef USE_AS_WCSLEN ++ /* NB: Divide bytes by 4 to get wchar_t count. */ + shrl $2, %eax + # endif + VZEROUPPER_RETURN +@@ -133,14 +144,19 @@ L(first_vec_x2): + # ifdef USE_AS_STRNLEN + /* Use ecx which was computed earlier to compute correct value. + */ ++# ifdef USE_AS_WCSLEN ++ leal -(VEC_SIZE * 3 + 1)(%rax, %rcx, 4), %eax ++# else + subl $(VEC_SIZE * 3 + 1), %ecx + addl %ecx, %eax ++# endif + # else + subl %edx, %edi + addl $(VEC_SIZE + 1), %edi + addl %edi, %eax + # endif + # ifdef USE_AS_WCSLEN ++ /* NB: Divide bytes by 4 to get wchar_t count. */ + shrl $2, %eax + # endif + VZEROUPPER_RETURN +@@ -153,14 +169,19 @@ L(first_vec_x3): + # ifdef USE_AS_STRNLEN + /* Use ecx which was computed earlier to compute correct value. + */ ++# ifdef USE_AS_WCSLEN ++ leal -(VEC_SIZE * 2 + 1)(%rax, %rcx, 4), %eax ++# else + subl $(VEC_SIZE * 2 + 1), %ecx + addl %ecx, %eax ++# endif + # else + subl %edx, %edi + addl $(VEC_SIZE * 2 + 1), %edi + addl %edi, %eax + # endif + # ifdef USE_AS_WCSLEN ++ /* NB: Divide bytes by 4 to get wchar_t count. */ + shrl $2, %eax + # endif + VZEROUPPER_RETURN +@@ -173,14 +194,19 @@ L(first_vec_x4): + # ifdef USE_AS_STRNLEN + /* Use ecx which was computed earlier to compute correct value. + */ ++# ifdef USE_AS_WCSLEN ++ leal -(VEC_SIZE * 1 + 1)(%rax, %rcx, 4), %eax ++# else + subl $(VEC_SIZE + 1), %ecx + addl %ecx, %eax ++# endif + # else + subl %edx, %edi + addl $(VEC_SIZE * 3 + 1), %edi + addl %edi, %eax + # endif + # ifdef USE_AS_WCSLEN ++ /* NB: Divide bytes by 4 to get wchar_t count. */ + shrl $2, %eax + # endif + VZEROUPPER_RETURN +@@ -195,10 +221,14 @@ L(cross_page_continue): + /* Check the first 4 * VEC_SIZE. Only one VEC_SIZE at a time + since data is only aligned to VEC_SIZE. */ + # ifdef USE_AS_STRNLEN +- /* + 1 because rdi is aligned to VEC_SIZE - 1. + CHAR_SIZE because +- it simplies the logic in last_4x_vec_or_less. */ ++ /* + 1 because rdi is aligned to VEC_SIZE - 1. + CHAR_SIZE ++ because it simplies the logic in last_4x_vec_or_less. */ + leaq (VEC_SIZE * 4 + CHAR_SIZE + 1)(%rdi), %rcx + subq %rdx, %rcx ++# ifdef USE_AS_WCSLEN ++ /* NB: Divide bytes by 4 to get the wchar_t count. */ ++ sarl $2, %ecx ++# endif + # endif + /* Load first VEC regardless. */ + VPCMPEQ 1(%rdi), %ymm0, %ymm1 +@@ -207,34 +237,38 @@ L(cross_page_continue): + subq %rcx, %rsi + jb L(last_4x_vec_or_less) + # endif +- vpmovmskb %ymm1, %eax ++ vpmovmskb %ymm1, %eax + testl %eax, %eax + jnz L(first_vec_x1) + + VPCMPEQ (VEC_SIZE + 1)(%rdi), %ymm0, %ymm1 +- vpmovmskb %ymm1, %eax ++ vpmovmskb %ymm1, %eax + testl %eax, %eax + jnz L(first_vec_x2) + + VPCMPEQ (VEC_SIZE * 2 + 1)(%rdi), %ymm0, %ymm1 +- vpmovmskb %ymm1, %eax ++ vpmovmskb %ymm1, %eax + testl %eax, %eax + jnz L(first_vec_x3) + + VPCMPEQ (VEC_SIZE * 3 + 1)(%rdi), %ymm0, %ymm1 +- vpmovmskb %ymm1, %eax ++ vpmovmskb %ymm1, %eax + testl %eax, %eax + jnz L(first_vec_x4) + + /* Align data to VEC_SIZE * 4 - 1. */ + # ifdef USE_AS_STRNLEN + /* Before adjusting length check if at last VEC_SIZE * 4. */ +- cmpq $(VEC_SIZE * 4 - 1), %rsi ++ cmpq $(CHAR_PER_VEC * 4 - 1), %rsi + jbe L(last_4x_vec_or_less_load) + incq %rdi + movl %edi, %ecx + orq $(VEC_SIZE * 4 - 1), %rdi + andl $(VEC_SIZE * 4 - 1), %ecx ++# ifdef USE_AS_WCSLEN ++ /* NB: Divide bytes by 4 to get the wchar_t count. */ ++ sarl $2, %ecx ++# endif + /* Readjust length. */ + addq %rcx, %rsi + # else +@@ -246,13 +280,13 @@ L(cross_page_continue): + L(loop_4x_vec): + # ifdef USE_AS_STRNLEN + /* Break if at end of length. */ +- subq $(VEC_SIZE * 4), %rsi ++ subq $(CHAR_PER_VEC * 4), %rsi + jb L(last_4x_vec_or_less_cmpeq) + # endif +- /* Save some code size by microfusing VPMINU with the load. Since +- the matches in ymm2/ymm4 can only be returned if there where no +- matches in ymm1/ymm3 respectively there is no issue with overlap. +- */ ++ /* Save some code size by microfusing VPMINU with the load. ++ Since the matches in ymm2/ymm4 can only be returned if there ++ where no matches in ymm1/ymm3 respectively there is no issue ++ with overlap. */ + vmovdqa 1(%rdi), %ymm1 + VPMINU (VEC_SIZE + 1)(%rdi), %ymm1, %ymm2 + vmovdqa (VEC_SIZE * 2 + 1)(%rdi), %ymm3 +@@ -260,7 +294,7 @@ L(loop_4x_vec): + + VPMINU %ymm2, %ymm4, %ymm5 + VPCMPEQ %ymm5, %ymm0, %ymm5 +- vpmovmskb %ymm5, %ecx ++ vpmovmskb %ymm5, %ecx + + subq $-(VEC_SIZE * 4), %rdi + testl %ecx, %ecx +@@ -268,27 +302,28 @@ L(loop_4x_vec): + + + VPCMPEQ %ymm1, %ymm0, %ymm1 +- vpmovmskb %ymm1, %eax ++ vpmovmskb %ymm1, %eax + subq %rdx, %rdi + testl %eax, %eax + jnz L(last_vec_return_x0) + + VPCMPEQ %ymm2, %ymm0, %ymm2 +- vpmovmskb %ymm2, %eax ++ vpmovmskb %ymm2, %eax + testl %eax, %eax + jnz L(last_vec_return_x1) + + /* Combine last 2 VEC. */ + VPCMPEQ %ymm3, %ymm0, %ymm3 +- vpmovmskb %ymm3, %eax +- /* rcx has combined result from all 4 VEC. It will only be used if +- the first 3 other VEC all did not contain a match. */ ++ vpmovmskb %ymm3, %eax ++ /* rcx has combined result from all 4 VEC. It will only be used ++ if the first 3 other VEC all did not contain a match. */ + salq $32, %rcx + orq %rcx, %rax + tzcntq %rax, %rax + subq $(VEC_SIZE * 2 - 1), %rdi + addq %rdi, %rax + # ifdef USE_AS_WCSLEN ++ /* NB: Divide bytes by 4 to get wchar_t count. */ + shrq $2, %rax + # endif + VZEROUPPER_RETURN +@@ -297,15 +332,19 @@ L(loop_4x_vec): + # ifdef USE_AS_STRNLEN + .p2align 4 + L(last_4x_vec_or_less_load): +- /* Depending on entry adjust rdi / prepare first VEC in ymm1. */ ++ /* Depending on entry adjust rdi / prepare first VEC in ymm1. ++ */ + subq $-(VEC_SIZE * 4), %rdi + L(last_4x_vec_or_less_cmpeq): + VPCMPEQ 1(%rdi), %ymm0, %ymm1 + L(last_4x_vec_or_less): +- +- vpmovmskb %ymm1, %eax +- /* If remaining length > VEC_SIZE * 2. This works if esi is off by +- VEC_SIZE * 4. */ ++# ifdef USE_AS_WCSLEN ++ /* NB: Multiply length by 4 to get byte count. */ ++ sall $2, %esi ++# endif ++ vpmovmskb %ymm1, %eax ++ /* If remaining length > VEC_SIZE * 2. This works if esi is off ++ by VEC_SIZE * 4. */ + testl $(VEC_SIZE * 2), %esi + jnz L(last_4x_vec) + +@@ -320,7 +359,7 @@ L(last_4x_vec_or_less): + jb L(max) + + VPCMPEQ (VEC_SIZE + 1)(%rdi), %ymm0, %ymm1 +- vpmovmskb %ymm1, %eax ++ vpmovmskb %ymm1, %eax + tzcntl %eax, %eax + /* Check the end of data. */ + cmpl %eax, %esi +@@ -329,6 +368,7 @@ L(last_4x_vec_or_less): + addl $(VEC_SIZE + 1), %eax + addq %rdi, %rax + # ifdef USE_AS_WCSLEN ++ /* NB: Divide bytes by 4 to get wchar_t count. */ + shrq $2, %rax + # endif + VZEROUPPER_RETURN +@@ -340,6 +380,7 @@ L(last_vec_return_x0): + subq $(VEC_SIZE * 4 - 1), %rdi + addq %rdi, %rax + # ifdef USE_AS_WCSLEN ++ /* NB: Divide bytes by 4 to get wchar_t count. */ + shrq $2, %rax + # endif + VZEROUPPER_RETURN +@@ -350,6 +391,7 @@ L(last_vec_return_x1): + subq $(VEC_SIZE * 3 - 1), %rdi + addq %rdi, %rax + # ifdef USE_AS_WCSLEN ++ /* NB: Divide bytes by 4 to get wchar_t count. */ + shrq $2, %rax + # endif + VZEROUPPER_RETURN +@@ -366,6 +408,7 @@ L(last_vec_x1_check): + incl %eax + addq %rdi, %rax + # ifdef USE_AS_WCSLEN ++ /* NB: Divide bytes by 4 to get wchar_t count. */ + shrq $2, %rax + # endif + VZEROUPPER_RETURN +@@ -381,14 +424,14 @@ L(last_4x_vec): + jnz L(last_vec_x1) + + VPCMPEQ (VEC_SIZE + 1)(%rdi), %ymm0, %ymm1 +- vpmovmskb %ymm1, %eax ++ vpmovmskb %ymm1, %eax + testl %eax, %eax + jnz L(last_vec_x2) + + /* Normalize length. */ + andl $(VEC_SIZE * 4 - 1), %esi + VPCMPEQ (VEC_SIZE * 2 + 1)(%rdi), %ymm0, %ymm1 +- vpmovmskb %ymm1, %eax ++ vpmovmskb %ymm1, %eax + testl %eax, %eax + jnz L(last_vec_x3) + +@@ -396,7 +439,7 @@ L(last_4x_vec): + jb L(max) + + VPCMPEQ (VEC_SIZE * 3 + 1)(%rdi), %ymm0, %ymm1 +- vpmovmskb %ymm1, %eax ++ vpmovmskb %ymm1, %eax + tzcntl %eax, %eax + /* Check the end of data. */ + cmpl %eax, %esi +@@ -405,6 +448,7 @@ L(last_4x_vec): + addl $(VEC_SIZE * 3 + 1), %eax + addq %rdi, %rax + # ifdef USE_AS_WCSLEN ++ /* NB: Divide bytes by 4 to get wchar_t count. */ + shrq $2, %rax + # endif + VZEROUPPER_RETURN +@@ -419,6 +463,7 @@ L(last_vec_x1): + incl %eax + addq %rdi, %rax + # ifdef USE_AS_WCSLEN ++ /* NB: Divide bytes by 4 to get wchar_t count. */ + shrq $2, %rax + # endif + VZEROUPPER_RETURN +@@ -432,6 +477,7 @@ L(last_vec_x2): + addl $(VEC_SIZE + 1), %eax + addq %rdi, %rax + # ifdef USE_AS_WCSLEN ++ /* NB: Divide bytes by 4 to get wchar_t count. */ + shrq $2, %rax + # endif + VZEROUPPER_RETURN +@@ -447,6 +493,7 @@ L(last_vec_x3): + addl $(VEC_SIZE * 2 + 1), %eax + addq %rdi, %rax + # ifdef USE_AS_WCSLEN ++ /* NB: Divide bytes by 4 to get wchar_t count. */ + shrq $2, %rax + # endif + VZEROUPPER_RETURN +@@ -455,13 +502,13 @@ L(max_end): + VZEROUPPER_RETURN + # endif + +- /* Cold case for crossing page with first load. */ ++ /* Cold case for crossing page with first load. */ + .p2align 4 + L(cross_page_boundary): + /* Align data to VEC_SIZE - 1. */ + orq $(VEC_SIZE - 1), %rdi + VPCMPEQ -(VEC_SIZE - 1)(%rdi), %ymm0, %ymm1 +- vpmovmskb %ymm1, %eax ++ vpmovmskb %ymm1, %eax + /* Remove the leading bytes. sarxl only uses bits [5:0] of COUNT + so no need to manually mod rdx. */ + sarxl %edx, %eax, %eax +@@ -470,6 +517,10 @@ L(cross_page_boundary): + jnz L(cross_page_less_vec) + leaq 1(%rdi), %rcx + subq %rdx, %rcx ++# ifdef USE_AS_WCSLEN ++ /* NB: Divide bytes by 4 to get wchar_t count. */ ++ shrl $2, %ecx ++# endif + /* Check length. */ + cmpq %rsi, %rcx + jb L(cross_page_continue) +@@ -479,6 +530,7 @@ L(cross_page_boundary): + jz L(cross_page_continue) + tzcntl %eax, %eax + # ifdef USE_AS_WCSLEN ++ /* NB: Divide length by 4 to get wchar_t count. */ + shrl $2, %eax + # endif + # endif +@@ -489,6 +541,10 @@ L(return_vzeroupper): + .p2align 4 + L(cross_page_less_vec): + tzcntl %eax, %eax ++# ifdef USE_AS_WCSLEN ++ /* NB: Multiply length by 4 to get byte count. */ ++ sall $2, %esi ++# endif + cmpq %rax, %rsi + cmovb %esi, %eax + # ifdef USE_AS_WCSLEN +diff --git a/sysdeps/x86_64/multiarch/strlen-vec.S b/sysdeps/x86_64/multiarch/strlen-vec.S +index 8f660bb9..439e486a 100644 +--- a/sysdeps/x86_64/multiarch/strlen-vec.S ++++ b/sysdeps/x86_64/multiarch/strlen-vec.S +@@ -65,12 +65,25 @@ ENTRY(strlen) + ret + L(n_nonzero): + # ifdef AS_WCSLEN +- shl $2, %RSI_LP ++/* Check for overflow from maxlen * sizeof(wchar_t). If it would ++ overflow the only way this program doesn't have undefined behavior ++ is if there is a null terminator in valid memory so wcslen will ++ suffice. */ ++ mov %RSI_LP, %R10_LP ++ sar $62, %R10_LP ++ test %R10_LP, %R10_LP ++ jnz __wcslen_sse4_1 ++ sal $2, %RSI_LP + # endif + ++ + /* Initialize long lived registers. */ + + add %RDI_LP, %RSI_LP ++# ifdef AS_WCSLEN ++/* Check for overflow again from s + maxlen * sizeof(wchar_t). */ ++ jbe __wcslen_sse4_1 ++# endif + mov %RSI_LP, %R10_LP + and $-64, %R10_LP + mov %RSI_LP, %R11_LP +-- +GitLab + diff --git a/SOURCES/glibc-RHEL-15696-31.patch b/SOURCES/glibc-RHEL-15696-31.patch new file mode 100644 index 0000000..4ef6911 --- /dev/null +++ b/SOURCES/glibc-RHEL-15696-31.patch @@ -0,0 +1,745 @@ +From 4ba65586847751372520a36757c17f114588794e Mon Sep 17 00:00:00 2001 +From: Noah Goldstein +Date: Mon, 19 Apr 2021 19:36:06 -0400 +Subject: [PATCH] x86: Optimize strlen-evex.S +Content-type: text/plain; charset=UTF-8 + +No bug. This commit optimizes strlen-evex.S. The +optimizations are mostly small things but they add up to roughly +10-30% performance improvement for strlen. The results for strnlen are +bit more ambiguous. test-strlen, test-strnlen, test-wcslen, and +test-wcsnlen are all passing. + +Signed-off-by: Noah Goldstein +--- + sysdeps/x86_64/multiarch/strlen-evex.S | 581 ++++++++++++++----------- + 1 file changed, 317 insertions(+), 264 deletions(-) + +diff --git a/sysdeps/x86_64/multiarch/strlen-evex.S b/sysdeps/x86_64/multiarch/strlen-evex.S +index 05838190..4bf6874b 100644 +--- a/sysdeps/x86_64/multiarch/strlen-evex.S ++++ b/sysdeps/x86_64/multiarch/strlen-evex.S +@@ -29,11 +29,13 @@ + # ifdef USE_AS_WCSLEN + # define VPCMP vpcmpd + # define VPMINU vpminud +-# define SHIFT_REG r9d ++# define SHIFT_REG ecx ++# define CHAR_SIZE 4 + # else + # define VPCMP vpcmpb + # define VPMINU vpminub +-# define SHIFT_REG ecx ++# define SHIFT_REG edx ++# define CHAR_SIZE 1 + # endif + + # define XMMZERO xmm16 +@@ -46,132 +48,165 @@ + # define YMM6 ymm22 + + # define VEC_SIZE 32 ++# define PAGE_SIZE 4096 ++# define CHAR_PER_VEC (VEC_SIZE / CHAR_SIZE) + + .section .text.evex,"ax",@progbits + ENTRY (STRLEN) + # ifdef USE_AS_STRNLEN +- /* Check for zero length. */ ++ /* Check zero length. */ + test %RSI_LP, %RSI_LP + jz L(zero) +-# ifdef USE_AS_WCSLEN +- shl $2, %RSI_LP +-# elif defined __ILP32__ ++# ifdef __ILP32__ + /* Clear the upper 32 bits. */ + movl %esi, %esi + # endif + mov %RSI_LP, %R8_LP + # endif +- movl %edi, %ecx +- movq %rdi, %rdx ++ movl %edi, %eax + vpxorq %XMMZERO, %XMMZERO, %XMMZERO +- ++ /* Clear high bits from edi. Only keeping bits relevant to page ++ cross check. */ ++ andl $(PAGE_SIZE - 1), %eax + /* Check if we may cross page boundary with one vector load. */ +- andl $(2 * VEC_SIZE - 1), %ecx +- cmpl $VEC_SIZE, %ecx +- ja L(cros_page_boundary) ++ cmpl $(PAGE_SIZE - VEC_SIZE), %eax ++ ja L(cross_page_boundary) + + /* Check the first VEC_SIZE bytes. Each bit in K0 represents a + null byte. */ + VPCMP $0, (%rdi), %YMMZERO, %k0 + kmovd %k0, %eax +- testl %eax, %eax +- + # ifdef USE_AS_STRNLEN +- jnz L(first_vec_x0_check) +- /* Adjust length and check the end of data. */ +- subq $VEC_SIZE, %rsi +- jbe L(max) +-# else +- jnz L(first_vec_x0) ++ /* If length < CHAR_PER_VEC handle special. */ ++ cmpq $CHAR_PER_VEC, %rsi ++ jbe L(first_vec_x0) + # endif +- +- /* Align data for aligned loads in the loop. */ +- addq $VEC_SIZE, %rdi +- andl $(VEC_SIZE - 1), %ecx +- andq $-VEC_SIZE, %rdi +- ++ testl %eax, %eax ++ jz L(aligned_more) ++ tzcntl %eax, %eax ++ ret + # ifdef USE_AS_STRNLEN +- /* Adjust length. */ +- addq %rcx, %rsi ++L(zero): ++ xorl %eax, %eax ++ ret + +- subq $(VEC_SIZE * 4), %rsi +- jbe L(last_4x_vec_or_less) ++ .p2align 4 ++L(first_vec_x0): ++ /* Set bit for max len so that tzcnt will return min of max len ++ and position of first match. */ ++ btsq %rsi, %rax ++ tzcntl %eax, %eax ++ ret + # endif +- jmp L(more_4x_vec) + + .p2align 4 +-L(cros_page_boundary): +- andl $(VEC_SIZE - 1), %ecx +- andq $-VEC_SIZE, %rdi +- +-# ifdef USE_AS_WCSLEN +- /* NB: Divide shift count by 4 since each bit in K0 represent 4 +- bytes. */ +- movl %ecx, %SHIFT_REG +- sarl $2, %SHIFT_REG ++L(first_vec_x1): ++ tzcntl %eax, %eax ++ /* Safe to use 32 bit instructions as these are only called for ++ size = [1, 159]. */ ++# ifdef USE_AS_STRNLEN ++ /* Use ecx which was computed earlier to compute correct value. ++ */ ++ leal -(CHAR_PER_VEC * 4 + 1)(%rcx, %rax), %eax ++# else ++ subl %edx, %edi ++# ifdef USE_AS_WCSLEN ++ /* NB: Divide bytes by 4 to get the wchar_t count. */ ++ sarl $2, %edi ++# endif ++ leal CHAR_PER_VEC(%rdi, %rax), %eax + # endif +- VPCMP $0, (%rdi), %YMMZERO, %k0 +- kmovd %k0, %eax ++ ret + +- /* Remove the leading bytes. */ +- sarxl %SHIFT_REG, %eax, %eax +- testl %eax, %eax +- jz L(aligned_more) ++ .p2align 4 ++L(first_vec_x2): + tzcntl %eax, %eax +-# ifdef USE_AS_WCSLEN +- /* NB: Multiply wchar_t count by 4 to get the number of bytes. */ +- sall $2, %eax +-# endif ++ /* Safe to use 32 bit instructions as these are only called for ++ size = [1, 159]. */ + # ifdef USE_AS_STRNLEN +- /* Check the end of data. */ +- cmpq %rax, %rsi +- jbe L(max) +-# endif +- addq %rdi, %rax +- addq %rcx, %rax +- subq %rdx, %rax +-# ifdef USE_AS_WCSLEN +- shrq $2, %rax ++ /* Use ecx which was computed earlier to compute correct value. ++ */ ++ leal -(CHAR_PER_VEC * 3 + 1)(%rcx, %rax), %eax ++# else ++ subl %edx, %edi ++# ifdef USE_AS_WCSLEN ++ /* NB: Divide bytes by 4 to get the wchar_t count. */ ++ sarl $2, %edi ++# endif ++ leal (CHAR_PER_VEC * 2)(%rdi, %rax), %eax + # endif + ret + + .p2align 4 +-L(aligned_more): ++L(first_vec_x3): ++ tzcntl %eax, %eax ++ /* Safe to use 32 bit instructions as these are only called for ++ size = [1, 159]. */ + # ifdef USE_AS_STRNLEN +- /* "rcx" is less than VEC_SIZE. Calculate "rdx + rcx - VEC_SIZE" +- with "rdx - (VEC_SIZE - rcx)" instead of "(rdx + rcx) - VEC_SIZE" +- to void possible addition overflow. */ +- negq %rcx +- addq $VEC_SIZE, %rcx +- +- /* Check the end of data. */ +- subq %rcx, %rsi +- jbe L(max) ++ /* Use ecx which was computed earlier to compute correct value. ++ */ ++ leal -(CHAR_PER_VEC * 2 + 1)(%rcx, %rax), %eax ++# else ++ subl %edx, %edi ++# ifdef USE_AS_WCSLEN ++ /* NB: Divide bytes by 4 to get the wchar_t count. */ ++ sarl $2, %edi ++# endif ++ leal (CHAR_PER_VEC * 3)(%rdi, %rax), %eax + # endif ++ ret + +- addq $VEC_SIZE, %rdi +- ++ .p2align 4 ++L(first_vec_x4): ++ tzcntl %eax, %eax ++ /* Safe to use 32 bit instructions as these are only called for ++ size = [1, 159]. */ + # ifdef USE_AS_STRNLEN +- subq $(VEC_SIZE * 4), %rsi +- jbe L(last_4x_vec_or_less) ++ /* Use ecx which was computed earlier to compute correct value. ++ */ ++ leal -(CHAR_PER_VEC + 1)(%rcx, %rax), %eax ++# else ++ subl %edx, %edi ++# ifdef USE_AS_WCSLEN ++ /* NB: Divide bytes by 4 to get the wchar_t count. */ ++ sarl $2, %edi ++# endif ++ leal (CHAR_PER_VEC * 4)(%rdi, %rax), %eax + # endif ++ ret + +-L(more_4x_vec): ++ .p2align 5 ++L(aligned_more): ++ movq %rdi, %rdx ++ /* Align data to VEC_SIZE. */ ++ andq $-(VEC_SIZE), %rdi ++L(cross_page_continue): + /* Check the first 4 * VEC_SIZE. Only one VEC_SIZE at a time + since data is only aligned to VEC_SIZE. */ +- VPCMP $0, (%rdi), %YMMZERO, %k0 +- kmovd %k0, %eax +- testl %eax, %eax +- jnz L(first_vec_x0) +- ++# ifdef USE_AS_STRNLEN ++ /* + CHAR_SIZE because it simplies the logic in ++ last_4x_vec_or_less. */ ++ leaq (VEC_SIZE * 5 + CHAR_SIZE)(%rdi), %rcx ++ subq %rdx, %rcx ++# ifdef USE_AS_WCSLEN ++ /* NB: Divide bytes by 4 to get the wchar_t count. */ ++ sarl $2, %ecx ++# endif ++# endif ++ /* Load first VEC regardless. */ + VPCMP $0, VEC_SIZE(%rdi), %YMMZERO, %k0 ++# ifdef USE_AS_STRNLEN ++ /* Adjust length. If near end handle specially. */ ++ subq %rcx, %rsi ++ jb L(last_4x_vec_or_less) ++# endif + kmovd %k0, %eax + testl %eax, %eax + jnz L(first_vec_x1) + + VPCMP $0, (VEC_SIZE * 2)(%rdi), %YMMZERO, %k0 + kmovd %k0, %eax +- testl %eax, %eax ++ test %eax, %eax + jnz L(first_vec_x2) + + VPCMP $0, (VEC_SIZE * 3)(%rdi), %YMMZERO, %k0 +@@ -179,258 +214,276 @@ L(more_4x_vec): + testl %eax, %eax + jnz L(first_vec_x3) + +- addq $(VEC_SIZE * 4), %rdi +- +-# ifdef USE_AS_STRNLEN +- subq $(VEC_SIZE * 4), %rsi +- jbe L(last_4x_vec_or_less) +-# endif +- +- /* Align data to 4 * VEC_SIZE. */ +- movq %rdi, %rcx +- andl $(4 * VEC_SIZE - 1), %ecx +- andq $-(4 * VEC_SIZE), %rdi ++ VPCMP $0, (VEC_SIZE * 4)(%rdi), %YMMZERO, %k0 ++ kmovd %k0, %eax ++ testl %eax, %eax ++ jnz L(first_vec_x4) + ++ addq $VEC_SIZE, %rdi + # ifdef USE_AS_STRNLEN +- /* Adjust length. */ ++ /* Check if at last VEC_SIZE * 4 length. */ ++ cmpq $(CHAR_PER_VEC * 4 - 1), %rsi ++ jbe L(last_4x_vec_or_less_load) ++ movl %edi, %ecx ++ andl $(VEC_SIZE * 4 - 1), %ecx ++# ifdef USE_AS_WCSLEN ++ /* NB: Divide bytes by 4 to get the wchar_t count. */ ++ sarl $2, %ecx ++# endif ++ /* Readjust length. */ + addq %rcx, %rsi + # endif ++ /* Align data to VEC_SIZE * 4. */ ++ andq $-(VEC_SIZE * 4), %rdi + ++ /* Compare 4 * VEC at a time forward. */ + .p2align 4 + L(loop_4x_vec): +- /* Compare 4 * VEC at a time forward. */ +- VMOVA (%rdi), %YMM1 +- VMOVA VEC_SIZE(%rdi), %YMM2 +- VMOVA (VEC_SIZE * 2)(%rdi), %YMM3 +- VMOVA (VEC_SIZE * 3)(%rdi), %YMM4 +- +- VPMINU %YMM1, %YMM2, %YMM5 +- VPMINU %YMM3, %YMM4, %YMM6 ++ /* Load first VEC regardless. */ ++ VMOVA (VEC_SIZE * 4)(%rdi), %YMM1 ++# ifdef USE_AS_STRNLEN ++ /* Break if at end of length. */ ++ subq $(CHAR_PER_VEC * 4), %rsi ++ jb L(last_4x_vec_or_less_cmpeq) ++# endif ++ /* Save some code size by microfusing VPMINU with the load. Since ++ the matches in ymm2/ymm4 can only be returned if there where no ++ matches in ymm1/ymm3 respectively there is no issue with overlap. ++ */ ++ VPMINU (VEC_SIZE * 5)(%rdi), %YMM1, %YMM2 ++ VMOVA (VEC_SIZE * 6)(%rdi), %YMM3 ++ VPMINU (VEC_SIZE * 7)(%rdi), %YMM3, %YMM4 ++ ++ VPCMP $0, %YMM2, %YMMZERO, %k0 ++ VPCMP $0, %YMM4, %YMMZERO, %k1 ++ subq $-(VEC_SIZE * 4), %rdi ++ kortestd %k0, %k1 ++ jz L(loop_4x_vec) ++ ++ /* Check if end was in first half. */ ++ kmovd %k0, %eax ++ subq %rdx, %rdi ++# ifdef USE_AS_WCSLEN ++ shrq $2, %rdi ++# endif ++ testl %eax, %eax ++ jz L(second_vec_return) + +- VPMINU %YMM5, %YMM6, %YMM5 +- VPCMP $0, %YMM5, %YMMZERO, %k0 +- ktestd %k0, %k0 +- jnz L(4x_vec_end) ++ VPCMP $0, %YMM1, %YMMZERO, %k2 ++ kmovd %k2, %edx ++ /* Combine VEC1 matches (edx) with VEC2 matches (eax). */ ++# ifdef USE_AS_WCSLEN ++ sall $CHAR_PER_VEC, %eax ++ orl %edx, %eax ++ tzcntl %eax, %eax ++# else ++ salq $CHAR_PER_VEC, %rax ++ orq %rdx, %rax ++ tzcntq %rax, %rax ++# endif ++ addq %rdi, %rax ++ ret + +- addq $(VEC_SIZE * 4), %rdi + +-# ifndef USE_AS_STRNLEN +- jmp L(loop_4x_vec) +-# else +- subq $(VEC_SIZE * 4), %rsi +- ja L(loop_4x_vec) ++# ifdef USE_AS_STRNLEN + ++L(last_4x_vec_or_less_load): ++ /* Depending on entry adjust rdi / prepare first VEC in YMM1. */ ++ VMOVA (VEC_SIZE * 4)(%rdi), %YMM1 ++L(last_4x_vec_or_less_cmpeq): ++ VPCMP $0, %YMM1, %YMMZERO, %k0 ++ addq $(VEC_SIZE * 3), %rdi + L(last_4x_vec_or_less): +- /* Less than 4 * VEC and aligned to VEC_SIZE. */ +- addl $(VEC_SIZE * 2), %esi +- jle L(last_2x_vec) +- +- VPCMP $0, (%rdi), %YMMZERO, %k0 + kmovd %k0, %eax ++ /* If remaining length > VEC_SIZE * 2. This works if esi is off by ++ VEC_SIZE * 4. */ ++ testl $(CHAR_PER_VEC * 2), %esi ++ jnz L(last_4x_vec) ++ ++ /* length may have been negative or positive by an offset of ++ CHAR_PER_VEC * 4 depending on where this was called from. This ++ fixes that. */ ++ andl $(CHAR_PER_VEC * 4 - 1), %esi + testl %eax, %eax +- jnz L(first_vec_x0) ++ jnz L(last_vec_x1_check) + +- VPCMP $0, VEC_SIZE(%rdi), %YMMZERO, %k0 +- kmovd %k0, %eax +- testl %eax, %eax +- jnz L(first_vec_x1) ++ /* Check the end of data. */ ++ subl $CHAR_PER_VEC, %esi ++ jb L(max) + + VPCMP $0, (VEC_SIZE * 2)(%rdi), %YMMZERO, %k0 + kmovd %k0, %eax +- testl %eax, %eax +- jnz L(first_vec_x2_check) +- subl $VEC_SIZE, %esi +- jle L(max) ++ tzcntl %eax, %eax ++ /* Check the end of data. */ ++ cmpl %eax, %esi ++ jb L(max) + +- VPCMP $0, (VEC_SIZE * 3)(%rdi), %YMMZERO, %k0 +- kmovd %k0, %eax +- testl %eax, %eax +- jnz L(first_vec_x3_check) ++ subq %rdx, %rdi ++# ifdef USE_AS_WCSLEN ++ /* NB: Divide bytes by 4 to get the wchar_t count. */ ++ sarq $2, %rdi ++# endif ++ leaq (CHAR_PER_VEC * 2)(%rdi, %rax), %rax ++ ret ++L(max): + movq %r8, %rax ++ ret ++# endif ++ ++ /* Placed here in strnlen so that the jcc L(last_4x_vec_or_less) ++ in the 4x VEC loop can use 2 byte encoding. */ ++ .p2align 4 ++L(second_vec_return): ++ VPCMP $0, %YMM3, %YMMZERO, %k0 ++ /* Combine YMM3 matches (k0) with YMM4 matches (k1). */ ++# ifdef USE_AS_WCSLEN ++ kunpckbw %k0, %k1, %k0 ++ kmovd %k0, %eax ++ tzcntl %eax, %eax ++# else ++ kunpckdq %k0, %k1, %k0 ++ kmovq %k0, %rax ++ tzcntq %rax, %rax ++# endif ++ leaq (CHAR_PER_VEC * 2)(%rdi, %rax), %rax ++ ret ++ ++ ++# ifdef USE_AS_STRNLEN ++L(last_vec_x1_check): ++ tzcntl %eax, %eax ++ /* Check the end of data. */ ++ cmpl %eax, %esi ++ jb L(max) ++ subq %rdx, %rdi + # ifdef USE_AS_WCSLEN +- shrq $2, %rax ++ /* NB: Divide bytes by 4 to get the wchar_t count. */ ++ sarq $2, %rdi + # endif ++ leaq (CHAR_PER_VEC)(%rdi, %rax), %rax + ret + + .p2align 4 +-L(last_2x_vec): +- addl $(VEC_SIZE * 2), %esi ++L(last_4x_vec): ++ /* Test first 2x VEC normally. */ ++ testl %eax, %eax ++ jnz L(last_vec_x1) + +- VPCMP $0, (%rdi), %YMMZERO, %k0 ++ VPCMP $0, (VEC_SIZE * 2)(%rdi), %YMMZERO, %k0 + kmovd %k0, %eax + testl %eax, %eax +- jnz L(first_vec_x0_check) +- subl $VEC_SIZE, %esi +- jle L(max) ++ jnz L(last_vec_x2) + +- VPCMP $0, VEC_SIZE(%rdi), %YMMZERO, %k0 ++ /* Normalize length. */ ++ andl $(CHAR_PER_VEC * 4 - 1), %esi ++ VPCMP $0, (VEC_SIZE * 3)(%rdi), %YMMZERO, %k0 + kmovd %k0, %eax + testl %eax, %eax +- jnz L(first_vec_x1_check) +- movq %r8, %rax +-# ifdef USE_AS_WCSLEN +- shrq $2, %rax +-# endif +- ret ++ jnz L(last_vec_x3) + +- .p2align 4 +-L(first_vec_x0_check): ++ /* Check the end of data. */ ++ subl $(CHAR_PER_VEC * 3), %esi ++ jb L(max) ++ ++ VPCMP $0, (VEC_SIZE * 4)(%rdi), %YMMZERO, %k0 ++ kmovd %k0, %eax + tzcntl %eax, %eax +-# ifdef USE_AS_WCSLEN +- /* NB: Multiply wchar_t count by 4 to get the number of bytes. */ +- sall $2, %eax +-# endif + /* Check the end of data. */ +- cmpq %rax, %rsi +- jbe L(max) +- addq %rdi, %rax +- subq %rdx, %rax ++ cmpl %eax, %esi ++ jb L(max_end) ++ ++ subq %rdx, %rdi + # ifdef USE_AS_WCSLEN +- shrq $2, %rax ++ /* NB: Divide bytes by 4 to get the wchar_t count. */ ++ sarq $2, %rdi + # endif ++ leaq (CHAR_PER_VEC * 4)(%rdi, %rax), %rax + ret + + .p2align 4 +-L(first_vec_x1_check): ++L(last_vec_x1): + tzcntl %eax, %eax ++ subq %rdx, %rdi + # ifdef USE_AS_WCSLEN +- /* NB: Multiply wchar_t count by 4 to get the number of bytes. */ +- sall $2, %eax +-# endif +- /* Check the end of data. */ +- cmpq %rax, %rsi +- jbe L(max) +- addq $VEC_SIZE, %rax +- addq %rdi, %rax +- subq %rdx, %rax +-# ifdef USE_AS_WCSLEN +- shrq $2, %rax ++ /* NB: Divide bytes by 4 to get the wchar_t count. */ ++ sarq $2, %rdi + # endif ++ leaq (CHAR_PER_VEC)(%rdi, %rax), %rax + ret + + .p2align 4 +-L(first_vec_x2_check): ++L(last_vec_x2): + tzcntl %eax, %eax ++ subq %rdx, %rdi + # ifdef USE_AS_WCSLEN +- /* NB: Multiply wchar_t count by 4 to get the number of bytes. */ +- sall $2, %eax +-# endif +- /* Check the end of data. */ +- cmpq %rax, %rsi +- jbe L(max) +- addq $(VEC_SIZE * 2), %rax +- addq %rdi, %rax +- subq %rdx, %rax +-# ifdef USE_AS_WCSLEN +- shrq $2, %rax ++ /* NB: Divide bytes by 4 to get the wchar_t count. */ ++ sarq $2, %rdi + # endif ++ leaq (CHAR_PER_VEC * 2)(%rdi, %rax), %rax + ret + + .p2align 4 +-L(first_vec_x3_check): ++L(last_vec_x3): + tzcntl %eax, %eax +-# ifdef USE_AS_WCSLEN +- /* NB: Multiply wchar_t count by 4 to get the number of bytes. */ +- sall $2, %eax +-# endif ++ subl $(CHAR_PER_VEC * 2), %esi + /* Check the end of data. */ +- cmpq %rax, %rsi +- jbe L(max) +- addq $(VEC_SIZE * 3), %rax +- addq %rdi, %rax +- subq %rdx, %rax ++ cmpl %eax, %esi ++ jb L(max_end) ++ subq %rdx, %rdi + # ifdef USE_AS_WCSLEN +- shrq $2, %rax ++ /* NB: Divide bytes by 4 to get the wchar_t count. */ ++ sarq $2, %rdi + # endif ++ leaq (CHAR_PER_VEC * 3)(%rdi, %rax), %rax + ret +- +- .p2align 4 +-L(max): ++L(max_end): + movq %r8, %rax +-# ifdef USE_AS_WCSLEN +- shrq $2, %rax +-# endif +- ret +- +- .p2align 4 +-L(zero): +- xorl %eax, %eax + ret + # endif + ++ /* Cold case for crossing page with first load. */ + .p2align 4 +-L(first_vec_x0): +- tzcntl %eax, %eax +-# ifdef USE_AS_WCSLEN +- /* NB: Multiply wchar_t count by 4 to get the number of bytes. */ +- sall $2, %eax +-# endif +- addq %rdi, %rax +- subq %rdx, %rax ++L(cross_page_boundary): ++ movq %rdi, %rdx ++ /* Align data to VEC_SIZE. */ ++ andq $-VEC_SIZE, %rdi ++ VPCMP $0, (%rdi), %YMMZERO, %k0 ++ kmovd %k0, %eax ++ /* Remove the leading bytes. */ + # ifdef USE_AS_WCSLEN +- shrq $2, %rax ++ /* NB: Divide shift count by 4 since each bit in K0 represent 4 ++ bytes. */ ++ movl %edx, %ecx ++ shrl $2, %ecx ++ andl $(CHAR_PER_VEC - 1), %ecx + # endif +- ret +- +- .p2align 4 +-L(first_vec_x1): ++ /* SHIFT_REG is ecx for USE_AS_WCSLEN and edx otherwise. */ ++ sarxl %SHIFT_REG, %eax, %eax ++ testl %eax, %eax ++# ifndef USE_AS_STRNLEN ++ jz L(cross_page_continue) + tzcntl %eax, %eax +-# ifdef USE_AS_WCSLEN +- /* NB: Multiply wchar_t count by 4 to get the number of bytes. */ +- sall $2, %eax +-# endif +- addq $VEC_SIZE, %rax +- addq %rdi, %rax +- subq %rdx, %rax +-# ifdef USE_AS_WCSLEN +- shrq $2, %rax +-# endif + ret +- +- .p2align 4 +-L(first_vec_x2): +- tzcntl %eax, %eax +-# ifdef USE_AS_WCSLEN +- /* NB: Multiply wchar_t count by 4 to get the number of bytes. */ +- sall $2, %eax +-# endif +- addq $(VEC_SIZE * 2), %rax +- addq %rdi, %rax +- subq %rdx, %rax +-# ifdef USE_AS_WCSLEN +- shrq $2, %rax +-# endif ++# else ++ jnz L(cross_page_less_vec) ++# ifndef USE_AS_WCSLEN ++ movl %edx, %ecx ++ andl $(CHAR_PER_VEC - 1), %ecx ++# endif ++ movl $CHAR_PER_VEC, %eax ++ subl %ecx, %eax ++ /* Check the end of data. */ ++ cmpq %rax, %rsi ++ ja L(cross_page_continue) ++ movl %esi, %eax + ret +- +- .p2align 4 +-L(4x_vec_end): +- VPCMP $0, %YMM1, %YMMZERO, %k0 +- kmovd %k0, %eax +- testl %eax, %eax +- jnz L(first_vec_x0) +- VPCMP $0, %YMM2, %YMMZERO, %k1 +- kmovd %k1, %eax +- testl %eax, %eax +- jnz L(first_vec_x1) +- VPCMP $0, %YMM3, %YMMZERO, %k2 +- kmovd %k2, %eax +- testl %eax, %eax +- jnz L(first_vec_x2) +- VPCMP $0, %YMM4, %YMMZERO, %k3 +- kmovd %k3, %eax +-L(first_vec_x3): ++L(cross_page_less_vec): + tzcntl %eax, %eax +-# ifdef USE_AS_WCSLEN +- /* NB: Multiply wchar_t count by 4 to get the number of bytes. */ +- sall $2, %eax +-# endif +- addq $(VEC_SIZE * 3), %rax +- addq %rdi, %rax +- subq %rdx, %rax +-# ifdef USE_AS_WCSLEN +- shrq $2, %rax +-# endif ++ /* Select min of length and position of first null. */ ++ cmpq %rax, %rsi ++ cmovb %esi, %eax + ret ++# endif + + END (STRLEN) + #endif +-- +GitLab + diff --git a/SOURCES/glibc-RHEL-15696-32.patch b/SOURCES/glibc-RHEL-15696-32.patch new file mode 100644 index 0000000..8f1a94a --- /dev/null +++ b/SOURCES/glibc-RHEL-15696-32.patch @@ -0,0 +1,158 @@ +From ea8e465a6b8d0f26c72bcbe453a854de3abf68ec Mon Sep 17 00:00:00 2001 +From: "H.J. Lu" +Date: Wed, 30 Jun 2021 10:47:06 -0700 +Subject: [PATCH] x86: Check RTM_ALWAYS_ABORT for RTM [BZ #28033] +Content-type: text/plain; charset=UTF-8 + +From + +https://www.intel.com/content/www/us/en/support/articles/000059422/processors.html + +* Intel TSX will be disabled by default. +* The processor will force abort all Restricted Transactional Memory (RTM) + transactions by default. +* A new CPUID bit CPUID.07H.0H.EDX[11](RTM_ALWAYS_ABORT) will be enumerated, + which is set to indicate to updated software that the loaded microcode is + forcing RTM abort. +* On processors that enumerate support for RTM, the CPUID enumeration bits + for Intel TSX (CPUID.07H.0H.EBX[11] and CPUID.07H.0H.EBX[4]) continue to + be set by default after microcode update. +* Workloads that were benefited from Intel TSX might experience a change + in performance. +* System software may use a new bit in Model-Specific Register (MSR) 0x10F + TSX_FORCE_ABORT[TSX_CPUID_CLEAR] functionality to clear the Hardware Lock + Elision (HLE) and RTM bits to indicate to software that Intel TSX is + disabled. + +1. Add RTM_ALWAYS_ABORT to CPUID features. +2. Set RTM usable only if RTM_ALWAYS_ABORT isn't set. This skips the +string/tst-memchr-rtm etc. testcases on the affected processors, which +always fail after a microcde update. +3. Check RTM feature, instead of usability, against /proc/cpuinfo. + +This fixes BZ #28033. +--- + manual/platform.texi | 3 +++ + sysdeps/x86/cpu-features.c | 5 ++++- + sysdeps/x86/sys/platform/x86.h | 6 +++--- + sysdeps/x86/tst-cpu-features-supports.c | 2 +- + sysdeps/x86/tst-get-cpu-features.c | 2 ++ + 5 files changed, 13 insertions(+), 5 deletions(-) + +Conflicts: + sysdeps/x86/bits/platform/x86.h + (doesn't exist) + sysdeps/x86/bits/platform/x86.h + (account for lack of upstream renames) + +diff --git a/manual/platform.texi b/manual/platform.texi +index 8fec2933..b7e8aef7 100644 +--- a/manual/platform.texi ++++ b/manual/platform.texi +@@ -510,6 +510,9 @@ capability. + @item + @code{RTM} -- RTM instruction extensions. + ++@item ++@code{RTM_ALWAYS_ABORT} -- Transactions always abort, making RTM unusable. ++ + @item + @code{SDBG} -- IA32_DEBUG_INTERFACE MSR for silicon debug. + +diff --git a/sysdeps/x86/cpu-features.c b/sysdeps/x86/cpu-features.c +index 3610ee5c..4889f062 100644 +--- a/sysdeps/x86/cpu-features.c ++++ b/sysdeps/x86/cpu-features.c +@@ -74,7 +74,6 @@ update_usable (struct cpu_features *cpu_features) + CPU_FEATURE_SET_USABLE (cpu_features, HLE); + CPU_FEATURE_SET_USABLE (cpu_features, BMI2); + CPU_FEATURE_SET_USABLE (cpu_features, ERMS); +- CPU_FEATURE_SET_USABLE (cpu_features, RTM); + CPU_FEATURE_SET_USABLE (cpu_features, RDSEED); + CPU_FEATURE_SET_USABLE (cpu_features, ADX); + CPU_FEATURE_SET_USABLE (cpu_features, CLFLUSHOPT); +@@ -90,6 +89,7 @@ update_usable (struct cpu_features *cpu_features) + CPU_FEATURE_SET_USABLE (cpu_features, MOVDIRI); + CPU_FEATURE_SET_USABLE (cpu_features, MOVDIR64B); + CPU_FEATURE_SET_USABLE (cpu_features, FSRM); ++ CPU_FEATURE_SET_USABLE (cpu_features, RTM_ALWAYS_ABORT); + CPU_FEATURE_SET_USABLE (cpu_features, SERIALIZE); + CPU_FEATURE_SET_USABLE (cpu_features, TSXLDTRK); + CPU_FEATURE_SET_USABLE (cpu_features, LAHF64_SAHF64); +@@ -779,6 +779,9 @@ no_cpuid: + GLRO(dl_platform) = "i586"; + #endif + ++ if (!CPU_FEATURES_CPU_P (cpu_features, RTM_ALWAYS_ABORT)) ++ CPU_FEATURE_SET_USABLE (cpu_features, RTM); ++ + #if CET_ENABLED + # if HAVE_TUNABLES + TUNABLE_GET (x86_ibt, tunable_val_t *, +diff --git a/sysdeps/x86/sys/platform/x86.h b/sysdeps/x86/sys/platform/x86.h +index e5cc7c68..7a434926 100644 +--- a/sysdeps/x86/sys/platform/x86.h ++++ b/sysdeps/x86/sys/platform/x86.h +@@ -247,7 +247,7 @@ extern const struct cpu_features *__x86_get_cpu_features (unsigned int) + #define bit_cpu_AVX512_VP2INTERSECT (1u << 8) + #define bit_cpu_INDEX_7_EDX_9 (1u << 9) + #define bit_cpu_MD_CLEAR (1u << 10) +-#define bit_cpu_INDEX_7_EDX_11 (1u << 11) ++#define bit_cpu_RTM_ALWAYS_ABORT (1u << 11) + #define bit_cpu_INDEX_7_EDX_12 (1u << 12) + #define bit_cpu_INDEX_7_EDX_13 (1u << 13) + #define bit_cpu_SERIALIZE (1u << 14) +@@ -471,7 +471,7 @@ extern const struct cpu_features *__x86_get_cpu_features (unsigned int) + #define index_cpu_AVX512_VP2INTERSECT COMMON_CPUID_INDEX_7 + #define index_cpu_INDEX_7_EDX_9 COMMON_CPUID_INDEX_7 + #define index_cpu_MD_CLEAR COMMON_CPUID_INDEX_7 +-#define index_cpu_INDEX_7_EDX_11 COMMON_CPUID_INDEX_7 ++#define index_cpu_RTM_ALWAYS_ABORT COMMON_CPUID_INDEX_7 + #define index_cpu_INDEX_7_EDX_12 COMMON_CPUID_INDEX_7 + #define index_cpu_INDEX_7_EDX_13 COMMON_CPUID_INDEX_7 + #define index_cpu_SERIALIZE COMMON_CPUID_INDEX_7 +@@ -695,7 +695,7 @@ extern const struct cpu_features *__x86_get_cpu_features (unsigned int) + #define reg_AVX512_VP2INTERSECT edx + #define reg_INDEX_7_EDX_9 edx + #define reg_MD_CLEAR edx +-#define reg_INDEX_7_EDX_11 edx ++#define reg_RTM_ALWAYS_ABORT edx + #define reg_INDEX_7_EDX_12 edx + #define reg_INDEX_7_EDX_13 edx + #define reg_SERIALIZE edx +diff --git a/sysdeps/x86/tst-cpu-features-supports.c b/sysdeps/x86/tst-cpu-features-supports.c +index 287cf01f..8100a319 100644 +--- a/sysdeps/x86/tst-cpu-features-supports.c ++++ b/sysdeps/x86/tst-cpu-features-supports.c +@@ -152,7 +152,7 @@ do_test (int argc, char **argv) + fails += CHECK_SUPPORTS (rdpid, RDPID); + fails += CHECK_SUPPORTS (rdrnd, RDRAND); + fails += CHECK_SUPPORTS (rdseed, RDSEED); +- fails += CHECK_SUPPORTS (rtm, RTM); ++ fails += CHECK_CPU_SUPPORTS (rtm, RTM); + fails += CHECK_SUPPORTS (serialize, SERIALIZE); + fails += CHECK_SUPPORTS (sha, SHA); + fails += CHECK_CPU_SUPPORTS (shstk, SHSTK); +diff --git a/sysdeps/x86/tst-get-cpu-features.c b/sysdeps/x86/tst-get-cpu-features.c +index 2763deb6..0717e5d8 100644 +--- a/sysdeps/x86/tst-get-cpu-features.c ++++ b/sysdeps/x86/tst-get-cpu-features.c +@@ -183,6 +183,7 @@ do_test (void) + CHECK_CPU_FEATURE (UINTR); + CHECK_CPU_FEATURE (AVX512_VP2INTERSECT); + CHECK_CPU_FEATURE (MD_CLEAR); ++ CHECK_CPU_FEATURE (RTM_ALWAYS_ABORT); + CHECK_CPU_FEATURE (SERIALIZE); + CHECK_CPU_FEATURE (HYBRID); + CHECK_CPU_FEATURE (TSXLDTRK); +@@ -344,6 +345,7 @@ do_test (void) + CHECK_CPU_FEATURE_USABLE (FSRM); + CHECK_CPU_FEATURE_USABLE (AVX512_VP2INTERSECT); + CHECK_CPU_FEATURE_USABLE (MD_CLEAR); ++ CHECK_CPU_FEATURE_USABLE (RTM_ALWAYS_ABORT); + CHECK_CPU_FEATURE_USABLE (SERIALIZE); + CHECK_CPU_FEATURE_USABLE (HYBRID); + CHECK_CPU_FEATURE_USABLE (TSXLDTRK); +-- +GitLab + diff --git a/SOURCES/glibc-RHEL-15696-33.patch b/SOURCES/glibc-RHEL-15696-33.patch new file mode 100644 index 0000000..1196471 --- /dev/null +++ b/SOURCES/glibc-RHEL-15696-33.patch @@ -0,0 +1,51 @@ +From 0679442defedf7e52a94264975880ab8674736b2 Mon Sep 17 00:00:00 2001 +From: Noah Goldstein +Date: Thu, 8 Jul 2021 16:13:19 -0400 +Subject: [PATCH] x86: Remove wcsnlen-sse4_1 from wcslen ifunc-impl-list [BZ + #28064] +Content-type: text/plain; charset=UTF-8 + +The following commit + +commit 6f573a27b6c8b4236445810a44660612323f5a73 +Author: Noah Goldstein +Date: Wed Jun 23 01:19:34 2021 -0400 + + x86-64: Add wcslen optimize for sse4.1 + +Added wcsnlen-sse4.1 to the wcslen ifunc implementation list and did +not add wcslen-sse4.1 to wcslen ifunc implementation list. This commit +fixes that by removing wcsnlen-sse4.1 from the wcslen ifunc +implementation list and adding wcslen-sse4.1 to the ifunc +implementation list. + +Testing: +test-wcslen.c, test-rsi-wcslen.c, and test-rsi-strlen.c are passing as +well as all other tests in wcsmbs and string. + +Signed-off-by: Noah Goldstein +Reviewed-by: H.J. Lu +Reviewed-by: H.J. Lu +--- + sysdeps/x86_64/multiarch/ifunc-impl-list.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/sysdeps/x86_64/multiarch/ifunc-impl-list.c b/sysdeps/x86_64/multiarch/ifunc-impl-list.c +index 580913ca..695cdba6 100644 +--- a/sysdeps/x86_64/multiarch/ifunc-impl-list.c ++++ b/sysdeps/x86_64/multiarch/ifunc-impl-list.c +@@ -657,9 +657,9 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + && CPU_FEATURE_USABLE (AVX512BW) + && CPU_FEATURE_USABLE (BMI2)), + __wcslen_evex) +- IFUNC_IMPL_ADD (array, i, wcsnlen, ++ IFUNC_IMPL_ADD (array, i, wcslen, + CPU_FEATURE_USABLE (SSE4_1), +- __wcsnlen_sse4_1) ++ __wcslen_sse4_1) + IFUNC_IMPL_ADD (array, i, wcslen, 1, __wcslen_sse2)) + + /* Support sysdeps/x86_64/multiarch/wcsnlen.c. */ +-- +GitLab + diff --git a/SOURCES/glibc-RHEL-15696-34.patch b/SOURCES/glibc-RHEL-15696-34.patch new file mode 100644 index 0000000..f7c9a56 --- /dev/null +++ b/SOURCES/glibc-RHEL-15696-34.patch @@ -0,0 +1,135 @@ +From c6272098323153db373f2986c67786ea8c85f1cf Mon Sep 17 00:00:00 2001 +From: Noah Goldstein +Date: Tue, 15 Feb 2022 08:18:15 -0600 +Subject: [PATCH] x86: Fallback {str|wcs}cmp RTM in the ncmp overflow case [BZ + #28896] +Content-type: text/plain; charset=UTF-8 + +In the overflow fallback strncmp-avx2-rtm and wcsncmp-avx2-rtm would +call strcmp-avx2 and wcscmp-avx2 respectively. This would have +not checks around vzeroupper and would trigger spurious +aborts. This commit fixes that. + +test-strcmp, test-strncmp, test-wcscmp, and test-wcsncmp all pass on +AVX2 machines with and without RTM. + +Co-authored-by: H.J. Lu +--- + sysdeps/x86/Makefile | 2 +- + sysdeps/x86/tst-strncmp-rtm.c | 17 ++++++++++++++++- + sysdeps/x86_64/multiarch/strcmp-avx2.S | 2 +- + sysdeps/x86_64/multiarch/strncmp-avx2-rtm.S | 1 + + sysdeps/x86_64/multiarch/strncmp-avx2.S | 1 + + sysdeps/x86_64/multiarch/wcsncmp-avx2-rtm.S | 2 +- + sysdeps/x86_64/multiarch/wcsncmp-avx2.S | 2 +- + 7 files changed, 22 insertions(+), 5 deletions(-) + +Conflicts: + sysdeps/x86_64/multiarch/strcmp-avx2.S + (split into two patches due to upstream bug differences) + +diff --git a/sysdeps/x86/Makefile b/sysdeps/x86/Makefile +index 5be71ada..2d814915 100644 +--- a/sysdeps/x86/Makefile ++++ b/sysdeps/x86/Makefile +@@ -38,7 +38,7 @@ CFLAGS-tst-memset-rtm.c += -mrtm + CFLAGS-tst-strchr-rtm.c += -mrtm + CFLAGS-tst-strcpy-rtm.c += -mrtm + CFLAGS-tst-strlen-rtm.c += -mrtm +-CFLAGS-tst-strncmp-rtm.c += -mrtm ++CFLAGS-tst-strncmp-rtm.c += -mrtm -Wno-error + CFLAGS-tst-strrchr-rtm.c += -mrtm + endif + +diff --git a/sysdeps/x86/tst-strncmp-rtm.c b/sysdeps/x86/tst-strncmp-rtm.c +index 236ad951..4d0004b5 100644 +--- a/sysdeps/x86/tst-strncmp-rtm.c ++++ b/sysdeps/x86/tst-strncmp-rtm.c +@@ -16,6 +16,7 @@ + License along with the GNU C Library; if not, see + . */ + ++#include + #include + + #define LOOP 3000 +@@ -45,8 +46,22 @@ function (void) + return 1; + } + ++__attribute__ ((noinline, noclone)) ++static int ++function_overflow (void) ++{ ++ if (strncmp (string1, string2, SIZE_MAX) == 0) ++ return 0; ++ else ++ return 1; ++} ++ + static int + do_test (void) + { +- return do_test_1 ("strncmp", LOOP, prepare, function); ++ int status = do_test_1 ("strncmp", LOOP, prepare, function); ++ if (status != EXIT_SUCCESS) ++ return status; ++ status = do_test_1 ("strncmp", LOOP, prepare, function_overflow); ++ return status; + } +diff --git a/sysdeps/x86_64/multiarch/strcmp-avx2.S b/sysdeps/x86_64/multiarch/strcmp-avx2.S +index 5d1c9d90..433ae047 100644 +--- a/sysdeps/x86_64/multiarch/strcmp-avx2.S ++++ b/sysdeps/x86_64/multiarch/strcmp-avx2.S +@@ -95,7 +95,7 @@ ENTRY (STRCMP) + length to bound a valid memory region. In these cases just use + 'wcscmp'. */ + shrq $56, %rcx +- jnz __wcscmp_avx2 ++ jnz OVERFLOW_STRCMP + # endif + /* Convert units: from wide to byte char. */ + shl $2, %RDX_LP +diff --git a/sysdeps/x86_64/multiarch/strncmp-avx2-rtm.S b/sysdeps/x86_64/multiarch/strncmp-avx2-rtm.S +index 37d1224b..68bad365 100644 +--- a/sysdeps/x86_64/multiarch/strncmp-avx2-rtm.S ++++ b/sysdeps/x86_64/multiarch/strncmp-avx2-rtm.S +@@ -1,3 +1,4 @@ + #define STRCMP __strncmp_avx2_rtm + #define USE_AS_STRNCMP 1 ++#define OVERFLOW_STRCMP __strcmp_avx2_rtm + #include "strcmp-avx2-rtm.S" +diff --git a/sysdeps/x86_64/multiarch/strncmp-avx2.S b/sysdeps/x86_64/multiarch/strncmp-avx2.S +index 1678bcc2..f138e9f1 100644 +--- a/sysdeps/x86_64/multiarch/strncmp-avx2.S ++++ b/sysdeps/x86_64/multiarch/strncmp-avx2.S +@@ -1,3 +1,4 @@ + #define STRCMP __strncmp_avx2 + #define USE_AS_STRNCMP 1 ++#define OVERFLOW_STRCMP __strcmp_avx2 + #include "strcmp-avx2.S" +diff --git a/sysdeps/x86_64/multiarch/wcsncmp-avx2-rtm.S b/sysdeps/x86_64/multiarch/wcsncmp-avx2-rtm.S +index 4e88c70c..f467582c 100644 +--- a/sysdeps/x86_64/multiarch/wcsncmp-avx2-rtm.S ++++ b/sysdeps/x86_64/multiarch/wcsncmp-avx2-rtm.S +@@ -1,5 +1,5 @@ + #define STRCMP __wcsncmp_avx2_rtm + #define USE_AS_STRNCMP 1 + #define USE_AS_WCSCMP 1 +- ++#define OVERFLOW_STRCMP __wcscmp_avx2_rtm + #include "strcmp-avx2-rtm.S" +diff --git a/sysdeps/x86_64/multiarch/wcsncmp-avx2.S b/sysdeps/x86_64/multiarch/wcsncmp-avx2.S +index 4fa1de4d..e9ede522 100644 +--- a/sysdeps/x86_64/multiarch/wcsncmp-avx2.S ++++ b/sysdeps/x86_64/multiarch/wcsncmp-avx2.S +@@ -1,5 +1,5 @@ + #define STRCMP __wcsncmp_avx2 + #define USE_AS_STRNCMP 1 + #define USE_AS_WCSCMP 1 +- ++#define OVERFLOW_STRCMP __wcscmp_avx2 + #include "strcmp-avx2.S" +-- +GitLab + diff --git a/SOURCES/glibc-RHEL-15696-35.patch b/SOURCES/glibc-RHEL-15696-35.patch new file mode 100644 index 0000000..5e4fbdd --- /dev/null +++ b/SOURCES/glibc-RHEL-15696-35.patch @@ -0,0 +1,51 @@ +From 55c7bcc71b84123d5d4bd2814366a6b05fcf8ebd Mon Sep 17 00:00:00 2001 +From: "H.J. Lu" +Date: Sat, 9 May 2020 12:04:23 -0700 +Subject: [PATCH] x86-64: Use RDX_LP on __x86_shared_non_temporal_threshold [BZ + #25966] +Content-type: text/plain; charset=UTF-8 + +Since __x86_shared_non_temporal_threshold is defined as + +long int __x86_shared_non_temporal_threshold; + +and long int is 4 bytes for x32, use RDX_LP to compare against +__x86_shared_non_temporal_threshold in assembly code. +--- + sysdeps/x86_64/multiarch/memmove-vec-unaligned-erms.S | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/sysdeps/x86_64/multiarch/memmove-vec-unaligned-erms.S b/sysdeps/x86_64/multiarch/memmove-vec-unaligned-erms.S +index 71f5954d..673b73aa 100644 +--- a/sysdeps/x86_64/multiarch/memmove-vec-unaligned-erms.S ++++ b/sysdeps/x86_64/multiarch/memmove-vec-unaligned-erms.S +@@ -245,7 +245,7 @@ L(return): + #endif + + L(movsb): +- cmpq __x86_shared_non_temporal_threshold(%rip), %rdx ++ cmp __x86_shared_non_temporal_threshold(%rip), %RDX_LP + jae L(more_8x_vec) + cmpq %rsi, %rdi + jb 1f +@@ -397,7 +397,7 @@ L(more_8x_vec): + addq %r8, %rdx + #if (defined USE_MULTIARCH || VEC_SIZE == 16) && IS_IN (libc) + /* Check non-temporal store threshold. */ +- cmpq __x86_shared_non_temporal_threshold(%rip), %rdx ++ cmp __x86_shared_non_temporal_threshold(%rip), %RDX_LP + ja L(large_forward) + #endif + L(loop_4x_vec_forward): +@@ -448,7 +448,7 @@ L(more_8x_vec_backward): + subq %r8, %rdx + #if (defined USE_MULTIARCH || VEC_SIZE == 16) && IS_IN (libc) + /* Check non-temporal store threshold. */ +- cmpq __x86_shared_non_temporal_threshold(%rip), %rdx ++ cmp __x86_shared_non_temporal_threshold(%rip), %RDX_LP + ja L(large_backward) + #endif + L(loop_4x_vec_backward): +-- +GitLab + diff --git a/SOURCES/glibc-RHEL-15696-36.patch b/SOURCES/glibc-RHEL-15696-36.patch new file mode 100644 index 0000000..e00b96e --- /dev/null +++ b/SOURCES/glibc-RHEL-15696-36.patch @@ -0,0 +1,44 @@ +From a35a59036ebae3efcdf5e8167610e0656fca9770 Mon Sep 17 00:00:00 2001 +From: "H.J. Lu" +Date: Thu, 11 Jun 2020 12:41:18 -0700 +Subject: [PATCH] x86_64: Use %xmmN with vpxor to clear a vector register +Content-type: text/plain; charset=UTF-8 + +Since "vpxor %xmmN, %xmmN, %xmmN" clears the whole vector register, use +%xmmN, instead of %ymmN, with vpxor to clear a vector register. +--- + sysdeps/x86_64/multiarch/strcmp-avx2.S | 4 ++-- + sysdeps/x86_64/multiarch/strrchr-avx2.S | 2 +- + 2 files changed, 3 insertions(+), 3 deletions(-) + +diff --git a/sysdeps/x86_64/multiarch/strcmp-avx2.S b/sysdeps/x86_64/multiarch/strcmp-avx2.S +index 433ae047..70d8499b 100644 +--- a/sysdeps/x86_64/multiarch/strcmp-avx2.S ++++ b/sysdeps/x86_64/multiarch/strcmp-avx2.S +@@ -105,8 +105,8 @@ ENTRY (STRCMP) + # endif + movl %edi, %eax + xorl %edx, %edx +- /* Make %ymm7 all zeros in this function. */ +- vpxor %ymm7, %ymm7, %ymm7 ++ /* Make %xmm7 (%ymm7) all zeros in this function. */ ++ vpxor %xmm7, %xmm7, %xmm7 + orl %esi, %eax + andl $(PAGE_SIZE - 1), %eax + cmpl $(PAGE_SIZE - (VEC_SIZE * 4)), %eax +diff --git a/sysdeps/x86_64/multiarch/strrchr-avx2.S b/sysdeps/x86_64/multiarch/strrchr-avx2.S +index 9f22a15e..c949410b 100644 +--- a/sysdeps/x86_64/multiarch/strrchr-avx2.S ++++ b/sysdeps/x86_64/multiarch/strrchr-avx2.S +@@ -48,7 +48,7 @@ ENTRY (STRRCHR) + movl %edi, %ecx + /* Broadcast CHAR to YMM4. */ + VPBROADCAST %xmm4, %ymm4 +- vpxor %ymm0, %ymm0, %ymm0 ++ vpxor %xmm0, %xmm0, %xmm0 + + /* Check if we may cross page boundary with one vector load. */ + andl $(2 * VEC_SIZE - 1), %ecx +-- +GitLab + diff --git a/SOURCES/glibc-RHEL-15696-37.patch b/SOURCES/glibc-RHEL-15696-37.patch new file mode 100644 index 0000000..10b0cc4 --- /dev/null +++ b/SOURCES/glibc-RHEL-15696-37.patch @@ -0,0 +1,359 @@ +From 1f745ecc2109890886b161d4791e1406fdfc29b8 Mon Sep 17 00:00:00 2001 +From: noah +Date: Wed, 3 Feb 2021 00:38:59 -0500 +Subject: [PATCH] x86-64: Refactor and improve performance of strchr-avx2.S +Content-type: text/plain; charset=UTF-8 + +No bug. Just seemed the performance could be improved a bit. Observed +and expected behavior are unchanged. Optimized body of main +loop. Updated page cross logic and optimized accordingly. Made a few +minor instruction selection modifications. No regressions in test +suite. Both test-strchrnul and test-strchr passed. +--- + sysdeps/x86_64/multiarch/strchr-avx2.S | 225 ++++++++++++------------- + sysdeps/x86_64/multiarch/strchr.c | 4 +- + 2 files changed, 114 insertions(+), 115 deletions(-) + +Conflicts: + sysdeps/x86_64/multiarch/strchr.c + (account for missing upstream macros) + +diff --git a/sysdeps/x86_64/multiarch/strchr-avx2.S b/sysdeps/x86_64/multiarch/strchr-avx2.S +index da7d2620..919d256c 100644 +--- a/sysdeps/x86_64/multiarch/strchr-avx2.S ++++ b/sysdeps/x86_64/multiarch/strchr-avx2.S +@@ -27,10 +27,12 @@ + # ifdef USE_AS_WCSCHR + # define VPBROADCAST vpbroadcastd + # define VPCMPEQ vpcmpeqd ++# define VPMINU vpminud + # define CHAR_REG esi + # else + # define VPBROADCAST vpbroadcastb + # define VPCMPEQ vpcmpeqb ++# define VPMINU vpminub + # define CHAR_REG sil + # endif + +@@ -43,71 +45,54 @@ + # endif + + # define VEC_SIZE 32 ++# define PAGE_SIZE 4096 + + .section SECTION(.text),"ax",@progbits + ENTRY (STRCHR) + movl %edi, %ecx +- /* Broadcast CHAR to YMM0. */ ++# ifndef USE_AS_STRCHRNUL ++ xorl %edx, %edx ++# endif ++ ++ /* Broadcast CHAR to YMM0. */ + vmovd %esi, %xmm0 + vpxor %xmm9, %xmm9, %xmm9 + VPBROADCAST %xmm0, %ymm0 +- /* Check if we may cross page boundary with one vector load. */ +- andl $(2 * VEC_SIZE - 1), %ecx +- cmpl $VEC_SIZE, %ecx +- ja L(cros_page_boundary) + +- /* Check the first VEC_SIZE bytes. Search for both CHAR and the +- null byte. */ +- vmovdqu (%rdi), %ymm8 +- VPCMPEQ %ymm8, %ymm0, %ymm1 +- VPCMPEQ %ymm8, %ymm9, %ymm2 +- vpor %ymm1, %ymm2, %ymm1 +- vpmovmskb %ymm1, %eax +- testl %eax, %eax +- jnz L(first_vec_x0) ++ /* Check if we cross page boundary with one vector load. */ ++ andl $(PAGE_SIZE - 1), %ecx ++ cmpl $(PAGE_SIZE - VEC_SIZE), %ecx ++ ja L(cross_page_boundary) + +- /* Align data for aligned loads in the loop. */ +- addq $VEC_SIZE, %rdi +- andl $(VEC_SIZE - 1), %ecx +- andq $-VEC_SIZE, %rdi +- +- jmp L(more_4x_vec) +- +- .p2align 4 +-L(cros_page_boundary): +- andl $(VEC_SIZE - 1), %ecx +- andq $-VEC_SIZE, %rdi ++ /* Check the first VEC_SIZE bytes. Search for both CHAR and the ++ null byte. */ + vmovdqu (%rdi), %ymm8 + VPCMPEQ %ymm8, %ymm0, %ymm1 + VPCMPEQ %ymm8, %ymm9, %ymm2 + vpor %ymm1, %ymm2, %ymm1 + vpmovmskb %ymm1, %eax +- /* Remove the leading bytes. */ +- sarl %cl, %eax + testl %eax, %eax +- jz L(aligned_more) +- /* Found CHAR or the null byte. */ ++ jz L(more_vecs) + tzcntl %eax, %eax +- addq %rcx, %rax +-# ifdef USE_AS_STRCHRNUL ++ /* Found CHAR or the null byte. */ + addq %rdi, %rax +-# else +- xorl %edx, %edx +- leaq (%rdi, %rax), %rax +- cmp (%rax), %CHAR_REG ++# ifndef USE_AS_STRCHRNUL ++ cmp (%rax), %CHAR_REG + cmovne %rdx, %rax + # endif + L(return_vzeroupper): + ZERO_UPPER_VEC_REGISTERS_RETURN + + .p2align 4 ++L(more_vecs): ++ /* Align data for aligned loads in the loop. */ ++ andq $-VEC_SIZE, %rdi + L(aligned_more): +- addq $VEC_SIZE, %rdi + +-L(more_4x_vec): +- /* Check the first 4 * VEC_SIZE. Only one VEC_SIZE at a time +- since data is only aligned to VEC_SIZE. */ +- vmovdqa (%rdi), %ymm8 ++ /* Check the next 4 * VEC_SIZE. Only one VEC_SIZE at a time ++ since data is only aligned to VEC_SIZE. */ ++ vmovdqa VEC_SIZE(%rdi), %ymm8 ++ addq $VEC_SIZE, %rdi + VPCMPEQ %ymm8, %ymm0, %ymm1 + VPCMPEQ %ymm8, %ymm9, %ymm2 + vpor %ymm1, %ymm2, %ymm1 +@@ -137,61 +122,24 @@ L(more_4x_vec): + vpor %ymm1, %ymm2, %ymm1 + vpmovmskb %ymm1, %eax + testl %eax, %eax +- jnz L(first_vec_x3) +- +- addq $(VEC_SIZE * 4), %rdi +- +- /* Align data to 4 * VEC_SIZE. */ +- movq %rdi, %rcx +- andl $(4 * VEC_SIZE - 1), %ecx +- andq $-(4 * VEC_SIZE), %rdi +- +- .p2align 4 +-L(loop_4x_vec): +- /* Compare 4 * VEC at a time forward. */ +- vmovdqa (%rdi), %ymm5 +- vmovdqa VEC_SIZE(%rdi), %ymm6 +- vmovdqa (VEC_SIZE * 2)(%rdi), %ymm7 +- vmovdqa (VEC_SIZE * 3)(%rdi), %ymm8 +- +- VPCMPEQ %ymm5, %ymm0, %ymm1 +- VPCMPEQ %ymm6, %ymm0, %ymm2 +- VPCMPEQ %ymm7, %ymm0, %ymm3 +- VPCMPEQ %ymm8, %ymm0, %ymm4 +- +- VPCMPEQ %ymm5, %ymm9, %ymm5 +- VPCMPEQ %ymm6, %ymm9, %ymm6 +- VPCMPEQ %ymm7, %ymm9, %ymm7 +- VPCMPEQ %ymm8, %ymm9, %ymm8 +- +- vpor %ymm1, %ymm5, %ymm1 +- vpor %ymm2, %ymm6, %ymm2 +- vpor %ymm3, %ymm7, %ymm3 +- vpor %ymm4, %ymm8, %ymm4 +- +- vpor %ymm1, %ymm2, %ymm5 +- vpor %ymm3, %ymm4, %ymm6 +- +- vpor %ymm5, %ymm6, %ymm5 +- +- vpmovmskb %ymm5, %eax +- testl %eax, %eax +- jnz L(4x_vec_end) +- +- addq $(VEC_SIZE * 4), %rdi ++ jz L(prep_loop_4x) + +- jmp L(loop_4x_vec) ++ tzcntl %eax, %eax ++ leaq (VEC_SIZE * 3)(%rdi, %rax), %rax ++# ifndef USE_AS_STRCHRNUL ++ cmp (%rax), %CHAR_REG ++ cmovne %rdx, %rax ++# endif ++ VZEROUPPER ++ ret + + .p2align 4 + L(first_vec_x0): +- /* Found CHAR or the null byte. */ + tzcntl %eax, %eax +-# ifdef USE_AS_STRCHRNUL ++ /* Found CHAR or the null byte. */ + addq %rdi, %rax +-# else +- xorl %edx, %edx +- leaq (%rdi, %rax), %rax +- cmp (%rax), %CHAR_REG ++# ifndef USE_AS_STRCHRNUL ++ cmp (%rax), %CHAR_REG + cmovne %rdx, %rax + # endif + VZEROUPPER_RETURN +@@ -199,13 +147,9 @@ L(first_vec_x0): + .p2align 4 + L(first_vec_x1): + tzcntl %eax, %eax +-# ifdef USE_AS_STRCHRNUL +- addq $VEC_SIZE, %rax +- addq %rdi, %rax +-# else +- xorl %edx, %edx + leaq VEC_SIZE(%rdi, %rax), %rax +- cmp (%rax), %CHAR_REG ++# ifndef USE_AS_STRCHRNUL ++ cmp (%rax), %CHAR_REG + cmovne %rdx, %rax + # endif + VZEROUPPER_RETURN +@@ -213,42 +157,97 @@ L(first_vec_x1): + .p2align 4 + L(first_vec_x2): + tzcntl %eax, %eax +-# ifdef USE_AS_STRCHRNUL +- addq $(VEC_SIZE * 2), %rax +- addq %rdi, %rax +-# else +- xorl %edx, %edx ++ /* Found CHAR or the null byte. */ + leaq (VEC_SIZE * 2)(%rdi, %rax), %rax +- cmp (%rax), %CHAR_REG ++# ifndef USE_AS_STRCHRNUL ++ cmp (%rax), %CHAR_REG + cmovne %rdx, %rax + # endif + VZEROUPPER_RETURN + ++L(prep_loop_4x): ++ /* Align data to 4 * VEC_SIZE. */ ++ andq $-(VEC_SIZE * 4), %rdi ++ + .p2align 4 +-L(4x_vec_end): ++L(loop_4x_vec): ++ /* Compare 4 * VEC at a time forward. */ ++ vmovdqa (VEC_SIZE * 4)(%rdi), %ymm5 ++ vmovdqa (VEC_SIZE * 5)(%rdi), %ymm6 ++ vmovdqa (VEC_SIZE * 6)(%rdi), %ymm7 ++ vmovdqa (VEC_SIZE * 7)(%rdi), %ymm8 ++ ++ /* Leaves only CHARS matching esi as 0. */ ++ vpxor %ymm5, %ymm0, %ymm1 ++ vpxor %ymm6, %ymm0, %ymm2 ++ vpxor %ymm7, %ymm0, %ymm3 ++ vpxor %ymm8, %ymm0, %ymm4 ++ ++ VPMINU %ymm1, %ymm5, %ymm1 ++ VPMINU %ymm2, %ymm6, %ymm2 ++ VPMINU %ymm3, %ymm7, %ymm3 ++ VPMINU %ymm4, %ymm8, %ymm4 ++ ++ VPMINU %ymm1, %ymm2, %ymm5 ++ VPMINU %ymm3, %ymm4, %ymm6 ++ ++ VPMINU %ymm5, %ymm6, %ymm5 ++ ++ VPCMPEQ %ymm5, %ymm9, %ymm5 ++ vpmovmskb %ymm5, %eax ++ ++ addq $(VEC_SIZE * 4), %rdi ++ testl %eax, %eax ++ jz L(loop_4x_vec) ++ ++ VPCMPEQ %ymm1, %ymm9, %ymm1 + vpmovmskb %ymm1, %eax + testl %eax, %eax + jnz L(first_vec_x0) ++ ++ VPCMPEQ %ymm2, %ymm9, %ymm2 + vpmovmskb %ymm2, %eax + testl %eax, %eax + jnz L(first_vec_x1) +- vpmovmskb %ymm3, %eax +- testl %eax, %eax +- jnz L(first_vec_x2) ++ ++ VPCMPEQ %ymm3, %ymm9, %ymm3 ++ VPCMPEQ %ymm4, %ymm9, %ymm4 ++ vpmovmskb %ymm3, %ecx + vpmovmskb %ymm4, %eax ++ salq $32, %rax ++ orq %rcx, %rax ++ tzcntq %rax, %rax ++ leaq (VEC_SIZE * 2)(%rdi, %rax), %rax ++# ifndef USE_AS_STRCHRNUL ++ cmp (%rax), %CHAR_REG ++ cmovne %rdx, %rax ++# endif ++ VZEROUPPER ++ ret ++ ++ /* Cold case for crossing page with first load. */ ++ .p2align 4 ++L(cross_page_boundary): ++ andq $-VEC_SIZE, %rdi ++ andl $(VEC_SIZE - 1), %ecx ++ ++ vmovdqa (%rdi), %ymm8 ++ VPCMPEQ %ymm8, %ymm0, %ymm1 ++ VPCMPEQ %ymm8, %ymm9, %ymm2 ++ vpor %ymm1, %ymm2, %ymm1 ++ vpmovmskb %ymm1, %eax ++ /* Remove the leading bits. */ ++ sarxl %ecx, %eax, %eax + testl %eax, %eax +-L(first_vec_x3): ++ jz L(aligned_more) + tzcntl %eax, %eax +-# ifdef USE_AS_STRCHRNUL +- addq $(VEC_SIZE * 3), %rax ++ addq %rcx, %rdi + addq %rdi, %rax +-# else +- xorl %edx, %edx +- leaq (VEC_SIZE * 3)(%rdi, %rax), %rax +- cmp (%rax), %CHAR_REG ++# ifndef USE_AS_STRCHRNUL ++ cmp (%rax), %CHAR_REG + cmovne %rdx, %rax + # endif + VZEROUPPER_RETURN + + END (STRCHR) +-#endif ++# endif +diff --git a/sysdeps/x86_64/multiarch/strchr.c b/sysdeps/x86_64/multiarch/strchr.c +index 7e582f02..5225bd4f 100644 +--- a/sysdeps/x86_64/multiarch/strchr.c ++++ b/sysdeps/x86_64/multiarch/strchr.c +@@ -38,11 +38,11 @@ IFUNC_SELECTOR (void) + const struct cpu_features* cpu_features = __get_cpu_features (); + + if (CPU_FEATURE_USABLE_P (cpu_features, AVX2) ++ && CPU_FEATURE_USABLE_P (cpu_features, BMI2) + && CPU_FEATURES_ARCH_P (cpu_features, AVX_Fast_Unaligned_Load)) + { + if (CPU_FEATURE_USABLE_P (cpu_features, AVX512VL) +- && CPU_FEATURE_USABLE_P (cpu_features, AVX512BW) +- && CPU_FEATURE_USABLE_P (cpu_features, BMI2)) ++ && CPU_FEATURE_USABLE_P (cpu_features, AVX512BW)) + return OPTIMIZE (evex); + + if (CPU_FEATURE_USABLE_P (cpu_features, RTM)) +-- +GitLab + diff --git a/SOURCES/glibc-RHEL-15696-38.patch b/SOURCES/glibc-RHEL-15696-38.patch new file mode 100644 index 0000000..f97ab23 --- /dev/null +++ b/SOURCES/glibc-RHEL-15696-38.patch @@ -0,0 +1,67 @@ +From 3ec5d83d2a237d39e7fd6ef7a0bc8ac4c171a4a5 Mon Sep 17 00:00:00 2001 +From: "H.J. Lu" +Date: Sat, 25 Jan 2020 14:19:40 -0800 +Subject: [PATCH] x86-64: Avoid rep movsb with short distance [BZ #27130] +Content-type: text/plain; charset=UTF-8 + +When copying with "rep movsb", if the distance between source and +destination is N*4GB + [1..63] with N >= 0, performance may be very +slow. This patch updates memmove-vec-unaligned-erms.S for AVX and +AVX512 versions with the distance in RCX: + + cmpl $63, %ecx + // Don't use "rep movsb" if ECX <= 63 + jbe L(Don't use rep movsb") + Use "rep movsb" + +Benchtests data with bench-memcpy, bench-memcpy-large, bench-memcpy-random +and bench-memcpy-walk on Skylake, Ice Lake and Tiger Lake show that its +performance impact is within noise range as "rep movsb" is only used for +data size >= 4KB. +--- + .../multiarch/memmove-vec-unaligned-erms.S | 21 +++++++++++++++++++ + 1 file changed, 21 insertions(+) + +diff --git a/sysdeps/x86_64/multiarch/memmove-vec-unaligned-erms.S b/sysdeps/x86_64/multiarch/memmove-vec-unaligned-erms.S +index 673b73aa..c475fed4 100644 +--- a/sysdeps/x86_64/multiarch/memmove-vec-unaligned-erms.S ++++ b/sysdeps/x86_64/multiarch/memmove-vec-unaligned-erms.S +@@ -64,6 +64,13 @@ + # endif + #endif + ++/* Avoid short distance rep movsb only with non-SSE vector. */ ++#ifndef AVOID_SHORT_DISTANCE_REP_MOVSB ++# define AVOID_SHORT_DISTANCE_REP_MOVSB (VEC_SIZE > 16) ++#else ++# define AVOID_SHORT_DISTANCE_REP_MOVSB 0 ++#endif ++ + #ifndef PREFETCH + # define PREFETCH(addr) prefetcht0 addr + #endif +@@ -255,7 +262,21 @@ L(movsb): + cmpq %r9, %rdi + /* Avoid slow backward REP MOVSB. */ + jb L(more_8x_vec_backward) ++# if AVOID_SHORT_DISTANCE_REP_MOVSB ++ movq %rdi, %rcx ++ subq %rsi, %rcx ++ jmp 2f ++# endif + 1: ++# if AVOID_SHORT_DISTANCE_REP_MOVSB ++ movq %rsi, %rcx ++ subq %rdi, %rcx ++2: ++/* Avoid "rep movsb" if RCX, the distance between source and destination, ++ is N*4GB + [1..63] with N >= 0. */ ++ cmpl $63, %ecx ++ jbe L(more_2x_vec) /* Avoid "rep movsb" if ECX <= 63. */ ++# endif + mov %RDX_LP, %RCX_LP + rep movsb + L(nop): +-- +GitLab + diff --git a/SOURCES/glibc-RHEL-15696-39.patch b/SOURCES/glibc-RHEL-15696-39.patch new file mode 100644 index 0000000..8343ba9 --- /dev/null +++ b/SOURCES/glibc-RHEL-15696-39.patch @@ -0,0 +1,449 @@ +From 1a8605b6cd257e8a74e29b5b71c057211f5fb847 Mon Sep 17 00:00:00 2001 +From: noah +Date: Sat, 3 Apr 2021 04:12:15 -0400 +Subject: [PATCH] x86: Update large memcpy case in memmove-vec-unaligned-erms.S +Content-type: text/plain; charset=UTF-8 + +No Bug. This commit updates the large memcpy case (no overlap). The +update is to perform memcpy on either 2 or 4 contiguous pages at +once. This 1) helps to alleviate the affects of false memory aliasing +when destination and source have a close 4k alignment and 2) In most +cases and for most DRAM units is a modestly more efficient access +pattern. These changes are a clear performance improvement for +VEC_SIZE =16/32, though more ambiguous for VEC_SIZE=64. test-memcpy, +test-memccpy, test-mempcpy, test-memmove, and tst-memmove-overflow all +pass. + +Signed-off-by: Noah Goldstein +--- + .../multiarch/memmove-vec-unaligned-erms.S | 338 ++++++++++++++---- + 1 file changed, 265 insertions(+), 73 deletions(-) + +Conflicts: + sysdeps/x86_64/multiarch/memmove-vec-unaligned-erms.S + (different number of sections) + +diff --git a/sysdeps/x86_64/multiarch/memmove-vec-unaligned-erms.S b/sysdeps/x86_64/multiarch/memmove-vec-unaligned-erms.S +index c475fed4..3e2dd6bc 100644 +--- a/sysdeps/x86_64/multiarch/memmove-vec-unaligned-erms.S ++++ b/sysdeps/x86_64/multiarch/memmove-vec-unaligned-erms.S +@@ -32,7 +32,16 @@ + overlapping addresses. + 6. If size >= __x86_shared_non_temporal_threshold and there is no + overlap between destination and source, use non-temporal store +- instead of aligned store. */ ++ instead of aligned store copying from either 2 or 4 pages at ++ once. ++ 8. For point 7) if size < 16 * __x86_shared_non_temporal_threshold ++ and source and destination do not page alias, copy from 2 pages ++ at once using non-temporal stores. Page aliasing in this case is ++ considered true if destination's page alignment - sources' page ++ alignment is less than 8 * VEC_SIZE. ++ 9. If size >= 16 * __x86_shared_non_temporal_threshold or source ++ and destination do page alias copy from 4 pages at once using ++ non-temporal stores. */ + + #include + +@@ -64,6 +73,34 @@ + # endif + #endif + ++#ifndef PAGE_SIZE ++# define PAGE_SIZE 4096 ++#endif ++ ++#if PAGE_SIZE != 4096 ++# error Unsupported PAGE_SIZE ++#endif ++ ++#ifndef LOG_PAGE_SIZE ++# define LOG_PAGE_SIZE 12 ++#endif ++ ++#if PAGE_SIZE != (1 << LOG_PAGE_SIZE) ++# error Invalid LOG_PAGE_SIZE ++#endif ++ ++/* Byte per page for large_memcpy inner loop. */ ++#if VEC_SIZE == 64 ++# define LARGE_LOAD_SIZE (VEC_SIZE * 2) ++#else ++# define LARGE_LOAD_SIZE (VEC_SIZE * 4) ++#endif ++ ++/* Amount to shift rdx by to compare for memcpy_large_4x. */ ++#ifndef LOG_4X_MEMCPY_THRESH ++# define LOG_4X_MEMCPY_THRESH 4 ++#endif ++ + /* Avoid short distance rep movsb only with non-SSE vector. */ + #ifndef AVOID_SHORT_DISTANCE_REP_MOVSB + # define AVOID_SHORT_DISTANCE_REP_MOVSB (VEC_SIZE > 16) +@@ -103,6 +140,28 @@ + # error Unsupported PREFETCH_SIZE! + #endif + ++#if LARGE_LOAD_SIZE == (VEC_SIZE * 2) ++# define LOAD_ONE_SET(base, offset, vec0, vec1, ...) \ ++ VMOVU (offset)base, vec0; \ ++ VMOVU ((offset) + VEC_SIZE)base, vec1; ++# define STORE_ONE_SET(base, offset, vec0, vec1, ...) \ ++ VMOVNT vec0, (offset)base; \ ++ VMOVNT vec1, ((offset) + VEC_SIZE)base; ++#elif LARGE_LOAD_SIZE == (VEC_SIZE * 4) ++# define LOAD_ONE_SET(base, offset, vec0, vec1, vec2, vec3) \ ++ VMOVU (offset)base, vec0; \ ++ VMOVU ((offset) + VEC_SIZE)base, vec1; \ ++ VMOVU ((offset) + VEC_SIZE * 2)base, vec2; \ ++ VMOVU ((offset) + VEC_SIZE * 3)base, vec3; ++# define STORE_ONE_SET(base, offset, vec0, vec1, vec2, vec3) \ ++ VMOVNT vec0, (offset)base; \ ++ VMOVNT vec1, ((offset) + VEC_SIZE)base; \ ++ VMOVNT vec2, ((offset) + VEC_SIZE * 2)base; \ ++ VMOVNT vec3, ((offset) + VEC_SIZE * 3)base; ++#else ++# error Invalid LARGE_LOAD_SIZE ++#endif ++ + #ifndef SECTION + # error SECTION is not defined! + #endif +@@ -390,6 +449,15 @@ L(last_4x_vec): + VZEROUPPER_RETURN + + L(more_8x_vec): ++ /* Check if non-temporal move candidate. */ ++#if (defined USE_MULTIARCH || VEC_SIZE == 16) && IS_IN (libc) ++ /* Check non-temporal store threshold. */ ++ cmp __x86_shared_non_temporal_threshold(%rip), %RDX_LP ++ ja L(large_memcpy_2x) ++#endif ++ /* Entry if rdx is greater than non-temporal threshold but there ++ is overlap. */ ++L(more_8x_vec_check): + cmpq %rsi, %rdi + ja L(more_8x_vec_backward) + /* Source == destination is less common. */ +@@ -416,24 +484,21 @@ L(more_8x_vec): + subq %r8, %rdi + /* Adjust length. */ + addq %r8, %rdx +-#if (defined USE_MULTIARCH || VEC_SIZE == 16) && IS_IN (libc) +- /* Check non-temporal store threshold. */ +- cmp __x86_shared_non_temporal_threshold(%rip), %RDX_LP +- ja L(large_forward) +-#endif ++ ++ .p2align 4 + L(loop_4x_vec_forward): + /* Copy 4 * VEC a time forward. */ + VMOVU (%rsi), %VEC(0) + VMOVU VEC_SIZE(%rsi), %VEC(1) + VMOVU (VEC_SIZE * 2)(%rsi), %VEC(2) + VMOVU (VEC_SIZE * 3)(%rsi), %VEC(3) +- addq $(VEC_SIZE * 4), %rsi +- subq $(VEC_SIZE * 4), %rdx ++ subq $-(VEC_SIZE * 4), %rsi ++ addq $-(VEC_SIZE * 4), %rdx + VMOVA %VEC(0), (%rdi) + VMOVA %VEC(1), VEC_SIZE(%rdi) + VMOVA %VEC(2), (VEC_SIZE * 2)(%rdi) + VMOVA %VEC(3), (VEC_SIZE * 3)(%rdi) +- addq $(VEC_SIZE * 4), %rdi ++ subq $-(VEC_SIZE * 4), %rdi + cmpq $(VEC_SIZE * 4), %rdx + ja L(loop_4x_vec_forward) + /* Store the last 4 * VEC. */ +@@ -467,24 +532,21 @@ L(more_8x_vec_backward): + subq %r8, %r9 + /* Adjust length. */ + subq %r8, %rdx +-#if (defined USE_MULTIARCH || VEC_SIZE == 16) && IS_IN (libc) +- /* Check non-temporal store threshold. */ +- cmp __x86_shared_non_temporal_threshold(%rip), %RDX_LP +- ja L(large_backward) +-#endif ++ ++ .p2align 4 + L(loop_4x_vec_backward): + /* Copy 4 * VEC a time backward. */ + VMOVU (%rcx), %VEC(0) + VMOVU -VEC_SIZE(%rcx), %VEC(1) + VMOVU -(VEC_SIZE * 2)(%rcx), %VEC(2) + VMOVU -(VEC_SIZE * 3)(%rcx), %VEC(3) +- subq $(VEC_SIZE * 4), %rcx +- subq $(VEC_SIZE * 4), %rdx ++ addq $-(VEC_SIZE * 4), %rcx ++ addq $-(VEC_SIZE * 4), %rdx + VMOVA %VEC(0), (%r9) + VMOVA %VEC(1), -VEC_SIZE(%r9) + VMOVA %VEC(2), -(VEC_SIZE * 2)(%r9) + VMOVA %VEC(3), -(VEC_SIZE * 3)(%r9) +- subq $(VEC_SIZE * 4), %r9 ++ addq $-(VEC_SIZE * 4), %r9 + cmpq $(VEC_SIZE * 4), %rdx + ja L(loop_4x_vec_backward) + /* Store the first 4 * VEC. */ +@@ -497,72 +559,202 @@ L(loop_4x_vec_backward): + VZEROUPPER_RETURN + + #if (defined USE_MULTIARCH || VEC_SIZE == 16) && IS_IN (libc) +-L(large_forward): ++ .p2align 4 ++L(large_memcpy_2x): ++ /* Compute absolute value of difference between source and ++ destination. */ ++ movq %rdi, %r9 ++ subq %rsi, %r9 ++ movq %r9, %r8 ++ leaq -1(%r9), %rcx ++ sarq $63, %r8 ++ xorq %r8, %r9 ++ subq %r8, %r9 + /* Don't use non-temporal store if there is overlap between +- destination and source since destination may be in cache +- when source is loaded. */ +- leaq (%rdi, %rdx), %r10 +- cmpq %r10, %rsi +- jb L(loop_4x_vec_forward) +-L(loop_large_forward): ++ destination and source since destination may be in cache when ++ source is loaded. */ ++ cmpq %r9, %rdx ++ ja L(more_8x_vec_check) ++ ++ /* Cache align destination. First store the first 64 bytes then ++ adjust alignments. */ ++ VMOVU (%rsi), %VEC(8) ++#if VEC_SIZE < 64 ++ VMOVU VEC_SIZE(%rsi), %VEC(9) ++#if VEC_SIZE < 32 ++ VMOVU (VEC_SIZE * 2)(%rsi), %VEC(10) ++ VMOVU (VEC_SIZE * 3)(%rsi), %VEC(11) ++#endif ++#endif ++ VMOVU %VEC(8), (%rdi) ++#if VEC_SIZE < 64 ++ VMOVU %VEC(9), VEC_SIZE(%rdi) ++#if VEC_SIZE < 32 ++ VMOVU %VEC(10), (VEC_SIZE * 2)(%rdi) ++ VMOVU %VEC(11), (VEC_SIZE * 3)(%rdi) ++#endif ++#endif ++ /* Adjust source, destination, and size. */ ++ movq %rdi, %r8 ++ andq $63, %r8 ++ /* Get the negative of offset for alignment. */ ++ subq $64, %r8 ++ /* Adjust source. */ ++ subq %r8, %rsi ++ /* Adjust destination which should be aligned now. */ ++ subq %r8, %rdi ++ /* Adjust length. */ ++ addq %r8, %rdx ++ ++ /* Test if source and destination addresses will alias. If they do ++ the larger pipeline in large_memcpy_4x alleviated the ++ performance drop. */ ++ testl $(PAGE_SIZE - VEC_SIZE * 8), %ecx ++ jz L(large_memcpy_4x) ++ ++ movq %rdx, %r10 ++ shrq $LOG_4X_MEMCPY_THRESH, %r10 ++ cmp __x86_shared_non_temporal_threshold(%rip), %r10 ++ jae L(large_memcpy_4x) ++ ++ /* edx will store remainder size for copying tail. */ ++ andl $(PAGE_SIZE * 2 - 1), %edx ++ /* r10 stores outer loop counter. */ ++ shrq $((LOG_PAGE_SIZE + 1) - LOG_4X_MEMCPY_THRESH), %r10 ++ /* Copy 4x VEC at a time from 2 pages. */ ++ .p2align 4 ++L(loop_large_memcpy_2x_outer): ++ /* ecx stores inner loop counter. */ ++ movl $(PAGE_SIZE / LARGE_LOAD_SIZE), %ecx ++L(loop_large_memcpy_2x_inner): ++ PREFETCH_ONE_SET(1, (%rsi), PREFETCHED_LOAD_SIZE) ++ PREFETCH_ONE_SET(1, (%rsi), PREFETCHED_LOAD_SIZE * 2) ++ PREFETCH_ONE_SET(1, (%rsi), PAGE_SIZE + PREFETCHED_LOAD_SIZE) ++ PREFETCH_ONE_SET(1, (%rsi), PAGE_SIZE + PREFETCHED_LOAD_SIZE * 2) ++ /* Load vectors from rsi. */ ++ LOAD_ONE_SET((%rsi), 0, %VEC(0), %VEC(1), %VEC(2), %VEC(3)) ++ LOAD_ONE_SET((%rsi), PAGE_SIZE, %VEC(4), %VEC(5), %VEC(6), %VEC(7)) ++ subq $-LARGE_LOAD_SIZE, %rsi ++ /* Non-temporal store vectors to rdi. */ ++ STORE_ONE_SET((%rdi), 0, %VEC(0), %VEC(1), %VEC(2), %VEC(3)) ++ STORE_ONE_SET((%rdi), PAGE_SIZE, %VEC(4), %VEC(5), %VEC(6), %VEC(7)) ++ subq $-LARGE_LOAD_SIZE, %rdi ++ decl %ecx ++ jnz L(loop_large_memcpy_2x_inner) ++ addq $PAGE_SIZE, %rdi ++ addq $PAGE_SIZE, %rsi ++ decq %r10 ++ jne L(loop_large_memcpy_2x_outer) ++ sfence ++ ++ /* Check if only last 4 loads are needed. */ ++ cmpl $(VEC_SIZE * 4), %edx ++ jbe L(large_memcpy_2x_end) ++ ++ /* Handle the last 2 * PAGE_SIZE bytes. */ ++L(loop_large_memcpy_2x_tail): + /* Copy 4 * VEC a time forward with non-temporal stores. */ +- PREFETCH_ONE_SET (1, (%rsi), PREFETCHED_LOAD_SIZE * 2) +- PREFETCH_ONE_SET (1, (%rsi), PREFETCHED_LOAD_SIZE * 3) ++ PREFETCH_ONE_SET (1, (%rsi), PREFETCHED_LOAD_SIZE) ++ PREFETCH_ONE_SET (1, (%rdi), PREFETCHED_LOAD_SIZE) + VMOVU (%rsi), %VEC(0) + VMOVU VEC_SIZE(%rsi), %VEC(1) + VMOVU (VEC_SIZE * 2)(%rsi), %VEC(2) + VMOVU (VEC_SIZE * 3)(%rsi), %VEC(3) +- addq $PREFETCHED_LOAD_SIZE, %rsi +- subq $PREFETCHED_LOAD_SIZE, %rdx +- VMOVNT %VEC(0), (%rdi) +- VMOVNT %VEC(1), VEC_SIZE(%rdi) +- VMOVNT %VEC(2), (VEC_SIZE * 2)(%rdi) +- VMOVNT %VEC(3), (VEC_SIZE * 3)(%rdi) +- addq $PREFETCHED_LOAD_SIZE, %rdi +- cmpq $PREFETCHED_LOAD_SIZE, %rdx +- ja L(loop_large_forward) +- sfence ++ subq $-(VEC_SIZE * 4), %rsi ++ addl $-(VEC_SIZE * 4), %edx ++ VMOVA %VEC(0), (%rdi) ++ VMOVA %VEC(1), VEC_SIZE(%rdi) ++ VMOVA %VEC(2), (VEC_SIZE * 2)(%rdi) ++ VMOVA %VEC(3), (VEC_SIZE * 3)(%rdi) ++ subq $-(VEC_SIZE * 4), %rdi ++ cmpl $(VEC_SIZE * 4), %edx ++ ja L(loop_large_memcpy_2x_tail) ++ ++L(large_memcpy_2x_end): + /* Store the last 4 * VEC. */ +- VMOVU %VEC(5), (%rcx) +- VMOVU %VEC(6), -VEC_SIZE(%rcx) +- VMOVU %VEC(7), -(VEC_SIZE * 2)(%rcx) +- VMOVU %VEC(8), -(VEC_SIZE * 3)(%rcx) +- /* Store the first VEC. */ +- VMOVU %VEC(4), (%r11) ++ VMOVU -(VEC_SIZE * 4)(%rsi, %rdx), %VEC(0) ++ VMOVU -(VEC_SIZE * 3)(%rsi, %rdx), %VEC(1) ++ VMOVU -(VEC_SIZE * 2)(%rsi, %rdx), %VEC(2) ++ VMOVU -VEC_SIZE(%rsi, %rdx), %VEC(3) ++ ++ VMOVU %VEC(0), -(VEC_SIZE * 4)(%rdi, %rdx) ++ VMOVU %VEC(1), -(VEC_SIZE * 3)(%rdi, %rdx) ++ VMOVU %VEC(2), -(VEC_SIZE * 2)(%rdi, %rdx) ++ VMOVU %VEC(3), -VEC_SIZE(%rdi, %rdx) + VZEROUPPER_RETURN + +-L(large_backward): +- /* Don't use non-temporal store if there is overlap between +- destination and source since destination may be in cache +- when source is loaded. */ +- leaq (%rcx, %rdx), %r10 +- cmpq %r10, %r9 +- jb L(loop_4x_vec_backward) +-L(loop_large_backward): +- /* Copy 4 * VEC a time backward with non-temporal stores. */ +- PREFETCH_ONE_SET (-1, (%rcx), -PREFETCHED_LOAD_SIZE * 2) +- PREFETCH_ONE_SET (-1, (%rcx), -PREFETCHED_LOAD_SIZE * 3) +- VMOVU (%rcx), %VEC(0) +- VMOVU -VEC_SIZE(%rcx), %VEC(1) +- VMOVU -(VEC_SIZE * 2)(%rcx), %VEC(2) +- VMOVU -(VEC_SIZE * 3)(%rcx), %VEC(3) +- subq $PREFETCHED_LOAD_SIZE, %rcx +- subq $PREFETCHED_LOAD_SIZE, %rdx +- VMOVNT %VEC(0), (%r9) +- VMOVNT %VEC(1), -VEC_SIZE(%r9) +- VMOVNT %VEC(2), -(VEC_SIZE * 2)(%r9) +- VMOVNT %VEC(3), -(VEC_SIZE * 3)(%r9) +- subq $PREFETCHED_LOAD_SIZE, %r9 +- cmpq $PREFETCHED_LOAD_SIZE, %rdx +- ja L(loop_large_backward) ++ .p2align 4 ++L(large_memcpy_4x): ++ movq %rdx, %r10 ++ /* edx will store remainder size for copying tail. */ ++ andl $(PAGE_SIZE * 4 - 1), %edx ++ /* r10 stores outer loop counter. */ ++ shrq $(LOG_PAGE_SIZE + 2), %r10 ++ /* Copy 4x VEC at a time from 4 pages. */ ++ .p2align 4 ++L(loop_large_memcpy_4x_outer): ++ /* ecx stores inner loop counter. */ ++ movl $(PAGE_SIZE / LARGE_LOAD_SIZE), %ecx ++L(loop_large_memcpy_4x_inner): ++ /* Only one prefetch set per page as doing 4 pages give more time ++ for prefetcher to keep up. */ ++ PREFETCH_ONE_SET(1, (%rsi), PREFETCHED_LOAD_SIZE) ++ PREFETCH_ONE_SET(1, (%rsi), PAGE_SIZE + PREFETCHED_LOAD_SIZE) ++ PREFETCH_ONE_SET(1, (%rsi), PAGE_SIZE * 2 + PREFETCHED_LOAD_SIZE) ++ PREFETCH_ONE_SET(1, (%rsi), PAGE_SIZE * 3 + PREFETCHED_LOAD_SIZE) ++ /* Load vectors from rsi. */ ++ LOAD_ONE_SET((%rsi), 0, %VEC(0), %VEC(1), %VEC(2), %VEC(3)) ++ LOAD_ONE_SET((%rsi), PAGE_SIZE, %VEC(4), %VEC(5), %VEC(6), %VEC(7)) ++ LOAD_ONE_SET((%rsi), PAGE_SIZE * 2, %VEC(8), %VEC(9), %VEC(10), %VEC(11)) ++ LOAD_ONE_SET((%rsi), PAGE_SIZE * 3, %VEC(12), %VEC(13), %VEC(14), %VEC(15)) ++ subq $-LARGE_LOAD_SIZE, %rsi ++ /* Non-temporal store vectors to rdi. */ ++ STORE_ONE_SET((%rdi), 0, %VEC(0), %VEC(1), %VEC(2), %VEC(3)) ++ STORE_ONE_SET((%rdi), PAGE_SIZE, %VEC(4), %VEC(5), %VEC(6), %VEC(7)) ++ STORE_ONE_SET((%rdi), PAGE_SIZE * 2, %VEC(8), %VEC(9), %VEC(10), %VEC(11)) ++ STORE_ONE_SET((%rdi), PAGE_SIZE * 3, %VEC(12), %VEC(13), %VEC(14), %VEC(15)) ++ subq $-LARGE_LOAD_SIZE, %rdi ++ decl %ecx ++ jnz L(loop_large_memcpy_4x_inner) ++ addq $(PAGE_SIZE * 3), %rdi ++ addq $(PAGE_SIZE * 3), %rsi ++ decq %r10 ++ jne L(loop_large_memcpy_4x_outer) + sfence +- /* Store the first 4 * VEC. */ +- VMOVU %VEC(4), (%rdi) +- VMOVU %VEC(5), VEC_SIZE(%rdi) +- VMOVU %VEC(6), (VEC_SIZE * 2)(%rdi) +- VMOVU %VEC(7), (VEC_SIZE * 3)(%rdi) +- /* Store the last VEC. */ +- VMOVU %VEC(8), (%r11) ++ /* Check if only last 4 loads are needed. */ ++ cmpl $(VEC_SIZE * 4), %edx ++ jbe L(large_memcpy_4x_end) ++ ++ /* Handle the last 4 * PAGE_SIZE bytes. */ ++L(loop_large_memcpy_4x_tail): ++ /* Copy 4 * VEC a time forward with non-temporal stores. */ ++ PREFETCH_ONE_SET (1, (%rsi), PREFETCHED_LOAD_SIZE) ++ PREFETCH_ONE_SET (1, (%rdi), PREFETCHED_LOAD_SIZE) ++ VMOVU (%rsi), %VEC(0) ++ VMOVU VEC_SIZE(%rsi), %VEC(1) ++ VMOVU (VEC_SIZE * 2)(%rsi), %VEC(2) ++ VMOVU (VEC_SIZE * 3)(%rsi), %VEC(3) ++ subq $-(VEC_SIZE * 4), %rsi ++ addl $-(VEC_SIZE * 4), %edx ++ VMOVA %VEC(0), (%rdi) ++ VMOVA %VEC(1), VEC_SIZE(%rdi) ++ VMOVA %VEC(2), (VEC_SIZE * 2)(%rdi) ++ VMOVA %VEC(3), (VEC_SIZE * 3)(%rdi) ++ subq $-(VEC_SIZE * 4), %rdi ++ cmpl $(VEC_SIZE * 4), %edx ++ ja L(loop_large_memcpy_4x_tail) ++ ++L(large_memcpy_4x_end): ++ /* Store the last 4 * VEC. */ ++ VMOVU -(VEC_SIZE * 4)(%rsi, %rdx), %VEC(0) ++ VMOVU -(VEC_SIZE * 3)(%rsi, %rdx), %VEC(1) ++ VMOVU -(VEC_SIZE * 2)(%rsi, %rdx), %VEC(2) ++ VMOVU -VEC_SIZE(%rsi, %rdx), %VEC(3) ++ ++ VMOVU %VEC(0), -(VEC_SIZE * 4)(%rdi, %rdx) ++ VMOVU %VEC(1), -(VEC_SIZE * 3)(%rdi, %rdx) ++ VMOVU %VEC(2), -(VEC_SIZE * 2)(%rdi, %rdx) ++ VMOVU %VEC(3), -VEC_SIZE(%rdi, %rdx) + VZEROUPPER_RETURN + #endif + END (MEMMOVE_SYMBOL (__memmove, unaligned_erms)) +-- +GitLab + diff --git a/SOURCES/glibc-RHEL-15696-4.patch b/SOURCES/glibc-RHEL-15696-4.patch new file mode 100644 index 0000000..531c171 --- /dev/null +++ b/SOURCES/glibc-RHEL-15696-4.patch @@ -0,0 +1,151 @@ +From ecd8b842cf37ea112e59cd9085ff1f1b6e208ae0 Mon Sep 17 00:00:00 2001 +From: "H.J. Lu" +Date: Mon, 21 Jan 2019 11:29:58 -0800 +Subject: [PATCH] x86-64 memrchr: Properly handle the length parameter [BZ# + 24097] +Content-type: text/plain; charset=UTF-8 + +On x32, the size_t parameter may be passed in the lower 32 bits of a +64-bit register with the non-zero upper 32 bits. The string/memory +functions written in assembly can only use the lower 32 bits of a +64-bit register as length or must clear the upper 32 bits before using +the full 64-bit register for length. + +This pach fixes memrchr for x32. Tested on x86-64 and x32. On x86-64, +libc.so is the same with and withou the fix. + + [BZ# 24097] + CVE-2019-6488 + * sysdeps/x86_64/memrchr.S: Use RDX_LP for length. + * sysdeps/x86_64/multiarch/memrchr-avx2.S: Likewise. + * sysdeps/x86_64/x32/Makefile (tests): Add tst-size_t-memrchr. + * sysdeps/x86_64/x32/tst-size_t-memrchr.c: New file. +--- + sysdeps/x86_64/memrchr.S | 4 +- + sysdeps/x86_64/multiarch/memrchr-avx2.S | 4 +- + sysdeps/x86_64/x32/Makefile | 3 +- + sysdeps/x86_64/x32/tst-size_t-memrchr.c | 57 +++++++++++++++++++++++++ + 4 files changed, 63 insertions(+), 5 deletions(-) + create mode 100644 sysdeps/x86_64/x32/tst-size_t-memrchr.c + +Conflicts: + ChangeLog + (removed) + +diff --git a/sysdeps/x86_64/memrchr.S b/sysdeps/x86_64/memrchr.S +index b8e3fa1d..dc82f8f7 100644 +--- a/sysdeps/x86_64/memrchr.S ++++ b/sysdeps/x86_64/memrchr.S +@@ -24,13 +24,13 @@ + ENTRY (__memrchr) + movd %esi, %xmm1 + +- sub $16, %rdx ++ sub $16, %RDX_LP + jbe L(length_less16) + + punpcklbw %xmm1, %xmm1 + punpcklbw %xmm1, %xmm1 + +- add %rdx, %rdi ++ add %RDX_LP, %RDI_LP + pshufd $0, %xmm1, %xmm1 + + movdqu (%rdi), %xmm0 +diff --git a/sysdeps/x86_64/multiarch/memrchr-avx2.S b/sysdeps/x86_64/multiarch/memrchr-avx2.S +index b41a58bc..ce488dd9 100644 +--- a/sysdeps/x86_64/multiarch/memrchr-avx2.S ++++ b/sysdeps/x86_64/multiarch/memrchr-avx2.S +@@ -32,10 +32,10 @@ ENTRY (__memrchr_avx2) + vmovd %esi, %xmm0 + vpbroadcastb %xmm0, %ymm0 + +- subq $VEC_SIZE, %rdx ++ sub $VEC_SIZE, %RDX_LP + jbe L(last_vec_or_less) + +- addq %rdx, %rdi ++ add %RDX_LP, %RDI_LP + + /* Check the last VEC_SIZE bytes. */ + vpcmpeqb (%rdi), %ymm0, %ymm1 +diff --git a/sysdeps/x86_64/x32/Makefile b/sysdeps/x86_64/x32/Makefile +index 2fe1e5ac..e99dbd7c 100644 +--- a/sysdeps/x86_64/x32/Makefile ++++ b/sysdeps/x86_64/x32/Makefile +@@ -6,7 +6,8 @@ CFLAGS-s_llround.c += -fno-builtin-lround + endif + + ifeq ($(subdir),string) +-tests += tst-size_t-memchr tst-size_t-memcmp tst-size_t-memcpy ++tests += tst-size_t-memchr tst-size_t-memcmp tst-size_t-memcpy \ ++ tst-size_t-memrchr + endif + + ifeq ($(subdir),wcsmbs) +diff --git a/sysdeps/x86_64/x32/tst-size_t-memrchr.c b/sysdeps/x86_64/x32/tst-size_t-memrchr.c +new file mode 100644 +index 00000000..c83699c0 +--- /dev/null ++++ b/sysdeps/x86_64/x32/tst-size_t-memrchr.c +@@ -0,0 +1,57 @@ ++/* Test memrchr with size_t in the lower 32 bits of 64-bit register. ++ 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, see ++ . */ ++ ++#define TEST_NAME "memrchr" ++#include "test-size_t.h" ++ ++IMPL (memchr, 1) ++ ++typedef void * (*proto_t) (const void *, int, size_t); ++ ++static void * ++__attribute__ ((noinline, noclone)) ++do_memrchr (parameter_t a, parameter_t b) ++{ ++ return CALL (&b, a.p, (uintptr_t) b.p, a.len); ++} ++ ++static int ++test_main (void) ++{ ++ test_init (); ++ ++ parameter_t src = { { page_size }, buf2 }; ++ parameter_t c = { { 0 }, (void *) (uintptr_t) 0x12 }; ++ ++ int ret = 0; ++ FOR_EACH_IMPL (impl, 0) ++ { ++ c.fn = impl->fn; ++ void * res = do_memrchr (src, c); ++ if (res) ++ { ++ error (0, 0, "Wrong result in function %s: %p != NULL", ++ impl->name, res); ++ ret = 1; ++ } ++ } ++ ++ return ret ? EXIT_FAILURE : EXIT_SUCCESS; ++} ++ ++#include +-- +GitLab + diff --git a/SOURCES/glibc-RHEL-15696-40.patch b/SOURCES/glibc-RHEL-15696-40.patch new file mode 100644 index 0000000..7b7c07b --- /dev/null +++ b/SOURCES/glibc-RHEL-15696-40.patch @@ -0,0 +1,92 @@ +From 83c5b368226c34a2f0a5287df40fc290b2b34359 Mon Sep 17 00:00:00 2001 +From: "H.J. Lu" +Date: Mon, 19 Apr 2021 10:45:07 -0700 +Subject: [PATCH] x86-64: Require BMI2 for strchr-avx2.S +Content-type: text/plain; charset=UTF-8 + +Since strchr-avx2.S updated by + +commit 1f745ecc2109890886b161d4791e1406fdfc29b8 +Author: noah +Date: Wed Feb 3 00:38:59 2021 -0500 + + x86-64: Refactor and improve performance of strchr-avx2.S + +uses sarx: + +c4 e2 72 f7 c0 sarx %ecx,%eax,%eax + +for strchr-avx2 family functions, require BMI2 in ifunc-impl-list.c and +ifunc-avx2.h. +--- + sysdeps/x86_64/multiarch/ifunc-avx2.h | 4 ++-- + sysdeps/x86_64/multiarch/ifunc-impl-list.c | 12 +++++++++--- + 2 files changed, 11 insertions(+), 5 deletions(-) + +diff --git a/sysdeps/x86_64/multiarch/ifunc-avx2.h b/sysdeps/x86_64/multiarch/ifunc-avx2.h +index e0f30e61..ef72b73f 100644 +--- a/sysdeps/x86_64/multiarch/ifunc-avx2.h ++++ b/sysdeps/x86_64/multiarch/ifunc-avx2.h +@@ -30,11 +30,11 @@ IFUNC_SELECTOR (void) + const struct cpu_features* cpu_features = __get_cpu_features (); + + if (CPU_FEATURE_USABLE_P (cpu_features, AVX2) ++ && CPU_FEATURE_USABLE_P (cpu_features, BMI2) + && CPU_FEATURES_ARCH_P (cpu_features, AVX_Fast_Unaligned_Load)) + { + if (CPU_FEATURE_USABLE_P (cpu_features, AVX512VL) +- && CPU_FEATURE_USABLE_P (cpu_features, AVX512BW) +- && CPU_FEATURE_USABLE_P (cpu_features, BMI2)) ++ && CPU_FEATURE_USABLE_P (cpu_features, AVX512BW)) + return OPTIMIZE (evex); + + if (CPU_FEATURE_USABLE_P (cpu_features, RTM)) +diff --git a/sysdeps/x86_64/multiarch/ifunc-impl-list.c b/sysdeps/x86_64/multiarch/ifunc-impl-list.c +index 695cdba6..85b8863a 100644 +--- a/sysdeps/x86_64/multiarch/ifunc-impl-list.c ++++ b/sysdeps/x86_64/multiarch/ifunc-impl-list.c +@@ -400,10 +400,12 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + /* Support sysdeps/x86_64/multiarch/strchr.c. */ + IFUNC_IMPL (i, name, strchr, + IFUNC_IMPL_ADD (array, i, strchr, +- CPU_FEATURE_USABLE (AVX2), ++ (CPU_FEATURE_USABLE (AVX2) ++ && CPU_FEATURE_USABLE (BMI2)), + __strchr_avx2) + IFUNC_IMPL_ADD (array, i, strchr, + (CPU_FEATURE_USABLE (AVX2) ++ && CPU_FEATURE_USABLE (BMI2) + && CPU_FEATURE_USABLE (RTM)), + __strchr_avx2_rtm) + IFUNC_IMPL_ADD (array, i, strchr, +@@ -417,10 +419,12 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + /* Support sysdeps/x86_64/multiarch/strchrnul.c. */ + IFUNC_IMPL (i, name, strchrnul, + IFUNC_IMPL_ADD (array, i, strchrnul, +- CPU_FEATURE_USABLE (AVX2), ++ (CPU_FEATURE_USABLE (AVX2) ++ && CPU_FEATURE_USABLE (BMI2)), + __strchrnul_avx2) + IFUNC_IMPL_ADD (array, i, strchrnul, + (CPU_FEATURE_USABLE (AVX2) ++ && CPU_FEATURE_USABLE (BMI2) + && CPU_FEATURE_USABLE (RTM)), + __strchrnul_avx2_rtm) + IFUNC_IMPL_ADD (array, i, strchrnul, +@@ -574,10 +578,12 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + /* Support sysdeps/x86_64/multiarch/wcschr.c. */ + IFUNC_IMPL (i, name, wcschr, + IFUNC_IMPL_ADD (array, i, wcschr, +- CPU_FEATURE_USABLE (AVX2), ++ (CPU_FEATURE_USABLE (AVX2) ++ && CPU_FEATURE_USABLE (BMI2)), + __wcschr_avx2) + IFUNC_IMPL_ADD (array, i, wcschr, + (CPU_FEATURE_USABLE (AVX2) ++ && CPU_FEATURE_USABLE (BMI2) + && CPU_FEATURE_USABLE (RTM)), + __wcschr_avx2_rtm) + IFUNC_IMPL_ADD (array, i, wcschr, +-- +GitLab + diff --git a/SOURCES/glibc-RHEL-15696-41.patch b/SOURCES/glibc-RHEL-15696-41.patch new file mode 100644 index 0000000..aa8fc69 --- /dev/null +++ b/SOURCES/glibc-RHEL-15696-41.patch @@ -0,0 +1,265 @@ +From f53790272ce7bdc5ecd14b45f65d0464d2a61a3a Mon Sep 17 00:00:00 2001 +From: Noah Goldstein +Date: Mon, 19 Apr 2021 17:48:10 -0400 +Subject: [PATCH] x86: Optimize less_vec evex and avx512 + memset-vec-unaligned-erms.S +Content-type: text/plain; charset=UTF-8 + +No bug. This commit adds optimized cased for less_vec memset case that +uses the avx512vl/avx512bw mask store avoiding the excessive +branches. test-memset and test-wmemset are passing. + +Signed-off-by: Noah Goldstein +--- + sysdeps/x86_64/multiarch/ifunc-impl-list.c | 40 ++++++++++----- + sysdeps/x86_64/multiarch/ifunc-memset.h | 6 ++- + .../multiarch/memset-avx512-unaligned-erms.S | 2 +- + .../multiarch/memset-evex-unaligned-erms.S | 2 +- + .../multiarch/memset-vec-unaligned-erms.S | 51 +++++++++++++++---- + 5 files changed, 74 insertions(+), 27 deletions(-) + +diff --git a/sysdeps/x86_64/multiarch/ifunc-impl-list.c b/sysdeps/x86_64/multiarch/ifunc-impl-list.c +index 85b8863a..d59d65f8 100644 +--- a/sysdeps/x86_64/multiarch/ifunc-impl-list.c ++++ b/sysdeps/x86_64/multiarch/ifunc-impl-list.c +@@ -204,19 +204,23 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + __memset_chk_avx2_unaligned_erms_rtm) + IFUNC_IMPL_ADD (array, i, __memset_chk, + (CPU_FEATURE_USABLE (AVX512VL) +- && CPU_FEATURE_USABLE (AVX512BW)), ++ && CPU_FEATURE_USABLE (AVX512BW) ++ && CPU_FEATURE_USABLE (BMI2)), + __memset_chk_evex_unaligned) + IFUNC_IMPL_ADD (array, i, __memset_chk, + (CPU_FEATURE_USABLE (AVX512VL) +- && CPU_FEATURE_USABLE (AVX512BW)), ++ && CPU_FEATURE_USABLE (AVX512BW) ++ && CPU_FEATURE_USABLE (BMI2)), + __memset_chk_evex_unaligned_erms) + IFUNC_IMPL_ADD (array, i, __memset_chk, + (CPU_FEATURE_USABLE (AVX512VL) +- && CPU_FEATURE_USABLE (AVX512BW)), ++ && CPU_FEATURE_USABLE (AVX512BW) ++ && CPU_FEATURE_USABLE (BMI2)), + __memset_chk_avx512_unaligned_erms) + IFUNC_IMPL_ADD (array, i, __memset_chk, + (CPU_FEATURE_USABLE (AVX512VL) +- && CPU_FEATURE_USABLE (AVX512BW)), ++ && CPU_FEATURE_USABLE (AVX512BW) ++ && CPU_FEATURE_USABLE (BMI2)), + __memset_chk_avx512_unaligned) + IFUNC_IMPL_ADD (array, i, __memset_chk, + CPU_FEATURE_USABLE (AVX512F), +@@ -247,19 +251,23 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + __memset_avx2_unaligned_erms_rtm) + IFUNC_IMPL_ADD (array, i, memset, + (CPU_FEATURE_USABLE (AVX512VL) +- && CPU_FEATURE_USABLE (AVX512BW)), ++ && CPU_FEATURE_USABLE (AVX512BW) ++ && CPU_FEATURE_USABLE (BMI2)), + __memset_evex_unaligned) + IFUNC_IMPL_ADD (array, i, memset, + (CPU_FEATURE_USABLE (AVX512VL) +- && CPU_FEATURE_USABLE (AVX512BW)), ++ && CPU_FEATURE_USABLE (AVX512BW) ++ && CPU_FEATURE_USABLE (BMI2)), + __memset_evex_unaligned_erms) + IFUNC_IMPL_ADD (array, i, memset, + (CPU_FEATURE_USABLE (AVX512VL) +- && CPU_FEATURE_USABLE (AVX512BW)), ++ && CPU_FEATURE_USABLE (AVX512BW) ++ && CPU_FEATURE_USABLE (BMI2)), + __memset_avx512_unaligned_erms) + IFUNC_IMPL_ADD (array, i, memset, + (CPU_FEATURE_USABLE (AVX512VL) +- && CPU_FEATURE_USABLE (AVX512BW)), ++ && CPU_FEATURE_USABLE (AVX512BW) ++ && CPU_FEATURE_USABLE (BMI2)), + __memset_avx512_unaligned) + IFUNC_IMPL_ADD (array, i, memset, + CPU_FEATURE_USABLE (AVX512F), +@@ -739,10 +747,14 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + && CPU_FEATURE_USABLE (RTM)), + __wmemset_avx2_unaligned_rtm) + IFUNC_IMPL_ADD (array, i, wmemset, +- CPU_FEATURE_USABLE (AVX512VL), ++ (CPU_FEATURE_USABLE (AVX512VL) ++ && CPU_FEATURE_USABLE (AVX512BW) ++ && CPU_FEATURE_USABLE (BMI2)), + __wmemset_evex_unaligned) + IFUNC_IMPL_ADD (array, i, wmemset, +- CPU_FEATURE_USABLE (AVX512VL), ++ (CPU_FEATURE_USABLE (AVX512VL) ++ && CPU_FEATURE_USABLE (AVX512BW) ++ && CPU_FEATURE_USABLE (BMI2)), + __wmemset_avx512_unaligned)) + + #ifdef SHARED +@@ -946,10 +958,14 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + CPU_FEATURE_USABLE (AVX2), + __wmemset_chk_avx2_unaligned) + IFUNC_IMPL_ADD (array, i, __wmemset_chk, +- CPU_FEATURE_USABLE (AVX512VL), ++ (CPU_FEATURE_USABLE (AVX512VL) ++ && CPU_FEATURE_USABLE (AVX512BW) ++ && CPU_FEATURE_USABLE (BMI2)), + __wmemset_chk_evex_unaligned) + IFUNC_IMPL_ADD (array, i, __wmemset_chk, +- CPU_FEATURE_USABLE (AVX512F), ++ (CPU_FEATURE_USABLE (AVX512VL) ++ && CPU_FEATURE_USABLE (AVX512BW) ++ && CPU_FEATURE_USABLE (BMI2)), + __wmemset_chk_avx512_unaligned)) + #endif + +diff --git a/sysdeps/x86_64/multiarch/ifunc-memset.h b/sysdeps/x86_64/multiarch/ifunc-memset.h +index 19795938..100e3707 100644 +--- a/sysdeps/x86_64/multiarch/ifunc-memset.h ++++ b/sysdeps/x86_64/multiarch/ifunc-memset.h +@@ -54,7 +54,8 @@ IFUNC_SELECTOR (void) + && !CPU_FEATURES_ARCH_P (cpu_features, Prefer_No_AVX512)) + { + if (CPU_FEATURE_USABLE_P (cpu_features, AVX512VL) +- && CPU_FEATURE_USABLE_P (cpu_features, AVX512BW)) ++ && CPU_FEATURE_USABLE_P (cpu_features, AVX512BW) ++ && CPU_FEATURE_USABLE_P (cpu_features, BMI2)) + { + if (CPU_FEATURE_USABLE_P (cpu_features, ERMS)) + return OPTIMIZE (avx512_unaligned_erms); +@@ -68,7 +69,8 @@ IFUNC_SELECTOR (void) + if (CPU_FEATURE_USABLE_P (cpu_features, AVX2)) + { + if (CPU_FEATURE_USABLE_P (cpu_features, AVX512VL) +- && CPU_FEATURE_USABLE_P (cpu_features, AVX512BW)) ++ && CPU_FEATURE_USABLE_P (cpu_features, AVX512BW) ++ && CPU_FEATURE_USABLE_P (cpu_features, BMI2)) + { + if (CPU_FEATURE_USABLE_P (cpu_features, ERMS)) + return OPTIMIZE (evex_unaligned_erms); +diff --git a/sysdeps/x86_64/multiarch/memset-avx512-unaligned-erms.S b/sysdeps/x86_64/multiarch/memset-avx512-unaligned-erms.S +index 22e7b187..8ad842fc 100644 +--- a/sysdeps/x86_64/multiarch/memset-avx512-unaligned-erms.S ++++ b/sysdeps/x86_64/multiarch/memset-avx512-unaligned-erms.S +@@ -19,6 +19,6 @@ + # define SECTION(p) p##.evex512 + # define MEMSET_SYMBOL(p,s) p##_avx512_##s + # define WMEMSET_SYMBOL(p,s) p##_avx512_##s +- ++# define USE_LESS_VEC_MASK_STORE 1 + # include "memset-vec-unaligned-erms.S" + #endif +diff --git a/sysdeps/x86_64/multiarch/memset-evex-unaligned-erms.S b/sysdeps/x86_64/multiarch/memset-evex-unaligned-erms.S +index ae0a4d6e..640f0929 100644 +--- a/sysdeps/x86_64/multiarch/memset-evex-unaligned-erms.S ++++ b/sysdeps/x86_64/multiarch/memset-evex-unaligned-erms.S +@@ -19,6 +19,6 @@ + # define SECTION(p) p##.evex + # define MEMSET_SYMBOL(p,s) p##_evex_##s + # define WMEMSET_SYMBOL(p,s) p##_evex_##s +- ++# define USE_LESS_VEC_MASK_STORE 1 + # include "memset-vec-unaligned-erms.S" + #endif +diff --git a/sysdeps/x86_64/multiarch/memset-vec-unaligned-erms.S b/sysdeps/x86_64/multiarch/memset-vec-unaligned-erms.S +index bae5cba4..f877ac9d 100644 +--- a/sysdeps/x86_64/multiarch/memset-vec-unaligned-erms.S ++++ b/sysdeps/x86_64/multiarch/memset-vec-unaligned-erms.S +@@ -63,6 +63,8 @@ + # endif + #endif + ++#define PAGE_SIZE 4096 ++ + #ifndef SECTION + # error SECTION is not defined! + #endif +@@ -213,11 +215,38 @@ L(loop): + cmpq %rcx, %rdx + jne L(loop) + VZEROUPPER_SHORT_RETURN ++ ++ .p2align 4 + L(less_vec): + /* Less than 1 VEC. */ + # if VEC_SIZE != 16 && VEC_SIZE != 32 && VEC_SIZE != 64 + # error Unsupported VEC_SIZE! + # endif ++# ifdef USE_LESS_VEC_MASK_STORE ++ /* Clear high bits from edi. Only keeping bits relevant to page ++ cross check. Note that we are using rax which is set in ++ MEMSET_VDUP_TO_VEC0_AND_SET_RETURN as ptr from here on out. ++ */ ++ andl $(PAGE_SIZE - 1), %edi ++ /* Check if VEC_SIZE store cross page. Mask stores suffer serious ++ performance degradation when it has to fault supress. */ ++ cmpl $(PAGE_SIZE - VEC_SIZE), %edi ++ ja L(cross_page) ++# if VEC_SIZE > 32 ++ movq $-1, %rcx ++ bzhiq %rdx, %rcx, %rcx ++ kmovq %rcx, %k1 ++# else ++ movl $-1, %ecx ++ bzhil %edx, %ecx, %ecx ++ kmovd %ecx, %k1 ++# endif ++ vmovdqu8 %VEC(0), (%rax) {%k1} ++ VZEROUPPER_RETURN ++ ++ .p2align 4 ++L(cross_page): ++# endif + # if VEC_SIZE > 32 + cmpb $32, %dl + jae L(between_32_63) +@@ -234,36 +263,36 @@ L(less_vec): + cmpb $1, %dl + ja L(between_2_3) + jb 1f +- movb %cl, (%rdi) ++ movb %cl, (%rax) + 1: + VZEROUPPER_RETURN + # if VEC_SIZE > 32 + /* From 32 to 63. No branch when size == 32. */ + L(between_32_63): +- VMOVU %YMM0, -32(%rdi,%rdx) +- VMOVU %YMM0, (%rdi) ++ VMOVU %YMM0, -32(%rax,%rdx) ++ VMOVU %YMM0, (%rax) + VZEROUPPER_RETURN + # endif + # if VEC_SIZE > 16 + /* From 16 to 31. No branch when size == 16. */ + L(between_16_31): +- VMOVU %XMM0, -16(%rdi,%rdx) +- VMOVU %XMM0, (%rdi) ++ VMOVU %XMM0, -16(%rax,%rdx) ++ VMOVU %XMM0, (%rax) + VZEROUPPER_RETURN + # endif + /* From 8 to 15. No branch when size == 8. */ + L(between_8_15): +- movq %rcx, -8(%rdi,%rdx) +- movq %rcx, (%rdi) ++ movq %rcx, -8(%rax,%rdx) ++ movq %rcx, (%rax) + VZEROUPPER_RETURN + L(between_4_7): + /* From 4 to 7. No branch when size == 4. */ +- movl %ecx, -4(%rdi,%rdx) +- movl %ecx, (%rdi) ++ movl %ecx, -4(%rax,%rdx) ++ movl %ecx, (%rax) + VZEROUPPER_RETURN + L(between_2_3): + /* From 2 to 3. No branch when size == 2. */ +- movw %cx, -2(%rdi,%rdx) +- movw %cx, (%rdi) ++ movw %cx, -2(%rax,%rdx) ++ movw %cx, (%rax) + VZEROUPPER_RETURN + END (MEMSET_SYMBOL (__memset, unaligned_erms)) +-- +GitLab + diff --git a/SOURCES/glibc-RHEL-15696-42.patch b/SOURCES/glibc-RHEL-15696-42.patch new file mode 100644 index 0000000..e2ca245 --- /dev/null +++ b/SOURCES/glibc-RHEL-15696-42.patch @@ -0,0 +1,396 @@ +From ccabe7971f508709d034b63b8672f6f751a3d356 Mon Sep 17 00:00:00 2001 +From: Noah Goldstein +Date: Fri, 23 Apr 2021 15:56:24 -0400 +Subject: [PATCH] x86: Optimize strchr-avx2.S +Content-type: text/plain; charset=UTF-8 + +No bug. This commit optimizes strchr-avx2.S. The optimizations are all +small things such as save an ALU in the alignment process, saving a +few instructions in the loop return, saving some bytes in the main +loop, and increasing the ILP in the return cases. test-strchr, +test-strchrnul, test-wcschr, and test-wcschrnul are all passing. + +Signed-off-by: Noah Goldstein +--- + sysdeps/x86_64/multiarch/strchr-avx2.S | 290 +++++++++++++++---------- + 1 file changed, 170 insertions(+), 120 deletions(-) + +Conflics: + sysdeps/x86_64/multiarch/strchr-avx2.S + (rearranged to account for branch changes) + +diff --git a/sysdeps/x86_64/multiarch/strchr-avx2.S b/sysdeps/x86_64/multiarch/strchr-avx2.S +index 919d256c..5884726b 100644 +--- a/sysdeps/x86_64/multiarch/strchr-avx2.S ++++ b/sysdeps/x86_64/multiarch/strchr-avx2.S +@@ -49,133 +49,144 @@ + + .section SECTION(.text),"ax",@progbits + ENTRY (STRCHR) +- movl %edi, %ecx +-# ifndef USE_AS_STRCHRNUL +- xorl %edx, %edx +-# endif +- + /* Broadcast CHAR to YMM0. */ + vmovd %esi, %xmm0 ++ movl %edi, %eax ++ andl $(PAGE_SIZE - 1), %eax ++ VPBROADCAST %xmm0, %ymm0 + vpxor %xmm9, %xmm9, %xmm9 +- VPBROADCAST %xmm0, %ymm0 + + /* Check if we cross page boundary with one vector load. */ +- andl $(PAGE_SIZE - 1), %ecx +- cmpl $(PAGE_SIZE - VEC_SIZE), %ecx +- ja L(cross_page_boundary) ++ cmpl $(PAGE_SIZE - VEC_SIZE), %eax ++ ja L(cross_page_boundary) + + /* Check the first VEC_SIZE bytes. Search for both CHAR and the + null byte. */ + vmovdqu (%rdi), %ymm8 +- VPCMPEQ %ymm8, %ymm0, %ymm1 +- VPCMPEQ %ymm8, %ymm9, %ymm2 ++ VPCMPEQ %ymm8, %ymm0, %ymm1 ++ VPCMPEQ %ymm8, %ymm9, %ymm2 + vpor %ymm1, %ymm2, %ymm1 + vpmovmskb %ymm1, %eax + testl %eax, %eax +- jz L(more_vecs) ++ jz L(aligned_more) + tzcntl %eax, %eax ++# ifndef USE_AS_STRCHRNUL + /* Found CHAR or the null byte. */ ++ cmp (%rdi, %rax), %CHAR_REG ++ jne L(zero) ++# endif + addq %rdi, %rax ++ VZEROUPPER_RETURN ++ ++ /* .p2align 5 helps keep performance more consistent if ENTRY() ++ alignment % 32 was either 16 or 0. As well this makes the ++ alignment % 32 of the loop_4x_vec fixed which makes tuning it ++ easier. */ ++ .p2align 5 ++L(first_vec_x4): ++ tzcntl %eax, %eax ++ addq $(VEC_SIZE * 3 + 1), %rdi + # ifndef USE_AS_STRCHRNUL +- cmp (%rax), %CHAR_REG +- cmovne %rdx, %rax ++ /* Found CHAR or the null byte. */ ++ cmp (%rdi, %rax), %CHAR_REG ++ jne L(zero) + # endif +-L(return_vzeroupper): +- ZERO_UPPER_VEC_REGISTERS_RETURN +- +- .p2align 4 +-L(more_vecs): +- /* Align data for aligned loads in the loop. */ +- andq $-VEC_SIZE, %rdi +-L(aligned_more): +- +- /* Check the next 4 * VEC_SIZE. Only one VEC_SIZE at a time +- since data is only aligned to VEC_SIZE. */ +- vmovdqa VEC_SIZE(%rdi), %ymm8 +- addq $VEC_SIZE, %rdi +- VPCMPEQ %ymm8, %ymm0, %ymm1 +- VPCMPEQ %ymm8, %ymm9, %ymm2 +- vpor %ymm1, %ymm2, %ymm1 +- vpmovmskb %ymm1, %eax +- testl %eax, %eax +- jnz L(first_vec_x0) +- +- vmovdqa VEC_SIZE(%rdi), %ymm8 +- VPCMPEQ %ymm8, %ymm0, %ymm1 +- VPCMPEQ %ymm8, %ymm9, %ymm2 +- vpor %ymm1, %ymm2, %ymm1 +- vpmovmskb %ymm1, %eax +- testl %eax, %eax +- jnz L(first_vec_x1) +- +- vmovdqa (VEC_SIZE * 2)(%rdi), %ymm8 +- VPCMPEQ %ymm8, %ymm0, %ymm1 +- VPCMPEQ %ymm8, %ymm9, %ymm2 +- vpor %ymm1, %ymm2, %ymm1 +- vpmovmskb %ymm1, %eax +- testl %eax, %eax +- jnz L(first_vec_x2) +- +- vmovdqa (VEC_SIZE * 3)(%rdi), %ymm8 +- VPCMPEQ %ymm8, %ymm0, %ymm1 +- VPCMPEQ %ymm8, %ymm9, %ymm2 +- vpor %ymm1, %ymm2, %ymm1 +- vpmovmskb %ymm1, %eax +- testl %eax, %eax +- jz L(prep_loop_4x) ++ addq %rdi, %rax ++ VZEROUPPER_RETURN + +- tzcntl %eax, %eax +- leaq (VEC_SIZE * 3)(%rdi, %rax), %rax + # ifndef USE_AS_STRCHRNUL +- cmp (%rax), %CHAR_REG +- cmovne %rdx, %rax ++L(zero): ++ xorl %eax, %eax ++ VZEROUPPER_RETURN + # endif +- VZEROUPPER +- ret ++ + + .p2align 4 +-L(first_vec_x0): ++L(first_vec_x1): + tzcntl %eax, %eax +- /* Found CHAR or the null byte. */ +- addq %rdi, %rax ++ incq %rdi + # ifndef USE_AS_STRCHRNUL +- cmp (%rax), %CHAR_REG +- cmovne %rdx, %rax ++ /* Found CHAR or the null byte. */ ++ cmp (%rdi, %rax), %CHAR_REG ++ jne L(zero) + # endif ++ addq %rdi, %rax + VZEROUPPER_RETURN + + .p2align 4 +-L(first_vec_x1): ++L(first_vec_x2): + tzcntl %eax, %eax +- leaq VEC_SIZE(%rdi, %rax), %rax ++ addq $(VEC_SIZE + 1), %rdi + # ifndef USE_AS_STRCHRNUL +- cmp (%rax), %CHAR_REG +- cmovne %rdx, %rax ++ /* Found CHAR or the null byte. */ ++ cmp (%rdi, %rax), %CHAR_REG ++ jne L(zero) + # endif ++ addq %rdi, %rax + VZEROUPPER_RETURN + + .p2align 4 +-L(first_vec_x2): ++L(first_vec_x3): + tzcntl %eax, %eax +- /* Found CHAR or the null byte. */ +- leaq (VEC_SIZE * 2)(%rdi, %rax), %rax ++ addq $(VEC_SIZE * 2 + 1), %rdi + # ifndef USE_AS_STRCHRNUL +- cmp (%rax), %CHAR_REG +- cmovne %rdx, %rax ++ /* Found CHAR or the null byte. */ ++ cmp (%rdi, %rax), %CHAR_REG ++ jne L(zero) + # endif ++ addq %rdi, %rax + VZEROUPPER_RETURN + +-L(prep_loop_4x): +- /* Align data to 4 * VEC_SIZE. */ +- andq $-(VEC_SIZE * 4), %rdi ++ .p2align 4 ++L(aligned_more): ++ /* Align data to VEC_SIZE - 1. This is the same number of ++ instructions as using andq -VEC_SIZE but saves 4 bytes of code ++ on x4 check. */ ++ orq $(VEC_SIZE - 1), %rdi ++L(cross_page_continue): ++ /* Check the next 4 * VEC_SIZE. Only one VEC_SIZE at a time ++ since data is only aligned to VEC_SIZE. */ ++ vmovdqa 1(%rdi), %ymm8 ++ VPCMPEQ %ymm8, %ymm0, %ymm1 ++ VPCMPEQ %ymm8, %ymm9, %ymm2 ++ vpor %ymm1, %ymm2, %ymm1 ++ vpmovmskb %ymm1, %eax ++ testl %eax, %eax ++ jnz L(first_vec_x1) ++ ++ vmovdqa (VEC_SIZE + 1)(%rdi), %ymm8 ++ VPCMPEQ %ymm8, %ymm0, %ymm1 ++ VPCMPEQ %ymm8, %ymm9, %ymm2 ++ vpor %ymm1, %ymm2, %ymm1 ++ vpmovmskb %ymm1, %eax ++ testl %eax, %eax ++ jnz L(first_vec_x2) ++ ++ vmovdqa (VEC_SIZE * 2 + 1)(%rdi), %ymm8 ++ VPCMPEQ %ymm8, %ymm0, %ymm1 ++ VPCMPEQ %ymm8, %ymm9, %ymm2 ++ vpor %ymm1, %ymm2, %ymm1 ++ vpmovmskb %ymm1, %eax ++ testl %eax, %eax ++ jnz L(first_vec_x3) + ++ vmovdqa (VEC_SIZE * 3 + 1)(%rdi), %ymm8 ++ VPCMPEQ %ymm8, %ymm0, %ymm1 ++ VPCMPEQ %ymm8, %ymm9, %ymm2 ++ vpor %ymm1, %ymm2, %ymm1 ++ vpmovmskb %ymm1, %eax ++ testl %eax, %eax ++ jnz L(first_vec_x4) ++ /* Align data to VEC_SIZE * 4 - 1. */ ++ addq $(VEC_SIZE * 4 + 1), %rdi ++ andq $-(VEC_SIZE * 4), %rdi + .p2align 4 + L(loop_4x_vec): + /* Compare 4 * VEC at a time forward. */ +- vmovdqa (VEC_SIZE * 4)(%rdi), %ymm5 +- vmovdqa (VEC_SIZE * 5)(%rdi), %ymm6 +- vmovdqa (VEC_SIZE * 6)(%rdi), %ymm7 +- vmovdqa (VEC_SIZE * 7)(%rdi), %ymm8 ++ vmovdqa (%rdi), %ymm5 ++ vmovdqa (VEC_SIZE)(%rdi), %ymm6 ++ vmovdqa (VEC_SIZE * 2)(%rdi), %ymm7 ++ vmovdqa (VEC_SIZE * 3)(%rdi), %ymm8 + + /* Leaves only CHARS matching esi as 0. */ + vpxor %ymm5, %ymm0, %ymm1 +@@ -191,63 +202,102 @@ L(loop_4x_vec): + VPMINU %ymm1, %ymm2, %ymm5 + VPMINU %ymm3, %ymm4, %ymm6 + +- VPMINU %ymm5, %ymm6, %ymm5 ++ VPMINU %ymm5, %ymm6, %ymm6 + +- VPCMPEQ %ymm5, %ymm9, %ymm5 +- vpmovmskb %ymm5, %eax ++ VPCMPEQ %ymm6, %ymm9, %ymm6 ++ vpmovmskb %ymm6, %ecx ++ subq $-(VEC_SIZE * 4), %rdi ++ testl %ecx, %ecx ++ jz L(loop_4x_vec) + +- addq $(VEC_SIZE * 4), %rdi +- testl %eax, %eax +- jz L(loop_4x_vec) + +- VPCMPEQ %ymm1, %ymm9, %ymm1 ++ VPCMPEQ %ymm1, %ymm9, %ymm1 + vpmovmskb %ymm1, %eax + testl %eax, %eax +- jnz L(first_vec_x0) ++ jnz L(last_vec_x0) ++ + +- VPCMPEQ %ymm2, %ymm9, %ymm2 ++ VPCMPEQ %ymm5, %ymm9, %ymm2 + vpmovmskb %ymm2, %eax + testl %eax, %eax +- jnz L(first_vec_x1) ++ jnz L(last_vec_x1) ++ ++ VPCMPEQ %ymm3, %ymm9, %ymm3 ++ vpmovmskb %ymm3, %eax ++ /* rcx has combined result from all 4 VEC. It will only be used ++ if the first 3 other VEC all did not contain a match. */ ++ salq $32, %rcx ++ orq %rcx, %rax ++ tzcntq %rax, %rax ++ subq $(VEC_SIZE * 2), %rdi ++# ifndef USE_AS_STRCHRNUL ++ /* Found CHAR or the null byte. */ ++ cmp (%rdi, %rax), %CHAR_REG ++ jne L(zero_end) ++# endif ++ addq %rdi, %rax ++ VZEROUPPER_RETURN ++ ++ ++ .p2align 4 ++L(last_vec_x0): ++ tzcntl %eax, %eax ++ addq $-(VEC_SIZE * 4), %rdi ++# ifndef USE_AS_STRCHRNUL ++ /* Found CHAR or the null byte. */ ++ cmp (%rdi, %rax), %CHAR_REG ++ jne L(zero_end) ++# endif ++ addq %rdi, %rax ++ VZEROUPPER_RETURN + +- VPCMPEQ %ymm3, %ymm9, %ymm3 +- VPCMPEQ %ymm4, %ymm9, %ymm4 +- vpmovmskb %ymm3, %ecx +- vpmovmskb %ymm4, %eax +- salq $32, %rax +- orq %rcx, %rax +- tzcntq %rax, %rax +- leaq (VEC_SIZE * 2)(%rdi, %rax), %rax + # ifndef USE_AS_STRCHRNUL +- cmp (%rax), %CHAR_REG +- cmovne %rdx, %rax ++L(zero_end): ++ xorl %eax, %eax ++ VZEROUPPER_RETURN + # endif +- VZEROUPPER +- ret ++ ++ .p2align 4 ++L(last_vec_x1): ++ tzcntl %eax, %eax ++ subq $(VEC_SIZE * 3), %rdi ++# ifndef USE_AS_STRCHRNUL ++ /* Found CHAR or the null byte. */ ++ cmp (%rdi, %rax), %CHAR_REG ++ jne L(zero_end) ++# endif ++ addq %rdi, %rax ++ VZEROUPPER_RETURN ++ + + /* Cold case for crossing page with first load. */ + .p2align 4 + L(cross_page_boundary): +- andq $-VEC_SIZE, %rdi +- andl $(VEC_SIZE - 1), %ecx +- +- vmovdqa (%rdi), %ymm8 +- VPCMPEQ %ymm8, %ymm0, %ymm1 +- VPCMPEQ %ymm8, %ymm9, %ymm2 ++ movq %rdi, %rdx ++ /* Align rdi to VEC_SIZE - 1. */ ++ orq $(VEC_SIZE - 1), %rdi ++ vmovdqa -(VEC_SIZE - 1)(%rdi), %ymm8 ++ VPCMPEQ %ymm8, %ymm0, %ymm1 ++ VPCMPEQ %ymm8, %ymm9, %ymm2 + vpor %ymm1, %ymm2, %ymm1 + vpmovmskb %ymm1, %eax +- /* Remove the leading bits. */ +- sarxl %ecx, %eax, %eax ++ /* Remove the leading bytes. sarxl only uses bits [5:0] of COUNT ++ so no need to manually mod edx. */ ++ sarxl %edx, %eax, %eax + testl %eax, %eax +- jz L(aligned_more) ++ jz L(cross_page_continue) + tzcntl %eax, %eax +- addq %rcx, %rdi +- addq %rdi, %rax + # ifndef USE_AS_STRCHRNUL +- cmp (%rax), %CHAR_REG +- cmovne %rdx, %rax ++ xorl %ecx, %ecx ++ /* Found CHAR or the null byte. */ ++ cmp (%rdx, %rax), %CHAR_REG ++ leaq (%rdx, %rax), %rax ++ cmovne %rcx, %rax ++# else ++ addq %rdx, %rax + # endif +- VZEROUPPER_RETURN ++L(return_vzeroupper): ++ ZERO_UPPER_VEC_REGISTERS_RETURN + + END (STRCHR) + # endif +-- +GitLab + diff --git a/SOURCES/glibc-RHEL-15696-43.patch b/SOURCES/glibc-RHEL-15696-43.patch new file mode 100644 index 0000000..9f76b11 --- /dev/null +++ b/SOURCES/glibc-RHEL-15696-43.patch @@ -0,0 +1,532 @@ +From 7f3e7c262cab4e2401e4331a6ef29c428de02044 Mon Sep 17 00:00:00 2001 +From: Noah Goldstein +Date: Fri, 23 Apr 2021 15:56:25 -0400 +Subject: [PATCH] x86: Optimize strchr-evex.S +Content-type: text/plain; charset=UTF-8 + +No bug. This commit optimizes strchr-evex.S. The optimizations are +mostly small things such as save an ALU in the alignment process, +saving a few instructions in the loop return. The one significant +change is saving 2 instructions in the 4x loop. test-strchr, +test-strchrnul, test-wcschr, and test-wcschrnul are all passing. + +Signed-off-by: Noah Goldstein +--- + sysdeps/x86_64/multiarch/strchr-evex.S | 392 ++++++++++++++----------- + 1 file changed, 218 insertions(+), 174 deletions(-) + +diff --git a/sysdeps/x86_64/multiarch/strchr-evex.S b/sysdeps/x86_64/multiarch/strchr-evex.S +index ddc86a70..7f9d4ee4 100644 +--- a/sysdeps/x86_64/multiarch/strchr-evex.S ++++ b/sysdeps/x86_64/multiarch/strchr-evex.S +@@ -32,13 +32,15 @@ + # define VPCMP vpcmpd + # define VPMINU vpminud + # define CHAR_REG esi +-# define SHIFT_REG r8d ++# define SHIFT_REG ecx ++# define CHAR_SIZE 4 + # else + # define VPBROADCAST vpbroadcastb + # define VPCMP vpcmpb + # define VPMINU vpminub + # define CHAR_REG sil +-# define SHIFT_REG ecx ++# define SHIFT_REG edx ++# define CHAR_SIZE 1 + # endif + + # define XMMZERO xmm16 +@@ -56,23 +58,20 @@ + + # define VEC_SIZE 32 + # define PAGE_SIZE 4096 ++# define CHAR_PER_VEC (VEC_SIZE / CHAR_SIZE) + + .section .text.evex,"ax",@progbits + ENTRY (STRCHR) +- movl %edi, %ecx +-# ifndef USE_AS_STRCHRNUL +- xorl %edx, %edx +-# endif +- + /* Broadcast CHAR to YMM0. */ +- VPBROADCAST %esi, %YMM0 +- ++ VPBROADCAST %esi, %YMM0 ++ movl %edi, %eax ++ andl $(PAGE_SIZE - 1), %eax + vpxorq %XMMZERO, %XMMZERO, %XMMZERO + +- /* Check if we cross page boundary with one vector load. */ +- andl $(PAGE_SIZE - 1), %ecx +- cmpl $(PAGE_SIZE - VEC_SIZE), %ecx +- ja L(cross_page_boundary) ++ /* Check if we cross page boundary with one vector load. ++ Otherwise it is safe to use an unaligned load. */ ++ cmpl $(PAGE_SIZE - VEC_SIZE), %eax ++ ja L(cross_page_boundary) + + /* Check the first VEC_SIZE bytes. Search for both CHAR and the + null bytes. */ +@@ -83,251 +82,296 @@ ENTRY (STRCHR) + VPMINU %YMM2, %YMM1, %YMM2 + /* Each bit in K0 represents a CHAR or a null byte in YMM1. */ + VPCMP $0, %YMMZERO, %YMM2, %k0 +- ktestd %k0, %k0 +- jz L(more_vecs) + kmovd %k0, %eax ++ testl %eax, %eax ++ jz L(aligned_more) + tzcntl %eax, %eax +- /* Found CHAR or the null byte. */ + # ifdef USE_AS_WCSCHR +- /* NB: Multiply wchar_t count by 4 to get the number of bytes. */ +- leaq (%rdi, %rax, 4), %rax ++ /* NB: Multiply wchar_t count by 4 to get the number of bytes. ++ */ ++ leaq (%rdi, %rax, CHAR_SIZE), %rax + # else + addq %rdi, %rax + # endif + # ifndef USE_AS_STRCHRNUL +- cmp (%rax), %CHAR_REG +- cmovne %rdx, %rax ++ /* Found CHAR or the null byte. */ ++ cmp (%rax), %CHAR_REG ++ jne L(zero) + # endif + ret + +- .p2align 4 +-L(more_vecs): +- /* Align data for aligned loads in the loop. */ +- andq $-VEC_SIZE, %rdi +-L(aligned_more): +- +- /* Check the next 4 * VEC_SIZE. Only one VEC_SIZE at a time +- since data is only aligned to VEC_SIZE. */ +- VMOVA VEC_SIZE(%rdi), %YMM1 +- addq $VEC_SIZE, %rdi +- +- /* Leaves only CHARS matching esi as 0. */ +- vpxorq %YMM1, %YMM0, %YMM2 +- VPMINU %YMM2, %YMM1, %YMM2 +- /* Each bit in K0 represents a CHAR or a null byte in YMM1. */ +- VPCMP $0, %YMMZERO, %YMM2, %k0 +- kmovd %k0, %eax +- testl %eax, %eax +- jnz L(first_vec_x0) +- +- VMOVA VEC_SIZE(%rdi), %YMM1 +- /* Leaves only CHARS matching esi as 0. */ +- vpxorq %YMM1, %YMM0, %YMM2 +- VPMINU %YMM2, %YMM1, %YMM2 +- /* Each bit in K0 represents a CHAR or a null byte in YMM1. */ +- VPCMP $0, %YMMZERO, %YMM2, %k0 +- kmovd %k0, %eax +- testl %eax, %eax +- jnz L(first_vec_x1) +- +- VMOVA (VEC_SIZE * 2)(%rdi), %YMM1 +- /* Leaves only CHARS matching esi as 0. */ +- vpxorq %YMM1, %YMM0, %YMM2 +- VPMINU %YMM2, %YMM1, %YMM2 +- /* Each bit in K0 represents a CHAR or a null byte in YMM1. */ +- VPCMP $0, %YMMZERO, %YMM2, %k0 +- kmovd %k0, %eax +- testl %eax, %eax +- jnz L(first_vec_x2) +- +- VMOVA (VEC_SIZE * 3)(%rdi), %YMM1 +- /* Leaves only CHARS matching esi as 0. */ +- vpxorq %YMM1, %YMM0, %YMM2 +- VPMINU %YMM2, %YMM1, %YMM2 +- /* Each bit in K0 represents a CHAR or a null byte in YMM1. */ +- VPCMP $0, %YMMZERO, %YMM2, %k0 +- ktestd %k0, %k0 +- jz L(prep_loop_4x) +- +- kmovd %k0, %eax ++ /* .p2align 5 helps keep performance more consistent if ENTRY() ++ alignment % 32 was either 16 or 0. As well this makes the ++ alignment % 32 of the loop_4x_vec fixed which makes tuning it ++ easier. */ ++ .p2align 5 ++L(first_vec_x3): + tzcntl %eax, %eax ++# ifndef USE_AS_STRCHRNUL + /* Found CHAR or the null byte. */ +-# ifdef USE_AS_WCSCHR +- /* NB: Multiply wchar_t count by 4 to get the number of bytes. */ +- leaq (VEC_SIZE * 3)(%rdi, %rax, 4), %rax +-# else +- leaq (VEC_SIZE * 3)(%rdi, %rax), %rax ++ cmp (VEC_SIZE * 3)(%rdi, %rax, CHAR_SIZE), %CHAR_REG ++ jne L(zero) + # endif ++ /* NB: Multiply sizeof char type (1 or 4) to get the number of ++ bytes. */ ++ leaq (VEC_SIZE * 3)(%rdi, %rax, CHAR_SIZE), %rax ++ ret ++ + # ifndef USE_AS_STRCHRNUL +- cmp (%rax), %CHAR_REG +- cmovne %rdx, %rax +-# endif ++L(zero): ++ xorl %eax, %eax + ret ++# endif + + .p2align 4 +-L(first_vec_x0): ++L(first_vec_x4): ++# ifndef USE_AS_STRCHRNUL ++ /* Check to see if first match was CHAR (k0) or null (k1). */ ++ kmovd %k0, %eax + tzcntl %eax, %eax +- /* Found CHAR or the null byte. */ +-# ifdef USE_AS_WCSCHR +- /* NB: Multiply wchar_t count by 4 to get the number of bytes. */ +- leaq (%rdi, %rax, 4), %rax ++ kmovd %k1, %ecx ++ /* bzhil will not be 0 if first match was null. */ ++ bzhil %eax, %ecx, %ecx ++ jne L(zero) + # else +- addq %rdi, %rax +-# endif +-# ifndef USE_AS_STRCHRNUL +- cmp (%rax), %CHAR_REG +- cmovne %rdx, %rax ++ /* Combine CHAR and null matches. */ ++ kord %k0, %k1, %k0 ++ kmovd %k0, %eax ++ tzcntl %eax, %eax + # endif ++ /* NB: Multiply sizeof char type (1 or 4) to get the number of ++ bytes. */ ++ leaq (VEC_SIZE * 4)(%rdi, %rax, CHAR_SIZE), %rax + ret + + .p2align 4 + L(first_vec_x1): + tzcntl %eax, %eax +- /* Found CHAR or the null byte. */ +-# ifdef USE_AS_WCSCHR +- /* NB: Multiply wchar_t count by 4 to get the number of bytes. */ +- leaq VEC_SIZE(%rdi, %rax, 4), %rax +-# else +- leaq VEC_SIZE(%rdi, %rax), %rax +-# endif + # ifndef USE_AS_STRCHRNUL +- cmp (%rax), %CHAR_REG +- cmovne %rdx, %rax ++ /* Found CHAR or the null byte. */ ++ cmp (VEC_SIZE)(%rdi, %rax, CHAR_SIZE), %CHAR_REG ++ jne L(zero) ++ + # endif ++ /* NB: Multiply sizeof char type (1 or 4) to get the number of ++ bytes. */ ++ leaq (VEC_SIZE)(%rdi, %rax, CHAR_SIZE), %rax + ret + + .p2align 4 + L(first_vec_x2): ++# ifndef USE_AS_STRCHRNUL ++ /* Check to see if first match was CHAR (k0) or null (k1). */ ++ kmovd %k0, %eax + tzcntl %eax, %eax +- /* Found CHAR or the null byte. */ +-# ifdef USE_AS_WCSCHR +- /* NB: Multiply wchar_t count by 4 to get the number of bytes. */ +- leaq (VEC_SIZE * 2)(%rdi, %rax, 4), %rax ++ kmovd %k1, %ecx ++ /* bzhil will not be 0 if first match was null. */ ++ bzhil %eax, %ecx, %ecx ++ jne L(zero) + # else +- leaq (VEC_SIZE * 2)(%rdi, %rax), %rax +-# endif +-# ifndef USE_AS_STRCHRNUL +- cmp (%rax), %CHAR_REG +- cmovne %rdx, %rax ++ /* Combine CHAR and null matches. */ ++ kord %k0, %k1, %k0 ++ kmovd %k0, %eax ++ tzcntl %eax, %eax + # endif ++ /* NB: Multiply sizeof char type (1 or 4) to get the number of ++ bytes. */ ++ leaq (VEC_SIZE * 2)(%rdi, %rax, CHAR_SIZE), %rax + ret + +-L(prep_loop_4x): +- /* Align data to 4 * VEC_SIZE. */ ++ .p2align 4 ++L(aligned_more): ++ /* Align data to VEC_SIZE. */ ++ andq $-VEC_SIZE, %rdi ++L(cross_page_continue): ++ /* Check the next 4 * VEC_SIZE. Only one VEC_SIZE at a time since ++ data is only aligned to VEC_SIZE. Use two alternating methods ++ for checking VEC to balance latency and port contention. */ ++ ++ /* This method has higher latency but has better port ++ distribution. */ ++ VMOVA (VEC_SIZE)(%rdi), %YMM1 ++ /* Leaves only CHARS matching esi as 0. */ ++ vpxorq %YMM1, %YMM0, %YMM2 ++ VPMINU %YMM2, %YMM1, %YMM2 ++ /* Each bit in K0 represents a CHAR or a null byte in YMM1. */ ++ VPCMP $0, %YMMZERO, %YMM2, %k0 ++ kmovd %k0, %eax ++ testl %eax, %eax ++ jnz L(first_vec_x1) ++ ++ /* This method has higher latency but has better port ++ distribution. */ ++ VMOVA (VEC_SIZE * 2)(%rdi), %YMM1 ++ /* Each bit in K0 represents a CHAR in YMM1. */ ++ VPCMP $0, %YMM1, %YMM0, %k0 ++ /* Each bit in K1 represents a CHAR in YMM1. */ ++ VPCMP $0, %YMM1, %YMMZERO, %k1 ++ kortestd %k0, %k1 ++ jnz L(first_vec_x2) ++ ++ VMOVA (VEC_SIZE * 3)(%rdi), %YMM1 ++ /* Leaves only CHARS matching esi as 0. */ ++ vpxorq %YMM1, %YMM0, %YMM2 ++ VPMINU %YMM2, %YMM1, %YMM2 ++ /* Each bit in K0 represents a CHAR or a null byte in YMM1. */ ++ VPCMP $0, %YMMZERO, %YMM2, %k0 ++ kmovd %k0, %eax ++ testl %eax, %eax ++ jnz L(first_vec_x3) ++ ++ VMOVA (VEC_SIZE * 4)(%rdi), %YMM1 ++ /* Each bit in K0 represents a CHAR in YMM1. */ ++ VPCMP $0, %YMM1, %YMM0, %k0 ++ /* Each bit in K1 represents a CHAR in YMM1. */ ++ VPCMP $0, %YMM1, %YMMZERO, %k1 ++ kortestd %k0, %k1 ++ jnz L(first_vec_x4) ++ ++ /* Align data to VEC_SIZE * 4 for the loop. */ ++ addq $VEC_SIZE, %rdi + andq $-(VEC_SIZE * 4), %rdi + + .p2align 4 + L(loop_4x_vec): +- /* Compare 4 * VEC at a time forward. */ ++ /* Check 4x VEC at a time. No penalty to imm32 offset with evex ++ encoding. */ + VMOVA (VEC_SIZE * 4)(%rdi), %YMM1 + VMOVA (VEC_SIZE * 5)(%rdi), %YMM2 + VMOVA (VEC_SIZE * 6)(%rdi), %YMM3 + VMOVA (VEC_SIZE * 7)(%rdi), %YMM4 + +- /* Leaves only CHARS matching esi as 0. */ ++ /* For YMM1 and YMM3 use xor to set the CHARs matching esi to ++ zero. */ + vpxorq %YMM1, %YMM0, %YMM5 +- vpxorq %YMM2, %YMM0, %YMM6 ++ /* For YMM2 and YMM4 cmp not equals to CHAR and store result in ++ k register. Its possible to save either 1 or 2 instructions ++ using cmp no equals method for either YMM1 or YMM1 and YMM3 ++ respectively but bottleneck on p5 makes it not worth it. */ ++ VPCMP $4, %YMM0, %YMM2, %k2 + vpxorq %YMM3, %YMM0, %YMM7 +- vpxorq %YMM4, %YMM0, %YMM8 +- +- VPMINU %YMM5, %YMM1, %YMM5 +- VPMINU %YMM6, %YMM2, %YMM6 +- VPMINU %YMM7, %YMM3, %YMM7 +- VPMINU %YMM8, %YMM4, %YMM8 +- +- VPMINU %YMM5, %YMM6, %YMM1 +- VPMINU %YMM7, %YMM8, %YMM2 +- +- VPMINU %YMM1, %YMM2, %YMM1 +- +- /* Each bit in K0 represents a CHAR or a null byte. */ +- VPCMP $0, %YMMZERO, %YMM1, %k0 +- +- addq $(VEC_SIZE * 4), %rdi +- +- ktestd %k0, %k0 ++ VPCMP $4, %YMM0, %YMM4, %k4 ++ ++ /* Use min to select all zeros from either xor or end of string). ++ */ ++ VPMINU %YMM1, %YMM5, %YMM1 ++ VPMINU %YMM3, %YMM7, %YMM3 ++ ++ /* Use min + zeromask to select for zeros. Since k2 and k4 will ++ have 0 as positions that matched with CHAR which will set ++ zero in the corresponding destination bytes in YMM2 / YMM4. ++ */ ++ VPMINU %YMM1, %YMM2, %YMM2{%k2}{z} ++ VPMINU %YMM3, %YMM4, %YMM4 ++ VPMINU %YMM2, %YMM4, %YMM4{%k4}{z} ++ ++ VPCMP $0, %YMMZERO, %YMM4, %k1 ++ kmovd %k1, %ecx ++ subq $-(VEC_SIZE * 4), %rdi ++ testl %ecx, %ecx + jz L(loop_4x_vec) + +- /* Each bit in K0 represents a CHAR or a null byte in YMM1. */ +- VPCMP $0, %YMMZERO, %YMM5, %k0 ++ VPCMP $0, %YMMZERO, %YMM1, %k0 + kmovd %k0, %eax + testl %eax, %eax +- jnz L(first_vec_x0) ++ jnz L(last_vec_x1) + +- /* Each bit in K1 represents a CHAR or a null byte in YMM2. */ +- VPCMP $0, %YMMZERO, %YMM6, %k1 +- kmovd %k1, %eax ++ VPCMP $0, %YMMZERO, %YMM2, %k0 ++ kmovd %k0, %eax + testl %eax, %eax +- jnz L(first_vec_x1) +- +- /* Each bit in K2 represents a CHAR or a null byte in YMM3. */ +- VPCMP $0, %YMMZERO, %YMM7, %k2 +- /* Each bit in K3 represents a CHAR or a null byte in YMM4. */ +- VPCMP $0, %YMMZERO, %YMM8, %k3 ++ jnz L(last_vec_x2) + ++ VPCMP $0, %YMMZERO, %YMM3, %k0 ++ kmovd %k0, %eax ++ /* Combine YMM3 matches (eax) with YMM4 matches (ecx). */ + # ifdef USE_AS_WCSCHR +- /* NB: Each bit in K2/K3 represents 4-byte element. */ +- kshiftlw $8, %k3, %k1 ++ sall $8, %ecx ++ orl %ecx, %eax ++ tzcntl %eax, %eax + # else +- kshiftlq $32, %k3, %k1 ++ salq $32, %rcx ++ orq %rcx, %rax ++ tzcntq %rax, %rax + # endif ++# ifndef USE_AS_STRCHRNUL ++ /* Check if match was CHAR or null. */ ++ cmp (VEC_SIZE * 2)(%rdi, %rax, CHAR_SIZE), %CHAR_REG ++ jne L(zero_end) ++# endif ++ /* NB: Multiply sizeof char type (1 or 4) to get the number of ++ bytes. */ ++ leaq (VEC_SIZE * 2)(%rdi, %rax, CHAR_SIZE), %rax ++ ret + +- /* Each bit in K1 represents a NULL or a mismatch. */ +- korq %k1, %k2, %k1 +- kmovq %k1, %rax ++# ifndef USE_AS_STRCHRNUL ++L(zero_end): ++ xorl %eax, %eax ++ ret ++# endif + +- tzcntq %rax, %rax +-# ifdef USE_AS_WCSCHR +- /* NB: Multiply wchar_t count by 4 to get the number of bytes. */ +- leaq (VEC_SIZE * 2)(%rdi, %rax, 4), %rax +-# else +- leaq (VEC_SIZE * 2)(%rdi, %rax), %rax ++ .p2align 4 ++L(last_vec_x1): ++ tzcntl %eax, %eax ++# ifndef USE_AS_STRCHRNUL ++ /* Check if match was null. */ ++ cmp (%rdi, %rax, CHAR_SIZE), %CHAR_REG ++ jne L(zero_end) + # endif ++ /* NB: Multiply sizeof char type (1 or 4) to get the number of ++ bytes. */ ++ leaq (%rdi, %rax, CHAR_SIZE), %rax ++ ret ++ ++ .p2align 4 ++L(last_vec_x2): ++ tzcntl %eax, %eax + # ifndef USE_AS_STRCHRNUL +- cmp (%rax), %CHAR_REG +- cmovne %rdx, %rax ++ /* Check if match was null. */ ++ cmp (VEC_SIZE)(%rdi, %rax, CHAR_SIZE), %CHAR_REG ++ jne L(zero_end) + # endif ++ /* NB: Multiply sizeof char type (1 or 4) to get the number of ++ bytes. */ ++ leaq (VEC_SIZE)(%rdi, %rax, CHAR_SIZE), %rax + ret + + /* Cold case for crossing page with first load. */ + .p2align 4 + L(cross_page_boundary): ++ movq %rdi, %rdx ++ /* Align rdi. */ + andq $-VEC_SIZE, %rdi +- andl $(VEC_SIZE - 1), %ecx +- + VMOVA (%rdi), %YMM1 +- + /* Leaves only CHARS matching esi as 0. */ + vpxorq %YMM1, %YMM0, %YMM2 + VPMINU %YMM2, %YMM1, %YMM2 + /* Each bit in K0 represents a CHAR or a null byte in YMM1. */ + VPCMP $0, %YMMZERO, %YMM2, %k0 + kmovd %k0, %eax +- testl %eax, %eax +- ++ /* Remove the leading bits. */ + # ifdef USE_AS_WCSCHR ++ movl %edx, %SHIFT_REG + /* NB: Divide shift count by 4 since each bit in K1 represent 4 + bytes. */ +- movl %ecx, %SHIFT_REG +- sarl $2, %SHIFT_REG ++ sarl $2, %SHIFT_REG ++ andl $(CHAR_PER_VEC - 1), %SHIFT_REG + # endif +- +- /* Remove the leading bits. */ + sarxl %SHIFT_REG, %eax, %eax ++ /* If eax is zero continue. */ + testl %eax, %eax +- +- jz L(aligned_more) ++ jz L(cross_page_continue) + tzcntl %eax, %eax +- addq %rcx, %rdi ++# ifndef USE_AS_STRCHRNUL ++ /* Check to see if match was CHAR or null. */ ++ cmp (%rdx, %rax, CHAR_SIZE), %CHAR_REG ++ jne L(zero_end) ++# endif + # ifdef USE_AS_WCSCHR +- /* NB: Multiply wchar_t count by 4 to get the number of bytes. */ +- leaq (%rdi, %rax, 4), %rax ++ /* NB: Multiply wchar_t count by 4 to get the number of ++ bytes. */ ++ leaq (%rdx, %rax, CHAR_SIZE), %rax + # else +- addq %rdi, %rax +-# endif +-# ifndef USE_AS_STRCHRNUL +- cmp (%rax), %CHAR_REG +- cmovne %rdx, %rax ++ addq %rdx, %rax + # endif + ret + +-- +GitLab + diff --git a/SOURCES/glibc-RHEL-15696-44.patch b/SOURCES/glibc-RHEL-15696-44.patch new file mode 100644 index 0000000..52fec88 --- /dev/null +++ b/SOURCES/glibc-RHEL-15696-44.patch @@ -0,0 +1,536 @@ +From 104c7b1967c3e78435c6f7eab5e225a7eddf9c6e Mon Sep 17 00:00:00 2001 +From: Noah Goldstein +Date: Tue, 4 May 2021 19:02:40 -0400 +Subject: [PATCH] x86: Add EVEX optimized memchr family not safe for RTM +Content-type: text/plain; charset=UTF-8 + +No bug. + +This commit adds a new implementation for EVEX memchr that is not safe +for RTM because it uses vzeroupper. The benefit is that by using +ymm0-ymm15 it can use vpcmpeq and vpternlogd in the 4x loop which is +faster than the RTM safe version which cannot use vpcmpeq because +there is no EVEX encoding for the instruction. All parts of the +implementation aside from the 4x loop are the same for the two +versions and the optimization is only relevant for large sizes. + +Tigerlake: +size , algn , Pos , Cur T , New T , Win , Dif +512 , 6 , 192 , 9.2 , 9.04 , no-RTM , 0.16 +512 , 7 , 224 , 9.19 , 8.98 , no-RTM , 0.21 +2048 , 0 , 256 , 10.74 , 10.54 , no-RTM , 0.2 +2048 , 0 , 512 , 14.81 , 14.87 , RTM , 0.06 +2048 , 0 , 1024 , 22.97 , 22.57 , no-RTM , 0.4 +2048 , 0 , 2048 , 37.49 , 34.51 , no-RTM , 2.98 <-- + +Icelake: +size , algn , Pos , Cur T , New T , Win , Dif +512 , 6 , 192 , 7.6 , 7.3 , no-RTM , 0.3 +512 , 7 , 224 , 7.63 , 7.27 , no-RTM , 0.36 +2048 , 0 , 256 , 8.48 , 8.38 , no-RTM , 0.1 +2048 , 0 , 512 , 11.57 , 11.42 , no-RTM , 0.15 +2048 , 0 , 1024 , 17.92 , 17.38 , no-RTM , 0.54 +2048 , 0 , 2048 , 30.37 , 27.34 , no-RTM , 3.03 <-- + +test-memchr, test-wmemchr, and test-rawmemchr are all passing. + +Signed-off-by: Noah Goldstein +Reviewed-by: H.J. Lu +--- + sysdeps/x86_64/multiarch/Makefile | 7 +- + sysdeps/x86_64/multiarch/ifunc-evex.h | 55 ++++++ + sysdeps/x86_64/multiarch/ifunc-impl-list.c | 15 ++ + sysdeps/x86_64/multiarch/memchr-evex-rtm.S | 8 + + sysdeps/x86_64/multiarch/memchr-evex.S | 161 ++++++++++++++---- + sysdeps/x86_64/multiarch/memchr.c | 2 +- + sysdeps/x86_64/multiarch/rawmemchr-evex-rtm.S | 3 + + sysdeps/x86_64/multiarch/rawmemchr.c | 2 +- + sysdeps/x86_64/multiarch/wmemchr-evex-rtm.S | 3 + + sysdeps/x86_64/multiarch/wmemchr.c | 2 +- + 10 files changed, 217 insertions(+), 41 deletions(-) + create mode 100644 sysdeps/x86_64/multiarch/ifunc-evex.h + create mode 100644 sysdeps/x86_64/multiarch/memchr-evex-rtm.S + create mode 100644 sysdeps/x86_64/multiarch/rawmemchr-evex-rtm.S + create mode 100644 sysdeps/x86_64/multiarch/wmemchr-evex-rtm.S + +diff --git a/sysdeps/x86_64/multiarch/Makefile b/sysdeps/x86_64/multiarch/Makefile +index 65fde4eb..26be4095 100644 +--- a/sysdeps/x86_64/multiarch/Makefile ++++ b/sysdeps/x86_64/multiarch/Makefile +@@ -77,7 +77,9 @@ sysdep_routines += strncat-c stpncpy-c strncpy-c \ + strncmp-evex \ + strncpy-evex \ + strnlen-evex \ +- strrchr-evex ++ strrchr-evex \ ++ memchr-evex-rtm \ ++ rawmemchr-evex-rtm + CFLAGS-varshift.c += -msse4 + CFLAGS-strcspn-c.c += -msse4 + CFLAGS-strpbrk-c.c += -msse4 +@@ -110,7 +112,8 @@ sysdep_routines += wmemcmp-sse4 wmemcmp-ssse3 wmemcmp-c \ + wcsnlen-evex \ + wcsrchr-evex \ + wmemchr-evex \ +- wmemcmp-evex-movbe ++ wmemcmp-evex-movbe \ ++ wmemchr-evex-rtm + endif + + ifeq ($(subdir),debug) +diff --git a/sysdeps/x86_64/multiarch/ifunc-evex.h b/sysdeps/x86_64/multiarch/ifunc-evex.h +new file mode 100644 +index 00000000..fc391edb +--- /dev/null ++++ b/sysdeps/x86_64/multiarch/ifunc-evex.h +@@ -0,0 +1,55 @@ ++/* Common definition for ifunc selection optimized with EVEX. ++ All versions must be listed in ifunc-impl-list.c. ++ Copyright (C) 2017-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 ++ ++extern __typeof (REDIRECT_NAME) OPTIMIZE (sse2) attribute_hidden; ++extern __typeof (REDIRECT_NAME) OPTIMIZE (avx2) attribute_hidden; ++extern __typeof (REDIRECT_NAME) OPTIMIZE (avx2_rtm) attribute_hidden; ++extern __typeof (REDIRECT_NAME) OPTIMIZE (evex) attribute_hidden; ++extern __typeof (REDIRECT_NAME) OPTIMIZE (evex_rtm) attribute_hidden; ++ ++ ++static inline void * ++IFUNC_SELECTOR (void) ++{ ++ const struct cpu_features* cpu_features = __get_cpu_features (); ++ ++ if (CPU_FEATURE_USABLE_P (cpu_features, AVX2) ++ && CPU_FEATURE_USABLE_P (cpu_features, BMI2) ++ && CPU_FEATURES_ARCH_P (cpu_features, AVX_Fast_Unaligned_Load)) ++ { ++ if (CPU_FEATURE_USABLE_P (cpu_features, AVX512VL) ++ && CPU_FEATURE_USABLE_P (cpu_features, AVX512BW)) ++ { ++ if (CPU_FEATURE_USABLE_P (cpu_features, RTM)) ++ return OPTIMIZE (evex_rtm); ++ ++ return OPTIMIZE (evex); ++ } ++ ++ if (CPU_FEATURE_USABLE_P (cpu_features, RTM)) ++ return OPTIMIZE (avx2_rtm); ++ ++ if (!CPU_FEATURES_ARCH_P (cpu_features, Prefer_No_VZEROUPPER)) ++ return OPTIMIZE (avx2); ++ } ++ ++ return OPTIMIZE (sse2); ++} +diff --git a/sysdeps/x86_64/multiarch/ifunc-impl-list.c b/sysdeps/x86_64/multiarch/ifunc-impl-list.c +index d59d65f8..ac097e8d 100644 +--- a/sysdeps/x86_64/multiarch/ifunc-impl-list.c ++++ b/sysdeps/x86_64/multiarch/ifunc-impl-list.c +@@ -52,6 +52,11 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + && CPU_FEATURE_USABLE (AVX512BW) + && CPU_FEATURE_USABLE (BMI2)), + __memchr_evex) ++ IFUNC_IMPL_ADD (array, i, memchr, ++ (CPU_FEATURE_USABLE (AVX512VL) ++ && CPU_FEATURE_USABLE (AVX512BW) ++ && CPU_FEATURE_USABLE (BMI2)), ++ __memchr_evex_rtm) + IFUNC_IMPL_ADD (array, i, memchr, 1, __memchr_sse2)) + + /* Support sysdeps/x86_64/multiarch/memcmp.c. */ +@@ -288,6 +293,11 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + && CPU_FEATURE_USABLE (AVX512BW) + && CPU_FEATURE_USABLE (BMI2)), + __rawmemchr_evex) ++ IFUNC_IMPL_ADD (array, i, rawmemchr, ++ (CPU_FEATURE_USABLE (AVX512VL) ++ && CPU_FEATURE_USABLE (AVX512BW) ++ && CPU_FEATURE_USABLE (BMI2)), ++ __rawmemchr_evex_rtm) + IFUNC_IMPL_ADD (array, i, rawmemchr, 1, __rawmemchr_sse2)) + + /* Support sysdeps/x86_64/multiarch/strlen.c. */ +@@ -711,6 +721,11 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + && CPU_FEATURE_USABLE (AVX512BW) + && CPU_FEATURE_USABLE (BMI2)), + __wmemchr_evex) ++ IFUNC_IMPL_ADD (array, i, wmemchr, ++ (CPU_FEATURE_USABLE (AVX512VL) ++ && CPU_FEATURE_USABLE (AVX512BW) ++ && CPU_FEATURE_USABLE (BMI2)), ++ __wmemchr_evex_rtm) + IFUNC_IMPL_ADD (array, i, wmemchr, 1, __wmemchr_sse2)) + + /* Support sysdeps/x86_64/multiarch/wmemcmp.c. */ +diff --git a/sysdeps/x86_64/multiarch/memchr-evex-rtm.S b/sysdeps/x86_64/multiarch/memchr-evex-rtm.S +new file mode 100644 +index 00000000..19871882 +--- /dev/null ++++ b/sysdeps/x86_64/multiarch/memchr-evex-rtm.S +@@ -0,0 +1,8 @@ ++#ifndef MEMCHR ++# define MEMCHR __memchr_evex_rtm ++#endif ++ ++#define USE_IN_RTM 1 ++#define SECTION(p) p##.evex.rtm ++ ++#include "memchr-evex.S" +diff --git a/sysdeps/x86_64/multiarch/memchr-evex.S b/sysdeps/x86_64/multiarch/memchr-evex.S +index f3fdad4f..4d0ed6d1 100644 +--- a/sysdeps/x86_64/multiarch/memchr-evex.S ++++ b/sysdeps/x86_64/multiarch/memchr-evex.S +@@ -38,10 +38,32 @@ + # define CHAR_SIZE 1 + # endif + ++ /* In the 4x loop the RTM and non-RTM versions have data pointer ++ off by VEC_SIZE * 4 with RTM version being VEC_SIZE * 4 greater. ++ This is represented by BASE_OFFSET. As well because the RTM ++ version uses vpcmp which stores a bit per element compared where ++ the non-RTM version uses vpcmpeq which stores a bit per byte ++ compared RET_SCALE of CHAR_SIZE is only relevant for the RTM ++ version. */ ++# ifdef USE_IN_RTM ++# define VZEROUPPER ++# define BASE_OFFSET (VEC_SIZE * 4) ++# define RET_SCALE CHAR_SIZE ++# else ++# define VZEROUPPER vzeroupper ++# define BASE_OFFSET 0 ++# define RET_SCALE 1 ++# endif ++ ++ /* In the return from 4x loop memchr and rawmemchr versions have ++ data pointers off by VEC_SIZE * 4 with memchr version being ++ VEC_SIZE * 4 greater. */ + # ifdef USE_AS_RAWMEMCHR ++# define RET_OFFSET (BASE_OFFSET - (VEC_SIZE * 4)) + # define RAW_PTR_REG rcx + # define ALGN_PTR_REG rdi + # else ++# define RET_OFFSET BASE_OFFSET + # define RAW_PTR_REG rdi + # define ALGN_PTR_REG rcx + # endif +@@ -57,11 +79,15 @@ + # define YMM5 ymm21 + # define YMM6 ymm22 + ++# ifndef SECTION ++# define SECTION(p) p##.evex ++# endif ++ + # define VEC_SIZE 32 + # define CHAR_PER_VEC (VEC_SIZE / CHAR_SIZE) + # define PAGE_SIZE 4096 + +- .section .text.evex,"ax",@progbits ++ .section SECTION(.text),"ax",@progbits + ENTRY (MEMCHR) + # ifndef USE_AS_RAWMEMCHR + /* Check for zero length. */ +@@ -237,14 +263,15 @@ L(cross_page_continue): + /* Check if at last CHAR_PER_VEC * 4 length. */ + subq $(CHAR_PER_VEC * 4), %rdx + jbe L(last_4x_vec_or_less_cmpeq) +- addq $VEC_SIZE, %rdi ++ /* +VEC_SIZE if USE_IN_RTM otherwise +VEC_SIZE * 5. */ ++ addq $(VEC_SIZE + (VEC_SIZE * 4 - BASE_OFFSET)), %rdi + + /* Align data to VEC_SIZE * 4 for the loop and readjust length. + */ + # ifdef USE_AS_WMEMCHR + movl %edi, %ecx + andq $-(4 * VEC_SIZE), %rdi +- andl $(VEC_SIZE * 4 - 1), %ecx ++ subl %edi, %ecx + /* NB: Divide bytes by 4 to get the wchar_t count. */ + sarl $2, %ecx + addq %rcx, %rdx +@@ -254,15 +281,28 @@ L(cross_page_continue): + subq %rdi, %rdx + # endif + # else +- addq $VEC_SIZE, %rdi ++ addq $(VEC_SIZE + (VEC_SIZE * 4 - BASE_OFFSET)), %rdi + andq $-(4 * VEC_SIZE), %rdi + # endif +- ++# ifdef USE_IN_RTM + vpxorq %XMMZERO, %XMMZERO, %XMMZERO ++# else ++ /* copy ymmmatch to ymm0 so we can use vpcmpeq which is not ++ encodable with EVEX registers (ymm16-ymm31). */ ++ vmovdqa64 %YMMMATCH, %ymm0 ++# endif + + /* Compare 4 * VEC at a time forward. */ + .p2align 4 + L(loop_4x_vec): ++ /* Two versions of the loop. One that does not require ++ vzeroupper by not using ymm0-ymm15 and another does that require ++ vzeroupper because it uses ymm0-ymm15. The reason why ymm0-ymm15 ++ is used at all is because there is no EVEX encoding vpcmpeq and ++ with vpcmpeq this loop can be performed more efficiently. The ++ non-vzeroupper version is safe for RTM while the vzeroupper ++ version should be prefered if RTM are not supported. */ ++# ifdef USE_IN_RTM + /* It would be possible to save some instructions using 4x VPCMP + but bottleneck on port 5 makes it not woth it. */ + VPCMP $4, (VEC_SIZE * 4)(%rdi), %YMMMATCH, %k1 +@@ -273,12 +313,55 @@ L(loop_4x_vec): + /* Reduce VEC2 / VEC3 with min and VEC1 with zero mask. */ + VPMINU %YMM2, %YMM3, %YMM3{%k1}{z} + VPCMP $0, %YMM3, %YMMZERO, %k2 ++# else ++ /* Since vptern can only take 3x vectors fastest to do 1 vec ++ seperately with EVEX vpcmp. */ ++# ifdef USE_AS_WMEMCHR ++ /* vptern can only accept masks for epi32/epi64 so can only save ++ instruction using not equals mask on vptern with wmemchr. */ ++ VPCMP $4, (%rdi), %YMMMATCH, %k1 ++# else ++ VPCMP $0, (%rdi), %YMMMATCH, %k1 ++# endif ++ /* Compare 3x with vpcmpeq and or them all together with vptern. ++ */ ++ VPCMPEQ VEC_SIZE(%rdi), %ymm0, %ymm2 ++ VPCMPEQ (VEC_SIZE * 2)(%rdi), %ymm0, %ymm3 ++ VPCMPEQ (VEC_SIZE * 3)(%rdi), %ymm0, %ymm4 ++# ifdef USE_AS_WMEMCHR ++ /* This takes the not of or between ymm2, ymm3, ymm4 as well as ++ combines result from VEC0 with zero mask. */ ++ vpternlogd $1, %ymm2, %ymm3, %ymm4{%k1}{z} ++ vpmovmskb %ymm4, %ecx ++# else ++ /* 254 is mask for oring ymm2, ymm3, ymm4 into ymm4. */ ++ vpternlogd $254, %ymm2, %ymm3, %ymm4 ++ vpmovmskb %ymm4, %ecx ++ kmovd %k1, %eax ++# endif ++# endif ++ + # ifdef USE_AS_RAWMEMCHR + subq $-(VEC_SIZE * 4), %rdi ++# endif ++# ifdef USE_IN_RTM + kortestd %k2, %k3 ++# else ++# ifdef USE_AS_WMEMCHR ++ /* ecx contains not of matches. All 1s means no matches. incl will ++ overflow and set zeroflag if that is the case. */ ++ incl %ecx ++# else ++ /* If either VEC1 (eax) or VEC2-VEC4 (ecx) are not zero. Adding ++ to ecx is not an issue because if eax is non-zero it will be ++ used for returning the match. If it is zero the add does ++ nothing. */ ++ addq %rax, %rcx ++# endif ++# endif ++# ifdef USE_AS_RAWMEMCHR + jz L(loop_4x_vec) + # else +- kortestd %k2, %k3 + jnz L(loop_4x_vec_end) + + subq $-(VEC_SIZE * 4), %rdi +@@ -288,10 +371,11 @@ L(loop_4x_vec): + + /* Fall through into less than 4 remaining vectors of length case. + */ +- VPCMP $0, (VEC_SIZE * 4)(%rdi), %YMMMATCH, %k0 ++ VPCMP $0, BASE_OFFSET(%rdi), %YMMMATCH, %k0 ++ addq $(BASE_OFFSET - VEC_SIZE), %rdi + kmovd %k0, %eax +- addq $(VEC_SIZE * 3), %rdi +- .p2align 4 ++ VZEROUPPER ++ + L(last_4x_vec_or_less): + /* Check if first VEC contained match. */ + testl %eax, %eax +@@ -338,73 +422,78 @@ L(loop_4x_vec_end): + /* rawmemchr will fall through into this if match was found in + loop. */ + ++# if defined USE_IN_RTM || defined USE_AS_WMEMCHR + /* k1 has not of matches with VEC1. */ + kmovd %k1, %eax +-# ifdef USE_AS_WMEMCHR ++# ifdef USE_AS_WMEMCHR + subl $((1 << CHAR_PER_VEC) - 1), %eax +-# else ++# else + incl %eax ++# endif ++# else ++ /* eax already has matches for VEC1. */ ++ testl %eax, %eax + # endif + jnz L(last_vec_x1_return) + ++# ifdef USE_IN_RTM + VPCMP $0, %YMM2, %YMMZERO, %k0 + kmovd %k0, %eax ++# else ++ vpmovmskb %ymm2, %eax ++# endif + testl %eax, %eax + jnz L(last_vec_x2_return) + ++# ifdef USE_IN_RTM + kmovd %k2, %eax + testl %eax, %eax + jnz L(last_vec_x3_return) + + kmovd %k3, %eax + tzcntl %eax, %eax +-# ifdef USE_AS_RAWMEMCHR +- leaq (VEC_SIZE * 3)(%rdi, %rax, CHAR_SIZE), %rax ++ leaq (VEC_SIZE * 3 + RET_OFFSET)(%rdi, %rax, CHAR_SIZE), %rax + # else +- leaq (VEC_SIZE * 7)(%rdi, %rax, CHAR_SIZE), %rax ++ vpmovmskb %ymm3, %eax ++ /* Combine matches in VEC3 (eax) with matches in VEC4 (ecx). */ ++ salq $VEC_SIZE, %rcx ++ orq %rcx, %rax ++ tzcntq %rax, %rax ++ leaq (VEC_SIZE * 2 + RET_OFFSET)(%rdi, %rax), %rax ++ VZEROUPPER + # endif + ret + + .p2align 4 + L(last_vec_x1_return): + tzcntl %eax, %eax +-# ifdef USE_AS_RAWMEMCHR +-# ifdef USE_AS_WMEMCHR ++# if defined USE_AS_WMEMCHR || RET_OFFSET != 0 + /* NB: Multiply bytes by CHAR_SIZE to get the wchar_t count. */ +- leaq (%rdi, %rax, CHAR_SIZE), %rax +-# else +- addq %rdi, %rax +-# endif ++ leaq RET_OFFSET(%rdi, %rax, CHAR_SIZE), %rax + # else +- /* NB: Multiply bytes by CHAR_SIZE to get the wchar_t count. */ +- leaq (VEC_SIZE * 4)(%rdi, %rax, CHAR_SIZE), %rax ++ addq %rdi, %rax + # endif ++ VZEROUPPER + ret + + .p2align 4 + L(last_vec_x2_return): + tzcntl %eax, %eax +-# ifdef USE_AS_RAWMEMCHR +- /* NB: Multiply bytes by CHAR_SIZE to get the wchar_t count. */ +- leaq VEC_SIZE(%rdi, %rax, CHAR_SIZE), %rax +-# else +- /* NB: Multiply bytes by CHAR_SIZE to get the wchar_t count. */ +- leaq (VEC_SIZE * 5)(%rdi, %rax, CHAR_SIZE), %rax +-# endif ++ /* NB: Multiply bytes by RET_SCALE to get the wchar_t count ++ if relevant (RET_SCALE = CHAR_SIZE if USE_AS_WMEMCHAR and ++ USE_IN_RTM are both defined. Otherwise RET_SCALE = 1. */ ++ leaq (VEC_SIZE + RET_OFFSET)(%rdi, %rax, RET_SCALE), %rax ++ VZEROUPPER + ret + ++# ifdef USE_IN_RTM + .p2align 4 + L(last_vec_x3_return): + tzcntl %eax, %eax +-# ifdef USE_AS_RAWMEMCHR +- /* NB: Multiply bytes by CHAR_SIZE to get the wchar_t count. */ +- leaq (VEC_SIZE * 2)(%rdi, %rax, CHAR_SIZE), %rax +-# else + /* NB: Multiply bytes by CHAR_SIZE to get the wchar_t count. */ +- leaq (VEC_SIZE * 6)(%rdi, %rax, CHAR_SIZE), %rax +-# endif ++ leaq (VEC_SIZE * 2 + RET_OFFSET)(%rdi, %rax, CHAR_SIZE), %rax + ret +- ++# endif + + # ifndef USE_AS_RAWMEMCHR + L(last_4x_vec_or_less_cmpeq): +diff --git a/sysdeps/x86_64/multiarch/memchr.c b/sysdeps/x86_64/multiarch/memchr.c +index 016f5784..f28aea77 100644 +--- a/sysdeps/x86_64/multiarch/memchr.c ++++ b/sysdeps/x86_64/multiarch/memchr.c +@@ -24,7 +24,7 @@ + # undef memchr + + # define SYMBOL_NAME memchr +-# include "ifunc-avx2.h" ++# include "ifunc-evex.h" + + libc_ifunc_redirected (__redirect_memchr, memchr, IFUNC_SELECTOR ()); + strong_alias (memchr, __memchr) +diff --git a/sysdeps/x86_64/multiarch/rawmemchr-evex-rtm.S b/sysdeps/x86_64/multiarch/rawmemchr-evex-rtm.S +new file mode 100644 +index 00000000..deda1ca3 +--- /dev/null ++++ b/sysdeps/x86_64/multiarch/rawmemchr-evex-rtm.S +@@ -0,0 +1,3 @@ ++#define MEMCHR __rawmemchr_evex_rtm ++#define USE_AS_RAWMEMCHR 1 ++#include "memchr-evex-rtm.S" +diff --git a/sysdeps/x86_64/multiarch/rawmemchr.c b/sysdeps/x86_64/multiarch/rawmemchr.c +index 8a0bc313..1f764f35 100644 +--- a/sysdeps/x86_64/multiarch/rawmemchr.c ++++ b/sysdeps/x86_64/multiarch/rawmemchr.c +@@ -26,7 +26,7 @@ + # undef __rawmemchr + + # define SYMBOL_NAME rawmemchr +-# include "ifunc-avx2.h" ++# include "ifunc-evex.h" + + libc_ifunc_redirected (__redirect_rawmemchr, __rawmemchr, + IFUNC_SELECTOR ()); +diff --git a/sysdeps/x86_64/multiarch/wmemchr-evex-rtm.S b/sysdeps/x86_64/multiarch/wmemchr-evex-rtm.S +new file mode 100644 +index 00000000..a346cd35 +--- /dev/null ++++ b/sysdeps/x86_64/multiarch/wmemchr-evex-rtm.S +@@ -0,0 +1,3 @@ ++#define MEMCHR __wmemchr_evex_rtm ++#define USE_AS_WMEMCHR 1 ++#include "memchr-evex-rtm.S" +diff --git a/sysdeps/x86_64/multiarch/wmemchr.c b/sysdeps/x86_64/multiarch/wmemchr.c +index 6d833702..f9c91915 100644 +--- a/sysdeps/x86_64/multiarch/wmemchr.c ++++ b/sysdeps/x86_64/multiarch/wmemchr.c +@@ -26,7 +26,7 @@ + # undef __wmemchr + + # define SYMBOL_NAME wmemchr +-# include "ifunc-avx2.h" ++# include "ifunc-evex.h" + + libc_ifunc_redirected (__redirect_wmemchr, __wmemchr, IFUNC_SELECTOR ()); + weak_alias (__wmemchr, wmemchr) +-- +GitLab + diff --git a/SOURCES/glibc-RHEL-15696-45.patch b/SOURCES/glibc-RHEL-15696-45.patch new file mode 100644 index 0000000..380217e --- /dev/null +++ b/SOURCES/glibc-RHEL-15696-45.patch @@ -0,0 +1,873 @@ +From 16d12015c57701b08d7bbed6ec536641bcafb428 Mon Sep 17 00:00:00 2001 +From: Noah Goldstein +Date: Mon, 17 May 2021 13:56:52 -0400 +Subject: [PATCH] x86: Optimize memcmp-avx2-movbe.S +Content-type: text/plain; charset=UTF-8 + +No bug. This commit optimizes memcmp-avx2.S. The optimizations include +adding a new vec compare path for small sizes, reorganizing the entry +control flow, and removing some unnecissary ALU instructions from the +main loop. test-memcmp and test-wmemcmp are both passing. + +Signed-off-by: Noah Goldstein +Reviewed-by: H.J. Lu +--- + sysdeps/x86_64/multiarch/ifunc-impl-list.c | 6 + + sysdeps/x86_64/multiarch/ifunc-memcmp.h | 1 + + sysdeps/x86_64/multiarch/memcmp-avx2-movbe.S | 676 +++++++++++-------- + 3 files changed, 402 insertions(+), 281 deletions(-) + +diff --git a/sysdeps/x86_64/multiarch/ifunc-impl-list.c b/sysdeps/x86_64/multiarch/ifunc-impl-list.c +index ac097e8d..8be0d78a 100644 +--- a/sysdeps/x86_64/multiarch/ifunc-impl-list.c ++++ b/sysdeps/x86_64/multiarch/ifunc-impl-list.c +@@ -63,16 +63,19 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + IFUNC_IMPL (i, name, memcmp, + IFUNC_IMPL_ADD (array, i, memcmp, + (CPU_FEATURE_USABLE (AVX2) ++ && CPU_FEATURE_USABLE (BMI2) + && CPU_FEATURE_USABLE (MOVBE)), + __memcmp_avx2_movbe) + IFUNC_IMPL_ADD (array, i, memcmp, + (CPU_FEATURE_USABLE (AVX2) ++ && CPU_FEATURE_USABLE (BMI2) + && CPU_FEATURE_USABLE (MOVBE) + && CPU_FEATURE_USABLE (RTM)), + __memcmp_avx2_movbe_rtm) + IFUNC_IMPL_ADD (array, i, memcmp, + (CPU_FEATURE_USABLE (AVX512VL) + && CPU_FEATURE_USABLE (AVX512BW) ++ && CPU_FEATURE_USABLE (BMI2) + && CPU_FEATURE_USABLE (MOVBE)), + __memcmp_evex_movbe) + IFUNC_IMPL_ADD (array, i, memcmp, CPU_FEATURE_USABLE (SSE4_1), +@@ -732,16 +735,19 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + IFUNC_IMPL (i, name, wmemcmp, + IFUNC_IMPL_ADD (array, i, wmemcmp, + (CPU_FEATURE_USABLE (AVX2) ++ && CPU_FEATURE_USABLE (BMI2) + && CPU_FEATURE_USABLE (MOVBE)), + __wmemcmp_avx2_movbe) + IFUNC_IMPL_ADD (array, i, wmemcmp, + (CPU_FEATURE_USABLE (AVX2) ++ && CPU_FEATURE_USABLE (BMI2) + && CPU_FEATURE_USABLE (MOVBE) + && CPU_FEATURE_USABLE (RTM)), + __wmemcmp_avx2_movbe_rtm) + IFUNC_IMPL_ADD (array, i, wmemcmp, + (CPU_FEATURE_USABLE (AVX512VL) + && CPU_FEATURE_USABLE (AVX512BW) ++ && CPU_FEATURE_USABLE (BMI2) + && CPU_FEATURE_USABLE (MOVBE)), + __wmemcmp_evex_movbe) + IFUNC_IMPL_ADD (array, i, wmemcmp, CPU_FEATURE_USABLE (SSE4_1), +diff --git a/sysdeps/x86_64/multiarch/ifunc-memcmp.h b/sysdeps/x86_64/multiarch/ifunc-memcmp.h +index 8043c635..690dffe8 100644 +--- a/sysdeps/x86_64/multiarch/ifunc-memcmp.h ++++ b/sysdeps/x86_64/multiarch/ifunc-memcmp.h +@@ -33,6 +33,7 @@ IFUNC_SELECTOR (void) + + if (CPU_FEATURE_USABLE_P (cpu_features, AVX2) + && CPU_FEATURE_USABLE_P (cpu_features, MOVBE) ++ && CPU_FEATURE_USABLE_P (cpu_features, BMI2) + && CPU_FEATURES_ARCH_P (cpu_features, AVX_Fast_Unaligned_Load)) + { + if (CPU_FEATURE_USABLE_P (cpu_features, AVX512VL) +diff --git a/sysdeps/x86_64/multiarch/memcmp-avx2-movbe.S b/sysdeps/x86_64/multiarch/memcmp-avx2-movbe.S +index 9d5c9c72..16fc673e 100644 +--- a/sysdeps/x86_64/multiarch/memcmp-avx2-movbe.S ++++ b/sysdeps/x86_64/multiarch/memcmp-avx2-movbe.S +@@ -19,17 +19,23 @@ + #if IS_IN (libc) + + /* memcmp/wmemcmp is implemented as: +- 1. For size from 2 to 7 bytes, load as big endian with movbe and bswap +- to avoid branches. +- 2. Use overlapping compare to avoid branch. +- 3. Use vector compare when size >= 4 bytes for memcmp or size >= 8 +- bytes for wmemcmp. +- 4. If size is 8 * VEC_SIZE or less, unroll the loop. +- 5. Compare 4 * VEC_SIZE at a time with the aligned first memory ++ 1. Use ymm vector compares when possible. The only case where ++ vector compares is not possible for when size < VEC_SIZE ++ and loading from either s1 or s2 would cause a page cross. ++ 2. For size from 2 to 7 bytes on page cross, load as big endian ++ with movbe and bswap to avoid branches. ++ 3. Use xmm vector compare when size >= 4 bytes for memcmp or ++ size >= 8 bytes for wmemcmp. ++ 4. Optimistically compare up to first 4 * VEC_SIZE one at a ++ to check for early mismatches. Only do this if its guranteed the ++ work is not wasted. ++ 5. If size is 8 * VEC_SIZE or less, unroll the loop. ++ 6. Compare 4 * VEC_SIZE at a time with the aligned first memory + area. +- 6. Use 2 vector compares when size is 2 * VEC_SIZE or less. +- 7. Use 4 vector compares when size is 4 * VEC_SIZE or less. +- 8. Use 8 vector compares when size is 8 * VEC_SIZE or less. */ ++ 7. Use 2 vector compares when size is 2 * VEC_SIZE or less. ++ 8. Use 4 vector compares when size is 4 * VEC_SIZE or less. ++ 9. Use 8 vector compares when size is 8 * VEC_SIZE or less. */ ++ + + # include + +@@ -38,8 +44,10 @@ + # endif + + # ifdef USE_AS_WMEMCMP ++# define CHAR_SIZE 4 + # define VPCMPEQ vpcmpeqd + # else ++# define CHAR_SIZE 1 + # define VPCMPEQ vpcmpeqb + # endif + +@@ -52,7 +60,7 @@ + # endif + + # define VEC_SIZE 32 +-# define VEC_MASK ((1 << VEC_SIZE) - 1) ++# define PAGE_SIZE 4096 + + /* Warning! + wmemcmp has to use SIGNED comparison for elements. +@@ -71,136 +79,359 @@ ENTRY (MEMCMP) + jb L(less_vec) + + /* From VEC to 2 * VEC. No branch when size == VEC_SIZE. */ +- vmovdqu (%rsi), %ymm2 +- VPCMPEQ (%rdi), %ymm2, %ymm2 +- vpmovmskb %ymm2, %eax +- subl $VEC_MASK, %eax +- jnz L(first_vec) ++ vmovdqu (%rsi), %ymm1 ++ VPCMPEQ (%rdi), %ymm1, %ymm1 ++ vpmovmskb %ymm1, %eax ++ /* NB: eax must be destination register if going to ++ L(return_vec_[0,2]). For L(return_vec_3 destination register ++ must be ecx. */ ++ incl %eax ++ jnz L(return_vec_0) + + cmpq $(VEC_SIZE * 2), %rdx +- jbe L(last_vec) +- +- VPCMPEQ %ymm0, %ymm0, %ymm0 +- /* More than 2 * VEC. */ +- cmpq $(VEC_SIZE * 8), %rdx +- ja L(more_8x_vec) +- cmpq $(VEC_SIZE * 4), %rdx +- jb L(last_4x_vec) +- +- /* From 4 * VEC to 8 * VEC, inclusively. */ +- vmovdqu (%rsi), %ymm1 +- VPCMPEQ (%rdi), %ymm1, %ymm1 ++ jbe L(last_1x_vec) + ++ /* Check second VEC no matter what. */ + vmovdqu VEC_SIZE(%rsi), %ymm2 +- VPCMPEQ VEC_SIZE(%rdi), %ymm2, %ymm2 ++ VPCMPEQ VEC_SIZE(%rdi), %ymm2, %ymm2 ++ vpmovmskb %ymm2, %eax ++ /* If all 4 VEC where equal eax will be all 1s so incl will ++ overflow and set zero flag. */ ++ incl %eax ++ jnz L(return_vec_1) + +- vmovdqu (VEC_SIZE * 2)(%rsi), %ymm3 +- VPCMPEQ (VEC_SIZE * 2)(%rdi), %ymm3, %ymm3 ++ /* Less than 4 * VEC. */ ++ cmpq $(VEC_SIZE * 4), %rdx ++ jbe L(last_2x_vec) + ++ /* Check third and fourth VEC no matter what. */ ++ vmovdqu (VEC_SIZE * 2)(%rsi), %ymm3 ++ VPCMPEQ (VEC_SIZE * 2)(%rdi), %ymm3, %ymm3 ++ vpmovmskb %ymm3, %eax ++ incl %eax ++ jnz L(return_vec_2) + vmovdqu (VEC_SIZE * 3)(%rsi), %ymm4 +- VPCMPEQ (VEC_SIZE * 3)(%rdi), %ymm4, %ymm4 ++ VPCMPEQ (VEC_SIZE * 3)(%rdi), %ymm4, %ymm4 ++ vpmovmskb %ymm4, %ecx ++ incl %ecx ++ jnz L(return_vec_3) + +- vpand %ymm1, %ymm2, %ymm5 +- vpand %ymm3, %ymm4, %ymm6 +- vpand %ymm5, %ymm6, %ymm5 ++ /* Go to 4x VEC loop. */ ++ cmpq $(VEC_SIZE * 8), %rdx ++ ja L(more_8x_vec) + +- vptest %ymm0, %ymm5 +- jnc L(4x_vec_end) ++ /* Handle remainder of size = 4 * VEC + 1 to 8 * VEC without any ++ branches. */ + ++ /* Load first two VEC from s2 before adjusting addresses. */ ++ vmovdqu -(VEC_SIZE * 4)(%rsi, %rdx), %ymm1 ++ vmovdqu -(VEC_SIZE * 3)(%rsi, %rdx), %ymm2 + leaq -(4 * VEC_SIZE)(%rdi, %rdx), %rdi + leaq -(4 * VEC_SIZE)(%rsi, %rdx), %rsi +- vmovdqu (%rsi), %ymm1 +- VPCMPEQ (%rdi), %ymm1, %ymm1 + +- vmovdqu VEC_SIZE(%rsi), %ymm2 +- VPCMPEQ VEC_SIZE(%rdi), %ymm2, %ymm2 +- vpand %ymm2, %ymm1, %ymm5 ++ /* Wait to load from s1 until addressed adjust due to ++ unlamination of microfusion with complex address mode. */ ++ VPCMPEQ (%rdi), %ymm1, %ymm1 ++ VPCMPEQ (VEC_SIZE)(%rdi), %ymm2, %ymm2 + + vmovdqu (VEC_SIZE * 2)(%rsi), %ymm3 +- VPCMPEQ (VEC_SIZE * 2)(%rdi), %ymm3, %ymm3 +- vpand %ymm3, %ymm5, %ymm5 +- ++ VPCMPEQ (VEC_SIZE * 2)(%rdi), %ymm3, %ymm3 + vmovdqu (VEC_SIZE * 3)(%rsi), %ymm4 +- VPCMPEQ (VEC_SIZE * 3)(%rdi), %ymm4, %ymm4 +- vpand %ymm4, %ymm5, %ymm5 ++ VPCMPEQ (VEC_SIZE * 3)(%rdi), %ymm4, %ymm4 + +- vptest %ymm0, %ymm5 +- jnc L(4x_vec_end) +- xorl %eax, %eax ++ /* Reduce VEC0 - VEC4. */ ++ vpand %ymm1, %ymm2, %ymm5 ++ vpand %ymm3, %ymm4, %ymm6 ++ vpand %ymm5, %ymm6, %ymm7 ++ vpmovmskb %ymm7, %ecx ++ incl %ecx ++ jnz L(return_vec_0_1_2_3) ++ /* NB: eax must be zero to reach here. */ ++ VZEROUPPER_RETURN ++ ++ .p2align 4 ++L(return_vec_0): ++ tzcntl %eax, %eax ++# ifdef USE_AS_WMEMCMP ++ movl (%rdi, %rax), %ecx ++ xorl %edx, %edx ++ cmpl (%rsi, %rax), %ecx ++ /* NB: no partial register stall here because xorl zero idiom ++ above. */ ++ setg %dl ++ leal -1(%rdx, %rdx), %eax ++# else ++ movzbl (%rsi, %rax), %ecx ++ movzbl (%rdi, %rax), %eax ++ subl %ecx, %eax ++# endif + L(return_vzeroupper): + ZERO_UPPER_VEC_REGISTERS_RETURN + + .p2align 4 +-L(last_2x_vec): +- /* From VEC to 2 * VEC. No branch when size == VEC_SIZE. */ +- vmovdqu (%rsi), %ymm2 +- VPCMPEQ (%rdi), %ymm2, %ymm2 +- vpmovmskb %ymm2, %eax +- subl $VEC_MASK, %eax +- jnz L(first_vec) ++L(return_vec_1): ++ tzcntl %eax, %eax ++# ifdef USE_AS_WMEMCMP ++ movl VEC_SIZE(%rdi, %rax), %ecx ++ xorl %edx, %edx ++ cmpl VEC_SIZE(%rsi, %rax), %ecx ++ setg %dl ++ leal -1(%rdx, %rdx), %eax ++# else ++ movzbl VEC_SIZE(%rsi, %rax), %ecx ++ movzbl VEC_SIZE(%rdi, %rax), %eax ++ subl %ecx, %eax ++# endif ++ VZEROUPPER_RETURN ++ ++ .p2align 4 ++L(return_vec_2): ++ tzcntl %eax, %eax ++# ifdef USE_AS_WMEMCMP ++ movl (VEC_SIZE * 2)(%rdi, %rax), %ecx ++ xorl %edx, %edx ++ cmpl (VEC_SIZE * 2)(%rsi, %rax), %ecx ++ setg %dl ++ leal -1(%rdx, %rdx), %eax ++# else ++ movzbl (VEC_SIZE * 2)(%rsi, %rax), %ecx ++ movzbl (VEC_SIZE * 2)(%rdi, %rax), %eax ++ subl %ecx, %eax ++# endif ++ VZEROUPPER_RETURN ++ ++ /* NB: p2align 5 here to ensure 4x loop is 32 byte aligned. */ ++ .p2align 5 ++L(8x_return_vec_0_1_2_3): ++ /* Returning from L(more_8x_vec) requires restoring rsi. */ ++ addq %rdi, %rsi ++L(return_vec_0_1_2_3): ++ vpmovmskb %ymm1, %eax ++ incl %eax ++ jnz L(return_vec_0) + +-L(last_vec): +- /* Use overlapping loads to avoid branches. */ +- leaq -VEC_SIZE(%rdi, %rdx), %rdi +- leaq -VEC_SIZE(%rsi, %rdx), %rsi +- vmovdqu (%rsi), %ymm2 +- VPCMPEQ (%rdi), %ymm2, %ymm2 + vpmovmskb %ymm2, %eax +- subl $VEC_MASK, %eax +- jnz L(first_vec) ++ incl %eax ++ jnz L(return_vec_1) ++ ++ vpmovmskb %ymm3, %eax ++ incl %eax ++ jnz L(return_vec_2) ++L(return_vec_3): ++ tzcntl %ecx, %ecx ++# ifdef USE_AS_WMEMCMP ++ movl (VEC_SIZE * 3)(%rdi, %rcx), %eax ++ xorl %edx, %edx ++ cmpl (VEC_SIZE * 3)(%rsi, %rcx), %eax ++ setg %dl ++ leal -1(%rdx, %rdx), %eax ++# else ++ movzbl (VEC_SIZE * 3)(%rdi, %rcx), %eax ++ movzbl (VEC_SIZE * 3)(%rsi, %rcx), %ecx ++ subl %ecx, %eax ++# endif ++ VZEROUPPER_RETURN ++ ++ .p2align 4 ++L(more_8x_vec): ++ /* Set end of s1 in rdx. */ ++ leaq -(VEC_SIZE * 4)(%rdi, %rdx), %rdx ++ /* rsi stores s2 - s1. This allows loop to only update one ++ pointer. */ ++ subq %rdi, %rsi ++ /* Align s1 pointer. */ ++ andq $-VEC_SIZE, %rdi ++ /* Adjust because first 4x vec where check already. */ ++ subq $-(VEC_SIZE * 4), %rdi ++ .p2align 4 ++L(loop_4x_vec): ++ /* rsi has s2 - s1 so get correct address by adding s1 (in rdi). ++ */ ++ vmovdqu (%rsi, %rdi), %ymm1 ++ VPCMPEQ (%rdi), %ymm1, %ymm1 ++ ++ vmovdqu VEC_SIZE(%rsi, %rdi), %ymm2 ++ VPCMPEQ VEC_SIZE(%rdi), %ymm2, %ymm2 ++ ++ vmovdqu (VEC_SIZE * 2)(%rsi, %rdi), %ymm3 ++ VPCMPEQ (VEC_SIZE * 2)(%rdi), %ymm3, %ymm3 ++ ++ vmovdqu (VEC_SIZE * 3)(%rsi, %rdi), %ymm4 ++ VPCMPEQ (VEC_SIZE * 3)(%rdi), %ymm4, %ymm4 ++ ++ vpand %ymm1, %ymm2, %ymm5 ++ vpand %ymm3, %ymm4, %ymm6 ++ vpand %ymm5, %ymm6, %ymm7 ++ vpmovmskb %ymm7, %ecx ++ incl %ecx ++ jnz L(8x_return_vec_0_1_2_3) ++ subq $-(VEC_SIZE * 4), %rdi ++ /* Check if s1 pointer at end. */ ++ cmpq %rdx, %rdi ++ jb L(loop_4x_vec) ++ ++ subq %rdx, %rdi ++ /* rdi has 4 * VEC_SIZE - remaining length. */ ++ cmpl $(VEC_SIZE * 3), %edi ++ jae L(8x_last_1x_vec) ++ /* Load regardless of branch. */ ++ vmovdqu (VEC_SIZE * 2)(%rsi, %rdx), %ymm3 ++ cmpl $(VEC_SIZE * 2), %edi ++ jae L(8x_last_2x_vec) ++ ++ /* Check last 4 VEC. */ ++ vmovdqu (%rsi, %rdx), %ymm1 ++ VPCMPEQ (%rdx), %ymm1, %ymm1 ++ ++ vmovdqu VEC_SIZE(%rsi, %rdx), %ymm2 ++ VPCMPEQ VEC_SIZE(%rdx), %ymm2, %ymm2 ++ ++ VPCMPEQ (VEC_SIZE * 2)(%rdx), %ymm3, %ymm3 ++ ++ vmovdqu (VEC_SIZE * 3)(%rsi, %rdx), %ymm4 ++ VPCMPEQ (VEC_SIZE * 3)(%rdx), %ymm4, %ymm4 ++ ++ vpand %ymm1, %ymm2, %ymm5 ++ vpand %ymm3, %ymm4, %ymm6 ++ vpand %ymm5, %ymm6, %ymm7 ++ vpmovmskb %ymm7, %ecx ++ /* Restore s1 pointer to rdi. */ ++ movq %rdx, %rdi ++ incl %ecx ++ jnz L(8x_return_vec_0_1_2_3) ++ /* NB: eax must be zero to reach here. */ ++ VZEROUPPER_RETURN ++ ++ /* Only entry is from L(more_8x_vec). */ ++ .p2align 4 ++L(8x_last_2x_vec): ++ /* Check second to last VEC. rdx store end pointer of s1 and ++ ymm3 has already been loaded with second to last VEC from s2. ++ */ ++ VPCMPEQ (VEC_SIZE * 2)(%rdx), %ymm3, %ymm3 ++ vpmovmskb %ymm3, %eax ++ incl %eax ++ jnz L(8x_return_vec_2) ++ /* Check last VEC. */ ++ .p2align 4 ++L(8x_last_1x_vec): ++ vmovdqu (VEC_SIZE * 3)(%rsi, %rdx), %ymm4 ++ VPCMPEQ (VEC_SIZE * 3)(%rdx), %ymm4, %ymm4 ++ vpmovmskb %ymm4, %eax ++ incl %eax ++ jnz L(8x_return_vec_3) + VZEROUPPER_RETURN + + .p2align 4 +-L(first_vec): +- /* A byte or int32 is different within 16 or 32 bytes. */ +- tzcntl %eax, %ecx ++L(last_2x_vec): ++ /* Check second to last VEC. */ ++ vmovdqu -(VEC_SIZE * 2)(%rsi, %rdx), %ymm1 ++ VPCMPEQ -(VEC_SIZE * 2)(%rdi, %rdx), %ymm1, %ymm1 ++ vpmovmskb %ymm1, %eax ++ incl %eax ++ jnz L(return_vec_1_end) ++ /* Check last VEC. */ ++L(last_1x_vec): ++ vmovdqu -(VEC_SIZE * 1)(%rsi, %rdx), %ymm1 ++ VPCMPEQ -(VEC_SIZE * 1)(%rdi, %rdx), %ymm1, %ymm1 ++ vpmovmskb %ymm1, %eax ++ incl %eax ++ jnz L(return_vec_0_end) ++ VZEROUPPER_RETURN ++ ++ .p2align 4 ++L(8x_return_vec_2): ++ subq $VEC_SIZE, %rdx ++L(8x_return_vec_3): ++ tzcntl %eax, %eax ++ addq %rdx, %rax + # ifdef USE_AS_WMEMCMP +- xorl %eax, %eax +- movl (%rdi, %rcx), %edx +- cmpl (%rsi, %rcx), %edx +-L(wmemcmp_return): +- setl %al +- negl %eax +- orl $1, %eax ++ movl (VEC_SIZE * 3)(%rax), %ecx ++ xorl %edx, %edx ++ cmpl (VEC_SIZE * 3)(%rsi, %rax), %ecx ++ setg %dl ++ leal -1(%rdx, %rdx), %eax + # else +- movzbl (%rdi, %rcx), %eax +- movzbl (%rsi, %rcx), %edx +- sub %edx, %eax ++ movzbl (VEC_SIZE * 3)(%rsi, %rax), %ecx ++ movzbl (VEC_SIZE * 3)(%rax), %eax ++ subl %ecx, %eax + # endif + VZEROUPPER_RETURN + +-# ifdef USE_AS_WMEMCMP + .p2align 4 +-L(4): +- xorl %eax, %eax +- movl (%rdi), %edx +- cmpl (%rsi), %edx +- jne L(wmemcmp_return) +- ret ++L(return_vec_1_end): ++ tzcntl %eax, %eax ++ addl %edx, %eax ++# ifdef USE_AS_WMEMCMP ++ movl -(VEC_SIZE * 2)(%rdi, %rax), %ecx ++ xorl %edx, %edx ++ cmpl -(VEC_SIZE * 2)(%rsi, %rax), %ecx ++ setg %dl ++ leal -1(%rdx, %rdx), %eax + # else ++ movzbl -(VEC_SIZE * 2)(%rsi, %rax), %ecx ++ movzbl -(VEC_SIZE * 2)(%rdi, %rax), %eax ++ subl %ecx, %eax ++# endif ++ VZEROUPPER_RETURN ++ + .p2align 4 +-L(between_4_7): +- /* Load as big endian with overlapping movbe to avoid branches. */ +- movbe (%rdi), %eax +- movbe (%rsi), %ecx +- shlq $32, %rax +- shlq $32, %rcx +- movbe -4(%rdi, %rdx), %edi +- movbe -4(%rsi, %rdx), %esi +- orq %rdi, %rax +- orq %rsi, %rcx +- subq %rcx, %rax +- je L(exit) +- sbbl %eax, %eax +- orl $1, %eax +- ret ++L(return_vec_0_end): ++ tzcntl %eax, %eax ++ addl %edx, %eax ++# ifdef USE_AS_WMEMCMP ++ movl -VEC_SIZE(%rdi, %rax), %ecx ++ xorl %edx, %edx ++ cmpl -VEC_SIZE(%rsi, %rax), %ecx ++ setg %dl ++ leal -1(%rdx, %rdx), %eax ++# else ++ movzbl -VEC_SIZE(%rsi, %rax), %ecx ++ movzbl -VEC_SIZE(%rdi, %rax), %eax ++ subl %ecx, %eax ++# endif ++ VZEROUPPER_RETURN + + .p2align 4 +-L(exit): +- ret ++L(less_vec): ++ /* Check if one or less CHAR. This is necessary for size = 0 but ++ is also faster for size = CHAR_SIZE. */ ++ cmpl $CHAR_SIZE, %edx ++ jbe L(one_or_less) ++ ++ /* Check if loading one VEC from either s1 or s2 could cause a ++ page cross. This can have false positives but is by far the ++ fastest method. */ ++ movl %edi, %eax ++ orl %esi, %eax ++ andl $(PAGE_SIZE - 1), %eax ++ cmpl $(PAGE_SIZE - VEC_SIZE), %eax ++ jg L(page_cross_less_vec) ++ ++ /* No page cross possible. */ ++ vmovdqu (%rsi), %ymm2 ++ VPCMPEQ (%rdi), %ymm2, %ymm2 ++ vpmovmskb %ymm2, %eax ++ incl %eax ++ /* Result will be zero if s1 and s2 match. Otherwise first set ++ bit will be first mismatch. */ ++ bzhil %edx, %eax, %edx ++ jnz L(return_vec_0) ++ xorl %eax, %eax ++ VZEROUPPER_RETURN + + .p2align 4 +-L(between_2_3): ++L(page_cross_less_vec): ++ /* if USE_AS_WMEMCMP it can only be 0, 4, 8, 12, 16, 20, 24, 28 ++ bytes. */ ++ cmpl $16, %edx ++ jae L(between_16_31) ++# ifndef USE_AS_WMEMCMP ++ cmpl $8, %edx ++ jae L(between_8_15) ++ cmpl $4, %edx ++ jae L(between_4_7) ++ + /* Load as big endian to avoid branches. */ + movzwl (%rdi), %eax + movzwl (%rsi), %ecx +@@ -208,223 +439,106 @@ L(between_2_3): + shll $8, %ecx + bswap %eax + bswap %ecx +- movb -1(%rdi, %rdx), %al +- movb -1(%rsi, %rdx), %cl ++ movzbl -1(%rdi, %rdx), %edi ++ movzbl -1(%rsi, %rdx), %esi ++ orl %edi, %eax ++ orl %esi, %ecx + /* Subtraction is okay because the upper 8 bits are zero. */ + subl %ecx, %eax ++ /* No ymm register was touched. */ + ret + + .p2align 4 +-L(1): +- movzbl (%rdi), %eax ++L(one_or_less): ++ jb L(zero) + movzbl (%rsi), %ecx ++ movzbl (%rdi), %eax + subl %ecx, %eax +- ret +-# endif +- +- .p2align 4 +-L(zero): +- xorl %eax, %eax ++ /* No ymm register was touched. */ + ret + + .p2align 4 +-L(less_vec): +-# ifdef USE_AS_WMEMCMP +- /* It can only be 0, 4, 8, 12, 16, 20, 24, 28 bytes. */ +- cmpb $4, %dl +- je L(4) +- jb L(zero) +-# else +- cmpb $1, %dl +- je L(1) +- jb L(zero) +- cmpb $4, %dl +- jb L(between_2_3) +- cmpb $8, %dl +- jb L(between_4_7) ++L(between_8_15): + # endif +- cmpb $16, %dl +- jae L(between_16_31) +- /* It is between 8 and 15 bytes. */ ++ /* If USE_AS_WMEMCMP fall through into 8-15 byte case. */ + vmovq (%rdi), %xmm1 + vmovq (%rsi), %xmm2 +- VPCMPEQ %xmm1, %xmm2, %xmm2 ++ VPCMPEQ %xmm1, %xmm2, %xmm2 + vpmovmskb %xmm2, %eax +- subl $0xffff, %eax +- jnz L(first_vec) ++ subl $0xffff, %eax ++ jnz L(return_vec_0) + /* Use overlapping loads to avoid branches. */ + leaq -8(%rdi, %rdx), %rdi + leaq -8(%rsi, %rdx), %rsi + vmovq (%rdi), %xmm1 + vmovq (%rsi), %xmm2 +- VPCMPEQ %xmm1, %xmm2, %xmm2 ++ VPCMPEQ %xmm1, %xmm2, %xmm2 + vpmovmskb %xmm2, %eax +- subl $0xffff, %eax +- jnz L(first_vec) ++ subl $0xffff, %eax ++ jnz L(return_vec_0) ++ /* No ymm register was touched. */ ++ ret ++ ++ .p2align 4 ++L(zero): ++ xorl %eax, %eax + ret + + .p2align 4 + L(between_16_31): + /* From 16 to 31 bytes. No branch when size == 16. */ + vmovdqu (%rsi), %xmm2 +- VPCMPEQ (%rdi), %xmm2, %xmm2 ++ VPCMPEQ (%rdi), %xmm2, %xmm2 + vpmovmskb %xmm2, %eax +- subl $0xffff, %eax +- jnz L(first_vec) ++ subl $0xffff, %eax ++ jnz L(return_vec_0) + + /* Use overlapping loads to avoid branches. */ ++ ++ vmovdqu -16(%rsi, %rdx), %xmm2 + leaq -16(%rdi, %rdx), %rdi + leaq -16(%rsi, %rdx), %rsi +- vmovdqu (%rsi), %xmm2 +- VPCMPEQ (%rdi), %xmm2, %xmm2 ++ VPCMPEQ (%rdi), %xmm2, %xmm2 + vpmovmskb %xmm2, %eax +- subl $0xffff, %eax +- jnz L(first_vec) ++ subl $0xffff, %eax ++ jnz L(return_vec_0) ++ /* No ymm register was touched. */ + ret + +- .p2align 4 +-L(more_8x_vec): +- /* More than 8 * VEC. Check the first VEC. */ +- vmovdqu (%rsi), %ymm2 +- VPCMPEQ (%rdi), %ymm2, %ymm2 +- vpmovmskb %ymm2, %eax +- subl $VEC_MASK, %eax +- jnz L(first_vec) +- +- /* Align the first memory area for aligned loads in the loop. +- Compute how much the first memory area is misaligned. */ +- movq %rdi, %rcx +- andl $(VEC_SIZE - 1), %ecx +- /* Get the negative of offset for alignment. */ +- subq $VEC_SIZE, %rcx +- /* Adjust the second memory area. */ +- subq %rcx, %rsi +- /* Adjust the first memory area which should be aligned now. */ +- subq %rcx, %rdi +- /* Adjust length. */ +- addq %rcx, %rdx +- +-L(loop_4x_vec): +- /* Compare 4 * VEC at a time forward. */ +- vmovdqu (%rsi), %ymm1 +- VPCMPEQ (%rdi), %ymm1, %ymm1 +- +- vmovdqu VEC_SIZE(%rsi), %ymm2 +- VPCMPEQ VEC_SIZE(%rdi), %ymm2, %ymm2 +- vpand %ymm2, %ymm1, %ymm5 +- +- vmovdqu (VEC_SIZE * 2)(%rsi), %ymm3 +- VPCMPEQ (VEC_SIZE * 2)(%rdi), %ymm3, %ymm3 +- vpand %ymm3, %ymm5, %ymm5 +- +- vmovdqu (VEC_SIZE * 3)(%rsi), %ymm4 +- VPCMPEQ (VEC_SIZE * 3)(%rdi), %ymm4, %ymm4 +- vpand %ymm4, %ymm5, %ymm5 +- +- vptest %ymm0, %ymm5 +- jnc L(4x_vec_end) +- +- addq $(VEC_SIZE * 4), %rdi +- addq $(VEC_SIZE * 4), %rsi +- +- subq $(VEC_SIZE * 4), %rdx +- cmpq $(VEC_SIZE * 4), %rdx +- jae L(loop_4x_vec) +- +- /* Less than 4 * VEC. */ +- cmpq $VEC_SIZE, %rdx +- jbe L(last_vec) +- cmpq $(VEC_SIZE * 2), %rdx +- jbe L(last_2x_vec) +- +-L(last_4x_vec): +- /* From 2 * VEC to 4 * VEC. */ +- vmovdqu (%rsi), %ymm2 +- VPCMPEQ (%rdi), %ymm2, %ymm2 +- vpmovmskb %ymm2, %eax +- subl $VEC_MASK, %eax +- jnz L(first_vec) +- +- addq $VEC_SIZE, %rdi +- addq $VEC_SIZE, %rsi +- vmovdqu (%rsi), %ymm2 +- VPCMPEQ (%rdi), %ymm2, %ymm2 +- vpmovmskb %ymm2, %eax +- subl $VEC_MASK, %eax +- jnz L(first_vec) +- +- /* Use overlapping loads to avoid branches. */ +- leaq -(3 * VEC_SIZE)(%rdi, %rdx), %rdi +- leaq -(3 * VEC_SIZE)(%rsi, %rdx), %rsi +- vmovdqu (%rsi), %ymm2 +- VPCMPEQ (%rdi), %ymm2, %ymm2 +- vpmovmskb %ymm2, %eax +- subl $VEC_MASK, %eax +- jnz L(first_vec) +- +- addq $VEC_SIZE, %rdi +- addq $VEC_SIZE, %rsi +- vmovdqu (%rsi), %ymm2 +- VPCMPEQ (%rdi), %ymm2, %ymm2 +- vpmovmskb %ymm2, %eax +- subl $VEC_MASK, %eax +- jnz L(first_vec) +- VZEROUPPER_RETURN +- +- .p2align 4 +-L(4x_vec_end): +- vpmovmskb %ymm1, %eax +- subl $VEC_MASK, %eax +- jnz L(first_vec) +- vpmovmskb %ymm2, %eax +- subl $VEC_MASK, %eax +- jnz L(first_vec_x1) +- vpmovmskb %ymm3, %eax +- subl $VEC_MASK, %eax +- jnz L(first_vec_x2) +- vpmovmskb %ymm4, %eax +- subl $VEC_MASK, %eax +- tzcntl %eax, %ecx + # ifdef USE_AS_WMEMCMP +- xorl %eax, %eax +- movl (VEC_SIZE * 3)(%rdi, %rcx), %edx +- cmpl (VEC_SIZE * 3)(%rsi, %rcx), %edx +- jmp L(wmemcmp_return) +-# else +- movzbl (VEC_SIZE * 3)(%rdi, %rcx), %eax +- movzbl (VEC_SIZE * 3)(%rsi, %rcx), %edx +- sub %edx, %eax +-# endif +- VZEROUPPER_RETURN +- + .p2align 4 +-L(first_vec_x1): +- tzcntl %eax, %ecx +-# ifdef USE_AS_WMEMCMP +- xorl %eax, %eax +- movl VEC_SIZE(%rdi, %rcx), %edx +- cmpl VEC_SIZE(%rsi, %rcx), %edx +- jmp L(wmemcmp_return) ++L(one_or_less): ++ jb L(zero) ++ movl (%rdi), %ecx ++ xorl %edx, %edx ++ cmpl (%rsi), %ecx ++ je L(zero) ++ setg %dl ++ leal -1(%rdx, %rdx), %eax ++ /* No ymm register was touched. */ ++ ret + # else +- movzbl VEC_SIZE(%rdi, %rcx), %eax +- movzbl VEC_SIZE(%rsi, %rcx), %edx +- sub %edx, %eax +-# endif +- VZEROUPPER_RETURN + + .p2align 4 +-L(first_vec_x2): +- tzcntl %eax, %ecx +-# ifdef USE_AS_WMEMCMP +- xorl %eax, %eax +- movl (VEC_SIZE * 2)(%rdi, %rcx), %edx +- cmpl (VEC_SIZE * 2)(%rsi, %rcx), %edx +- jmp L(wmemcmp_return) +-# else +- movzbl (VEC_SIZE * 2)(%rdi, %rcx), %eax +- movzbl (VEC_SIZE * 2)(%rsi, %rcx), %edx +- sub %edx, %eax ++L(between_4_7): ++ /* Load as big endian with overlapping movbe to avoid branches. ++ */ ++ movbe (%rdi), %eax ++ movbe (%rsi), %ecx ++ shlq $32, %rax ++ shlq $32, %rcx ++ movbe -4(%rdi, %rdx), %edi ++ movbe -4(%rsi, %rdx), %esi ++ orq %rdi, %rax ++ orq %rsi, %rcx ++ subq %rcx, %rax ++ jz L(zero_4_7) ++ sbbl %eax, %eax ++ orl $1, %eax ++L(zero_4_7): ++ /* No ymm register was touched. */ ++ ret + # endif +- VZEROUPPER_RETURN ++ + END (MEMCMP) + #endif +-- +GitLab + diff --git a/SOURCES/glibc-RHEL-15696-46.patch b/SOURCES/glibc-RHEL-15696-46.patch new file mode 100644 index 0000000..881fe81 --- /dev/null +++ b/SOURCES/glibc-RHEL-15696-46.patch @@ -0,0 +1,851 @@ +From 4ad473e97acdc5f6d811755b67c09f2128a644ce Mon Sep 17 00:00:00 2001 +From: Noah Goldstein +Date: Mon, 17 May 2021 13:57:24 -0400 +Subject: [PATCH] x86: Optimize memcmp-evex-movbe.S +Content-type: text/plain; charset=UTF-8 + +No bug. This commit optimizes memcmp-evex.S. The optimizations include +adding a new vec compare path for small sizes, reorganizing the entry +control flow, removing some unnecissary ALU instructions from the main +loop, and most importantly replacing the heavy use of vpcmp + kand +logic with vpxor + vptern. test-memcmp and test-wmemcmp are both +passing. + +Signed-off-by: Noah Goldstein +Reviewed-by: H.J. Lu +--- + sysdeps/x86_64/multiarch/memcmp-evex-movbe.S | 710 +++++++++++-------- + 1 file changed, 408 insertions(+), 302 deletions(-) + +diff --git a/sysdeps/x86_64/multiarch/memcmp-evex-movbe.S b/sysdeps/x86_64/multiarch/memcmp-evex-movbe.S +index 9c093972..654dc7ac 100644 +--- a/sysdeps/x86_64/multiarch/memcmp-evex-movbe.S ++++ b/sysdeps/x86_64/multiarch/memcmp-evex-movbe.S +@@ -19,17 +19,22 @@ + #if IS_IN (libc) + + /* memcmp/wmemcmp is implemented as: +- 1. For size from 2 to 7 bytes, load as big endian with movbe and bswap +- to avoid branches. +- 2. Use overlapping compare to avoid branch. +- 3. Use vector compare when size >= 4 bytes for memcmp or size >= 8 +- bytes for wmemcmp. +- 4. If size is 8 * VEC_SIZE or less, unroll the loop. +- 5. Compare 4 * VEC_SIZE at a time with the aligned first memory ++ 1. Use ymm vector compares when possible. The only case where ++ vector compares is not possible for when size < CHAR_PER_VEC ++ and loading from either s1 or s2 would cause a page cross. ++ 2. For size from 2 to 7 bytes on page cross, load as big endian ++ with movbe and bswap to avoid branches. ++ 3. Use xmm vector compare when size >= 4 bytes for memcmp or ++ size >= 8 bytes for wmemcmp. ++ 4. Optimistically compare up to first 4 * CHAR_PER_VEC one at a ++ to check for early mismatches. Only do this if its guranteed the ++ work is not wasted. ++ 5. If size is 8 * VEC_SIZE or less, unroll the loop. ++ 6. Compare 4 * VEC_SIZE at a time with the aligned first memory + area. +- 6. Use 2 vector compares when size is 2 * VEC_SIZE or less. +- 7. Use 4 vector compares when size is 4 * VEC_SIZE or less. +- 8. Use 8 vector compares when size is 8 * VEC_SIZE or less. */ ++ 7. Use 2 vector compares when size is 2 * CHAR_PER_VEC or less. ++ 8. Use 4 vector compares when size is 4 * CHAR_PER_VEC or less. ++ 9. Use 8 vector compares when size is 8 * CHAR_PER_VEC or less. */ + + # include + +@@ -40,11 +45,21 @@ + # define VMOVU vmovdqu64 + + # ifdef USE_AS_WMEMCMP +-# define VPCMPEQ vpcmpeqd ++# define CHAR_SIZE 4 ++# define VPCMP vpcmpd + # else +-# define VPCMPEQ vpcmpeqb ++# define CHAR_SIZE 1 ++# define VPCMP vpcmpub + # endif + ++# define VEC_SIZE 32 ++# define PAGE_SIZE 4096 ++# define CHAR_PER_VEC (VEC_SIZE / CHAR_SIZE) ++ ++# define XMM0 xmm16 ++# define XMM1 xmm17 ++# define XMM2 xmm18 ++# define YMM0 ymm16 + # define XMM1 xmm17 + # define XMM2 xmm18 + # define YMM1 ymm17 +@@ -54,15 +69,6 @@ + # define YMM5 ymm21 + # define YMM6 ymm22 + +-# define VEC_SIZE 32 +-# ifdef USE_AS_WMEMCMP +-# define VEC_MASK 0xff +-# define XMM_MASK 0xf +-# else +-# define VEC_MASK 0xffffffff +-# define XMM_MASK 0xffff +-# endif +- + /* Warning! + wmemcmp has to use SIGNED comparison for elements. + memcmp has to use UNSIGNED comparison for elemnts. +@@ -70,145 +76,370 @@ + + .section .text.evex,"ax",@progbits + ENTRY (MEMCMP) +-# ifdef USE_AS_WMEMCMP +- shl $2, %RDX_LP +-# elif defined __ILP32__ ++# ifdef __ILP32__ + /* Clear the upper 32 bits. */ + movl %edx, %edx + # endif +- cmp $VEC_SIZE, %RDX_LP ++ cmp $CHAR_PER_VEC, %RDX_LP + jb L(less_vec) + + /* From VEC to 2 * VEC. No branch when size == VEC_SIZE. */ +- VMOVU (%rsi), %YMM2 +- VPCMPEQ (%rdi), %YMM2, %k1 ++ VMOVU (%rsi), %YMM1 ++ /* Use compare not equals to directly check for mismatch. */ ++ VPCMP $4, (%rdi), %YMM1, %k1 + kmovd %k1, %eax +- subl $VEC_MASK, %eax +- jnz L(first_vec) +- +- cmpq $(VEC_SIZE * 2), %rdx +- jbe L(last_vec) +- +- /* More than 2 * VEC. */ +- cmpq $(VEC_SIZE * 8), %rdx +- ja L(more_8x_vec) +- cmpq $(VEC_SIZE * 4), %rdx +- jb L(last_4x_vec) ++ /* NB: eax must be destination register if going to ++ L(return_vec_[0,2]). For L(return_vec_3 destination register ++ must be ecx. */ ++ testl %eax, %eax ++ jnz L(return_vec_0) + +- /* From 4 * VEC to 8 * VEC, inclusively. */ +- VMOVU (%rsi), %YMM1 +- VPCMPEQ (%rdi), %YMM1, %k1 ++ cmpq $(CHAR_PER_VEC * 2), %rdx ++ jbe L(last_1x_vec) + ++ /* Check second VEC no matter what. */ + VMOVU VEC_SIZE(%rsi), %YMM2 +- VPCMPEQ VEC_SIZE(%rdi), %YMM2, %k2 ++ VPCMP $4, VEC_SIZE(%rdi), %YMM2, %k1 ++ kmovd %k1, %eax ++ testl %eax, %eax ++ jnz L(return_vec_1) ++ ++ /* Less than 4 * VEC. */ ++ cmpq $(CHAR_PER_VEC * 4), %rdx ++ jbe L(last_2x_vec) + ++ /* Check third and fourth VEC no matter what. */ + VMOVU (VEC_SIZE * 2)(%rsi), %YMM3 +- VPCMPEQ (VEC_SIZE * 2)(%rdi), %YMM3, %k3 ++ VPCMP $4, (VEC_SIZE * 2)(%rdi), %YMM3, %k1 ++ kmovd %k1, %eax ++ testl %eax, %eax ++ jnz L(return_vec_2) + + VMOVU (VEC_SIZE * 3)(%rsi), %YMM4 +- VPCMPEQ (VEC_SIZE * 3)(%rdi), %YMM4, %k4 ++ VPCMP $4, (VEC_SIZE * 3)(%rdi), %YMM4, %k1 ++ kmovd %k1, %ecx ++ testl %ecx, %ecx ++ jnz L(return_vec_3) + +- kandd %k1, %k2, %k5 +- kandd %k3, %k4, %k6 +- kandd %k5, %k6, %k6 ++ /* Zero YMM0. 4x VEC reduction is done with vpxor + vtern so ++ compare with zero to get a mask is needed. */ ++ vpxorq %XMM0, %XMM0, %XMM0 + +- kmovd %k6, %eax +- cmpl $VEC_MASK, %eax +- jne L(4x_vec_end) ++ /* Go to 4x VEC loop. */ ++ cmpq $(CHAR_PER_VEC * 8), %rdx ++ ja L(more_8x_vec) + +- leaq -(4 * VEC_SIZE)(%rdi, %rdx), %rdi +- leaq -(4 * VEC_SIZE)(%rsi, %rdx), %rsi +- VMOVU (%rsi), %YMM1 +- VPCMPEQ (%rdi), %YMM1, %k1 ++ /* Handle remainder of size = 4 * VEC + 1 to 8 * VEC without any ++ branches. */ + +- VMOVU VEC_SIZE(%rsi), %YMM2 +- VPCMPEQ VEC_SIZE(%rdi), %YMM2, %k2 +- kandd %k1, %k2, %k5 ++ /* Load first two VEC from s2 before adjusting addresses. */ ++ VMOVU -(VEC_SIZE * 4)(%rsi, %rdx, CHAR_SIZE), %YMM1 ++ VMOVU -(VEC_SIZE * 3)(%rsi, %rdx, CHAR_SIZE), %YMM2 ++ leaq -(4 * VEC_SIZE)(%rdi, %rdx, CHAR_SIZE), %rdi ++ leaq -(4 * VEC_SIZE)(%rsi, %rdx, CHAR_SIZE), %rsi ++ ++ /* Wait to load from s1 until addressed adjust due to ++ unlamination of microfusion with complex address mode. */ ++ ++ /* vpxor will be all 0s if s1 and s2 are equal. Otherwise it ++ will have some 1s. */ ++ vpxorq (%rdi), %YMM1, %YMM1 ++ vpxorq (VEC_SIZE)(%rdi), %YMM2, %YMM2 + + VMOVU (VEC_SIZE * 2)(%rsi), %YMM3 +- VPCMPEQ (VEC_SIZE * 2)(%rdi), %YMM3, %k3 +- kandd %k3, %k5, %k5 ++ vpxorq (VEC_SIZE * 2)(%rdi), %YMM3, %YMM3 ++ /* Or together YMM1, YMM2, and YMM3 into YMM3. */ ++ vpternlogd $0xfe, %YMM1, %YMM2, %YMM3 + + VMOVU (VEC_SIZE * 3)(%rsi), %YMM4 +- VPCMPEQ (VEC_SIZE * 3)(%rdi), %YMM4, %k4 +- kandd %k4, %k5, %k5 ++ /* Ternary logic to xor (VEC_SIZE * 3)(%rdi) with YMM4 while ++ oring with YMM3. Result is stored in YMM4. */ ++ vpternlogd $0xde, (VEC_SIZE * 3)(%rdi), %YMM3, %YMM4 ++ /* Compare YMM4 with 0. If any 1s s1 and s2 don't match. */ ++ VPCMP $4, %YMM4, %YMM0, %k1 ++ kmovd %k1, %ecx ++ testl %ecx, %ecx ++ jnz L(return_vec_0_1_2_3) ++ /* NB: eax must be zero to reach here. */ ++ ret + +- kmovd %k5, %eax +- cmpl $VEC_MASK, %eax +- jne L(4x_vec_end) +- xorl %eax, %eax ++ /* NB: aligning 32 here allows for the rest of the jump targets ++ to be tuned for 32 byte alignment. Most important this ensures ++ the L(more_8x_vec) loop is 32 byte aligned. */ ++ .p2align 5 ++L(less_vec): ++ /* Check if one or less CHAR. This is necessary for size = 0 but ++ is also faster for size = CHAR_SIZE. */ ++ cmpl $1, %edx ++ jbe L(one_or_less) ++ ++ /* Check if loading one VEC from either s1 or s2 could cause a ++ page cross. This can have false positives but is by far the ++ fastest method. */ ++ movl %edi, %eax ++ orl %esi, %eax ++ andl $(PAGE_SIZE - 1), %eax ++ cmpl $(PAGE_SIZE - VEC_SIZE), %eax ++ jg L(page_cross_less_vec) ++ ++ /* No page cross possible. */ ++ VMOVU (%rsi), %YMM2 ++ VPCMP $4, (%rdi), %YMM2, %k1 ++ kmovd %k1, %eax ++ /* Create mask in ecx for potentially in bound matches. */ ++ bzhil %edx, %eax, %eax ++ jnz L(return_vec_0) + ret + + .p2align 4 +-L(last_2x_vec): +- /* From VEC to 2 * VEC. No branch when size == VEC_SIZE. */ +- VMOVU (%rsi), %YMM2 +- VPCMPEQ (%rdi), %YMM2, %k2 +- kmovd %k2, %eax +- subl $VEC_MASK, %eax +- jnz L(first_vec) ++L(return_vec_0): ++ tzcntl %eax, %eax ++# ifdef USE_AS_WMEMCMP ++ movl (%rdi, %rax, CHAR_SIZE), %ecx ++ xorl %edx, %edx ++ cmpl (%rsi, %rax, CHAR_SIZE), %ecx ++ /* NB: no partial register stall here because xorl zero idiom ++ above. */ ++ setg %dl ++ leal -1(%rdx, %rdx), %eax ++# else ++ movzbl (%rsi, %rax), %ecx ++ movzbl (%rdi, %rax), %eax ++ subl %ecx, %eax ++# endif ++ ret + +-L(last_vec): +- /* Use overlapping loads to avoid branches. */ +- leaq -VEC_SIZE(%rdi, %rdx), %rdi +- leaq -VEC_SIZE(%rsi, %rdx), %rsi +- VMOVU (%rsi), %YMM2 +- VPCMPEQ (%rdi), %YMM2, %k2 +- kmovd %k2, %eax +- subl $VEC_MASK, %eax +- jnz L(first_vec) ++ /* NB: No p2align necessary. Alignment % 16 is naturally 1 ++ which is good enough for a target not in a loop. */ ++L(return_vec_1): ++ tzcntl %eax, %eax ++# ifdef USE_AS_WMEMCMP ++ movl VEC_SIZE(%rdi, %rax, CHAR_SIZE), %ecx ++ xorl %edx, %edx ++ cmpl VEC_SIZE(%rsi, %rax, CHAR_SIZE), %ecx ++ setg %dl ++ leal -1(%rdx, %rdx), %eax ++# else ++ movzbl VEC_SIZE(%rsi, %rax), %ecx ++ movzbl VEC_SIZE(%rdi, %rax), %eax ++ subl %ecx, %eax ++# endif + ret + +- .p2align 4 +-L(first_vec): +- /* A byte or int32 is different within 16 or 32 bytes. */ +- tzcntl %eax, %ecx ++ /* NB: No p2align necessary. Alignment % 16 is naturally 2 ++ which is good enough for a target not in a loop. */ ++L(return_vec_2): ++ tzcntl %eax, %eax + # ifdef USE_AS_WMEMCMP +- xorl %eax, %eax +- movl (%rdi, %rcx, 4), %edx +- cmpl (%rsi, %rcx, 4), %edx +-L(wmemcmp_return): +- setl %al +- negl %eax +- orl $1, %eax ++ movl (VEC_SIZE * 2)(%rdi, %rax, CHAR_SIZE), %ecx ++ xorl %edx, %edx ++ cmpl (VEC_SIZE * 2)(%rsi, %rax, CHAR_SIZE), %ecx ++ setg %dl ++ leal -1(%rdx, %rdx), %eax + # else +- movzbl (%rdi, %rcx), %eax +- movzbl (%rsi, %rcx), %edx +- sub %edx, %eax ++ movzbl (VEC_SIZE * 2)(%rsi, %rax), %ecx ++ movzbl (VEC_SIZE * 2)(%rdi, %rax), %eax ++ subl %ecx, %eax + # endif + ret + ++ .p2align 4 ++L(8x_return_vec_0_1_2_3): ++ /* Returning from L(more_8x_vec) requires restoring rsi. */ ++ addq %rdi, %rsi ++L(return_vec_0_1_2_3): ++ VPCMP $4, %YMM1, %YMM0, %k0 ++ kmovd %k0, %eax ++ testl %eax, %eax ++ jnz L(return_vec_0) ++ ++ VPCMP $4, %YMM2, %YMM0, %k0 ++ kmovd %k0, %eax ++ testl %eax, %eax ++ jnz L(return_vec_1) ++ ++ VPCMP $4, %YMM3, %YMM0, %k0 ++ kmovd %k0, %eax ++ testl %eax, %eax ++ jnz L(return_vec_2) ++L(return_vec_3): ++ tzcntl %ecx, %ecx + # ifdef USE_AS_WMEMCMP ++ movl (VEC_SIZE * 3)(%rdi, %rcx, CHAR_SIZE), %eax ++ xorl %edx, %edx ++ cmpl (VEC_SIZE * 3)(%rsi, %rcx, CHAR_SIZE), %eax ++ setg %dl ++ leal -1(%rdx, %rdx), %eax ++# else ++ movzbl (VEC_SIZE * 3)(%rdi, %rcx), %eax ++ movzbl (VEC_SIZE * 3)(%rsi, %rcx), %ecx ++ subl %ecx, %eax ++# endif ++ ret ++ + .p2align 4 +-L(4): +- xorl %eax, %eax +- movl (%rdi), %edx +- cmpl (%rsi), %edx +- jne L(wmemcmp_return) ++L(more_8x_vec): ++ /* Set end of s1 in rdx. */ ++ leaq -(VEC_SIZE * 4)(%rdi, %rdx, CHAR_SIZE), %rdx ++ /* rsi stores s2 - s1. This allows loop to only update one ++ pointer. */ ++ subq %rdi, %rsi ++ /* Align s1 pointer. */ ++ andq $-VEC_SIZE, %rdi ++ /* Adjust because first 4x vec where check already. */ ++ subq $-(VEC_SIZE * 4), %rdi ++ .p2align 4 ++L(loop_4x_vec): ++ VMOVU (%rsi, %rdi), %YMM1 ++ vpxorq (%rdi), %YMM1, %YMM1 ++ ++ VMOVU VEC_SIZE(%rsi, %rdi), %YMM2 ++ vpxorq VEC_SIZE(%rdi), %YMM2, %YMM2 ++ ++ VMOVU (VEC_SIZE * 2)(%rsi, %rdi), %YMM3 ++ vpxorq (VEC_SIZE * 2)(%rdi), %YMM3, %YMM3 ++ vpternlogd $0xfe, %YMM1, %YMM2, %YMM3 ++ ++ VMOVU (VEC_SIZE * 3)(%rsi, %rdi), %YMM4 ++ vpternlogd $0xde, (VEC_SIZE * 3)(%rdi), %YMM3, %YMM4 ++ VPCMP $4, %YMM4, %YMM0, %k1 ++ kmovd %k1, %ecx ++ testl %ecx, %ecx ++ jnz L(8x_return_vec_0_1_2_3) ++ subq $-(VEC_SIZE * 4), %rdi ++ cmpq %rdx, %rdi ++ jb L(loop_4x_vec) ++ ++ subq %rdx, %rdi ++ /* rdi has 4 * VEC_SIZE - remaining length. */ ++ cmpl $(VEC_SIZE * 3), %edi ++ jae L(8x_last_1x_vec) ++ /* Load regardless of branch. */ ++ VMOVU (VEC_SIZE * 2)(%rsi, %rdx), %YMM3 ++ cmpl $(VEC_SIZE * 2), %edi ++ jae L(8x_last_2x_vec) ++ ++ VMOVU (%rsi, %rdx), %YMM1 ++ vpxorq (%rdx), %YMM1, %YMM1 ++ ++ VMOVU VEC_SIZE(%rsi, %rdx), %YMM2 ++ vpxorq VEC_SIZE(%rdx), %YMM2, %YMM2 ++ ++ vpxorq (VEC_SIZE * 2)(%rdx), %YMM3, %YMM3 ++ vpternlogd $0xfe, %YMM1, %YMM2, %YMM3 ++ ++ VMOVU (VEC_SIZE * 3)(%rsi, %rdx), %YMM4 ++ vpternlogd $0xde, (VEC_SIZE * 3)(%rdx), %YMM3, %YMM4 ++ VPCMP $4, %YMM4, %YMM0, %k1 ++ kmovd %k1, %ecx ++ /* Restore s1 pointer to rdi. */ ++ movq %rdx, %rdi ++ testl %ecx, %ecx ++ jnz L(8x_return_vec_0_1_2_3) ++ /* NB: eax must be zero to reach here. */ ++ ret ++ ++ /* Only entry is from L(more_8x_vec). */ ++ .p2align 4 ++L(8x_last_2x_vec): ++ VPCMP $4, (VEC_SIZE * 2)(%rdx), %YMM3, %k1 ++ kmovd %k1, %eax ++ testl %eax, %eax ++ jnz L(8x_return_vec_2) ++ /* Naturally aligned to 16 bytes. */ ++L(8x_last_1x_vec): ++ VMOVU (VEC_SIZE * 3)(%rsi, %rdx), %YMM1 ++ VPCMP $4, (VEC_SIZE * 3)(%rdx), %YMM1, %k1 ++ kmovd %k1, %eax ++ testl %eax, %eax ++ jnz L(8x_return_vec_3) ++ ret ++ ++ .p2align 4 ++L(last_2x_vec): ++ /* Check second to last VEC. */ ++ VMOVU -(VEC_SIZE * 2)(%rsi, %rdx, CHAR_SIZE), %YMM1 ++ VPCMP $4, -(VEC_SIZE * 2)(%rdi, %rdx, CHAR_SIZE), %YMM1, %k1 ++ kmovd %k1, %eax ++ testl %eax, %eax ++ jnz L(return_vec_1_end) ++ ++ /* Check last VEC. */ ++ .p2align 4 ++L(last_1x_vec): ++ VMOVU -(VEC_SIZE * 1)(%rsi, %rdx, CHAR_SIZE), %YMM1 ++ VPCMP $4, -(VEC_SIZE * 1)(%rdi, %rdx, CHAR_SIZE), %YMM1, %k1 ++ kmovd %k1, %eax ++ testl %eax, %eax ++ jnz L(return_vec_0_end) + ret ++ ++ .p2align 4 ++L(8x_return_vec_2): ++ subq $VEC_SIZE, %rdx ++L(8x_return_vec_3): ++ tzcntl %eax, %eax ++# ifdef USE_AS_WMEMCMP ++ leaq (%rdx, %rax, CHAR_SIZE), %rax ++ movl (VEC_SIZE * 3)(%rax), %ecx ++ xorl %edx, %edx ++ cmpl (VEC_SIZE * 3)(%rsi, %rax), %ecx ++ setg %dl ++ leal -1(%rdx, %rdx), %eax + # else ++ addq %rdx, %rax ++ movzbl (VEC_SIZE * 3)(%rsi, %rax), %ecx ++ movzbl (VEC_SIZE * 3)(%rax), %eax ++ subl %ecx, %eax ++# endif ++ ret ++ + .p2align 4 +-L(between_4_7): +- /* Load as big endian with overlapping movbe to avoid branches. */ +- movbe (%rdi), %eax +- movbe (%rsi), %ecx +- shlq $32, %rax +- shlq $32, %rcx +- movbe -4(%rdi, %rdx), %edi +- movbe -4(%rsi, %rdx), %esi +- orq %rdi, %rax +- orq %rsi, %rcx +- subq %rcx, %rax +- je L(exit) +- sbbl %eax, %eax +- orl $1, %eax ++L(return_vec_0_end): ++ tzcntl %eax, %eax ++ addl %edx, %eax ++# ifdef USE_AS_WMEMCMP ++ movl -VEC_SIZE(%rdi, %rax, CHAR_SIZE), %ecx ++ xorl %edx, %edx ++ cmpl -VEC_SIZE(%rsi, %rax, CHAR_SIZE), %ecx ++ setg %dl ++ leal -1(%rdx, %rdx), %eax ++# else ++ movzbl -VEC_SIZE(%rsi, %rax), %ecx ++ movzbl -VEC_SIZE(%rdi, %rax), %eax ++ subl %ecx, %eax ++# endif + ret + + .p2align 4 +-L(exit): ++L(return_vec_1_end): ++ tzcntl %eax, %eax ++ addl %edx, %eax ++# ifdef USE_AS_WMEMCMP ++ movl -(VEC_SIZE * 2)(%rdi, %rax, CHAR_SIZE), %ecx ++ xorl %edx, %edx ++ cmpl -(VEC_SIZE * 2)(%rsi, %rax, CHAR_SIZE), %ecx ++ setg %dl ++ leal -1(%rdx, %rdx), %eax ++# else ++ movzbl -(VEC_SIZE * 2)(%rsi, %rax), %ecx ++ movzbl -(VEC_SIZE * 2)(%rdi, %rax), %eax ++ subl %ecx, %eax ++# endif + ret + ++ + .p2align 4 ++L(page_cross_less_vec): ++ /* if USE_AS_WMEMCMP it can only be 0, 4, 8, 12, 16, 20, 24, 28 ++ bytes. */ ++ cmpl $(16 / CHAR_SIZE), %edx ++ jae L(between_16_31) ++# ifndef USE_AS_WMEMCMP ++ cmpl $8, %edx ++ jae L(between_8_15) ++ cmpl $4, %edx ++ jae L(between_4_7) + L(between_2_3): + /* Load as big endian to avoid branches. */ + movzwl (%rdi), %eax +@@ -217,224 +448,99 @@ L(between_2_3): + shll $8, %ecx + bswap %eax + bswap %ecx +- movb -1(%rdi, %rdx), %al +- movb -1(%rsi, %rdx), %cl ++ movzbl -1(%rdi, %rdx), %edi ++ movzbl -1(%rsi, %rdx), %esi ++ orl %edi, %eax ++ orl %esi, %ecx + /* Subtraction is okay because the upper 8 bits are zero. */ + subl %ecx, %eax + ret +- + .p2align 4 +-L(1): +- movzbl (%rdi), %eax ++L(one_or_less): ++ jb L(zero) + movzbl (%rsi), %ecx ++ movzbl (%rdi), %eax + subl %ecx, %eax + ret +-# endif +- +- .p2align 4 +-L(zero): +- xorl %eax, %eax +- ret + + .p2align 4 +-L(less_vec): +-# ifdef USE_AS_WMEMCMP +- /* It can only be 0, 4, 8, 12, 16, 20, 24, 28 bytes. */ +- cmpb $4, %dl +- je L(4) +- jb L(zero) +-# else +- cmpb $1, %dl +- je L(1) +- jb L(zero) +- cmpb $4, %dl +- jb L(between_2_3) +- cmpb $8, %dl +- jb L(between_4_7) ++L(between_8_15): + # endif +- cmpb $16, %dl +- jae L(between_16_31) +- /* It is between 8 and 15 bytes. */ ++ /* If USE_AS_WMEMCMP fall through into 8-15 byte case. */ + vmovq (%rdi), %XMM1 + vmovq (%rsi), %XMM2 +- VPCMPEQ %XMM1, %XMM2, %k2 +- kmovw %k2, %eax +- subl $XMM_MASK, %eax +- jnz L(first_vec) ++ VPCMP $4, %XMM1, %XMM2, %k1 ++ kmovd %k1, %eax ++ testl %eax, %eax ++ jnz L(return_vec_0) + /* Use overlapping loads to avoid branches. */ +- leaq -8(%rdi, %rdx), %rdi +- leaq -8(%rsi, %rdx), %rsi ++ leaq -8(%rdi, %rdx, CHAR_SIZE), %rdi ++ leaq -8(%rsi, %rdx, CHAR_SIZE), %rsi + vmovq (%rdi), %XMM1 + vmovq (%rsi), %XMM2 +- VPCMPEQ %XMM1, %XMM2, %k2 +- kmovw %k2, %eax +- subl $XMM_MASK, %eax +- jnz L(first_vec) ++ VPCMP $4, %XMM1, %XMM2, %k1 ++ kmovd %k1, %eax ++ testl %eax, %eax ++ jnz L(return_vec_0) + ret + + .p2align 4 +-L(between_16_31): +- /* From 16 to 31 bytes. No branch when size == 16. */ +- VMOVU (%rsi), %XMM2 +- VPCMPEQ (%rdi), %XMM2, %k2 +- kmovw %k2, %eax +- subl $XMM_MASK, %eax +- jnz L(first_vec) +- +- /* Use overlapping loads to avoid branches. */ +- leaq -16(%rdi, %rdx), %rdi +- leaq -16(%rsi, %rdx), %rsi +- VMOVU (%rsi), %XMM2 +- VPCMPEQ (%rdi), %XMM2, %k2 +- kmovw %k2, %eax +- subl $XMM_MASK, %eax +- jnz L(first_vec) ++L(zero): ++ xorl %eax, %eax + ret + + .p2align 4 +-L(more_8x_vec): +- /* More than 8 * VEC. Check the first VEC. */ +- VMOVU (%rsi), %YMM2 +- VPCMPEQ (%rdi), %YMM2, %k2 +- kmovd %k2, %eax +- subl $VEC_MASK, %eax +- jnz L(first_vec) +- +- /* Align the first memory area for aligned loads in the loop. +- Compute how much the first memory area is misaligned. */ +- movq %rdi, %rcx +- andl $(VEC_SIZE - 1), %ecx +- /* Get the negative of offset for alignment. */ +- subq $VEC_SIZE, %rcx +- /* Adjust the second memory area. */ +- subq %rcx, %rsi +- /* Adjust the first memory area which should be aligned now. */ +- subq %rcx, %rdi +- /* Adjust length. */ +- addq %rcx, %rdx +- +-L(loop_4x_vec): +- /* Compare 4 * VEC at a time forward. */ +- VMOVU (%rsi), %YMM1 +- VPCMPEQ (%rdi), %YMM1, %k1 +- +- VMOVU VEC_SIZE(%rsi), %YMM2 +- VPCMPEQ VEC_SIZE(%rdi), %YMM2, %k2 +- kandd %k2, %k1, %k5 +- +- VMOVU (VEC_SIZE * 2)(%rsi), %YMM3 +- VPCMPEQ (VEC_SIZE * 2)(%rdi), %YMM3, %k3 +- kandd %k3, %k5, %k5 +- +- VMOVU (VEC_SIZE * 3)(%rsi), %YMM4 +- VPCMPEQ (VEC_SIZE * 3)(%rdi), %YMM4, %k4 +- kandd %k4, %k5, %k5 +- +- kmovd %k5, %eax +- cmpl $VEC_MASK, %eax +- jne L(4x_vec_end) +- +- addq $(VEC_SIZE * 4), %rdi +- addq $(VEC_SIZE * 4), %rsi +- +- subq $(VEC_SIZE * 4), %rdx +- cmpq $(VEC_SIZE * 4), %rdx +- jae L(loop_4x_vec) +- +- /* Less than 4 * VEC. */ +- cmpq $VEC_SIZE, %rdx +- jbe L(last_vec) +- cmpq $(VEC_SIZE * 2), %rdx +- jbe L(last_2x_vec) +- +-L(last_4x_vec): +- /* From 2 * VEC to 4 * VEC. */ +- VMOVU (%rsi), %YMM2 +- VPCMPEQ (%rdi), %YMM2, %k2 +- kmovd %k2, %eax +- subl $VEC_MASK, %eax +- jnz L(first_vec) +- +- addq $VEC_SIZE, %rdi +- addq $VEC_SIZE, %rsi +- VMOVU (%rsi), %YMM2 +- VPCMPEQ (%rdi), %YMM2, %k2 +- kmovd %k2, %eax +- subl $VEC_MASK, %eax +- jnz L(first_vec) ++L(between_16_31): ++ /* From 16 to 31 bytes. No branch when size == 16. */ ++ VMOVU (%rsi), %XMM2 ++ VPCMP $4, (%rdi), %XMM2, %k1 ++ kmovd %k1, %eax ++ testl %eax, %eax ++ jnz L(return_vec_0) + + /* Use overlapping loads to avoid branches. */ +- leaq -(3 * VEC_SIZE)(%rdi, %rdx), %rdi +- leaq -(3 * VEC_SIZE)(%rsi, %rdx), %rsi +- VMOVU (%rsi), %YMM2 +- VPCMPEQ (%rdi), %YMM2, %k2 +- kmovd %k2, %eax +- subl $VEC_MASK, %eax +- jnz L(first_vec) + +- addq $VEC_SIZE, %rdi +- addq $VEC_SIZE, %rsi +- VMOVU (%rsi), %YMM2 +- VPCMPEQ (%rdi), %YMM2, %k2 +- kmovd %k2, %eax +- subl $VEC_MASK, %eax +- jnz L(first_vec) +- ret +- +- .p2align 4 +-L(4x_vec_end): ++ VMOVU -16(%rsi, %rdx, CHAR_SIZE), %XMM2 ++ leaq -16(%rdi, %rdx, CHAR_SIZE), %rdi ++ leaq -16(%rsi, %rdx, CHAR_SIZE), %rsi ++ VPCMP $4, (%rdi), %XMM2, %k1 + kmovd %k1, %eax +- subl $VEC_MASK, %eax +- jnz L(first_vec) +- kmovd %k2, %eax +- subl $VEC_MASK, %eax +- jnz L(first_vec_x1) +- kmovd %k3, %eax +- subl $VEC_MASK, %eax +- jnz L(first_vec_x2) +- kmovd %k4, %eax +- subl $VEC_MASK, %eax +- tzcntl %eax, %ecx +-# ifdef USE_AS_WMEMCMP +- xorl %eax, %eax +- movl (VEC_SIZE * 3)(%rdi, %rcx, 4), %edx +- cmpl (VEC_SIZE * 3)(%rsi, %rcx, 4), %edx +- jmp L(wmemcmp_return) +-# else +- movzbl (VEC_SIZE * 3)(%rdi, %rcx), %eax +- movzbl (VEC_SIZE * 3)(%rsi, %rcx), %edx +- sub %edx, %eax +-# endif ++ testl %eax, %eax ++ jnz L(return_vec_0) + ret + +- .p2align 4 +-L(first_vec_x1): +- tzcntl %eax, %ecx + # ifdef USE_AS_WMEMCMP +- xorl %eax, %eax +- movl VEC_SIZE(%rdi, %rcx, 4), %edx +- cmpl VEC_SIZE(%rsi, %rcx, 4), %edx +- jmp L(wmemcmp_return) +-# else +- movzbl VEC_SIZE(%rdi, %rcx), %eax +- movzbl VEC_SIZE(%rsi, %rcx), %edx +- sub %edx, %eax +-# endif ++ .p2align 4 ++L(one_or_less): ++ jb L(zero) ++ movl (%rdi), %ecx ++ xorl %edx, %edx ++ cmpl (%rsi), %ecx ++ je L(zero) ++ setg %dl ++ leal -1(%rdx, %rdx), %eax + ret ++# else + + .p2align 4 +-L(first_vec_x2): +- tzcntl %eax, %ecx +-# ifdef USE_AS_WMEMCMP +- xorl %eax, %eax +- movl (VEC_SIZE * 2)(%rdi, %rcx, 4), %edx +- cmpl (VEC_SIZE * 2)(%rsi, %rcx, 4), %edx +- jmp L(wmemcmp_return) +-# else +- movzbl (VEC_SIZE * 2)(%rdi, %rcx), %eax +- movzbl (VEC_SIZE * 2)(%rsi, %rcx), %edx +- sub %edx, %eax +-# endif ++L(between_4_7): ++ /* Load as big endian with overlapping movbe to avoid branches. ++ */ ++ movbe (%rdi), %eax ++ movbe (%rsi), %ecx ++ shlq $32, %rax ++ shlq $32, %rcx ++ movbe -4(%rdi, %rdx), %edi ++ movbe -4(%rsi, %rdx), %esi ++ orq %rdi, %rax ++ orq %rsi, %rcx ++ subq %rcx, %rax ++ jz L(zero_4_7) ++ sbbl %eax, %eax ++ orl $1, %eax ++L(zero_4_7): + ret ++# endif ++ + END (MEMCMP) + #endif +-- +GitLab + diff --git a/SOURCES/glibc-RHEL-15696-47.patch b/SOURCES/glibc-RHEL-15696-47.patch new file mode 100644 index 0000000..70c3171 --- /dev/null +++ b/SOURCES/glibc-RHEL-15696-47.patch @@ -0,0 +1,104 @@ +From 6abf27980a947f9b6e514d6b33b83059d39566ae Mon Sep 17 00:00:00 2001 +From: Noah Goldstein +Date: Thu, 20 May 2021 13:13:51 -0400 +Subject: [PATCH] x86: Improve memset-vec-unaligned-erms.S +Content-type: text/plain; charset=UTF-8 + +No bug. This commit makes a few small improvements to +memset-vec-unaligned-erms.S. The changes are 1) only aligning to 64 +instead of 128. Either alignment will perform equally well in a loop +and 128 just increases the odds of having to do an extra iteration +which can be significant overhead for small values. 2) Align some +targets and the loop. 3) Remove an ALU from the alignment process. 4) +Reorder the last 4x VEC so that they are stored after the loop. 5) +Move the condition for leq 8x VEC to before the alignment +process. test-memset and test-wmemset are both passing. + +Signed-off-by: Noah Goldstein +Reviewed-by: H.J. Lu +--- + .../multiarch/memset-vec-unaligned-erms.S | 50 +++++++++++-------- + 1 file changed, 28 insertions(+), 22 deletions(-) + +diff --git a/sysdeps/x86_64/multiarch/memset-vec-unaligned-erms.S b/sysdeps/x86_64/multiarch/memset-vec-unaligned-erms.S +index f877ac9d..909c33f6 100644 +--- a/sysdeps/x86_64/multiarch/memset-vec-unaligned-erms.S ++++ b/sysdeps/x86_64/multiarch/memset-vec-unaligned-erms.S +@@ -173,17 +173,22 @@ ENTRY (MEMSET_SYMBOL (__memset, unaligned_erms)) + VMOVU %VEC(0), (%rdi) + VZEROUPPER_RETURN + ++ .p2align 4 + L(stosb_more_2x_vec): + cmp __x86_rep_stosb_threshold(%rip), %RDX_LP + ja L(stosb) ++#else ++ .p2align 4 + #endif + L(more_2x_vec): +- cmpq $(VEC_SIZE * 4), %rdx +- ja L(loop_start) ++ /* Stores to first 2x VEC before cmp as any path forward will ++ require it. */ + VMOVU %VEC(0), (%rdi) + VMOVU %VEC(0), VEC_SIZE(%rdi) +- VMOVU %VEC(0), -VEC_SIZE(%rdi,%rdx) ++ cmpq $(VEC_SIZE * 4), %rdx ++ ja L(loop_start) + VMOVU %VEC(0), -(VEC_SIZE * 2)(%rdi,%rdx) ++ VMOVU %VEC(0), -VEC_SIZE(%rdi,%rdx) + L(return): + #if VEC_SIZE > 16 + ZERO_UPPER_VEC_REGISTERS_RETURN +@@ -192,28 +197,29 @@ L(return): + #endif + + L(loop_start): +- leaq (VEC_SIZE * 4)(%rdi), %rcx +- VMOVU %VEC(0), (%rdi) +- andq $-(VEC_SIZE * 4), %rcx +- VMOVU %VEC(0), -VEC_SIZE(%rdi,%rdx) +- VMOVU %VEC(0), VEC_SIZE(%rdi) +- VMOVU %VEC(0), -(VEC_SIZE * 2)(%rdi,%rdx) + VMOVU %VEC(0), (VEC_SIZE * 2)(%rdi) +- VMOVU %VEC(0), -(VEC_SIZE * 3)(%rdi,%rdx) + VMOVU %VEC(0), (VEC_SIZE * 3)(%rdi) +- VMOVU %VEC(0), -(VEC_SIZE * 4)(%rdi,%rdx) +- addq %rdi, %rdx +- andq $-(VEC_SIZE * 4), %rdx +- cmpq %rdx, %rcx +- je L(return) ++ cmpq $(VEC_SIZE * 8), %rdx ++ jbe L(loop_end) ++ andq $-(VEC_SIZE * 2), %rdi ++ subq $-(VEC_SIZE * 4), %rdi ++ leaq -(VEC_SIZE * 4)(%rax, %rdx), %rcx ++ .p2align 4 + L(loop): +- VMOVA %VEC(0), (%rcx) +- VMOVA %VEC(0), VEC_SIZE(%rcx) +- VMOVA %VEC(0), (VEC_SIZE * 2)(%rcx) +- VMOVA %VEC(0), (VEC_SIZE * 3)(%rcx) +- addq $(VEC_SIZE * 4), %rcx +- cmpq %rcx, %rdx +- jne L(loop) ++ VMOVA %VEC(0), (%rdi) ++ VMOVA %VEC(0), VEC_SIZE(%rdi) ++ VMOVA %VEC(0), (VEC_SIZE * 2)(%rdi) ++ VMOVA %VEC(0), (VEC_SIZE * 3)(%rdi) ++ subq $-(VEC_SIZE * 4), %rdi ++ cmpq %rcx, %rdi ++ jb L(loop) ++L(loop_end): ++ /* NB: rax is set as ptr in MEMSET_VDUP_TO_VEC0_AND_SET_RETURN. ++ rdx as length is also unchanged. */ ++ VMOVU %VEC(0), -(VEC_SIZE * 4)(%rax, %rdx) ++ VMOVU %VEC(0), -(VEC_SIZE * 3)(%rax, %rdx) ++ VMOVU %VEC(0), -(VEC_SIZE * 2)(%rax, %rdx) ++ VMOVU %VEC(0), -VEC_SIZE(%rax, %rdx) + VZEROUPPER_SHORT_RETURN + + .p2align 4 +-- +GitLab + diff --git a/SOURCES/glibc-RHEL-15696-48.patch b/SOURCES/glibc-RHEL-15696-48.patch new file mode 100644 index 0000000..645536e --- /dev/null +++ b/SOURCES/glibc-RHEL-15696-48.patch @@ -0,0 +1,84 @@ +From 1b992204f68af851e905c16016756fd4421e1934 Mon Sep 17 00:00:00 2001 +From: Noah Goldstein +Date: Sun, 23 May 2021 19:43:24 -0400 +Subject: [PATCH] x86: Improve memmove-vec-unaligned-erms.S +Content-type: text/plain; charset=UTF-8 + +This patch changes the condition for copy 4x VEC so that if length is +exactly equal to 4 * VEC_SIZE it will use the 4x VEC case instead of +8x VEC case. + +Results For Skylake memcpy-avx2-erms +size, al1 , al2 , Cur T , New T , Win , New / Cur +128 , 0 , 0 , 9.137 , 6.873 , New , 75.22 +128 , 7 , 0 , 12.933 , 7.732 , New , 59.79 +128 , 0 , 7 , 11.852 , 6.76 , New , 57.04 +128 , 7 , 7 , 12.587 , 6.808 , New , 54.09 + +Results For Icelake memcpy-evex-erms +size, al1 , al2 , Cur T , New T , Win , New / Cur +128 , 0 , 0 , 9.963 , 5.416 , New , 54.36 +128 , 7 , 0 , 16.467 , 8.061 , New , 48.95 +128 , 0 , 7 , 14.388 , 7.644 , New , 53.13 +128 , 7 , 7 , 14.546 , 7.642 , New , 52.54 + +Results For Tigerlake memcpy-evex-erms +size, al1 , al2 , Cur T , New T , Win , New / Cur +128 , 0 , 0 , 8.979 , 4.95 , New , 55.13 +128 , 7 , 0 , 14.245 , 7.122 , New , 50.0 +128 , 0 , 7 , 12.668 , 6.675 , New , 52.69 +128 , 7 , 7 , 13.042 , 6.802 , New , 52.15 + +Results For Skylake memmove-avx2-erms +size, al1 , al2 , Cur T , New T , Win , New / Cur +128 , 0 , 32 , 6.181 , 5.691 , New , 92.07 +128 , 32 , 0 , 6.165 , 5.752 , New , 93.3 +128 , 0 , 7 , 13.923 , 9.37 , New , 67.3 +128 , 7 , 0 , 12.049 , 10.182 , New , 84.5 + +Results For Icelake memmove-evex-erms +size, al1 , al2 , Cur T , New T , Win , New / Cur +128 , 0 , 32 , 5.479 , 4.889 , New , 89.23 +128 , 32 , 0 , 5.127 , 4.911 , New , 95.79 +128 , 0 , 7 , 18.885 , 13.547 , New , 71.73 +128 , 7 , 0 , 15.565 , 14.436 , New , 92.75 + +Results For Tigerlake memmove-evex-erms +size, al1 , al2 , Cur T , New T , Win , New / Cur +128 , 0 , 32 , 5.275 , 4.815 , New , 91.28 +128 , 32 , 0 , 5.376 , 4.565 , New , 84.91 +128 , 0 , 7 , 19.426 , 14.273 , New , 73.47 +128 , 7 , 0 , 15.924 , 14.951 , New , 93.89 + +Signed-off-by: Noah Goldstein +--- + sysdeps/x86_64/multiarch/memmove-vec-unaligned-erms.S | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/sysdeps/x86_64/multiarch/memmove-vec-unaligned-erms.S b/sysdeps/x86_64/multiarch/memmove-vec-unaligned-erms.S +index 3e2dd6bc..572cef04 100644 +--- a/sysdeps/x86_64/multiarch/memmove-vec-unaligned-erms.S ++++ b/sysdeps/x86_64/multiarch/memmove-vec-unaligned-erms.S +@@ -417,8 +417,8 @@ L(more_2x_vec): + cmpq $(VEC_SIZE * 8), %rdx + ja L(more_8x_vec) + cmpq $(VEC_SIZE * 4), %rdx +- jb L(last_4x_vec) +- /* Copy from 4 * VEC to 8 * VEC, inclusively. */ ++ jbe L(last_4x_vec) ++ /* Copy from 4 * VEC + 1 to 8 * VEC, inclusively. */ + VMOVU (%rsi), %VEC(0) + VMOVU VEC_SIZE(%rsi), %VEC(1) + VMOVU (VEC_SIZE * 2)(%rsi), %VEC(2) +@@ -437,7 +437,7 @@ L(more_2x_vec): + VMOVU %VEC(7), -(VEC_SIZE * 4)(%rdi,%rdx) + VZEROUPPER_RETURN + L(last_4x_vec): +- /* Copy from 2 * VEC to 4 * VEC. */ ++ /* Copy from 2 * VEC + 1 to 4 * VEC, inclusively. */ + VMOVU (%rsi), %VEC(0) + VMOVU VEC_SIZE(%rsi), %VEC(1) + VMOVU -VEC_SIZE(%rsi,%rdx), %VEC(2) +-- +GitLab + diff --git a/SOURCES/glibc-RHEL-15696-49.patch b/SOURCES/glibc-RHEL-15696-49.patch new file mode 100644 index 0000000..b59f582 --- /dev/null +++ b/SOURCES/glibc-RHEL-15696-49.patch @@ -0,0 +1,55 @@ +From 08cbcd4dbc686bb38ec3093aff2f919fbff5ec17 Mon Sep 17 00:00:00 2001 +From: Noah Goldstein +Date: Wed, 23 Jun 2021 19:19:34 -0400 +Subject: [PATCH] x86: Remove unnecessary overflow check from wcsnlen-sse4_1.S +Content-type: text/plain; charset=UTF-8 + +No bug. The way wcsnlen will check if near the end of maxlen +is the following macro: + + mov %r11, %rsi; \ + subq %rax, %rsi; \ + andq $-64, %rax; \ + testq $-64, %rsi; \ + je L(strnlen_ret) + +Which words independently of s + maxlen overflowing. So the +second overflow check is unnecissary for correctness and +just extra overhead in the common no overflow case. + +test-strlen.c, test-wcslen.c, test-strnlen.c and test-wcsnlen.c are +all passing + +Signed-off-by: Noah Goldstein +Reviewed-by: H.J. Lu +--- + sysdeps/x86_64/multiarch/strlen-vec.S | 7 ------- + 1 file changed, 7 deletions(-) + +diff --git a/sysdeps/x86_64/multiarch/strlen-vec.S b/sysdeps/x86_64/multiarch/strlen-vec.S +index 439e486a..b7657282 100644 +--- a/sysdeps/x86_64/multiarch/strlen-vec.S ++++ b/sysdeps/x86_64/multiarch/strlen-vec.S +@@ -71,19 +71,12 @@ L(n_nonzero): + suffice. */ + mov %RSI_LP, %R10_LP + sar $62, %R10_LP +- test %R10_LP, %R10_LP + jnz __wcslen_sse4_1 + sal $2, %RSI_LP + # endif + +- + /* Initialize long lived registers. */ +- + add %RDI_LP, %RSI_LP +-# ifdef AS_WCSLEN +-/* Check for overflow again from s + maxlen * sizeof(wchar_t). */ +- jbe __wcslen_sse4_1 +-# endif + mov %RSI_LP, %R10_LP + and $-64, %R10_LP + mov %RSI_LP, %R11_LP +-- +GitLab + diff --git a/SOURCES/glibc-RHEL-15696-5.patch b/SOURCES/glibc-RHEL-15696-5.patch new file mode 100644 index 0000000..75d3978 --- /dev/null +++ b/SOURCES/glibc-RHEL-15696-5.patch @@ -0,0 +1,290 @@ +From 82d0b4a4d76db554eb6757acb790fcea30b19965 Mon Sep 17 00:00:00 2001 +From: "H.J. Lu" +Date: Mon, 21 Jan 2019 11:32:24 -0800 +Subject: [PATCH] x86-64 memset/wmemset: Properly handle the length parameter + [BZ# 24097] +Content-type: text/plain; charset=UTF-8 + +On x32, the size_t parameter may be passed in the lower 32 bits of a +64-bit register with the non-zero upper 32 bits. The string/memory +functions written in assembly can only use the lower 32 bits of a +64-bit register as length or must clear the upper 32 bits before using +the full 64-bit register for length. + +This pach fixes memset/wmemset for x32. Tested on x86-64 and x32. On +x86-64, libc.so is the same with and withou the fix. + + [BZ# 24097] + CVE-2019-6488 + * sysdeps/x86_64/multiarch/memset-avx512-no-vzeroupper.S: Use + RDX_LP for length. Clear the upper 32 bits of RDX register. + * sysdeps/x86_64/multiarch/memset-vec-unaligned-erms.S: Likewise. + * sysdeps/x86_64/x32/Makefile (tests): Add tst-size_t-wmemset. + * sysdeps/x86_64/x32/tst-size_t-memset.c: New file. + * sysdeps/x86_64/x32/tst-size_t-wmemset.c: Likewise. +--- + .../multiarch/memset-avx512-no-vzeroupper.S | 6 +- + .../multiarch/memset-vec-unaligned-erms.S | 34 +++++---- + sysdeps/x86_64/x32/Makefile | 4 +- + sysdeps/x86_64/x32/tst-size_t-memset.c | 73 +++++++++++++++++++ + sysdeps/x86_64/x32/tst-size_t-wmemset.c | 20 +++++ + 5 files changed, 121 insertions(+), 16 deletions(-) + create mode 100644 sysdeps/x86_64/x32/tst-size_t-memset.c + create mode 100644 sysdeps/x86_64/x32/tst-size_t-wmemset.c + +Conflicts: + ChangeLog + (removed) + +diff --git a/sysdeps/x86_64/multiarch/memset-avx512-no-vzeroupper.S b/sysdeps/x86_64/multiarch/memset-avx512-no-vzeroupper.S +index 689cc119..99e25519 100644 +--- a/sysdeps/x86_64/multiarch/memset-avx512-no-vzeroupper.S ++++ b/sysdeps/x86_64/multiarch/memset-avx512-no-vzeroupper.S +@@ -29,12 +29,16 @@ + .section .text.avx512,"ax",@progbits + #if defined PIC + ENTRY (MEMSET_CHK) +- cmpq %rdx, %rcx ++ cmp %RDX_LP, %RCX_LP + jb HIDDEN_JUMPTARGET (__chk_fail) + END (MEMSET_CHK) + #endif + + ENTRY (MEMSET) ++# ifdef __ILP32__ ++ /* Clear the upper 32 bits. */ ++ mov %edx, %edx ++# endif + vpxor %xmm0, %xmm0, %xmm0 + vmovd %esi, %xmm1 + lea (%rdi, %rdx), %rsi +diff --git a/sysdeps/x86_64/multiarch/memset-vec-unaligned-erms.S b/sysdeps/x86_64/multiarch/memset-vec-unaligned-erms.S +index 270a1d49..9a0fd818 100644 +--- a/sysdeps/x86_64/multiarch/memset-vec-unaligned-erms.S ++++ b/sysdeps/x86_64/multiarch/memset-vec-unaligned-erms.S +@@ -65,8 +65,8 @@ + .section SECTION(.text),"ax",@progbits + #if VEC_SIZE == 16 && IS_IN (libc) + ENTRY (__bzero) +- movq %rdi, %rax /* Set return value. */ +- movq %rsi, %rdx /* Set n. */ ++ mov %RDI_LP, %RAX_LP /* Set return value. */ ++ mov %RSI_LP, %RDX_LP /* Set n. */ + pxor %xmm0, %xmm0 + jmp L(entry_from_bzero) + END (__bzero) +@@ -76,13 +76,13 @@ weak_alias (__bzero, bzero) + #if IS_IN (libc) + # if defined SHARED + ENTRY_CHK (WMEMSET_CHK_SYMBOL (__wmemset_chk, unaligned)) +- cmpq %rdx, %rcx ++ cmp %RDX_LP, %RCX_LP + jb HIDDEN_JUMPTARGET (__chk_fail) + END_CHK (WMEMSET_CHK_SYMBOL (__wmemset_chk, unaligned)) + # endif + + ENTRY (WMEMSET_SYMBOL (__wmemset, unaligned)) +- shlq $2, %rdx ++ shl $2, %RDX_LP + WMEMSET_VDUP_TO_VEC0_AND_SET_RETURN (%esi, %rdi) + jmp L(entry_from_bzero) + END (WMEMSET_SYMBOL (__wmemset, unaligned)) +@@ -90,13 +90,17 @@ END (WMEMSET_SYMBOL (__wmemset, unaligned)) + + #if defined SHARED && IS_IN (libc) + ENTRY_CHK (MEMSET_CHK_SYMBOL (__memset_chk, unaligned)) +- cmpq %rdx, %rcx ++ cmp %RDX_LP, %RCX_LP + jb HIDDEN_JUMPTARGET (__chk_fail) + END_CHK (MEMSET_CHK_SYMBOL (__memset_chk, unaligned)) + #endif + + ENTRY (MEMSET_SYMBOL (__memset, unaligned)) + MEMSET_VDUP_TO_VEC0_AND_SET_RETURN (%esi, %rdi) ++# ifdef __ILP32__ ++ /* Clear the upper 32 bits. */ ++ mov %edx, %edx ++# endif + L(entry_from_bzero): + cmpq $VEC_SIZE, %rdx + jb L(less_vec) +@@ -112,14 +116,14 @@ END (MEMSET_SYMBOL (__memset, unaligned)) + + # if VEC_SIZE == 16 + ENTRY (__memset_chk_erms) +- cmpq %rdx, %rcx ++ cmp %RDX_LP, %RCX_LP + jb HIDDEN_JUMPTARGET (__chk_fail) + END (__memset_chk_erms) + + /* Only used to measure performance of REP STOSB. */ + ENTRY (__memset_erms) + /* Skip zero length. */ +- testq %rdx, %rdx ++ test %RDX_LP, %RDX_LP + jnz L(stosb) + movq %rdi, %rax + ret +@@ -131,11 +135,11 @@ ENTRY (MEMSET_SYMBOL (__memset, erms)) + L(stosb): + /* Issue vzeroupper before rep stosb. */ + VZEROUPPER +- movq %rdx, %rcx ++ mov %RDX_LP, %RCX_LP + movzbl %sil, %eax +- movq %rdi, %rdx ++ mov %RDI_LP, %RDX_LP + rep stosb +- movq %rdx, %rax ++ mov %RDX_LP, %RAX_LP + ret + # if VEC_SIZE == 16 + END (__memset_erms) +@@ -145,16 +149,20 @@ END (MEMSET_SYMBOL (__memset, erms)) + + # if defined SHARED && IS_IN (libc) + ENTRY_CHK (MEMSET_CHK_SYMBOL (__memset_chk, unaligned_erms)) +- cmpq %rdx, %rcx ++ cmp %RDX_LP, %RCX_LP + jb HIDDEN_JUMPTARGET (__chk_fail) + END_CHK (MEMSET_CHK_SYMBOL (__memset_chk, unaligned_erms)) + # endif + + ENTRY (MEMSET_SYMBOL (__memset, unaligned_erms)) + MEMSET_VDUP_TO_VEC0_AND_SET_RETURN (%esi, %rdi) +- cmpq $VEC_SIZE, %rdx ++# ifdef __ILP32__ ++ /* Clear the upper 32 bits. */ ++ mov %edx, %edx ++# endif ++ cmp $VEC_SIZE, %RDX_LP + jb L(less_vec) +- cmpq $(VEC_SIZE * 2), %rdx ++ cmp $(VEC_SIZE * 2), %RDX_LP + ja L(stosb_more_2x_vec) + /* From VEC and to 2 * VEC. No branch when size == VEC_SIZE. */ + VMOVU %VEC(0), -VEC_SIZE(%rdi,%rdx) +diff --git a/sysdeps/x86_64/x32/Makefile b/sysdeps/x86_64/x32/Makefile +index e99dbd7c..98bd9ae9 100644 +--- a/sysdeps/x86_64/x32/Makefile ++++ b/sysdeps/x86_64/x32/Makefile +@@ -7,9 +7,9 @@ endif + + ifeq ($(subdir),string) + tests += tst-size_t-memchr tst-size_t-memcmp tst-size_t-memcpy \ +- tst-size_t-memrchr ++ tst-size_t-memrchr tst-size_t-memset + endif + + ifeq ($(subdir),wcsmbs) +-tests += tst-size_t-wmemchr tst-size_t-wmemcmp ++tests += tst-size_t-wmemchr tst-size_t-wmemcmp tst-size_t-wmemset + endif +diff --git a/sysdeps/x86_64/x32/tst-size_t-memset.c b/sysdeps/x86_64/x32/tst-size_t-memset.c +new file mode 100644 +index 00000000..2c367af6 +--- /dev/null ++++ b/sysdeps/x86_64/x32/tst-size_t-memset.c +@@ -0,0 +1,73 @@ ++/* Test memset with size_t in the lower 32 bits of 64-bit register. ++ 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, see ++ . */ ++ ++#ifdef WIDE ++# define TEST_NAME "wmemset" ++#else ++# define TEST_NAME "memset" ++#endif /* WIDE */ ++ ++#include "test-size_t.h" ++ ++#ifdef WIDE ++# include ++# define MEMSET wmemset ++# define CHAR wchar_t ++#else ++# define MEMSET memset ++# define CHAR char ++#endif /* WIDE */ ++ ++IMPL (MEMSET, 1) ++ ++typedef CHAR *(*proto_t) (CHAR *, int, size_t); ++ ++static void * ++__attribute__ ((noinline, noclone)) ++do_memset (parameter_t a, parameter_t b) ++{ ++ return CALL (&b, a.p, (uintptr_t) b.p, a.len); ++} ++ ++static int ++test_main (void) ++{ ++ test_init (); ++ ++ CHAR ch = 0x23; ++ parameter_t src = { { page_size / sizeof (CHAR) }, buf2 }; ++ parameter_t c = { { 0 }, (void *) (uintptr_t) ch }; ++ ++ int ret = 0; ++ FOR_EACH_IMPL (impl, 0) ++ { ++ c.fn = impl->fn; ++ CHAR *p = (CHAR *) do_memset (src, c); ++ size_t i; ++ for (i = 0; i < src.len; i++) ++ if (p[i] != ch) ++ { ++ error (0, 0, "Wrong result in function %s", impl->name); ++ ret = 1; ++ } ++ } ++ ++ return ret ? EXIT_FAILURE : EXIT_SUCCESS; ++} ++ ++#include +diff --git a/sysdeps/x86_64/x32/tst-size_t-wmemset.c b/sysdeps/x86_64/x32/tst-size_t-wmemset.c +new file mode 100644 +index 00000000..955eb488 +--- /dev/null ++++ b/sysdeps/x86_64/x32/tst-size_t-wmemset.c +@@ -0,0 +1,20 @@ ++/* Test wmemset with size_t in the lower 32 bits of 64-bit register. ++ 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, see ++ . */ ++ ++#define WIDE 1 ++#include "tst-size_t-memset.c" +-- +GitLab + diff --git a/SOURCES/glibc-RHEL-15696-50.patch b/SOURCES/glibc-RHEL-15696-50.patch new file mode 100644 index 0000000..e896698 --- /dev/null +++ b/SOURCES/glibc-RHEL-15696-50.patch @@ -0,0 +1,43 @@ +From 447954a206837b5f153869cfeeeab44631c3fac9 Mon Sep 17 00:00:00 2001 +Author: Shen-Ta Hsieh 2021-05-23 21:43:10 +Committer: H.J. Lu 2021-06-27 10:56:57 +Parent: 2c16cb88a6e5ace0fb7cedca86860ea7bde522a7 (Linux: Move timer helper routines from librt to libc) +Child: 1683249d17e14827b6579529742eb895027dfa84 (x86_64: roundeven with sse4.1 support) +Branches: master, remotes/origin/master and many more (41) +Follows: glibc-2.33.9000 +Precedes: glibc-2.34 + + math: redirect roundeven function + + This patch redirect roundeven function for futhermore changes. + + Signed-off-by: Shen-Ta Hsieh + Reviewed-by: H.J. Lu + +Conflicts: + * + (rewritten for older branch) + +diff --git a/sysdeps/ieee754/dbl-64/wordsize-64/s_roundeven.c b/sysdeps/ieee754/dbl-64/wordsize-64/s_roundeven.c +index 7bbbb2dc..8728d0f2 100644 +--- a/sysdeps/ieee754/dbl-64/wordsize-64/s_roundeven.c ++++ b/sysdeps/ieee754/dbl-64/wordsize-64/s_roundeven.c +@@ -17,6 +17,7 @@ + License along with the GNU C Library; if not, see + . */ + ++#define NO_MATH_REDIRECT + #include + #include + #include +@@ -67,5 +68,6 @@ __roundeven (double x) + INSERT_WORDS64 (x, ix); + return x; + } +-hidden_def (__roundeven) ++#ifndef __roundeven + libm_alias_double (__roundeven, roundeven) ++#endif +-- +GitLab + diff --git a/SOURCES/glibc-RHEL-15696-51.patch b/SOURCES/glibc-RHEL-15696-51.patch new file mode 100644 index 0000000..105843d --- /dev/null +++ b/SOURCES/glibc-RHEL-15696-51.patch @@ -0,0 +1,118 @@ +From 447954a206837b5f153869cfeeeab44631c3fac9 Mon Sep 17 00:00:00 2001 +From: Shen-Ta Hsieh +Date: Mon, 24 May 2021 09:43:10 +0800 +Subject: [PATCH] math: redirect roundeven function +Content-type: text/plain; charset=UTF-8 + +This patch redirect roundeven function for futhermore changes. + +Signed-off-by: Shen-Ta Hsieh +Reviewed-by: H.J. Lu +--- + include/math.h | 3 ++- + sysdeps/ieee754/dbl-64/s_roundeven.c | 4 +++- + sysdeps/ieee754/float128/s_roundevenf128.c | 1 + + sysdeps/ieee754/flt-32/s_roundevenf.c | 3 +++ + sysdeps/ieee754/ldbl-128/s_roundevenl.c | 1 + + sysdeps/ieee754/ldbl-96/s_roundevenl.c | 1 + + 6 files changed, 11 insertions(+), 2 deletions(-) + +Conflicts: + include/math.h + (missing MATH_REDIRECT macros) + +diff --git a/include/math.h b/include/math.h +index e21d34b8..1f9f9a54 100644 +--- a/include/math.h ++++ b/include/math.h +@@ -38,7 +38,6 @@ libm_hidden_proto (__issignaling) + libm_hidden_proto (__issignalingf) + libm_hidden_proto (__exp) + libm_hidden_proto (__expf) +-libm_hidden_proto (__roundeven) + + # ifndef __NO_LONG_DOUBLE_MATH + libm_hidden_proto (__fpclassifyl) +@@ -56,6 +55,8 @@ libm_hidden_proto (__expm1f128) + + # if !(defined __FINITE_MATH_ONLY__ && __FINITE_MATH_ONLY__ > 0) + # ifndef NO_MATH_REDIRECT ++float (roundevenf) (float) asm ("__roundevenf"); ++double (roundeven) (double) asm ("__roundeven"); + /* Declare sqrt for use within GLIBC. Compilers typically inline sqrt as a + single instruction. Use an asm to avoid use of PLTs if it doesn't. */ + float (sqrtf) (float) asm ("__ieee754_sqrtf"); +diff --git a/sysdeps/ieee754/dbl-64/s_roundeven.c b/sysdeps/ieee754/dbl-64/s_roundeven.c +index 1438e81d..61962184 100644 +--- a/sysdeps/ieee754/dbl-64/s_roundeven.c ++++ b/sysdeps/ieee754/dbl-64/s_roundeven.c +@@ -17,6 +17,7 @@ + License along with the GNU C Library; if not, see + . */ + ++#define NO_MATH_REDIRECT + #include + #include + #include +@@ -101,5 +102,6 @@ __roundeven (double x) + INSERT_WORDS (x, hx, lx); + return x; + } +-hidden_def (__roundeven) ++#ifndef __roundeven + libm_alias_double (__roundeven, roundeven) ++#endif +diff --git a/sysdeps/ieee754/float128/s_roundevenf128.c b/sysdeps/ieee754/float128/s_roundevenf128.c +index 5a9b3f39..e0faf727 100644 +--- a/sysdeps/ieee754/float128/s_roundevenf128.c ++++ b/sysdeps/ieee754/float128/s_roundevenf128.c +@@ -1,2 +1,3 @@ ++#define NO_MATH_REDIRECT + #include + #include "../ldbl-128/s_roundevenl.c" +diff --git a/sysdeps/ieee754/flt-32/s_roundevenf.c b/sysdeps/ieee754/flt-32/s_roundevenf.c +index 90f991d5..a661875e 100644 +--- a/sysdeps/ieee754/flt-32/s_roundevenf.c ++++ b/sysdeps/ieee754/flt-32/s_roundevenf.c +@@ -17,6 +17,7 @@ + License along with the GNU C Library; if not, see + . */ + ++#define NO_MATH_REDIRECT + #include + #include + #include +@@ -67,4 +68,6 @@ __roundevenf (float x) + SET_FLOAT_WORD (x, ix); + return x; + } ++#ifndef __roundevenf + libm_alias_float (__roundeven, roundeven) ++#endif +diff --git a/sysdeps/ieee754/ldbl-128/s_roundevenl.c b/sysdeps/ieee754/ldbl-128/s_roundevenl.c +index 5fc59af4..b9375b6c 100644 +--- a/sysdeps/ieee754/ldbl-128/s_roundevenl.c ++++ b/sysdeps/ieee754/ldbl-128/s_roundevenl.c +@@ -17,6 +17,7 @@ + License along with the GNU C Library; if not, see + . */ + ++#define NO_MATH_REDIRECT + #include + #include + #include +diff --git a/sysdeps/ieee754/ldbl-96/s_roundevenl.c b/sysdeps/ieee754/ldbl-96/s_roundevenl.c +index be2e4fa4..65031ab7 100644 +--- a/sysdeps/ieee754/ldbl-96/s_roundevenl.c ++++ b/sysdeps/ieee754/ldbl-96/s_roundevenl.c +@@ -17,6 +17,7 @@ + License along with the GNU C Library; if not, see + . */ + ++#define NO_MATH_REDIRECT + #include + #include + #include +-- +GitLab + diff --git a/SOURCES/glibc-RHEL-15696-52.patch b/SOURCES/glibc-RHEL-15696-52.patch new file mode 100644 index 0000000..4602f51 --- /dev/null +++ b/SOURCES/glibc-RHEL-15696-52.patch @@ -0,0 +1,242 @@ +From 1683249d17e14827b6579529742eb895027dfa84 Mon Sep 17 00:00:00 2001 +From: Shen-Ta Hsieh +Date: Mon, 24 May 2021 09:43:11 +0800 +Subject: [PATCH] x86_64: roundeven with sse4.1 support +Content-type: text/plain; charset=UTF-8 + +This patch adds support for the sse4.1 hardware floating point +roundeven. + +Here is some benchmark results on my systems: + +=AMD Ryzen 9 3900X 12-Core Processor= + +* benchmark result before this commit +| | roundeven | roundevenf | +|------------|--------------|--------------| +| duration | 3.75587e+09 | 3.75114e+09 | +| iterations | 3.93053e+08 | 4.35402e+08 | +| max | 52.592 | 58.71 | +| min | 7.98 | 7.22 | +| mean | 9.55563 | 8.61535 | + +* benchmark result after this commit +| | roundeven | roundevenf | +|------------|---------------|--------------| +| duration | 3.73815e+09 | 3.73738e+09 | +| iterations | 5.82692e+08 | 5.91498e+08 | +| max | 56.468 | 51.642 | +| min | 6.27 | 6.156 | +| mean | 6.41532 | 6.3185 | + +=Intel(R) Pentium(R) CPU D1508 @ 2.20GHz= + +* benchmark result before this commit +| | roundeven | roundevenf | +|------------|--------------|--------------| +| duration | 2.18208e+09 | 2.18258e+09 | +| iterations | 2.39932e+08 | 2.46924e+08 | +| max | 96.378 | 98.035 | +| min | 6.776 | 5.94 | +| mean | 9.09456 | 8.83907 | + +* benchmark result after this commit +| | roundeven | roundevenf | +|------------|--------------|--------------| +| duration | 2.17415e+09 | 2.17005e+09 | +| iterations | 3.56193e+08 | 4.09824e+08 | +| max | 51.693 | 97.192 | +| min | 5.926 | 5.093 | +| mean | 6.10385 | 5.29507 | + +Signed-off-by: Shen-Ta Hsieh +Reviewed-by: H.J. Lu +--- + sysdeps/x86_64/fpu/multiarch/Makefile | 5 +-- + sysdeps/x86_64/fpu/multiarch/s_roundeven-c.c | 2 ++ + .../x86_64/fpu/multiarch/s_roundeven-sse4_1.S | 24 ++++++++++++++ + sysdeps/x86_64/fpu/multiarch/s_roundeven.c | 31 +++++++++++++++++++ + sysdeps/x86_64/fpu/multiarch/s_roundevenf-c.c | 3 ++ + .../fpu/multiarch/s_roundevenf-sse4_1.S | 24 ++++++++++++++ + sysdeps/x86_64/fpu/multiarch/s_roundevenf.c | 31 +++++++++++++++++++ + 7 files changed, 118 insertions(+), 2 deletions(-) + create mode 100644 sysdeps/x86_64/fpu/multiarch/s_roundeven-c.c + create mode 100644 sysdeps/x86_64/fpu/multiarch/s_roundeven-sse4_1.S + create mode 100644 sysdeps/x86_64/fpu/multiarch/s_roundeven.c + create mode 100644 sysdeps/x86_64/fpu/multiarch/s_roundevenf-c.c + create mode 100644 sysdeps/x86_64/fpu/multiarch/s_roundevenf-sse4_1.S + create mode 100644 sysdeps/x86_64/fpu/multiarch/s_roundevenf.c + +diff --git a/sysdeps/x86_64/fpu/multiarch/Makefile b/sysdeps/x86_64/fpu/multiarch/Makefile +index 9f387248..6ddd1c01 100644 +--- a/sysdeps/x86_64/fpu/multiarch/Makefile ++++ b/sysdeps/x86_64/fpu/multiarch/Makefile +@@ -1,11 +1,12 @@ + ifeq ($(subdir),math) + libm-sysdep_routines += s_floor-c s_ceil-c s_floorf-c s_ceilf-c \ + s_rint-c s_rintf-c s_nearbyint-c s_nearbyintf-c \ +- s_trunc-c s_truncf-c ++ s_roundeven-c s_roundevenf-c s_trunc-c s_truncf-c + + libm-sysdep_routines += s_ceil-sse4_1 s_ceilf-sse4_1 s_floor-sse4_1 \ + s_floorf-sse4_1 s_nearbyint-sse4_1 \ +- s_nearbyintf-sse4_1 s_rint-sse4_1 s_rintf-sse4_1 \ ++ s_nearbyintf-sse4_1 s_roundeven-sse4_1 \ ++ s_roundevenf-sse4_1 s_rint-sse4_1 s_rintf-sse4_1 \ + s_trunc-sse4_1 s_truncf-sse4_1 + + libm-sysdep_routines += e_exp-fma e_log-fma e_pow-fma s_atan-fma \ +diff --git a/sysdeps/x86_64/fpu/multiarch/s_roundeven-c.c b/sysdeps/x86_64/fpu/multiarch/s_roundeven-c.c +new file mode 100644 +index 00000000..c7be43cb +--- /dev/null ++++ b/sysdeps/x86_64/fpu/multiarch/s_roundeven-c.c +@@ -0,0 +1,2 @@ ++#define __roundeven __roundeven_c ++#include +diff --git a/sysdeps/x86_64/fpu/multiarch/s_roundeven-sse4_1.S b/sysdeps/x86_64/fpu/multiarch/s_roundeven-sse4_1.S +new file mode 100644 +index 00000000..6ae8f6b1 +--- /dev/null ++++ b/sysdeps/x86_64/fpu/multiarch/s_roundeven-sse4_1.S +@@ -0,0 +1,24 @@ ++/* 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 ++ ++ .section .text.sse4.1,"ax",@progbits ++ENTRY(__roundeven_sse41) ++ roundsd $8, %xmm0, %xmm0 ++ ret ++END(__roundeven_sse41) +diff --git a/sysdeps/x86_64/fpu/multiarch/s_roundeven.c b/sysdeps/x86_64/fpu/multiarch/s_roundeven.c +new file mode 100644 +index 00000000..d92eda65 +--- /dev/null ++++ b/sysdeps/x86_64/fpu/multiarch/s_roundeven.c +@@ -0,0 +1,31 @@ ++/* Multiple versions of __roundeven. ++ 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 ++ ++#define roundeven __redirect_roundeven ++#define __roundeven __redirect___roundeven ++#include ++#undef roundeven ++#undef __roundeven ++ ++#define SYMBOL_NAME roundeven ++#include "ifunc-sse4_1.h" ++ ++libc_ifunc_redirected (__redirect_roundeven, __roundeven, IFUNC_SELECTOR ()); ++libm_alias_double (__roundeven, roundeven) +diff --git a/sysdeps/x86_64/fpu/multiarch/s_roundevenf-c.c b/sysdeps/x86_64/fpu/multiarch/s_roundevenf-c.c +new file mode 100644 +index 00000000..72a6e7d1 +--- /dev/null ++++ b/sysdeps/x86_64/fpu/multiarch/s_roundevenf-c.c +@@ -0,0 +1,3 @@ ++#undef __roundevenf ++#define __roundevenf __roundevenf_c ++#include +diff --git a/sysdeps/x86_64/fpu/multiarch/s_roundevenf-sse4_1.S b/sysdeps/x86_64/fpu/multiarch/s_roundevenf-sse4_1.S +new file mode 100644 +index 00000000..a76e1080 +--- /dev/null ++++ b/sysdeps/x86_64/fpu/multiarch/s_roundevenf-sse4_1.S +@@ -0,0 +1,24 @@ ++/* 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 ++ ++ .section .text.sse4.1,"ax",@progbits ++ENTRY(__roundevenf_sse41) ++ roundss $8, %xmm0, %xmm0 ++ ret ++END(__roundevenf_sse41) +diff --git a/sysdeps/x86_64/fpu/multiarch/s_roundevenf.c b/sysdeps/x86_64/fpu/multiarch/s_roundevenf.c +new file mode 100644 +index 00000000..2ee196e6 +--- /dev/null ++++ b/sysdeps/x86_64/fpu/multiarch/s_roundevenf.c +@@ -0,0 +1,31 @@ ++/* Multiple versions of __roundevenf. ++ 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 ++ ++#define roundevenf __redirect_roundevenf ++#define __roundevenf __redirect___roundevenf ++#include ++#undef roundevenf ++#undef __roundevenf ++ ++#define SYMBOL_NAME roundevenf ++#include "ifunc-sse4_1.h" ++ ++libc_ifunc_redirected (__redirect_roundevenf, __roundevenf, IFUNC_SELECTOR ()); ++libm_alias_float (__roundeven, roundeven) +-- +GitLab + diff --git a/SOURCES/glibc-RHEL-15696-53.patch b/SOURCES/glibc-RHEL-15696-53.patch new file mode 100644 index 0000000..7221d38 --- /dev/null +++ b/SOURCES/glibc-RHEL-15696-53.patch @@ -0,0 +1,41 @@ +From 7e08db3359c86c94918feb33a1182cd0ff3bb10b Mon Sep 17 00:00:00 2001 +From: Noah Goldstein +Date: Sun, 9 Jan 2022 16:02:28 -0600 +Subject: [PATCH] x86: Fix __wcsncmp_evex in strcmp-evex.S [BZ# 28755] +Content-type: text/plain; charset=UTF-8 + +Fixes [BZ# 28755] for wcsncmp by redirecting length >= 2^56 to +__wcscmp_evex. For x86_64 this covers the entire address range so any +length larger could not possibly be used to bound `s1` or `s2`. + +test-strcmp, test-strncmp, test-wcscmp, and test-wcsncmp all pass. + +Signed-off-by: Noah Goldstein +--- + sysdeps/x86_64/multiarch/strcmp-evex.S | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +diff --git a/sysdeps/x86_64/multiarch/strcmp-evex.S b/sysdeps/x86_64/multiarch/strcmp-evex.S +index 459eeed0..d5aa6daa 100644 +--- a/sysdeps/x86_64/multiarch/strcmp-evex.S ++++ b/sysdeps/x86_64/multiarch/strcmp-evex.S +@@ -97,6 +97,16 @@ ENTRY (STRCMP) + je L(char0) + jb L(zero) + # ifdef USE_AS_WCSCMP ++# ifndef __ILP32__ ++ movq %rdx, %rcx ++ /* Check if length could overflow when multiplied by ++ sizeof(wchar_t). Checking top 8 bits will cover all potential ++ overflow cases as well as redirect cases where its impossible to ++ length to bound a valid memory region. In these cases just use ++ 'wcscmp'. */ ++ shrq $56, %rcx ++ jnz __wcscmp_evex ++# endif + /* Convert units: from wide to byte char. */ + shl $2, %RDX_LP + # endif +-- +GitLab + diff --git a/SOURCES/glibc-RHEL-15696-54.patch b/SOURCES/glibc-RHEL-15696-54.patch new file mode 100644 index 0000000..b2aaaa1 --- /dev/null +++ b/SOURCES/glibc-RHEL-15696-54.patch @@ -0,0 +1,268 @@ +From 78c9ec9000f873abe7a15a91b87080a2e4308260 Mon Sep 17 00:00:00 2001 +From: "H.J. Lu" +Date: Fri, 20 Aug 2021 06:42:24 -0700 +Subject: [PATCH] x86-64: Optimize load of all bits set into ZMM register [BZ + #28252] +Content-type: text/plain; charset=UTF-8 + +Optimize loads of all bits set into ZMM register in AVX512 SVML codes +by replacing + + vpbroadcastq .L_2il0floatpacket.16(%rip), %zmmX + +and + + vmovups .L_2il0floatpacket.13(%rip), %zmmX + +with + vpternlogd $0xff, %zmmX, %zmmX, %zmmX + +This fixes BZ #28252. +--- + .../x86_64/fpu/multiarch/svml_d_cos8_core_avx512.S | 7 +------ + .../x86_64/fpu/multiarch/svml_d_log8_core_avx512.S | 7 +------ + .../x86_64/fpu/multiarch/svml_d_sin8_core_avx512.S | 7 +------ + .../fpu/multiarch/svml_d_sincos8_core_avx512.S | 7 +------ + .../x86_64/fpu/multiarch/svml_s_cosf16_core_avx512.S | 7 +------ + .../x86_64/fpu/multiarch/svml_s_expf16_core_avx512.S | 7 +------ + .../x86_64/fpu/multiarch/svml_s_logf16_core_avx512.S | 7 +------ + .../x86_64/fpu/multiarch/svml_s_powf16_core_avx512.S | 12 ++---------- + .../fpu/multiarch/svml_s_sincosf16_core_avx512.S | 7 +------ + .../x86_64/fpu/multiarch/svml_s_sinf16_core_avx512.S | 7 +------ + 10 files changed, 11 insertions(+), 64 deletions(-) + +diff --git a/sysdeps/x86_64/fpu/multiarch/svml_d_cos8_core_avx512.S b/sysdeps/x86_64/fpu/multiarch/svml_d_cos8_core_avx512.S +index 24e3b363..07dfed85 100644 +--- a/sysdeps/x86_64/fpu/multiarch/svml_d_cos8_core_avx512.S ++++ b/sysdeps/x86_64/fpu/multiarch/svml_d_cos8_core_avx512.S +@@ -265,7 +265,7 @@ WRAPPER_IMPL_AVX512 _ZGVdN4v_cos + vmovaps %zmm0, %zmm8 + + /* Check for large arguments path */ +- vpbroadcastq .L_2il0floatpacket.16(%rip), %zmm2 ++ vpternlogd $0xff, %zmm2, %zmm2, %zmm2 + + /* + ARGUMENT RANGE REDUCTION: +@@ -456,8 +456,3 @@ WRAPPER_IMPL_AVX512 _ZGVdN4v_cos + jmp .LBL_2_7 + #endif + END (_ZGVeN8v_cos_skx) +- +- .section .rodata, "a" +-.L_2il0floatpacket.16: +- .long 0xffffffff,0xffffffff +- .type .L_2il0floatpacket.16,@object +diff --git a/sysdeps/x86_64/fpu/multiarch/svml_d_log8_core_avx512.S b/sysdeps/x86_64/fpu/multiarch/svml_d_log8_core_avx512.S +index ae8af8d8..ddb60e5b 100644 +--- a/sysdeps/x86_64/fpu/multiarch/svml_d_log8_core_avx512.S ++++ b/sysdeps/x86_64/fpu/multiarch/svml_d_log8_core_avx512.S +@@ -274,7 +274,7 @@ WRAPPER_IMPL_AVX512 _ZGVdN4v_log + + /* preserve mantissa, set input exponent to 2^(-10) */ + vpternlogq $248, _ExpMask(%rax), %zmm3, %zmm2 +- vpbroadcastq .L_2il0floatpacket.12(%rip), %zmm1 ++ vpternlogd $0xff, %zmm1, %zmm1, %zmm1 + vpsrlq $32, %zmm4, %zmm6 + + /* reciprocal approximation good to at least 11 bits */ +@@ -461,8 +461,3 @@ WRAPPER_IMPL_AVX512 _ZGVdN4v_log + jmp .LBL_2_7 + #endif + END (_ZGVeN8v_log_skx) +- +- .section .rodata, "a" +-.L_2il0floatpacket.12: +- .long 0xffffffff,0xffffffff +- .type .L_2il0floatpacket.12,@object +diff --git a/sysdeps/x86_64/fpu/multiarch/svml_d_sin8_core_avx512.S b/sysdeps/x86_64/fpu/multiarch/svml_d_sin8_core_avx512.S +index 2d4b14fd..529c454a 100644 +--- a/sysdeps/x86_64/fpu/multiarch/svml_d_sin8_core_avx512.S ++++ b/sysdeps/x86_64/fpu/multiarch/svml_d_sin8_core_avx512.S +@@ -261,7 +261,7 @@ WRAPPER_IMPL_AVX512 _ZGVdN4v_sin + andq $-64, %rsp + subq $1280, %rsp + movq __svml_d_trig_data@GOTPCREL(%rip), %rax +- vpbroadcastq .L_2il0floatpacket.14(%rip), %zmm14 ++ vpternlogd $0xff, %zmm1, %zmm1, %zmm14 + vmovups __dAbsMask(%rax), %zmm7 + vmovups __dInvPI(%rax), %zmm2 + vmovups __dRShifter(%rax), %zmm1 +@@ -458,8 +458,3 @@ WRAPPER_IMPL_AVX512 _ZGVdN4v_sin + jmp .LBL_2_7 + #endif + END (_ZGVeN8v_sin_skx) +- +- .section .rodata, "a" +-.L_2il0floatpacket.14: +- .long 0xffffffff,0xffffffff +- .type .L_2il0floatpacket.14,@object +diff --git a/sysdeps/x86_64/fpu/multiarch/svml_d_sincos8_core_avx512.S b/sysdeps/x86_64/fpu/multiarch/svml_d_sincos8_core_avx512.S +index 2df626c0..e501a53a 100644 +--- a/sysdeps/x86_64/fpu/multiarch/svml_d_sincos8_core_avx512.S ++++ b/sysdeps/x86_64/fpu/multiarch/svml_d_sincos8_core_avx512.S +@@ -430,7 +430,7 @@ WRAPPER_IMPL_AVX512_fFF _ZGVdN4vl8l8_sincos + + /* SinPoly = SinR*SinPoly */ + vfmadd213pd %zmm5, %zmm5, %zmm4 +- vpbroadcastq .L_2il0floatpacket.15(%rip), %zmm3 ++ vpternlogd $0xff, %zmm3, %zmm3, %zmm3 + + /* Update Cos result's sign */ + vxorpd %zmm2, %zmm1, %zmm1 +@@ -741,8 +741,3 @@ END (_ZGVeN8vvv_sincos_knl) + ENTRY (_ZGVeN8vvv_sincos_skx) + WRAPPER_AVX512_vvv_vl8l8 _ZGVeN8vl8l8_sincos_skx + END (_ZGVeN8vvv_sincos_skx) +- +- .section .rodata, "a" +-.L_2il0floatpacket.15: +- .long 0xffffffff,0xffffffff +- .type .L_2il0floatpacket.15,@object +diff --git a/sysdeps/x86_64/fpu/multiarch/svml_s_cosf16_core_avx512.S b/sysdeps/x86_64/fpu/multiarch/svml_s_cosf16_core_avx512.S +index 6ea1137b..377af394 100644 +--- a/sysdeps/x86_64/fpu/multiarch/svml_s_cosf16_core_avx512.S ++++ b/sysdeps/x86_64/fpu/multiarch/svml_s_cosf16_core_avx512.S +@@ -278,7 +278,7 @@ WRAPPER_IMPL_AVX512 _ZGVdN8v_cosf + X = X - Y*PI1 - Y*PI2 - Y*PI3 + */ + vmovaps %zmm0, %zmm6 +- vmovups .L_2il0floatpacket.13(%rip), %zmm12 ++ vpternlogd $0xff, %zmm12, %zmm12, %zmm12 + vmovups __sRShifter(%rax), %zmm3 + vmovups __sPI1_FMA(%rax), %zmm5 + vmovups __sA9_FMA(%rax), %zmm9 +@@ -453,8 +453,3 @@ WRAPPER_IMPL_AVX512 _ZGVdN8v_cosf + jmp .LBL_2_7 + #endif + END (_ZGVeN16v_cosf_skx) +- +- .section .rodata, "a" +-.L_2il0floatpacket.13: +- .long 0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff +- .type .L_2il0floatpacket.13,@object +diff --git a/sysdeps/x86_64/fpu/multiarch/svml_s_expf16_core_avx512.S b/sysdeps/x86_64/fpu/multiarch/svml_s_expf16_core_avx512.S +index 89ba0df2..46f33d46 100644 +--- a/sysdeps/x86_64/fpu/multiarch/svml_s_expf16_core_avx512.S ++++ b/sysdeps/x86_64/fpu/multiarch/svml_s_expf16_core_avx512.S +@@ -264,7 +264,7 @@ WRAPPER_IMPL_AVX512 _ZGVdN8v_expf + vmovaps %zmm0, %zmm7 + + /* compare against threshold */ +- vmovups .L_2il0floatpacket.13(%rip), %zmm3 ++ vpternlogd $0xff, %zmm3, %zmm3, %zmm3 + vmovups __sInvLn2(%rax), %zmm4 + vmovups __sShifter(%rax), %zmm1 + vmovups __sLn2hi(%rax), %zmm6 +@@ -440,8 +440,3 @@ WRAPPER_IMPL_AVX512 _ZGVdN8v_expf + + #endif + END (_ZGVeN16v_expf_skx) +- +- .section .rodata, "a" +-.L_2il0floatpacket.13: +- .long 0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff +- .type .L_2il0floatpacket.13,@object +diff --git a/sysdeps/x86_64/fpu/multiarch/svml_s_logf16_core_avx512.S b/sysdeps/x86_64/fpu/multiarch/svml_s_logf16_core_avx512.S +index 4cf0a96f..9e254956 100644 +--- a/sysdeps/x86_64/fpu/multiarch/svml_s_logf16_core_avx512.S ++++ b/sysdeps/x86_64/fpu/multiarch/svml_s_logf16_core_avx512.S +@@ -235,7 +235,7 @@ WRAPPER_IMPL_AVX512 _ZGVdN8v_logf + andq $-64, %rsp + subq $1280, %rsp + movq __svml_slog_data@GOTPCREL(%rip), %rax +- vmovups .L_2il0floatpacket.7(%rip), %zmm6 ++ vpternlogd $0xff, %zmm6, %zmm6, %zmm6 + vmovups _iBrkValue(%rax), %zmm4 + vmovups _sPoly_7(%rax), %zmm8 + +@@ -409,8 +409,3 @@ WRAPPER_IMPL_AVX512 _ZGVdN8v_logf + + #endif + END (_ZGVeN16v_logf_skx) +- +- .section .rodata, "a" +-.L_2il0floatpacket.7: +- .long 0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff +- .type .L_2il0floatpacket.7,@object +diff --git a/sysdeps/x86_64/fpu/multiarch/svml_s_powf16_core_avx512.S b/sysdeps/x86_64/fpu/multiarch/svml_s_powf16_core_avx512.S +index bdcd50af..e8331ba1 100644 +--- a/sysdeps/x86_64/fpu/multiarch/svml_s_powf16_core_avx512.S ++++ b/sysdeps/x86_64/fpu/multiarch/svml_s_powf16_core_avx512.S +@@ -385,7 +385,7 @@ WRAPPER_IMPL_AVX512_ff _ZGVdN8vv_powf + vpsrlq $32, %zmm3, %zmm2 + vpmovqd %zmm2, %ymm11 + vcvtps2pd %ymm14, %zmm13 +- vmovups .L_2il0floatpacket.23(%rip), %zmm14 ++ vpternlogd $0xff, %zmm14, %zmm14, %zmm14 + vmovaps %zmm14, %zmm26 + vpandd _ABSMASK(%rax), %zmm1, %zmm8 + vpcmpd $1, _INF(%rax), %zmm8, %k2 +@@ -427,7 +427,7 @@ WRAPPER_IMPL_AVX512_ff _ZGVdN8vv_powf + vpmovqd %zmm11, %ymm5 + vpxord %zmm10, %zmm10, %zmm10 + vgatherdpd _Log2Rcp_lookup(%rax,%ymm4), %zmm10{%k3} +- vpbroadcastq .L_2il0floatpacket.24(%rip), %zmm4 ++ vpternlogd $0xff, %zmm4, %zmm4, %zmm4 + vpxord %zmm11, %zmm11, %zmm11 + vcvtdq2pd %ymm7, %zmm7 + vgatherdpd _Log2Rcp_lookup(%rax,%ymm5), %zmm11{%k1} +@@ -643,11 +643,3 @@ WRAPPER_IMPL_AVX512_ff _ZGVdN8vv_powf + jmp .LBL_2_7 + #endif + END (_ZGVeN16vv_powf_skx) +- +- .section .rodata, "a" +-.L_2il0floatpacket.23: +- .long 0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff +- .type .L_2il0floatpacket.23,@object +-.L_2il0floatpacket.24: +- .long 0xffffffff,0xffffffff +- .type .L_2il0floatpacket.24,@object +diff --git a/sysdeps/x86_64/fpu/multiarch/svml_s_sincosf16_core_avx512.S b/sysdeps/x86_64/fpu/multiarch/svml_s_sincosf16_core_avx512.S +index 5fa4bc41..1f46f334 100644 +--- a/sysdeps/x86_64/fpu/multiarch/svml_s_sincosf16_core_avx512.S ++++ b/sysdeps/x86_64/fpu/multiarch/svml_s_sincosf16_core_avx512.S +@@ -317,7 +317,7 @@ WRAPPER_IMPL_AVX512_fFF _ZGVdN8vvv_sincosf + + /* Result sign calculations */ + vpternlogd $150, %zmm0, %zmm14, %zmm1 +- vmovups .L_2il0floatpacket.13(%rip), %zmm14 ++ vpternlogd $0xff, %zmm14, %zmm14, %zmm14 + + /* Add correction term 0.5 for cos() part */ + vaddps %zmm8, %zmm5, %zmm15 +@@ -748,8 +748,3 @@ END (_ZGVeN16vvv_sincosf_knl) + ENTRY (_ZGVeN16vvv_sincosf_skx) + WRAPPER_AVX512_vvv_vl4l4 _ZGVeN16vl4l4_sincosf_skx + END (_ZGVeN16vvv_sincosf_skx) +- +- .section .rodata, "a" +-.L_2il0floatpacket.13: +- .long 0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff +- .type .L_2il0floatpacket.13,@object +diff --git a/sysdeps/x86_64/fpu/multiarch/svml_s_sinf16_core_avx512.S b/sysdeps/x86_64/fpu/multiarch/svml_s_sinf16_core_avx512.S +index 141f747e..1fc9308a 100644 +--- a/sysdeps/x86_64/fpu/multiarch/svml_s_sinf16_core_avx512.S ++++ b/sysdeps/x86_64/fpu/multiarch/svml_s_sinf16_core_avx512.S +@@ -280,7 +280,7 @@ WRAPPER_IMPL_AVX512 _ZGVdN8v_sinf + movq __svml_s_trig_data@GOTPCREL(%rip), %rax + + /* Check for large and special values */ +- vmovups .L_2il0floatpacket.11(%rip), %zmm14 ++ vpternlogd $0xff, %zmm14, %zmm14, %zmm14 + vmovups __sAbsMask(%rax), %zmm5 + vmovups __sInvPI(%rax), %zmm1 + vmovups __sRShifter(%rax), %zmm2 +@@ -472,8 +472,3 @@ WRAPPER_IMPL_AVX512 _ZGVdN8v_sinf + jmp .LBL_2_7 + #endif + END (_ZGVeN16v_sinf_skx) +- +- .section .rodata, "a" +-.L_2il0floatpacket.11: +- .long 0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff +- .type .L_2il0floatpacket.11,@object +-- +GitLab + diff --git a/SOURCES/glibc-RHEL-15696-55.patch b/SOURCES/glibc-RHEL-15696-55.patch new file mode 100644 index 0000000..d44eef1 --- /dev/null +++ b/SOURCES/glibc-RHEL-15696-55.patch @@ -0,0 +1,48 @@ +From fc5bd179ef3a953dff8d1655bd530d0e230ffe71 Mon Sep 17 00:00:00 2001 +From: Noah Goldstein +Date: Tue, 21 Sep 2021 18:31:49 -0500 +Subject: [PATCH] x86: Modify ENTRY in sysdep.h so that p2align can be + specified +Content-type: text/plain; charset=UTF-8 + +No bug. + +This change adds a new macro ENTRY_P2ALIGN which takes a second +argument, log2 of the desired function alignment. + +The old ENTRY(name) macro is just ENTRY_P2ALIGN(name, 4) so this +doesn't affect any existing functionality. + +Signed-off-by: Noah Goldstein +--- + sysdeps/x86/sysdep.h | 7 +++++-- + 1 file changed, 5 insertions(+), 2 deletions(-) + +diff --git a/sysdeps/x86/sysdep.h b/sysdeps/x86/sysdep.h +index 01bac0f6..a70bb3a2 100644 +--- a/sysdeps/x86/sysdep.h ++++ b/sysdeps/x86/sysdep.h +@@ -78,15 +78,18 @@ enum cf_protection_level + #define ASM_SIZE_DIRECTIVE(name) .size name,.-name; + + /* Define an entry point visible from C. */ +-#define ENTRY(name) \ ++#define ENTRY_P2ALIGN(name, alignment) \ + .globl C_SYMBOL_NAME(name); \ + .type C_SYMBOL_NAME(name),@function; \ +- .align ALIGNARG(4); \ ++ .align ALIGNARG(alignment); \ + C_LABEL(name) \ + cfi_startproc; \ + _CET_ENDBR; \ + CALL_MCOUNT + ++/* Common entry 16 byte aligns. */ ++#define ENTRY(name) ENTRY_P2ALIGN (name, 4) ++ + #undef END + #define END(name) \ + cfi_endproc; \ +-- +GitLab + diff --git a/SOURCES/glibc-RHEL-15696-56.patch b/SOURCES/glibc-RHEL-15696-56.patch new file mode 100644 index 0000000..45b9975 --- /dev/null +++ b/SOURCES/glibc-RHEL-15696-56.patch @@ -0,0 +1,658 @@ +From 1bd8b8d58fc9967cc073d2c13bfb6befefca2faa Mon Sep 17 00:00:00 2001 +From: Noah Goldstein +Date: Tue, 21 Sep 2021 18:45:03 -0500 +Subject: [PATCH] x86: Optimize memcmp-evex-movbe.S for frontend behavior and + size +Content-type: text/plain; charset=UTF-8 + +No bug. + +The frontend optimizations are to: +1. Reorganize logically connected basic blocks so they are either in + the same cache line or adjacent cache lines. +2. Avoid cases when basic blocks unnecissarily cross cache lines. +3. Try and 32 byte align any basic blocks possible without sacrificing + code size. Smaller / Less hot basic blocks are used for this. + +Overall code size shrunk by 168 bytes. This should make up for any +extra costs due to aligning to 64 bytes. + +In general performance before deviated a great deal dependending on +whether entry alignment % 64 was 0, 16, 32, or 48. These changes +essentially make it so that the current implementation is at least +equal to the best alignment of the original for any arguments. + +The only additional optimization is in the page cross case. Branch on +equals case was removed from the size == [4, 7] case. As well the [4, +7] and [2, 3] case where swapped as [4, 7] is likely a more hot +argument size. + +test-memcmp and test-wmemcmp are both passing. +--- + sysdeps/x86_64/multiarch/memcmp-evex-movbe.S | 434 +++++++++++-------- + 1 file changed, 242 insertions(+), 192 deletions(-) + +diff --git a/sysdeps/x86_64/multiarch/memcmp-evex-movbe.S b/sysdeps/x86_64/multiarch/memcmp-evex-movbe.S +index 654dc7ac..2761b54f 100644 +--- a/sysdeps/x86_64/multiarch/memcmp-evex-movbe.S ++++ b/sysdeps/x86_64/multiarch/memcmp-evex-movbe.S +@@ -34,7 +34,24 @@ + area. + 7. Use 2 vector compares when size is 2 * CHAR_PER_VEC or less. + 8. Use 4 vector compares when size is 4 * CHAR_PER_VEC or less. +- 9. Use 8 vector compares when size is 8 * CHAR_PER_VEC or less. */ ++ 9. Use 8 vector compares when size is 8 * CHAR_PER_VEC or less. ++ ++When possible the implementation tries to optimize for frontend in the ++following ways: ++Throughput: ++ 1. All code sections that fit are able to run optimally out of the ++ LSD. ++ 2. All code sections that fit are able to run optimally out of the ++ DSB ++ 3. Basic blocks are contained in minimum number of fetch blocks ++ necessary. ++ ++Latency: ++ 1. Logically connected basic blocks are put in the same ++ cache-line. ++ 2. Logically connected basic blocks that do not fit in the same ++ cache-line are put in adjacent lines. This can get beneficial ++ L2 spatial prefetching and L1 next-line prefetching. */ + + # include + +@@ -47,9 +64,11 @@ + # ifdef USE_AS_WMEMCMP + # define CHAR_SIZE 4 + # define VPCMP vpcmpd ++# define VPTEST vptestmd + # else + # define CHAR_SIZE 1 + # define VPCMP vpcmpub ++# define VPTEST vptestmb + # endif + + # define VEC_SIZE 32 +@@ -75,7 +94,9 @@ + */ + + .section .text.evex,"ax",@progbits +-ENTRY (MEMCMP) ++/* Cache align memcmp entry. This allows for much more thorough ++ frontend optimization. */ ++ENTRY_P2ALIGN (MEMCMP, 6) + # ifdef __ILP32__ + /* Clear the upper 32 bits. */ + movl %edx, %edx +@@ -89,7 +110,7 @@ ENTRY (MEMCMP) + VPCMP $4, (%rdi), %YMM1, %k1 + kmovd %k1, %eax + /* NB: eax must be destination register if going to +- L(return_vec_[0,2]). For L(return_vec_3 destination register ++ L(return_vec_[0,2]). For L(return_vec_3) destination register + must be ecx. */ + testl %eax, %eax + jnz L(return_vec_0) +@@ -121,10 +142,6 @@ ENTRY (MEMCMP) + testl %ecx, %ecx + jnz L(return_vec_3) + +- /* Zero YMM0. 4x VEC reduction is done with vpxor + vtern so +- compare with zero to get a mask is needed. */ +- vpxorq %XMM0, %XMM0, %XMM0 +- + /* Go to 4x VEC loop. */ + cmpq $(CHAR_PER_VEC * 8), %rdx + ja L(more_8x_vec) +@@ -148,47 +165,61 @@ ENTRY (MEMCMP) + + VMOVU (VEC_SIZE * 2)(%rsi), %YMM3 + vpxorq (VEC_SIZE * 2)(%rdi), %YMM3, %YMM3 +- /* Or together YMM1, YMM2, and YMM3 into YMM3. */ +- vpternlogd $0xfe, %YMM1, %YMM2, %YMM3 + + VMOVU (VEC_SIZE * 3)(%rsi), %YMM4 + /* Ternary logic to xor (VEC_SIZE * 3)(%rdi) with YMM4 while +- oring with YMM3. Result is stored in YMM4. */ +- vpternlogd $0xde, (VEC_SIZE * 3)(%rdi), %YMM3, %YMM4 +- /* Compare YMM4 with 0. If any 1s s1 and s2 don't match. */ +- VPCMP $4, %YMM4, %YMM0, %k1 ++ oring with YMM1. Result is stored in YMM4. */ ++ vpternlogd $0xde, (VEC_SIZE * 3)(%rdi), %YMM1, %YMM4 ++ ++ /* Or together YMM2, YMM3, and YMM4 into YMM4. */ ++ vpternlogd $0xfe, %YMM2, %YMM3, %YMM4 ++ ++ /* Test YMM4 against itself. Store any CHAR mismatches in k1. ++ */ ++ VPTEST %YMM4, %YMM4, %k1 ++ /* k1 must go to ecx for L(return_vec_0_1_2_3). */ + kmovd %k1, %ecx + testl %ecx, %ecx + jnz L(return_vec_0_1_2_3) + /* NB: eax must be zero to reach here. */ + ret + +- /* NB: aligning 32 here allows for the rest of the jump targets +- to be tuned for 32 byte alignment. Most important this ensures +- the L(more_8x_vec) loop is 32 byte aligned. */ +- .p2align 5 +-L(less_vec): +- /* Check if one or less CHAR. This is necessary for size = 0 but +- is also faster for size = CHAR_SIZE. */ +- cmpl $1, %edx +- jbe L(one_or_less) ++ .p2align 4 ++L(8x_end_return_vec_0_1_2_3): ++ movq %rdx, %rdi ++L(8x_return_vec_0_1_2_3): ++ addq %rdi, %rsi ++L(return_vec_0_1_2_3): ++ VPTEST %YMM1, %YMM1, %k0 ++ kmovd %k0, %eax ++ testl %eax, %eax ++ jnz L(return_vec_0) + +- /* Check if loading one VEC from either s1 or s2 could cause a +- page cross. This can have false positives but is by far the +- fastest method. */ +- movl %edi, %eax +- orl %esi, %eax +- andl $(PAGE_SIZE - 1), %eax +- cmpl $(PAGE_SIZE - VEC_SIZE), %eax +- jg L(page_cross_less_vec) ++ VPTEST %YMM2, %YMM2, %k0 ++ kmovd %k0, %eax ++ testl %eax, %eax ++ jnz L(return_vec_1) + +- /* No page cross possible. */ +- VMOVU (%rsi), %YMM2 +- VPCMP $4, (%rdi), %YMM2, %k1 +- kmovd %k1, %eax +- /* Create mask in ecx for potentially in bound matches. */ +- bzhil %edx, %eax, %eax +- jnz L(return_vec_0) ++ VPTEST %YMM3, %YMM3, %k0 ++ kmovd %k0, %eax ++ testl %eax, %eax ++ jnz L(return_vec_2) ++L(return_vec_3): ++ /* bsf saves 1 byte from tzcnt. This keep L(return_vec_3) in one ++ fetch block and the entire L(*return_vec_0_1_2_3) in 1 cache ++ line. */ ++ bsfl %ecx, %ecx ++# ifdef USE_AS_WMEMCMP ++ movl (VEC_SIZE * 3)(%rdi, %rcx, CHAR_SIZE), %eax ++ xorl %edx, %edx ++ cmpl (VEC_SIZE * 3)(%rsi, %rcx, CHAR_SIZE), %eax ++ setg %dl ++ leal -1(%rdx, %rdx), %eax ++# else ++ movzbl (VEC_SIZE * 3)(%rdi, %rcx), %eax ++ movzbl (VEC_SIZE * 3)(%rsi, %rcx), %ecx ++ subl %ecx, %eax ++# endif + ret + + .p2align 4 +@@ -209,10 +240,11 @@ L(return_vec_0): + # endif + ret + +- /* NB: No p2align necessary. Alignment % 16 is naturally 1 +- which is good enough for a target not in a loop. */ ++ .p2align 4 + L(return_vec_1): +- tzcntl %eax, %eax ++ /* bsf saves 1 byte over tzcnt and keeps L(return_vec_1) in one ++ fetch block. */ ++ bsfl %eax, %eax + # ifdef USE_AS_WMEMCMP + movl VEC_SIZE(%rdi, %rax, CHAR_SIZE), %ecx + xorl %edx, %edx +@@ -226,10 +258,11 @@ L(return_vec_1): + # endif + ret + +- /* NB: No p2align necessary. Alignment % 16 is naturally 2 +- which is good enough for a target not in a loop. */ ++ .p2align 4,, 10 + L(return_vec_2): +- tzcntl %eax, %eax ++ /* bsf saves 1 byte over tzcnt and keeps L(return_vec_2) in one ++ fetch block. */ ++ bsfl %eax, %eax + # ifdef USE_AS_WMEMCMP + movl (VEC_SIZE * 2)(%rdi, %rax, CHAR_SIZE), %ecx + xorl %edx, %edx +@@ -243,40 +276,6 @@ L(return_vec_2): + # endif + ret + +- .p2align 4 +-L(8x_return_vec_0_1_2_3): +- /* Returning from L(more_8x_vec) requires restoring rsi. */ +- addq %rdi, %rsi +-L(return_vec_0_1_2_3): +- VPCMP $4, %YMM1, %YMM0, %k0 +- kmovd %k0, %eax +- testl %eax, %eax +- jnz L(return_vec_0) +- +- VPCMP $4, %YMM2, %YMM0, %k0 +- kmovd %k0, %eax +- testl %eax, %eax +- jnz L(return_vec_1) +- +- VPCMP $4, %YMM3, %YMM0, %k0 +- kmovd %k0, %eax +- testl %eax, %eax +- jnz L(return_vec_2) +-L(return_vec_3): +- tzcntl %ecx, %ecx +-# ifdef USE_AS_WMEMCMP +- movl (VEC_SIZE * 3)(%rdi, %rcx, CHAR_SIZE), %eax +- xorl %edx, %edx +- cmpl (VEC_SIZE * 3)(%rsi, %rcx, CHAR_SIZE), %eax +- setg %dl +- leal -1(%rdx, %rdx), %eax +-# else +- movzbl (VEC_SIZE * 3)(%rdi, %rcx), %eax +- movzbl (VEC_SIZE * 3)(%rsi, %rcx), %ecx +- subl %ecx, %eax +-# endif +- ret +- + .p2align 4 + L(more_8x_vec): + /* Set end of s1 in rdx. */ +@@ -288,21 +287,19 @@ L(more_8x_vec): + andq $-VEC_SIZE, %rdi + /* Adjust because first 4x vec where check already. */ + subq $-(VEC_SIZE * 4), %rdi ++ + .p2align 4 + L(loop_4x_vec): + VMOVU (%rsi, %rdi), %YMM1 + vpxorq (%rdi), %YMM1, %YMM1 +- + VMOVU VEC_SIZE(%rsi, %rdi), %YMM2 + vpxorq VEC_SIZE(%rdi), %YMM2, %YMM2 +- + VMOVU (VEC_SIZE * 2)(%rsi, %rdi), %YMM3 + vpxorq (VEC_SIZE * 2)(%rdi), %YMM3, %YMM3 +- vpternlogd $0xfe, %YMM1, %YMM2, %YMM3 +- + VMOVU (VEC_SIZE * 3)(%rsi, %rdi), %YMM4 +- vpternlogd $0xde, (VEC_SIZE * 3)(%rdi), %YMM3, %YMM4 +- VPCMP $4, %YMM4, %YMM0, %k1 ++ vpternlogd $0xde, (VEC_SIZE * 3)(%rdi), %YMM1, %YMM4 ++ vpternlogd $0xfe, %YMM2, %YMM3, %YMM4 ++ VPTEST %YMM4, %YMM4, %k1 + kmovd %k1, %ecx + testl %ecx, %ecx + jnz L(8x_return_vec_0_1_2_3) +@@ -319,28 +316,25 @@ L(loop_4x_vec): + cmpl $(VEC_SIZE * 2), %edi + jae L(8x_last_2x_vec) + ++ vpxorq (VEC_SIZE * 2)(%rdx), %YMM3, %YMM3 ++ + VMOVU (%rsi, %rdx), %YMM1 + vpxorq (%rdx), %YMM1, %YMM1 + + VMOVU VEC_SIZE(%rsi, %rdx), %YMM2 + vpxorq VEC_SIZE(%rdx), %YMM2, %YMM2 +- +- vpxorq (VEC_SIZE * 2)(%rdx), %YMM3, %YMM3 +- vpternlogd $0xfe, %YMM1, %YMM2, %YMM3 +- + VMOVU (VEC_SIZE * 3)(%rsi, %rdx), %YMM4 +- vpternlogd $0xde, (VEC_SIZE * 3)(%rdx), %YMM3, %YMM4 +- VPCMP $4, %YMM4, %YMM0, %k1 ++ vpternlogd $0xde, (VEC_SIZE * 3)(%rdx), %YMM1, %YMM4 ++ vpternlogd $0xfe, %YMM2, %YMM3, %YMM4 ++ VPTEST %YMM4, %YMM4, %k1 + kmovd %k1, %ecx +- /* Restore s1 pointer to rdi. */ +- movq %rdx, %rdi + testl %ecx, %ecx +- jnz L(8x_return_vec_0_1_2_3) ++ jnz L(8x_end_return_vec_0_1_2_3) + /* NB: eax must be zero to reach here. */ + ret + + /* Only entry is from L(more_8x_vec). */ +- .p2align 4 ++ .p2align 4,, 10 + L(8x_last_2x_vec): + VPCMP $4, (VEC_SIZE * 2)(%rdx), %YMM3, %k1 + kmovd %k1, %eax +@@ -355,7 +349,31 @@ L(8x_last_1x_vec): + jnz L(8x_return_vec_3) + ret + +- .p2align 4 ++ /* Not ideally aligned (at offset +9 bytes in fetch block) but ++ not aligning keeps it in the same cache line as ++ L(8x_last_1x/2x_vec) so likely worth it. As well, saves code ++ size. */ ++ .p2align 4,, 4 ++L(8x_return_vec_2): ++ subq $VEC_SIZE, %rdx ++L(8x_return_vec_3): ++ bsfl %eax, %eax ++# ifdef USE_AS_WMEMCMP ++ leaq (%rdx, %rax, CHAR_SIZE), %rax ++ movl (VEC_SIZE * 3)(%rax), %ecx ++ xorl %edx, %edx ++ cmpl (VEC_SIZE * 3)(%rsi, %rax), %ecx ++ setg %dl ++ leal -1(%rdx, %rdx), %eax ++# else ++ addq %rdx, %rax ++ movzbl (VEC_SIZE * 3)(%rsi, %rax), %ecx ++ movzbl (VEC_SIZE * 3)(%rax), %eax ++ subl %ecx, %eax ++# endif ++ ret ++ ++ .p2align 4,, 10 + L(last_2x_vec): + /* Check second to last VEC. */ + VMOVU -(VEC_SIZE * 2)(%rsi, %rdx, CHAR_SIZE), %YMM1 +@@ -374,26 +392,49 @@ L(last_1x_vec): + jnz L(return_vec_0_end) + ret + +- .p2align 4 +-L(8x_return_vec_2): +- subq $VEC_SIZE, %rdx +-L(8x_return_vec_3): +- tzcntl %eax, %eax ++ .p2align 4,, 10 ++L(return_vec_1_end): ++ /* Use bsf to save code size. This is necessary to have ++ L(one_or_less) fit in aligning bytes between. */ ++ bsfl %eax, %eax ++ addl %edx, %eax + # ifdef USE_AS_WMEMCMP +- leaq (%rdx, %rax, CHAR_SIZE), %rax +- movl (VEC_SIZE * 3)(%rax), %ecx ++ movl -(VEC_SIZE * 2)(%rdi, %rax, CHAR_SIZE), %ecx + xorl %edx, %edx +- cmpl (VEC_SIZE * 3)(%rsi, %rax), %ecx ++ cmpl -(VEC_SIZE * 2)(%rsi, %rax, CHAR_SIZE), %ecx + setg %dl + leal -1(%rdx, %rdx), %eax + # else +- addq %rdx, %rax +- movzbl (VEC_SIZE * 3)(%rsi, %rax), %ecx +- movzbl (VEC_SIZE * 3)(%rax), %eax ++ movzbl -(VEC_SIZE * 2)(%rsi, %rax), %ecx ++ movzbl -(VEC_SIZE * 2)(%rdi, %rax), %eax + subl %ecx, %eax + # endif + ret + ++ /* NB: L(one_or_less) fits in alignment padding between ++ L(return_vec_1_end) and L(return_vec_0_end). */ ++# ifdef USE_AS_WMEMCMP ++L(one_or_less): ++ jb L(zero) ++ movl (%rdi), %ecx ++ xorl %edx, %edx ++ cmpl (%rsi), %ecx ++ je L(zero) ++ setg %dl ++ leal -1(%rdx, %rdx), %eax ++ ret ++# else ++L(one_or_less): ++ jb L(zero) ++ movzbl (%rsi), %ecx ++ movzbl (%rdi), %eax ++ subl %ecx, %eax ++ ret ++# endif ++L(zero): ++ xorl %eax, %eax ++ ret ++ + .p2align 4 + L(return_vec_0_end): + tzcntl %eax, %eax +@@ -412,23 +453,56 @@ L(return_vec_0_end): + ret + + .p2align 4 +-L(return_vec_1_end): ++L(less_vec): ++ /* Check if one or less CHAR. This is necessary for size == 0 ++ but is also faster for size == CHAR_SIZE. */ ++ cmpl $1, %edx ++ jbe L(one_or_less) ++ ++ /* Check if loading one VEC from either s1 or s2 could cause a ++ page cross. This can have false positives but is by far the ++ fastest method. */ ++ movl %edi, %eax ++ orl %esi, %eax ++ andl $(PAGE_SIZE - 1), %eax ++ cmpl $(PAGE_SIZE - VEC_SIZE), %eax ++ jg L(page_cross_less_vec) ++ ++ /* No page cross possible. */ ++ VMOVU (%rsi), %YMM2 ++ VPCMP $4, (%rdi), %YMM2, %k1 ++ kmovd %k1, %eax ++ /* Check if any matches where in bounds. Intentionally not ++ storing result in eax to limit dependency chain if it goes to ++ L(return_vec_0_lv). */ ++ bzhil %edx, %eax, %edx ++ jnz L(return_vec_0_lv) ++ xorl %eax, %eax ++ ret ++ ++ /* Essentially duplicate of L(return_vec_0). Ends up not costing ++ any code as shrinks L(less_vec) by allowing 2-byte encoding of ++ the jump and ends up fitting in aligning bytes. As well fits on ++ same cache line as L(less_vec) so also saves a line from having ++ to be fetched on cold calls to memcmp. */ ++ .p2align 4,, 4 ++L(return_vec_0_lv): + tzcntl %eax, %eax +- addl %edx, %eax + # ifdef USE_AS_WMEMCMP +- movl -(VEC_SIZE * 2)(%rdi, %rax, CHAR_SIZE), %ecx ++ movl (%rdi, %rax, CHAR_SIZE), %ecx + xorl %edx, %edx +- cmpl -(VEC_SIZE * 2)(%rsi, %rax, CHAR_SIZE), %ecx ++ cmpl (%rsi, %rax, CHAR_SIZE), %ecx ++ /* NB: no partial register stall here because xorl zero idiom ++ above. */ + setg %dl + leal -1(%rdx, %rdx), %eax + # else +- movzbl -(VEC_SIZE * 2)(%rsi, %rax), %ecx +- movzbl -(VEC_SIZE * 2)(%rdi, %rax), %eax ++ movzbl (%rsi, %rax), %ecx ++ movzbl (%rdi, %rax), %eax + subl %ecx, %eax + # endif + ret + +- + .p2align 4 + L(page_cross_less_vec): + /* if USE_AS_WMEMCMP it can only be 0, 4, 8, 12, 16, 20, 24, 28 +@@ -439,108 +513,84 @@ L(page_cross_less_vec): + cmpl $8, %edx + jae L(between_8_15) + cmpl $4, %edx +- jae L(between_4_7) +-L(between_2_3): +- /* Load as big endian to avoid branches. */ +- movzwl (%rdi), %eax +- movzwl (%rsi), %ecx +- shll $8, %eax +- shll $8, %ecx +- bswap %eax +- bswap %ecx +- movzbl -1(%rdi, %rdx), %edi +- movzbl -1(%rsi, %rdx), %esi +- orl %edi, %eax +- orl %esi, %ecx +- /* Subtraction is okay because the upper 8 bits are zero. */ +- subl %ecx, %eax +- ret +- .p2align 4 +-L(one_or_less): +- jb L(zero) +- movzbl (%rsi), %ecx +- movzbl (%rdi), %eax +- subl %ecx, %eax ++ jb L(between_2_3) ++ ++ /* Load as big endian with overlapping movbe to avoid branches. ++ */ ++ movbe (%rdi), %eax ++ movbe (%rsi), %ecx ++ shlq $32, %rax ++ shlq $32, %rcx ++ movbe -4(%rdi, %rdx), %edi ++ movbe -4(%rsi, %rdx), %esi ++ orq %rdi, %rax ++ orq %rsi, %rcx ++ subq %rcx, %rax ++ /* edx is guranteed to be positive int32 in range [4, 7]. */ ++ cmovne %edx, %eax ++ /* ecx is -1 if rcx > rax. Otherwise 0. */ ++ sbbl %ecx, %ecx ++ /* If rcx > rax, then ecx is 0 and eax is positive. If rcx == ++ rax then eax and ecx are zero. If rax < rax then ecx is -1 so ++ eax doesn't matter. */ ++ orl %ecx, %eax + ret + +- .p2align 4 ++ .p2align 4,, 8 + L(between_8_15): + # endif + /* If USE_AS_WMEMCMP fall through into 8-15 byte case. */ +- vmovq (%rdi), %XMM1 +- vmovq (%rsi), %XMM2 +- VPCMP $4, %XMM1, %XMM2, %k1 ++ vmovq (%rdi), %xmm1 ++ vmovq (%rsi), %xmm2 ++ VPCMP $4, %xmm1, %xmm2, %k1 + kmovd %k1, %eax + testl %eax, %eax +- jnz L(return_vec_0) ++ jnz L(return_vec_0_lv) + /* Use overlapping loads to avoid branches. */ +- leaq -8(%rdi, %rdx, CHAR_SIZE), %rdi +- leaq -8(%rsi, %rdx, CHAR_SIZE), %rsi +- vmovq (%rdi), %XMM1 +- vmovq (%rsi), %XMM2 +- VPCMP $4, %XMM1, %XMM2, %k1 ++ vmovq -8(%rdi, %rdx, CHAR_SIZE), %xmm1 ++ vmovq -8(%rsi, %rdx, CHAR_SIZE), %xmm2 ++ VPCMP $4, %xmm1, %xmm2, %k1 ++ addl $(CHAR_PER_VEC - (8 / CHAR_SIZE)), %edx + kmovd %k1, %eax + testl %eax, %eax +- jnz L(return_vec_0) +- ret +- +- .p2align 4 +-L(zero): +- xorl %eax, %eax ++ jnz L(return_vec_0_end) + ret + +- .p2align 4 ++ .p2align 4,, 8 + L(between_16_31): + /* From 16 to 31 bytes. No branch when size == 16. */ +- VMOVU (%rsi), %XMM2 +- VPCMP $4, (%rdi), %XMM2, %k1 ++ ++ /* Use movups to save code size. */ ++ movups (%rsi), %xmm2 ++ VPCMP $4, (%rdi), %xmm2, %k1 + kmovd %k1, %eax + testl %eax, %eax +- jnz L(return_vec_0) +- ++ jnz L(return_vec_0_lv) + /* Use overlapping loads to avoid branches. */ +- +- VMOVU -16(%rsi, %rdx, CHAR_SIZE), %XMM2 +- leaq -16(%rdi, %rdx, CHAR_SIZE), %rdi +- leaq -16(%rsi, %rdx, CHAR_SIZE), %rsi +- VPCMP $4, (%rdi), %XMM2, %k1 ++ movups -16(%rsi, %rdx, CHAR_SIZE), %xmm2 ++ VPCMP $4, -16(%rdi, %rdx, CHAR_SIZE), %xmm2, %k1 ++ addl $(CHAR_PER_VEC - (16 / CHAR_SIZE)), %edx + kmovd %k1, %eax + testl %eax, %eax +- jnz L(return_vec_0) +- ret +- +-# ifdef USE_AS_WMEMCMP +- .p2align 4 +-L(one_or_less): +- jb L(zero) +- movl (%rdi), %ecx +- xorl %edx, %edx +- cmpl (%rsi), %ecx +- je L(zero) +- setg %dl +- leal -1(%rdx, %rdx), %eax ++ jnz L(return_vec_0_end) + ret +-# else + +- .p2align 4 +-L(between_4_7): +- /* Load as big endian with overlapping movbe to avoid branches. +- */ +- movbe (%rdi), %eax +- movbe (%rsi), %ecx +- shlq $32, %rax +- shlq $32, %rcx +- movbe -4(%rdi, %rdx), %edi +- movbe -4(%rsi, %rdx), %esi +- orq %rdi, %rax +- orq %rsi, %rcx +- subq %rcx, %rax +- jz L(zero_4_7) +- sbbl %eax, %eax +- orl $1, %eax +-L(zero_4_7): ++# ifndef USE_AS_WMEMCMP ++L(between_2_3): ++ /* Load as big endian to avoid branches. */ ++ movzwl (%rdi), %eax ++ movzwl (%rsi), %ecx ++ shll $8, %eax ++ shll $8, %ecx ++ bswap %eax ++ bswap %ecx ++ movzbl -1(%rdi, %rdx), %edi ++ movzbl -1(%rsi, %rdx), %esi ++ orl %edi, %eax ++ orl %esi, %ecx ++ /* Subtraction is okay because the upper 8 bits are zero. */ ++ subl %ecx, %eax + ret + # endif +- + END (MEMCMP) + #endif +-- +GitLab + diff --git a/SOURCES/glibc-RHEL-15696-57.patch b/SOURCES/glibc-RHEL-15696-57.patch new file mode 100644 index 0000000..51d5dd0 --- /dev/null +++ b/SOURCES/glibc-RHEL-15696-57.patch @@ -0,0 +1,510 @@ +From e59ced238482fd71f3e493717f14f6507346741e Mon Sep 17 00:00:00 2001 +From: Noah Goldstein +Date: Mon, 20 Sep 2021 16:20:15 -0500 +Subject: [PATCH] x86: Optimize memset-vec-unaligned-erms.S +Content-type: text/plain; charset=UTF-8 + +No bug. + +Optimization are + +1. change control flow for L(more_2x_vec) to fall through to loop and + jump for L(less_4x_vec) and L(less_8x_vec). This uses less code + size and saves jumps for length > 4x VEC_SIZE. + +2. For EVEX/AVX512 move L(less_vec) closer to entry. + +3. Avoid complex address mode for length > 2x VEC_SIZE + +4. Slightly better aligning code for the loop from the perspective of + code size and uops. + +5. Align targets so they make full use of their fetch block and if + possible cache line. + +6. Try and reduce total number of icache lines that will need to be + pulled in for a given length. + +7. Include "local" version of stosb target. For AVX2/EVEX/AVX512 + jumping to the stosb target in the sse2 code section will almost + certainly be to a new page. The new version does increase code size + marginally by duplicating the target but should get better iTLB + behavior as a result. + +test-memset, test-wmemset, and test-bzero are all passing. + +Signed-off-by: Noah Goldstein +Reviewed-by: H.J. Lu +--- + sysdeps/x86_64/memset.S | 10 +- + .../multiarch/memset-avx2-unaligned-erms.S | 10 +- + .../multiarch/memset-avx512-unaligned-erms.S | 11 +- + .../multiarch/memset-evex-unaligned-erms.S | 11 +- + .../multiarch/memset-vec-unaligned-erms.S | 285 ++++++++++++------ + 5 files changed, 232 insertions(+), 95 deletions(-) + +Conflicts: + sysdeps/x86_64/memset.S + (GNU URL) + +diff --git a/sysdeps/x86_64/memset.S b/sysdeps/x86_64/memset.S +index b3426795..8672b030 100644 +--- a/sysdeps/x86_64/memset.S ++++ b/sysdeps/x86_64/memset.S +@@ -18,13 +18,15 @@ + . */ + + #include ++#define USE_WITH_SSE2 1 + + #define VEC_SIZE 16 ++#define MOV_SIZE 3 ++#define RET_SIZE 1 ++ + #define VEC(i) xmm##i +-/* Don't use movups and movaps since it will get larger nop paddings for +- alignment. */ +-#define VMOVU movdqu +-#define VMOVA movdqa ++#define VMOVU movups ++#define VMOVA movaps + + #define MEMSET_VDUP_TO_VEC0_AND_SET_RETURN(d, r) \ + movd d, %xmm0; \ +diff --git a/sysdeps/x86_64/multiarch/memset-avx2-unaligned-erms.S b/sysdeps/x86_64/multiarch/memset-avx2-unaligned-erms.S +index ae0860f3..1af668af 100644 +--- a/sysdeps/x86_64/multiarch/memset-avx2-unaligned-erms.S ++++ b/sysdeps/x86_64/multiarch/memset-avx2-unaligned-erms.S +@@ -1,8 +1,14 @@ + #if IS_IN (libc) ++# define USE_WITH_AVX2 1 ++ + # define VEC_SIZE 32 ++# define MOV_SIZE 4 ++# define RET_SIZE 4 ++ + # define VEC(i) ymm##i +-# define VMOVU vmovdqu +-# define VMOVA vmovdqa ++ ++# define VMOVU vmovdqu ++# define VMOVA vmovdqa + + # define MEMSET_VDUP_TO_VEC0_AND_SET_RETURN(d, r) \ + vmovd d, %xmm0; \ +diff --git a/sysdeps/x86_64/multiarch/memset-avx512-unaligned-erms.S b/sysdeps/x86_64/multiarch/memset-avx512-unaligned-erms.S +index 8ad842fc..f14d6f84 100644 +--- a/sysdeps/x86_64/multiarch/memset-avx512-unaligned-erms.S ++++ b/sysdeps/x86_64/multiarch/memset-avx512-unaligned-erms.S +@@ -1,11 +1,18 @@ + #if IS_IN (libc) ++# define USE_WITH_AVX512 1 ++ + # define VEC_SIZE 64 ++# define MOV_SIZE 6 ++# define RET_SIZE 1 ++ + # define XMM0 xmm16 + # define YMM0 ymm16 + # define VEC0 zmm16 + # define VEC(i) VEC##i +-# define VMOVU vmovdqu64 +-# define VMOVA vmovdqa64 ++ ++# define VMOVU vmovdqu64 ++# define VMOVA vmovdqa64 ++ + # define VZEROUPPER + + # define MEMSET_VDUP_TO_VEC0_AND_SET_RETURN(d, r) \ +diff --git a/sysdeps/x86_64/multiarch/memset-evex-unaligned-erms.S b/sysdeps/x86_64/multiarch/memset-evex-unaligned-erms.S +index 640f0929..64b09e77 100644 +--- a/sysdeps/x86_64/multiarch/memset-evex-unaligned-erms.S ++++ b/sysdeps/x86_64/multiarch/memset-evex-unaligned-erms.S +@@ -1,11 +1,18 @@ + #if IS_IN (libc) ++# define USE_WITH_EVEX 1 ++ + # define VEC_SIZE 32 ++# define MOV_SIZE 6 ++# define RET_SIZE 1 ++ + # define XMM0 xmm16 + # define YMM0 ymm16 + # define VEC0 ymm16 + # define VEC(i) VEC##i +-# define VMOVU vmovdqu64 +-# define VMOVA vmovdqa64 ++ ++# define VMOVU vmovdqu64 ++# define VMOVA vmovdqa64 ++ + # define VZEROUPPER + + # define MEMSET_VDUP_TO_VEC0_AND_SET_RETURN(d, r) \ +diff --git a/sysdeps/x86_64/multiarch/memset-vec-unaligned-erms.S b/sysdeps/x86_64/multiarch/memset-vec-unaligned-erms.S +index 909c33f6..f08b7323 100644 +--- a/sysdeps/x86_64/multiarch/memset-vec-unaligned-erms.S ++++ b/sysdeps/x86_64/multiarch/memset-vec-unaligned-erms.S +@@ -63,8 +63,27 @@ + # endif + #endif + ++#if VEC_SIZE == 64 ++# define LOOP_4X_OFFSET (VEC_SIZE * 4) ++#else ++# define LOOP_4X_OFFSET (0) ++#endif ++ ++#if defined USE_WITH_EVEX || defined USE_WITH_AVX512 ++# define END_REG rcx ++# define LOOP_REG rdi ++#else ++# define END_REG rdi ++# define LOOP_REG rdx ++#endif ++ + #define PAGE_SIZE 4096 + ++/* Macro to calculate size of small memset block for aligning ++ purposes. */ ++#define SMALL_MEMSET_ALIGN(mov_sz, ret_sz) (2 * (mov_sz) + (ret_sz) + 1) ++ ++ + #ifndef SECTION + # error SECTION is not defined! + #endif +@@ -74,6 +93,7 @@ + ENTRY (__bzero) + mov %RDI_LP, %RAX_LP /* Set return value. */ + mov %RSI_LP, %RDX_LP /* Set n. */ ++ xorl %esi, %esi + pxor %XMM0, %XMM0 + jmp L(entry_from_bzero) + END (__bzero) +@@ -158,7 +178,7 @@ ENTRY_CHK (MEMSET_CHK_SYMBOL (__memset_chk, unaligned_erms)) + END_CHK (MEMSET_CHK_SYMBOL (__memset_chk, unaligned_erms)) + # endif + +-ENTRY (MEMSET_SYMBOL (__memset, unaligned_erms)) ++ENTRY_P2ALIGN (MEMSET_SYMBOL (__memset, unaligned_erms), 6) + MEMSET_VDUP_TO_VEC0_AND_SET_RETURN (%esi, %rdi) + # ifdef __ILP32__ + /* Clear the upper 32 bits. */ +@@ -168,75 +188,43 @@ ENTRY (MEMSET_SYMBOL (__memset, unaligned_erms)) + jb L(less_vec) + cmp $(VEC_SIZE * 2), %RDX_LP + ja L(stosb_more_2x_vec) +- /* From VEC and to 2 * VEC. No branch when size == VEC_SIZE. */ +- VMOVU %VEC(0), -VEC_SIZE(%rdi,%rdx) +- VMOVU %VEC(0), (%rdi) ++ /* From VEC and to 2 * VEC. No branch when size == VEC_SIZE. ++ */ ++ VMOVU %VEC(0), (%rax) ++ VMOVU %VEC(0), -VEC_SIZE(%rax, %rdx) + VZEROUPPER_RETURN +- +- .p2align 4 +-L(stosb_more_2x_vec): +- cmp __x86_rep_stosb_threshold(%rip), %RDX_LP +- ja L(stosb) +-#else +- .p2align 4 + #endif +-L(more_2x_vec): +- /* Stores to first 2x VEC before cmp as any path forward will +- require it. */ +- VMOVU %VEC(0), (%rdi) +- VMOVU %VEC(0), VEC_SIZE(%rdi) +- cmpq $(VEC_SIZE * 4), %rdx +- ja L(loop_start) +- VMOVU %VEC(0), -(VEC_SIZE * 2)(%rdi,%rdx) +- VMOVU %VEC(0), -VEC_SIZE(%rdi,%rdx) +-L(return): +-#if VEC_SIZE > 16 +- ZERO_UPPER_VEC_REGISTERS_RETURN ++ ++ .p2align 4,, 10 ++L(last_2x_vec): ++#ifdef USE_LESS_VEC_MASK_STORE ++ VMOVU %VEC(0), (VEC_SIZE * 2 + LOOP_4X_OFFSET)(%rcx) ++ VMOVU %VEC(0), (VEC_SIZE * 3 + LOOP_4X_OFFSET)(%rcx) + #else +- ret ++ VMOVU %VEC(0), (VEC_SIZE * -2)(%rdi) ++ VMOVU %VEC(0), (VEC_SIZE * -1)(%rdi) + #endif ++ VZEROUPPER_RETURN + +-L(loop_start): +- VMOVU %VEC(0), (VEC_SIZE * 2)(%rdi) +- VMOVU %VEC(0), (VEC_SIZE * 3)(%rdi) +- cmpq $(VEC_SIZE * 8), %rdx +- jbe L(loop_end) +- andq $-(VEC_SIZE * 2), %rdi +- subq $-(VEC_SIZE * 4), %rdi +- leaq -(VEC_SIZE * 4)(%rax, %rdx), %rcx +- .p2align 4 +-L(loop): +- VMOVA %VEC(0), (%rdi) +- VMOVA %VEC(0), VEC_SIZE(%rdi) +- VMOVA %VEC(0), (VEC_SIZE * 2)(%rdi) +- VMOVA %VEC(0), (VEC_SIZE * 3)(%rdi) +- subq $-(VEC_SIZE * 4), %rdi +- cmpq %rcx, %rdi +- jb L(loop) +-L(loop_end): +- /* NB: rax is set as ptr in MEMSET_VDUP_TO_VEC0_AND_SET_RETURN. +- rdx as length is also unchanged. */ +- VMOVU %VEC(0), -(VEC_SIZE * 4)(%rax, %rdx) +- VMOVU %VEC(0), -(VEC_SIZE * 3)(%rax, %rdx) +- VMOVU %VEC(0), -(VEC_SIZE * 2)(%rax, %rdx) +- VMOVU %VEC(0), -VEC_SIZE(%rax, %rdx) +- VZEROUPPER_SHORT_RETURN +- +- .p2align 4 ++ /* If have AVX512 mask instructions put L(less_vec) close to ++ entry as it doesn't take much space and is likely a hot target. ++ */ ++#ifdef USE_LESS_VEC_MASK_STORE ++ .p2align 4,, 10 + L(less_vec): + /* Less than 1 VEC. */ + # if VEC_SIZE != 16 && VEC_SIZE != 32 && VEC_SIZE != 64 + # error Unsupported VEC_SIZE! + # endif +-# ifdef USE_LESS_VEC_MASK_STORE + /* Clear high bits from edi. Only keeping bits relevant to page + cross check. Note that we are using rax which is set in +- MEMSET_VDUP_TO_VEC0_AND_SET_RETURN as ptr from here on out. +- */ ++ MEMSET_VDUP_TO_VEC0_AND_SET_RETURN as ptr from here on out. */ + andl $(PAGE_SIZE - 1), %edi +- /* Check if VEC_SIZE store cross page. Mask stores suffer serious +- performance degradation when it has to fault supress. */ ++ /* Check if VEC_SIZE store cross page. Mask stores suffer ++ serious performance degradation when it has to fault supress. ++ */ + cmpl $(PAGE_SIZE - VEC_SIZE), %edi ++ /* This is generally considered a cold target. */ + ja L(cross_page) + # if VEC_SIZE > 32 + movq $-1, %rcx +@@ -247,58 +235,185 @@ L(less_vec): + bzhil %edx, %ecx, %ecx + kmovd %ecx, %k1 + # endif +- vmovdqu8 %VEC(0), (%rax) {%k1} ++ vmovdqu8 %VEC(0), (%rax){%k1} + VZEROUPPER_RETURN + ++# if defined USE_MULTIARCH && IS_IN (libc) ++ /* Include L(stosb_local) here if including L(less_vec) between ++ L(stosb_more_2x_vec) and ENTRY. This is to cache align the ++ L(stosb_more_2x_vec) target. */ ++ .p2align 4,, 10 ++L(stosb_local): ++ movzbl %sil, %eax ++ mov %RDX_LP, %RCX_LP ++ mov %RDI_LP, %RDX_LP ++ rep stosb ++ mov %RDX_LP, %RAX_LP ++ VZEROUPPER_RETURN ++# endif ++#endif ++ ++#if defined USE_MULTIARCH && IS_IN (libc) + .p2align 4 +-L(cross_page): ++L(stosb_more_2x_vec): ++ cmp __x86_rep_stosb_threshold(%rip), %RDX_LP ++ ja L(stosb_local) ++#endif ++ /* Fallthrough goes to L(loop_4x_vec). Tests for memset (2x, 4x] ++ and (4x, 8x] jump to target. */ ++L(more_2x_vec): ++ ++ /* Two different methods of setting up pointers / compare. The ++ two methods are based on the fact that EVEX/AVX512 mov ++ instructions take more bytes then AVX2/SSE2 mov instructions. As ++ well that EVEX/AVX512 machines also have fast LEA_BID. Both ++ setup and END_REG to avoid complex address mode. For EVEX/AVX512 ++ this saves code size and keeps a few targets in one fetch block. ++ For AVX2/SSE2 this helps prevent AGU bottlenecks. */ ++#if defined USE_WITH_EVEX || defined USE_WITH_AVX512 ++ /* If EVEX/AVX512 compute END_REG - (VEC_SIZE * 4 + ++ LOOP_4X_OFFSET) with LEA_BID. */ ++ ++ /* END_REG is rcx for EVEX/AVX512. */ ++ leaq -(VEC_SIZE * 4 + LOOP_4X_OFFSET)(%rdi, %rdx), %END_REG ++#endif ++ ++ /* Stores to first 2x VEC before cmp as any path forward will ++ require it. */ ++ VMOVU %VEC(0), (%rax) ++ VMOVU %VEC(0), VEC_SIZE(%rax) ++ ++ ++#if !(defined USE_WITH_EVEX || defined USE_WITH_AVX512) ++ /* If AVX2/SSE2 compute END_REG (rdi) with ALU. */ ++ addq %rdx, %END_REG ++#endif ++ ++ cmpq $(VEC_SIZE * 4), %rdx ++ jbe L(last_2x_vec) ++ ++ /* Store next 2x vec regardless. */ ++ VMOVU %VEC(0), (VEC_SIZE * 2)(%rax) ++ VMOVU %VEC(0), (VEC_SIZE * 3)(%rax) ++ ++ ++#if defined USE_WITH_EVEX || defined USE_WITH_AVX512 ++ /* If LOOP_4X_OFFSET don't readjust LOOP_REG (rdi), just add ++ extra offset to addresses in loop. Used for AVX512 to save space ++ as no way to get (VEC_SIZE * 4) in imm8. */ ++# if LOOP_4X_OFFSET == 0 ++ subq $-(VEC_SIZE * 4), %LOOP_REG + # endif +-# if VEC_SIZE > 32 +- cmpb $32, %dl +- jae L(between_32_63) ++ /* Avoid imm32 compare here to save code size. */ ++ cmpq %rdi, %rcx ++#else ++ addq $-(VEC_SIZE * 4), %END_REG ++ cmpq $(VEC_SIZE * 8), %rdx ++#endif ++ jbe L(last_4x_vec) ++#if !(defined USE_WITH_EVEX || defined USE_WITH_AVX512) ++ /* Set LOOP_REG (rdx). */ ++ leaq (VEC_SIZE * 4)(%rax), %LOOP_REG ++#endif ++ /* Align dst for loop. */ ++ andq $(VEC_SIZE * -2), %LOOP_REG ++ .p2align 4 ++L(loop): ++ VMOVA %VEC(0), LOOP_4X_OFFSET(%LOOP_REG) ++ VMOVA %VEC(0), (VEC_SIZE + LOOP_4X_OFFSET)(%LOOP_REG) ++ VMOVA %VEC(0), (VEC_SIZE * 2 + LOOP_4X_OFFSET)(%LOOP_REG) ++ VMOVA %VEC(0), (VEC_SIZE * 3 + LOOP_4X_OFFSET)(%LOOP_REG) ++ subq $-(VEC_SIZE * 4), %LOOP_REG ++ cmpq %END_REG, %LOOP_REG ++ jb L(loop) ++ .p2align 4,, MOV_SIZE ++L(last_4x_vec): ++ VMOVU %VEC(0), LOOP_4X_OFFSET(%END_REG) ++ VMOVU %VEC(0), (VEC_SIZE + LOOP_4X_OFFSET)(%END_REG) ++ VMOVU %VEC(0), (VEC_SIZE * 2 + LOOP_4X_OFFSET)(%END_REG) ++ VMOVU %VEC(0), (VEC_SIZE * 3 + LOOP_4X_OFFSET)(%END_REG) ++L(return): ++#if VEC_SIZE > 16 ++ ZERO_UPPER_VEC_REGISTERS_RETURN ++#else ++ ret ++#endif ++ ++ .p2align 4,, 10 ++#ifndef USE_LESS_VEC_MASK_STORE ++# if defined USE_MULTIARCH && IS_IN (libc) ++ /* If no USE_LESS_VEC_MASK put L(stosb_local) here. Will be in ++ range for 2-byte jump encoding. */ ++L(stosb_local): ++ movzbl %sil, %eax ++ mov %RDX_LP, %RCX_LP ++ mov %RDI_LP, %RDX_LP ++ rep stosb ++ mov %RDX_LP, %RAX_LP ++ VZEROUPPER_RETURN + # endif +-# if VEC_SIZE > 16 +- cmpb $16, %dl ++ /* Define L(less_vec) only if not otherwise defined. */ ++ .p2align 4 ++L(less_vec): ++#endif ++L(cross_page): ++#if VEC_SIZE > 32 ++ cmpl $32, %edx ++ jae L(between_32_63) ++#endif ++#if VEC_SIZE > 16 ++ cmpl $16, %edx + jae L(between_16_31) +-# endif +- MOVQ %XMM0, %rcx +- cmpb $8, %dl ++#endif ++ MOVQ %XMM0, %rdi ++ cmpl $8, %edx + jae L(between_8_15) +- cmpb $4, %dl ++ cmpl $4, %edx + jae L(between_4_7) +- cmpb $1, %dl ++ cmpl $1, %edx + ja L(between_2_3) +- jb 1f +- movb %cl, (%rax) +-1: ++ jb L(return) ++ movb %sil, (%rax) + VZEROUPPER_RETURN +-# if VEC_SIZE > 32 ++ ++ /* Align small targets only if not doing so would cross a fetch ++ line. */ ++#if VEC_SIZE > 32 ++ .p2align 4,, SMALL_MEMSET_ALIGN(MOV_SIZE, RET_SIZE) + /* From 32 to 63. No branch when size == 32. */ + L(between_32_63): +- VMOVU %YMM0, -32(%rax,%rdx) + VMOVU %YMM0, (%rax) ++ VMOVU %YMM0, -32(%rax, %rdx) + VZEROUPPER_RETURN +-# endif +-# if VEC_SIZE > 16 +- /* From 16 to 31. No branch when size == 16. */ ++#endif ++ ++#if VEC_SIZE >= 32 ++ .p2align 4,, SMALL_MEMSET_ALIGN(MOV_SIZE, RET_SIZE) + L(between_16_31): +- VMOVU %XMM0, -16(%rax,%rdx) ++ /* From 16 to 31. No branch when size == 16. */ + VMOVU %XMM0, (%rax) ++ VMOVU %XMM0, -16(%rax, %rdx) + VZEROUPPER_RETURN +-# endif +- /* From 8 to 15. No branch when size == 8. */ ++#endif ++ ++ .p2align 4,, SMALL_MEMSET_ALIGN(3, RET_SIZE) + L(between_8_15): +- movq %rcx, -8(%rax,%rdx) +- movq %rcx, (%rax) ++ /* From 8 to 15. No branch when size == 8. */ ++ movq %rdi, (%rax) ++ movq %rdi, -8(%rax, %rdx) + VZEROUPPER_RETURN ++ ++ .p2align 4,, SMALL_MEMSET_ALIGN(2, RET_SIZE) + L(between_4_7): + /* From 4 to 7. No branch when size == 4. */ +- movl %ecx, -4(%rax,%rdx) +- movl %ecx, (%rax) ++ movl %edi, (%rax) ++ movl %edi, -4(%rax, %rdx) + VZEROUPPER_RETURN ++ ++ .p2align 4,, SMALL_MEMSET_ALIGN(3, RET_SIZE) + L(between_2_3): + /* From 2 to 3. No branch when size == 2. */ +- movw %cx, -2(%rax,%rdx) +- movw %cx, (%rax) ++ movw %di, (%rax) ++ movb %dil, -1(%rax, %rdx) + VZEROUPPER_RETURN + END (MEMSET_SYMBOL (__memset, unaligned_erms)) +-- +GitLab + diff --git a/SOURCES/glibc-RHEL-15696-58.patch b/SOURCES/glibc-RHEL-15696-58.patch new file mode 100644 index 0000000..cec0788 --- /dev/null +++ b/SOURCES/glibc-RHEL-15696-58.patch @@ -0,0 +1,45 @@ +From bad852b61b79503fcb3c5fc379c70f768df3e1fb Mon Sep 17 00:00:00 2001 +From: Noah Goldstein +Date: Sat, 23 Oct 2021 01:26:47 -0400 +Subject: [PATCH] x86: Replace sse2 instructions with avx in + memcmp-evex-movbe.S +Content-type: text/plain; charset=UTF-8 + +This commit replaces two usages of SSE2 'movups' with AVX 'vmovdqu'. + +it could potentially be dangerous to use SSE2 if this function is ever +called without using 'vzeroupper' beforehand. While compilers appear +to use 'vzeroupper' before function calls if AVX2 has been used, using +SSE2 here is more brittle. Since it is not absolutely necessary it +should be avoided. + +It costs 2-extra bytes but the extra bytes should only eat into +alignment padding. +Reviewed-by: H.J. Lu +--- + sysdeps/x86_64/multiarch/memcmp-evex-movbe.S | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/sysdeps/x86_64/multiarch/memcmp-evex-movbe.S b/sysdeps/x86_64/multiarch/memcmp-evex-movbe.S +index 2761b54f..640f6757 100644 +--- a/sysdeps/x86_64/multiarch/memcmp-evex-movbe.S ++++ b/sysdeps/x86_64/multiarch/memcmp-evex-movbe.S +@@ -561,13 +561,13 @@ L(between_16_31): + /* From 16 to 31 bytes. No branch when size == 16. */ + + /* Use movups to save code size. */ +- movups (%rsi), %xmm2 ++ vmovdqu (%rsi), %xmm2 + VPCMP $4, (%rdi), %xmm2, %k1 + kmovd %k1, %eax + testl %eax, %eax + jnz L(return_vec_0_lv) + /* Use overlapping loads to avoid branches. */ +- movups -16(%rsi, %rdx, CHAR_SIZE), %xmm2 ++ vmovdqu -16(%rsi, %rdx, CHAR_SIZE), %xmm2 + VPCMP $4, -16(%rdi, %rdx, CHAR_SIZE), %xmm2, %k1 + addl $(CHAR_PER_VEC - (16 / CHAR_SIZE)), %edx + kmovd %k1, %eax +-- +GitLab + diff --git a/SOURCES/glibc-RHEL-15696-59.patch b/SOURCES/glibc-RHEL-15696-59.patch new file mode 100644 index 0000000..efc618c --- /dev/null +++ b/SOURCES/glibc-RHEL-15696-59.patch @@ -0,0 +1,695 @@ +From c46e9afb2df5fc9e39ff4d13777e4b4c26e04e55 Mon Sep 17 00:00:00 2001 +From: "H.J. Lu" +Date: Fri, 29 Oct 2021 12:40:20 -0700 +Subject: [PATCH] x86-64: Improve EVEX strcmp with masked load +Content-type: text/plain; charset=UTF-8 + +In strcmp-evex.S, to compare 2 32-byte strings, replace + + VMOVU (%rdi, %rdx), %YMM0 + VMOVU (%rsi, %rdx), %YMM1 + /* Each bit in K0 represents a mismatch in YMM0 and YMM1. */ + VPCMP $4, %YMM0, %YMM1, %k0 + VPCMP $0, %YMMZERO, %YMM0, %k1 + VPCMP $0, %YMMZERO, %YMM1, %k2 + /* Each bit in K1 represents a NULL in YMM0 or YMM1. */ + kord %k1, %k2, %k1 + /* Each bit in K1 represents a NULL or a mismatch. */ + kord %k0, %k1, %k1 + kmovd %k1, %ecx + testl %ecx, %ecx + jne L(last_vector) + +with + + VMOVU (%rdi, %rdx), %YMM0 + VPTESTM %YMM0, %YMM0, %k2 + /* Each bit cleared in K1 represents a mismatch or a null CHAR + in YMM0 and 32 bytes at (%rsi, %rdx). */ + VPCMP $0, (%rsi, %rdx), %YMM0, %k1{%k2} + kmovd %k1, %ecx + incl %ecx + jne L(last_vector) + +It makes EVEX strcmp faster than AVX2 strcmp by up to 40% on Tiger Lake +and Ice Lake. + +Co-Authored-By: Noah Goldstein +--- + sysdeps/x86_64/multiarch/strcmp-evex.S | 461 +++++++++++++------------ + 1 file changed, 243 insertions(+), 218 deletions(-) + +diff --git a/sysdeps/x86_64/multiarch/strcmp-evex.S b/sysdeps/x86_64/multiarch/strcmp-evex.S +index d5aa6daa..82f12ac8 100644 +--- a/sysdeps/x86_64/multiarch/strcmp-evex.S ++++ b/sysdeps/x86_64/multiarch/strcmp-evex.S +@@ -41,6 +41,8 @@ + # ifdef USE_AS_WCSCMP + /* Compare packed dwords. */ + # define VPCMP vpcmpd ++# define VPMINU vpminud ++# define VPTESTM vptestmd + # define SHIFT_REG32 r8d + # define SHIFT_REG64 r8 + /* 1 dword char == 4 bytes. */ +@@ -48,6 +50,8 @@ + # else + /* Compare packed bytes. */ + # define VPCMP vpcmpb ++# define VPMINU vpminub ++# define VPTESTM vptestmb + # define SHIFT_REG32 ecx + # define SHIFT_REG64 rcx + /* 1 byte char == 1 byte. */ +@@ -67,6 +71,9 @@ + # define YMM5 ymm22 + # define YMM6 ymm23 + # define YMM7 ymm24 ++# define YMM8 ymm25 ++# define YMM9 ymm26 ++# define YMM10 ymm27 + + /* Warning! + wcscmp/wcsncmp have to use SIGNED comparison for elements. +@@ -76,7 +83,7 @@ + /* The main idea of the string comparison (byte or dword) using 256-bit + EVEX instructions consists of comparing (VPCMP) two ymm vectors. The + latter can be on either packed bytes or dwords depending on +- USE_AS_WCSCMP. In order to check the null char, algorithm keeps the ++ USE_AS_WCSCMP. In order to check the null CHAR, algorithm keeps the + matched bytes/dwords, requiring 5 EVEX instructions (3 VPCMP and 2 + KORD). In general, the costs of comparing VEC_SIZE bytes (32-bytes) + are 3 VPCMP and 2 KORD instructions, together with VMOVU and ktestd +@@ -123,27 +130,21 @@ ENTRY (STRCMP) + jg L(cross_page) + /* Start comparing 4 vectors. */ + VMOVU (%rdi), %YMM0 +- VMOVU (%rsi), %YMM1 + +- /* Each bit in K0 represents a mismatch in YMM0 and YMM1. */ +- VPCMP $4, %YMM0, %YMM1, %k0 ++ /* Each bit set in K2 represents a non-null CHAR in YMM0. */ ++ VPTESTM %YMM0, %YMM0, %k2 + +- /* Check for NULL in YMM0. */ +- VPCMP $0, %YMMZERO, %YMM0, %k1 +- /* Check for NULL in YMM1. */ +- VPCMP $0, %YMMZERO, %YMM1, %k2 +- /* Each bit in K1 represents a NULL in YMM0 or YMM1. */ +- kord %k1, %k2, %k1 ++ /* Each bit cleared in K1 represents a mismatch or a null CHAR ++ in YMM0 and 32 bytes at (%rsi). */ ++ VPCMP $0, (%rsi), %YMM0, %k1{%k2} + +- /* Each bit in K1 represents: +- 1. A mismatch in YMM0 and YMM1. Or +- 2. A NULL in YMM0 or YMM1. +- */ +- kord %k0, %k1, %k1 +- +- ktestd %k1, %k1 +- je L(next_3_vectors) + kmovd %k1, %ecx ++# ifdef USE_AS_WCSCMP ++ subl $0xff, %ecx ++# else ++ incl %ecx ++# endif ++ je L(next_3_vectors) + tzcntl %ecx, %edx + # ifdef USE_AS_WCSCMP + /* NB: Multiply wchar_t count by 4 to get the number of bytes. */ +@@ -172,9 +173,7 @@ L(return): + # endif + ret + +- .p2align 4 + L(return_vec_size): +- kmovd %k1, %ecx + tzcntl %ecx, %edx + # ifdef USE_AS_WCSCMP + /* NB: Multiply wchar_t count by 4 to get the number of bytes. */ +@@ -210,9 +209,7 @@ L(return_vec_size): + # endif + ret + +- .p2align 4 + L(return_2_vec_size): +- kmovd %k1, %ecx + tzcntl %ecx, %edx + # ifdef USE_AS_WCSCMP + /* NB: Multiply wchar_t count by 4 to get the number of bytes. */ +@@ -248,9 +245,7 @@ L(return_2_vec_size): + # endif + ret + +- .p2align 4 + L(return_3_vec_size): +- kmovd %k1, %ecx + tzcntl %ecx, %edx + # ifdef USE_AS_WCSCMP + /* NB: Multiply wchar_t count by 4 to get the number of bytes. */ +@@ -289,43 +284,45 @@ L(return_3_vec_size): + .p2align 4 + L(next_3_vectors): + VMOVU VEC_SIZE(%rdi), %YMM0 +- VMOVU VEC_SIZE(%rsi), %YMM1 +- /* Each bit in K0 represents a mismatch in YMM0 and YMM1. */ +- VPCMP $4, %YMM0, %YMM1, %k0 +- VPCMP $0, %YMMZERO, %YMM0, %k1 +- VPCMP $0, %YMMZERO, %YMM1, %k2 +- /* Each bit in K1 represents a NULL in YMM0 or YMM1. */ +- kord %k1, %k2, %k1 +- /* Each bit in K1 represents a NULL or a mismatch. */ +- kord %k0, %k1, %k1 +- ktestd %k1, %k1 ++ /* Each bit set in K2 represents a non-null CHAR in YMM0. */ ++ VPTESTM %YMM0, %YMM0, %k2 ++ /* Each bit cleared in K1 represents a mismatch or a null CHAR ++ in YMM0 and 32 bytes at VEC_SIZE(%rsi). */ ++ VPCMP $0, VEC_SIZE(%rsi), %YMM0, %k1{%k2} ++ kmovd %k1, %ecx ++# ifdef USE_AS_WCSCMP ++ subl $0xff, %ecx ++# else ++ incl %ecx ++# endif + jne L(return_vec_size) + +- VMOVU (VEC_SIZE * 2)(%rdi), %YMM2 +- VMOVU (VEC_SIZE * 3)(%rdi), %YMM3 +- VMOVU (VEC_SIZE * 2)(%rsi), %YMM4 +- VMOVU (VEC_SIZE * 3)(%rsi), %YMM5 +- +- /* Each bit in K0 represents a mismatch in YMM2 and YMM4. */ +- VPCMP $4, %YMM2, %YMM4, %k0 +- VPCMP $0, %YMMZERO, %YMM2, %k1 +- VPCMP $0, %YMMZERO, %YMM4, %k2 +- /* Each bit in K1 represents a NULL in YMM2 or YMM4. */ +- kord %k1, %k2, %k1 +- /* Each bit in K1 represents a NULL or a mismatch. */ +- kord %k0, %k1, %k1 +- ktestd %k1, %k1 ++ VMOVU (VEC_SIZE * 2)(%rdi), %YMM0 ++ /* Each bit set in K2 represents a non-null CHAR in YMM0. */ ++ VPTESTM %YMM0, %YMM0, %k2 ++ /* Each bit cleared in K1 represents a mismatch or a null CHAR ++ in YMM0 and 32 bytes at (VEC_SIZE * 2)(%rsi). */ ++ VPCMP $0, (VEC_SIZE * 2)(%rsi), %YMM0, %k1{%k2} ++ kmovd %k1, %ecx ++# ifdef USE_AS_WCSCMP ++ subl $0xff, %ecx ++# else ++ incl %ecx ++# endif + jne L(return_2_vec_size) + +- /* Each bit in K0 represents a mismatch in YMM3 and YMM5. */ +- VPCMP $4, %YMM3, %YMM5, %k0 +- VPCMP $0, %YMMZERO, %YMM3, %k1 +- VPCMP $0, %YMMZERO, %YMM5, %k2 +- /* Each bit in K1 represents a NULL in YMM3 or YMM5. */ +- kord %k1, %k2, %k1 +- /* Each bit in K1 represents a NULL or a mismatch. */ +- kord %k0, %k1, %k1 +- ktestd %k1, %k1 ++ VMOVU (VEC_SIZE * 3)(%rdi), %YMM0 ++ /* Each bit set in K2 represents a non-null CHAR in YMM0. */ ++ VPTESTM %YMM0, %YMM0, %k2 ++ /* Each bit cleared in K1 represents a mismatch or a null CHAR ++ in YMM0 and 32 bytes at (VEC_SIZE * 2)(%rsi). */ ++ VPCMP $0, (VEC_SIZE * 3)(%rsi), %YMM0, %k1{%k2} ++ kmovd %k1, %ecx ++# ifdef USE_AS_WCSCMP ++ subl $0xff, %ecx ++# else ++ incl %ecx ++# endif + jne L(return_3_vec_size) + L(main_loop_header): + leaq (VEC_SIZE * 4)(%rdi), %rdx +@@ -375,56 +372,51 @@ L(back_to_loop): + VMOVA VEC_SIZE(%rax), %YMM2 + VMOVA (VEC_SIZE * 2)(%rax), %YMM4 + VMOVA (VEC_SIZE * 3)(%rax), %YMM6 +- VMOVU (%rdx), %YMM1 +- VMOVU VEC_SIZE(%rdx), %YMM3 +- VMOVU (VEC_SIZE * 2)(%rdx), %YMM5 +- VMOVU (VEC_SIZE * 3)(%rdx), %YMM7 +- +- VPCMP $4, %YMM0, %YMM1, %k0 +- VPCMP $0, %YMMZERO, %YMM0, %k1 +- VPCMP $0, %YMMZERO, %YMM1, %k2 +- kord %k1, %k2, %k1 +- /* Each bit in K4 represents a NULL or a mismatch in YMM0 and +- YMM1. */ +- kord %k0, %k1, %k4 +- +- VPCMP $4, %YMM2, %YMM3, %k0 +- VPCMP $0, %YMMZERO, %YMM2, %k1 +- VPCMP $0, %YMMZERO, %YMM3, %k2 +- kord %k1, %k2, %k1 +- /* Each bit in K5 represents a NULL or a mismatch in YMM2 and +- YMM3. */ +- kord %k0, %k1, %k5 +- +- VPCMP $4, %YMM4, %YMM5, %k0 +- VPCMP $0, %YMMZERO, %YMM4, %k1 +- VPCMP $0, %YMMZERO, %YMM5, %k2 +- kord %k1, %k2, %k1 +- /* Each bit in K6 represents a NULL or a mismatch in YMM4 and +- YMM5. */ +- kord %k0, %k1, %k6 +- +- VPCMP $4, %YMM6, %YMM7, %k0 +- VPCMP $0, %YMMZERO, %YMM6, %k1 +- VPCMP $0, %YMMZERO, %YMM7, %k2 +- kord %k1, %k2, %k1 +- /* Each bit in K7 represents a NULL or a mismatch in YMM6 and +- YMM7. */ +- kord %k0, %k1, %k7 +- +- kord %k4, %k5, %k0 +- kord %k6, %k7, %k1 +- +- /* Test each mask (32 bits) individually because for VEC_SIZE +- == 32 is not possible to OR the four masks and keep all bits +- in a 64-bit integer register, differing from SSE2 strcmp +- where ORing is possible. */ +- kortestd %k0, %k1 +- je L(loop) +- ktestd %k4, %k4 ++ ++ VPMINU %YMM0, %YMM2, %YMM8 ++ VPMINU %YMM4, %YMM6, %YMM9 ++ ++ /* A zero CHAR in YMM8 means that there is a null CHAR. */ ++ VPMINU %YMM8, %YMM9, %YMM8 ++ ++ /* Each bit set in K1 represents a non-null CHAR in YMM8. */ ++ VPTESTM %YMM8, %YMM8, %k1 ++ ++ /* (YMM ^ YMM): A non-zero CHAR represents a mismatch. */ ++ vpxorq (%rdx), %YMM0, %YMM1 ++ vpxorq VEC_SIZE(%rdx), %YMM2, %YMM3 ++ vpxorq (VEC_SIZE * 2)(%rdx), %YMM4, %YMM5 ++ vpxorq (VEC_SIZE * 3)(%rdx), %YMM6, %YMM7 ++ ++ vporq %YMM1, %YMM3, %YMM9 ++ vporq %YMM5, %YMM7, %YMM10 ++ ++ /* A non-zero CHAR in YMM9 represents a mismatch. */ ++ vporq %YMM9, %YMM10, %YMM9 ++ ++ /* Each bit cleared in K0 represents a mismatch or a null CHAR. */ ++ VPCMP $0, %YMMZERO, %YMM9, %k0{%k1} ++ kmovd %k0, %ecx ++# ifdef USE_AS_WCSCMP ++ subl $0xff, %ecx ++# else ++ incl %ecx ++# endif ++ je L(loop) ++ ++ /* Each bit set in K1 represents a non-null CHAR in YMM0. */ ++ VPTESTM %YMM0, %YMM0, %k1 ++ /* Each bit cleared in K0 represents a mismatch or a null CHAR ++ in YMM0 and (%rdx). */ ++ VPCMP $0, %YMMZERO, %YMM1, %k0{%k1} ++ kmovd %k0, %ecx ++# ifdef USE_AS_WCSCMP ++ subl $0xff, %ecx ++# else ++ incl %ecx ++# endif + je L(test_vec) +- kmovd %k4, %edi +- tzcntl %edi, %ecx ++ tzcntl %ecx, %ecx + # ifdef USE_AS_WCSCMP + /* NB: Multiply wchar_t count by 4 to get the number of bytes. */ + sall $2, %ecx +@@ -466,9 +458,18 @@ L(test_vec): + cmpq $VEC_SIZE, %r11 + jbe L(zero) + # endif +- ktestd %k5, %k5 ++ /* Each bit set in K1 represents a non-null CHAR in YMM2. */ ++ VPTESTM %YMM2, %YMM2, %k1 ++ /* Each bit cleared in K0 represents a mismatch or a null CHAR ++ in YMM2 and VEC_SIZE(%rdx). */ ++ VPCMP $0, %YMMZERO, %YMM3, %k0{%k1} ++ kmovd %k0, %ecx ++# ifdef USE_AS_WCSCMP ++ subl $0xff, %ecx ++# else ++ incl %ecx ++# endif + je L(test_2_vec) +- kmovd %k5, %ecx + tzcntl %ecx, %edi + # ifdef USE_AS_WCSCMP + /* NB: Multiply wchar_t count by 4 to get the number of bytes. */ +@@ -512,9 +513,18 @@ L(test_2_vec): + cmpq $(VEC_SIZE * 2), %r11 + jbe L(zero) + # endif +- ktestd %k6, %k6 ++ /* Each bit set in K1 represents a non-null CHAR in YMM4. */ ++ VPTESTM %YMM4, %YMM4, %k1 ++ /* Each bit cleared in K0 represents a mismatch or a null CHAR ++ in YMM4 and (VEC_SIZE * 2)(%rdx). */ ++ VPCMP $0, %YMMZERO, %YMM5, %k0{%k1} ++ kmovd %k0, %ecx ++# ifdef USE_AS_WCSCMP ++ subl $0xff, %ecx ++# else ++ incl %ecx ++# endif + je L(test_3_vec) +- kmovd %k6, %ecx + tzcntl %ecx, %edi + # ifdef USE_AS_WCSCMP + /* NB: Multiply wchar_t count by 4 to get the number of bytes. */ +@@ -558,8 +568,18 @@ L(test_3_vec): + cmpq $(VEC_SIZE * 3), %r11 + jbe L(zero) + # endif +- kmovd %k7, %esi +- tzcntl %esi, %ecx ++ /* Each bit set in K1 represents a non-null CHAR in YMM6. */ ++ VPTESTM %YMM6, %YMM6, %k1 ++ /* Each bit cleared in K0 represents a mismatch or a null CHAR ++ in YMM6 and (VEC_SIZE * 3)(%rdx). */ ++ VPCMP $0, %YMMZERO, %YMM7, %k0{%k1} ++ kmovd %k0, %ecx ++# ifdef USE_AS_WCSCMP ++ subl $0xff, %ecx ++# else ++ incl %ecx ++# endif ++ tzcntl %ecx, %ecx + # ifdef USE_AS_WCSCMP + /* NB: Multiply wchar_t count by 4 to get the number of bytes. */ + sall $2, %ecx +@@ -615,39 +635,51 @@ L(loop_cross_page): + + VMOVU (%rax, %r10), %YMM2 + VMOVU VEC_SIZE(%rax, %r10), %YMM3 +- VMOVU (%rdx, %r10), %YMM4 +- VMOVU VEC_SIZE(%rdx, %r10), %YMM5 +- +- VPCMP $4, %YMM4, %YMM2, %k0 +- VPCMP $0, %YMMZERO, %YMM2, %k1 +- VPCMP $0, %YMMZERO, %YMM4, %k2 +- kord %k1, %k2, %k1 +- /* Each bit in K1 represents a NULL or a mismatch in YMM2 and +- YMM4. */ +- kord %k0, %k1, %k1 +- +- VPCMP $4, %YMM5, %YMM3, %k3 +- VPCMP $0, %YMMZERO, %YMM3, %k4 +- VPCMP $0, %YMMZERO, %YMM5, %k5 +- kord %k4, %k5, %k4 +- /* Each bit in K3 represents a NULL or a mismatch in YMM3 and +- YMM5. */ +- kord %k3, %k4, %k3 ++ ++ /* Each bit set in K2 represents a non-null CHAR in YMM2. */ ++ VPTESTM %YMM2, %YMM2, %k2 ++ /* Each bit cleared in K1 represents a mismatch or a null CHAR ++ in YMM2 and 32 bytes at (%rdx, %r10). */ ++ VPCMP $0, (%rdx, %r10), %YMM2, %k1{%k2} ++ kmovd %k1, %r9d ++ /* Don't use subl since it is the lower 16/32 bits of RDI ++ below. */ ++ notl %r9d ++# ifdef USE_AS_WCSCMP ++ /* Only last 8 bits are valid. */ ++ andl $0xff, %r9d ++# endif ++ ++ /* Each bit set in K4 represents a non-null CHAR in YMM3. */ ++ VPTESTM %YMM3, %YMM3, %k4 ++ /* Each bit cleared in K3 represents a mismatch or a null CHAR ++ in YMM3 and 32 bytes at VEC_SIZE(%rdx, %r10). */ ++ VPCMP $0, VEC_SIZE(%rdx, %r10), %YMM3, %k3{%k4} ++ kmovd %k3, %edi ++# ifdef USE_AS_WCSCMP ++ /* Don't use subl since it is the upper 8 bits of EDI below. */ ++ notl %edi ++ andl $0xff, %edi ++# else ++ incl %edi ++# endif + + # ifdef USE_AS_WCSCMP +- /* NB: Each bit in K1/K3 represents 4-byte element. */ +- kshiftlw $8, %k3, %k2 ++ /* NB: Each bit in EDI/R9D represents 4-byte element. */ ++ sall $8, %edi + /* NB: Divide shift count by 4 since each bit in K1 represent 4 + bytes. */ + movl %ecx, %SHIFT_REG32 + sarl $2, %SHIFT_REG32 ++ ++ /* Each bit in EDI represents a null CHAR or a mismatch. */ ++ orl %r9d, %edi + # else +- kshiftlq $32, %k3, %k2 +-# endif ++ salq $32, %rdi + +- /* Each bit in K1 represents a NULL or a mismatch. */ +- korq %k1, %k2, %k1 +- kmovq %k1, %rdi ++ /* Each bit in RDI represents a null CHAR or a mismatch. */ ++ orq %r9, %rdi ++# endif + + /* Since ECX < VEC_SIZE * 2, simply skip the first ECX bytes. */ + shrxq %SHIFT_REG64, %rdi, %rdi +@@ -692,35 +724,45 @@ L(loop_cross_page_2_vec): + /* The first VEC_SIZE * 2 bytes match or are ignored. */ + VMOVU (VEC_SIZE * 2)(%rax, %r10), %YMM0 + VMOVU (VEC_SIZE * 3)(%rax, %r10), %YMM1 +- VMOVU (VEC_SIZE * 2)(%rdx, %r10), %YMM2 +- VMOVU (VEC_SIZE * 3)(%rdx, %r10), %YMM3 +- +- VPCMP $4, %YMM0, %YMM2, %k0 +- VPCMP $0, %YMMZERO, %YMM0, %k1 +- VPCMP $0, %YMMZERO, %YMM2, %k2 +- kord %k1, %k2, %k1 +- /* Each bit in K1 represents a NULL or a mismatch in YMM0 and +- YMM2. */ +- kord %k0, %k1, %k1 +- +- VPCMP $4, %YMM1, %YMM3, %k3 +- VPCMP $0, %YMMZERO, %YMM1, %k4 +- VPCMP $0, %YMMZERO, %YMM3, %k5 +- kord %k4, %k5, %k4 +- /* Each bit in K3 represents a NULL or a mismatch in YMM1 and +- YMM3. */ +- kord %k3, %k4, %k3 + ++ VPTESTM %YMM0, %YMM0, %k2 ++ /* Each bit cleared in K1 represents a mismatch or a null CHAR ++ in YMM0 and 32 bytes at (VEC_SIZE * 2)(%rdx, %r10). */ ++ VPCMP $0, (VEC_SIZE * 2)(%rdx, %r10), %YMM0, %k1{%k2} ++ kmovd %k1, %r9d ++ /* Don't use subl since it is the lower 16/32 bits of RDI ++ below. */ ++ notl %r9d + # ifdef USE_AS_WCSCMP +- /* NB: Each bit in K1/K3 represents 4-byte element. */ +- kshiftlw $8, %k3, %k2 ++ /* Only last 8 bits are valid. */ ++ andl $0xff, %r9d ++# endif ++ ++ VPTESTM %YMM1, %YMM1, %k4 ++ /* Each bit cleared in K3 represents a mismatch or a null CHAR ++ in YMM1 and 32 bytes at (VEC_SIZE * 3)(%rdx, %r10). */ ++ VPCMP $0, (VEC_SIZE * 3)(%rdx, %r10), %YMM1, %k3{%k4} ++ kmovd %k3, %edi ++# ifdef USE_AS_WCSCMP ++ /* Don't use subl since it is the upper 8 bits of EDI below. */ ++ notl %edi ++ andl $0xff, %edi + # else +- kshiftlq $32, %k3, %k2 ++ incl %edi + # endif + +- /* Each bit in K1 represents a NULL or a mismatch. */ +- korq %k1, %k2, %k1 +- kmovq %k1, %rdi ++# ifdef USE_AS_WCSCMP ++ /* NB: Each bit in EDI/R9D represents 4-byte element. */ ++ sall $8, %edi ++ ++ /* Each bit in EDI represents a null CHAR or a mismatch. */ ++ orl %r9d, %edi ++# else ++ salq $32, %rdi ++ ++ /* Each bit in RDI represents a null CHAR or a mismatch. */ ++ orq %r9, %rdi ++# endif + + xorl %r8d, %r8d + /* If ECX > VEC_SIZE * 2, skip ECX - (VEC_SIZE * 2) bytes. */ +@@ -729,12 +771,15 @@ L(loop_cross_page_2_vec): + /* R8 has number of bytes skipped. */ + movl %ecx, %r8d + # ifdef USE_AS_WCSCMP +- /* NB: Divide shift count by 4 since each bit in K1 represent 4 ++ /* NB: Divide shift count by 4 since each bit in RDI represent 4 + bytes. */ + sarl $2, %ecx +-# endif ++ /* Skip ECX bytes. */ ++ shrl %cl, %edi ++# else + /* Skip ECX bytes. */ + shrq %cl, %rdi ++# endif + 1: + /* Before jumping back to the loop, set ESI to the number of + VEC_SIZE * 4 blocks before page crossing. */ +@@ -818,7 +863,7 @@ L(cross_page_loop): + movzbl (%rdi, %rdx), %eax + movzbl (%rsi, %rdx), %ecx + # endif +- /* Check null char. */ ++ /* Check null CHAR. */ + testl %eax, %eax + jne L(cross_page_loop) + /* Since %eax == 0, subtract is OK for both SIGNED and UNSIGNED +@@ -901,18 +946,17 @@ L(cross_page): + jg L(cross_page_1_vector) + L(loop_1_vector): + VMOVU (%rdi, %rdx), %YMM0 +- VMOVU (%rsi, %rdx), %YMM1 +- +- /* Each bit in K0 represents a mismatch in YMM0 and YMM1. */ +- VPCMP $4, %YMM0, %YMM1, %k0 +- VPCMP $0, %YMMZERO, %YMM0, %k1 +- VPCMP $0, %YMMZERO, %YMM1, %k2 +- /* Each bit in K1 represents a NULL in YMM0 or YMM1. */ +- kord %k1, %k2, %k1 +- /* Each bit in K1 represents a NULL or a mismatch. */ +- kord %k0, %k1, %k1 ++ ++ VPTESTM %YMM0, %YMM0, %k2 ++ /* Each bit cleared in K1 represents a mismatch or a null CHAR ++ in YMM0 and 32 bytes at (%rsi, %rdx). */ ++ VPCMP $0, (%rsi, %rdx), %YMM0, %k1{%k2} + kmovd %k1, %ecx +- testl %ecx, %ecx ++# ifdef USE_AS_WCSCMP ++ subl $0xff, %ecx ++# else ++ incl %ecx ++# endif + jne L(last_vector) + + addl $VEC_SIZE, %edx +@@ -931,18 +975,17 @@ L(cross_page_1_vector): + cmpl $(PAGE_SIZE - 16), %eax + jg L(cross_page_1_xmm) + VMOVU (%rdi, %rdx), %XMM0 +- VMOVU (%rsi, %rdx), %XMM1 +- +- /* Each bit in K0 represents a mismatch in XMM0 and XMM1. */ +- VPCMP $4, %XMM0, %XMM1, %k0 +- VPCMP $0, %XMMZERO, %XMM0, %k1 +- VPCMP $0, %XMMZERO, %XMM1, %k2 +- /* Each bit in K1 represents a NULL in XMM0 or XMM1. */ +- korw %k1, %k2, %k1 +- /* Each bit in K1 represents a NULL or a mismatch. */ +- korw %k0, %k1, %k1 +- kmovw %k1, %ecx +- testl %ecx, %ecx ++ ++ VPTESTM %YMM0, %YMM0, %k2 ++ /* Each bit cleared in K1 represents a mismatch or a null CHAR ++ in XMM0 and 16 bytes at (%rsi, %rdx). */ ++ VPCMP $0, (%rsi, %rdx), %XMM0, %k1{%k2} ++ kmovd %k1, %ecx ++# ifdef USE_AS_WCSCMP ++ subl $0xf, %ecx ++# else ++ subl $0xffff, %ecx ++# endif + jne L(last_vector) + + addl $16, %edx +@@ -965,25 +1008,16 @@ L(cross_page_1_xmm): + vmovq (%rdi, %rdx), %XMM0 + vmovq (%rsi, %rdx), %XMM1 + +- /* Each bit in K0 represents a mismatch in XMM0 and XMM1. */ +- VPCMP $4, %XMM0, %XMM1, %k0 +- VPCMP $0, %XMMZERO, %XMM0, %k1 +- VPCMP $0, %XMMZERO, %XMM1, %k2 +- /* Each bit in K1 represents a NULL in XMM0 or XMM1. */ +- kord %k1, %k2, %k1 +- /* Each bit in K1 represents a NULL or a mismatch. */ +- kord %k0, %k1, %k1 +- kmovd %k1, %ecx +- ++ VPTESTM %YMM0, %YMM0, %k2 ++ /* Each bit cleared in K1 represents a mismatch or a null CHAR ++ in XMM0 and XMM1. */ ++ VPCMP $0, %XMM1, %XMM0, %k1{%k2} ++ kmovb %k1, %ecx + # ifdef USE_AS_WCSCMP +- /* Only last 2 bits are valid. */ +- andl $0x3, %ecx ++ subl $0x3, %ecx + # else +- /* Only last 8 bits are valid. */ +- andl $0xff, %ecx ++ subl $0xff, %ecx + # endif +- +- testl %ecx, %ecx + jne L(last_vector) + + addl $8, %edx +@@ -1002,25 +1036,16 @@ L(cross_page_8bytes): + vmovd (%rdi, %rdx), %XMM0 + vmovd (%rsi, %rdx), %XMM1 + +- /* Each bit in K0 represents a mismatch in XMM0 and XMM1. */ +- VPCMP $4, %XMM0, %XMM1, %k0 +- VPCMP $0, %XMMZERO, %XMM0, %k1 +- VPCMP $0, %XMMZERO, %XMM1, %k2 +- /* Each bit in K1 represents a NULL in XMM0 or XMM1. */ +- kord %k1, %k2, %k1 +- /* Each bit in K1 represents a NULL or a mismatch. */ +- kord %k0, %k1, %k1 ++ VPTESTM %YMM0, %YMM0, %k2 ++ /* Each bit cleared in K1 represents a mismatch or a null CHAR ++ in XMM0 and XMM1. */ ++ VPCMP $0, %XMM1, %XMM0, %k1{%k2} + kmovd %k1, %ecx +- + # ifdef USE_AS_WCSCMP +- /* Only the last bit is valid. */ +- andl $0x1, %ecx ++ subl $0x1, %ecx + # else +- /* Only last 4 bits are valid. */ +- andl $0xf, %ecx ++ subl $0xf, %ecx + # endif +- +- testl %ecx, %ecx + jne L(last_vector) + + addl $4, %edx +-- +GitLab + diff --git a/SOURCES/glibc-RHEL-15696-6.patch b/SOURCES/glibc-RHEL-15696-6.patch new file mode 100644 index 0000000..f6725a6 --- /dev/null +++ b/SOURCES/glibc-RHEL-15696-6.patch @@ -0,0 +1,300 @@ +From ee915088a0231cd421054dbd8abab7aadf331153 Mon Sep 17 00:00:00 2001 +From: "H.J. Lu" +Date: Mon, 21 Jan 2019 11:33:52 -0800 +Subject: [PATCH] x86-64 strncmp family: Properly handle the length parameter + [BZ# 24097] +Content-type: text/plain; charset=UTF-8 + +On x32, the size_t parameter may be passed in the lower 32 bits of a +64-bit register with the non-zero upper 32 bits. The string/memory +functions written in assembly can only use the lower 32 bits of a +64-bit register as length or must clear the upper 32 bits before using +the full 64-bit register for length. + +This pach fixes the strncmp family for x32. Tested on x86-64 and x32. +On x86-64, libc.so is the same with and withou the fix. + + [BZ# 24097] + CVE-2019-6488 + * sysdeps/x86_64/multiarch/strcmp-avx2.S: Use RDX_LP for length. + * sysdeps/x86_64/multiarch/strcmp-sse42.S: Likewise. + * sysdeps/x86_64/strcmp.S: Likewise. + * sysdeps/x86_64/x32/Makefile (tests): Add tst-size_t-strncasecmp, + tst-size_t-strncmp and tst-size_t-wcsncmp. + * sysdeps/x86_64/x32/tst-size_t-strncasecmp.c: New file. + * sysdeps/x86_64/x32/tst-size_t-strncmp.c: Likewise. + * sysdeps/x86_64/x32/tst-size_t-wcsncmp.c: Likewise. +--- + sysdeps/x86_64/multiarch/strcmp-avx2.S | 6 +- + sysdeps/x86_64/multiarch/strcmp-sse42.S | 6 +- + sysdeps/x86_64/strcmp.S | 6 +- + sysdeps/x86_64/x32/Makefile | 6 +- + sysdeps/x86_64/x32/tst-size_t-strncasecmp.c | 59 ++++++++++++++++ + sysdeps/x86_64/x32/tst-size_t-strncmp.c | 78 +++++++++++++++++++++ + sysdeps/x86_64/x32/tst-size_t-wcsncmp.c | 20 ++++++ + 7 files changed, 170 insertions(+), 11 deletions(-) + create mode 100644 sysdeps/x86_64/x32/tst-size_t-strncasecmp.c + create mode 100644 sysdeps/x86_64/x32/tst-size_t-strncmp.c + create mode 100644 sysdeps/x86_64/x32/tst-size_t-wcsncmp.c + +Conflicts: + ChangeLog + (removed) + +diff --git a/sysdeps/x86_64/multiarch/strcmp-avx2.S b/sysdeps/x86_64/multiarch/strcmp-avx2.S +index 327e3d87..156c1949 100644 +--- a/sysdeps/x86_64/multiarch/strcmp-avx2.S ++++ b/sysdeps/x86_64/multiarch/strcmp-avx2.S +@@ -79,15 +79,15 @@ + ENTRY (STRCMP) + # ifdef USE_AS_STRNCMP + /* Check for simple cases (0 or 1) in offset. */ +- cmp $1, %rdx ++ cmp $1, %RDX_LP + je L(char0) + jb L(zero) + # ifdef USE_AS_WCSCMP + /* Convert units: from wide to byte char. */ +- shl $2, %rdx ++ shl $2, %RDX_LP + # endif + /* Register %r11 tracks the maximum offset. */ +- movq %rdx, %r11 ++ mov %RDX_LP, %R11_LP + # endif + movl %edi, %eax + xorl %edx, %edx +diff --git a/sysdeps/x86_64/multiarch/strcmp-sse42.S b/sysdeps/x86_64/multiarch/strcmp-sse42.S +index d3c07bd2..a1ebea46 100644 +--- a/sysdeps/x86_64/multiarch/strcmp-sse42.S ++++ b/sysdeps/x86_64/multiarch/strcmp-sse42.S +@@ -156,11 +156,11 @@ STRCMP_SSE42: + #endif + + #if defined USE_AS_STRNCMP || defined USE_AS_STRNCASECMP_L +- test %rdx, %rdx ++ test %RDX_LP, %RDX_LP + je LABEL(strcmp_exitz) +- cmp $1, %rdx ++ cmp $1, %RDX_LP + je LABEL(Byte0) +- mov %rdx, %r11 ++ mov %RDX_LP, %R11_LP + #endif + mov %esi, %ecx + mov %edi, %eax +diff --git a/sysdeps/x86_64/strcmp.S b/sysdeps/x86_64/strcmp.S +index e16945b9..f47c8ad4 100644 +--- a/sysdeps/x86_64/strcmp.S ++++ b/sysdeps/x86_64/strcmp.S +@@ -135,11 +135,11 @@ ENTRY (STRCMP) + * This implementation uses SSE to compare up to 16 bytes at a time. + */ + #if defined USE_AS_STRNCMP || defined USE_AS_STRNCASECMP_L +- test %rdx, %rdx ++ test %RDX_LP, %RDX_LP + je LABEL(strcmp_exitz) +- cmp $1, %rdx ++ cmp $1, %RDX_LP + je LABEL(Byte0) +- mov %rdx, %r11 ++ mov %RDX_LP, %R11_LP + #endif + mov %esi, %ecx + mov %edi, %eax +diff --git a/sysdeps/x86_64/x32/Makefile b/sysdeps/x86_64/x32/Makefile +index 98bd9ae9..db302839 100644 +--- a/sysdeps/x86_64/x32/Makefile ++++ b/sysdeps/x86_64/x32/Makefile +@@ -7,9 +7,11 @@ endif + + ifeq ($(subdir),string) + tests += tst-size_t-memchr tst-size_t-memcmp tst-size_t-memcpy \ +- tst-size_t-memrchr tst-size_t-memset ++ tst-size_t-memrchr tst-size_t-memset tst-size_t-strncasecmp \ ++ tst-size_t-strncmp + endif + + ifeq ($(subdir),wcsmbs) +-tests += tst-size_t-wmemchr tst-size_t-wmemcmp tst-size_t-wmemset ++tests += tst-size_t-wmemchr tst-size_t-wmemcmp tst-size_t-wmemset \ ++ tst-size_t-wcsncmp + endif +diff --git a/sysdeps/x86_64/x32/tst-size_t-strncasecmp.c b/sysdeps/x86_64/x32/tst-size_t-strncasecmp.c +new file mode 100644 +index 00000000..86233593 +--- /dev/null ++++ b/sysdeps/x86_64/x32/tst-size_t-strncasecmp.c +@@ -0,0 +1,59 @@ ++/* Test strncaecmp with size_t in the lower 32 bits of 64-bit register. ++ 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, see ++ . */ ++ ++#define TEST_NAME "strncasecmp" ++#include "test-size_t.h" ++ ++IMPL (strncasecmp, 1) ++ ++typedef int (*proto_t) (const char *, const char *, size_t); ++ ++static int ++__attribute__ ((noinline, noclone)) ++do_strncasecmp (parameter_t a, parameter_t b) ++{ ++ return CALL (&b, a.p, b.p, a.len); ++} ++ ++static int ++test_main (void) ++{ ++ test_init (); ++ ++ parameter_t dest = { { page_size }, buf1 }; ++ parameter_t src = { { 0 }, buf2 }; ++ ++ strncpy ((char *) buf1, (const char *) buf2, page_size); ++ ++ int ret = 0; ++ FOR_EACH_IMPL (impl, 0) ++ { ++ src.fn = impl->fn; ++ int res = do_strncasecmp (dest, src); ++ if (res) ++ { ++ error (0, 0, "Wrong result in function %s: %i != 0", ++ impl->name, res); ++ ret = 1; ++ } ++ } ++ ++ return ret ? EXIT_FAILURE : EXIT_SUCCESS; ++} ++ ++#include +diff --git a/sysdeps/x86_64/x32/tst-size_t-strncmp.c b/sysdeps/x86_64/x32/tst-size_t-strncmp.c +new file mode 100644 +index 00000000..54e6bd83 +--- /dev/null ++++ b/sysdeps/x86_64/x32/tst-size_t-strncmp.c +@@ -0,0 +1,78 @@ ++/* Test strncmp with size_t in the lower 32 bits of 64-bit register. ++ 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, see ++ . */ ++ ++#ifdef WIDE ++# define TEST_NAME "wcsncmp" ++#else ++# define TEST_NAME "strncmp" ++#endif ++ ++#include "test-size_t.h" ++ ++#ifdef WIDE ++# include ++ ++# define STRNCMP wcsncmp ++# define STRNCPY wcsncpy ++# define CHAR wchar_t ++#else ++# define STRNCMP strncmp ++# define STRNCPY strncpy ++# define CHAR char ++#endif ++ ++IMPL (STRNCMP, 1) ++ ++typedef int (*proto_t) (const CHAR *, const CHAR *, size_t); ++ ++ ++static int ++__attribute__ ((noinline, noclone)) ++do_strncmp (parameter_t a, parameter_t b) ++{ ++ return CALL (&b, a.p, b.p, a.len); ++} ++ ++static int ++test_main (void) ++{ ++ test_init (); ++ ++ size_t size = page_size / sizeof (CHAR); ++ parameter_t dest = { { size }, buf1 }; ++ parameter_t src = { { 0 }, buf2 }; ++ ++ STRNCPY ((CHAR *) buf1, (const CHAR *) buf2, size); ++ ++ int ret = 0; ++ FOR_EACH_IMPL (impl, 0) ++ { ++ src.fn = impl->fn; ++ int res = do_strncmp (dest, src); ++ if (res) ++ { ++ error (0, 0, "Wrong result in function %s: %i != 0", ++ impl->name, res); ++ ret = 1; ++ } ++ } ++ ++ return ret ? EXIT_FAILURE : EXIT_SUCCESS; ++} ++ ++#include +diff --git a/sysdeps/x86_64/x32/tst-size_t-wcsncmp.c b/sysdeps/x86_64/x32/tst-size_t-wcsncmp.c +new file mode 100644 +index 00000000..4829647c +--- /dev/null ++++ b/sysdeps/x86_64/x32/tst-size_t-wcsncmp.c +@@ -0,0 +1,20 @@ ++/* Test wcsncmp with size_t in the lower 32 bits of 64-bit register. ++ 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, see ++ . */ ++ ++#define WIDE 1 ++#include "tst-size_t-strncmp.c" +-- +GitLab + diff --git a/SOURCES/glibc-RHEL-15696-60.patch b/SOURCES/glibc-RHEL-15696-60.patch new file mode 100644 index 0000000..a3739eb --- /dev/null +++ b/SOURCES/glibc-RHEL-15696-60.patch @@ -0,0 +1,54 @@ +From 6720d36b6623c5e48c070d86acf61198b33e144e Mon Sep 17 00:00:00 2001 +From: Fangrui Song +Date: Tue, 2 Nov 2021 20:59:52 -0700 +Subject: [PATCH] x86-64: Replace movzx with movzbl +Content-type: text/plain; charset=UTF-8 + +Clang cannot assemble movzx in the AT&T dialect mode. + +../sysdeps/x86_64/strcmp.S:2232:16: error: invalid operand for instruction + movzx (%rsi), %ecx + ^~~~ + +Change movzx to movzbl, which follows the AT&T dialect and is used +elsewhere in the file. + +Reviewed-by: H.J. Lu +--- + sysdeps/x86_64/multiarch/strcmp-sse42.S | 4 ++-- + sysdeps/x86_64/strcmp.S | 4 ++-- + 2 files changed, 4 insertions(+), 4 deletions(-) + +diff --git a/sysdeps/x86_64/multiarch/strcmp-sse42.S b/sysdeps/x86_64/multiarch/strcmp-sse42.S +index a1ebea46..d8fdeb3a 100644 +--- a/sysdeps/x86_64/multiarch/strcmp-sse42.S ++++ b/sysdeps/x86_64/multiarch/strcmp-sse42.S +@@ -1771,8 +1771,8 @@ LABEL(strcmp_exitz): + .p2align 4 + // XXX Same as code above + LABEL(Byte0): +- movzx (%rsi), %ecx +- movzx (%rdi), %eax ++ movzbl (%rsi), %ecx ++ movzbl (%rdi), %eax + + #if defined USE_AS_STRCASECMP_L || defined USE_AS_STRNCASECMP_L + leaq _nl_C_LC_CTYPE_tolower+128*4(%rip), %rdx +diff --git a/sysdeps/x86_64/strcmp.S b/sysdeps/x86_64/strcmp.S +index f47c8ad4..aa6df898 100644 +--- a/sysdeps/x86_64/strcmp.S ++++ b/sysdeps/x86_64/strcmp.S +@@ -2232,8 +2232,8 @@ LABEL(strcmp_exitz): + + .p2align 4 + LABEL(Byte0): +- movzx (%rsi), %ecx +- movzx (%rdi), %eax ++ movzbl (%rsi), %ecx ++ movzbl (%rdi), %eax + + #if defined USE_AS_STRCASECMP_L || defined USE_AS_STRNCASECMP_L + leaq _nl_C_LC_CTYPE_tolower+128*4(%rip), %rdx +-- +GitLab + diff --git a/SOURCES/glibc-RHEL-15696-61.patch b/SOURCES/glibc-RHEL-15696-61.patch new file mode 100644 index 0000000..d6dbe81 --- /dev/null +++ b/SOURCES/glibc-RHEL-15696-61.patch @@ -0,0 +1,56 @@ +From cf2c57526ba4b57e6863ad4db8a868e2678adce8 Mon Sep 17 00:00:00 2001 +From: "H.J. Lu" +Date: Fri, 30 Apr 2021 05:58:59 -0700 +Subject: [PATCH] x86: Set rep_movsb_threshold to 2112 on processors with FSRM +Content-type: text/plain; charset=UTF-8 + +The glibc memcpy benchmark on Intel Core i7-1065G7 (Ice Lake) showed +that REP MOVSB became faster after 2112 bytes: + + Vector Move REP MOVSB +length=2112, align1=0, align2=0: 24.20 24.40 +length=2112, align1=1, align2=0: 26.07 23.13 +length=2112, align1=0, align2=1: 27.18 28.13 +length=2112, align1=1, align2=1: 26.23 25.16 +length=2176, align1=0, align2=0: 23.18 22.52 +length=2176, align1=2, align2=0: 25.45 22.52 +length=2176, align1=0, align2=2: 27.14 27.82 +length=2176, align1=2, align2=2: 22.73 25.56 +length=2240, align1=0, align2=0: 24.62 24.25 +length=2240, align1=3, align2=0: 29.77 27.15 +length=2240, align1=0, align2=3: 35.55 29.93 +length=2240, align1=3, align2=3: 34.49 25.15 +length=2304, align1=0, align2=0: 34.75 26.64 +length=2304, align1=4, align2=0: 32.09 22.63 +length=2304, align1=0, align2=4: 28.43 31.24 + +Use REP MOVSB for data size > 2112 bytes in memcpy on processors with +fast short REP MOVSB (FSRM). + + * sysdeps/x86/dl-cacheinfo.h (dl_init_cacheinfo): Set + rep_movsb_threshold to 2112 on processors with fast short REP + MOVSB (FSRM). +--- + sysdeps/x86/cacheinfo.h | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/sysdeps/x86/cacheinfo.h b/sysdeps/x86/cacheinfo.h +index f72f634a..cc3941d3 100644 +--- a/sysdeps/x86/cacheinfo.h ++++ b/sysdeps/x86/cacheinfo.h +@@ -430,6 +430,12 @@ init_cacheinfo (void) + rep_movsb_threshold = 2048 * (16 / 16); + minimum_rep_movsb_threshold = 16 * 8; + } ++ ++ /* NB: The default REP MOVSB threshold is 2112 on processors with fast ++ short REP MOVSB (FSRM). */ ++ if (CPU_FEATURE_USABLE_P (cpu_features, FSRM)) ++ rep_movsb_threshold = 2112; ++ + if (cpu_features->rep_movsb_threshold > minimum_rep_movsb_threshold) + __x86_rep_movsb_threshold = cpu_features->rep_movsb_threshold; + else +-- +GitLab + diff --git a/SOURCES/glibc-RHEL-15696-62.patch b/SOURCES/glibc-RHEL-15696-62.patch new file mode 100644 index 0000000..a7a9286 --- /dev/null +++ b/SOURCES/glibc-RHEL-15696-62.patch @@ -0,0 +1,136 @@ +From 475b63702ef38b69558fc3d31a0b66776a70f1d3 Mon Sep 17 00:00:00 2001 +From: Noah Goldstein +Date: Mon, 1 Nov 2021 00:49:52 -0500 +Subject: [PATCH] x86: Double size of ERMS rep_movsb_threshold in + dl-cacheinfo.h +Content-type: text/plain; charset=UTF-8 + +No bug. + +This patch doubles the rep_movsb_threshold when using ERMS. Based on +benchmarks the vector copy loop, especially now that it handles 4k +aliasing, is better for these medium ranged. + +On Skylake with ERMS: + +Size, Align1, Align2, dst>src,(rep movsb) / (vec copy) +4096, 0, 0, 0, 0.975 +4096, 0, 0, 1, 0.953 +4096, 12, 0, 0, 0.969 +4096, 12, 0, 1, 0.872 +4096, 44, 0, 0, 0.979 +4096, 44, 0, 1, 0.83 +4096, 0, 12, 0, 1.006 +4096, 0, 12, 1, 0.989 +4096, 0, 44, 0, 0.739 +4096, 0, 44, 1, 0.942 +4096, 12, 12, 0, 1.009 +4096, 12, 12, 1, 0.973 +4096, 44, 44, 0, 0.791 +4096, 44, 44, 1, 0.961 +4096, 2048, 0, 0, 0.978 +4096, 2048, 0, 1, 0.951 +4096, 2060, 0, 0, 0.986 +4096, 2060, 0, 1, 0.963 +4096, 2048, 12, 0, 0.971 +4096, 2048, 12, 1, 0.941 +4096, 2060, 12, 0, 0.977 +4096, 2060, 12, 1, 0.949 +8192, 0, 0, 0, 0.85 +8192, 0, 0, 1, 0.845 +8192, 13, 0, 0, 0.937 +8192, 13, 0, 1, 0.939 +8192, 45, 0, 0, 0.932 +8192, 45, 0, 1, 0.927 +8192, 0, 13, 0, 0.621 +8192, 0, 13, 1, 0.62 +8192, 0, 45, 0, 0.53 +8192, 0, 45, 1, 0.516 +8192, 13, 13, 0, 0.664 +8192, 13, 13, 1, 0.659 +8192, 45, 45, 0, 0.593 +8192, 45, 45, 1, 0.575 +8192, 2048, 0, 0, 0.854 +8192, 2048, 0, 1, 0.834 +8192, 2061, 0, 0, 0.863 +8192, 2061, 0, 1, 0.857 +8192, 2048, 13, 0, 0.63 +8192, 2048, 13, 1, 0.629 +8192, 2061, 13, 0, 0.627 +8192, 2061, 13, 1, 0.62 + +Signed-off-by: Noah Goldstein +Reviewed-by: H.J. Lu +--- + sysdeps/x86/cacheinfo.h | 8 +++++--- + sysdeps/x86/dl-tunables.list | 26 +++++++++++++++----------- + 2 files changed, 20 insertions(+), 14 deletions(-) + +diff --git a/sysdeps/x86/cacheinfo.h b/sysdeps/x86/cacheinfo.h +index cc3941d3..ac025e08 100644 +--- a/sysdeps/x86/cacheinfo.h ++++ b/sysdeps/x86/cacheinfo.h +@@ -411,18 +411,20 @@ init_cacheinfo (void) + + /* NB: The REP MOVSB threshold must be greater than VEC_SIZE * 8. */ + unsigned int minimum_rep_movsb_threshold; +- /* NB: The default REP MOVSB threshold is 2048 * (VEC_SIZE / 16). */ ++ /* NB: The default REP MOVSB threshold is 4096 * (VEC_SIZE / 16) for ++ VEC_SIZE == 64 or 32. For VEC_SIZE == 16, the default REP MOVSB ++ threshold is 2048 * (VEC_SIZE / 16). */ + unsigned int rep_movsb_threshold; + if (CPU_FEATURE_USABLE_P (cpu_features, AVX512F) + && !CPU_FEATURE_PREFERRED_P (cpu_features, Prefer_No_AVX512)) + { +- rep_movsb_threshold = 2048 * (64 / 16); ++ rep_movsb_threshold = 4096 * (64 / 16); + minimum_rep_movsb_threshold = 64 * 8; + } + else if (CPU_FEATURE_PREFERRED_P (cpu_features, + AVX_Fast_Unaligned_Load)) + { +- rep_movsb_threshold = 2048 * (32 / 16); ++ rep_movsb_threshold = 4096 * (32 / 16); + minimum_rep_movsb_threshold = 32 * 8; + } + else +diff --git a/sysdeps/x86/dl-tunables.list b/sysdeps/x86/dl-tunables.list +index 89bf2966..56c6834a 100644 +--- a/sysdeps/x86/dl-tunables.list ++++ b/sysdeps/x86/dl-tunables.list +@@ -32,17 +32,21 @@ glibc { + } + x86_rep_movsb_threshold { + type: SIZE_T +- # Since there is overhead to set up REP MOVSB operation, REP MOVSB +- # isn't faster on short data. The memcpy micro benchmark in glibc +- # shows that 2KB is the approximate value above which REP MOVSB +- # becomes faster than SSE2 optimization on processors with Enhanced +- # REP MOVSB. Since larger register size can move more data with a +- # single load and store, the threshold is higher with larger register +- # size. Note: Since the REP MOVSB threshold must be greater than 8 +- # times of vector size and the default value is 2048 * (vector size +- # / 16), the default value and the minimum value must be updated at +- # run-time. NB: Don't set the default value since we can't tell if +- # the tunable value is set by user or not [BZ #27069]. ++ # Since there is overhead to set up REP MOVSB operation, REP ++ # MOVSB isn't faster on short data. The memcpy micro benchmark ++ # in glibc shows that 2KB is the approximate value above which ++ # REP MOVSB becomes faster than SSE2 optimization on processors ++ # with Enhanced REP MOVSB. Since larger register size can move ++ # more data with a single load and store, the threshold is ++ # higher with larger register size. Micro benchmarks show AVX ++ # REP MOVSB becomes faster apprximately at 8KB. The AVX512 ++ # threshold is extrapolated to 16KB. For machines with FSRM the ++ # threshold is universally set at 2112 bytes. Note: Since the ++ # REP MOVSB threshold must be greater than 8 times of vector ++ # size and the default value is 4096 * (vector size / 16), the ++ # default value and the minimum value must be updated at ++ # run-time. NB: Don't set the default value since we can't tell ++ # if the tunable value is set by user or not [BZ #27069]. + minval: 1 + } + x86_rep_stosb_threshold { +-- +GitLab + diff --git a/SOURCES/glibc-RHEL-15696-63.patch b/SOURCES/glibc-RHEL-15696-63.patch new file mode 100644 index 0000000..c14e8b3 --- /dev/null +++ b/SOURCES/glibc-RHEL-15696-63.patch @@ -0,0 +1,2428 @@ +From 2f9062d7171850451e6044ef78d91ff8c017b9c0 Mon Sep 17 00:00:00 2001 +From: Noah Goldstein +Date: Wed, 10 Nov 2021 16:18:56 -0600 +Subject: [PATCH] x86: Shrink memcmp-sse4.S code size +Content-type: text/plain; charset=UTF-8 + +No bug. + +This implementation refactors memcmp-sse4.S primarily with minimizing +code size in mind. It does this by removing the lookup table logic and +removing the unrolled check from (256, 512] bytes. + +memcmp-sse4 code size reduction : -3487 bytes +wmemcmp-sse4 code size reduction: -1472 bytes + +The current memcmp-sse4.S implementation has a large code size +cost. This has serious adverse affects on the ICache / ITLB. While +in micro-benchmarks the implementations appears fast, traces of +real-world code have shown that the speed in micro benchmarks does not +translate when the ICache/ITLB are not primed, and that the cost +of the code size has measurable negative affects on overall +application performance. + +See https://research.google/pubs/pub48320/ for more details. + +Signed-off-by: Noah Goldstein +Reviewed-by: H.J. Lu +--- + sysdeps/x86_64/multiarch/memcmp-sse4.S | 2267 +++++++----------------- + 1 file changed, 646 insertions(+), 1621 deletions(-) + +diff --git a/sysdeps/x86_64/multiarch/memcmp-sse4.S b/sysdeps/x86_64/multiarch/memcmp-sse4.S +index 302900f5..50060006 100644 +--- a/sysdeps/x86_64/multiarch/memcmp-sse4.S ++++ b/sysdeps/x86_64/multiarch/memcmp-sse4.S +@@ -25,14 +25,14 @@ + # define MEMCMP __memcmp_sse4_1 + # endif + +-# define JMPTBL(I, B) (I - B) ++#ifdef USE_AS_WMEMCMP ++# define CMPEQ pcmpeqd ++# define CHAR_SIZE 4 ++#else ++# define CMPEQ pcmpeqb ++# define CHAR_SIZE 1 ++#endif + +-# define BRANCH_TO_JMPTBL_ENTRY(TABLE, INDEX, SCALE) \ +- lea TABLE(%rip), %r11; \ +- movslq (%r11, INDEX, SCALE), %rcx; \ +- add %r11, %rcx; \ +- _CET_NOTRACK jmp *%rcx; \ +- ud2 + + /* Warning! + wmemcmp has to use SIGNED comparison for elements. +@@ -47,33 +47,253 @@ ENTRY (MEMCMP) + /* Clear the upper 32 bits. */ + mov %edx, %edx + # endif +- pxor %xmm0, %xmm0 + cmp $79, %RDX_LP + ja L(79bytesormore) ++ ++ cmp $CHAR_SIZE, %RDX_LP ++ jbe L(firstbyte) ++ ++ /* N in (CHAR_SIZE, 79) bytes. */ ++ cmpl $32, %edx ++ ja L(more_32_bytes) ++ ++ cmpl $16, %edx ++ jae L(16_to_32_bytes) ++ + # ifndef USE_AS_WMEMCMP +- cmp $1, %RDX_LP +- je L(firstbyte) ++ cmpl $8, %edx ++ jae L(8_to_16_bytes) ++ ++ cmpl $4, %edx ++ jb L(2_to_3_bytes) ++ ++ movl (%rdi), %eax ++ movl (%rsi), %ecx ++ ++ bswap %eax ++ bswap %ecx ++ ++ shlq $32, %rax ++ shlq $32, %rcx ++ ++ movl -4(%rdi, %rdx), %edi ++ movl -4(%rsi, %rdx), %esi ++ ++ bswap %edi ++ bswap %esi ++ ++ orq %rdi, %rax ++ orq %rsi, %rcx ++ subq %rcx, %rax ++ cmovne %edx, %eax ++ sbbl %ecx, %ecx ++ orl %ecx, %eax ++ ret ++ ++ .p2align 4,, 8 ++L(2_to_3_bytes): ++ movzwl (%rdi), %eax ++ movzwl (%rsi), %ecx ++ shll $8, %eax ++ shll $8, %ecx ++ bswap %eax ++ bswap %ecx ++ movzbl -1(%rdi, %rdx), %edi ++ movzbl -1(%rsi, %rdx), %esi ++ orl %edi, %eax ++ orl %esi, %ecx ++ subl %ecx, %eax ++ ret ++ ++ .p2align 4,, 8 ++L(8_to_16_bytes): ++ movq (%rdi), %rax ++ movq (%rsi), %rcx ++ ++ bswap %rax ++ bswap %rcx ++ ++ subq %rcx, %rax ++ jne L(8_to_16_bytes_done) ++ ++ movq -8(%rdi, %rdx), %rax ++ movq -8(%rsi, %rdx), %rcx ++ ++ bswap %rax ++ bswap %rcx ++ ++ subq %rcx, %rax ++ ++L(8_to_16_bytes_done): ++ cmovne %edx, %eax ++ sbbl %ecx, %ecx ++ orl %ecx, %eax ++ ret ++# else ++ xorl %eax, %eax ++ movl (%rdi), %ecx ++ cmpl (%rsi), %ecx ++ jne L(8_to_16_bytes_done) ++ movl 4(%rdi), %ecx ++ cmpl 4(%rsi), %ecx ++ jne L(8_to_16_bytes_done) ++ movl -4(%rdi, %rdx), %ecx ++ cmpl -4(%rsi, %rdx), %ecx ++ jne L(8_to_16_bytes_done) ++ ret + # endif +- add %rdx, %rsi +- add %rdx, %rdi +- BRANCH_TO_JMPTBL_ENTRY(L(table_64bytes), %rdx, 4) + +-# ifndef USE_AS_WMEMCMP +- .p2align 4 ++ .p2align 4,, 3 ++L(ret_zero): ++ xorl %eax, %eax ++L(zero): ++ ret ++ ++ .p2align 4,, 8 + L(firstbyte): ++ jb L(ret_zero) ++# ifdef USE_AS_WMEMCMP ++ xorl %eax, %eax ++ movl (%rdi), %ecx ++ cmpl (%rsi), %ecx ++ je L(zero) ++L(8_to_16_bytes_done): ++ setg %al ++ leal -1(%rax, %rax), %eax ++# else + movzbl (%rdi), %eax + movzbl (%rsi), %ecx + sub %ecx, %eax ++# endif + ret ++ ++ .p2align 4 ++L(vec_return_begin_48): ++ addq $16, %rdi ++ addq $16, %rsi ++L(vec_return_begin_32): ++ bsfl %eax, %eax ++# ifdef USE_AS_WMEMCMP ++ movl 32(%rdi, %rax), %ecx ++ xorl %edx, %edx ++ cmpl 32(%rsi, %rax), %ecx ++ setg %dl ++ leal -1(%rdx, %rdx), %eax ++# else ++ movzbl 32(%rsi, %rax), %ecx ++ movzbl 32(%rdi, %rax), %eax ++ subl %ecx, %eax ++# endif ++ ret ++ ++ .p2align 4 ++L(vec_return_begin_16): ++ addq $16, %rdi ++ addq $16, %rsi ++L(vec_return_begin): ++ bsfl %eax, %eax ++# ifdef USE_AS_WMEMCMP ++ movl (%rdi, %rax), %ecx ++ xorl %edx, %edx ++ cmpl (%rsi, %rax), %ecx ++ setg %dl ++ leal -1(%rdx, %rdx), %eax ++# else ++ movzbl (%rsi, %rax), %ecx ++ movzbl (%rdi, %rax), %eax ++ subl %ecx, %eax ++# endif ++ ret ++ ++ .p2align 4 ++L(vec_return_end_16): ++ subl $16, %edx ++L(vec_return_end): ++ bsfl %eax, %eax ++ addl %edx, %eax ++# ifdef USE_AS_WMEMCMP ++ movl -16(%rdi, %rax), %ecx ++ xorl %edx, %edx ++ cmpl -16(%rsi, %rax), %ecx ++ setg %dl ++ leal -1(%rdx, %rdx), %eax ++# else ++ movzbl -16(%rsi, %rax), %ecx ++ movzbl -16(%rdi, %rax), %eax ++ subl %ecx, %eax + # endif ++ ret ++ ++ .p2align 4,, 8 ++L(more_32_bytes): ++ movdqu (%rdi), %xmm0 ++ movdqu (%rsi), %xmm1 ++ CMPEQ %xmm0, %xmm1 ++ pmovmskb %xmm1, %eax ++ incw %ax ++ jnz L(vec_return_begin) ++ ++ movdqu 16(%rdi), %xmm0 ++ movdqu 16(%rsi), %xmm1 ++ CMPEQ %xmm0, %xmm1 ++ pmovmskb %xmm1, %eax ++ incw %ax ++ jnz L(vec_return_begin_16) ++ ++ cmpl $64, %edx ++ jbe L(32_to_64_bytes) ++ movdqu 32(%rdi), %xmm0 ++ movdqu 32(%rsi), %xmm1 ++ CMPEQ %xmm0, %xmm1 ++ pmovmskb %xmm1, %eax ++ incw %ax ++ jnz L(vec_return_begin_32) ++ ++ .p2align 4,, 6 ++L(32_to_64_bytes): ++ movdqu -32(%rdi, %rdx), %xmm0 ++ movdqu -32(%rsi, %rdx), %xmm1 ++ CMPEQ %xmm0, %xmm1 ++ pmovmskb %xmm1, %eax ++ incw %ax ++ jnz L(vec_return_end_16) ++ ++ movdqu -16(%rdi, %rdx), %xmm0 ++ movdqu -16(%rsi, %rdx), %xmm1 ++ CMPEQ %xmm0, %xmm1 ++ pmovmskb %xmm1, %eax ++ incw %ax ++ jnz L(vec_return_end) ++ ret ++ ++ .p2align 4 ++L(16_to_32_bytes): ++ movdqu (%rdi), %xmm0 ++ movdqu (%rsi), %xmm1 ++ CMPEQ %xmm0, %xmm1 ++ pmovmskb %xmm1, %eax ++ incw %ax ++ jnz L(vec_return_begin) ++ ++ movdqu -16(%rdi, %rdx), %xmm0 ++ movdqu -16(%rsi, %rdx), %xmm1 ++ CMPEQ %xmm0, %xmm1 ++ pmovmskb %xmm1, %eax ++ incw %ax ++ jnz L(vec_return_end) ++ ret ++ + + .p2align 4 + L(79bytesormore): ++ movdqu (%rdi), %xmm0 + movdqu (%rsi), %xmm1 +- movdqu (%rdi), %xmm2 +- pxor %xmm1, %xmm2 +- ptest %xmm2, %xmm0 +- jnc L(16bytesin256) ++ CMPEQ %xmm0, %xmm1 ++ pmovmskb %xmm1, %eax ++ incw %ax ++ jnz L(vec_return_begin) ++ ++ + mov %rsi, %rcx + and $-16, %rsi + add $16, %rsi +@@ -86,1694 +306,499 @@ L(79bytesormore): + + cmp $128, %rdx + ja L(128bytesormore) +-L(less128bytes): +- sub $64, %rdx +- +- movdqu (%rdi), %xmm2 +- pxor (%rsi), %xmm2 +- ptest %xmm2, %xmm0 +- jnc L(16bytesin256) + +- movdqu 16(%rdi), %xmm2 +- pxor 16(%rsi), %xmm2 +- ptest %xmm2, %xmm0 +- jnc L(32bytesin256) +- +- movdqu 32(%rdi), %xmm2 +- pxor 32(%rsi), %xmm2 +- ptest %xmm2, %xmm0 +- jnc L(48bytesin256) +- +- movdqu 48(%rdi), %xmm2 +- pxor 48(%rsi), %xmm2 +- ptest %xmm2, %xmm0 +- jnc L(64bytesin256) +- cmp $32, %rdx +- jb L(less32bytesin64) +- +- movdqu 64(%rdi), %xmm2 +- pxor 64(%rsi), %xmm2 +- ptest %xmm2, %xmm0 +- jnc L(80bytesin256) +- +- movdqu 80(%rdi), %xmm2 +- pxor 80(%rsi), %xmm2 +- ptest %xmm2, %xmm0 +- jnc L(96bytesin256) +- sub $32, %rdx +- add $32, %rdi +- add $32, %rsi +-L(less32bytesin64): +- add $64, %rdi +- add $64, %rsi +- add %rdx, %rsi +- add %rdx, %rdi +- BRANCH_TO_JMPTBL_ENTRY(L(table_64bytes), %rdx, 4) ++ .p2align 4,, 6 ++L(less128bytes): ++ movdqu (%rdi), %xmm1 ++ CMPEQ (%rsi), %xmm1 ++ pmovmskb %xmm1, %eax ++ incw %ax ++ jnz L(vec_return_begin) ++ ++ movdqu 16(%rdi), %xmm1 ++ CMPEQ 16(%rsi), %xmm1 ++ pmovmskb %xmm1, %eax ++ incw %ax ++ jnz L(vec_return_begin_16) ++ ++ movdqu 32(%rdi), %xmm1 ++ CMPEQ 32(%rsi), %xmm1 ++ pmovmskb %xmm1, %eax ++ incw %ax ++ jnz L(vec_return_begin_32) ++ ++ movdqu 48(%rdi), %xmm1 ++ CMPEQ 48(%rsi), %xmm1 ++ pmovmskb %xmm1, %eax ++ incw %ax ++ jnz L(vec_return_begin_48) ++ ++ cmp $96, %rdx ++ jb L(32_to_64_bytes) ++ ++ addq $64, %rdi ++ addq $64, %rsi ++ subq $64, %rdx ++ ++ .p2align 4,, 6 ++L(last_64_bytes): ++ movdqu (%rdi), %xmm1 ++ CMPEQ (%rsi), %xmm1 ++ pmovmskb %xmm1, %eax ++ incw %ax ++ jnz L(vec_return_begin) ++ ++ movdqu 16(%rdi), %xmm1 ++ CMPEQ 16(%rsi), %xmm1 ++ pmovmskb %xmm1, %eax ++ incw %ax ++ jnz L(vec_return_begin_16) ++ ++ movdqu -32(%rdi, %rdx), %xmm0 ++ movdqu -32(%rsi, %rdx), %xmm1 ++ CMPEQ %xmm0, %xmm1 ++ pmovmskb %xmm1, %eax ++ incw %ax ++ jnz L(vec_return_end_16) ++ ++ movdqu -16(%rdi, %rdx), %xmm0 ++ movdqu -16(%rsi, %rdx), %xmm1 ++ CMPEQ %xmm0, %xmm1 ++ pmovmskb %xmm1, %eax ++ incw %ax ++ jnz L(vec_return_end) ++ ret + ++ .p2align 4 + L(128bytesormore): +- cmp $512, %rdx +- ja L(512bytesormore) + cmp $256, %rdx +- ja L(less512bytes) ++ ja L(unaligned_loop) + L(less256bytes): +- sub $128, %rdx +- +- movdqu (%rdi), %xmm2 +- pxor (%rsi), %xmm2 +- ptest %xmm2, %xmm0 +- jnc L(16bytesin256) +- +- movdqu 16(%rdi), %xmm2 +- pxor 16(%rsi), %xmm2 +- ptest %xmm2, %xmm0 +- jnc L(32bytesin256) +- +- movdqu 32(%rdi), %xmm2 +- pxor 32(%rsi), %xmm2 +- ptest %xmm2, %xmm0 +- jnc L(48bytesin256) +- +- movdqu 48(%rdi), %xmm2 +- pxor 48(%rsi), %xmm2 +- ptest %xmm2, %xmm0 +- jnc L(64bytesin256) +- +- movdqu 64(%rdi), %xmm2 +- pxor 64(%rsi), %xmm2 +- ptest %xmm2, %xmm0 +- jnc L(80bytesin256) +- +- movdqu 80(%rdi), %xmm2 +- pxor 80(%rsi), %xmm2 +- ptest %xmm2, %xmm0 +- jnc L(96bytesin256) +- +- movdqu 96(%rdi), %xmm2 +- pxor 96(%rsi), %xmm2 +- ptest %xmm2, %xmm0 +- jnc L(112bytesin256) +- +- movdqu 112(%rdi), %xmm2 +- pxor 112(%rsi), %xmm2 +- ptest %xmm2, %xmm0 +- jnc L(128bytesin256) +- +- add $128, %rsi +- add $128, %rdi +- +- cmp $64, %rdx +- jae L(less128bytes) +- +- cmp $32, %rdx +- jb L(less32bytesin128) +- +- movdqu (%rdi), %xmm2 +- pxor (%rsi), %xmm2 +- ptest %xmm2, %xmm0 +- jnc L(16bytesin256) +- +- movdqu 16(%rdi), %xmm2 +- pxor 16(%rsi), %xmm2 +- ptest %xmm2, %xmm0 +- jnc L(32bytesin256) +- sub $32, %rdx +- add $32, %rdi +- add $32, %rsi +-L(less32bytesin128): +- add %rdx, %rsi +- add %rdx, %rdi +- BRANCH_TO_JMPTBL_ENTRY(L(table_64bytes), %rdx, 4) +- +-L(less512bytes): +- sub $256, %rdx +- movdqu (%rdi), %xmm2 +- pxor (%rsi), %xmm2 +- ptest %xmm2, %xmm0 +- jnc L(16bytesin256) +- +- movdqu 16(%rdi), %xmm2 +- pxor 16(%rsi), %xmm2 +- ptest %xmm2, %xmm0 +- jnc L(32bytesin256) +- +- movdqu 32(%rdi), %xmm2 +- pxor 32(%rsi), %xmm2 +- ptest %xmm2, %xmm0 +- jnc L(48bytesin256) +- +- movdqu 48(%rdi), %xmm2 +- pxor 48(%rsi), %xmm2 +- ptest %xmm2, %xmm0 +- jnc L(64bytesin256) +- +- movdqu 64(%rdi), %xmm2 +- pxor 64(%rsi), %xmm2 +- ptest %xmm2, %xmm0 +- jnc L(80bytesin256) +- +- movdqu 80(%rdi), %xmm2 +- pxor 80(%rsi), %xmm2 +- ptest %xmm2, %xmm0 +- jnc L(96bytesin256) +- +- movdqu 96(%rdi), %xmm2 +- pxor 96(%rsi), %xmm2 +- ptest %xmm2, %xmm0 +- jnc L(112bytesin256) +- +- movdqu 112(%rdi), %xmm2 +- pxor 112(%rsi), %xmm2 +- ptest %xmm2, %xmm0 +- jnc L(128bytesin256) +- +- movdqu 128(%rdi), %xmm2 +- pxor 128(%rsi), %xmm2 +- ptest %xmm2, %xmm0 +- jnc L(144bytesin256) +- +- movdqu 144(%rdi), %xmm2 +- pxor 144(%rsi), %xmm2 +- ptest %xmm2, %xmm0 +- jnc L(160bytesin256) +- +- movdqu 160(%rdi), %xmm2 +- pxor 160(%rsi), %xmm2 +- ptest %xmm2, %xmm0 +- jnc L(176bytesin256) +- +- movdqu 176(%rdi), %xmm2 +- pxor 176(%rsi), %xmm2 +- ptest %xmm2, %xmm0 +- jnc L(192bytesin256) +- +- movdqu 192(%rdi), %xmm2 +- pxor 192(%rsi), %xmm2 +- ptest %xmm2, %xmm0 +- jnc L(208bytesin256) +- +- movdqu 208(%rdi), %xmm2 +- pxor 208(%rsi), %xmm2 +- ptest %xmm2, %xmm0 +- jnc L(224bytesin256) +- +- movdqu 224(%rdi), %xmm2 +- pxor 224(%rsi), %xmm2 +- ptest %xmm2, %xmm0 +- jnc L(240bytesin256) +- +- movdqu 240(%rdi), %xmm2 +- pxor 240(%rsi), %xmm2 +- ptest %xmm2, %xmm0 +- jnc L(256bytesin256) +- +- add $256, %rsi +- add $256, %rdi +- +- cmp $128, %rdx +- jae L(less256bytes) ++ movdqu (%rdi), %xmm1 ++ CMPEQ (%rsi), %xmm1 ++ pmovmskb %xmm1, %eax ++ incw %ax ++ jnz L(vec_return_begin) ++ ++ movdqu 16(%rdi), %xmm1 ++ CMPEQ 16(%rsi), %xmm1 ++ pmovmskb %xmm1, %eax ++ incw %ax ++ jnz L(vec_return_begin_16) ++ ++ movdqu 32(%rdi), %xmm1 ++ CMPEQ 32(%rsi), %xmm1 ++ pmovmskb %xmm1, %eax ++ incw %ax ++ jnz L(vec_return_begin_32) ++ ++ movdqu 48(%rdi), %xmm1 ++ CMPEQ 48(%rsi), %xmm1 ++ pmovmskb %xmm1, %eax ++ incw %ax ++ jnz L(vec_return_begin_48) ++ ++ addq $64, %rdi ++ addq $64, %rsi ++ ++ movdqu (%rdi), %xmm1 ++ CMPEQ (%rsi), %xmm1 ++ pmovmskb %xmm1, %eax ++ incw %ax ++ jnz L(vec_return_begin) ++ ++ movdqu 16(%rdi), %xmm1 ++ CMPEQ 16(%rsi), %xmm1 ++ pmovmskb %xmm1, %eax ++ incw %ax ++ jnz L(vec_return_begin_16) ++ ++ movdqu 32(%rdi), %xmm1 ++ CMPEQ 32(%rsi), %xmm1 ++ pmovmskb %xmm1, %eax ++ incw %ax ++ jnz L(vec_return_begin_32) ++ ++ movdqu 48(%rdi), %xmm1 ++ CMPEQ 48(%rsi), %xmm1 ++ pmovmskb %xmm1, %eax ++ incw %ax ++ jnz L(vec_return_begin_48) ++ ++ addq $-128, %rdx ++ subq $-64, %rsi ++ subq $-64, %rdi + + cmp $64, %rdx +- jae L(less128bytes) ++ ja L(less128bytes) + + cmp $32, %rdx +- jb L(less32bytesin256) +- +- movdqu (%rdi), %xmm2 +- pxor (%rsi), %xmm2 +- ptest %xmm2, %xmm0 +- jnc L(16bytesin256) +- +- movdqu 16(%rdi), %xmm2 +- pxor 16(%rsi), %xmm2 +- ptest %xmm2, %xmm0 +- jnc L(32bytesin256) +- sub $32, %rdx +- add $32, %rdi +- add $32, %rsi +-L(less32bytesin256): +- add %rdx, %rsi +- add %rdx, %rdi +- BRANCH_TO_JMPTBL_ENTRY(L(table_64bytes), %rdx, 4) ++ ja L(last_64_bytes) ++ ++ movdqu -32(%rdi, %rdx), %xmm0 ++ movdqu -32(%rsi, %rdx), %xmm1 ++ CMPEQ %xmm0, %xmm1 ++ pmovmskb %xmm1, %eax ++ incw %ax ++ jnz L(vec_return_end_16) ++ ++ movdqu -16(%rdi, %rdx), %xmm0 ++ movdqu -16(%rsi, %rdx), %xmm1 ++ CMPEQ %xmm0, %xmm1 ++ pmovmskb %xmm1, %eax ++ incw %ax ++ jnz L(vec_return_end) ++ ret + + .p2align 4 +-L(512bytesormore): ++L(unaligned_loop): + # ifdef DATA_CACHE_SIZE_HALF + mov $DATA_CACHE_SIZE_HALF, %R8_LP + # else + mov __x86_data_cache_size_half(%rip), %R8_LP + # endif +- mov %r8, %r9 +- shr $1, %r8 +- add %r9, %r8 +- cmp %r8, %rdx +- ja L(L2_L3_cache_unaglined) ++ movq %r8, %r9 ++ addq %r8, %r8 ++ addq %r9, %r8 ++ cmpq %r8, %rdx ++ ja L(L2_L3_cache_unaligned) + sub $64, %rdx + .p2align 4 + L(64bytesormore_loop): +- movdqu (%rdi), %xmm2 +- pxor (%rsi), %xmm2 +- movdqa %xmm2, %xmm1 ++ movdqu (%rdi), %xmm0 ++ movdqu 16(%rdi), %xmm1 ++ movdqu 32(%rdi), %xmm2 ++ movdqu 48(%rdi), %xmm3 + +- movdqu 16(%rdi), %xmm3 +- pxor 16(%rsi), %xmm3 +- por %xmm3, %xmm1 ++ CMPEQ (%rsi), %xmm0 ++ CMPEQ 16(%rsi), %xmm1 ++ CMPEQ 32(%rsi), %xmm2 ++ CMPEQ 48(%rsi), %xmm3 + +- movdqu 32(%rdi), %xmm4 +- pxor 32(%rsi), %xmm4 +- por %xmm4, %xmm1 ++ pand %xmm0, %xmm1 ++ pand %xmm2, %xmm3 ++ pand %xmm1, %xmm3 + +- movdqu 48(%rdi), %xmm5 +- pxor 48(%rsi), %xmm5 +- por %xmm5, %xmm1 ++ pmovmskb %xmm3, %eax ++ incw %ax ++ jnz L(64bytesormore_loop_end) + +- ptest %xmm1, %xmm0 +- jnc L(64bytesormore_loop_end) + add $64, %rsi + add $64, %rdi + sub $64, %rdx +- jae L(64bytesormore_loop) ++ ja L(64bytesormore_loop) + +- add $64, %rdx +- add %rdx, %rsi +- add %rdx, %rdi +- BRANCH_TO_JMPTBL_ENTRY(L(table_64bytes), %rdx, 4) ++ .p2align 4,, 6 ++L(loop_tail): ++ addq %rdx, %rdi ++ movdqu (%rdi), %xmm0 ++ movdqu 16(%rdi), %xmm1 ++ movdqu 32(%rdi), %xmm2 ++ movdqu 48(%rdi), %xmm3 ++ ++ addq %rdx, %rsi ++ movdqu (%rsi), %xmm4 ++ movdqu 16(%rsi), %xmm5 ++ movdqu 32(%rsi), %xmm6 ++ movdqu 48(%rsi), %xmm7 ++ ++ CMPEQ %xmm4, %xmm0 ++ CMPEQ %xmm5, %xmm1 ++ CMPEQ %xmm6, %xmm2 ++ CMPEQ %xmm7, %xmm3 ++ ++ pand %xmm0, %xmm1 ++ pand %xmm2, %xmm3 ++ pand %xmm1, %xmm3 ++ ++ pmovmskb %xmm3, %eax ++ incw %ax ++ jnz L(64bytesormore_loop_end) ++ ret + +-L(L2_L3_cache_unaglined): +- sub $64, %rdx ++L(L2_L3_cache_unaligned): ++ subq $64, %rdx + .p2align 4 + L(L2_L3_unaligned_128bytes_loop): + prefetchnta 0x1c0(%rdi) + prefetchnta 0x1c0(%rsi) +- movdqu (%rdi), %xmm2 +- pxor (%rsi), %xmm2 +- movdqa %xmm2, %xmm1 + +- movdqu 16(%rdi), %xmm3 +- pxor 16(%rsi), %xmm3 +- por %xmm3, %xmm1 ++ movdqu (%rdi), %xmm0 ++ movdqu 16(%rdi), %xmm1 ++ movdqu 32(%rdi), %xmm2 ++ movdqu 48(%rdi), %xmm3 ++ ++ CMPEQ (%rsi), %xmm0 ++ CMPEQ 16(%rsi), %xmm1 ++ CMPEQ 32(%rsi), %xmm2 ++ CMPEQ 48(%rsi), %xmm3 + +- movdqu 32(%rdi), %xmm4 +- pxor 32(%rsi), %xmm4 +- por %xmm4, %xmm1 ++ pand %xmm0, %xmm1 ++ pand %xmm2, %xmm3 ++ pand %xmm1, %xmm3 + +- movdqu 48(%rdi), %xmm5 +- pxor 48(%rsi), %xmm5 +- por %xmm5, %xmm1 ++ pmovmskb %xmm3, %eax ++ incw %ax ++ jnz L(64bytesormore_loop_end) + +- ptest %xmm1, %xmm0 +- jnc L(64bytesormore_loop_end) + add $64, %rsi + add $64, %rdi + sub $64, %rdx +- jae L(L2_L3_unaligned_128bytes_loop) ++ ja L(L2_L3_unaligned_128bytes_loop) ++ jmp L(loop_tail) + +- add $64, %rdx +- add %rdx, %rsi +- add %rdx, %rdi +- BRANCH_TO_JMPTBL_ENTRY(L(table_64bytes), %rdx, 4) + +-/* +- * This case is for machines which are sensitive for unaligned instructions. +- */ ++ /* This case is for machines which are sensitive for unaligned ++ * instructions. */ + .p2align 4 + L(2aligned): + cmp $128, %rdx + ja L(128bytesormorein2aligned) + L(less128bytesin2aligned): +- sub $64, %rdx +- +- movdqa (%rdi), %xmm2 +- pxor (%rsi), %xmm2 +- ptest %xmm2, %xmm0 +- jnc L(16bytesin256) +- +- movdqa 16(%rdi), %xmm2 +- pxor 16(%rsi), %xmm2 +- ptest %xmm2, %xmm0 +- jnc L(32bytesin256) +- +- movdqa 32(%rdi), %xmm2 +- pxor 32(%rsi), %xmm2 +- ptest %xmm2, %xmm0 +- jnc L(48bytesin256) +- +- movdqa 48(%rdi), %xmm2 +- pxor 48(%rsi), %xmm2 +- ptest %xmm2, %xmm0 +- jnc L(64bytesin256) +- cmp $32, %rdx +- jb L(less32bytesin64in2alinged) +- +- movdqa 64(%rdi), %xmm2 +- pxor 64(%rsi), %xmm2 +- ptest %xmm2, %xmm0 +- jnc L(80bytesin256) +- +- movdqa 80(%rdi), %xmm2 +- pxor 80(%rsi), %xmm2 +- ptest %xmm2, %xmm0 +- jnc L(96bytesin256) +- sub $32, %rdx +- add $32, %rdi +- add $32, %rsi +-L(less32bytesin64in2alinged): +- add $64, %rdi +- add $64, %rsi +- add %rdx, %rsi +- add %rdx, %rdi +- BRANCH_TO_JMPTBL_ENTRY(L(table_64bytes), %rdx, 4) ++ movdqa (%rdi), %xmm1 ++ CMPEQ (%rsi), %xmm1 ++ pmovmskb %xmm1, %eax ++ incw %ax ++ jnz L(vec_return_begin) ++ ++ movdqa 16(%rdi), %xmm1 ++ CMPEQ 16(%rsi), %xmm1 ++ pmovmskb %xmm1, %eax ++ incw %ax ++ jnz L(vec_return_begin_16) ++ ++ movdqa 32(%rdi), %xmm1 ++ CMPEQ 32(%rsi), %xmm1 ++ pmovmskb %xmm1, %eax ++ incw %ax ++ jnz L(vec_return_begin_32) ++ ++ movdqa 48(%rdi), %xmm1 ++ CMPEQ 48(%rsi), %xmm1 ++ pmovmskb %xmm1, %eax ++ incw %ax ++ jnz L(vec_return_begin_48) ++ ++ cmp $96, %rdx ++ jb L(32_to_64_bytes) ++ ++ addq $64, %rdi ++ addq $64, %rsi ++ subq $64, %rdx ++ ++ .p2align 4,, 6 ++L(aligned_last_64_bytes): ++ movdqa (%rdi), %xmm1 ++ CMPEQ (%rsi), %xmm1 ++ pmovmskb %xmm1, %eax ++ incw %ax ++ jnz L(vec_return_begin) ++ ++ movdqa 16(%rdi), %xmm1 ++ CMPEQ 16(%rsi), %xmm1 ++ pmovmskb %xmm1, %eax ++ incw %ax ++ jnz L(vec_return_begin_16) ++ ++ movdqu -32(%rdi, %rdx), %xmm0 ++ movdqu -32(%rsi, %rdx), %xmm1 ++ CMPEQ %xmm0, %xmm1 ++ pmovmskb %xmm1, %eax ++ incw %ax ++ jnz L(vec_return_end_16) ++ ++ movdqu -16(%rdi, %rdx), %xmm0 ++ movdqu -16(%rsi, %rdx), %xmm1 ++ CMPEQ %xmm0, %xmm1 ++ pmovmskb %xmm1, %eax ++ incw %ax ++ jnz L(vec_return_end) ++ ret + + .p2align 4 + L(128bytesormorein2aligned): +- cmp $512, %rdx +- ja L(512bytesormorein2aligned) + cmp $256, %rdx +- ja L(256bytesormorein2aligned) ++ ja L(aligned_loop) + L(less256bytesin2alinged): +- sub $128, %rdx +- +- movdqa (%rdi), %xmm2 +- pxor (%rsi), %xmm2 +- ptest %xmm2, %xmm0 +- jnc L(16bytesin256) +- +- movdqa 16(%rdi), %xmm2 +- pxor 16(%rsi), %xmm2 +- ptest %xmm2, %xmm0 +- jnc L(32bytesin256) +- +- movdqa 32(%rdi), %xmm2 +- pxor 32(%rsi), %xmm2 +- ptest %xmm2, %xmm0 +- jnc L(48bytesin256) +- +- movdqa 48(%rdi), %xmm2 +- pxor 48(%rsi), %xmm2 +- ptest %xmm2, %xmm0 +- jnc L(64bytesin256) +- +- movdqa 64(%rdi), %xmm2 +- pxor 64(%rsi), %xmm2 +- ptest %xmm2, %xmm0 +- jnc L(80bytesin256) +- +- movdqa 80(%rdi), %xmm2 +- pxor 80(%rsi), %xmm2 +- ptest %xmm2, %xmm0 +- jnc L(96bytesin256) +- +- movdqa 96(%rdi), %xmm2 +- pxor 96(%rsi), %xmm2 +- ptest %xmm2, %xmm0 +- jnc L(112bytesin256) +- +- movdqa 112(%rdi), %xmm2 +- pxor 112(%rsi), %xmm2 +- ptest %xmm2, %xmm0 +- jnc L(128bytesin256) +- +- add $128, %rsi +- add $128, %rdi ++ movdqa (%rdi), %xmm1 ++ CMPEQ (%rsi), %xmm1 ++ pmovmskb %xmm1, %eax ++ incw %ax ++ jnz L(vec_return_begin) ++ ++ movdqa 16(%rdi), %xmm1 ++ CMPEQ 16(%rsi), %xmm1 ++ pmovmskb %xmm1, %eax ++ incw %ax ++ jnz L(vec_return_begin_16) ++ ++ movdqa 32(%rdi), %xmm1 ++ CMPEQ 32(%rsi), %xmm1 ++ pmovmskb %xmm1, %eax ++ incw %ax ++ jnz L(vec_return_begin_32) ++ ++ movdqa 48(%rdi), %xmm1 ++ CMPEQ 48(%rsi), %xmm1 ++ pmovmskb %xmm1, %eax ++ incw %ax ++ jnz L(vec_return_begin_48) ++ ++ addq $64, %rdi ++ addq $64, %rsi ++ ++ movdqa (%rdi), %xmm1 ++ CMPEQ (%rsi), %xmm1 ++ pmovmskb %xmm1, %eax ++ incw %ax ++ jnz L(vec_return_begin) ++ ++ movdqa 16(%rdi), %xmm1 ++ CMPEQ 16(%rsi), %xmm1 ++ pmovmskb %xmm1, %eax ++ incw %ax ++ jnz L(vec_return_begin_16) ++ ++ movdqa 32(%rdi), %xmm1 ++ CMPEQ 32(%rsi), %xmm1 ++ pmovmskb %xmm1, %eax ++ incw %ax ++ jnz L(vec_return_begin_32) ++ ++ movdqa 48(%rdi), %xmm1 ++ CMPEQ 48(%rsi), %xmm1 ++ pmovmskb %xmm1, %eax ++ incw %ax ++ jnz L(vec_return_begin_48) ++ ++ addq $-128, %rdx ++ subq $-64, %rsi ++ subq $-64, %rdi + + cmp $64, %rdx +- jae L(less128bytesin2aligned) ++ ja L(less128bytesin2aligned) + + cmp $32, %rdx +- jb L(less32bytesin128in2aligned) +- +- movdqu (%rdi), %xmm2 +- pxor (%rsi), %xmm2 +- ptest %xmm2, %xmm0 +- jnc L(16bytesin256) +- +- movdqu 16(%rdi), %xmm2 +- pxor 16(%rsi), %xmm2 +- ptest %xmm2, %xmm0 +- jnc L(32bytesin256) +- sub $32, %rdx +- add $32, %rdi +- add $32, %rsi +-L(less32bytesin128in2aligned): +- add %rdx, %rsi +- add %rdx, %rdi +- BRANCH_TO_JMPTBL_ENTRY(L(table_64bytes), %rdx, 4) +- +- .p2align 4 +-L(256bytesormorein2aligned): +- +- sub $256, %rdx +- movdqa (%rdi), %xmm2 +- pxor (%rsi), %xmm2 +- ptest %xmm2, %xmm0 +- jnc L(16bytesin256) +- +- movdqa 16(%rdi), %xmm2 +- pxor 16(%rsi), %xmm2 +- ptest %xmm2, %xmm0 +- jnc L(32bytesin256) +- +- movdqa 32(%rdi), %xmm2 +- pxor 32(%rsi), %xmm2 +- ptest %xmm2, %xmm0 +- jnc L(48bytesin256) +- +- movdqa 48(%rdi), %xmm2 +- pxor 48(%rsi), %xmm2 +- ptest %xmm2, %xmm0 +- jnc L(64bytesin256) +- +- movdqa 64(%rdi), %xmm2 +- pxor 64(%rsi), %xmm2 +- ptest %xmm2, %xmm0 +- jnc L(80bytesin256) +- +- movdqa 80(%rdi), %xmm2 +- pxor 80(%rsi), %xmm2 +- ptest %xmm2, %xmm0 +- jnc L(96bytesin256) +- +- movdqa 96(%rdi), %xmm2 +- pxor 96(%rsi), %xmm2 +- ptest %xmm2, %xmm0 +- jnc L(112bytesin256) +- +- movdqa 112(%rdi), %xmm2 +- pxor 112(%rsi), %xmm2 +- ptest %xmm2, %xmm0 +- jnc L(128bytesin256) +- +- movdqa 128(%rdi), %xmm2 +- pxor 128(%rsi), %xmm2 +- ptest %xmm2, %xmm0 +- jnc L(144bytesin256) +- +- movdqa 144(%rdi), %xmm2 +- pxor 144(%rsi), %xmm2 +- ptest %xmm2, %xmm0 +- jnc L(160bytesin256) +- +- movdqa 160(%rdi), %xmm2 +- pxor 160(%rsi), %xmm2 +- ptest %xmm2, %xmm0 +- jnc L(176bytesin256) +- +- movdqa 176(%rdi), %xmm2 +- pxor 176(%rsi), %xmm2 +- ptest %xmm2, %xmm0 +- jnc L(192bytesin256) +- +- movdqa 192(%rdi), %xmm2 +- pxor 192(%rsi), %xmm2 +- ptest %xmm2, %xmm0 +- jnc L(208bytesin256) +- +- movdqa 208(%rdi), %xmm2 +- pxor 208(%rsi), %xmm2 +- ptest %xmm2, %xmm0 +- jnc L(224bytesin256) +- +- movdqa 224(%rdi), %xmm2 +- pxor 224(%rsi), %xmm2 +- ptest %xmm2, %xmm0 +- jnc L(240bytesin256) +- +- movdqa 240(%rdi), %xmm2 +- pxor 240(%rsi), %xmm2 +- ptest %xmm2, %xmm0 +- jnc L(256bytesin256) +- +- add $256, %rsi +- add $256, %rdi +- +- cmp $128, %rdx +- jae L(less256bytesin2alinged) +- +- cmp $64, %rdx +- jae L(less128bytesin2aligned) +- +- cmp $32, %rdx +- jb L(less32bytesin256in2alinged) +- +- movdqa (%rdi), %xmm2 +- pxor (%rsi), %xmm2 +- ptest %xmm2, %xmm0 +- jnc L(16bytesin256) +- +- movdqa 16(%rdi), %xmm2 +- pxor 16(%rsi), %xmm2 +- ptest %xmm2, %xmm0 +- jnc L(32bytesin256) +- sub $32, %rdx +- add $32, %rdi +- add $32, %rsi +-L(less32bytesin256in2alinged): +- add %rdx, %rsi +- add %rdx, %rdi +- BRANCH_TO_JMPTBL_ENTRY(L(table_64bytes), %rdx, 4) ++ ja L(aligned_last_64_bytes) ++ ++ movdqu -32(%rdi, %rdx), %xmm0 ++ movdqu -32(%rsi, %rdx), %xmm1 ++ CMPEQ %xmm0, %xmm1 ++ pmovmskb %xmm1, %eax ++ incw %ax ++ jnz L(vec_return_end_16) ++ ++ movdqu -16(%rdi, %rdx), %xmm0 ++ movdqu -16(%rsi, %rdx), %xmm1 ++ CMPEQ %xmm0, %xmm1 ++ pmovmskb %xmm1, %eax ++ incw %ax ++ jnz L(vec_return_end) ++ ret + + .p2align 4 +-L(512bytesormorein2aligned): ++L(aligned_loop): + # ifdef DATA_CACHE_SIZE_HALF + mov $DATA_CACHE_SIZE_HALF, %R8_LP + # else + mov __x86_data_cache_size_half(%rip), %R8_LP + # endif +- mov %r8, %r9 +- shr $1, %r8 +- add %r9, %r8 +- cmp %r8, %rdx +- ja L(L2_L3_cache_aglined) ++ movq %r8, %r9 ++ addq %r8, %r8 ++ addq %r9, %r8 ++ cmpq %r8, %rdx ++ ja L(L2_L3_cache_aligned) + + sub $64, %rdx + .p2align 4 + L(64bytesormore_loopin2aligned): +- movdqa (%rdi), %xmm2 +- pxor (%rsi), %xmm2 +- movdqa %xmm2, %xmm1 +- +- movdqa 16(%rdi), %xmm3 +- pxor 16(%rsi), %xmm3 +- por %xmm3, %xmm1 ++ movdqa (%rdi), %xmm0 ++ movdqa 16(%rdi), %xmm1 ++ movdqa 32(%rdi), %xmm2 ++ movdqa 48(%rdi), %xmm3 + +- movdqa 32(%rdi), %xmm4 +- pxor 32(%rsi), %xmm4 +- por %xmm4, %xmm1 ++ CMPEQ (%rsi), %xmm0 ++ CMPEQ 16(%rsi), %xmm1 ++ CMPEQ 32(%rsi), %xmm2 ++ CMPEQ 48(%rsi), %xmm3 + +- movdqa 48(%rdi), %xmm5 +- pxor 48(%rsi), %xmm5 +- por %xmm5, %xmm1 ++ pand %xmm0, %xmm1 ++ pand %xmm2, %xmm3 ++ pand %xmm1, %xmm3 + +- ptest %xmm1, %xmm0 +- jnc L(64bytesormore_loop_end) ++ pmovmskb %xmm3, %eax ++ incw %ax ++ jnz L(64bytesormore_loop_end) + add $64, %rsi + add $64, %rdi + sub $64, %rdx +- jae L(64bytesormore_loopin2aligned) +- +- add $64, %rdx +- add %rdx, %rsi +- add %rdx, %rdi +- BRANCH_TO_JMPTBL_ENTRY(L(table_64bytes), %rdx, 4) +-L(L2_L3_cache_aglined): +- sub $64, %rdx ++ ja L(64bytesormore_loopin2aligned) ++ jmp L(loop_tail) + ++L(L2_L3_cache_aligned): ++ subq $64, %rdx + .p2align 4 + L(L2_L3_aligned_128bytes_loop): + prefetchnta 0x1c0(%rdi) + prefetchnta 0x1c0(%rsi) +- movdqa (%rdi), %xmm2 +- pxor (%rsi), %xmm2 +- movdqa %xmm2, %xmm1 +- +- movdqa 16(%rdi), %xmm3 +- pxor 16(%rsi), %xmm3 +- por %xmm3, %xmm1 ++ movdqa (%rdi), %xmm0 ++ movdqa 16(%rdi), %xmm1 ++ movdqa 32(%rdi), %xmm2 ++ movdqa 48(%rdi), %xmm3 + +- movdqa 32(%rdi), %xmm4 +- pxor 32(%rsi), %xmm4 +- por %xmm4, %xmm1 ++ CMPEQ (%rsi), %xmm0 ++ CMPEQ 16(%rsi), %xmm1 ++ CMPEQ 32(%rsi), %xmm2 ++ CMPEQ 48(%rsi), %xmm3 + +- movdqa 48(%rdi), %xmm5 +- pxor 48(%rsi), %xmm5 +- por %xmm5, %xmm1 ++ pand %xmm0, %xmm1 ++ pand %xmm2, %xmm3 ++ pand %xmm1, %xmm3 + +- ptest %xmm1, %xmm0 +- jnc L(64bytesormore_loop_end) +- add $64, %rsi +- add $64, %rdi +- sub $64, %rdx +- jae L(L2_L3_aligned_128bytes_loop) +- +- add $64, %rdx +- add %rdx, %rsi +- add %rdx, %rdi +- BRANCH_TO_JMPTBL_ENTRY(L(table_64bytes), %rdx, 4) ++ pmovmskb %xmm3, %eax ++ incw %ax ++ jnz L(64bytesormore_loop_end) + ++ addq $64, %rsi ++ addq $64, %rdi ++ subq $64, %rdx ++ ja L(L2_L3_aligned_128bytes_loop) ++ jmp L(loop_tail) + + .p2align 4 + L(64bytesormore_loop_end): +- add $16, %rdi +- add $16, %rsi +- ptest %xmm2, %xmm0 +- jnc L(16bytes) +- +- add $16, %rdi +- add $16, %rsi +- ptest %xmm3, %xmm0 +- jnc L(16bytes) +- +- add $16, %rdi +- add $16, %rsi +- ptest %xmm4, %xmm0 +- jnc L(16bytes) +- +- add $16, %rdi +- add $16, %rsi +- jmp L(16bytes) +- +-L(256bytesin256): +- add $256, %rdi +- add $256, %rsi +- jmp L(16bytes) +-L(240bytesin256): +- add $240, %rdi +- add $240, %rsi +- jmp L(16bytes) +-L(224bytesin256): +- add $224, %rdi +- add $224, %rsi +- jmp L(16bytes) +-L(208bytesin256): +- add $208, %rdi +- add $208, %rsi +- jmp L(16bytes) +-L(192bytesin256): +- add $192, %rdi +- add $192, %rsi +- jmp L(16bytes) +-L(176bytesin256): +- add $176, %rdi +- add $176, %rsi +- jmp L(16bytes) +-L(160bytesin256): +- add $160, %rdi +- add $160, %rsi +- jmp L(16bytes) +-L(144bytesin256): +- add $144, %rdi +- add $144, %rsi +- jmp L(16bytes) +-L(128bytesin256): +- add $128, %rdi +- add $128, %rsi +- jmp L(16bytes) +-L(112bytesin256): +- add $112, %rdi +- add $112, %rsi +- jmp L(16bytes) +-L(96bytesin256): +- add $96, %rdi +- add $96, %rsi +- jmp L(16bytes) +-L(80bytesin256): +- add $80, %rdi +- add $80, %rsi +- jmp L(16bytes) +-L(64bytesin256): +- add $64, %rdi +- add $64, %rsi +- jmp L(16bytes) +-L(48bytesin256): +- add $16, %rdi +- add $16, %rsi +-L(32bytesin256): +- add $16, %rdi +- add $16, %rsi +-L(16bytesin256): +- add $16, %rdi +- add $16, %rsi +-L(16bytes): +- mov -16(%rdi), %rax +- mov -16(%rsi), %rcx +- cmp %rax, %rcx +- jne L(diffin8bytes) +-L(8bytes): +- mov -8(%rdi), %rax +- mov -8(%rsi), %rcx +- cmp %rax, %rcx +- jne L(diffin8bytes) +- xor %eax, %eax +- ret +- +- .p2align 4 +-L(12bytes): +- mov -12(%rdi), %rax +- mov -12(%rsi), %rcx +- cmp %rax, %rcx +- jne L(diffin8bytes) +-L(4bytes): +- mov -4(%rsi), %ecx +-# ifndef USE_AS_WMEMCMP +- mov -4(%rdi), %eax +- cmp %eax, %ecx +-# else +- cmp -4(%rdi), %ecx +-# endif +- jne L(diffin4bytes) +-L(0bytes): +- xor %eax, %eax +- ret +- +-# ifndef USE_AS_WMEMCMP +-/* unreal case for wmemcmp */ +- .p2align 4 +-L(65bytes): +- movdqu -65(%rdi), %xmm1 +- movdqu -65(%rsi), %xmm2 +- mov $-65, %dl +- pxor %xmm1, %xmm2 +- ptest %xmm2, %xmm0 +- jnc L(less16bytes) +-L(49bytes): +- movdqu -49(%rdi), %xmm1 +- movdqu -49(%rsi), %xmm2 +- mov $-49, %dl +- pxor %xmm1, %xmm2 +- ptest %xmm2, %xmm0 +- jnc L(less16bytes) +-L(33bytes): +- movdqu -33(%rdi), %xmm1 +- movdqu -33(%rsi), %xmm2 +- mov $-33, %dl +- pxor %xmm1, %xmm2 +- ptest %xmm2, %xmm0 +- jnc L(less16bytes) +-L(17bytes): +- mov -17(%rdi), %rax +- mov -17(%rsi), %rcx +- cmp %rax, %rcx +- jne L(diffin8bytes) +-L(9bytes): +- mov -9(%rdi), %rax +- mov -9(%rsi), %rcx +- cmp %rax, %rcx +- jne L(diffin8bytes) +- movzbl -1(%rdi), %eax +- movzbl -1(%rsi), %edx +- sub %edx, %eax +- ret +- +- .p2align 4 +-L(13bytes): +- mov -13(%rdi), %rax +- mov -13(%rsi), %rcx +- cmp %rax, %rcx +- jne L(diffin8bytes) +- mov -8(%rdi), %rax +- mov -8(%rsi), %rcx +- cmp %rax, %rcx +- jne L(diffin8bytes) +- xor %eax, %eax +- ret +- +- .p2align 4 +-L(5bytes): +- mov -5(%rdi), %eax +- mov -5(%rsi), %ecx +- cmp %eax, %ecx +- jne L(diffin4bytes) +- movzbl -1(%rdi), %eax +- movzbl -1(%rsi), %edx +- sub %edx, %eax +- ret +- +- .p2align 4 +-L(66bytes): +- movdqu -66(%rdi), %xmm1 +- movdqu -66(%rsi), %xmm2 +- mov $-66, %dl +- pxor %xmm1, %xmm2 +- ptest %xmm2, %xmm0 +- jnc L(less16bytes) +-L(50bytes): +- movdqu -50(%rdi), %xmm1 +- movdqu -50(%rsi), %xmm2 +- mov $-50, %dl +- pxor %xmm1, %xmm2 +- ptest %xmm2, %xmm0 +- jnc L(less16bytes) +-L(34bytes): +- movdqu -34(%rdi), %xmm1 +- movdqu -34(%rsi), %xmm2 +- mov $-34, %dl +- pxor %xmm1, %xmm2 +- ptest %xmm2, %xmm0 +- jnc L(less16bytes) +-L(18bytes): +- mov -18(%rdi), %rax +- mov -18(%rsi), %rcx +- cmp %rax, %rcx +- jne L(diffin8bytes) +-L(10bytes): +- mov -10(%rdi), %rax +- mov -10(%rsi), %rcx +- cmp %rax, %rcx +- jne L(diffin8bytes) +- movzwl -2(%rdi), %eax +- movzwl -2(%rsi), %ecx +- cmp %cl, %al +- jne L(end) +- and $0xffff, %eax +- and $0xffff, %ecx +- sub %ecx, %eax +- ret +- +- .p2align 4 +-L(14bytes): +- mov -14(%rdi), %rax +- mov -14(%rsi), %rcx +- cmp %rax, %rcx +- jne L(diffin8bytes) +- mov -8(%rdi), %rax +- mov -8(%rsi), %rcx +- cmp %rax, %rcx +- jne L(diffin8bytes) +- xor %eax, %eax +- ret +- +- .p2align 4 +-L(6bytes): +- mov -6(%rdi), %eax +- mov -6(%rsi), %ecx +- cmp %eax, %ecx +- jne L(diffin4bytes) +-L(2bytes): +- movzwl -2(%rsi), %ecx +- movzwl -2(%rdi), %eax +- cmp %cl, %al +- jne L(end) +- and $0xffff, %eax +- and $0xffff, %ecx +- sub %ecx, %eax +- ret +- +- .p2align 4 +-L(67bytes): +- movdqu -67(%rdi), %xmm2 +- movdqu -67(%rsi), %xmm1 +- mov $-67, %dl +- pxor %xmm1, %xmm2 +- ptest %xmm2, %xmm0 +- jnc L(less16bytes) +-L(51bytes): +- movdqu -51(%rdi), %xmm2 +- movdqu -51(%rsi), %xmm1 +- mov $-51, %dl +- pxor %xmm1, %xmm2 +- ptest %xmm2, %xmm0 +- jnc L(less16bytes) +-L(35bytes): +- movdqu -35(%rsi), %xmm1 +- movdqu -35(%rdi), %xmm2 +- mov $-35, %dl +- pxor %xmm1, %xmm2 +- ptest %xmm2, %xmm0 +- jnc L(less16bytes) +-L(19bytes): +- mov -19(%rdi), %rax +- mov -19(%rsi), %rcx +- cmp %rax, %rcx +- jne L(diffin8bytes) +-L(11bytes): +- mov -11(%rdi), %rax +- mov -11(%rsi), %rcx +- cmp %rax, %rcx +- jne L(diffin8bytes) +- mov -4(%rdi), %eax +- mov -4(%rsi), %ecx +- cmp %eax, %ecx +- jne L(diffin4bytes) +- xor %eax, %eax +- ret +- +- .p2align 4 +-L(15bytes): +- mov -15(%rdi), %rax +- mov -15(%rsi), %rcx +- cmp %rax, %rcx +- jne L(diffin8bytes) +- mov -8(%rdi), %rax +- mov -8(%rsi), %rcx +- cmp %rax, %rcx +- jne L(diffin8bytes) +- xor %eax, %eax +- ret +- +- .p2align 4 +-L(7bytes): +- mov -7(%rdi), %eax +- mov -7(%rsi), %ecx +- cmp %eax, %ecx +- jne L(diffin4bytes) +- mov -4(%rdi), %eax +- mov -4(%rsi), %ecx +- cmp %eax, %ecx +- jne L(diffin4bytes) +- xor %eax, %eax +- ret +- +- .p2align 4 +-L(3bytes): +- movzwl -3(%rdi), %eax +- movzwl -3(%rsi), %ecx +- cmp %eax, %ecx +- jne L(diffin2bytes) +-L(1bytes): +- movzbl -1(%rdi), %eax +- movzbl -1(%rsi), %ecx +- sub %ecx, %eax +- ret +-# endif +- +- .p2align 4 +-L(68bytes): +- movdqu -68(%rdi), %xmm2 +- movdqu -68(%rsi), %xmm1 +- mov $-68, %dl +- pxor %xmm1, %xmm2 +- ptest %xmm2, %xmm0 +- jnc L(less16bytes) +-L(52bytes): +- movdqu -52(%rdi), %xmm2 +- movdqu -52(%rsi), %xmm1 +- mov $-52, %dl +- pxor %xmm1, %xmm2 +- ptest %xmm2, %xmm0 +- jnc L(less16bytes) +-L(36bytes): +- movdqu -36(%rdi), %xmm2 +- movdqu -36(%rsi), %xmm1 +- mov $-36, %dl +- pxor %xmm1, %xmm2 +- ptest %xmm2, %xmm0 +- jnc L(less16bytes) +-L(20bytes): +- movdqu -20(%rdi), %xmm2 +- movdqu -20(%rsi), %xmm1 +- mov $-20, %dl +- pxor %xmm1, %xmm2 +- ptest %xmm2, %xmm0 +- jnc L(less16bytes) +- mov -4(%rsi), %ecx +- +-# ifndef USE_AS_WMEMCMP +- mov -4(%rdi), %eax +- cmp %eax, %ecx +-# else +- cmp -4(%rdi), %ecx +-# endif +- jne L(diffin4bytes) +- xor %eax, %eax +- ret +- +-# ifndef USE_AS_WMEMCMP +-/* unreal cases for wmemcmp */ +- .p2align 4 +-L(69bytes): +- movdqu -69(%rsi), %xmm1 +- movdqu -69(%rdi), %xmm2 +- mov $-69, %dl +- pxor %xmm1, %xmm2 +- ptest %xmm2, %xmm0 +- jnc L(less16bytes) +-L(53bytes): +- movdqu -53(%rsi), %xmm1 +- movdqu -53(%rdi), %xmm2 +- mov $-53, %dl +- pxor %xmm1, %xmm2 +- ptest %xmm2, %xmm0 +- jnc L(less16bytes) +-L(37bytes): +- movdqu -37(%rsi), %xmm1 +- movdqu -37(%rdi), %xmm2 +- mov $-37, %dl +- pxor %xmm1, %xmm2 +- ptest %xmm2, %xmm0 +- jnc L(less16bytes) +-L(21bytes): +- movdqu -21(%rsi), %xmm1 +- movdqu -21(%rdi), %xmm2 +- mov $-21, %dl +- pxor %xmm1, %xmm2 +- ptest %xmm2, %xmm0 +- jnc L(less16bytes) +- mov -8(%rdi), %rax +- mov -8(%rsi), %rcx +- cmp %rax, %rcx +- jne L(diffin8bytes) +- xor %eax, %eax +- ret +- +- .p2align 4 +-L(70bytes): +- movdqu -70(%rsi), %xmm1 +- movdqu -70(%rdi), %xmm2 +- mov $-70, %dl +- pxor %xmm1, %xmm2 +- ptest %xmm2, %xmm0 +- jnc L(less16bytes) +-L(54bytes): +- movdqu -54(%rsi), %xmm1 +- movdqu -54(%rdi), %xmm2 +- mov $-54, %dl +- pxor %xmm1, %xmm2 +- ptest %xmm2, %xmm0 +- jnc L(less16bytes) +-L(38bytes): +- movdqu -38(%rsi), %xmm1 +- movdqu -38(%rdi), %xmm2 +- mov $-38, %dl +- pxor %xmm1, %xmm2 +- ptest %xmm2, %xmm0 +- jnc L(less16bytes) +-L(22bytes): +- movdqu -22(%rsi), %xmm1 +- movdqu -22(%rdi), %xmm2 +- mov $-22, %dl +- pxor %xmm1, %xmm2 +- ptest %xmm2, %xmm0 +- jnc L(less16bytes) +- mov -8(%rdi), %rax +- mov -8(%rsi), %rcx +- cmp %rax, %rcx +- jne L(diffin8bytes) +- xor %eax, %eax +- ret +- +- .p2align 4 +-L(71bytes): +- movdqu -71(%rsi), %xmm1 +- movdqu -71(%rdi), %xmm2 +- mov $-71, %dl +- pxor %xmm1, %xmm2 +- ptest %xmm2, %xmm0 +- jnc L(less16bytes) +-L(55bytes): +- movdqu -55(%rdi), %xmm2 +- movdqu -55(%rsi), %xmm1 +- mov $-55, %dl +- pxor %xmm1, %xmm2 +- ptest %xmm2, %xmm0 +- jnc L(less16bytes) +-L(39bytes): +- movdqu -39(%rdi), %xmm2 +- movdqu -39(%rsi), %xmm1 +- mov $-39, %dl +- pxor %xmm1, %xmm2 +- ptest %xmm2, %xmm0 +- jnc L(less16bytes) +-L(23bytes): +- movdqu -23(%rdi), %xmm2 +- movdqu -23(%rsi), %xmm1 +- mov $-23, %dl +- pxor %xmm1, %xmm2 +- ptest %xmm2, %xmm0 +- jnc L(less16bytes) +- mov -8(%rdi), %rax +- mov -8(%rsi), %rcx +- cmp %rax, %rcx +- jne L(diffin8bytes) +- xor %eax, %eax +- ret +-# endif +- +- .p2align 4 +-L(72bytes): +- movdqu -72(%rsi), %xmm1 +- movdqu -72(%rdi), %xmm2 +- mov $-72, %dl +- pxor %xmm1, %xmm2 +- ptest %xmm2, %xmm0 +- jnc L(less16bytes) +-L(56bytes): +- movdqu -56(%rdi), %xmm2 +- movdqu -56(%rsi), %xmm1 +- mov $-56, %dl +- pxor %xmm1, %xmm2 +- ptest %xmm2, %xmm0 +- jnc L(less16bytes) +-L(40bytes): +- movdqu -40(%rdi), %xmm2 +- movdqu -40(%rsi), %xmm1 +- mov $-40, %dl +- pxor %xmm1, %xmm2 +- ptest %xmm2, %xmm0 +- jnc L(less16bytes) +-L(24bytes): +- movdqu -24(%rdi), %xmm2 +- movdqu -24(%rsi), %xmm1 +- mov $-24, %dl +- pxor %xmm1, %xmm2 +- ptest %xmm2, %xmm0 +- jnc L(less16bytes) +- +- mov -8(%rsi), %rcx +- mov -8(%rdi), %rax +- cmp %rax, %rcx +- jne L(diffin8bytes) +- xor %eax, %eax +- ret +- +-# ifndef USE_AS_WMEMCMP +-/* unreal cases for wmemcmp */ +- .p2align 4 +-L(73bytes): +- movdqu -73(%rsi), %xmm1 +- movdqu -73(%rdi), %xmm2 +- mov $-73, %dl +- pxor %xmm1, %xmm2 +- ptest %xmm2, %xmm0 +- jnc L(less16bytes) +-L(57bytes): +- movdqu -57(%rdi), %xmm2 +- movdqu -57(%rsi), %xmm1 +- mov $-57, %dl +- pxor %xmm1, %xmm2 +- ptest %xmm2, %xmm0 +- jnc L(less16bytes) +-L(41bytes): +- movdqu -41(%rdi), %xmm2 +- movdqu -41(%rsi), %xmm1 +- mov $-41, %dl +- pxor %xmm1, %xmm2 +- ptest %xmm2, %xmm0 +- jnc L(less16bytes) +-L(25bytes): +- movdqu -25(%rdi), %xmm2 +- movdqu -25(%rsi), %xmm1 +- mov $-25, %dl +- pxor %xmm1, %xmm2 +- ptest %xmm2, %xmm0 +- jnc L(less16bytes) +- mov -9(%rdi), %rax +- mov -9(%rsi), %rcx +- cmp %rax, %rcx +- jne L(diffin8bytes) +- movzbl -1(%rdi), %eax +- movzbl -1(%rsi), %ecx +- sub %ecx, %eax +- ret +- +- .p2align 4 +-L(74bytes): +- movdqu -74(%rsi), %xmm1 +- movdqu -74(%rdi), %xmm2 +- mov $-74, %dl +- pxor %xmm1, %xmm2 +- ptest %xmm2, %xmm0 +- jnc L(less16bytes) +-L(58bytes): +- movdqu -58(%rdi), %xmm2 +- movdqu -58(%rsi), %xmm1 +- mov $-58, %dl +- pxor %xmm1, %xmm2 +- ptest %xmm2, %xmm0 +- jnc L(less16bytes) +-L(42bytes): +- movdqu -42(%rdi), %xmm2 +- movdqu -42(%rsi), %xmm1 +- mov $-42, %dl +- pxor %xmm1, %xmm2 +- ptest %xmm2, %xmm0 +- jnc L(less16bytes) +-L(26bytes): +- movdqu -26(%rdi), %xmm2 +- movdqu -26(%rsi), %xmm1 +- mov $-26, %dl +- pxor %xmm1, %xmm2 +- ptest %xmm2, %xmm0 +- jnc L(less16bytes) +- mov -10(%rdi), %rax +- mov -10(%rsi), %rcx +- cmp %rax, %rcx +- jne L(diffin8bytes) +- movzwl -2(%rdi), %eax +- movzwl -2(%rsi), %ecx +- jmp L(diffin2bytes) +- +- .p2align 4 +-L(75bytes): +- movdqu -75(%rsi), %xmm1 +- movdqu -75(%rdi), %xmm2 +- mov $-75, %dl +- pxor %xmm1, %xmm2 +- ptest %xmm2, %xmm0 +- jnc L(less16bytes) +-L(59bytes): +- movdqu -59(%rdi), %xmm2 +- movdqu -59(%rsi), %xmm1 +- mov $-59, %dl +- pxor %xmm1, %xmm2 +- ptest %xmm2, %xmm0 +- jnc L(less16bytes) +-L(43bytes): +- movdqu -43(%rdi), %xmm2 +- movdqu -43(%rsi), %xmm1 +- mov $-43, %dl +- pxor %xmm1, %xmm2 +- ptest %xmm2, %xmm0 +- jnc L(less16bytes) +-L(27bytes): +- movdqu -27(%rdi), %xmm2 +- movdqu -27(%rsi), %xmm1 +- mov $-27, %dl +- pxor %xmm1, %xmm2 +- ptest %xmm2, %xmm0 +- jnc L(less16bytes) +- mov -11(%rdi), %rax +- mov -11(%rsi), %rcx +- cmp %rax, %rcx +- jne L(diffin8bytes) +- mov -4(%rdi), %eax +- mov -4(%rsi), %ecx +- cmp %eax, %ecx +- jne L(diffin4bytes) +- xor %eax, %eax +- ret +-# endif +- .p2align 4 +-L(76bytes): +- movdqu -76(%rsi), %xmm1 +- movdqu -76(%rdi), %xmm2 +- mov $-76, %dl +- pxor %xmm1, %xmm2 +- ptest %xmm2, %xmm0 +- jnc L(less16bytes) +-L(60bytes): +- movdqu -60(%rdi), %xmm2 +- movdqu -60(%rsi), %xmm1 +- mov $-60, %dl +- pxor %xmm1, %xmm2 +- ptest %xmm2, %xmm0 +- jnc L(less16bytes) +-L(44bytes): +- movdqu -44(%rdi), %xmm2 +- movdqu -44(%rsi), %xmm1 +- mov $-44, %dl +- pxor %xmm1, %xmm2 +- ptest %xmm2, %xmm0 +- jnc L(less16bytes) +-L(28bytes): +- movdqu -28(%rdi), %xmm2 +- movdqu -28(%rsi), %xmm1 +- mov $-28, %dl +- pxor %xmm1, %xmm2 +- ptest %xmm2, %xmm0 +- jnc L(less16bytes) +- mov -12(%rdi), %rax +- mov -12(%rsi), %rcx +- cmp %rax, %rcx +- jne L(diffin8bytes) +- mov -4(%rsi), %ecx +-# ifndef USE_AS_WMEMCMP +- mov -4(%rdi), %eax +- cmp %eax, %ecx +-# else +- cmp -4(%rdi), %ecx +-# endif +- jne L(diffin4bytes) +- xor %eax, %eax +- ret +- +-# ifndef USE_AS_WMEMCMP +-/* unreal cases for wmemcmp */ +- .p2align 4 +-L(77bytes): +- movdqu -77(%rsi), %xmm1 +- movdqu -77(%rdi), %xmm2 +- mov $-77, %dl +- pxor %xmm1, %xmm2 +- ptest %xmm2, %xmm0 +- jnc L(less16bytes) +-L(61bytes): +- movdqu -61(%rdi), %xmm2 +- movdqu -61(%rsi), %xmm1 +- mov $-61, %dl +- pxor %xmm1, %xmm2 +- ptest %xmm2, %xmm0 +- jnc L(less16bytes) +-L(45bytes): +- movdqu -45(%rdi), %xmm2 +- movdqu -45(%rsi), %xmm1 +- mov $-45, %dl +- pxor %xmm1, %xmm2 +- ptest %xmm2, %xmm0 +- jnc L(less16bytes) +-L(29bytes): +- movdqu -29(%rdi), %xmm2 +- movdqu -29(%rsi), %xmm1 +- mov $-29, %dl +- pxor %xmm1, %xmm2 +- ptest %xmm2, %xmm0 +- jnc L(less16bytes) +- +- mov -13(%rdi), %rax +- mov -13(%rsi), %rcx +- cmp %rax, %rcx +- jne L(diffin8bytes) +- +- mov -8(%rdi), %rax +- mov -8(%rsi), %rcx +- cmp %rax, %rcx +- jne L(diffin8bytes) +- xor %eax, %eax +- ret +- +- .p2align 4 +-L(78bytes): +- movdqu -78(%rsi), %xmm1 +- movdqu -78(%rdi), %xmm2 +- mov $-78, %dl +- pxor %xmm1, %xmm2 +- ptest %xmm2, %xmm0 +- jnc L(less16bytes) +-L(62bytes): +- movdqu -62(%rdi), %xmm2 +- movdqu -62(%rsi), %xmm1 +- mov $-62, %dl +- pxor %xmm1, %xmm2 +- ptest %xmm2, %xmm0 +- jnc L(less16bytes) +-L(46bytes): +- movdqu -46(%rdi), %xmm2 +- movdqu -46(%rsi), %xmm1 +- mov $-46, %dl +- pxor %xmm1, %xmm2 +- ptest %xmm2, %xmm0 +- jnc L(less16bytes) +-L(30bytes): +- movdqu -30(%rdi), %xmm2 +- movdqu -30(%rsi), %xmm1 +- mov $-30, %dl +- pxor %xmm1, %xmm2 +- ptest %xmm2, %xmm0 +- jnc L(less16bytes) +- mov -14(%rdi), %rax +- mov -14(%rsi), %rcx +- cmp %rax, %rcx +- jne L(diffin8bytes) +- mov -8(%rdi), %rax +- mov -8(%rsi), %rcx +- cmp %rax, %rcx +- jne L(diffin8bytes) +- xor %eax, %eax +- ret +- +- .p2align 4 +-L(79bytes): +- movdqu -79(%rsi), %xmm1 +- movdqu -79(%rdi), %xmm2 +- mov $-79, %dl +- pxor %xmm1, %xmm2 +- ptest %xmm2, %xmm0 +- jnc L(less16bytes) +-L(63bytes): +- movdqu -63(%rdi), %xmm2 +- movdqu -63(%rsi), %xmm1 +- mov $-63, %dl +- pxor %xmm1, %xmm2 +- ptest %xmm2, %xmm0 +- jnc L(less16bytes) +-L(47bytes): +- movdqu -47(%rdi), %xmm2 +- movdqu -47(%rsi), %xmm1 +- mov $-47, %dl +- pxor %xmm1, %xmm2 +- ptest %xmm2, %xmm0 +- jnc L(less16bytes) +-L(31bytes): +- movdqu -31(%rdi), %xmm2 +- movdqu -31(%rsi), %xmm1 +- mov $-31, %dl +- pxor %xmm1, %xmm2 +- ptest %xmm2, %xmm0 +- jnc L(less16bytes) +- mov -15(%rdi), %rax +- mov -15(%rsi), %rcx +- cmp %rax, %rcx +- jne L(diffin8bytes) +- mov -8(%rdi), %rax +- mov -8(%rsi), %rcx +- cmp %rax, %rcx +- jne L(diffin8bytes) +- xor %eax, %eax +- ret +-# endif +- .p2align 4 +-L(64bytes): +- movdqu -64(%rdi), %xmm2 +- movdqu -64(%rsi), %xmm1 +- mov $-64, %dl +- pxor %xmm1, %xmm2 +- ptest %xmm2, %xmm0 +- jnc L(less16bytes) +-L(48bytes): +- movdqu -48(%rdi), %xmm2 +- movdqu -48(%rsi), %xmm1 +- mov $-48, %dl +- pxor %xmm1, %xmm2 +- ptest %xmm2, %xmm0 +- jnc L(less16bytes) +-L(32bytes): +- movdqu -32(%rdi), %xmm2 +- movdqu -32(%rsi), %xmm1 +- mov $-32, %dl +- pxor %xmm1, %xmm2 +- ptest %xmm2, %xmm0 +- jnc L(less16bytes) +- +- mov -16(%rdi), %rax +- mov -16(%rsi), %rcx +- cmp %rax, %rcx +- jne L(diffin8bytes) +- +- mov -8(%rdi), %rax +- mov -8(%rsi), %rcx +- cmp %rax, %rcx +- jne L(diffin8bytes) +- xor %eax, %eax +- ret +- +-/* +- * Aligned 8 bytes to avoid 2 branch "taken" in one 16 alinged code block. +- */ +- .p2align 3 +-L(less16bytes): +- movsbq %dl, %rdx +- mov (%rsi, %rdx), %rcx +- mov (%rdi, %rdx), %rax +- cmp %rax, %rcx +- jne L(diffin8bytes) +- mov 8(%rsi, %rdx), %rcx +- mov 8(%rdi, %rdx), %rax +-L(diffin8bytes): +- cmp %eax, %ecx +- jne L(diffin4bytes) +- shr $32, %rcx +- shr $32, %rax +- ++ pmovmskb %xmm0, %ecx ++ incw %cx ++ jnz L(loop_end_ret) ++ ++ pmovmskb %xmm1, %ecx ++ notw %cx ++ sall $16, %ecx ++ jnz L(loop_end_ret) ++ ++ pmovmskb %xmm2, %ecx ++ notw %cx ++ shlq $32, %rcx ++ jnz L(loop_end_ret) ++ ++ addq $48, %rdi ++ addq $48, %rsi ++ movq %rax, %rcx ++ ++ .p2align 4,, 6 ++L(loop_end_ret): ++ bsfq %rcx, %rcx + # ifdef USE_AS_WMEMCMP +-/* for wmemcmp */ +- cmp %eax, %ecx +- jne L(diffin4bytes) +- xor %eax, %eax +- ret +-# endif +- +-L(diffin4bytes): +-# ifndef USE_AS_WMEMCMP +- cmp %cx, %ax +- jne L(diffin2bytes) +- shr $16, %ecx +- shr $16, %eax +-L(diffin2bytes): +- cmp %cl, %al +- jne L(end) +- and $0xffff, %eax +- and $0xffff, %ecx +- sub %ecx, %eax +- ret +- +- .p2align 4 +-L(end): +- and $0xff, %eax +- and $0xff, %ecx +- sub %ecx, %eax +- ret ++ movl (%rdi, %rcx), %eax ++ xorl %edx, %edx ++ cmpl (%rsi, %rcx), %eax ++ setg %dl ++ leal -1(%rdx, %rdx), %eax + # else +- +-/* for wmemcmp */ +- mov $1, %eax +- jl L(nequal_bigger) +- neg %eax +- ret +- +- .p2align 4 +-L(nequal_bigger): +- ret +- +-L(unreal_case): +- xor %eax, %eax +- ret ++ movzbl (%rdi, %rcx), %eax ++ movzbl (%rsi, %rcx), %ecx ++ subl %ecx, %eax + # endif +- ++ ret + END (MEMCMP) +- +- .section .rodata.sse4.1,"a",@progbits +- .p2align 3 +-# ifndef USE_AS_WMEMCMP +-L(table_64bytes): +- .int JMPTBL (L(0bytes), L(table_64bytes)) +- .int JMPTBL (L(1bytes), L(table_64bytes)) +- .int JMPTBL (L(2bytes), L(table_64bytes)) +- .int JMPTBL (L(3bytes), L(table_64bytes)) +- .int JMPTBL (L(4bytes), L(table_64bytes)) +- .int JMPTBL (L(5bytes), L(table_64bytes)) +- .int JMPTBL (L(6bytes), L(table_64bytes)) +- .int JMPTBL (L(7bytes), L(table_64bytes)) +- .int JMPTBL (L(8bytes), L(table_64bytes)) +- .int JMPTBL (L(9bytes), L(table_64bytes)) +- .int JMPTBL (L(10bytes), L(table_64bytes)) +- .int JMPTBL (L(11bytes), L(table_64bytes)) +- .int JMPTBL (L(12bytes), L(table_64bytes)) +- .int JMPTBL (L(13bytes), L(table_64bytes)) +- .int JMPTBL (L(14bytes), L(table_64bytes)) +- .int JMPTBL (L(15bytes), L(table_64bytes)) +- .int JMPTBL (L(16bytes), L(table_64bytes)) +- .int JMPTBL (L(17bytes), L(table_64bytes)) +- .int JMPTBL (L(18bytes), L(table_64bytes)) +- .int JMPTBL (L(19bytes), L(table_64bytes)) +- .int JMPTBL (L(20bytes), L(table_64bytes)) +- .int JMPTBL (L(21bytes), L(table_64bytes)) +- .int JMPTBL (L(22bytes), L(table_64bytes)) +- .int JMPTBL (L(23bytes), L(table_64bytes)) +- .int JMPTBL (L(24bytes), L(table_64bytes)) +- .int JMPTBL (L(25bytes), L(table_64bytes)) +- .int JMPTBL (L(26bytes), L(table_64bytes)) +- .int JMPTBL (L(27bytes), L(table_64bytes)) +- .int JMPTBL (L(28bytes), L(table_64bytes)) +- .int JMPTBL (L(29bytes), L(table_64bytes)) +- .int JMPTBL (L(30bytes), L(table_64bytes)) +- .int JMPTBL (L(31bytes), L(table_64bytes)) +- .int JMPTBL (L(32bytes), L(table_64bytes)) +- .int JMPTBL (L(33bytes), L(table_64bytes)) +- .int JMPTBL (L(34bytes), L(table_64bytes)) +- .int JMPTBL (L(35bytes), L(table_64bytes)) +- .int JMPTBL (L(36bytes), L(table_64bytes)) +- .int JMPTBL (L(37bytes), L(table_64bytes)) +- .int JMPTBL (L(38bytes), L(table_64bytes)) +- .int JMPTBL (L(39bytes), L(table_64bytes)) +- .int JMPTBL (L(40bytes), L(table_64bytes)) +- .int JMPTBL (L(41bytes), L(table_64bytes)) +- .int JMPTBL (L(42bytes), L(table_64bytes)) +- .int JMPTBL (L(43bytes), L(table_64bytes)) +- .int JMPTBL (L(44bytes), L(table_64bytes)) +- .int JMPTBL (L(45bytes), L(table_64bytes)) +- .int JMPTBL (L(46bytes), L(table_64bytes)) +- .int JMPTBL (L(47bytes), L(table_64bytes)) +- .int JMPTBL (L(48bytes), L(table_64bytes)) +- .int JMPTBL (L(49bytes), L(table_64bytes)) +- .int JMPTBL (L(50bytes), L(table_64bytes)) +- .int JMPTBL (L(51bytes), L(table_64bytes)) +- .int JMPTBL (L(52bytes), L(table_64bytes)) +- .int JMPTBL (L(53bytes), L(table_64bytes)) +- .int JMPTBL (L(54bytes), L(table_64bytes)) +- .int JMPTBL (L(55bytes), L(table_64bytes)) +- .int JMPTBL (L(56bytes), L(table_64bytes)) +- .int JMPTBL (L(57bytes), L(table_64bytes)) +- .int JMPTBL (L(58bytes), L(table_64bytes)) +- .int JMPTBL (L(59bytes), L(table_64bytes)) +- .int JMPTBL (L(60bytes), L(table_64bytes)) +- .int JMPTBL (L(61bytes), L(table_64bytes)) +- .int JMPTBL (L(62bytes), L(table_64bytes)) +- .int JMPTBL (L(63bytes), L(table_64bytes)) +- .int JMPTBL (L(64bytes), L(table_64bytes)) +- .int JMPTBL (L(65bytes), L(table_64bytes)) +- .int JMPTBL (L(66bytes), L(table_64bytes)) +- .int JMPTBL (L(67bytes), L(table_64bytes)) +- .int JMPTBL (L(68bytes), L(table_64bytes)) +- .int JMPTBL (L(69bytes), L(table_64bytes)) +- .int JMPTBL (L(70bytes), L(table_64bytes)) +- .int JMPTBL (L(71bytes), L(table_64bytes)) +- .int JMPTBL (L(72bytes), L(table_64bytes)) +- .int JMPTBL (L(73bytes), L(table_64bytes)) +- .int JMPTBL (L(74bytes), L(table_64bytes)) +- .int JMPTBL (L(75bytes), L(table_64bytes)) +- .int JMPTBL (L(76bytes), L(table_64bytes)) +- .int JMPTBL (L(77bytes), L(table_64bytes)) +- .int JMPTBL (L(78bytes), L(table_64bytes)) +- .int JMPTBL (L(79bytes), L(table_64bytes)) +-# else +-L(table_64bytes): +- .int JMPTBL (L(0bytes), L(table_64bytes)) +- .int JMPTBL (L(unreal_case), L(table_64bytes)) +- .int JMPTBL (L(unreal_case), L(table_64bytes)) +- .int JMPTBL (L(unreal_case), L(table_64bytes)) +- .int JMPTBL (L(4bytes), L(table_64bytes)) +- .int JMPTBL (L(unreal_case), L(table_64bytes)) +- .int JMPTBL (L(unreal_case), L(table_64bytes)) +- .int JMPTBL (L(unreal_case), L(table_64bytes)) +- .int JMPTBL (L(8bytes), L(table_64bytes)) +- .int JMPTBL (L(unreal_case), L(table_64bytes)) +- .int JMPTBL (L(unreal_case), L(table_64bytes)) +- .int JMPTBL (L(unreal_case), L(table_64bytes)) +- .int JMPTBL (L(12bytes), L(table_64bytes)) +- .int JMPTBL (L(unreal_case), L(table_64bytes)) +- .int JMPTBL (L(unreal_case), L(table_64bytes)) +- .int JMPTBL (L(unreal_case), L(table_64bytes)) +- .int JMPTBL (L(16bytes), L(table_64bytes)) +- .int JMPTBL (L(unreal_case), L(table_64bytes)) +- .int JMPTBL (L(unreal_case), L(table_64bytes)) +- .int JMPTBL (L(unreal_case), L(table_64bytes)) +- .int JMPTBL (L(20bytes), L(table_64bytes)) +- .int JMPTBL (L(unreal_case), L(table_64bytes)) +- .int JMPTBL (L(unreal_case), L(table_64bytes)) +- .int JMPTBL (L(unreal_case), L(table_64bytes)) +- .int JMPTBL (L(24bytes), L(table_64bytes)) +- .int JMPTBL (L(unreal_case), L(table_64bytes)) +- .int JMPTBL (L(unreal_case), L(table_64bytes)) +- .int JMPTBL (L(unreal_case), L(table_64bytes)) +- .int JMPTBL (L(28bytes), L(table_64bytes)) +- .int JMPTBL (L(unreal_case), L(table_64bytes)) +- .int JMPTBL (L(unreal_case), L(table_64bytes)) +- .int JMPTBL (L(unreal_case), L(table_64bytes)) +- .int JMPTBL (L(32bytes), L(table_64bytes)) +- .int JMPTBL (L(unreal_case), L(table_64bytes)) +- .int JMPTBL (L(unreal_case), L(table_64bytes)) +- .int JMPTBL (L(unreal_case), L(table_64bytes)) +- .int JMPTBL (L(36bytes), L(table_64bytes)) +- .int JMPTBL (L(unreal_case), L(table_64bytes)) +- .int JMPTBL (L(unreal_case), L(table_64bytes)) +- .int JMPTBL (L(unreal_case), L(table_64bytes)) +- .int JMPTBL (L(40bytes), L(table_64bytes)) +- .int JMPTBL (L(unreal_case), L(table_64bytes)) +- .int JMPTBL (L(unreal_case), L(table_64bytes)) +- .int JMPTBL (L(unreal_case), L(table_64bytes)) +- .int JMPTBL (L(44bytes), L(table_64bytes)) +- .int JMPTBL (L(unreal_case), L(table_64bytes)) +- .int JMPTBL (L(unreal_case), L(table_64bytes)) +- .int JMPTBL (L(unreal_case), L(table_64bytes)) +- .int JMPTBL (L(48bytes), L(table_64bytes)) +- .int JMPTBL (L(unreal_case), L(table_64bytes)) +- .int JMPTBL (L(unreal_case), L(table_64bytes)) +- .int JMPTBL (L(unreal_case), L(table_64bytes)) +- .int JMPTBL (L(52bytes), L(table_64bytes)) +- .int JMPTBL (L(unreal_case), L(table_64bytes)) +- .int JMPTBL (L(unreal_case), L(table_64bytes)) +- .int JMPTBL (L(unreal_case), L(table_64bytes)) +- .int JMPTBL (L(56bytes), L(table_64bytes)) +- .int JMPTBL (L(unreal_case), L(table_64bytes)) +- .int JMPTBL (L(unreal_case), L(table_64bytes)) +- .int JMPTBL (L(unreal_case), L(table_64bytes)) +- .int JMPTBL (L(60bytes), L(table_64bytes)) +- .int JMPTBL (L(unreal_case), L(table_64bytes)) +- .int JMPTBL (L(unreal_case), L(table_64bytes)) +- .int JMPTBL (L(unreal_case), L(table_64bytes)) +- .int JMPTBL (L(64bytes), L(table_64bytes)) +- .int JMPTBL (L(unreal_case), L(table_64bytes)) +- .int JMPTBL (L(unreal_case), L(table_64bytes)) +- .int JMPTBL (L(unreal_case), L(table_64bytes)) +- .int JMPTBL (L(68bytes), L(table_64bytes)) +- .int JMPTBL (L(unreal_case), L(table_64bytes)) +- .int JMPTBL (L(unreal_case), L(table_64bytes)) +- .int JMPTBL (L(unreal_case), L(table_64bytes)) +- .int JMPTBL (L(72bytes), L(table_64bytes)) +- .int JMPTBL (L(unreal_case), L(table_64bytes)) +- .int JMPTBL (L(unreal_case), L(table_64bytes)) +- .int JMPTBL (L(unreal_case), L(table_64bytes)) +- .int JMPTBL (L(76bytes), L(table_64bytes)) +- .int JMPTBL (L(unreal_case), L(table_64bytes)) +- .int JMPTBL (L(unreal_case), L(table_64bytes)) +- .int JMPTBL (L(unreal_case), L(table_64bytes)) +-# endif + #endif +-- +GitLab + diff --git a/SOURCES/glibc-RHEL-15696-64.patch b/SOURCES/glibc-RHEL-15696-64.patch new file mode 100644 index 0000000..ba7f14a --- /dev/null +++ b/SOURCES/glibc-RHEL-15696-64.patch @@ -0,0 +1,39 @@ +From 0b82747dc48d5bf0871bdc6da8cb6eec1256355f Mon Sep 17 00:00:00 2001 +From: "H.J. Lu" +Date: Thu, 11 Nov 2021 06:31:51 -0800 +Subject: [PATCH] Avoid extra load with CAS in __pthread_mutex_lock_full [BZ + #28537] +Content-type: text/plain; charset=UTF-8 + +Replace boolean CAS with value CAS to avoid the extra load. + +Reviewed-by: Szabolcs Nagy +--- + nptl/pthread_mutex_lock.c | 10 +++++----- + 1 file changed, 5 insertions(+), 5 deletions(-) + +diff --git a/nptl/pthread_mutex_lock.c b/nptl/pthread_mutex_lock.c +index 29cc143e..60ada70d 100644 +--- a/nptl/pthread_mutex_lock.c ++++ b/nptl/pthread_mutex_lock.c +@@ -292,12 +292,12 @@ __pthread_mutex_lock_full (pthread_mutex_t *mutex) + meantime. */ + if ((oldval & FUTEX_WAITERS) == 0) + { +- if (atomic_compare_and_exchange_bool_acq (&mutex->__data.__lock, +- oldval | FUTEX_WAITERS, +- oldval) +- != 0) ++ int val; ++ if ((val = atomic_compare_and_exchange_val_acq ++ (&mutex->__data.__lock, oldval | FUTEX_WAITERS, ++ oldval)) != oldval) + { +- oldval = mutex->__data.__lock; ++ oldval = val; + continue; + } + oldval |= FUTEX_WAITERS; +-- +GitLab + diff --git a/SOURCES/glibc-RHEL-15696-65.patch b/SOURCES/glibc-RHEL-15696-65.patch new file mode 100644 index 0000000..296d4a9 --- /dev/null +++ b/SOURCES/glibc-RHEL-15696-65.patch @@ -0,0 +1,39 @@ +From 49302b8fdf9103b6fc0a398678668a22fa19574c Mon Sep 17 00:00:00 2001 +From: "H.J. Lu" +Date: Thu, 11 Nov 2021 06:54:01 -0800 +Subject: [PATCH] Avoid extra load with CAS in __pthread_mutex_clocklock_common + [BZ #28537] +Content-type: text/plain; charset=UTF-8 + +Replace boolean CAS with value CAS to avoid the extra load. + +Reviewed-by: Szabolcs Nagy +--- + nptl/pthread_mutex_timedlock.c | 10 +++++----- + 1 file changed, 5 insertions(+), 5 deletions(-) + +diff --git a/nptl/pthread_mutex_timedlock.c b/nptl/pthread_mutex_timedlock.c +index 888c12fe..c4627ef6 100644 +--- a/nptl/pthread_mutex_timedlock.c ++++ b/nptl/pthread_mutex_timedlock.c +@@ -269,12 +269,12 @@ __pthread_mutex_timedlock (pthread_mutex_t *mutex, + meantime. */ + if ((oldval & FUTEX_WAITERS) == 0) + { +- if (atomic_compare_and_exchange_bool_acq (&mutex->__data.__lock, +- oldval | FUTEX_WAITERS, +- oldval) +- != 0) ++ int val; ++ if ((val = atomic_compare_and_exchange_val_acq ++ (&mutex->__data.__lock, oldval | FUTEX_WAITERS, ++ oldval)) != oldval) + { +- oldval = mutex->__data.__lock; ++ oldval = val; + continue; + } + oldval |= FUTEX_WAITERS; +-- +GitLab + diff --git a/SOURCES/glibc-RHEL-15696-66.patch b/SOURCES/glibc-RHEL-15696-66.patch new file mode 100644 index 0000000..4579636 --- /dev/null +++ b/SOURCES/glibc-RHEL-15696-66.patch @@ -0,0 +1,51 @@ +From d672a98a1af106bd68deb15576710cd61363f7a6 Mon Sep 17 00:00:00 2001 +From: "H.J. Lu" +Date: Tue, 2 Nov 2021 18:33:07 -0700 +Subject: [PATCH] Add LLL_MUTEX_READ_LOCK [BZ #28537] +Content-type: text/plain; charset=UTF-8 + +CAS instruction is expensive. From the x86 CPU's point of view, getting +a cache line for writing is more expensive than reading. See Appendix +A.2 Spinlock in: + +https://www.intel.com/content/dam/www/public/us/en/documents/white-papers/xeon-lock-scaling-analysis-paper.pdf + +The full compare and swap will grab the cache line exclusive and cause +excessive cache line bouncing. + +Add LLL_MUTEX_READ_LOCK to do an atomic load and skip CAS in spinlock +loop if compare may fail to reduce cache line bouncing on contended locks. + +Reviewed-by: Szabolcs Nagy +--- + nptl/pthread_mutex_lock.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/nptl/pthread_mutex_lock.c b/nptl/pthread_mutex_lock.c +index 60ada70d..eb4d8baa 100644 +--- a/nptl/pthread_mutex_lock.c ++++ b/nptl/pthread_mutex_lock.c +@@ -56,6 +56,11 @@ + #define FORCE_ELISION(m, s) + #endif + ++#ifndef LLL_MUTEX_READ_LOCK ++# define LLL_MUTEX_READ_LOCK(mutex) \ ++ atomic_load_relaxed (&(mutex)->__data.__lock) ++#endif ++ + static int __pthread_mutex_lock_full (pthread_mutex_t *mutex) + __attribute_noinline__; + +@@ -136,6 +141,8 @@ __pthread_mutex_lock (pthread_mutex_t *mutex) + break; + } + atomic_spin_nop (); ++ if (LLL_MUTEX_READ_LOCK (mutex) != 0) ++ continue; + } + while (LLL_MUTEX_TRYLOCK (mutex) != 0); + +-- +GitLab + diff --git a/SOURCES/glibc-RHEL-15696-67.patch b/SOURCES/glibc-RHEL-15696-67.patch new file mode 100644 index 0000000..73c8306 --- /dev/null +++ b/SOURCES/glibc-RHEL-15696-67.patch @@ -0,0 +1,71 @@ +From 120ac6d238825452e8024e2f627da33b2508dfd3 Mon Sep 17 00:00:00 2001 +From: "H.J. Lu" +Date: Fri, 12 Nov 2021 11:47:42 -0800 +Subject: [PATCH] Move assignment out of the CAS condition +Content-type: text/plain; charset=UTF-8 + +Update + +commit 49302b8fdf9103b6fc0a398678668a22fa19574c +Author: H.J. Lu +Date: Thu Nov 11 06:54:01 2021 -0800 + + Avoid extra load with CAS in __pthread_mutex_clocklock_common [BZ #28537] + + Replace boolean CAS with value CAS to avoid the extra load. + +and + +commit 0b82747dc48d5bf0871bdc6da8cb6eec1256355f +Author: H.J. Lu +Date: Thu Nov 11 06:31:51 2021 -0800 + + Avoid extra load with CAS in __pthread_mutex_lock_full [BZ #28537] + + Replace boolean CAS with value CAS to avoid the extra load. + +by moving assignment out of the CAS condition. +--- + nptl/pthread_mutex_lock.c | 7 +++---- + nptl/pthread_mutex_timedlock.c | 7 +++---- + 2 files changed, 6 insertions(+), 8 deletions(-) + +diff --git a/nptl/pthread_mutex_lock.c b/nptl/pthread_mutex_lock.c +index eb4d8baa..a633d95e 100644 +--- a/nptl/pthread_mutex_lock.c ++++ b/nptl/pthread_mutex_lock.c +@@ -299,10 +299,9 @@ __pthread_mutex_lock_full (pthread_mutex_t *mutex) + meantime. */ + if ((oldval & FUTEX_WAITERS) == 0) + { +- int val; +- if ((val = atomic_compare_and_exchange_val_acq +- (&mutex->__data.__lock, oldval | FUTEX_WAITERS, +- oldval)) != oldval) ++ int val = atomic_compare_and_exchange_val_acq ++ (&mutex->__data.__lock, oldval | FUTEX_WAITERS, oldval); ++ if (val != oldval) + { + oldval = val; + continue; +diff --git a/nptl/pthread_mutex_timedlock.c b/nptl/pthread_mutex_timedlock.c +index c4627ef6..a76c30b7 100644 +--- a/nptl/pthread_mutex_timedlock.c ++++ b/nptl/pthread_mutex_timedlock.c +@@ -269,10 +269,9 @@ __pthread_mutex_timedlock (pthread_mutex_t *mutex, + meantime. */ + if ((oldval & FUTEX_WAITERS) == 0) + { +- int val; +- if ((val = atomic_compare_and_exchange_val_acq +- (&mutex->__data.__lock, oldval | FUTEX_WAITERS, +- oldval)) != oldval) ++ int val = atomic_compare_and_exchange_val_acq ++ (&mutex->__data.__lock, oldval | FUTEX_WAITERS, oldval); ++ if (val != oldval) + { + oldval = val; + continue; +-- +GitLab + diff --git a/SOURCES/glibc-RHEL-15696-68.patch b/SOURCES/glibc-RHEL-15696-68.patch new file mode 100644 index 0000000..df35b31 --- /dev/null +++ b/SOURCES/glibc-RHEL-15696-68.patch @@ -0,0 +1,60 @@ +From 4df1fa6ddc8925a75f3da644d5da3bb16eb33f02 Mon Sep 17 00:00:00 2001 +From: Noah Goldstein +Date: Fri, 3 Dec 2021 15:29:25 -0800 +Subject: [PATCH] x86-64: Use notl in EVEX strcmp [BZ #28646] +Content-type: text/plain; charset=UTF-8 + +Must use notl %edi here as lower bits are for CHAR comparisons +potentially out of range thus can be 0 without indicating mismatch. +This fixes BZ #28646. + +Co-Authored-By: H.J. Lu +--- + sysdeps/x86_64/multiarch/strcmp-evex.S | 14 ++++++++------ + 1 file changed, 8 insertions(+), 6 deletions(-) + +Conflicts: + string/test-strcmp.c + (new check omitted) + +diff --git a/sysdeps/x86_64/multiarch/strcmp-evex.S b/sysdeps/x86_64/multiarch/strcmp-evex.S +index 82f12ac8..6f5c4bf9 100644 +--- a/sysdeps/x86_64/multiarch/strcmp-evex.S ++++ b/sysdeps/x86_64/multiarch/strcmp-evex.S +@@ -656,12 +656,13 @@ L(loop_cross_page): + in YMM3 and 32 bytes at VEC_SIZE(%rdx, %r10). */ + VPCMP $0, VEC_SIZE(%rdx, %r10), %YMM3, %k3{%k4} + kmovd %k3, %edi ++ /* Must use notl %edi here as lower bits are for CHAR ++ comparisons potentially out of range thus can be 0 without ++ indicating mismatch. */ ++ notl %edi + # ifdef USE_AS_WCSCMP + /* Don't use subl since it is the upper 8 bits of EDI below. */ +- notl %edi + andl $0xff, %edi +-# else +- incl %edi + # endif + + # ifdef USE_AS_WCSCMP +@@ -743,12 +744,13 @@ L(loop_cross_page_2_vec): + in YMM1 and 32 bytes at (VEC_SIZE * 3)(%rdx, %r10). */ + VPCMP $0, (VEC_SIZE * 3)(%rdx, %r10), %YMM1, %k3{%k4} + kmovd %k3, %edi ++ /* Must use notl %edi here as lower bits are for CHAR ++ comparisons potentially out of range thus can be 0 without ++ indicating mismatch. */ ++ notl %edi + # ifdef USE_AS_WCSCMP + /* Don't use subl since it is the upper 8 bits of EDI below. */ +- notl %edi + andl $0xff, %edi +-# else +- incl %edi + # endif + + # ifdef USE_AS_WCSCMP +-- +GitLab + diff --git a/SOURCES/glibc-RHEL-15696-69.patch b/SOURCES/glibc-RHEL-15696-69.patch new file mode 100644 index 0000000..9f859f2 --- /dev/null +++ b/SOURCES/glibc-RHEL-15696-69.patch @@ -0,0 +1,35 @@ +From ceeffe968c01b1202e482f4855cb6baf5c6cb713 Mon Sep 17 00:00:00 2001 +From: "H.J. Lu" +Date: Mon, 6 Dec 2021 07:14:12 -0800 +Subject: [PATCH] x86: Don't set Prefer_No_AVX512 for processors with AVX512 + and AVX-VNNI +Content-type: text/plain; charset=UTF-8 + +Don't set Prefer_No_AVX512 on processors with AVX512 and AVX-VNNI since +they won't lower CPU frequency when ZMM load and store instructions are +used. +--- + sysdeps/x86/cpu-features.c | 7 +++++-- + 1 file changed, 5 insertions(+), 2 deletions(-) + +diff --git a/sysdeps/x86/cpu-features.c b/sysdeps/x86/cpu-features.c +index 956bfb4f..5ff2baa0 100644 +--- a/sysdeps/x86/cpu-features.c ++++ b/sysdeps/x86/cpu-features.c +@@ -525,8 +525,11 @@ init_cpu_features (struct cpu_features *cpu_features) + |= bit_arch_Prefer_No_VZEROUPPER; + else + { +- cpu_features->preferred[index_arch_Prefer_No_AVX512] +- |= bit_arch_Prefer_No_AVX512; ++ /* Processors with AVX512 and AVX-VNNI won't lower CPU frequency ++ when ZMM load and store instructions are used. */ ++ if (!CPU_FEATURES_CPU_P (cpu_features, AVX_VNNI)) ++ cpu_features->preferred[index_arch_Prefer_No_AVX512] ++ |= bit_arch_Prefer_No_AVX512; + + /* Avoid RTM abort triggered by VZEROUPPER inside a + transactionally executing RTM region. */ +-- +GitLab + diff --git a/SOURCES/glibc-RHEL-15696-7.patch b/SOURCES/glibc-RHEL-15696-7.patch new file mode 100644 index 0000000..8ef468c --- /dev/null +++ b/SOURCES/glibc-RHEL-15696-7.patch @@ -0,0 +1,153 @@ +From c7c54f65b080affb87a1513dee449c8ad6143c8b Mon Sep 17 00:00:00 2001 +From: "H.J. Lu" +Date: Mon, 21 Jan 2019 11:35:18 -0800 +Subject: [PATCH] x86-64 strncpy: Properly handle the length parameter [BZ# + 24097] +Content-type: text/plain; charset=UTF-8 + +On x32, the size_t parameter may be passed in the lower 32 bits of a +64-bit register with the non-zero upper 32 bits. The string/memory +functions written in assembly can only use the lower 32 bits of a +64-bit register as length or must clear the upper 32 bits before using +the full 64-bit register for length. + +This pach fixes strncpy for x32. Tested on x86-64 and x32. On x86-64, +libc.so is the same with and withou the fix. + + [BZ# 24097] + CVE-2019-6488 + * sysdeps/x86_64/multiarch/strcpy-avx2.S: Use RDX_LP for length. + * sysdeps/x86_64/multiarch/strcpy-sse2-unaligned.S: Likewise. + * sysdeps/x86_64/multiarch/strcpy-ssse3.S: Likewise. + * sysdeps/x86_64/x32/Makefile (tests): Add tst-size_t-strncpy. + * sysdeps/x86_64/x32/tst-size_t-strncpy.c: New file. +--- + .../x86_64/multiarch/strcpy-sse2-unaligned.S | 4 +- + sysdeps/x86_64/multiarch/strcpy-ssse3.S | 6 +- + sysdeps/x86_64/x32/Makefile | 2 +- + sysdeps/x86_64/x32/tst-size_t-strncpy.c | 58 +++++++++++++++++++ + 4 files changed, 64 insertions(+), 6 deletions(-) + create mode 100644 sysdeps/x86_64/x32/tst-size_t-strncpy.c + +Conflicts: + ChangeLog + (removed) + sysdeps/x86_64/multiarch/strcpy-avx2.S + (skipped, only needed for x32 arch) + +diff --git a/sysdeps/x86_64/multiarch/strcpy-sse2-unaligned.S b/sysdeps/x86_64/multiarch/strcpy-sse2-unaligned.S +index 72bf7e85..50aca22d 100644 +--- a/sysdeps/x86_64/multiarch/strcpy-sse2-unaligned.S ++++ b/sysdeps/x86_64/multiarch/strcpy-sse2-unaligned.S +@@ -40,8 +40,8 @@ + .text + ENTRY (STRCPY) + # ifdef USE_AS_STRNCPY +- mov %rdx, %r8 +- test %r8, %r8 ++ mov %RDX_LP, %R8_LP ++ test %R8_LP, %R8_LP + jz L(ExitZero) + # endif + mov %rsi, %rcx +diff --git a/sysdeps/x86_64/multiarch/strcpy-ssse3.S b/sysdeps/x86_64/multiarch/strcpy-ssse3.S +index 9858d0c4..0a62814a 100644 +--- a/sysdeps/x86_64/multiarch/strcpy-ssse3.S ++++ b/sysdeps/x86_64/multiarch/strcpy-ssse3.S +@@ -31,13 +31,13 @@ ENTRY (STRCPY) + + mov %rsi, %rcx + # ifdef USE_AS_STRNCPY +- mov %rdx, %r8 ++ mov %RDX_LP, %R8_LP + # endif + mov %rdi, %rdx + # ifdef USE_AS_STRNCPY +- test %r8, %r8 ++ test %R8_LP, %R8_LP + jz L(Exit0) +- cmp $8, %r8 ++ cmp $8, %R8_LP + jbe L(StrncpyExit8Bytes) + # endif + cmpb $0, (%rcx) +diff --git a/sysdeps/x86_64/x32/Makefile b/sysdeps/x86_64/x32/Makefile +index db302839..2a9e20a9 100644 +--- a/sysdeps/x86_64/x32/Makefile ++++ b/sysdeps/x86_64/x32/Makefile +@@ -8,7 +8,7 @@ endif + ifeq ($(subdir),string) + tests += tst-size_t-memchr tst-size_t-memcmp tst-size_t-memcpy \ + tst-size_t-memrchr tst-size_t-memset tst-size_t-strncasecmp \ +- tst-size_t-strncmp ++ tst-size_t-strncmp tst-size_t-strncpy + endif + + ifeq ($(subdir),wcsmbs) +diff --git a/sysdeps/x86_64/x32/tst-size_t-strncpy.c b/sysdeps/x86_64/x32/tst-size_t-strncpy.c +new file mode 100644 +index 00000000..4dec71e6 +--- /dev/null ++++ b/sysdeps/x86_64/x32/tst-size_t-strncpy.c +@@ -0,0 +1,58 @@ ++/* Test strncpy with size_t in the lower 32 bits of 64-bit register. ++ 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, see ++ . */ ++ ++#define TEST_NAME "strncpy" ++#include "test-size_t.h" ++ ++IMPL (strncpy, 1) ++ ++typedef char *(*proto_t) (char *, const char*, size_t); ++ ++static void * ++__attribute__ ((noinline, noclone)) ++do_strncpy (parameter_t a, parameter_t b) ++{ ++ return CALL (&b, a.p, b.p, a.len); ++} ++ ++static int ++test_main (void) ++{ ++ test_init (); ++ ++ parameter_t dest = { { page_size }, buf1 }; ++ parameter_t src = { { 0 }, buf2 }; ++ ++ int ret = 0; ++ FOR_EACH_IMPL (impl, 0) ++ { ++ src.fn = impl->fn; ++ do_strncpy (dest, src); ++ int res = strncmp (dest.p, src.p, dest.len); ++ if (res) ++ { ++ error (0, 0, "Wrong result in function %s: %i != 0", ++ impl->name, res); ++ ret = 1; ++ } ++ } ++ ++ return ret ? EXIT_FAILURE : EXIT_SUCCESS; ++} ++ ++#include +-- +GitLab + diff --git a/SOURCES/glibc-RHEL-15696-70.patch b/SOURCES/glibc-RHEL-15696-70.patch new file mode 100644 index 0000000..8935ac5 --- /dev/null +++ b/SOURCES/glibc-RHEL-15696-70.patch @@ -0,0 +1,389 @@ +From abddd61de090ae84e380aff68a98bd94ef704667 Mon Sep 17 00:00:00 2001 +From: Noah Goldstein +Date: Fri, 24 Dec 2021 18:54:41 -0600 +Subject: [PATCH] x86: Optimize L(less_vec) case in memcmp-evex-movbe.S +Content-type: text/plain; charset=UTF-8 + +No bug. +Optimizations are twofold. + +1) Replace page cross and 0/1 checks with masked load instructions in + L(less_vec). In applications this reduces branch-misses in the + hot [0, 32] case. +2) Change controlflow so that L(less_vec) case gets the fall through. + +Change 2) helps copies in the [0, 32] size range but comes at the cost +of copies in the [33, 64] size range. From profiles of GCC and +Python3, 94%+ and 99%+ of calls are in the [0, 32] range so this +appears to the the right tradeoff. + +Signed-off-by: Noah Goldstein +Reviewed-by: H.J. Lu +--- + sysdeps/x86_64/multiarch/memcmp-evex-movbe.S | 249 +++++-------------- + 1 file changed, 56 insertions(+), 193 deletions(-) + +diff --git a/sysdeps/x86_64/multiarch/memcmp-evex-movbe.S b/sysdeps/x86_64/multiarch/memcmp-evex-movbe.S +index 640f6757..d2899e7c 100644 +--- a/sysdeps/x86_64/multiarch/memcmp-evex-movbe.S ++++ b/sysdeps/x86_64/multiarch/memcmp-evex-movbe.S +@@ -62,15 +62,18 @@ Latency: + # define VMOVU vmovdqu64 + + # ifdef USE_AS_WMEMCMP ++# define VMOVU_MASK vmovdqu32 + # define CHAR_SIZE 4 + # define VPCMP vpcmpd + # define VPTEST vptestmd + # else ++# define VMOVU_MASK vmovdqu8 + # define CHAR_SIZE 1 + # define VPCMP vpcmpub + # define VPTEST vptestmb + # endif + ++ + # define VEC_SIZE 32 + # define PAGE_SIZE 4096 + # define CHAR_PER_VEC (VEC_SIZE / CHAR_SIZE) +@@ -102,12 +105,48 @@ ENTRY_P2ALIGN (MEMCMP, 6) + movl %edx, %edx + # endif + cmp $CHAR_PER_VEC, %RDX_LP +- jb L(less_vec) ++ /* Fall through for [0, VEC_SIZE] as its the hottest. */ ++ ja L(more_1x_vec) ++ ++ /* Create mask for CHAR's we want to compare. This allows us to ++ avoid having to include page cross logic. */ ++ movl $-1, %ecx ++ bzhil %edx, %ecx, %ecx ++ kmovd %ecx, %k2 ++ ++ /* Safe to load full ymm with mask. */ ++ VMOVU_MASK (%rsi), %YMM2{%k2} ++ VPCMP $4,(%rdi), %YMM2, %k1{%k2} ++ kmovd %k1, %eax ++ testl %eax, %eax ++ jnz L(return_vec_0) ++ ret + ++ .p2align 4 ++L(return_vec_0): ++ tzcntl %eax, %eax ++# ifdef USE_AS_WMEMCMP ++ movl (%rdi, %rax, CHAR_SIZE), %ecx ++ xorl %edx, %edx ++ cmpl (%rsi, %rax, CHAR_SIZE), %ecx ++ /* NB: no partial register stall here because xorl zero idiom ++ above. */ ++ setg %dl ++ leal -1(%rdx, %rdx), %eax ++# else ++ movzbl (%rsi, %rax), %ecx ++ movzbl (%rdi, %rax), %eax ++ subl %ecx, %eax ++# endif ++ ret ++ ++ ++ .p2align 4 ++L(more_1x_vec): + /* From VEC to 2 * VEC. No branch when size == VEC_SIZE. */ + VMOVU (%rsi), %YMM1 + /* Use compare not equals to directly check for mismatch. */ +- VPCMP $4, (%rdi), %YMM1, %k1 ++ VPCMP $4,(%rdi), %YMM1, %k1 + kmovd %k1, %eax + /* NB: eax must be destination register if going to + L(return_vec_[0,2]). For L(return_vec_3) destination register +@@ -131,13 +170,13 @@ ENTRY_P2ALIGN (MEMCMP, 6) + + /* Check third and fourth VEC no matter what. */ + VMOVU (VEC_SIZE * 2)(%rsi), %YMM3 +- VPCMP $4, (VEC_SIZE * 2)(%rdi), %YMM3, %k1 ++ VPCMP $4,(VEC_SIZE * 2)(%rdi), %YMM3, %k1 + kmovd %k1, %eax + testl %eax, %eax + jnz L(return_vec_2) + + VMOVU (VEC_SIZE * 3)(%rsi), %YMM4 +- VPCMP $4, (VEC_SIZE * 3)(%rdi), %YMM4, %k1 ++ VPCMP $4,(VEC_SIZE * 3)(%rdi), %YMM4, %k1 + kmovd %k1, %ecx + testl %ecx, %ecx + jnz L(return_vec_3) +@@ -169,7 +208,7 @@ ENTRY_P2ALIGN (MEMCMP, 6) + VMOVU (VEC_SIZE * 3)(%rsi), %YMM4 + /* Ternary logic to xor (VEC_SIZE * 3)(%rdi) with YMM4 while + oring with YMM1. Result is stored in YMM4. */ +- vpternlogd $0xde, (VEC_SIZE * 3)(%rdi), %YMM1, %YMM4 ++ vpternlogd $0xde,(VEC_SIZE * 3)(%rdi), %YMM1, %YMM4 + + /* Or together YMM2, YMM3, and YMM4 into YMM4. */ + vpternlogd $0xfe, %YMM2, %YMM3, %YMM4 +@@ -184,7 +223,8 @@ ENTRY_P2ALIGN (MEMCMP, 6) + /* NB: eax must be zero to reach here. */ + ret + +- .p2align 4 ++ ++ .p2align 4,, 8 + L(8x_end_return_vec_0_1_2_3): + movq %rdx, %rdi + L(8x_return_vec_0_1_2_3): +@@ -222,23 +262,6 @@ L(return_vec_3): + # endif + ret + +- .p2align 4 +-L(return_vec_0): +- tzcntl %eax, %eax +-# ifdef USE_AS_WMEMCMP +- movl (%rdi, %rax, CHAR_SIZE), %ecx +- xorl %edx, %edx +- cmpl (%rsi, %rax, CHAR_SIZE), %ecx +- /* NB: no partial register stall here because xorl zero idiom +- above. */ +- setg %dl +- leal -1(%rdx, %rdx), %eax +-# else +- movzbl (%rsi, %rax), %ecx +- movzbl (%rdi, %rax), %eax +- subl %ecx, %eax +-# endif +- ret + + .p2align 4 + L(return_vec_1): +@@ -297,7 +320,7 @@ L(loop_4x_vec): + VMOVU (VEC_SIZE * 2)(%rsi, %rdi), %YMM3 + vpxorq (VEC_SIZE * 2)(%rdi), %YMM3, %YMM3 + VMOVU (VEC_SIZE * 3)(%rsi, %rdi), %YMM4 +- vpternlogd $0xde, (VEC_SIZE * 3)(%rdi), %YMM1, %YMM4 ++ vpternlogd $0xde,(VEC_SIZE * 3)(%rdi), %YMM1, %YMM4 + vpternlogd $0xfe, %YMM2, %YMM3, %YMM4 + VPTEST %YMM4, %YMM4, %k1 + kmovd %k1, %ecx +@@ -324,7 +347,7 @@ L(loop_4x_vec): + VMOVU VEC_SIZE(%rsi, %rdx), %YMM2 + vpxorq VEC_SIZE(%rdx), %YMM2, %YMM2 + VMOVU (VEC_SIZE * 3)(%rsi, %rdx), %YMM4 +- vpternlogd $0xde, (VEC_SIZE * 3)(%rdx), %YMM1, %YMM4 ++ vpternlogd $0xde,(VEC_SIZE * 3)(%rdx), %YMM1, %YMM4 + vpternlogd $0xfe, %YMM2, %YMM3, %YMM4 + VPTEST %YMM4, %YMM4, %k1 + kmovd %k1, %ecx +@@ -336,14 +359,14 @@ L(loop_4x_vec): + /* Only entry is from L(more_8x_vec). */ + .p2align 4,, 10 + L(8x_last_2x_vec): +- VPCMP $4, (VEC_SIZE * 2)(%rdx), %YMM3, %k1 ++ VPCMP $4,(VEC_SIZE * 2)(%rdx), %YMM3, %k1 + kmovd %k1, %eax + testl %eax, %eax + jnz L(8x_return_vec_2) + /* Naturally aligned to 16 bytes. */ + L(8x_last_1x_vec): + VMOVU (VEC_SIZE * 3)(%rsi, %rdx), %YMM1 +- VPCMP $4, (VEC_SIZE * 3)(%rdx), %YMM1, %k1 ++ VPCMP $4,(VEC_SIZE * 3)(%rdx), %YMM1, %k1 + kmovd %k1, %eax + testl %eax, %eax + jnz L(8x_return_vec_3) +@@ -392,7 +415,9 @@ L(last_1x_vec): + jnz L(return_vec_0_end) + ret + +- .p2align 4,, 10 ++ ++ /* Don't align. Takes 2-fetch blocks either way and aligning ++ will cause code to spill into another cacheline. */ + L(return_vec_1_end): + /* Use bsf to save code size. This is necessary to have + L(one_or_less) fit in aligning bytes between. */ +@@ -411,31 +436,8 @@ L(return_vec_1_end): + # endif + ret + +- /* NB: L(one_or_less) fits in alignment padding between +- L(return_vec_1_end) and L(return_vec_0_end). */ +-# ifdef USE_AS_WMEMCMP +-L(one_or_less): +- jb L(zero) +- movl (%rdi), %ecx +- xorl %edx, %edx +- cmpl (%rsi), %ecx +- je L(zero) +- setg %dl +- leal -1(%rdx, %rdx), %eax +- ret +-# else +-L(one_or_less): +- jb L(zero) +- movzbl (%rsi), %ecx +- movzbl (%rdi), %eax +- subl %ecx, %eax +- ret +-# endif +-L(zero): +- xorl %eax, %eax +- ret +- +- .p2align 4 ++ /* Don't align. Takes 2-fetch blocks either way and aligning ++ will cause code to spill into another cacheline. */ + L(return_vec_0_end): + tzcntl %eax, %eax + addl %edx, %eax +@@ -451,146 +453,7 @@ L(return_vec_0_end): + subl %ecx, %eax + # endif + ret ++ /* 1-byte until next cache line. */ + +- .p2align 4 +-L(less_vec): +- /* Check if one or less CHAR. This is necessary for size == 0 +- but is also faster for size == CHAR_SIZE. */ +- cmpl $1, %edx +- jbe L(one_or_less) +- +- /* Check if loading one VEC from either s1 or s2 could cause a +- page cross. This can have false positives but is by far the +- fastest method. */ +- movl %edi, %eax +- orl %esi, %eax +- andl $(PAGE_SIZE - 1), %eax +- cmpl $(PAGE_SIZE - VEC_SIZE), %eax +- jg L(page_cross_less_vec) +- +- /* No page cross possible. */ +- VMOVU (%rsi), %YMM2 +- VPCMP $4, (%rdi), %YMM2, %k1 +- kmovd %k1, %eax +- /* Check if any matches where in bounds. Intentionally not +- storing result in eax to limit dependency chain if it goes to +- L(return_vec_0_lv). */ +- bzhil %edx, %eax, %edx +- jnz L(return_vec_0_lv) +- xorl %eax, %eax +- ret +- +- /* Essentially duplicate of L(return_vec_0). Ends up not costing +- any code as shrinks L(less_vec) by allowing 2-byte encoding of +- the jump and ends up fitting in aligning bytes. As well fits on +- same cache line as L(less_vec) so also saves a line from having +- to be fetched on cold calls to memcmp. */ +- .p2align 4,, 4 +-L(return_vec_0_lv): +- tzcntl %eax, %eax +-# ifdef USE_AS_WMEMCMP +- movl (%rdi, %rax, CHAR_SIZE), %ecx +- xorl %edx, %edx +- cmpl (%rsi, %rax, CHAR_SIZE), %ecx +- /* NB: no partial register stall here because xorl zero idiom +- above. */ +- setg %dl +- leal -1(%rdx, %rdx), %eax +-# else +- movzbl (%rsi, %rax), %ecx +- movzbl (%rdi, %rax), %eax +- subl %ecx, %eax +-# endif +- ret +- +- .p2align 4 +-L(page_cross_less_vec): +- /* if USE_AS_WMEMCMP it can only be 0, 4, 8, 12, 16, 20, 24, 28 +- bytes. */ +- cmpl $(16 / CHAR_SIZE), %edx +- jae L(between_16_31) +-# ifndef USE_AS_WMEMCMP +- cmpl $8, %edx +- jae L(between_8_15) +- cmpl $4, %edx +- jb L(between_2_3) +- +- /* Load as big endian with overlapping movbe to avoid branches. +- */ +- movbe (%rdi), %eax +- movbe (%rsi), %ecx +- shlq $32, %rax +- shlq $32, %rcx +- movbe -4(%rdi, %rdx), %edi +- movbe -4(%rsi, %rdx), %esi +- orq %rdi, %rax +- orq %rsi, %rcx +- subq %rcx, %rax +- /* edx is guranteed to be positive int32 in range [4, 7]. */ +- cmovne %edx, %eax +- /* ecx is -1 if rcx > rax. Otherwise 0. */ +- sbbl %ecx, %ecx +- /* If rcx > rax, then ecx is 0 and eax is positive. If rcx == +- rax then eax and ecx are zero. If rax < rax then ecx is -1 so +- eax doesn't matter. */ +- orl %ecx, %eax +- ret +- +- .p2align 4,, 8 +-L(between_8_15): +-# endif +- /* If USE_AS_WMEMCMP fall through into 8-15 byte case. */ +- vmovq (%rdi), %xmm1 +- vmovq (%rsi), %xmm2 +- VPCMP $4, %xmm1, %xmm2, %k1 +- kmovd %k1, %eax +- testl %eax, %eax +- jnz L(return_vec_0_lv) +- /* Use overlapping loads to avoid branches. */ +- vmovq -8(%rdi, %rdx, CHAR_SIZE), %xmm1 +- vmovq -8(%rsi, %rdx, CHAR_SIZE), %xmm2 +- VPCMP $4, %xmm1, %xmm2, %k1 +- addl $(CHAR_PER_VEC - (8 / CHAR_SIZE)), %edx +- kmovd %k1, %eax +- testl %eax, %eax +- jnz L(return_vec_0_end) +- ret +- +- .p2align 4,, 8 +-L(between_16_31): +- /* From 16 to 31 bytes. No branch when size == 16. */ +- +- /* Use movups to save code size. */ +- vmovdqu (%rsi), %xmm2 +- VPCMP $4, (%rdi), %xmm2, %k1 +- kmovd %k1, %eax +- testl %eax, %eax +- jnz L(return_vec_0_lv) +- /* Use overlapping loads to avoid branches. */ +- vmovdqu -16(%rsi, %rdx, CHAR_SIZE), %xmm2 +- VPCMP $4, -16(%rdi, %rdx, CHAR_SIZE), %xmm2, %k1 +- addl $(CHAR_PER_VEC - (16 / CHAR_SIZE)), %edx +- kmovd %k1, %eax +- testl %eax, %eax +- jnz L(return_vec_0_end) +- ret +- +-# ifndef USE_AS_WMEMCMP +-L(between_2_3): +- /* Load as big endian to avoid branches. */ +- movzwl (%rdi), %eax +- movzwl (%rsi), %ecx +- shll $8, %eax +- shll $8, %ecx +- bswap %eax +- bswap %ecx +- movzbl -1(%rdi, %rdx), %edi +- movzbl -1(%rsi, %rdx), %esi +- orl %edi, %eax +- orl %esi, %ecx +- /* Subtraction is okay because the upper 8 bits are zero. */ +- subl %ecx, %eax +- ret +-# endif + END (MEMCMP) + #endif +-- +GitLab + diff --git a/SOURCES/glibc-RHEL-15696-71.patch b/SOURCES/glibc-RHEL-15696-71.patch new file mode 100644 index 0000000..2d018d0 --- /dev/null +++ b/SOURCES/glibc-RHEL-15696-71.patch @@ -0,0 +1,43 @@ +From 6b8dbbd03ac88f169b65b5c7d7278576a11d2e44 Mon Sep 17 00:00:00 2001 +From: Jangwoong Kim <6812skiii@gmail.com> +Date: Tue, 14 Dec 2021 21:30:51 +0900 +Subject: [PATCH] nptl: Effectively skip CAS in spinlock loop +Content-type: text/plain; charset=UTF-8 + +The commit: +"Add LLL_MUTEX_READ_LOCK [BZ #28537]" +SHA1: d672a98a1af106bd68deb15576710cd61363f7a6 + +introduced LLL_MUTEX_READ_LOCK, to skip CAS in spinlock loop +if atomic load fails. But, "continue" inside of do-while loop +does not skip the evaluation of escape expression, thus CAS +is not skipped. + +Replace do-while with while and skip LLL_MUTEX_TRYLOCK if +LLL_MUTEX_READ_LOCK fails. + +Reviewed-by: H.J. Lu +--- + nptl/pthread_mutex_lock.c | 5 ++--- + 1 file changed, 2 insertions(+), 3 deletions(-) + +diff --git a/nptl/pthread_mutex_lock.c b/nptl/pthread_mutex_lock.c +index a633d95e..d96a9933 100644 +--- a/nptl/pthread_mutex_lock.c ++++ b/nptl/pthread_mutex_lock.c +@@ -141,10 +141,9 @@ __pthread_mutex_lock (pthread_mutex_t *mutex) + break; + } + atomic_spin_nop (); +- if (LLL_MUTEX_READ_LOCK (mutex) != 0) +- continue; + } +- while (LLL_MUTEX_TRYLOCK (mutex) != 0); ++ while (LLL_MUTEX_READ_LOCK (mutex) != 0 ++ || LLL_MUTEX_TRYLOCK (mutex) != 0); + + mutex->__data.__spins += (cnt - mutex->__data.__spins) / 8; + } +-- +GitLab + diff --git a/SOURCES/glibc-RHEL-15696-72.patch b/SOURCES/glibc-RHEL-15696-72.patch new file mode 100644 index 0000000..34f2a61 --- /dev/null +++ b/SOURCES/glibc-RHEL-15696-72.patch @@ -0,0 +1,146 @@ +From 7835d611af0854e69a0c71e3806f8fe379282d6f Mon Sep 17 00:00:00 2001 +From: Noah Goldstein +Date: Fri, 18 Feb 2022 14:19:15 -0600 +Subject: [PATCH] x86: Test wcscmp RTM in the wcsncmp overflow case [BZ #28896] +Content-type: text/plain; charset=UTF-8 + +In the overflow fallback strncmp-avx2-rtm and wcsncmp-avx2-rtm would +call strcmp-avx2 and wcscmp-avx2 respectively. This would have +not checks around vzeroupper and would trigger spurious +aborts. This commit fixes that. + +test-strcmp, test-strncmp, test-wcscmp, and test-wcsncmp all pass on +AVX2 machines with and without RTM. +Reviewed-by: H.J. Lu +--- + sysdeps/x86/Makefile | 5 ++++- + sysdeps/x86/tst-strncmp-rtm.c | 32 +++++++++++++++++++++++--------- + sysdeps/x86/tst-wcsncmp-rtm.c | 21 +++++++++++++++++++++ + 3 files changed, 48 insertions(+), 10 deletions(-) + create mode 100644 sysdeps/x86/tst-wcsncmp-rtm.c + +diff --git a/sysdeps/x86/Makefile b/sysdeps/x86/Makefile +index 2d814915..c2111f49 100644 +--- a/sysdeps/x86/Makefile ++++ b/sysdeps/x86/Makefile +@@ -28,7 +28,9 @@ tests += \ + tst-strcpy-rtm \ + tst-strlen-rtm \ + tst-strncmp-rtm \ +- tst-strrchr-rtm ++ tst-strrchr-rtm \ ++ tst-wcsncmp-rtm \ ++# tests + + CFLAGS-tst-memchr-rtm.c += -mrtm + CFLAGS-tst-memcmp-rtm.c += -mrtm +@@ -40,6 +42,7 @@ CFLAGS-tst-strcpy-rtm.c += -mrtm + CFLAGS-tst-strlen-rtm.c += -mrtm + CFLAGS-tst-strncmp-rtm.c += -mrtm -Wno-error + CFLAGS-tst-strrchr-rtm.c += -mrtm ++CFLAGS-tst-wcsncmp-rtm.c += -mrtm -Wno-error + endif + + ifneq ($(enable-cet),no) +diff --git a/sysdeps/x86/tst-strncmp-rtm.c b/sysdeps/x86/tst-strncmp-rtm.c +index 4d0004b5..4e9f094f 100644 +--- a/sysdeps/x86/tst-strncmp-rtm.c ++++ b/sysdeps/x86/tst-strncmp-rtm.c +@@ -19,18 +19,32 @@ + #include + #include + ++#ifdef WIDE ++# define CHAR wchar_t ++# define MEMSET wmemset ++# define STRNCMP wcsncmp ++# define TEST_NAME wcsncmp ++#else /* !WIDE */ ++# define CHAR char ++# define MEMSET memset ++# define STRNCMP strncmp ++# define TEST_NAME strncmp ++#endif /* !WIDE */ ++ ++ ++ + #define LOOP 3000 + #define STRING_SIZE 1024 +-char string1[STRING_SIZE]; +-char string2[STRING_SIZE]; ++CHAR string1[STRING_SIZE]; ++CHAR string2[STRING_SIZE]; + + __attribute__ ((noinline, noclone)) + static int + prepare (void) + { +- memset (string1, 'a', STRING_SIZE - 1); +- memset (string2, 'a', STRING_SIZE - 1); +- if (strncmp (string1, string2, STRING_SIZE) == 0) ++ MEMSET (string1, 'a', STRING_SIZE - 1); ++ MEMSET (string2, 'a', STRING_SIZE - 1); ++ if (STRNCMP (string1, string2, STRING_SIZE) == 0) + return EXIT_SUCCESS; + else + return EXIT_FAILURE; +@@ -40,7 +54,7 @@ __attribute__ ((noinline, noclone)) + static int + function (void) + { +- if (strncmp (string1, string2, STRING_SIZE) == 0) ++ if (STRNCMP (string1, string2, STRING_SIZE) == 0) + return 0; + else + return 1; +@@ -50,7 +64,7 @@ __attribute__ ((noinline, noclone)) + static int + function_overflow (void) + { +- if (strncmp (string1, string2, SIZE_MAX) == 0) ++ if (STRNCMP (string1, string2, SIZE_MAX) == 0) + return 0; + else + return 1; +@@ -59,9 +73,9 @@ function_overflow (void) + static int + do_test (void) + { +- int status = do_test_1 ("strncmp", LOOP, prepare, function); ++ int status = do_test_1 (TEST_NAME, LOOP, prepare, function); + if (status != EXIT_SUCCESS) + return status; +- status = do_test_1 ("strncmp", LOOP, prepare, function_overflow); ++ status = do_test_1 (TEST_NAME, LOOP, prepare, function_overflow); + return status; + } +diff --git a/sysdeps/x86/tst-wcsncmp-rtm.c b/sysdeps/x86/tst-wcsncmp-rtm.c +new file mode 100644 +index 00000000..bad3b863 +--- /dev/null ++++ b/sysdeps/x86/tst-wcsncmp-rtm.c +@@ -0,0 +1,21 @@ ++/* Test case for wcsncmp inside a transactionally executing RTM region. ++ 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 WIDE 1 ++#include ++#include "tst-strncmp-rtm.c" +-- +GitLab + diff --git a/SOURCES/glibc-RHEL-15696-73.patch b/SOURCES/glibc-RHEL-15696-73.patch new file mode 100644 index 0000000..e8cc3a2 --- /dev/null +++ b/SOURCES/glibc-RHEL-15696-73.patch @@ -0,0 +1,37 @@ +From b98d0bbf747f39770e0caba7e984ce9f8f900330 Mon Sep 17 00:00:00 2001 +From: Noah Goldstein +Date: Fri, 18 Feb 2022 17:00:25 -0600 +Subject: [PATCH] x86: Fix TEST_NAME to make it a string in tst-strncmp-rtm.c +Content-type: text/plain; charset=UTF-8 + +Previously TEST_NAME was passing a function pointer. This didn't fail +because of the -Wno-error flag (to allow for overflow sizes passed +to strncmp/wcsncmp) + +Reviewed-by: H.J. Lu +--- + sysdeps/x86/tst-strncmp-rtm.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/sysdeps/x86/tst-strncmp-rtm.c b/sysdeps/x86/tst-strncmp-rtm.c +index 4e9f094f..aef9866c 100644 +--- a/sysdeps/x86/tst-strncmp-rtm.c ++++ b/sysdeps/x86/tst-strncmp-rtm.c +@@ -23,12 +23,12 @@ + # define CHAR wchar_t + # define MEMSET wmemset + # define STRNCMP wcsncmp +-# define TEST_NAME wcsncmp ++# define TEST_NAME "wcsncmp" + #else /* !WIDE */ + # define CHAR char + # define MEMSET memset + # define STRNCMP strncmp +-# define TEST_NAME strncmp ++# define TEST_NAME "strncmp" + #endif /* !WIDE */ + + +-- +GitLab + diff --git a/SOURCES/glibc-RHEL-15696-74.patch b/SOURCES/glibc-RHEL-15696-74.patch new file mode 100644 index 0000000..e5e6842 --- /dev/null +++ b/SOURCES/glibc-RHEL-15696-74.patch @@ -0,0 +1,1798 @@ +From b77b06e0e296f1a2276c27a67e1d44f2cfa38d45 Mon Sep 17 00:00:00 2001 +From: Noah Goldstein +Date: Mon, 10 Jan 2022 15:35:38 -0600 +Subject: [PATCH] x86: Optimize strcmp-avx2.S +Content-type: text/plain; charset=UTF-8 + +Optimization are primarily to the loop logic and how the page cross +logic interacts with the loop. + +The page cross logic is at times more expensive for short strings near +the end of a page but not crossing the page. This is done to retest +the page cross conditions with a non-faulty check and to improve the +logic for entering the loop afterwards. This is only particular cases, +however, and is general made up for by more than 10x improvements on +the transition from the page cross -> loop case. + +The non-page cross cases are improved most for smaller sizes [0, 128] +and go about even for (128, 4096]. The loop page cross logic is +improved so some more significant speedup is seen there as well. + +test-strcmp, test-strncmp, test-wcscmp, and test-wcsncmp all pass. + +Signed-off-by: Noah Goldstein +--- + sysdeps/x86_64/multiarch/strcmp-avx2.S | 1592 ++++++++++++++---------- + 1 file changed, 940 insertions(+), 652 deletions(-) + +Conflicts: + sysdeps/x86_64/multiarch/strcmp-avx2.S + (account for sw28896 patches) + +diff --git a/sysdeps/x86_64/multiarch/strcmp-avx2.S b/sysdeps/x86_64/multiarch/strcmp-avx2.S +index 70d8499b..554ffe4c 100644 +--- a/sysdeps/x86_64/multiarch/strcmp-avx2.S ++++ b/sysdeps/x86_64/multiarch/strcmp-avx2.S +@@ -26,35 +26,57 @@ + + # define PAGE_SIZE 4096 + +-/* VEC_SIZE = Number of bytes in a ymm register */ ++ /* VEC_SIZE = Number of bytes in a ymm register. */ + # define VEC_SIZE 32 + +-/* Shift for dividing by (VEC_SIZE * 4). */ +-# define DIVIDE_BY_VEC_4_SHIFT 7 +-# if (VEC_SIZE * 4) != (1 << DIVIDE_BY_VEC_4_SHIFT) +-# error (VEC_SIZE * 4) != (1 << DIVIDE_BY_VEC_4_SHIFT) +-# endif ++# define VMOVU vmovdqu ++# define VMOVA vmovdqa + + # ifdef USE_AS_WCSCMP +-/* Compare packed dwords. */ ++ /* Compare packed dwords. */ + # define VPCMPEQ vpcmpeqd +-/* Compare packed dwords and store minimum. */ ++ /* Compare packed dwords and store minimum. */ + # define VPMINU vpminud +-/* 1 dword char == 4 bytes. */ ++ /* 1 dword char == 4 bytes. */ + # define SIZE_OF_CHAR 4 + # else +-/* Compare packed bytes. */ ++ /* Compare packed bytes. */ + # define VPCMPEQ vpcmpeqb +-/* Compare packed bytes and store minimum. */ ++ /* Compare packed bytes and store minimum. */ + # define VPMINU vpminub +-/* 1 byte char == 1 byte. */ ++ /* 1 byte char == 1 byte. */ + # define SIZE_OF_CHAR 1 + # endif + ++# ifdef USE_AS_STRNCMP ++# define LOOP_REG r9d ++# define LOOP_REG64 r9 ++ ++# define OFFSET_REG8 r9b ++# define OFFSET_REG r9d ++# define OFFSET_REG64 r9 ++# else ++# define LOOP_REG edx ++# define LOOP_REG64 rdx ++ ++# define OFFSET_REG8 dl ++# define OFFSET_REG edx ++# define OFFSET_REG64 rdx ++# endif ++ + # ifndef VZEROUPPER + # define VZEROUPPER vzeroupper + # endif + ++# if defined USE_AS_STRNCMP ++# define VEC_OFFSET 0 ++# else ++# define VEC_OFFSET (-VEC_SIZE) ++# endif ++ ++# define xmmZERO xmm15 ++# define ymmZERO ymm15 ++ + # ifndef SECTION + # define SECTION(p) p##.avx + # endif +@@ -79,783 +101,1049 @@ + the maximum offset is reached before a difference is found, zero is + returned. */ + +- .section SECTION(.text),"ax",@progbits +-ENTRY (STRCMP) ++ .section SECTION(.text), "ax", @progbits ++ENTRY(STRCMP) + # ifdef USE_AS_STRNCMP +- /* Check for simple cases (0 or 1) in offset. */ ++# ifdef __ILP32__ ++ /* Clear the upper 32 bits. */ ++ movl %edx, %rdx ++# endif + cmp $1, %RDX_LP +- je L(char0) +- jb L(zero) ++ /* Signed comparison intentional. We use this branch to also ++ test cases where length >= 2^63. These very large sizes can be ++ handled with strcmp as there is no way for that length to ++ actually bound the buffer. */ ++ jle L(one_or_less) + # ifdef USE_AS_WCSCMP +-# ifndef __ILP32__ + movq %rdx, %rcx +- /* Check if length could overflow when multiplied by +- sizeof(wchar_t). Checking top 8 bits will cover all potential +- overflow cases as well as redirect cases where its impossible to +- length to bound a valid memory region. In these cases just use +- 'wcscmp'. */ ++ ++ /* Multiplying length by sizeof(wchar_t) can result in overflow. ++ Check if that is possible. All cases where overflow are possible ++ are cases where length is large enough that it can never be a ++ bound on valid memory so just use wcscmp. */ + shrq $56, %rcx +- jnz OVERFLOW_STRCMP +-# endif +- /* Convert units: from wide to byte char. */ +- shl $2, %RDX_LP ++ jnz __wcscmp_avx2 ++ ++ leaq (, %rdx, 4), %rdx + # endif +- /* Register %r11 tracks the maximum offset. */ +- mov %RDX_LP, %R11_LP + # endif ++ vpxor %xmmZERO, %xmmZERO, %xmmZERO + movl %edi, %eax +- xorl %edx, %edx +- /* Make %xmm7 (%ymm7) all zeros in this function. */ +- vpxor %xmm7, %xmm7, %xmm7 + orl %esi, %eax +- andl $(PAGE_SIZE - 1), %eax +- cmpl $(PAGE_SIZE - (VEC_SIZE * 4)), %eax +- jg L(cross_page) +- /* Start comparing 4 vectors. */ +- vmovdqu (%rdi), %ymm1 +- VPCMPEQ (%rsi), %ymm1, %ymm0 +- VPMINU %ymm1, %ymm0, %ymm0 +- VPCMPEQ %ymm7, %ymm0, %ymm0 +- vpmovmskb %ymm0, %ecx +- testl %ecx, %ecx +- je L(next_3_vectors) +- tzcntl %ecx, %edx ++ sall $20, %eax ++ /* Check if s1 or s2 may cross a page in next 4x VEC loads. */ ++ cmpl $((PAGE_SIZE -(VEC_SIZE * 4)) << 20), %eax ++ ja L(page_cross) ++ ++L(no_page_cross): ++ /* Safe to compare 4x vectors. */ ++ VMOVU (%rdi), %ymm0 ++ /* 1s where s1 and s2 equal. */ ++ VPCMPEQ (%rsi), %ymm0, %ymm1 ++ /* 1s at null CHAR. */ ++ VPCMPEQ %ymm0, %ymmZERO, %ymm2 ++ /* 1s where s1 and s2 equal AND not null CHAR. */ ++ vpandn %ymm1, %ymm2, %ymm1 ++ ++ /* All 1s -> keep going, any 0s -> return. */ ++ vpmovmskb %ymm1, %ecx + # ifdef USE_AS_STRNCMP +- /* Return 0 if the mismatched index (%rdx) is after the maximum +- offset (%r11). */ +- cmpq %r11, %rdx +- jae L(zero) ++ cmpq $VEC_SIZE, %rdx ++ jbe L(vec_0_test_len) + # endif ++ ++ /* All 1s represents all equals. incl will overflow to zero in ++ all equals case. Otherwise 1s will carry until position of first ++ mismatch. */ ++ incl %ecx ++ jz L(more_3x_vec) ++ ++ .p2align 4,, 4 ++L(return_vec_0): ++ tzcntl %ecx, %ecx + # ifdef USE_AS_WCSCMP ++ movl (%rdi, %rcx), %edx + xorl %eax, %eax +- movl (%rdi, %rdx), %ecx +- cmpl (%rsi, %rdx), %ecx +- je L(return) +-L(wcscmp_return): ++ cmpl (%rsi, %rcx), %edx ++ je L(ret0) + setl %al + negl %eax + orl $1, %eax +-L(return): + # else +- movzbl (%rdi, %rdx), %eax +- movzbl (%rsi, %rdx), %edx +- subl %edx, %eax ++ movzbl (%rdi, %rcx), %eax ++ movzbl (%rsi, %rcx), %ecx ++ subl %ecx, %eax + # endif ++L(ret0): + L(return_vzeroupper): + ZERO_UPPER_VEC_REGISTERS_RETURN + +- .p2align 4 +-L(return_vec_size): +- tzcntl %ecx, %edx + # ifdef USE_AS_STRNCMP +- /* Return 0 if the mismatched index (%rdx + VEC_SIZE) is after +- the maximum offset (%r11). */ +- addq $VEC_SIZE, %rdx +- cmpq %r11, %rdx +- jae L(zero) +-# ifdef USE_AS_WCSCMP ++ .p2align 4,, 8 ++L(vec_0_test_len): ++ notl %ecx ++ bzhil %edx, %ecx, %eax ++ jnz L(return_vec_0) ++ /* Align if will cross fetch block. */ ++ .p2align 4,, 2 ++L(ret_zero): + xorl %eax, %eax +- movl (%rdi, %rdx), %ecx +- cmpl (%rsi, %rdx), %ecx +- jne L(wcscmp_return) +-# else +- movzbl (%rdi, %rdx), %eax +- movzbl (%rsi, %rdx), %edx +- subl %edx, %eax +-# endif +-# else ++ VZEROUPPER_RETURN ++ ++ .p2align 4,, 5 ++L(one_or_less): ++ jb L(ret_zero) + # ifdef USE_AS_WCSCMP ++ /* 'nbe' covers the case where length is negative (large ++ unsigned). */ ++ jnbe __wcscmp_avx2 ++ movl (%rdi), %edx + xorl %eax, %eax +- movl VEC_SIZE(%rdi, %rdx), %ecx +- cmpl VEC_SIZE(%rsi, %rdx), %ecx +- jne L(wcscmp_return) ++ cmpl (%rsi), %edx ++ je L(ret1) ++ setl %al ++ negl %eax ++ orl $1, %eax + # else +- movzbl VEC_SIZE(%rdi, %rdx), %eax +- movzbl VEC_SIZE(%rsi, %rdx), %edx +- subl %edx, %eax ++ /* 'nbe' covers the case where length is negative (large ++ unsigned). */ ++ ++ jnbe __strcmp_avx2 ++ movzbl (%rdi), %eax ++ movzbl (%rsi), %ecx ++ subl %ecx, %eax + # endif ++L(ret1): ++ ret + # endif +- VZEROUPPER_RETURN + +- .p2align 4 +-L(return_2_vec_size): +- tzcntl %ecx, %edx ++ .p2align 4,, 10 ++L(return_vec_1): ++ tzcntl %ecx, %ecx + # ifdef USE_AS_STRNCMP +- /* Return 0 if the mismatched index (%rdx + 2 * VEC_SIZE) is +- after the maximum offset (%r11). */ +- addq $(VEC_SIZE * 2), %rdx +- cmpq %r11, %rdx +- jae L(zero) +-# ifdef USE_AS_WCSCMP ++ /* rdx must be > CHAR_PER_VEC so save to subtract w.o fear of ++ overflow. */ ++ addq $-VEC_SIZE, %rdx ++ cmpq %rcx, %rdx ++ jbe L(ret_zero) ++# endif ++# ifdef USE_AS_WCSCMP ++ movl VEC_SIZE(%rdi, %rcx), %edx + xorl %eax, %eax +- movl (%rdi, %rdx), %ecx +- cmpl (%rsi, %rdx), %ecx +- jne L(wcscmp_return) +-# else +- movzbl (%rdi, %rdx), %eax +- movzbl (%rsi, %rdx), %edx +- subl %edx, %eax +-# endif ++ cmpl VEC_SIZE(%rsi, %rcx), %edx ++ je L(ret2) ++ setl %al ++ negl %eax ++ orl $1, %eax + # else +-# ifdef USE_AS_WCSCMP +- xorl %eax, %eax +- movl (VEC_SIZE * 2)(%rdi, %rdx), %ecx +- cmpl (VEC_SIZE * 2)(%rsi, %rdx), %ecx +- jne L(wcscmp_return) +-# else +- movzbl (VEC_SIZE * 2)(%rdi, %rdx), %eax +- movzbl (VEC_SIZE * 2)(%rsi, %rdx), %edx +- subl %edx, %eax +-# endif ++ movzbl VEC_SIZE(%rdi, %rcx), %eax ++ movzbl VEC_SIZE(%rsi, %rcx), %ecx ++ subl %ecx, %eax + # endif ++L(ret2): + VZEROUPPER_RETURN + +- .p2align 4 +-L(return_3_vec_size): +- tzcntl %ecx, %edx ++ .p2align 4,, 10 + # ifdef USE_AS_STRNCMP +- /* Return 0 if the mismatched index (%rdx + 3 * VEC_SIZE) is +- after the maximum offset (%r11). */ +- addq $(VEC_SIZE * 3), %rdx +- cmpq %r11, %rdx +- jae L(zero) +-# ifdef USE_AS_WCSCMP ++L(return_vec_3): ++ salq $32, %rcx ++# endif ++ ++L(return_vec_2): ++# ifndef USE_AS_STRNCMP ++ tzcntl %ecx, %ecx ++# else ++ tzcntq %rcx, %rcx ++ cmpq %rcx, %rdx ++ jbe L(ret_zero) ++# endif ++ ++# ifdef USE_AS_WCSCMP ++ movl (VEC_SIZE * 2)(%rdi, %rcx), %edx + xorl %eax, %eax +- movl (%rdi, %rdx), %ecx +- cmpl (%rsi, %rdx), %ecx +- jne L(wcscmp_return) +-# else +- movzbl (%rdi, %rdx), %eax +- movzbl (%rsi, %rdx), %edx +- subl %edx, %eax +-# endif ++ cmpl (VEC_SIZE * 2)(%rsi, %rcx), %edx ++ je L(ret3) ++ setl %al ++ negl %eax ++ orl $1, %eax + # else ++ movzbl (VEC_SIZE * 2)(%rdi, %rcx), %eax ++ movzbl (VEC_SIZE * 2)(%rsi, %rcx), %ecx ++ subl %ecx, %eax ++# endif ++L(ret3): ++ VZEROUPPER_RETURN ++ ++# ifndef USE_AS_STRNCMP ++ .p2align 4,, 10 ++L(return_vec_3): ++ tzcntl %ecx, %ecx + # ifdef USE_AS_WCSCMP ++ movl (VEC_SIZE * 3)(%rdi, %rcx), %edx + xorl %eax, %eax +- movl (VEC_SIZE * 3)(%rdi, %rdx), %ecx +- cmpl (VEC_SIZE * 3)(%rsi, %rdx), %ecx +- jne L(wcscmp_return) ++ cmpl (VEC_SIZE * 3)(%rsi, %rcx), %edx ++ je L(ret4) ++ setl %al ++ negl %eax ++ orl $1, %eax + # else +- movzbl (VEC_SIZE * 3)(%rdi, %rdx), %eax +- movzbl (VEC_SIZE * 3)(%rsi, %rdx), %edx +- subl %edx, %eax ++ movzbl (VEC_SIZE * 3)(%rdi, %rcx), %eax ++ movzbl (VEC_SIZE * 3)(%rsi, %rcx), %ecx ++ subl %ecx, %eax + # endif +-# endif ++L(ret4): + VZEROUPPER_RETURN ++# endif ++ ++ .p2align 4,, 10 ++L(more_3x_vec): ++ /* Safe to compare 4x vectors. */ ++ VMOVU VEC_SIZE(%rdi), %ymm0 ++ VPCMPEQ VEC_SIZE(%rsi), %ymm0, %ymm1 ++ VPCMPEQ %ymm0, %ymmZERO, %ymm2 ++ vpandn %ymm1, %ymm2, %ymm1 ++ vpmovmskb %ymm1, %ecx ++ incl %ecx ++ jnz L(return_vec_1) ++ ++# ifdef USE_AS_STRNCMP ++ subq $(VEC_SIZE * 2), %rdx ++ jbe L(ret_zero) ++# endif ++ ++ VMOVU (VEC_SIZE * 2)(%rdi), %ymm0 ++ VPCMPEQ (VEC_SIZE * 2)(%rsi), %ymm0, %ymm1 ++ VPCMPEQ %ymm0, %ymmZERO, %ymm2 ++ vpandn %ymm1, %ymm2, %ymm1 ++ vpmovmskb %ymm1, %ecx ++ incl %ecx ++ jnz L(return_vec_2) ++ ++ VMOVU (VEC_SIZE * 3)(%rdi), %ymm0 ++ VPCMPEQ (VEC_SIZE * 3)(%rsi), %ymm0, %ymm1 ++ VPCMPEQ %ymm0, %ymmZERO, %ymm2 ++ vpandn %ymm1, %ymm2, %ymm1 ++ vpmovmskb %ymm1, %ecx ++ incl %ecx ++ jnz L(return_vec_3) + +- .p2align 4 +-L(next_3_vectors): +- vmovdqu VEC_SIZE(%rdi), %ymm6 +- VPCMPEQ VEC_SIZE(%rsi), %ymm6, %ymm3 +- VPMINU %ymm6, %ymm3, %ymm3 +- VPCMPEQ %ymm7, %ymm3, %ymm3 +- vpmovmskb %ymm3, %ecx +- testl %ecx, %ecx +- jne L(return_vec_size) +- vmovdqu (VEC_SIZE * 2)(%rdi), %ymm5 +- vmovdqu (VEC_SIZE * 3)(%rdi), %ymm4 +- vmovdqu (VEC_SIZE * 3)(%rsi), %ymm0 +- VPCMPEQ (VEC_SIZE * 2)(%rsi), %ymm5, %ymm2 +- VPMINU %ymm5, %ymm2, %ymm2 +- VPCMPEQ %ymm4, %ymm0, %ymm0 +- VPCMPEQ %ymm7, %ymm2, %ymm2 +- vpmovmskb %ymm2, %ecx +- testl %ecx, %ecx +- jne L(return_2_vec_size) +- VPMINU %ymm4, %ymm0, %ymm0 +- VPCMPEQ %ymm7, %ymm0, %ymm0 +- vpmovmskb %ymm0, %ecx +- testl %ecx, %ecx +- jne L(return_3_vec_size) +-L(main_loop_header): +- leaq (VEC_SIZE * 4)(%rdi), %rdx +- movl $PAGE_SIZE, %ecx +- /* Align load via RAX. */ +- andq $-(VEC_SIZE * 4), %rdx +- subq %rdi, %rdx +- leaq (%rdi, %rdx), %rax + # ifdef USE_AS_STRNCMP +- /* Starting from this point, the maximum offset, or simply the +- 'offset', DECREASES by the same amount when base pointers are +- moved forward. Return 0 when: +- 1) On match: offset <= the matched vector index. +- 2) On mistmach, offset is before the mistmatched index. ++ cmpq $(VEC_SIZE * 2), %rdx ++ jbe L(ret_zero) ++# endif ++ ++# ifdef USE_AS_WCSCMP ++ /* any non-zero positive value that doesn't inference with 0x1. + */ +- subq %rdx, %r11 +- jbe L(zero) +-# endif +- addq %rsi, %rdx +- movq %rdx, %rsi +- andl $(PAGE_SIZE - 1), %esi +- /* Number of bytes before page crossing. */ +- subq %rsi, %rcx +- /* Number of VEC_SIZE * 4 blocks before page crossing. */ +- shrq $DIVIDE_BY_VEC_4_SHIFT, %rcx +- /* ESI: Number of VEC_SIZE * 4 blocks before page crossing. */ +- movl %ecx, %esi +- jmp L(loop_start) ++ movl $2, %r8d + ++# else ++ xorl %r8d, %r8d ++# endif ++ ++ /* The prepare labels are various entry points from the page ++ cross logic. */ ++L(prepare_loop): ++ ++# ifdef USE_AS_STRNCMP ++ /* Store N + (VEC_SIZE * 4) and place check at the begining of ++ the loop. */ ++ leaq (VEC_SIZE * 2)(%rdi, %rdx), %rdx ++# endif ++L(prepare_loop_no_len): ++ ++ /* Align s1 and adjust s2 accordingly. */ ++ subq %rdi, %rsi ++ andq $-(VEC_SIZE * 4), %rdi ++ addq %rdi, %rsi ++ ++# ifdef USE_AS_STRNCMP ++ subq %rdi, %rdx ++# endif ++ ++L(prepare_loop_aligned): ++ /* eax stores distance from rsi to next page cross. These cases ++ need to be handled specially as the 4x loop could potentially ++ read memory past the length of s1 or s2 and across a page ++ boundary. */ ++ movl $-(VEC_SIZE * 4), %eax ++ subl %esi, %eax ++ andl $(PAGE_SIZE - 1), %eax ++ ++ /* Loop 4x comparisons at a time. */ + .p2align 4 + L(loop): ++ ++ /* End condition for strncmp. */ + # ifdef USE_AS_STRNCMP +- /* Base pointers are moved forward by 4 * VEC_SIZE. Decrease +- the maximum offset (%r11) by the same amount. */ +- subq $(VEC_SIZE * 4), %r11 +- jbe L(zero) +-# endif +- addq $(VEC_SIZE * 4), %rax +- addq $(VEC_SIZE * 4), %rdx +-L(loop_start): +- testl %esi, %esi +- leal -1(%esi), %esi +- je L(loop_cross_page) +-L(back_to_loop): +- /* Main loop, comparing 4 vectors are a time. */ +- vmovdqa (%rax), %ymm0 +- vmovdqa VEC_SIZE(%rax), %ymm3 +- VPCMPEQ (%rdx), %ymm0, %ymm4 +- VPCMPEQ VEC_SIZE(%rdx), %ymm3, %ymm1 +- VPMINU %ymm0, %ymm4, %ymm4 +- VPMINU %ymm3, %ymm1, %ymm1 +- vmovdqa (VEC_SIZE * 2)(%rax), %ymm2 +- VPMINU %ymm1, %ymm4, %ymm0 +- vmovdqa (VEC_SIZE * 3)(%rax), %ymm3 +- VPCMPEQ (VEC_SIZE * 2)(%rdx), %ymm2, %ymm5 +- VPCMPEQ (VEC_SIZE * 3)(%rdx), %ymm3, %ymm6 +- VPMINU %ymm2, %ymm5, %ymm5 +- VPMINU %ymm3, %ymm6, %ymm6 +- VPMINU %ymm5, %ymm0, %ymm0 +- VPMINU %ymm6, %ymm0, %ymm0 +- VPCMPEQ %ymm7, %ymm0, %ymm0 +- +- /* Test each mask (32 bits) individually because for VEC_SIZE +- == 32 is not possible to OR the four masks and keep all bits +- in a 64-bit integer register, differing from SSE2 strcmp +- where ORing is possible. */ +- vpmovmskb %ymm0, %ecx ++ subq $(VEC_SIZE * 4), %rdx ++ jbe L(ret_zero) ++# endif ++ ++ subq $-(VEC_SIZE * 4), %rdi ++ subq $-(VEC_SIZE * 4), %rsi ++ ++ /* Check if rsi loads will cross a page boundary. */ ++ addl $-(VEC_SIZE * 4), %eax ++ jnb L(page_cross_during_loop) ++ ++ /* Loop entry after handling page cross during loop. */ ++L(loop_skip_page_cross_check): ++ VMOVA (VEC_SIZE * 0)(%rdi), %ymm0 ++ VMOVA (VEC_SIZE * 1)(%rdi), %ymm2 ++ VMOVA (VEC_SIZE * 2)(%rdi), %ymm4 ++ VMOVA (VEC_SIZE * 3)(%rdi), %ymm6 ++ ++ /* ymm1 all 1s where s1 and s2 equal. All 0s otherwise. */ ++ VPCMPEQ (VEC_SIZE * 0)(%rsi), %ymm0, %ymm1 ++ ++ VPCMPEQ (VEC_SIZE * 1)(%rsi), %ymm2, %ymm3 ++ VPCMPEQ (VEC_SIZE * 2)(%rsi), %ymm4, %ymm5 ++ VPCMPEQ (VEC_SIZE * 3)(%rsi), %ymm6, %ymm7 ++ ++ ++ /* If any mismatches or null CHAR then 0 CHAR, otherwise non- ++ zero. */ ++ vpand %ymm0, %ymm1, %ymm1 ++ ++ ++ vpand %ymm2, %ymm3, %ymm3 ++ vpand %ymm4, %ymm5, %ymm5 ++ vpand %ymm6, %ymm7, %ymm7 ++ ++ VPMINU %ymm1, %ymm3, %ymm3 ++ VPMINU %ymm5, %ymm7, %ymm7 ++ ++ /* Reduce all 0 CHARs for the 4x VEC into ymm7. */ ++ VPMINU %ymm3, %ymm7, %ymm7 ++ ++ /* If any 0 CHAR then done. */ ++ VPCMPEQ %ymm7, %ymmZERO, %ymm7 ++ vpmovmskb %ymm7, %LOOP_REG ++ testl %LOOP_REG, %LOOP_REG ++ jz L(loop) ++ ++ /* Find which VEC has the mismatch of end of string. */ ++ VPCMPEQ %ymm1, %ymmZERO, %ymm1 ++ vpmovmskb %ymm1, %ecx + testl %ecx, %ecx +- je L(loop) +- VPCMPEQ %ymm7, %ymm4, %ymm0 +- vpmovmskb %ymm0, %edi +- testl %edi, %edi +- je L(test_vec) +- tzcntl %edi, %ecx ++ jnz L(return_vec_0_end) ++ ++ ++ VPCMPEQ %ymm3, %ymmZERO, %ymm3 ++ vpmovmskb %ymm3, %ecx ++ testl %ecx, %ecx ++ jnz L(return_vec_1_end) ++ ++L(return_vec_2_3_end): + # ifdef USE_AS_STRNCMP +- cmpq %rcx, %r11 +- jbe L(zero) +-# ifdef USE_AS_WCSCMP +- movq %rax, %rsi ++ subq $(VEC_SIZE * 2), %rdx ++ jbe L(ret_zero_end) ++# endif ++ ++ VPCMPEQ %ymm5, %ymmZERO, %ymm5 ++ vpmovmskb %ymm5, %ecx ++ testl %ecx, %ecx ++ jnz L(return_vec_2_end) ++ ++ /* LOOP_REG contains matches for null/mismatch from the loop. If ++ VEC 0,1,and 2 all have no null and no mismatches then mismatch ++ must entirely be from VEC 3 which is fully represented by ++ LOOP_REG. */ ++ tzcntl %LOOP_REG, %LOOP_REG ++ ++# ifdef USE_AS_STRNCMP ++ subl $-(VEC_SIZE), %LOOP_REG ++ cmpq %LOOP_REG64, %rdx ++ jbe L(ret_zero_end) ++# endif ++ ++# ifdef USE_AS_WCSCMP ++ movl (VEC_SIZE * 2 - VEC_OFFSET)(%rdi, %LOOP_REG64), %ecx + xorl %eax, %eax +- movl (%rsi, %rcx), %edi +- cmpl (%rdx, %rcx), %edi +- jne L(wcscmp_return) +-# else +- movzbl (%rax, %rcx), %eax +- movzbl (%rdx, %rcx), %edx +- subl %edx, %eax +-# endif ++ cmpl (VEC_SIZE * 2 - VEC_OFFSET)(%rsi, %LOOP_REG64), %ecx ++ je L(ret5) ++ setl %al ++ negl %eax ++ xorl %r8d, %eax + # else +-# ifdef USE_AS_WCSCMP +- movq %rax, %rsi +- xorl %eax, %eax +- movl (%rsi, %rcx), %edi +- cmpl (%rdx, %rcx), %edi +- jne L(wcscmp_return) +-# else +- movzbl (%rax, %rcx), %eax +- movzbl (%rdx, %rcx), %edx +- subl %edx, %eax +-# endif ++ movzbl (VEC_SIZE * 2 - VEC_OFFSET)(%rdi, %LOOP_REG64), %eax ++ movzbl (VEC_SIZE * 2 - VEC_OFFSET)(%rsi, %LOOP_REG64), %ecx ++ subl %ecx, %eax ++ xorl %r8d, %eax ++ subl %r8d, %eax + # endif ++L(ret5): + VZEROUPPER_RETURN + +- .p2align 4 +-L(test_vec): + # ifdef USE_AS_STRNCMP +- /* The first vector matched. Return 0 if the maximum offset +- (%r11) <= VEC_SIZE. */ +- cmpq $VEC_SIZE, %r11 +- jbe L(zero) ++ .p2align 4,, 2 ++L(ret_zero_end): ++ xorl %eax, %eax ++ VZEROUPPER_RETURN + # endif +- VPCMPEQ %ymm7, %ymm1, %ymm1 +- vpmovmskb %ymm1, %ecx +- testl %ecx, %ecx +- je L(test_2_vec) +- tzcntl %ecx, %edi ++ ++ ++ /* The L(return_vec_N_end) differ from L(return_vec_N) in that ++ they use the value of `r8` to negate the return value. This is ++ because the page cross logic can swap `rdi` and `rsi`. */ ++ .p2align 4,, 10 + # ifdef USE_AS_STRNCMP +- addq $VEC_SIZE, %rdi +- cmpq %rdi, %r11 +- jbe L(zero) +-# ifdef USE_AS_WCSCMP +- movq %rax, %rsi ++L(return_vec_1_end): ++ salq $32, %rcx ++# endif ++L(return_vec_0_end): ++# ifndef USE_AS_STRNCMP ++ tzcntl %ecx, %ecx ++# else ++ tzcntq %rcx, %rcx ++ cmpq %rcx, %rdx ++ jbe L(ret_zero_end) ++# endif ++ ++# ifdef USE_AS_WCSCMP ++ movl (%rdi, %rcx), %edx + xorl %eax, %eax +- movl (%rsi, %rdi), %ecx +- cmpl (%rdx, %rdi), %ecx +- jne L(wcscmp_return) +-# else +- movzbl (%rax, %rdi), %eax +- movzbl (%rdx, %rdi), %edx +- subl %edx, %eax +-# endif ++ cmpl (%rsi, %rcx), %edx ++ je L(ret6) ++ setl %al ++ negl %eax ++ xorl %r8d, %eax + # else ++ movzbl (%rdi, %rcx), %eax ++ movzbl (%rsi, %rcx), %ecx ++ subl %ecx, %eax ++ xorl %r8d, %eax ++ subl %r8d, %eax ++# endif ++L(ret6): ++ VZEROUPPER_RETURN ++ ++# ifndef USE_AS_STRNCMP ++ .p2align 4,, 10 ++L(return_vec_1_end): ++ tzcntl %ecx, %ecx + # ifdef USE_AS_WCSCMP +- movq %rax, %rsi ++ movl VEC_SIZE(%rdi, %rcx), %edx + xorl %eax, %eax +- movl VEC_SIZE(%rsi, %rdi), %ecx +- cmpl VEC_SIZE(%rdx, %rdi), %ecx +- jne L(wcscmp_return) ++ cmpl VEC_SIZE(%rsi, %rcx), %edx ++ je L(ret7) ++ setl %al ++ negl %eax ++ xorl %r8d, %eax + # else +- movzbl VEC_SIZE(%rax, %rdi), %eax +- movzbl VEC_SIZE(%rdx, %rdi), %edx +- subl %edx, %eax ++ movzbl VEC_SIZE(%rdi, %rcx), %eax ++ movzbl VEC_SIZE(%rsi, %rcx), %ecx ++ subl %ecx, %eax ++ xorl %r8d, %eax ++ subl %r8d, %eax + # endif +-# endif ++L(ret7): + VZEROUPPER_RETURN ++# endif + +- .p2align 4 +-L(test_2_vec): ++ .p2align 4,, 10 ++L(return_vec_2_end): ++ tzcntl %ecx, %ecx + # ifdef USE_AS_STRNCMP +- /* The first 2 vectors matched. Return 0 if the maximum offset +- (%r11) <= 2 * VEC_SIZE. */ +- cmpq $(VEC_SIZE * 2), %r11 +- jbe L(zero) ++ cmpq %rcx, %rdx ++ jbe L(ret_zero_page_cross) + # endif +- VPCMPEQ %ymm7, %ymm5, %ymm5 +- vpmovmskb %ymm5, %ecx +- testl %ecx, %ecx +- je L(test_3_vec) +- tzcntl %ecx, %edi +-# ifdef USE_AS_STRNCMP +- addq $(VEC_SIZE * 2), %rdi +- cmpq %rdi, %r11 +- jbe L(zero) +-# ifdef USE_AS_WCSCMP +- movq %rax, %rsi ++# ifdef USE_AS_WCSCMP ++ movl (VEC_SIZE * 2)(%rdi, %rcx), %edx + xorl %eax, %eax +- movl (%rsi, %rdi), %ecx +- cmpl (%rdx, %rdi), %ecx +- jne L(wcscmp_return) +-# else +- movzbl (%rax, %rdi), %eax +- movzbl (%rdx, %rdi), %edx +- subl %edx, %eax +-# endif ++ cmpl (VEC_SIZE * 2)(%rsi, %rcx), %edx ++ je L(ret11) ++ setl %al ++ negl %eax ++ xorl %r8d, %eax + # else +-# ifdef USE_AS_WCSCMP +- movq %rax, %rsi +- xorl %eax, %eax +- movl (VEC_SIZE * 2)(%rsi, %rdi), %ecx +- cmpl (VEC_SIZE * 2)(%rdx, %rdi), %ecx +- jne L(wcscmp_return) +-# else +- movzbl (VEC_SIZE * 2)(%rax, %rdi), %eax +- movzbl (VEC_SIZE * 2)(%rdx, %rdi), %edx +- subl %edx, %eax +-# endif ++ movzbl (VEC_SIZE * 2)(%rdi, %rcx), %eax ++ movzbl (VEC_SIZE * 2)(%rsi, %rcx), %ecx ++ subl %ecx, %eax ++ xorl %r8d, %eax ++ subl %r8d, %eax + # endif ++L(ret11): + VZEROUPPER_RETURN + +- .p2align 4 +-L(test_3_vec): ++ ++ /* Page cross in rsi in next 4x VEC. */ ++ ++ /* TODO: Improve logic here. */ ++ .p2align 4,, 10 ++L(page_cross_during_loop): ++ /* eax contains [distance_from_page - (VEC_SIZE * 4)]. */ ++ ++ /* Optimistically rsi and rdi and both aligned inwhich case we ++ don't need any logic here. */ ++ cmpl $-(VEC_SIZE * 4), %eax ++ /* Don't adjust eax before jumping back to loop and we will ++ never hit page cross case again. */ ++ je L(loop_skip_page_cross_check) ++ ++ /* Check if we can safely load a VEC. */ ++ cmpl $-(VEC_SIZE * 3), %eax ++ jle L(less_1x_vec_till_page_cross) ++ ++ VMOVA (%rdi), %ymm0 ++ VPCMPEQ (%rsi), %ymm0, %ymm1 ++ VPCMPEQ %ymm0, %ymmZERO, %ymm2 ++ vpandn %ymm1, %ymm2, %ymm1 ++ vpmovmskb %ymm1, %ecx ++ incl %ecx ++ jnz L(return_vec_0_end) ++ ++ /* if distance >= 2x VEC then eax > -(VEC_SIZE * 2). */ ++ cmpl $-(VEC_SIZE * 2), %eax ++ jg L(more_2x_vec_till_page_cross) ++ ++ .p2align 4,, 4 ++L(less_1x_vec_till_page_cross): ++ subl $-(VEC_SIZE * 4), %eax ++ /* Guranteed safe to read from rdi - VEC_SIZE here. The only ++ concerning case is first iteration if incoming s1 was near start ++ of a page and s2 near end. If s1 was near the start of the page ++ we already aligned up to nearest VEC_SIZE * 4 so gurnateed safe ++ to read back -VEC_SIZE. If rdi is truly at the start of a page ++ here, it means the previous page (rdi - VEC_SIZE) has already ++ been loaded earlier so must be valid. */ ++ VMOVU -VEC_SIZE(%rdi, %rax), %ymm0 ++ VPCMPEQ -VEC_SIZE(%rsi, %rax), %ymm0, %ymm1 ++ VPCMPEQ %ymm0, %ymmZERO, %ymm2 ++ vpandn %ymm1, %ymm2, %ymm1 ++ vpmovmskb %ymm1, %ecx ++ ++ /* Mask of potentially valid bits. The lower bits can be out of ++ range comparisons (but safe regarding page crosses). */ ++ movl $-1, %r10d ++ shlxl %esi, %r10d, %r10d ++ notl %ecx ++ + # ifdef USE_AS_STRNCMP +- /* The first 3 vectors matched. Return 0 if the maximum offset +- (%r11) <= 3 * VEC_SIZE. */ +- cmpq $(VEC_SIZE * 3), %r11 +- jbe L(zero) +-# endif +- VPCMPEQ %ymm7, %ymm6, %ymm6 +- vpmovmskb %ymm6, %esi +- tzcntl %esi, %ecx ++ cmpq %rax, %rdx ++ jbe L(return_page_cross_end_check) ++# endif ++ movl %eax, %OFFSET_REG ++ addl $(PAGE_SIZE - VEC_SIZE * 4), %eax ++ ++ andl %r10d, %ecx ++ jz L(loop_skip_page_cross_check) ++ ++ .p2align 4,, 3 ++L(return_page_cross_end): ++ tzcntl %ecx, %ecx ++ + # ifdef USE_AS_STRNCMP +- addq $(VEC_SIZE * 3), %rcx +- cmpq %rcx, %r11 +- jbe L(zero) +-# ifdef USE_AS_WCSCMP +- movq %rax, %rsi +- xorl %eax, %eax +- movl (%rsi, %rcx), %esi +- cmpl (%rdx, %rcx), %esi +- jne L(wcscmp_return) +-# else +- movzbl (%rax, %rcx), %eax +- movzbl (%rdx, %rcx), %edx +- subl %edx, %eax +-# endif ++ leal -VEC_SIZE(%OFFSET_REG64, %rcx), %ecx ++L(return_page_cross_cmp_mem): + # else +-# ifdef USE_AS_WCSCMP +- movq %rax, %rsi ++ addl %OFFSET_REG, %ecx ++# endif ++# ifdef USE_AS_WCSCMP ++ movl VEC_OFFSET(%rdi, %rcx), %edx + xorl %eax, %eax +- movl (VEC_SIZE * 3)(%rsi, %rcx), %esi +- cmpl (VEC_SIZE * 3)(%rdx, %rcx), %esi +- jne L(wcscmp_return) +-# else +- movzbl (VEC_SIZE * 3)(%rax, %rcx), %eax +- movzbl (VEC_SIZE * 3)(%rdx, %rcx), %edx +- subl %edx, %eax +-# endif ++ cmpl VEC_OFFSET(%rsi, %rcx), %edx ++ je L(ret8) ++ setl %al ++ negl %eax ++ xorl %r8d, %eax ++# else ++ movzbl VEC_OFFSET(%rdi, %rcx), %eax ++ movzbl VEC_OFFSET(%rsi, %rcx), %ecx ++ subl %ecx, %eax ++ xorl %r8d, %eax ++ subl %r8d, %eax + # endif ++L(ret8): + VZEROUPPER_RETURN + +- .p2align 4 +-L(loop_cross_page): +- xorl %r10d, %r10d +- movq %rdx, %rcx +- /* Align load via RDX. We load the extra ECX bytes which should +- be ignored. */ +- andl $((VEC_SIZE * 4) - 1), %ecx +- /* R10 is -RCX. */ +- subq %rcx, %r10 +- +- /* This works only if VEC_SIZE * 2 == 64. */ +-# if (VEC_SIZE * 2) != 64 +-# error (VEC_SIZE * 2) != 64 +-# endif +- +- /* Check if the first VEC_SIZE * 2 bytes should be ignored. */ +- cmpl $(VEC_SIZE * 2), %ecx +- jge L(loop_cross_page_2_vec) +- +- vmovdqu (%rax, %r10), %ymm2 +- vmovdqu VEC_SIZE(%rax, %r10), %ymm3 +- VPCMPEQ (%rdx, %r10), %ymm2, %ymm0 +- VPCMPEQ VEC_SIZE(%rdx, %r10), %ymm3, %ymm1 +- VPMINU %ymm2, %ymm0, %ymm0 +- VPMINU %ymm3, %ymm1, %ymm1 +- VPCMPEQ %ymm7, %ymm0, %ymm0 +- VPCMPEQ %ymm7, %ymm1, %ymm1 +- +- vpmovmskb %ymm0, %edi +- vpmovmskb %ymm1, %esi +- +- salq $32, %rsi +- xorq %rsi, %rdi +- +- /* Since ECX < VEC_SIZE * 2, simply skip the first ECX bytes. */ +- shrq %cl, %rdi +- +- testq %rdi, %rdi +- je L(loop_cross_page_2_vec) +- tzcntq %rdi, %rcx + # ifdef USE_AS_STRNCMP +- cmpq %rcx, %r11 +- jbe L(zero) +-# ifdef USE_AS_WCSCMP +- movq %rax, %rsi ++ .p2align 4,, 10 ++L(return_page_cross_end_check): ++ tzcntl %ecx, %ecx ++ leal -VEC_SIZE(%rax, %rcx), %ecx ++ cmpl %ecx, %edx ++ ja L(return_page_cross_cmp_mem) + xorl %eax, %eax +- movl (%rsi, %rcx), %edi +- cmpl (%rdx, %rcx), %edi +- jne L(wcscmp_return) +-# else +- movzbl (%rax, %rcx), %eax +- movzbl (%rdx, %rcx), %edx +- subl %edx, %eax +-# endif +-# else +-# ifdef USE_AS_WCSCMP +- movq %rax, %rsi +- xorl %eax, %eax +- movl (%rsi, %rcx), %edi +- cmpl (%rdx, %rcx), %edi +- jne L(wcscmp_return) +-# else +- movzbl (%rax, %rcx), %eax +- movzbl (%rdx, %rcx), %edx +- subl %edx, %eax +-# endif +-# endif + VZEROUPPER_RETURN ++# endif + +- .p2align 4 +-L(loop_cross_page_2_vec): +- /* The first VEC_SIZE * 2 bytes match or are ignored. */ +- vmovdqu (VEC_SIZE * 2)(%rax, %r10), %ymm2 +- vmovdqu (VEC_SIZE * 3)(%rax, %r10), %ymm3 +- VPCMPEQ (VEC_SIZE * 2)(%rdx, %r10), %ymm2, %ymm5 +- VPMINU %ymm2, %ymm5, %ymm5 +- VPCMPEQ (VEC_SIZE * 3)(%rdx, %r10), %ymm3, %ymm6 +- VPCMPEQ %ymm7, %ymm5, %ymm5 +- VPMINU %ymm3, %ymm6, %ymm6 +- VPCMPEQ %ymm7, %ymm6, %ymm6 +- +- vpmovmskb %ymm5, %edi +- vpmovmskb %ymm6, %esi +- +- salq $32, %rsi +- xorq %rsi, %rdi + +- xorl %r8d, %r8d +- /* If ECX > VEC_SIZE * 2, skip ECX - (VEC_SIZE * 2) bytes. */ +- subl $(VEC_SIZE * 2), %ecx +- jle 1f +- /* Skip ECX bytes. */ +- shrq %cl, %rdi +- /* R8 has number of bytes skipped. */ +- movl %ecx, %r8d +-1: +- /* Before jumping back to the loop, set ESI to the number of +- VEC_SIZE * 4 blocks before page crossing. */ +- movl $(PAGE_SIZE / (VEC_SIZE * 4) - 1), %esi +- +- testq %rdi, %rdi ++ .p2align 4,, 10 ++L(more_2x_vec_till_page_cross): ++ /* If more 2x vec till cross we will complete a full loop ++ iteration here. */ ++ ++ VMOVU VEC_SIZE(%rdi), %ymm0 ++ VPCMPEQ VEC_SIZE(%rsi), %ymm0, %ymm1 ++ VPCMPEQ %ymm0, %ymmZERO, %ymm2 ++ vpandn %ymm1, %ymm2, %ymm1 ++ vpmovmskb %ymm1, %ecx ++ incl %ecx ++ jnz L(return_vec_1_end) ++ + # ifdef USE_AS_STRNCMP +- /* At this point, if %rdi value is 0, it already tested +- VEC_SIZE*4+%r10 byte starting from %rax. This label +- checks whether strncmp maximum offset reached or not. */ +- je L(string_nbyte_offset_check) +-# else +- je L(back_to_loop) ++ cmpq $(VEC_SIZE * 2), %rdx ++ jbe L(ret_zero_in_loop_page_cross) + # endif +- tzcntq %rdi, %rcx +- addq %r10, %rcx +- /* Adjust for number of bytes skipped. */ +- addq %r8, %rcx ++ ++ subl $-(VEC_SIZE * 4), %eax ++ ++ /* Safe to include comparisons from lower bytes. */ ++ VMOVU -(VEC_SIZE * 2)(%rdi, %rax), %ymm0 ++ VPCMPEQ -(VEC_SIZE * 2)(%rsi, %rax), %ymm0, %ymm1 ++ VPCMPEQ %ymm0, %ymmZERO, %ymm2 ++ vpandn %ymm1, %ymm2, %ymm1 ++ vpmovmskb %ymm1, %ecx ++ incl %ecx ++ jnz L(return_vec_page_cross_0) ++ ++ VMOVU -(VEC_SIZE * 1)(%rdi, %rax), %ymm0 ++ VPCMPEQ -(VEC_SIZE * 1)(%rsi, %rax), %ymm0, %ymm1 ++ VPCMPEQ %ymm0, %ymmZERO, %ymm2 ++ vpandn %ymm1, %ymm2, %ymm1 ++ vpmovmskb %ymm1, %ecx ++ incl %ecx ++ jnz L(return_vec_page_cross_1) ++ + # ifdef USE_AS_STRNCMP +- addq $(VEC_SIZE * 2), %rcx +- subq %rcx, %r11 +- jbe L(zero) +-# ifdef USE_AS_WCSCMP +- movq %rax, %rsi ++ /* Must check length here as length might proclude reading next ++ page. */ ++ cmpq %rax, %rdx ++ jbe L(ret_zero_in_loop_page_cross) ++# endif ++ ++ /* Finish the loop. */ ++ VMOVA (VEC_SIZE * 2)(%rdi), %ymm4 ++ VMOVA (VEC_SIZE * 3)(%rdi), %ymm6 ++ ++ VPCMPEQ (VEC_SIZE * 2)(%rsi), %ymm4, %ymm5 ++ VPCMPEQ (VEC_SIZE * 3)(%rsi), %ymm6, %ymm7 ++ vpand %ymm4, %ymm5, %ymm5 ++ vpand %ymm6, %ymm7, %ymm7 ++ VPMINU %ymm5, %ymm7, %ymm7 ++ VPCMPEQ %ymm7, %ymmZERO, %ymm7 ++ vpmovmskb %ymm7, %LOOP_REG ++ testl %LOOP_REG, %LOOP_REG ++ jnz L(return_vec_2_3_end) ++ ++ /* Best for code size to include ucond-jmp here. Would be faster ++ if this case is hot to duplicate the L(return_vec_2_3_end) code ++ as fall-through and have jump back to loop on mismatch ++ comparison. */ ++ subq $-(VEC_SIZE * 4), %rdi ++ subq $-(VEC_SIZE * 4), %rsi ++ addl $(PAGE_SIZE - VEC_SIZE * 8), %eax ++# ifdef USE_AS_STRNCMP ++ subq $(VEC_SIZE * 4), %rdx ++ ja L(loop_skip_page_cross_check) ++L(ret_zero_in_loop_page_cross): + xorl %eax, %eax +- movl (%rsi, %rcx), %edi +- cmpl (%rdx, %rcx), %edi +- jne L(wcscmp_return) +-# else +- movzbl (%rax, %rcx), %eax +- movzbl (%rdx, %rcx), %edx +- subl %edx, %eax +-# endif ++ VZEROUPPER_RETURN + # else +-# ifdef USE_AS_WCSCMP +- movq %rax, %rsi +- xorl %eax, %eax +- movl (VEC_SIZE * 2)(%rsi, %rcx), %edi +- cmpl (VEC_SIZE * 2)(%rdx, %rcx), %edi +- jne L(wcscmp_return) +-# else +- movzbl (VEC_SIZE * 2)(%rax, %rcx), %eax +- movzbl (VEC_SIZE * 2)(%rdx, %rcx), %edx +- subl %edx, %eax +-# endif ++ jmp L(loop_skip_page_cross_check) + # endif +- VZEROUPPER_RETURN + ++ ++ .p2align 4,, 10 ++L(return_vec_page_cross_0): ++ addl $-VEC_SIZE, %eax ++L(return_vec_page_cross_1): ++ tzcntl %ecx, %ecx + # ifdef USE_AS_STRNCMP +-L(string_nbyte_offset_check): +- leaq (VEC_SIZE * 4)(%r10), %r10 +- cmpq %r10, %r11 +- jbe L(zero) +- jmp L(back_to_loop) ++ leal -VEC_SIZE(%rax, %rcx), %ecx ++ cmpq %rcx, %rdx ++ jbe L(ret_zero_in_loop_page_cross) ++# else ++ addl %eax, %ecx + # endif + +- .p2align 4 +-L(cross_page_loop): +- /* Check one byte/dword at a time. */ + # ifdef USE_AS_WCSCMP +- cmpl %ecx, %eax ++ movl VEC_OFFSET(%rdi, %rcx), %edx ++ xorl %eax, %eax ++ cmpl VEC_OFFSET(%rsi, %rcx), %edx ++ je L(ret9) ++ setl %al ++ negl %eax ++ xorl %r8d, %eax + # else ++ movzbl VEC_OFFSET(%rdi, %rcx), %eax ++ movzbl VEC_OFFSET(%rsi, %rcx), %ecx + subl %ecx, %eax ++ xorl %r8d, %eax ++ subl %r8d, %eax + # endif +- jne L(different) +- addl $SIZE_OF_CHAR, %edx +- cmpl $(VEC_SIZE * 4), %edx +- je L(main_loop_header) +-# ifdef USE_AS_STRNCMP +- cmpq %r11, %rdx +- jae L(zero) ++L(ret9): ++ VZEROUPPER_RETURN ++ ++ ++ .p2align 4,, 10 ++L(page_cross): ++# ifndef USE_AS_STRNCMP ++ /* If both are VEC aligned we don't need any special logic here. ++ Only valid for strcmp where stop condition is guranteed to be ++ reachable by just reading memory. */ ++ testl $((VEC_SIZE - 1) << 20), %eax ++ jz L(no_page_cross) + # endif ++ ++ movl %edi, %eax ++ movl %esi, %ecx ++ andl $(PAGE_SIZE - 1), %eax ++ andl $(PAGE_SIZE - 1), %ecx ++ ++ xorl %OFFSET_REG, %OFFSET_REG ++ ++ /* Check which is closer to page cross, s1 or s2. */ ++ cmpl %eax, %ecx ++ jg L(page_cross_s2) ++ ++ /* The previous page cross check has false positives. Check for ++ true positive as page cross logic is very expensive. */ ++ subl $(PAGE_SIZE - VEC_SIZE * 4), %eax ++ jbe L(no_page_cross) ++ ++ /* Set r8 to not interfere with normal return value (rdi and rsi ++ did not swap). */ + # ifdef USE_AS_WCSCMP +- movl (%rdi, %rdx), %eax +- movl (%rsi, %rdx), %ecx ++ /* any non-zero positive value that doesn't inference with 0x1. ++ */ ++ movl $2, %r8d + # else +- movzbl (%rdi, %rdx), %eax +- movzbl (%rsi, %rdx), %ecx ++ xorl %r8d, %r8d + # endif +- /* Check null char. */ +- testl %eax, %eax +- jne L(cross_page_loop) +- /* Since %eax == 0, subtract is OK for both SIGNED and UNSIGNED +- comparisons. */ +- subl %ecx, %eax +-# ifndef USE_AS_WCSCMP +-L(different): ++ ++ /* Check if less than 1x VEC till page cross. */ ++ subl $(VEC_SIZE * 3), %eax ++ jg L(less_1x_vec_till_page) ++ ++ /* If more than 1x VEC till page cross, loop throuh safely ++ loadable memory until within 1x VEC of page cross. */ ++ ++ .p2align 4,, 10 ++L(page_cross_loop): ++ ++ VMOVU (%rdi, %OFFSET_REG64), %ymm0 ++ VPCMPEQ (%rsi, %OFFSET_REG64), %ymm0, %ymm1 ++ VPCMPEQ %ymm0, %ymmZERO, %ymm2 ++ vpandn %ymm1, %ymm2, %ymm1 ++ vpmovmskb %ymm1, %ecx ++ incl %ecx ++ ++ jnz L(check_ret_vec_page_cross) ++ addl $VEC_SIZE, %OFFSET_REG ++# ifdef USE_AS_STRNCMP ++ cmpq %OFFSET_REG64, %rdx ++ jbe L(ret_zero_page_cross) + # endif +- VZEROUPPER_RETURN ++ addl $VEC_SIZE, %eax ++ jl L(page_cross_loop) ++ ++ subl %eax, %OFFSET_REG ++ /* OFFSET_REG has distance to page cross - VEC_SIZE. Guranteed ++ to not cross page so is safe to load. Since we have already ++ loaded at least 1 VEC from rsi it is also guranteed to be safe. ++ */ ++ ++ VMOVU (%rdi, %OFFSET_REG64), %ymm0 ++ VPCMPEQ (%rsi, %OFFSET_REG64), %ymm0, %ymm1 ++ VPCMPEQ %ymm0, %ymmZERO, %ymm2 ++ vpandn %ymm1, %ymm2, %ymm1 ++ vpmovmskb %ymm1, %ecx ++ ++# ifdef USE_AS_STRNCMP ++ leal VEC_SIZE(%OFFSET_REG64), %eax ++ cmpq %rax, %rdx ++ jbe L(check_ret_vec_page_cross2) ++ addq %rdi, %rdx ++# endif ++ incl %ecx ++ jz L(prepare_loop_no_len) + ++ .p2align 4,, 4 ++L(ret_vec_page_cross): ++# ifndef USE_AS_STRNCMP ++L(check_ret_vec_page_cross): ++# endif ++ tzcntl %ecx, %ecx ++ addl %OFFSET_REG, %ecx ++L(ret_vec_page_cross_cont): + # ifdef USE_AS_WCSCMP +- .p2align 4 +-L(different): +- /* Use movl to avoid modifying EFLAGS. */ +- movl $0, %eax ++ movl (%rdi, %rcx), %edx ++ xorl %eax, %eax ++ cmpl (%rsi, %rcx), %edx ++ je L(ret12) + setl %al + negl %eax +- orl $1, %eax +- VZEROUPPER_RETURN ++ xorl %r8d, %eax ++# else ++ movzbl (%rdi, %rcx), %eax ++ movzbl (%rsi, %rcx), %ecx ++ subl %ecx, %eax ++ xorl %r8d, %eax ++ subl %r8d, %eax + # endif ++L(ret12): ++ VZEROUPPER_RETURN + + # ifdef USE_AS_STRNCMP +- .p2align 4 +-L(zero): ++ .p2align 4,, 10 ++L(check_ret_vec_page_cross2): ++ incl %ecx ++L(check_ret_vec_page_cross): ++ tzcntl %ecx, %ecx ++ addl %OFFSET_REG, %ecx ++ cmpq %rcx, %rdx ++ ja L(ret_vec_page_cross_cont) ++ .p2align 4,, 2 ++L(ret_zero_page_cross): + xorl %eax, %eax + VZEROUPPER_RETURN ++# endif + +- .p2align 4 +-L(char0): +-# ifdef USE_AS_WCSCMP +- xorl %eax, %eax +- movl (%rdi), %ecx +- cmpl (%rsi), %ecx +- jne L(wcscmp_return) +-# else +- movzbl (%rsi), %ecx +- movzbl (%rdi), %eax +- subl %ecx, %eax +-# endif +- VZEROUPPER_RETURN ++ .p2align 4,, 4 ++L(page_cross_s2): ++ /* Ensure this is a true page cross. */ ++ subl $(PAGE_SIZE - VEC_SIZE * 4), %ecx ++ jbe L(no_page_cross) ++ ++ ++ movl %ecx, %eax ++ movq %rdi, %rcx ++ movq %rsi, %rdi ++ movq %rcx, %rsi ++ ++ /* set r8 to negate return value as rdi and rsi swapped. */ ++# ifdef USE_AS_WCSCMP ++ movl $-4, %r8d ++# else ++ movl $-1, %r8d + # endif ++ xorl %OFFSET_REG, %OFFSET_REG + +- .p2align 4 +-L(last_vector): +- addq %rdx, %rdi +- addq %rdx, %rsi ++ /* Check if more than 1x VEC till page cross. */ ++ subl $(VEC_SIZE * 3), %eax ++ jle L(page_cross_loop) ++ ++ .p2align 4,, 6 ++L(less_1x_vec_till_page): ++ /* Find largest load size we can use. */ ++ cmpl $16, %eax ++ ja L(less_16_till_page) ++ ++ VMOVU (%rdi), %xmm0 ++ VPCMPEQ (%rsi), %xmm0, %xmm1 ++ VPCMPEQ %xmm0, %xmmZERO, %xmm2 ++ vpandn %xmm1, %xmm2, %xmm1 ++ vpmovmskb %ymm1, %ecx ++ incw %cx ++ jnz L(check_ret_vec_page_cross) ++ movl $16, %OFFSET_REG + # ifdef USE_AS_STRNCMP +- subq %rdx, %r11 ++ cmpq %OFFSET_REG64, %rdx ++ jbe L(ret_zero_page_cross_slow_case0) ++ subl %eax, %OFFSET_REG ++# else ++ /* Explicit check for 16 byte alignment. */ ++ subl %eax, %OFFSET_REG ++ jz L(prepare_loop) + # endif +- tzcntl %ecx, %edx ++ ++ VMOVU (%rdi, %OFFSET_REG64), %xmm0 ++ VPCMPEQ (%rsi, %OFFSET_REG64), %xmm0, %xmm1 ++ VPCMPEQ %xmm0, %xmmZERO, %xmm2 ++ vpandn %xmm1, %xmm2, %xmm1 ++ vpmovmskb %ymm1, %ecx ++ incw %cx ++ jnz L(check_ret_vec_page_cross) ++ + # ifdef USE_AS_STRNCMP +- cmpq %r11, %rdx +- jae L(zero) ++ addl $16, %OFFSET_REG ++ subq %OFFSET_REG64, %rdx ++ jbe L(ret_zero_page_cross_slow_case0) ++ subq $-(VEC_SIZE * 4), %rdx ++ ++ leaq -(VEC_SIZE * 4)(%rdi, %OFFSET_REG64), %rdi ++ leaq -(VEC_SIZE * 4)(%rsi, %OFFSET_REG64), %rsi ++# else ++ leaq (16 - VEC_SIZE * 4)(%rdi, %OFFSET_REG64), %rdi ++ leaq (16 - VEC_SIZE * 4)(%rsi, %OFFSET_REG64), %rsi + # endif +-# ifdef USE_AS_WCSCMP ++ jmp L(prepare_loop_aligned) ++ ++# ifdef USE_AS_STRNCMP ++ .p2align 4,, 2 ++L(ret_zero_page_cross_slow_case0): + xorl %eax, %eax +- movl (%rdi, %rdx), %ecx +- cmpl (%rsi, %rdx), %ecx +- jne L(wcscmp_return) +-# else +- movzbl (%rdi, %rdx), %eax +- movzbl (%rsi, %rdx), %edx +- subl %edx, %eax ++ ret + # endif +- VZEROUPPER_RETURN + +- /* Comparing on page boundary region requires special treatment: +- It must done one vector at the time, starting with the wider +- ymm vector if possible, if not, with xmm. If fetching 16 bytes +- (xmm) still passes the boundary, byte comparison must be done. +- */ +- .p2align 4 +-L(cross_page): +- /* Try one ymm vector at a time. */ +- cmpl $(PAGE_SIZE - VEC_SIZE), %eax +- jg L(cross_page_1_vector) +-L(loop_1_vector): +- vmovdqu (%rdi, %rdx), %ymm1 +- VPCMPEQ (%rsi, %rdx), %ymm1, %ymm0 +- VPMINU %ymm1, %ymm0, %ymm0 +- VPCMPEQ %ymm7, %ymm0, %ymm0 +- vpmovmskb %ymm0, %ecx +- testl %ecx, %ecx +- jne L(last_vector) + +- addl $VEC_SIZE, %edx ++ .p2align 4,, 10 ++L(less_16_till_page): ++ /* Find largest load size we can use. */ ++ cmpl $24, %eax ++ ja L(less_8_till_page) + +- addl $VEC_SIZE, %eax +-# ifdef USE_AS_STRNCMP +- /* Return 0 if the current offset (%rdx) >= the maximum offset +- (%r11). */ +- cmpq %r11, %rdx +- jae L(zero) +-# endif +- cmpl $(PAGE_SIZE - VEC_SIZE), %eax +- jle L(loop_1_vector) +-L(cross_page_1_vector): +- /* Less than 32 bytes to check, try one xmm vector. */ +- cmpl $(PAGE_SIZE - 16), %eax +- jg L(cross_page_1_xmm) +- vmovdqu (%rdi, %rdx), %xmm1 +- VPCMPEQ (%rsi, %rdx), %xmm1, %xmm0 +- VPMINU %xmm1, %xmm0, %xmm0 +- VPCMPEQ %xmm7, %xmm0, %xmm0 +- vpmovmskb %xmm0, %ecx +- testl %ecx, %ecx +- jne L(last_vector) ++ vmovq (%rdi), %xmm0 ++ vmovq (%rsi), %xmm1 ++ VPCMPEQ %xmm0, %xmmZERO, %xmm2 ++ VPCMPEQ %xmm1, %xmm0, %xmm1 ++ vpandn %xmm1, %xmm2, %xmm1 ++ vpmovmskb %ymm1, %ecx ++ incb %cl ++ jnz L(check_ret_vec_page_cross) + +- addl $16, %edx +-# ifndef USE_AS_WCSCMP +- addl $16, %eax ++ ++# ifdef USE_AS_STRNCMP ++ cmpq $8, %rdx ++ jbe L(ret_zero_page_cross_slow_case0) + # endif ++ movl $24, %OFFSET_REG ++ /* Explicit check for 16 byte alignment. */ ++ subl %eax, %OFFSET_REG ++ ++ ++ ++ vmovq (%rdi, %OFFSET_REG64), %xmm0 ++ vmovq (%rsi, %OFFSET_REG64), %xmm1 ++ VPCMPEQ %xmm0, %xmmZERO, %xmm2 ++ VPCMPEQ %xmm1, %xmm0, %xmm1 ++ vpandn %xmm1, %xmm2, %xmm1 ++ vpmovmskb %ymm1, %ecx ++ incb %cl ++ jnz L(check_ret_vec_page_cross) ++ + # ifdef USE_AS_STRNCMP +- /* Return 0 if the current offset (%rdx) >= the maximum offset +- (%r11). */ +- cmpq %r11, %rdx +- jae L(zero) +-# endif +- +-L(cross_page_1_xmm): +-# ifndef USE_AS_WCSCMP +- /* Less than 16 bytes to check, try 8 byte vector. NB: No need +- for wcscmp nor wcsncmp since wide char is 4 bytes. */ +- cmpl $(PAGE_SIZE - 8), %eax +- jg L(cross_page_8bytes) +- vmovq (%rdi, %rdx), %xmm1 +- vmovq (%rsi, %rdx), %xmm0 +- VPCMPEQ %xmm0, %xmm1, %xmm0 +- VPMINU %xmm1, %xmm0, %xmm0 +- VPCMPEQ %xmm7, %xmm0, %xmm0 +- vpmovmskb %xmm0, %ecx +- /* Only last 8 bits are valid. */ +- andl $0xff, %ecx +- testl %ecx, %ecx +- jne L(last_vector) ++ addl $8, %OFFSET_REG ++ subq %OFFSET_REG64, %rdx ++ jbe L(ret_zero_page_cross_slow_case0) ++ subq $-(VEC_SIZE * 4), %rdx + +- addl $8, %edx +- addl $8, %eax ++ leaq -(VEC_SIZE * 4)(%rdi, %OFFSET_REG64), %rdi ++ leaq -(VEC_SIZE * 4)(%rsi, %OFFSET_REG64), %rsi ++# else ++ leaq (8 - VEC_SIZE * 4)(%rdi, %OFFSET_REG64), %rdi ++ leaq (8 - VEC_SIZE * 4)(%rsi, %OFFSET_REG64), %rsi ++# endif ++ jmp L(prepare_loop_aligned) ++ ++ ++ .p2align 4,, 10 ++L(less_8_till_page): ++# ifdef USE_AS_WCSCMP ++ /* If using wchar then this is the only check before we reach ++ the page boundary. */ ++ movl (%rdi), %eax ++ movl (%rsi), %ecx ++ cmpl %ecx, %eax ++ jnz L(ret_less_8_wcs) + # ifdef USE_AS_STRNCMP +- /* Return 0 if the current offset (%rdx) >= the maximum offset +- (%r11). */ +- cmpq %r11, %rdx +- jae L(zero) ++ addq %rdi, %rdx ++ /* We already checked for len <= 1 so cannot hit that case here. ++ */ + # endif ++ testl %eax, %eax ++ jnz L(prepare_loop_no_len) ++ ret + +-L(cross_page_8bytes): +- /* Less than 8 bytes to check, try 4 byte vector. */ +- cmpl $(PAGE_SIZE - 4), %eax +- jg L(cross_page_4bytes) +- vmovd (%rdi, %rdx), %xmm1 +- vmovd (%rsi, %rdx), %xmm0 +- VPCMPEQ %xmm0, %xmm1, %xmm0 +- VPMINU %xmm1, %xmm0, %xmm0 +- VPCMPEQ %xmm7, %xmm0, %xmm0 +- vpmovmskb %xmm0, %ecx +- /* Only last 4 bits are valid. */ +- andl $0xf, %ecx +- testl %ecx, %ecx +- jne L(last_vector) ++ .p2align 4,, 8 ++L(ret_less_8_wcs): ++ setl %OFFSET_REG8 ++ negl %OFFSET_REG ++ movl %OFFSET_REG, %eax ++ xorl %r8d, %eax ++ ret ++ ++# else ++ ++ /* Find largest load size we can use. */ ++ cmpl $28, %eax ++ ja L(less_4_till_page) ++ ++ vmovd (%rdi), %xmm0 ++ vmovd (%rsi), %xmm1 ++ VPCMPEQ %xmm0, %xmmZERO, %xmm2 ++ VPCMPEQ %xmm1, %xmm0, %xmm1 ++ vpandn %xmm1, %xmm2, %xmm1 ++ vpmovmskb %ymm1, %ecx ++ subl $0xf, %ecx ++ jnz L(check_ret_vec_page_cross) + +- addl $4, %edx + # ifdef USE_AS_STRNCMP +- /* Return 0 if the current offset (%rdx) >= the maximum offset +- (%r11). */ +- cmpq %r11, %rdx +- jae L(zero) ++ cmpq $4, %rdx ++ jbe L(ret_zero_page_cross_slow_case1) + # endif ++ movl $28, %OFFSET_REG ++ /* Explicit check for 16 byte alignment. */ ++ subl %eax, %OFFSET_REG + +-L(cross_page_4bytes): +-# endif +- /* Less than 4 bytes to check, try one byte/dword at a time. */ +-# ifdef USE_AS_STRNCMP +- cmpq %r11, %rdx +- jae L(zero) +-# endif +-# ifdef USE_AS_WCSCMP +- movl (%rdi, %rdx), %eax +- movl (%rsi, %rdx), %ecx +-# else +- movzbl (%rdi, %rdx), %eax +- movzbl (%rsi, %rdx), %ecx +-# endif +- testl %eax, %eax +- jne L(cross_page_loop) ++ ++ ++ vmovd (%rdi, %OFFSET_REG64), %xmm0 ++ vmovd (%rsi, %OFFSET_REG64), %xmm1 ++ VPCMPEQ %xmm0, %xmmZERO, %xmm2 ++ VPCMPEQ %xmm1, %xmm0, %xmm1 ++ vpandn %xmm1, %xmm2, %xmm1 ++ vpmovmskb %ymm1, %ecx ++ subl $0xf, %ecx ++ jnz L(check_ret_vec_page_cross) ++ ++# ifdef USE_AS_STRNCMP ++ addl $4, %OFFSET_REG ++ subq %OFFSET_REG64, %rdx ++ jbe L(ret_zero_page_cross_slow_case1) ++ subq $-(VEC_SIZE * 4), %rdx ++ ++ leaq -(VEC_SIZE * 4)(%rdi, %OFFSET_REG64), %rdi ++ leaq -(VEC_SIZE * 4)(%rsi, %OFFSET_REG64), %rsi ++# else ++ leaq (4 - VEC_SIZE * 4)(%rdi, %OFFSET_REG64), %rdi ++ leaq (4 - VEC_SIZE * 4)(%rsi, %OFFSET_REG64), %rsi ++# endif ++ jmp L(prepare_loop_aligned) ++ ++# ifdef USE_AS_STRNCMP ++ .p2align 4,, 2 ++L(ret_zero_page_cross_slow_case1): ++ xorl %eax, %eax ++ ret ++# endif ++ ++ .p2align 4,, 10 ++L(less_4_till_page): ++ subq %rdi, %rsi ++ /* Extremely slow byte comparison loop. */ ++L(less_4_loop): ++ movzbl (%rdi), %eax ++ movzbl (%rsi, %rdi), %ecx + subl %ecx, %eax +- VZEROUPPER_RETURN +-END (STRCMP) ++ jnz L(ret_less_4_loop) ++ testl %ecx, %ecx ++ jz L(ret_zero_4_loop) ++# ifdef USE_AS_STRNCMP ++ decq %rdx ++ jz L(ret_zero_4_loop) ++# endif ++ incq %rdi ++ /* end condition is reach page boundary (rdi is aligned). */ ++ testl $31, %edi ++ jnz L(less_4_loop) ++ leaq -(VEC_SIZE * 4)(%rdi, %rsi), %rsi ++ addq $-(VEC_SIZE * 4), %rdi ++# ifdef USE_AS_STRNCMP ++ subq $-(VEC_SIZE * 4), %rdx ++# endif ++ jmp L(prepare_loop_aligned) ++ ++L(ret_zero_4_loop): ++ xorl %eax, %eax ++ ret ++L(ret_less_4_loop): ++ xorl %r8d, %eax ++ subl %r8d, %eax ++ ret ++# endif ++END(STRCMP) + #endif +-- +GitLab + diff --git a/SOURCES/glibc-RHEL-15696-75.patch b/SOURCES/glibc-RHEL-15696-75.patch new file mode 100644 index 0000000..4bd0cd4 --- /dev/null +++ b/SOURCES/glibc-RHEL-15696-75.patch @@ -0,0 +1,1992 @@ +From 8418eb3ff4b781d31c4ed5dc6c0bd7356bc45db9 Mon Sep 17 00:00:00 2001 +From: Noah Goldstein +Date: Mon, 10 Jan 2022 15:35:39 -0600 +Subject: [PATCH] x86: Optimize strcmp-evex.S +Content-type: text/plain; charset=UTF-8 + +Optimization are primarily to the loop logic and how the page cross +logic interacts with the loop. + +The page cross logic is at times more expensive for short strings near +the end of a page but not crossing the page. This is done to retest +the page cross conditions with a non-faulty check and to improve the +logic for entering the loop afterwards. This is only particular cases, +however, and is general made up for by more than 10x improvements on +the transition from the page cross -> loop case. + +The non-page cross cases as well are nearly universally improved. + +test-strcmp, test-strncmp, test-wcscmp, and test-wcsncmp all pass. + +Signed-off-by: Noah Goldstein +--- + sysdeps/x86_64/multiarch/strcmp-evex.S | 1712 +++++++++++++----------- + 1 file changed, 919 insertions(+), 793 deletions(-) + +diff --git a/sysdeps/x86_64/multiarch/strcmp-evex.S b/sysdeps/x86_64/multiarch/strcmp-evex.S +index 6f5c4bf9..99d8409a 100644 +--- a/sysdeps/x86_64/multiarch/strcmp-evex.S ++++ b/sysdeps/x86_64/multiarch/strcmp-evex.S +@@ -26,54 +26,69 @@ + + # define PAGE_SIZE 4096 + +-/* VEC_SIZE = Number of bytes in a ymm register */ ++ /* VEC_SIZE = Number of bytes in a ymm register. */ + # define VEC_SIZE 32 ++# define CHAR_PER_VEC (VEC_SIZE / SIZE_OF_CHAR) + +-/* Shift for dividing by (VEC_SIZE * 4). */ +-# define DIVIDE_BY_VEC_4_SHIFT 7 +-# if (VEC_SIZE * 4) != (1 << DIVIDE_BY_VEC_4_SHIFT) +-# error (VEC_SIZE * 4) != (1 << DIVIDE_BY_VEC_4_SHIFT) +-# endif +- +-# define VMOVU vmovdqu64 +-# define VMOVA vmovdqa64 ++# define VMOVU vmovdqu64 ++# define VMOVA vmovdqa64 + + # ifdef USE_AS_WCSCMP +-/* Compare packed dwords. */ +-# define VPCMP vpcmpd ++# define TESTEQ subl $0xff, ++ /* Compare packed dwords. */ ++# define VPCMP vpcmpd + # define VPMINU vpminud + # define VPTESTM vptestmd +-# define SHIFT_REG32 r8d +-# define SHIFT_REG64 r8 +-/* 1 dword char == 4 bytes. */ ++ /* 1 dword char == 4 bytes. */ + # define SIZE_OF_CHAR 4 + # else +-/* Compare packed bytes. */ +-# define VPCMP vpcmpb ++# define TESTEQ incl ++ /* Compare packed bytes. */ ++# define VPCMP vpcmpb + # define VPMINU vpminub + # define VPTESTM vptestmb +-# define SHIFT_REG32 ecx +-# define SHIFT_REG64 rcx +-/* 1 byte char == 1 byte. */ ++ /* 1 byte char == 1 byte. */ + # define SIZE_OF_CHAR 1 + # endif + ++# ifdef USE_AS_STRNCMP ++# define LOOP_REG r9d ++# define LOOP_REG64 r9 ++ ++# define OFFSET_REG8 r9b ++# define OFFSET_REG r9d ++# define OFFSET_REG64 r9 ++# else ++# define LOOP_REG edx ++# define LOOP_REG64 rdx ++ ++# define OFFSET_REG8 dl ++# define OFFSET_REG edx ++# define OFFSET_REG64 rdx ++# endif ++ ++# if defined USE_AS_STRNCMP || defined USE_AS_WCSCMP ++# define VEC_OFFSET 0 ++# else ++# define VEC_OFFSET (-VEC_SIZE) ++# endif ++ + # define XMMZERO xmm16 +-# define XMM0 xmm17 +-# define XMM1 xmm18 ++# define XMM0 xmm17 ++# define XMM1 xmm18 + + # define YMMZERO ymm16 +-# define YMM0 ymm17 +-# define YMM1 ymm18 +-# define YMM2 ymm19 +-# define YMM3 ymm20 +-# define YMM4 ymm21 +-# define YMM5 ymm22 +-# define YMM6 ymm23 +-# define YMM7 ymm24 +-# define YMM8 ymm25 +-# define YMM9 ymm26 +-# define YMM10 ymm27 ++# define YMM0 ymm17 ++# define YMM1 ymm18 ++# define YMM2 ymm19 ++# define YMM3 ymm20 ++# define YMM4 ymm21 ++# define YMM5 ymm22 ++# define YMM6 ymm23 ++# define YMM7 ymm24 ++# define YMM8 ymm25 ++# define YMM9 ymm26 ++# define YMM10 ymm27 + + /* Warning! + wcscmp/wcsncmp have to use SIGNED comparison for elements. +@@ -96,985 +111,1096 @@ + the maximum offset is reached before a difference is found, zero is + returned. */ + +- .section .text.evex,"ax",@progbits +-ENTRY (STRCMP) ++ .section .text.evex, "ax", @progbits ++ENTRY(STRCMP) + # ifdef USE_AS_STRNCMP +- /* Check for simple cases (0 or 1) in offset. */ +- cmp $1, %RDX_LP +- je L(char0) +- jb L(zero) +-# ifdef USE_AS_WCSCMP +-# ifndef __ILP32__ +- movq %rdx, %rcx +- /* Check if length could overflow when multiplied by +- sizeof(wchar_t). Checking top 8 bits will cover all potential +- overflow cases as well as redirect cases where its impossible to +- length to bound a valid memory region. In these cases just use +- 'wcscmp'. */ +- shrq $56, %rcx +- jnz __wcscmp_evex +-# endif +- /* Convert units: from wide to byte char. */ +- shl $2, %RDX_LP ++# ifdef __ILP32__ ++ /* Clear the upper 32 bits. */ ++ movl %edx, %rdx + # endif +- /* Register %r11 tracks the maximum offset. */ +- mov %RDX_LP, %R11_LP ++ cmp $1, %RDX_LP ++ /* Signed comparison intentional. We use this branch to also ++ test cases where length >= 2^63. These very large sizes can be ++ handled with strcmp as there is no way for that length to ++ actually bound the buffer. */ ++ jle L(one_or_less) + # endif + movl %edi, %eax +- xorl %edx, %edx +- /* Make %XMMZERO (%YMMZERO) all zeros in this function. */ +- vpxorq %XMMZERO, %XMMZERO, %XMMZERO + orl %esi, %eax +- andl $(PAGE_SIZE - 1), %eax +- cmpl $(PAGE_SIZE - (VEC_SIZE * 4)), %eax +- jg L(cross_page) +- /* Start comparing 4 vectors. */ ++ /* Shift out the bits irrelivant to page boundary ([63:12]). */ ++ sall $20, %eax ++ /* Check if s1 or s2 may cross a page in next 4x VEC loads. */ ++ cmpl $((PAGE_SIZE -(VEC_SIZE * 4)) << 20), %eax ++ ja L(page_cross) ++ ++L(no_page_cross): ++ /* Safe to compare 4x vectors. */ + VMOVU (%rdi), %YMM0 +- +- /* Each bit set in K2 represents a non-null CHAR in YMM0. */ + VPTESTM %YMM0, %YMM0, %k2 +- + /* Each bit cleared in K1 represents a mismatch or a null CHAR + in YMM0 and 32 bytes at (%rsi). */ + VPCMP $0, (%rsi), %YMM0, %k1{%k2} +- + kmovd %k1, %ecx +-# ifdef USE_AS_WCSCMP +- subl $0xff, %ecx +-# else +- incl %ecx +-# endif +- je L(next_3_vectors) +- tzcntl %ecx, %edx +-# ifdef USE_AS_WCSCMP +- /* NB: Multiply wchar_t count by 4 to get the number of bytes. */ +- sall $2, %edx +-# endif + # ifdef USE_AS_STRNCMP +- /* Return 0 if the mismatched index (%rdx) is after the maximum +- offset (%r11). */ +- cmpq %r11, %rdx +- jae L(zero) ++ cmpq $CHAR_PER_VEC, %rdx ++ jbe L(vec_0_test_len) + # endif ++ ++ /* TESTEQ is `incl` for strcmp/strncmp and `subl $0xff` for ++ wcscmp/wcsncmp. */ ++ ++ /* All 1s represents all equals. TESTEQ will overflow to zero in ++ all equals case. Otherwise 1s will carry until position of first ++ mismatch. */ ++ TESTEQ %ecx ++ jz L(more_3x_vec) ++ ++ .p2align 4,, 4 ++L(return_vec_0): ++ tzcntl %ecx, %ecx + # ifdef USE_AS_WCSCMP ++ movl (%rdi, %rcx, SIZE_OF_CHAR), %edx + xorl %eax, %eax +- movl (%rdi, %rdx), %ecx +- cmpl (%rsi, %rdx), %ecx +- je L(return) +-L(wcscmp_return): ++ cmpl (%rsi, %rcx, SIZE_OF_CHAR), %edx ++ je L(ret0) + setl %al + negl %eax + orl $1, %eax +-L(return): + # else +- movzbl (%rdi, %rdx), %eax +- movzbl (%rsi, %rdx), %edx +- subl %edx, %eax ++ movzbl (%rdi, %rcx), %eax ++ movzbl (%rsi, %rcx), %ecx ++ subl %ecx, %eax + # endif ++L(ret0): + ret + +-L(return_vec_size): +- tzcntl %ecx, %edx +-# ifdef USE_AS_WCSCMP +- /* NB: Multiply wchar_t count by 4 to get the number of bytes. */ +- sall $2, %edx +-# endif + # ifdef USE_AS_STRNCMP +- /* Return 0 if the mismatched index (%rdx + VEC_SIZE) is after +- the maximum offset (%r11). */ +- addq $VEC_SIZE, %rdx +- cmpq %r11, %rdx +- jae L(zero) +-# ifdef USE_AS_WCSCMP ++ .p2align 4,, 4 ++L(vec_0_test_len): ++ notl %ecx ++ bzhil %edx, %ecx, %eax ++ jnz L(return_vec_0) ++ /* Align if will cross fetch block. */ ++ .p2align 4,, 2 ++L(ret_zero): + xorl %eax, %eax +- movl (%rdi, %rdx), %ecx +- cmpl (%rsi, %rdx), %ecx +- jne L(wcscmp_return) +-# else +- movzbl (%rdi, %rdx), %eax +- movzbl (%rsi, %rdx), %edx +- subl %edx, %eax +-# endif +-# else ++ ret ++ ++ .p2align 4,, 5 ++L(one_or_less): ++ jb L(ret_zero) + # ifdef USE_AS_WCSCMP ++ /* 'nbe' covers the case where length is negative (large ++ unsigned). */ ++ jnbe __wcscmp_evex ++ movl (%rdi), %edx + xorl %eax, %eax +- movl VEC_SIZE(%rdi, %rdx), %ecx +- cmpl VEC_SIZE(%rsi, %rdx), %ecx +- jne L(wcscmp_return) ++ cmpl (%rsi), %edx ++ je L(ret1) ++ setl %al ++ negl %eax ++ orl $1, %eax + # else +- movzbl VEC_SIZE(%rdi, %rdx), %eax +- movzbl VEC_SIZE(%rsi, %rdx), %edx +- subl %edx, %eax ++ /* 'nbe' covers the case where length is negative (large ++ unsigned). */ ++ jnbe __strcmp_evex ++ movzbl (%rdi), %eax ++ movzbl (%rsi), %ecx ++ subl %ecx, %eax + # endif +-# endif ++L(ret1): + ret ++# endif + +-L(return_2_vec_size): +- tzcntl %ecx, %edx ++ .p2align 4,, 10 ++L(return_vec_1): ++ tzcntl %ecx, %ecx ++# ifdef USE_AS_STRNCMP ++ /* rdx must be > CHAR_PER_VEC so its safe to subtract without ++ worrying about underflow. */ ++ addq $-CHAR_PER_VEC, %rdx ++ cmpq %rcx, %rdx ++ jbe L(ret_zero) ++# endif + # ifdef USE_AS_WCSCMP +- /* NB: Multiply wchar_t count by 4 to get the number of bytes. */ +- sall $2, %edx ++ movl VEC_SIZE(%rdi, %rcx, SIZE_OF_CHAR), %edx ++ xorl %eax, %eax ++ cmpl VEC_SIZE(%rsi, %rcx, SIZE_OF_CHAR), %edx ++ je L(ret2) ++ setl %al ++ negl %eax ++ orl $1, %eax ++# else ++ movzbl VEC_SIZE(%rdi, %rcx), %eax ++ movzbl VEC_SIZE(%rsi, %rcx), %ecx ++ subl %ecx, %eax + # endif ++L(ret2): ++ ret ++ ++ .p2align 4,, 10 + # ifdef USE_AS_STRNCMP +- /* Return 0 if the mismatched index (%rdx + 2 * VEC_SIZE) is +- after the maximum offset (%r11). */ +- addq $(VEC_SIZE * 2), %rdx +- cmpq %r11, %rdx +- jae L(zero) +-# ifdef USE_AS_WCSCMP +- xorl %eax, %eax +- movl (%rdi, %rdx), %ecx +- cmpl (%rsi, %rdx), %ecx +- jne L(wcscmp_return) ++L(return_vec_3): ++# if CHAR_PER_VEC <= 16 ++ sall $CHAR_PER_VEC, %ecx + # else +- movzbl (%rdi, %rdx), %eax +- movzbl (%rsi, %rdx), %edx +- subl %edx, %eax ++ salq $CHAR_PER_VEC, %rcx + # endif ++# endif ++L(return_vec_2): ++# if (CHAR_PER_VEC <= 16) || !(defined USE_AS_STRNCMP) ++ tzcntl %ecx, %ecx + # else +-# ifdef USE_AS_WCSCMP +- xorl %eax, %eax +- movl (VEC_SIZE * 2)(%rdi, %rdx), %ecx +- cmpl (VEC_SIZE * 2)(%rsi, %rdx), %ecx +- jne L(wcscmp_return) +-# else +- movzbl (VEC_SIZE * 2)(%rdi, %rdx), %eax +- movzbl (VEC_SIZE * 2)(%rsi, %rdx), %edx +- subl %edx, %eax +-# endif ++ tzcntq %rcx, %rcx + # endif +- ret + +-L(return_3_vec_size): +- tzcntl %ecx, %edx +-# ifdef USE_AS_WCSCMP +- /* NB: Multiply wchar_t count by 4 to get the number of bytes. */ +- sall $2, %edx +-# endif + # ifdef USE_AS_STRNCMP +- /* Return 0 if the mismatched index (%rdx + 3 * VEC_SIZE) is +- after the maximum offset (%r11). */ +- addq $(VEC_SIZE * 3), %rdx +- cmpq %r11, %rdx +- jae L(zero) +-# ifdef USE_AS_WCSCMP ++ cmpq %rcx, %rdx ++ jbe L(ret_zero) ++# endif ++ ++# ifdef USE_AS_WCSCMP ++ movl (VEC_SIZE * 2)(%rdi, %rcx, SIZE_OF_CHAR), %edx + xorl %eax, %eax +- movl (%rdi, %rdx), %ecx +- cmpl (%rsi, %rdx), %ecx +- jne L(wcscmp_return) +-# else +- movzbl (%rdi, %rdx), %eax +- movzbl (%rsi, %rdx), %edx +- subl %edx, %eax +-# endif ++ cmpl (VEC_SIZE * 2)(%rsi, %rcx, SIZE_OF_CHAR), %edx ++ je L(ret3) ++ setl %al ++ negl %eax ++ orl $1, %eax + # else ++ movzbl (VEC_SIZE * 2)(%rdi, %rcx), %eax ++ movzbl (VEC_SIZE * 2)(%rsi, %rcx), %ecx ++ subl %ecx, %eax ++# endif ++L(ret3): ++ ret ++ ++# ifndef USE_AS_STRNCMP ++ .p2align 4,, 10 ++L(return_vec_3): ++ tzcntl %ecx, %ecx + # ifdef USE_AS_WCSCMP ++ movl (VEC_SIZE * 3)(%rdi, %rcx, SIZE_OF_CHAR), %edx + xorl %eax, %eax +- movl (VEC_SIZE * 3)(%rdi, %rdx), %ecx +- cmpl (VEC_SIZE * 3)(%rsi, %rdx), %ecx +- jne L(wcscmp_return) ++ cmpl (VEC_SIZE * 3)(%rsi, %rcx, SIZE_OF_CHAR), %edx ++ je L(ret4) ++ setl %al ++ negl %eax ++ orl $1, %eax + # else +- movzbl (VEC_SIZE * 3)(%rdi, %rdx), %eax +- movzbl (VEC_SIZE * 3)(%rsi, %rdx), %edx +- subl %edx, %eax ++ movzbl (VEC_SIZE * 3)(%rdi, %rcx), %eax ++ movzbl (VEC_SIZE * 3)(%rsi, %rcx), %ecx ++ subl %ecx, %eax + # endif +-# endif ++L(ret4): + ret ++# endif + +- .p2align 4 +-L(next_3_vectors): +- VMOVU VEC_SIZE(%rdi), %YMM0 +- /* Each bit set in K2 represents a non-null CHAR in YMM0. */ ++ /* 32 byte align here ensures the main loop is ideally aligned ++ for DSB. */ ++ .p2align 5 ++L(more_3x_vec): ++ /* Safe to compare 4x vectors. */ ++ VMOVU (VEC_SIZE)(%rdi), %YMM0 + VPTESTM %YMM0, %YMM0, %k2 +- /* Each bit cleared in K1 represents a mismatch or a null CHAR +- in YMM0 and 32 bytes at VEC_SIZE(%rsi). */ +- VPCMP $0, VEC_SIZE(%rsi), %YMM0, %k1{%k2} ++ VPCMP $0, (VEC_SIZE)(%rsi), %YMM0, %k1{%k2} + kmovd %k1, %ecx +-# ifdef USE_AS_WCSCMP +- subl $0xff, %ecx +-# else +- incl %ecx ++ TESTEQ %ecx ++ jnz L(return_vec_1) ++ ++# ifdef USE_AS_STRNCMP ++ subq $(CHAR_PER_VEC * 2), %rdx ++ jbe L(ret_zero) + # endif +- jne L(return_vec_size) + + VMOVU (VEC_SIZE * 2)(%rdi), %YMM0 +- /* Each bit set in K2 represents a non-null CHAR in YMM0. */ + VPTESTM %YMM0, %YMM0, %k2 +- /* Each bit cleared in K1 represents a mismatch or a null CHAR +- in YMM0 and 32 bytes at (VEC_SIZE * 2)(%rsi). */ + VPCMP $0, (VEC_SIZE * 2)(%rsi), %YMM0, %k1{%k2} + kmovd %k1, %ecx +-# ifdef USE_AS_WCSCMP +- subl $0xff, %ecx +-# else +- incl %ecx +-# endif +- jne L(return_2_vec_size) ++ TESTEQ %ecx ++ jnz L(return_vec_2) + + VMOVU (VEC_SIZE * 3)(%rdi), %YMM0 +- /* Each bit set in K2 represents a non-null CHAR in YMM0. */ + VPTESTM %YMM0, %YMM0, %k2 +- /* Each bit cleared in K1 represents a mismatch or a null CHAR +- in YMM0 and 32 bytes at (VEC_SIZE * 2)(%rsi). */ + VPCMP $0, (VEC_SIZE * 3)(%rsi), %YMM0, %k1{%k2} + kmovd %k1, %ecx ++ TESTEQ %ecx ++ jnz L(return_vec_3) ++ ++# ifdef USE_AS_STRNCMP ++ cmpq $(CHAR_PER_VEC * 2), %rdx ++ jbe L(ret_zero) ++# endif ++ ++ + # ifdef USE_AS_WCSCMP +- subl $0xff, %ecx ++ /* any non-zero positive value that doesn't inference with 0x1. ++ */ ++ movl $2, %r8d ++ + # else +- incl %ecx ++ xorl %r8d, %r8d + # endif +- jne L(return_3_vec_size) +-L(main_loop_header): +- leaq (VEC_SIZE * 4)(%rdi), %rdx +- movl $PAGE_SIZE, %ecx +- /* Align load via RAX. */ +- andq $-(VEC_SIZE * 4), %rdx +- subq %rdi, %rdx +- leaq (%rdi, %rdx), %rax ++ ++ /* The prepare labels are various entry points from the page ++ cross logic. */ ++L(prepare_loop): ++ + # ifdef USE_AS_STRNCMP +- /* Starting from this point, the maximum offset, or simply the +- 'offset', DECREASES by the same amount when base pointers are +- moved forward. Return 0 when: +- 1) On match: offset <= the matched vector index. +- 2) On mistmach, offset is before the mistmatched index. +- */ +- subq %rdx, %r11 +- jbe L(zero) ++# ifdef USE_AS_WCSCMP ++L(prepare_loop_no_len): ++ movl %edi, %ecx ++ andl $(VEC_SIZE * 4 - 1), %ecx ++ shrl $2, %ecx ++ leaq (CHAR_PER_VEC * 2)(%rdx, %rcx), %rdx ++# else ++ /* Store N + (VEC_SIZE * 4) and place check at the begining of ++ the loop. */ ++ leaq (VEC_SIZE * 2)(%rdi, %rdx), %rdx ++L(prepare_loop_no_len): ++# endif ++# else ++L(prepare_loop_no_len): + # endif +- addq %rsi, %rdx +- movq %rdx, %rsi +- andl $(PAGE_SIZE - 1), %esi +- /* Number of bytes before page crossing. */ +- subq %rsi, %rcx +- /* Number of VEC_SIZE * 4 blocks before page crossing. */ +- shrq $DIVIDE_BY_VEC_4_SHIFT, %rcx +- /* ESI: Number of VEC_SIZE * 4 blocks before page crossing. */ +- movl %ecx, %esi +- jmp L(loop_start) + ++ /* Align s1 and adjust s2 accordingly. */ ++ subq %rdi, %rsi ++ andq $-(VEC_SIZE * 4), %rdi ++L(prepare_loop_readj): ++ addq %rdi, %rsi ++# if (defined USE_AS_STRNCMP) && !(defined USE_AS_WCSCMP) ++ subq %rdi, %rdx ++# endif ++ ++L(prepare_loop_aligned): ++ /* eax stores distance from rsi to next page cross. These cases ++ need to be handled specially as the 4x loop could potentially ++ read memory past the length of s1 or s2 and across a page ++ boundary. */ ++ movl $-(VEC_SIZE * 4), %eax ++ subl %esi, %eax ++ andl $(PAGE_SIZE - 1), %eax ++ ++ vpxorq %YMMZERO, %YMMZERO, %YMMZERO ++ ++ /* Loop 4x comparisons at a time. */ + .p2align 4 + L(loop): ++ ++ /* End condition for strncmp. */ + # ifdef USE_AS_STRNCMP +- /* Base pointers are moved forward by 4 * VEC_SIZE. Decrease +- the maximum offset (%r11) by the same amount. */ +- subq $(VEC_SIZE * 4), %r11 +- jbe L(zero) ++ subq $(CHAR_PER_VEC * 4), %rdx ++ jbe L(ret_zero) + # endif +- addq $(VEC_SIZE * 4), %rax +- addq $(VEC_SIZE * 4), %rdx +-L(loop_start): +- testl %esi, %esi +- leal -1(%esi), %esi +- je L(loop_cross_page) +-L(back_to_loop): +- /* Main loop, comparing 4 vectors are a time. */ +- VMOVA (%rax), %YMM0 +- VMOVA VEC_SIZE(%rax), %YMM2 +- VMOVA (VEC_SIZE * 2)(%rax), %YMM4 +- VMOVA (VEC_SIZE * 3)(%rax), %YMM6 ++ ++ subq $-(VEC_SIZE * 4), %rdi ++ subq $-(VEC_SIZE * 4), %rsi ++ ++ /* Check if rsi loads will cross a page boundary. */ ++ addl $-(VEC_SIZE * 4), %eax ++ jnb L(page_cross_during_loop) ++ ++ /* Loop entry after handling page cross during loop. */ ++L(loop_skip_page_cross_check): ++ VMOVA (VEC_SIZE * 0)(%rdi), %YMM0 ++ VMOVA (VEC_SIZE * 1)(%rdi), %YMM2 ++ VMOVA (VEC_SIZE * 2)(%rdi), %YMM4 ++ VMOVA (VEC_SIZE * 3)(%rdi), %YMM6 + + VPMINU %YMM0, %YMM2, %YMM8 + VPMINU %YMM4, %YMM6, %YMM9 + +- /* A zero CHAR in YMM8 means that there is a null CHAR. */ +- VPMINU %YMM8, %YMM9, %YMM8 ++ /* A zero CHAR in YMM9 means that there is a null CHAR. */ ++ VPMINU %YMM8, %YMM9, %YMM9 + + /* Each bit set in K1 represents a non-null CHAR in YMM8. */ +- VPTESTM %YMM8, %YMM8, %k1 ++ VPTESTM %YMM9, %YMM9, %k1 + +- /* (YMM ^ YMM): A non-zero CHAR represents a mismatch. */ +- vpxorq (%rdx), %YMM0, %YMM1 +- vpxorq VEC_SIZE(%rdx), %YMM2, %YMM3 +- vpxorq (VEC_SIZE * 2)(%rdx), %YMM4, %YMM5 +- vpxorq (VEC_SIZE * 3)(%rdx), %YMM6, %YMM7 ++ vpxorq (VEC_SIZE * 0)(%rsi), %YMM0, %YMM1 ++ vpxorq (VEC_SIZE * 1)(%rsi), %YMM2, %YMM3 ++ vpxorq (VEC_SIZE * 2)(%rsi), %YMM4, %YMM5 ++ /* Ternary logic to xor (VEC_SIZE * 3)(%rsi) with YMM6 while ++ oring with YMM1. Result is stored in YMM6. */ ++ vpternlogd $0xde, (VEC_SIZE * 3)(%rsi), %YMM1, %YMM6 + +- vporq %YMM1, %YMM3, %YMM9 +- vporq %YMM5, %YMM7, %YMM10 ++ /* Or together YMM3, YMM5, and YMM6. */ ++ vpternlogd $0xfe, %YMM3, %YMM5, %YMM6 + +- /* A non-zero CHAR in YMM9 represents a mismatch. */ +- vporq %YMM9, %YMM10, %YMM9 + +- /* Each bit cleared in K0 represents a mismatch or a null CHAR. */ +- VPCMP $0, %YMMZERO, %YMM9, %k0{%k1} +- kmovd %k0, %ecx +-# ifdef USE_AS_WCSCMP +- subl $0xff, %ecx +-# else +- incl %ecx +-# endif +- je L(loop) ++ /* A non-zero CHAR in YMM6 represents a mismatch. */ ++ VPCMP $0, %YMMZERO, %YMM6, %k0{%k1} ++ kmovd %k0, %LOOP_REG + +- /* Each bit set in K1 represents a non-null CHAR in YMM0. */ ++ TESTEQ %LOOP_REG ++ jz L(loop) ++ ++ ++ /* Find which VEC has the mismatch of end of string. */ + VPTESTM %YMM0, %YMM0, %k1 +- /* Each bit cleared in K0 represents a mismatch or a null CHAR +- in YMM0 and (%rdx). */ + VPCMP $0, %YMMZERO, %YMM1, %k0{%k1} + kmovd %k0, %ecx +-# ifdef USE_AS_WCSCMP +- subl $0xff, %ecx +-# else +- incl %ecx +-# endif +- je L(test_vec) +- tzcntl %ecx, %ecx +-# ifdef USE_AS_WCSCMP +- /* NB: Multiply wchar_t count by 4 to get the number of bytes. */ +- sall $2, %ecx +-# endif +-# ifdef USE_AS_STRNCMP +- cmpq %rcx, %r11 +- jbe L(zero) +-# ifdef USE_AS_WCSCMP +- movq %rax, %rsi +- xorl %eax, %eax +- movl (%rsi, %rcx), %edi +- cmpl (%rdx, %rcx), %edi +- jne L(wcscmp_return) +-# else +- movzbl (%rax, %rcx), %eax +- movzbl (%rdx, %rcx), %edx +- subl %edx, %eax +-# endif +-# else +-# ifdef USE_AS_WCSCMP +- movq %rax, %rsi +- xorl %eax, %eax +- movl (%rsi, %rcx), %edi +- cmpl (%rdx, %rcx), %edi +- jne L(wcscmp_return) +-# else +- movzbl (%rax, %rcx), %eax +- movzbl (%rdx, %rcx), %edx +- subl %edx, %eax +-# endif +-# endif +- ret ++ TESTEQ %ecx ++ jnz L(return_vec_0_end) + +- .p2align 4 +-L(test_vec): +-# ifdef USE_AS_STRNCMP +- /* The first vector matched. Return 0 if the maximum offset +- (%r11) <= VEC_SIZE. */ +- cmpq $VEC_SIZE, %r11 +- jbe L(zero) +-# endif +- /* Each bit set in K1 represents a non-null CHAR in YMM2. */ + VPTESTM %YMM2, %YMM2, %k1 +- /* Each bit cleared in K0 represents a mismatch or a null CHAR +- in YMM2 and VEC_SIZE(%rdx). */ + VPCMP $0, %YMMZERO, %YMM3, %k0{%k1} + kmovd %k0, %ecx +-# ifdef USE_AS_WCSCMP +- subl $0xff, %ecx +-# else +- incl %ecx +-# endif +- je L(test_2_vec) +- tzcntl %ecx, %edi +-# ifdef USE_AS_WCSCMP +- /* NB: Multiply wchar_t count by 4 to get the number of bytes. */ +- sall $2, %edi +-# endif +-# ifdef USE_AS_STRNCMP +- addq $VEC_SIZE, %rdi +- cmpq %rdi, %r11 +- jbe L(zero) +-# ifdef USE_AS_WCSCMP +- movq %rax, %rsi +- xorl %eax, %eax +- movl (%rsi, %rdi), %ecx +- cmpl (%rdx, %rdi), %ecx +- jne L(wcscmp_return) +-# else +- movzbl (%rax, %rdi), %eax +- movzbl (%rdx, %rdi), %edx +- subl %edx, %eax +-# endif +-# else +-# ifdef USE_AS_WCSCMP +- movq %rax, %rsi +- xorl %eax, %eax +- movl VEC_SIZE(%rsi, %rdi), %ecx +- cmpl VEC_SIZE(%rdx, %rdi), %ecx +- jne L(wcscmp_return) +-# else +- movzbl VEC_SIZE(%rax, %rdi), %eax +- movzbl VEC_SIZE(%rdx, %rdi), %edx +- subl %edx, %eax +-# endif +-# endif +- ret ++ TESTEQ %ecx ++ jnz L(return_vec_1_end) + +- .p2align 4 +-L(test_2_vec): ++ ++ /* Handle VEC 2 and 3 without branches. */ ++L(return_vec_2_3_end): + # ifdef USE_AS_STRNCMP +- /* The first 2 vectors matched. Return 0 if the maximum offset +- (%r11) <= 2 * VEC_SIZE. */ +- cmpq $(VEC_SIZE * 2), %r11 +- jbe L(zero) ++ subq $(CHAR_PER_VEC * 2), %rdx ++ jbe L(ret_zero_end) + # endif +- /* Each bit set in K1 represents a non-null CHAR in YMM4. */ ++ + VPTESTM %YMM4, %YMM4, %k1 +- /* Each bit cleared in K0 represents a mismatch or a null CHAR +- in YMM4 and (VEC_SIZE * 2)(%rdx). */ + VPCMP $0, %YMMZERO, %YMM5, %k0{%k1} + kmovd %k0, %ecx +-# ifdef USE_AS_WCSCMP +- subl $0xff, %ecx ++ TESTEQ %ecx ++# if CHAR_PER_VEC <= 16 ++ sall $CHAR_PER_VEC, %LOOP_REG ++ orl %ecx, %LOOP_REG + # else +- incl %ecx ++ salq $CHAR_PER_VEC, %LOOP_REG64 ++ orq %rcx, %LOOP_REG64 ++# endif ++L(return_vec_3_end): ++ /* LOOP_REG contains matches for null/mismatch from the loop. If ++ VEC 0,1,and 2 all have no null and no mismatches then mismatch ++ must entirely be from VEC 3 which is fully represented by ++ LOOP_REG. */ ++# if CHAR_PER_VEC <= 16 ++ tzcntl %LOOP_REG, %LOOP_REG ++# else ++ tzcntq %LOOP_REG64, %LOOP_REG64 ++# endif ++# ifdef USE_AS_STRNCMP ++ cmpq %LOOP_REG64, %rdx ++ jbe L(ret_zero_end) + # endif +- je L(test_3_vec) +- tzcntl %ecx, %edi ++ + # ifdef USE_AS_WCSCMP +- /* NB: Multiply wchar_t count by 4 to get the number of bytes. */ +- sall $2, %edi ++ movl (VEC_SIZE * 2)(%rdi, %LOOP_REG64, SIZE_OF_CHAR), %ecx ++ xorl %eax, %eax ++ cmpl (VEC_SIZE * 2)(%rsi, %LOOP_REG64, SIZE_OF_CHAR), %ecx ++ je L(ret5) ++ setl %al ++ negl %eax ++ xorl %r8d, %eax ++# else ++ movzbl (VEC_SIZE * 2)(%rdi, %LOOP_REG64), %eax ++ movzbl (VEC_SIZE * 2)(%rsi, %LOOP_REG64), %ecx ++ subl %ecx, %eax ++ xorl %r8d, %eax ++ subl %r8d, %eax + # endif ++L(ret5): ++ ret ++ + # ifdef USE_AS_STRNCMP +- addq $(VEC_SIZE * 2), %rdi +- cmpq %rdi, %r11 +- jbe L(zero) +-# ifdef USE_AS_WCSCMP +- movq %rax, %rsi ++ .p2align 4,, 2 ++L(ret_zero_end): + xorl %eax, %eax +- movl (%rsi, %rdi), %ecx +- cmpl (%rdx, %rdi), %ecx +- jne L(wcscmp_return) ++ ret ++# endif ++ ++ ++ /* The L(return_vec_N_end) differ from L(return_vec_N) in that ++ they use the value of `r8` to negate the return value. This is ++ because the page cross logic can swap `rdi` and `rsi`. */ ++ .p2align 4,, 10 ++# ifdef USE_AS_STRNCMP ++L(return_vec_1_end): ++# if CHAR_PER_VEC <= 16 ++ sall $CHAR_PER_VEC, %ecx + # else +- movzbl (%rax, %rdi), %eax +- movzbl (%rdx, %rdi), %edx +- subl %edx, %eax ++ salq $CHAR_PER_VEC, %rcx + # endif ++# endif ++L(return_vec_0_end): ++# if (CHAR_PER_VEC <= 16) || !(defined USE_AS_STRNCMP) ++ tzcntl %ecx, %ecx + # else +-# ifdef USE_AS_WCSCMP +- movq %rax, %rsi +- xorl %eax, %eax +- movl (VEC_SIZE * 2)(%rsi, %rdi), %ecx +- cmpl (VEC_SIZE * 2)(%rdx, %rdi), %ecx +- jne L(wcscmp_return) +-# else +- movzbl (VEC_SIZE * 2)(%rax, %rdi), %eax +- movzbl (VEC_SIZE * 2)(%rdx, %rdi), %edx +- subl %edx, %eax +-# endif ++ tzcntq %rcx, %rcx + # endif +- ret + +- .p2align 4 +-L(test_3_vec): + # ifdef USE_AS_STRNCMP +- /* The first 3 vectors matched. Return 0 if the maximum offset +- (%r11) <= 3 * VEC_SIZE. */ +- cmpq $(VEC_SIZE * 3), %r11 +- jbe L(zero) ++ cmpq %rcx, %rdx ++ jbe L(ret_zero_end) + # endif +- /* Each bit set in K1 represents a non-null CHAR in YMM6. */ +- VPTESTM %YMM6, %YMM6, %k1 +- /* Each bit cleared in K0 represents a mismatch or a null CHAR +- in YMM6 and (VEC_SIZE * 3)(%rdx). */ +- VPCMP $0, %YMMZERO, %YMM7, %k0{%k1} +- kmovd %k0, %ecx ++ + # ifdef USE_AS_WCSCMP +- subl $0xff, %ecx ++ movl (%rdi, %rcx, SIZE_OF_CHAR), %edx ++ xorl %eax, %eax ++ cmpl (%rsi, %rcx, SIZE_OF_CHAR), %edx ++ je L(ret6) ++ setl %al ++ negl %eax ++ /* This is the non-zero case for `eax` so just xorl with `r8d` ++ flip is `rdi` and `rsi` where swapped. */ ++ xorl %r8d, %eax + # else +- incl %ecx ++ movzbl (%rdi, %rcx), %eax ++ movzbl (%rsi, %rcx), %ecx ++ subl %ecx, %eax ++ /* Flip `eax` if `rdi` and `rsi` where swapped in page cross ++ logic. Subtract `r8d` after xor for zero case. */ ++ xorl %r8d, %eax ++ subl %r8d, %eax + # endif ++L(ret6): ++ ret ++ ++# ifndef USE_AS_STRNCMP ++ .p2align 4,, 10 ++L(return_vec_1_end): + tzcntl %ecx, %ecx +-# ifdef USE_AS_WCSCMP +- /* NB: Multiply wchar_t count by 4 to get the number of bytes. */ +- sall $2, %ecx +-# endif +-# ifdef USE_AS_STRNCMP +- addq $(VEC_SIZE * 3), %rcx +- cmpq %rcx, %r11 +- jbe L(zero) + # ifdef USE_AS_WCSCMP +- movq %rax, %rsi ++ movl VEC_SIZE(%rdi, %rcx, SIZE_OF_CHAR), %edx + xorl %eax, %eax +- movl (%rsi, %rcx), %esi +- cmpl (%rdx, %rcx), %esi +- jne L(wcscmp_return) +-# else +- movzbl (%rax, %rcx), %eax +- movzbl (%rdx, %rcx), %edx +- subl %edx, %eax +-# endif +-# else +-# ifdef USE_AS_WCSCMP +- movq %rax, %rsi +- xorl %eax, %eax +- movl (VEC_SIZE * 3)(%rsi, %rcx), %esi +- cmpl (VEC_SIZE * 3)(%rdx, %rcx), %esi +- jne L(wcscmp_return) ++ cmpl VEC_SIZE(%rsi, %rcx, SIZE_OF_CHAR), %edx ++ je L(ret7) ++ setl %al ++ negl %eax ++ xorl %r8d, %eax + # else +- movzbl (VEC_SIZE * 3)(%rax, %rcx), %eax +- movzbl (VEC_SIZE * 3)(%rdx, %rcx), %edx +- subl %edx, %eax ++ movzbl VEC_SIZE(%rdi, %rcx), %eax ++ movzbl VEC_SIZE(%rsi, %rcx), %ecx ++ subl %ecx, %eax ++ xorl %r8d, %eax ++ subl %r8d, %eax + # endif +-# endif ++L(ret7): + ret +- +- .p2align 4 +-L(loop_cross_page): +- xorl %r10d, %r10d +- movq %rdx, %rcx +- /* Align load via RDX. We load the extra ECX bytes which should +- be ignored. */ +- andl $((VEC_SIZE * 4) - 1), %ecx +- /* R10 is -RCX. */ +- subq %rcx, %r10 +- +- /* This works only if VEC_SIZE * 2 == 64. */ +-# if (VEC_SIZE * 2) != 64 +-# error (VEC_SIZE * 2) != 64 + # endif + +- /* Check if the first VEC_SIZE * 2 bytes should be ignored. */ +- cmpl $(VEC_SIZE * 2), %ecx +- jge L(loop_cross_page_2_vec) + +- VMOVU (%rax, %r10), %YMM2 +- VMOVU VEC_SIZE(%rax, %r10), %YMM3 ++ /* Page cross in rsi in next 4x VEC. */ + +- /* Each bit set in K2 represents a non-null CHAR in YMM2. */ +- VPTESTM %YMM2, %YMM2, %k2 +- /* Each bit cleared in K1 represents a mismatch or a null CHAR +- in YMM2 and 32 bytes at (%rdx, %r10). */ +- VPCMP $0, (%rdx, %r10), %YMM2, %k1{%k2} +- kmovd %k1, %r9d +- /* Don't use subl since it is the lower 16/32 bits of RDI +- below. */ +- notl %r9d +-# ifdef USE_AS_WCSCMP +- /* Only last 8 bits are valid. */ +- andl $0xff, %r9d +-# endif ++ /* TODO: Improve logic here. */ ++ .p2align 4,, 10 ++L(page_cross_during_loop): ++ /* eax contains [distance_from_page - (VEC_SIZE * 4)]. */ + +- /* Each bit set in K4 represents a non-null CHAR in YMM3. */ +- VPTESTM %YMM3, %YMM3, %k4 +- /* Each bit cleared in K3 represents a mismatch or a null CHAR +- in YMM3 and 32 bytes at VEC_SIZE(%rdx, %r10). */ +- VPCMP $0, VEC_SIZE(%rdx, %r10), %YMM3, %k3{%k4} +- kmovd %k3, %edi +- /* Must use notl %edi here as lower bits are for CHAR +- comparisons potentially out of range thus can be 0 without +- indicating mismatch. */ +- notl %edi +-# ifdef USE_AS_WCSCMP +- /* Don't use subl since it is the upper 8 bits of EDI below. */ +- andl $0xff, %edi +-# endif ++ /* Optimistically rsi and rdi and both aligned in which case we ++ don't need any logic here. */ ++ cmpl $-(VEC_SIZE * 4), %eax ++ /* Don't adjust eax before jumping back to loop and we will ++ never hit page cross case again. */ ++ je L(loop_skip_page_cross_check) + +-# ifdef USE_AS_WCSCMP +- /* NB: Each bit in EDI/R9D represents 4-byte element. */ +- sall $8, %edi +- /* NB: Divide shift count by 4 since each bit in K1 represent 4 +- bytes. */ +- movl %ecx, %SHIFT_REG32 +- sarl $2, %SHIFT_REG32 +- +- /* Each bit in EDI represents a null CHAR or a mismatch. */ +- orl %r9d, %edi +-# else +- salq $32, %rdi ++ /* Check if we can safely load a VEC. */ ++ cmpl $-(VEC_SIZE * 3), %eax ++ jle L(less_1x_vec_till_page_cross) + +- /* Each bit in RDI represents a null CHAR or a mismatch. */ +- orq %r9, %rdi +-# endif ++ VMOVA (%rdi), %YMM0 ++ VPTESTM %YMM0, %YMM0, %k2 ++ VPCMP $0, (%rsi), %YMM0, %k1{%k2} ++ kmovd %k1, %ecx ++ TESTEQ %ecx ++ jnz L(return_vec_0_end) ++ ++ /* if distance >= 2x VEC then eax > -(VEC_SIZE * 2). */ ++ cmpl $-(VEC_SIZE * 2), %eax ++ jg L(more_2x_vec_till_page_cross) ++ ++ .p2align 4,, 4 ++L(less_1x_vec_till_page_cross): ++ subl $-(VEC_SIZE * 4), %eax ++ /* Guranteed safe to read from rdi - VEC_SIZE here. The only ++ concerning case is first iteration if incoming s1 was near start ++ of a page and s2 near end. If s1 was near the start of the page ++ we already aligned up to nearest VEC_SIZE * 4 so gurnateed safe ++ to read back -VEC_SIZE. If rdi is truly at the start of a page ++ here, it means the previous page (rdi - VEC_SIZE) has already ++ been loaded earlier so must be valid. */ ++ VMOVU -VEC_SIZE(%rdi, %rax), %YMM0 ++ VPTESTM %YMM0, %YMM0, %k2 ++ VPCMP $0, -VEC_SIZE(%rsi, %rax), %YMM0, %k1{%k2} ++ ++ /* Mask of potentially valid bits. The lower bits can be out of ++ range comparisons (but safe regarding page crosses). */ + +- /* Since ECX < VEC_SIZE * 2, simply skip the first ECX bytes. */ +- shrxq %SHIFT_REG64, %rdi, %rdi +- testq %rdi, %rdi +- je L(loop_cross_page_2_vec) +- tzcntq %rdi, %rcx + # ifdef USE_AS_WCSCMP +- /* NB: Multiply wchar_t count by 4 to get the number of bytes. */ +- sall $2, %ecx ++ movl $-1, %r10d ++ movl %esi, %ecx ++ andl $(VEC_SIZE - 1), %ecx ++ shrl $2, %ecx ++ shlxl %ecx, %r10d, %ecx ++ movzbl %cl, %r10d ++# else ++ movl $-1, %ecx ++ shlxl %esi, %ecx, %r10d + # endif ++ ++ kmovd %k1, %ecx ++ notl %ecx ++ ++ + # ifdef USE_AS_STRNCMP +- cmpq %rcx, %r11 +- jbe L(zero) + # ifdef USE_AS_WCSCMP +- movq %rax, %rsi +- xorl %eax, %eax +- movl (%rsi, %rcx), %edi +- cmpl (%rdx, %rcx), %edi +- jne L(wcscmp_return) ++ movl %eax, %r11d ++ shrl $2, %r11d ++ cmpq %r11, %rdx + # else +- movzbl (%rax, %rcx), %eax +- movzbl (%rdx, %rcx), %edx +- subl %edx, %eax ++ cmpq %rax, %rdx + # endif ++ jbe L(return_page_cross_end_check) ++# endif ++ movl %eax, %OFFSET_REG ++ ++ /* Readjust eax before potentially returning to the loop. */ ++ addl $(PAGE_SIZE - VEC_SIZE * 4), %eax ++ ++ andl %r10d, %ecx ++ jz L(loop_skip_page_cross_check) ++ ++ .p2align 4,, 3 ++L(return_page_cross_end): ++ tzcntl %ecx, %ecx ++ ++# if (defined USE_AS_STRNCMP) || (defined USE_AS_WCSCMP) ++ leal -VEC_SIZE(%OFFSET_REG64, %rcx, SIZE_OF_CHAR), %ecx ++L(return_page_cross_cmp_mem): + # else +-# ifdef USE_AS_WCSCMP +- movq %rax, %rsi ++ addl %OFFSET_REG, %ecx ++# endif ++# ifdef USE_AS_WCSCMP ++ movl VEC_OFFSET(%rdi, %rcx), %edx + xorl %eax, %eax +- movl (%rsi, %rcx), %edi +- cmpl (%rdx, %rcx), %edi +- jne L(wcscmp_return) +-# else +- movzbl (%rax, %rcx), %eax +- movzbl (%rdx, %rcx), %edx +- subl %edx, %eax +-# endif ++ cmpl VEC_OFFSET(%rsi, %rcx), %edx ++ je L(ret8) ++ setl %al ++ negl %eax ++ xorl %r8d, %eax ++# else ++ movzbl VEC_OFFSET(%rdi, %rcx), %eax ++ movzbl VEC_OFFSET(%rsi, %rcx), %ecx ++ subl %ecx, %eax ++ xorl %r8d, %eax ++ subl %r8d, %eax + # endif ++L(ret8): + ret + +- .p2align 4 +-L(loop_cross_page_2_vec): +- /* The first VEC_SIZE * 2 bytes match or are ignored. */ +- VMOVU (VEC_SIZE * 2)(%rax, %r10), %YMM0 +- VMOVU (VEC_SIZE * 3)(%rax, %r10), %YMM1 ++# ifdef USE_AS_STRNCMP ++ .p2align 4,, 10 ++L(return_page_cross_end_check): ++ tzcntl %ecx, %ecx ++ leal -VEC_SIZE(%rax, %rcx, SIZE_OF_CHAR), %ecx ++# ifdef USE_AS_WCSCMP ++ sall $2, %edx ++# endif ++ cmpl %ecx, %edx ++ ja L(return_page_cross_cmp_mem) ++ xorl %eax, %eax ++ ret ++# endif ++ + ++ .p2align 4,, 10 ++L(more_2x_vec_till_page_cross): ++ /* If more 2x vec till cross we will complete a full loop ++ iteration here. */ ++ ++ VMOVA VEC_SIZE(%rdi), %YMM0 + VPTESTM %YMM0, %YMM0, %k2 +- /* Each bit cleared in K1 represents a mismatch or a null CHAR +- in YMM0 and 32 bytes at (VEC_SIZE * 2)(%rdx, %r10). */ +- VPCMP $0, (VEC_SIZE * 2)(%rdx, %r10), %YMM0, %k1{%k2} +- kmovd %k1, %r9d +- /* Don't use subl since it is the lower 16/32 bits of RDI +- below. */ +- notl %r9d +-# ifdef USE_AS_WCSCMP +- /* Only last 8 bits are valid. */ +- andl $0xff, %r9d +-# endif ++ VPCMP $0, VEC_SIZE(%rsi), %YMM0, %k1{%k2} ++ kmovd %k1, %ecx ++ TESTEQ %ecx ++ jnz L(return_vec_1_end) + +- VPTESTM %YMM1, %YMM1, %k4 +- /* Each bit cleared in K3 represents a mismatch or a null CHAR +- in YMM1 and 32 bytes at (VEC_SIZE * 3)(%rdx, %r10). */ +- VPCMP $0, (VEC_SIZE * 3)(%rdx, %r10), %YMM1, %k3{%k4} +- kmovd %k3, %edi +- /* Must use notl %edi here as lower bits are for CHAR +- comparisons potentially out of range thus can be 0 without +- indicating mismatch. */ +- notl %edi +-# ifdef USE_AS_WCSCMP +- /* Don't use subl since it is the upper 8 bits of EDI below. */ +- andl $0xff, %edi ++# ifdef USE_AS_STRNCMP ++ cmpq $(CHAR_PER_VEC * 2), %rdx ++ jbe L(ret_zero_in_loop_page_cross) + # endif + +-# ifdef USE_AS_WCSCMP +- /* NB: Each bit in EDI/R9D represents 4-byte element. */ +- sall $8, %edi ++ subl $-(VEC_SIZE * 4), %eax + +- /* Each bit in EDI represents a null CHAR or a mismatch. */ +- orl %r9d, %edi +-# else +- salq $32, %rdi ++ /* Safe to include comparisons from lower bytes. */ ++ VMOVU -(VEC_SIZE * 2)(%rdi, %rax), %YMM0 ++ VPTESTM %YMM0, %YMM0, %k2 ++ VPCMP $0, -(VEC_SIZE * 2)(%rsi, %rax), %YMM0, %k1{%k2} ++ kmovd %k1, %ecx ++ TESTEQ %ecx ++ jnz L(return_vec_page_cross_0) ++ ++ VMOVU -(VEC_SIZE * 1)(%rdi, %rax), %YMM0 ++ VPTESTM %YMM0, %YMM0, %k2 ++ VPCMP $0, -(VEC_SIZE * 1)(%rsi, %rax), %YMM0, %k1{%k2} ++ kmovd %k1, %ecx ++ TESTEQ %ecx ++ jnz L(return_vec_page_cross_1) + +- /* Each bit in RDI represents a null CHAR or a mismatch. */ +- orq %r9, %rdi ++# ifdef USE_AS_STRNCMP ++ /* Must check length here as length might proclude reading next ++ page. */ ++# ifdef USE_AS_WCSCMP ++ movl %eax, %r11d ++ shrl $2, %r11d ++ cmpq %r11, %rdx ++# else ++ cmpq %rax, %rdx ++# endif ++ jbe L(ret_zero_in_loop_page_cross) + # endif + +- xorl %r8d, %r8d +- /* If ECX > VEC_SIZE * 2, skip ECX - (VEC_SIZE * 2) bytes. */ +- subl $(VEC_SIZE * 2), %ecx +- jle 1f +- /* R8 has number of bytes skipped. */ +- movl %ecx, %r8d +-# ifdef USE_AS_WCSCMP +- /* NB: Divide shift count by 4 since each bit in RDI represent 4 +- bytes. */ +- sarl $2, %ecx +- /* Skip ECX bytes. */ +- shrl %cl, %edi ++ /* Finish the loop. */ ++ VMOVA (VEC_SIZE * 2)(%rdi), %YMM4 ++ VMOVA (VEC_SIZE * 3)(%rdi), %YMM6 ++ VPMINU %YMM4, %YMM6, %YMM9 ++ VPTESTM %YMM9, %YMM9, %k1 ++ ++ vpxorq (VEC_SIZE * 2)(%rsi), %YMM4, %YMM5 ++ /* YMM6 = YMM5 | ((VEC_SIZE * 3)(%rsi) ^ YMM6). */ ++ vpternlogd $0xde, (VEC_SIZE * 3)(%rsi), %YMM5, %YMM6 ++ ++ VPCMP $0, %YMMZERO, %YMM6, %k0{%k1} ++ kmovd %k0, %LOOP_REG ++ TESTEQ %LOOP_REG ++ jnz L(return_vec_2_3_end) ++ ++ /* Best for code size to include ucond-jmp here. Would be faster ++ if this case is hot to duplicate the L(return_vec_2_3_end) code ++ as fall-through and have jump back to loop on mismatch ++ comparison. */ ++ subq $-(VEC_SIZE * 4), %rdi ++ subq $-(VEC_SIZE * 4), %rsi ++ addl $(PAGE_SIZE - VEC_SIZE * 8), %eax ++# ifdef USE_AS_STRNCMP ++ subq $(CHAR_PER_VEC * 4), %rdx ++ ja L(loop_skip_page_cross_check) ++L(ret_zero_in_loop_page_cross): ++ xorl %eax, %eax ++ ret + # else +- /* Skip ECX bytes. */ +- shrq %cl, %rdi ++ jmp L(loop_skip_page_cross_check) + # endif +-1: +- /* Before jumping back to the loop, set ESI to the number of +- VEC_SIZE * 4 blocks before page crossing. */ +- movl $(PAGE_SIZE / (VEC_SIZE * 4) - 1), %esi + +- testq %rdi, %rdi +-# ifdef USE_AS_STRNCMP +- /* At this point, if %rdi value is 0, it already tested +- VEC_SIZE*4+%r10 byte starting from %rax. This label +- checks whether strncmp maximum offset reached or not. */ +- je L(string_nbyte_offset_check) ++ ++ .p2align 4,, 10 ++L(return_vec_page_cross_0): ++ addl $-VEC_SIZE, %eax ++L(return_vec_page_cross_1): ++ tzcntl %ecx, %ecx ++# if defined USE_AS_STRNCMP || defined USE_AS_WCSCMP ++ leal -VEC_SIZE(%rax, %rcx, SIZE_OF_CHAR), %ecx ++# ifdef USE_AS_STRNCMP ++# ifdef USE_AS_WCSCMP ++ /* Must divide ecx instead of multiply rdx due to overflow. */ ++ movl %ecx, %eax ++ shrl $2, %eax ++ cmpq %rax, %rdx ++# else ++ cmpq %rcx, %rdx ++# endif ++ jbe L(ret_zero_in_loop_page_cross) ++# endif + # else +- je L(back_to_loop) ++ addl %eax, %ecx + # endif +- tzcntq %rdi, %rcx ++ + # ifdef USE_AS_WCSCMP +- /* NB: Multiply wchar_t count by 4 to get the number of bytes. */ +- sall $2, %ecx +-# endif +- addq %r10, %rcx +- /* Adjust for number of bytes skipped. */ +- addq %r8, %rcx +-# ifdef USE_AS_STRNCMP +- addq $(VEC_SIZE * 2), %rcx +- subq %rcx, %r11 +- jbe L(zero) +-# ifdef USE_AS_WCSCMP +- movq %rax, %rsi ++ movl VEC_OFFSET(%rdi, %rcx), %edx + xorl %eax, %eax +- movl (%rsi, %rcx), %edi +- cmpl (%rdx, %rcx), %edi +- jne L(wcscmp_return) +-# else +- movzbl (%rax, %rcx), %eax +- movzbl (%rdx, %rcx), %edx +- subl %edx, %eax +-# endif ++ cmpl VEC_OFFSET(%rsi, %rcx), %edx ++ je L(ret9) ++ setl %al ++ negl %eax ++ xorl %r8d, %eax + # else +-# ifdef USE_AS_WCSCMP +- movq %rax, %rsi +- xorl %eax, %eax +- movl (VEC_SIZE * 2)(%rsi, %rcx), %edi +- cmpl (VEC_SIZE * 2)(%rdx, %rcx), %edi +- jne L(wcscmp_return) +-# else +- movzbl (VEC_SIZE * 2)(%rax, %rcx), %eax +- movzbl (VEC_SIZE * 2)(%rdx, %rcx), %edx +- subl %edx, %eax +-# endif ++ movzbl VEC_OFFSET(%rdi, %rcx), %eax ++ movzbl VEC_OFFSET(%rsi, %rcx), %ecx ++ subl %ecx, %eax ++ xorl %r8d, %eax ++ subl %r8d, %eax + # endif ++L(ret9): + ret + +-# ifdef USE_AS_STRNCMP +-L(string_nbyte_offset_check): +- leaq (VEC_SIZE * 4)(%r10), %r10 +- cmpq %r10, %r11 +- jbe L(zero) +- jmp L(back_to_loop) ++ ++ .p2align 4,, 10 ++L(page_cross): ++# ifndef USE_AS_STRNCMP ++ /* If both are VEC aligned we don't need any special logic here. ++ Only valid for strcmp where stop condition is guranteed to be ++ reachable by just reading memory. */ ++ testl $((VEC_SIZE - 1) << 20), %eax ++ jz L(no_page_cross) + # endif + +- .p2align 4 +-L(cross_page_loop): +- /* Check one byte/dword at a time. */ ++ movl %edi, %eax ++ movl %esi, %ecx ++ andl $(PAGE_SIZE - 1), %eax ++ andl $(PAGE_SIZE - 1), %ecx ++ ++ xorl %OFFSET_REG, %OFFSET_REG ++ ++ /* Check which is closer to page cross, s1 or s2. */ ++ cmpl %eax, %ecx ++ jg L(page_cross_s2) ++ ++ /* The previous page cross check has false positives. Check for ++ true positive as page cross logic is very expensive. */ ++ subl $(PAGE_SIZE - VEC_SIZE * 4), %eax ++ jbe L(no_page_cross) ++ ++ ++ /* Set r8 to not interfere with normal return value (rdi and rsi ++ did not swap). */ + # ifdef USE_AS_WCSCMP +- cmpl %ecx, %eax ++ /* any non-zero positive value that doesn't inference with 0x1. ++ */ ++ movl $2, %r8d + # else +- subl %ecx, %eax ++ xorl %r8d, %r8d + # endif +- jne L(different) +- addl $SIZE_OF_CHAR, %edx +- cmpl $(VEC_SIZE * 4), %edx +- je L(main_loop_header) ++ ++ /* Check if less than 1x VEC till page cross. */ ++ subl $(VEC_SIZE * 3), %eax ++ jg L(less_1x_vec_till_page) ++ ++ ++ /* If more than 1x VEC till page cross, loop throuh safely ++ loadable memory until within 1x VEC of page cross. */ ++ .p2align 4,, 8 ++L(page_cross_loop): ++ VMOVU (%rdi, %OFFSET_REG64, SIZE_OF_CHAR), %YMM0 ++ VPTESTM %YMM0, %YMM0, %k2 ++ VPCMP $0, (%rsi, %OFFSET_REG64, SIZE_OF_CHAR), %YMM0, %k1{%k2} ++ kmovd %k1, %ecx ++ TESTEQ %ecx ++ jnz L(check_ret_vec_page_cross) ++ addl $CHAR_PER_VEC, %OFFSET_REG + # ifdef USE_AS_STRNCMP +- cmpq %r11, %rdx +- jae L(zero) ++ cmpq %OFFSET_REG64, %rdx ++ jbe L(ret_zero_page_cross) + # endif ++ addl $VEC_SIZE, %eax ++ jl L(page_cross_loop) ++ + # ifdef USE_AS_WCSCMP +- movl (%rdi, %rdx), %eax +- movl (%rsi, %rdx), %ecx +-# else +- movzbl (%rdi, %rdx), %eax +- movzbl (%rsi, %rdx), %ecx ++ shrl $2, %eax + # endif +- /* Check null CHAR. */ +- testl %eax, %eax +- jne L(cross_page_loop) +- /* Since %eax == 0, subtract is OK for both SIGNED and UNSIGNED +- comparisons. */ +- subl %ecx, %eax +-# ifndef USE_AS_WCSCMP +-L(different): ++ ++ ++ subl %eax, %OFFSET_REG ++ /* OFFSET_REG has distance to page cross - VEC_SIZE. Guranteed ++ to not cross page so is safe to load. Since we have already ++ loaded at least 1 VEC from rsi it is also guranteed to be safe. ++ */ ++ VMOVU (%rdi, %OFFSET_REG64, SIZE_OF_CHAR), %YMM0 ++ VPTESTM %YMM0, %YMM0, %k2 ++ VPCMP $0, (%rsi, %OFFSET_REG64, SIZE_OF_CHAR), %YMM0, %k1{%k2} ++ ++ kmovd %k1, %ecx ++# ifdef USE_AS_STRNCMP ++ leal CHAR_PER_VEC(%OFFSET_REG64), %eax ++ cmpq %rax, %rdx ++ jbe L(check_ret_vec_page_cross2) ++# ifdef USE_AS_WCSCMP ++ addq $-(CHAR_PER_VEC * 2), %rdx ++# else ++ addq %rdi, %rdx ++# endif + # endif +- ret ++ TESTEQ %ecx ++ jz L(prepare_loop_no_len) + ++ .p2align 4,, 4 ++L(ret_vec_page_cross): ++# ifndef USE_AS_STRNCMP ++L(check_ret_vec_page_cross): ++# endif ++ tzcntl %ecx, %ecx ++ addl %OFFSET_REG, %ecx ++L(ret_vec_page_cross_cont): + # ifdef USE_AS_WCSCMP +- .p2align 4 +-L(different): +- /* Use movl to avoid modifying EFLAGS. */ +- movl $0, %eax ++ movl (%rdi, %rcx, SIZE_OF_CHAR), %edx ++ xorl %eax, %eax ++ cmpl (%rsi, %rcx, SIZE_OF_CHAR), %edx ++ je L(ret12) + setl %al + negl %eax +- orl $1, %eax +- ret ++ xorl %r8d, %eax ++# else ++ movzbl (%rdi, %rcx, SIZE_OF_CHAR), %eax ++ movzbl (%rsi, %rcx, SIZE_OF_CHAR), %ecx ++ subl %ecx, %eax ++ xorl %r8d, %eax ++ subl %r8d, %eax + # endif ++L(ret12): ++ ret ++ + + # ifdef USE_AS_STRNCMP +- .p2align 4 +-L(zero): ++ .p2align 4,, 10 ++L(check_ret_vec_page_cross2): ++ TESTEQ %ecx ++L(check_ret_vec_page_cross): ++ tzcntl %ecx, %ecx ++ addl %OFFSET_REG, %ecx ++ cmpq %rcx, %rdx ++ ja L(ret_vec_page_cross_cont) ++ .p2align 4,, 2 ++L(ret_zero_page_cross): + xorl %eax, %eax + ret ++# endif + +- .p2align 4 +-L(char0): +-# ifdef USE_AS_WCSCMP +- xorl %eax, %eax +- movl (%rdi), %ecx +- cmpl (%rsi), %ecx +- jne L(wcscmp_return) +-# else +- movzbl (%rsi), %ecx +- movzbl (%rdi), %eax +- subl %ecx, %eax +-# endif +- ret ++ .p2align 4,, 4 ++L(page_cross_s2): ++ /* Ensure this is a true page cross. */ ++ subl $(PAGE_SIZE - VEC_SIZE * 4), %ecx ++ jbe L(no_page_cross) ++ ++ ++ movl %ecx, %eax ++ movq %rdi, %rcx ++ movq %rsi, %rdi ++ movq %rcx, %rsi ++ ++ /* set r8 to negate return value as rdi and rsi swapped. */ ++# ifdef USE_AS_WCSCMP ++ movl $-4, %r8d ++# else ++ movl $-1, %r8d + # endif ++ xorl %OFFSET_REG, %OFFSET_REG + +- .p2align 4 +-L(last_vector): +- addq %rdx, %rdi +- addq %rdx, %rsi +-# ifdef USE_AS_STRNCMP +- subq %rdx, %r11 ++ /* Check if more than 1x VEC till page cross. */ ++ subl $(VEC_SIZE * 3), %eax ++ jle L(page_cross_loop) ++ ++ .p2align 4,, 6 ++L(less_1x_vec_till_page): ++# ifdef USE_AS_WCSCMP ++ shrl $2, %eax + # endif +- tzcntl %ecx, %edx ++ /* Find largest load size we can use. */ ++ cmpl $(16 / SIZE_OF_CHAR), %eax ++ ja L(less_16_till_page) ++ ++ /* Use 16 byte comparison. */ ++ vmovdqu (%rdi), %xmm0 ++ VPTESTM %xmm0, %xmm0, %k2 ++ VPCMP $0, (%rsi), %xmm0, %k1{%k2} ++ kmovd %k1, %ecx + # ifdef USE_AS_WCSCMP +- /* NB: Multiply wchar_t count by 4 to get the number of bytes. */ +- sall $2, %edx ++ subl $0xf, %ecx ++# else ++ incw %cx + # endif ++ jnz L(check_ret_vec_page_cross) ++ movl $(16 / SIZE_OF_CHAR), %OFFSET_REG + # ifdef USE_AS_STRNCMP +- cmpq %r11, %rdx +- jae L(zero) ++ cmpq %OFFSET_REG64, %rdx ++ jbe L(ret_zero_page_cross_slow_case0) ++ subl %eax, %OFFSET_REG ++# else ++ /* Explicit check for 16 byte alignment. */ ++ subl %eax, %OFFSET_REG ++ jz L(prepare_loop) + # endif ++ vmovdqu (%rdi, %OFFSET_REG64, SIZE_OF_CHAR), %xmm0 ++ VPTESTM %xmm0, %xmm0, %k2 ++ VPCMP $0, (%rsi, %OFFSET_REG64, SIZE_OF_CHAR), %xmm0, %k1{%k2} ++ kmovd %k1, %ecx + # ifdef USE_AS_WCSCMP +- xorl %eax, %eax +- movl (%rdi, %rdx), %ecx +- cmpl (%rsi, %rdx), %ecx +- jne L(wcscmp_return) ++ subl $0xf, %ecx + # else +- movzbl (%rdi, %rdx), %eax +- movzbl (%rsi, %rdx), %edx +- subl %edx, %eax ++ incw %cx + # endif ++ jnz L(check_ret_vec_page_cross) ++# ifdef USE_AS_STRNCMP ++ addl $(16 / SIZE_OF_CHAR), %OFFSET_REG ++ subq %OFFSET_REG64, %rdx ++ jbe L(ret_zero_page_cross_slow_case0) ++ subq $-(CHAR_PER_VEC * 4), %rdx ++ ++ leaq -(VEC_SIZE * 4)(%rdi, %OFFSET_REG64, SIZE_OF_CHAR), %rdi ++ leaq -(VEC_SIZE * 4)(%rsi, %OFFSET_REG64, SIZE_OF_CHAR), %rsi ++# else ++ leaq (16 - VEC_SIZE * 4)(%rdi, %OFFSET_REG64, SIZE_OF_CHAR), %rdi ++ leaq (16 - VEC_SIZE * 4)(%rsi, %OFFSET_REG64, SIZE_OF_CHAR), %rsi ++# endif ++ jmp L(prepare_loop_aligned) ++ ++# ifdef USE_AS_STRNCMP ++ .p2align 4,, 2 ++L(ret_zero_page_cross_slow_case0): ++ xorl %eax, %eax + ret ++# endif + +- /* Comparing on page boundary region requires special treatment: +- It must done one vector at the time, starting with the wider +- ymm vector if possible, if not, with xmm. If fetching 16 bytes +- (xmm) still passes the boundary, byte comparison must be done. +- */ +- .p2align 4 +-L(cross_page): +- /* Try one ymm vector at a time. */ +- cmpl $(PAGE_SIZE - VEC_SIZE), %eax +- jg L(cross_page_1_vector) +-L(loop_1_vector): +- VMOVU (%rdi, %rdx), %YMM0 + +- VPTESTM %YMM0, %YMM0, %k2 +- /* Each bit cleared in K1 represents a mismatch or a null CHAR +- in YMM0 and 32 bytes at (%rsi, %rdx). */ +- VPCMP $0, (%rsi, %rdx), %YMM0, %k1{%k2} ++ .p2align 4,, 10 ++L(less_16_till_page): ++ cmpl $(24 / SIZE_OF_CHAR), %eax ++ ja L(less_8_till_page) ++ ++ /* Use 8 byte comparison. */ ++ vmovq (%rdi), %xmm0 ++ vmovq (%rsi), %xmm1 ++ VPTESTM %xmm0, %xmm0, %k2 ++ VPCMP $0, %xmm1, %xmm0, %k1{%k2} + kmovd %k1, %ecx + # ifdef USE_AS_WCSCMP +- subl $0xff, %ecx ++ subl $0x3, %ecx + # else +- incl %ecx ++ incb %cl + # endif +- jne L(last_vector) ++ jnz L(check_ret_vec_page_cross) + +- addl $VEC_SIZE, %edx + +- addl $VEC_SIZE, %eax + # ifdef USE_AS_STRNCMP +- /* Return 0 if the current offset (%rdx) >= the maximum offset +- (%r11). */ +- cmpq %r11, %rdx +- jae L(zero) ++ cmpq $(8 / SIZE_OF_CHAR), %rdx ++ jbe L(ret_zero_page_cross_slow_case0) + # endif +- cmpl $(PAGE_SIZE - VEC_SIZE), %eax +- jle L(loop_1_vector) +-L(cross_page_1_vector): +- /* Less than 32 bytes to check, try one xmm vector. */ +- cmpl $(PAGE_SIZE - 16), %eax +- jg L(cross_page_1_xmm) +- VMOVU (%rdi, %rdx), %XMM0 ++ movl $(24 / SIZE_OF_CHAR), %OFFSET_REG ++ subl %eax, %OFFSET_REG + +- VPTESTM %YMM0, %YMM0, %k2 +- /* Each bit cleared in K1 represents a mismatch or a null CHAR +- in XMM0 and 16 bytes at (%rsi, %rdx). */ +- VPCMP $0, (%rsi, %rdx), %XMM0, %k1{%k2} ++ vmovq (%rdi, %OFFSET_REG64, SIZE_OF_CHAR), %xmm0 ++ vmovq (%rsi, %OFFSET_REG64, SIZE_OF_CHAR), %xmm1 ++ VPTESTM %xmm0, %xmm0, %k2 ++ VPCMP $0, %xmm1, %xmm0, %k1{%k2} + kmovd %k1, %ecx + # ifdef USE_AS_WCSCMP +- subl $0xf, %ecx ++ subl $0x3, %ecx + # else +- subl $0xffff, %ecx ++ incb %cl + # endif +- jne L(last_vector) ++ jnz L(check_ret_vec_page_cross) ++ + +- addl $16, %edx +-# ifndef USE_AS_WCSCMP +- addl $16, %eax +-# endif + # ifdef USE_AS_STRNCMP +- /* Return 0 if the current offset (%rdx) >= the maximum offset +- (%r11). */ +- cmpq %r11, %rdx +- jae L(zero) ++ addl $(8 / SIZE_OF_CHAR), %OFFSET_REG ++ subq %OFFSET_REG64, %rdx ++ jbe L(ret_zero_page_cross_slow_case0) ++ subq $-(CHAR_PER_VEC * 4), %rdx ++ ++ leaq -(VEC_SIZE * 4)(%rdi, %OFFSET_REG64, SIZE_OF_CHAR), %rdi ++ leaq -(VEC_SIZE * 4)(%rsi, %OFFSET_REG64, SIZE_OF_CHAR), %rsi ++# else ++ leaq (8 - VEC_SIZE * 4)(%rdi, %OFFSET_REG64, SIZE_OF_CHAR), %rdi ++ leaq (8 - VEC_SIZE * 4)(%rsi, %OFFSET_REG64, SIZE_OF_CHAR), %rsi + # endif ++ jmp L(prepare_loop_aligned) + +-L(cross_page_1_xmm): +-# ifndef USE_AS_WCSCMP +- /* Less than 16 bytes to check, try 8 byte vector. NB: No need +- for wcscmp nor wcsncmp since wide char is 4 bytes. */ +- cmpl $(PAGE_SIZE - 8), %eax +- jg L(cross_page_8bytes) +- vmovq (%rdi, %rdx), %XMM0 +- vmovq (%rsi, %rdx), %XMM1 + +- VPTESTM %YMM0, %YMM0, %k2 +- /* Each bit cleared in K1 represents a mismatch or a null CHAR +- in XMM0 and XMM1. */ +- VPCMP $0, %XMM1, %XMM0, %k1{%k2} +- kmovb %k1, %ecx ++ ++ ++ .p2align 4,, 10 ++L(less_8_till_page): + # ifdef USE_AS_WCSCMP +- subl $0x3, %ecx ++ /* If using wchar then this is the only check before we reach ++ the page boundary. */ ++ movl (%rdi), %eax ++ movl (%rsi), %ecx ++ cmpl %ecx, %eax ++ jnz L(ret_less_8_wcs) ++# ifdef USE_AS_STRNCMP ++ addq $-(CHAR_PER_VEC * 2), %rdx ++ /* We already checked for len <= 1 so cannot hit that case here. ++ */ ++# endif ++ testl %eax, %eax ++ jnz L(prepare_loop) ++ ret ++ ++ .p2align 4,, 8 ++L(ret_less_8_wcs): ++ setl %OFFSET_REG8 ++ negl %OFFSET_REG ++ movl %OFFSET_REG, %eax ++ xorl %r8d, %eax ++ ret ++ + # else +- subl $0xff, %ecx +-# endif +- jne L(last_vector) ++ cmpl $28, %eax ++ ja L(less_4_till_page) ++ ++ vmovd (%rdi), %xmm0 ++ vmovd (%rsi), %xmm1 ++ VPTESTM %xmm0, %xmm0, %k2 ++ VPCMP $0, %xmm1, %xmm0, %k1{%k2} ++ kmovd %k1, %ecx ++ subl $0xf, %ecx ++ jnz L(check_ret_vec_page_cross) + +- addl $8, %edx +- addl $8, %eax + # ifdef USE_AS_STRNCMP +- /* Return 0 if the current offset (%rdx) >= the maximum offset +- (%r11). */ +- cmpq %r11, %rdx +- jae L(zero) ++ cmpq $4, %rdx ++ jbe L(ret_zero_page_cross_slow_case1) + # endif ++ movl $(28 / SIZE_OF_CHAR), %OFFSET_REG ++ subl %eax, %OFFSET_REG + +-L(cross_page_8bytes): +- /* Less than 8 bytes to check, try 4 byte vector. */ +- cmpl $(PAGE_SIZE - 4), %eax +- jg L(cross_page_4bytes) +- vmovd (%rdi, %rdx), %XMM0 +- vmovd (%rsi, %rdx), %XMM1 +- +- VPTESTM %YMM0, %YMM0, %k2 +- /* Each bit cleared in K1 represents a mismatch or a null CHAR +- in XMM0 and XMM1. */ +- VPCMP $0, %XMM1, %XMM0, %k1{%k2} ++ vmovd (%rdi, %OFFSET_REG64, SIZE_OF_CHAR), %xmm0 ++ vmovd (%rsi, %OFFSET_REG64, SIZE_OF_CHAR), %xmm1 ++ VPTESTM %xmm0, %xmm0, %k2 ++ VPCMP $0, %xmm1, %xmm0, %k1{%k2} + kmovd %k1, %ecx +-# ifdef USE_AS_WCSCMP +- subl $0x1, %ecx +-# else + subl $0xf, %ecx +-# endif +- jne L(last_vector) ++ jnz L(check_ret_vec_page_cross) ++# ifdef USE_AS_STRNCMP ++ addl $(4 / SIZE_OF_CHAR), %OFFSET_REG ++ subq %OFFSET_REG64, %rdx ++ jbe L(ret_zero_page_cross_slow_case1) ++ subq $-(CHAR_PER_VEC * 4), %rdx ++ ++ leaq -(VEC_SIZE * 4)(%rdi, %OFFSET_REG64, SIZE_OF_CHAR), %rdi ++ leaq -(VEC_SIZE * 4)(%rsi, %OFFSET_REG64, SIZE_OF_CHAR), %rsi ++# else ++ leaq (4 - VEC_SIZE * 4)(%rdi, %OFFSET_REG64, SIZE_OF_CHAR), %rdi ++ leaq (4 - VEC_SIZE * 4)(%rsi, %OFFSET_REG64, SIZE_OF_CHAR), %rsi ++# endif ++ jmp L(prepare_loop_aligned) ++ + +- addl $4, %edx + # ifdef USE_AS_STRNCMP +- /* Return 0 if the current offset (%rdx) >= the maximum offset +- (%r11). */ +- cmpq %r11, %rdx +- jae L(zero) ++ .p2align 4,, 2 ++L(ret_zero_page_cross_slow_case1): ++ xorl %eax, %eax ++ ret + # endif + +-L(cross_page_4bytes): +-# endif +- /* Less than 4 bytes to check, try one byte/dword at a time. */ +-# ifdef USE_AS_STRNCMP +- cmpq %r11, %rdx +- jae L(zero) +-# endif +-# ifdef USE_AS_WCSCMP +- movl (%rdi, %rdx), %eax +- movl (%rsi, %rdx), %ecx +-# else +- movzbl (%rdi, %rdx), %eax +- movzbl (%rsi, %rdx), %ecx +-# endif +- testl %eax, %eax +- jne L(cross_page_loop) ++ .p2align 4,, 10 ++L(less_4_till_page): ++ subq %rdi, %rsi ++ /* Extremely slow byte comparison loop. */ ++L(less_4_loop): ++ movzbl (%rdi), %eax ++ movzbl (%rsi, %rdi), %ecx + subl %ecx, %eax ++ jnz L(ret_less_4_loop) ++ testl %ecx, %ecx ++ jz L(ret_zero_4_loop) ++# ifdef USE_AS_STRNCMP ++ decq %rdx ++ jz L(ret_zero_4_loop) ++# endif ++ incq %rdi ++ /* end condition is reach page boundary (rdi is aligned). */ ++ testl $31, %edi ++ jnz L(less_4_loop) ++ leaq -(VEC_SIZE * 4)(%rdi, %rsi), %rsi ++ addq $-(VEC_SIZE * 4), %rdi ++# ifdef USE_AS_STRNCMP ++ subq $-(CHAR_PER_VEC * 4), %rdx ++# endif ++ jmp L(prepare_loop_aligned) ++ ++L(ret_zero_4_loop): ++ xorl %eax, %eax ++ ret ++L(ret_less_4_loop): ++ xorl %r8d, %eax ++ subl %r8d, %eax + ret +-END (STRCMP) ++# endif ++END(STRCMP) + #endif +-- +GitLab + diff --git a/SOURCES/glibc-RHEL-15696-76.patch b/SOURCES/glibc-RHEL-15696-76.patch new file mode 100644 index 0000000..84d9a6f --- /dev/null +++ b/SOURCES/glibc-RHEL-15696-76.patch @@ -0,0 +1,33 @@ +From c15efd011cea3d8f0494269eb539583215a1feed Mon Sep 17 00:00:00 2001 +From: "H.J. Lu" +Date: Fri, 4 Feb 2022 11:09:10 -0800 +Subject: [PATCH] x86-64: Fix strcmp-avx2.S +Content-type: text/plain; charset=UTF-8 + +Change "movl %edx, %rdx" to "movl %edx, %edx" in: + +commit b77b06e0e296f1a2276c27a67e1d44f2cfa38d45 +Author: Noah Goldstein +Date: Mon Jan 10 15:35:38 2022 -0600 + + x86: Optimize strcmp-avx2.S +--- + sysdeps/x86_64/multiarch/strcmp-avx2.S | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/sysdeps/x86_64/multiarch/strcmp-avx2.S b/sysdeps/x86_64/multiarch/strcmp-avx2.S +index 554ffe4c..04675aa4 100644 +--- a/sysdeps/x86_64/multiarch/strcmp-avx2.S ++++ b/sysdeps/x86_64/multiarch/strcmp-avx2.S +@@ -106,7 +106,7 @@ ENTRY(STRCMP) + # ifdef USE_AS_STRNCMP + # ifdef __ILP32__ + /* Clear the upper 32 bits. */ +- movl %edx, %rdx ++ movl %edx, %edx + # endif + cmp $1, %RDX_LP + /* Signed comparison intentional. We use this branch to also +-- +GitLab + diff --git a/SOURCES/glibc-RHEL-15696-77.patch b/SOURCES/glibc-RHEL-15696-77.patch new file mode 100644 index 0000000..1a1cdae --- /dev/null +++ b/SOURCES/glibc-RHEL-15696-77.patch @@ -0,0 +1,33 @@ +From 0e0199a9e02ebe42e2b36958964d63f03573c382 Mon Sep 17 00:00:00 2001 +From: "H.J. Lu" +Date: Fri, 4 Feb 2022 11:11:08 -0800 +Subject: [PATCH] x86-64: Fix strcmp-evex.S +Content-type: text/plain; charset=UTF-8 + +Change "movl %edx, %rdx" to "movl %edx, %edx" in: + +commit 8418eb3ff4b781d31c4ed5dc6c0bd7356bc45db9 +Author: Noah Goldstein +Date: Mon Jan 10 15:35:39 2022 -0600 + + x86: Optimize strcmp-evex.S +--- + sysdeps/x86_64/multiarch/strcmp-evex.S | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/sysdeps/x86_64/multiarch/strcmp-evex.S b/sysdeps/x86_64/multiarch/strcmp-evex.S +index 99d8409a..ed56af8e 100644 +--- a/sysdeps/x86_64/multiarch/strcmp-evex.S ++++ b/sysdeps/x86_64/multiarch/strcmp-evex.S +@@ -116,7 +116,7 @@ ENTRY(STRCMP) + # ifdef USE_AS_STRNCMP + # ifdef __ILP32__ + /* Clear the upper 32 bits. */ +- movl %edx, %rdx ++ movl %edx, %edx + # endif + cmp $1, %RDX_LP + /* Signed comparison intentional. We use this branch to also +-- +GitLab + diff --git a/SOURCES/glibc-RHEL-15696-78.patch b/SOURCES/glibc-RHEL-15696-78.patch new file mode 100644 index 0000000..885b715 --- /dev/null +++ b/SOURCES/glibc-RHEL-15696-78.patch @@ -0,0 +1,459 @@ +From b62ace2740a106222e124cc86956448fa07abf4d Mon Sep 17 00:00:00 2001 +From: Noah Goldstein +Date: Sun, 6 Feb 2022 00:54:18 -0600 +Subject: [PATCH] x86: Improve vec generation in memset-vec-unaligned-erms.S +Content-type: text/plain; charset=UTF-8 + +No bug. + +Split vec generation into multiple steps. This allows the +broadcast in AVX2 to use 'xmm' registers for the L(less_vec) +case. This saves an expensive lane-cross instruction and removes +the need for 'vzeroupper'. + +For SSE2 replace 2x 'punpck' instructions with zero-idiom 'pxor' for +byte broadcast. + +Results for memset-avx2 small (geomean of N = 20 benchset runs). + +size, New Time, Old Time, New / Old + 0, 4.100, 3.831, 0.934 + 1, 5.074, 4.399, 0.867 + 2, 4.433, 4.411, 0.995 + 4, 4.487, 4.415, 0.984 + 8, 4.454, 4.396, 0.987 + 16, 4.502, 4.443, 0.987 + +All relevant string/wcsmbs tests are passing. +Reviewed-by: H.J. Lu +--- + sysdeps/x86_64/memset.S | 21 ++- + .../multiarch/memset-avx2-unaligned-erms.S | 18 +- + .../multiarch/memset-avx512-unaligned-erms.S | 18 +- + .../multiarch/memset-evex-unaligned-erms.S | 18 +- + .../multiarch/memset-vec-unaligned-erms.S | 164 +++++++++++------- + 5 files changed, 152 insertions(+), 87 deletions(-) + +diff --git a/sysdeps/x86_64/memset.S b/sysdeps/x86_64/memset.S +index 8672b030..27debd2b 100644 +--- a/sysdeps/x86_64/memset.S ++++ b/sysdeps/x86_64/memset.S +@@ -28,17 +28,22 @@ + #define VMOVU movups + #define VMOVA movaps + +-#define MEMSET_VDUP_TO_VEC0_AND_SET_RETURN(d, r) \ ++# define MEMSET_SET_VEC0_AND_SET_RETURN(d, r) \ + movd d, %xmm0; \ +- movq r, %rax; \ +- punpcklbw %xmm0, %xmm0; \ +- punpcklwd %xmm0, %xmm0; \ +- pshufd $0, %xmm0, %xmm0 ++ pxor %xmm1, %xmm1; \ ++ pshufb %xmm1, %xmm0; \ ++ movq r, %rax + +-#define WMEMSET_VDUP_TO_VEC0_AND_SET_RETURN(d, r) \ ++# define WMEMSET_SET_VEC0_AND_SET_RETURN(d, r) \ + movd d, %xmm0; \ +- movq r, %rax; \ +- pshufd $0, %xmm0, %xmm0 ++ pshufd $0, %xmm0, %xmm0; \ ++ movq r, %rax ++ ++# define MEMSET_VDUP_TO_VEC0_HIGH() ++# define MEMSET_VDUP_TO_VEC0_LOW() ++ ++# define WMEMSET_VDUP_TO_VEC0_HIGH() ++# define WMEMSET_VDUP_TO_VEC0_LOW() + + #define SECTION(p) p + +diff --git a/sysdeps/x86_64/multiarch/memset-avx2-unaligned-erms.S b/sysdeps/x86_64/multiarch/memset-avx2-unaligned-erms.S +index 1af668af..c0bf2875 100644 +--- a/sysdeps/x86_64/multiarch/memset-avx2-unaligned-erms.S ++++ b/sysdeps/x86_64/multiarch/memset-avx2-unaligned-erms.S +@@ -10,15 +10,18 @@ + # define VMOVU vmovdqu + # define VMOVA vmovdqa + +-# define MEMSET_VDUP_TO_VEC0_AND_SET_RETURN(d, r) \ ++# define MEMSET_SET_VEC0_AND_SET_RETURN(d, r) \ + vmovd d, %xmm0; \ +- movq r, %rax; \ +- vpbroadcastb %xmm0, %ymm0 ++ movq r, %rax; + +-# define WMEMSET_VDUP_TO_VEC0_AND_SET_RETURN(d, r) \ +- vmovd d, %xmm0; \ +- movq r, %rax; \ +- vpbroadcastd %xmm0, %ymm0 ++# define WMEMSET_SET_VEC0_AND_SET_RETURN(d, r) \ ++ MEMSET_SET_VEC0_AND_SET_RETURN(d, r) ++ ++# define MEMSET_VDUP_TO_VEC0_HIGH() vpbroadcastb %xmm0, %ymm0 ++# define MEMSET_VDUP_TO_VEC0_LOW() vpbroadcastb %xmm0, %xmm0 ++ ++# define WMEMSET_VDUP_TO_VEC0_HIGH() vpbroadcastd %xmm0, %ymm0 ++# define WMEMSET_VDUP_TO_VEC0_LOW() vpbroadcastd %xmm0, %xmm0 + + # ifndef SECTION + # define SECTION(p) p##.avx +@@ -30,5 +33,6 @@ + # define WMEMSET_SYMBOL(p,s) p##_avx2_##s + # endif + ++# define USE_XMM_LESS_VEC + # include "memset-vec-unaligned-erms.S" + #endif +diff --git a/sysdeps/x86_64/multiarch/memset-avx512-unaligned-erms.S b/sysdeps/x86_64/multiarch/memset-avx512-unaligned-erms.S +index f14d6f84..5241216a 100644 +--- a/sysdeps/x86_64/multiarch/memset-avx512-unaligned-erms.S ++++ b/sysdeps/x86_64/multiarch/memset-avx512-unaligned-erms.S +@@ -15,13 +15,19 @@ + + # define VZEROUPPER + +-# define MEMSET_VDUP_TO_VEC0_AND_SET_RETURN(d, r) \ +- movq r, %rax; \ +- vpbroadcastb d, %VEC0 ++# define MEMSET_SET_VEC0_AND_SET_RETURN(d, r) \ ++ vpbroadcastb d, %VEC0; \ ++ movq r, %rax + +-# define WMEMSET_VDUP_TO_VEC0_AND_SET_RETURN(d, r) \ +- movq r, %rax; \ +- vpbroadcastd d, %VEC0 ++# define WMEMSET_SET_VEC0_AND_SET_RETURN(d, r) \ ++ vpbroadcastd d, %VEC0; \ ++ movq r, %rax ++ ++# define MEMSET_VDUP_TO_VEC0_HIGH() ++# define MEMSET_VDUP_TO_VEC0_LOW() ++ ++# define WMEMSET_VDUP_TO_VEC0_HIGH() ++# define WMEMSET_VDUP_TO_VEC0_LOW() + + # define SECTION(p) p##.evex512 + # define MEMSET_SYMBOL(p,s) p##_avx512_##s +diff --git a/sysdeps/x86_64/multiarch/memset-evex-unaligned-erms.S b/sysdeps/x86_64/multiarch/memset-evex-unaligned-erms.S +index 64b09e77..63700215 100644 +--- a/sysdeps/x86_64/multiarch/memset-evex-unaligned-erms.S ++++ b/sysdeps/x86_64/multiarch/memset-evex-unaligned-erms.S +@@ -15,13 +15,19 @@ + + # define VZEROUPPER + +-# define MEMSET_VDUP_TO_VEC0_AND_SET_RETURN(d, r) \ +- movq r, %rax; \ +- vpbroadcastb d, %VEC0 ++# define MEMSET_SET_VEC0_AND_SET_RETURN(d, r) \ ++ vpbroadcastb d, %VEC0; \ ++ movq r, %rax + +-# define WMEMSET_VDUP_TO_VEC0_AND_SET_RETURN(d, r) \ +- movq r, %rax; \ +- vpbroadcastd d, %VEC0 ++# define WMEMSET_SET_VEC0_AND_SET_RETURN(d, r) \ ++ vpbroadcastd d, %VEC0; \ ++ movq r, %rax ++ ++# define MEMSET_VDUP_TO_VEC0_HIGH() ++# define MEMSET_VDUP_TO_VEC0_LOW() ++ ++# define WMEMSET_VDUP_TO_VEC0_HIGH() ++# define WMEMSET_VDUP_TO_VEC0_LOW() + + # define SECTION(p) p##.evex + # define MEMSET_SYMBOL(p,s) p##_evex_##s +diff --git a/sysdeps/x86_64/multiarch/memset-vec-unaligned-erms.S b/sysdeps/x86_64/multiarch/memset-vec-unaligned-erms.S +index f08b7323..a67f9833 100644 +--- a/sysdeps/x86_64/multiarch/memset-vec-unaligned-erms.S ++++ b/sysdeps/x86_64/multiarch/memset-vec-unaligned-erms.S +@@ -58,8 +58,10 @@ + #ifndef MOVQ + # if VEC_SIZE > 16 + # define MOVQ vmovq ++# define MOVD vmovd + # else + # define MOVQ movq ++# define MOVD movd + # endif + #endif + +@@ -72,9 +74,17 @@ + #if defined USE_WITH_EVEX || defined USE_WITH_AVX512 + # define END_REG rcx + # define LOOP_REG rdi ++# define LESS_VEC_REG rax + #else + # define END_REG rdi + # define LOOP_REG rdx ++# define LESS_VEC_REG rdi ++#endif ++ ++#ifdef USE_XMM_LESS_VEC ++# define XMM_SMALL 1 ++#else ++# define XMM_SMALL 0 + #endif + + #define PAGE_SIZE 4096 +@@ -110,8 +120,12 @@ END_CHK (WMEMSET_CHK_SYMBOL (__wmemset_chk, unaligned)) + + ENTRY (WMEMSET_SYMBOL (__wmemset, unaligned)) + shl $2, %RDX_LP +- WMEMSET_VDUP_TO_VEC0_AND_SET_RETURN (%esi, %rdi) +- jmp L(entry_from_bzero) ++ WMEMSET_SET_VEC0_AND_SET_RETURN (%esi, %rdi) ++ WMEMSET_VDUP_TO_VEC0_LOW() ++ cmpq $VEC_SIZE, %rdx ++ jb L(less_vec_no_vdup) ++ WMEMSET_VDUP_TO_VEC0_HIGH() ++ jmp L(entry_from_wmemset) + END (WMEMSET_SYMBOL (__wmemset, unaligned)) + #endif + +@@ -123,7 +137,7 @@ END_CHK (MEMSET_CHK_SYMBOL (__memset_chk, unaligned)) + #endif + + ENTRY (MEMSET_SYMBOL (__memset, unaligned)) +- MEMSET_VDUP_TO_VEC0_AND_SET_RETURN (%esi, %rdi) ++ MEMSET_SET_VEC0_AND_SET_RETURN (%esi, %rdi) + # ifdef __ILP32__ + /* Clear the upper 32 bits. */ + mov %edx, %edx +@@ -131,6 +145,8 @@ ENTRY (MEMSET_SYMBOL (__memset, unaligned)) + L(entry_from_bzero): + cmpq $VEC_SIZE, %rdx + jb L(less_vec) ++ MEMSET_VDUP_TO_VEC0_HIGH() ++L(entry_from_wmemset): + cmpq $(VEC_SIZE * 2), %rdx + ja L(more_2x_vec) + /* From VEC and to 2 * VEC. No branch when size == VEC_SIZE. */ +@@ -179,27 +195,27 @@ END_CHK (MEMSET_CHK_SYMBOL (__memset_chk, unaligned_erms)) + # endif + + ENTRY_P2ALIGN (MEMSET_SYMBOL (__memset, unaligned_erms), 6) +- MEMSET_VDUP_TO_VEC0_AND_SET_RETURN (%esi, %rdi) ++ MEMSET_SET_VEC0_AND_SET_RETURN (%esi, %rdi) + # ifdef __ILP32__ + /* Clear the upper 32 bits. */ + mov %edx, %edx + # endif + cmp $VEC_SIZE, %RDX_LP + jb L(less_vec) ++ MEMSET_VDUP_TO_VEC0_HIGH () + cmp $(VEC_SIZE * 2), %RDX_LP + ja L(stosb_more_2x_vec) +- /* From VEC and to 2 * VEC. No branch when size == VEC_SIZE. +- */ +- VMOVU %VEC(0), (%rax) +- VMOVU %VEC(0), -VEC_SIZE(%rax, %rdx) ++ /* From VEC and to 2 * VEC. No branch when size == VEC_SIZE. */ ++ VMOVU %VEC(0), (%rdi) ++ VMOVU %VEC(0), (VEC_SIZE * -1)(%rdi, %rdx) + VZEROUPPER_RETURN + #endif + +- .p2align 4,, 10 ++ .p2align 4,, 4 + L(last_2x_vec): + #ifdef USE_LESS_VEC_MASK_STORE +- VMOVU %VEC(0), (VEC_SIZE * 2 + LOOP_4X_OFFSET)(%rcx) +- VMOVU %VEC(0), (VEC_SIZE * 3 + LOOP_4X_OFFSET)(%rcx) ++ VMOVU %VEC(0), (VEC_SIZE * -2)(%rdi, %rdx) ++ VMOVU %VEC(0), (VEC_SIZE * -1)(%rdi, %rdx) + #else + VMOVU %VEC(0), (VEC_SIZE * -2)(%rdi) + VMOVU %VEC(0), (VEC_SIZE * -1)(%rdi) +@@ -212,6 +228,7 @@ L(last_2x_vec): + #ifdef USE_LESS_VEC_MASK_STORE + .p2align 4,, 10 + L(less_vec): ++L(less_vec_no_vdup): + /* Less than 1 VEC. */ + # if VEC_SIZE != 16 && VEC_SIZE != 32 && VEC_SIZE != 64 + # error Unsupported VEC_SIZE! +@@ -262,28 +279,18 @@ L(stosb_more_2x_vec): + /* Fallthrough goes to L(loop_4x_vec). Tests for memset (2x, 4x] + and (4x, 8x] jump to target. */ + L(more_2x_vec): +- +- /* Two different methods of setting up pointers / compare. The +- two methods are based on the fact that EVEX/AVX512 mov +- instructions take more bytes then AVX2/SSE2 mov instructions. As +- well that EVEX/AVX512 machines also have fast LEA_BID. Both +- setup and END_REG to avoid complex address mode. For EVEX/AVX512 +- this saves code size and keeps a few targets in one fetch block. +- For AVX2/SSE2 this helps prevent AGU bottlenecks. */ +-#if defined USE_WITH_EVEX || defined USE_WITH_AVX512 +- /* If EVEX/AVX512 compute END_REG - (VEC_SIZE * 4 + +- LOOP_4X_OFFSET) with LEA_BID. */ +- +- /* END_REG is rcx for EVEX/AVX512. */ +- leaq -(VEC_SIZE * 4 + LOOP_4X_OFFSET)(%rdi, %rdx), %END_REG +-#endif +- +- /* Stores to first 2x VEC before cmp as any path forward will +- require it. */ +- VMOVU %VEC(0), (%rax) +- VMOVU %VEC(0), VEC_SIZE(%rax) ++ /* Store next 2x vec regardless. */ ++ VMOVU %VEC(0), (%rdi) ++ VMOVU %VEC(0), (VEC_SIZE * 1)(%rdi) + + ++ /* Two different methods of setting up pointers / compare. The two ++ methods are based on the fact that EVEX/AVX512 mov instructions take ++ more bytes then AVX2/SSE2 mov instructions. As well that EVEX/AVX512 ++ machines also have fast LEA_BID. Both setup and END_REG to avoid complex ++ address mode. For EVEX/AVX512 this saves code size and keeps a few ++ targets in one fetch block. For AVX2/SSE2 this helps prevent AGU ++ bottlenecks. */ + #if !(defined USE_WITH_EVEX || defined USE_WITH_AVX512) + /* If AVX2/SSE2 compute END_REG (rdi) with ALU. */ + addq %rdx, %END_REG +@@ -292,6 +299,15 @@ L(more_2x_vec): + cmpq $(VEC_SIZE * 4), %rdx + jbe L(last_2x_vec) + ++ ++#if defined USE_WITH_EVEX || defined USE_WITH_AVX512 ++ /* If EVEX/AVX512 compute END_REG - (VEC_SIZE * 4 + LOOP_4X_OFFSET) with ++ LEA_BID. */ ++ ++ /* END_REG is rcx for EVEX/AVX512. */ ++ leaq -(VEC_SIZE * 4 + LOOP_4X_OFFSET)(%rdi, %rdx), %END_REG ++#endif ++ + /* Store next 2x vec regardless. */ + VMOVU %VEC(0), (VEC_SIZE * 2)(%rax) + VMOVU %VEC(0), (VEC_SIZE * 3)(%rax) +@@ -355,65 +371,93 @@ L(stosb_local): + /* Define L(less_vec) only if not otherwise defined. */ + .p2align 4 + L(less_vec): ++ /* Broadcast esi to partial register (i.e VEC_SIZE == 32 broadcast to ++ xmm). This is only does anything for AVX2. */ ++ MEMSET_VDUP_TO_VEC0_LOW () ++L(less_vec_no_vdup): + #endif + L(cross_page): + #if VEC_SIZE > 32 + cmpl $32, %edx +- jae L(between_32_63) ++ jge L(between_32_63) + #endif + #if VEC_SIZE > 16 + cmpl $16, %edx +- jae L(between_16_31) ++ jge L(between_16_31) ++#endif ++#ifndef USE_XMM_LESS_VEC ++ MOVQ %XMM0, %rcx + #endif +- MOVQ %XMM0, %rdi + cmpl $8, %edx +- jae L(between_8_15) ++ jge L(between_8_15) + cmpl $4, %edx +- jae L(between_4_7) ++ jge L(between_4_7) + cmpl $1, %edx +- ja L(between_2_3) +- jb L(return) +- movb %sil, (%rax) +- VZEROUPPER_RETURN ++ jg L(between_2_3) ++ jl L(between_0_0) ++ movb %sil, (%LESS_VEC_REG) ++L(between_0_0): ++ ret + +- /* Align small targets only if not doing so would cross a fetch +- line. */ ++ /* Align small targets only if not doing so would cross a fetch line. ++ */ + #if VEC_SIZE > 32 + .p2align 4,, SMALL_MEMSET_ALIGN(MOV_SIZE, RET_SIZE) + /* From 32 to 63. No branch when size == 32. */ + L(between_32_63): +- VMOVU %YMM0, (%rax) +- VMOVU %YMM0, -32(%rax, %rdx) ++ VMOVU %YMM0, (%LESS_VEC_REG) ++ VMOVU %YMM0, -32(%LESS_VEC_REG, %rdx) + VZEROUPPER_RETURN + #endif + + #if VEC_SIZE >= 32 +- .p2align 4,, SMALL_MEMSET_ALIGN(MOV_SIZE, RET_SIZE) ++ .p2align 4,, SMALL_MEMSET_ALIGN(MOV_SIZE, 1) + L(between_16_31): + /* From 16 to 31. No branch when size == 16. */ +- VMOVU %XMM0, (%rax) +- VMOVU %XMM0, -16(%rax, %rdx) +- VZEROUPPER_RETURN ++ VMOVU %XMM0, (%LESS_VEC_REG) ++ VMOVU %XMM0, -16(%LESS_VEC_REG, %rdx) ++ ret + #endif + +- .p2align 4,, SMALL_MEMSET_ALIGN(3, RET_SIZE) ++ /* Move size is 3 for SSE2, EVEX, and AVX512. Move size is 4 for AVX2. ++ */ ++ .p2align 4,, SMALL_MEMSET_ALIGN(3 + XMM_SMALL, 1) + L(between_8_15): + /* From 8 to 15. No branch when size == 8. */ +- movq %rdi, (%rax) +- movq %rdi, -8(%rax, %rdx) +- VZEROUPPER_RETURN ++#ifdef USE_XMM_LESS_VEC ++ MOVQ %XMM0, (%rdi) ++ MOVQ %XMM0, -8(%rdi, %rdx) ++#else ++ movq %rcx, (%LESS_VEC_REG) ++ movq %rcx, -8(%LESS_VEC_REG, %rdx) ++#endif ++ ret + +- .p2align 4,, SMALL_MEMSET_ALIGN(2, RET_SIZE) ++ /* Move size is 2 for SSE2, EVEX, and AVX512. Move size is 4 for AVX2. ++ */ ++ .p2align 4,, SMALL_MEMSET_ALIGN(2 << XMM_SMALL, 1) + L(between_4_7): + /* From 4 to 7. No branch when size == 4. */ +- movl %edi, (%rax) +- movl %edi, -4(%rax, %rdx) +- VZEROUPPER_RETURN ++#ifdef USE_XMM_LESS_VEC ++ MOVD %XMM0, (%rdi) ++ MOVD %XMM0, -4(%rdi, %rdx) ++#else ++ movl %ecx, (%LESS_VEC_REG) ++ movl %ecx, -4(%LESS_VEC_REG, %rdx) ++#endif ++ ret + +- .p2align 4,, SMALL_MEMSET_ALIGN(3, RET_SIZE) ++ /* 4 * XMM_SMALL for the third mov for AVX2. */ ++ .p2align 4,, 4 * XMM_SMALL + SMALL_MEMSET_ALIGN(3, 1) + L(between_2_3): + /* From 2 to 3. No branch when size == 2. */ +- movw %di, (%rax) +- movb %dil, -1(%rax, %rdx) +- VZEROUPPER_RETURN ++#ifdef USE_XMM_LESS_VEC ++ movb %sil, (%rdi) ++ movb %sil, 1(%rdi) ++ movb %sil, -1(%rdi, %rdx) ++#else ++ movw %cx, (%LESS_VEC_REG) ++ movb %sil, -1(%LESS_VEC_REG, %rdx) ++#endif ++ ret + END (MEMSET_SYMBOL (__memset, unaligned_erms)) +-- +GitLab + diff --git a/SOURCES/glibc-RHEL-15696-79.patch b/SOURCES/glibc-RHEL-15696-79.patch new file mode 100644 index 0000000..91e850f --- /dev/null +++ b/SOURCES/glibc-RHEL-15696-79.patch @@ -0,0 +1,40 @@ +From 1b0c60f95bbe2eded80b2bb5be75c0e45b11cde1 Mon Sep 17 00:00:00 2001 +From: Noah Goldstein +Date: Mon, 7 Feb 2022 00:32:23 -0600 +Subject: [PATCH] x86: Remove SSSE3 instruction for broadcast in memset.S (SSE2 + Only) +Content-type: text/plain; charset=UTF-8 + +commit b62ace2740a106222e124cc86956448fa07abf4d +Author: Noah Goldstein +Date: Sun Feb 6 00:54:18 2022 -0600 + + x86: Improve vec generation in memset-vec-unaligned-erms.S + +Revert usage of 'pshufb' in broadcast logic as it is an SSSE3 +instruction and memset.S is restricted to only SSE2 instructions. +--- + sysdeps/x86_64/memset.S | 7 ++++--- + 1 file changed, 4 insertions(+), 3 deletions(-) + +diff --git a/sysdeps/x86_64/memset.S b/sysdeps/x86_64/memset.S +index 27debd2b..4cb4aa71 100644 +--- a/sysdeps/x86_64/memset.S ++++ b/sysdeps/x86_64/memset.S +@@ -30,9 +30,10 @@ + + # define MEMSET_SET_VEC0_AND_SET_RETURN(d, r) \ + movd d, %xmm0; \ +- pxor %xmm1, %xmm1; \ +- pshufb %xmm1, %xmm0; \ +- movq r, %rax ++ movq r, %rax; \ ++ punpcklbw %xmm0, %xmm0; \ ++ punpcklwd %xmm0, %xmm0; \ ++ pshufd $0, %xmm0, %xmm0 + + # define WMEMSET_SET_VEC0_AND_SET_RETURN(d, r) \ + movd d, %xmm0; \ +-- +GitLab + diff --git a/SOURCES/glibc-RHEL-15696-8.patch b/SOURCES/glibc-RHEL-15696-8.patch new file mode 100644 index 0000000..5cf7633 --- /dev/null +++ b/SOURCES/glibc-RHEL-15696-8.patch @@ -0,0 +1,218 @@ +From 5165de69c0908e28a380cbd4bb054e55ea4abc95 Mon Sep 17 00:00:00 2001 +From: "H.J. Lu" +Date: Mon, 21 Jan 2019 11:36:36 -0800 +Subject: [PATCH] x86-64 strnlen/wcsnlen: Properly handle the length parameter + [BZ# 24097] +Content-type: text/plain; charset=UTF-8 + +On x32, the size_t parameter may be passed in the lower 32 bits of a +64-bit register with the non-zero upper 32 bits. The string/memory +functions written in assembly can only use the lower 32 bits of a +64-bit register as length or must clear the upper 32 bits before using +the full 64-bit register for length. + +This pach fixes strnlen/wcsnlen for x32. Tested on x86-64 and x32. On +x86-64, libc.so is the same with and withou the fix. + + [BZ# 24097] + CVE-2019-6488 + * sysdeps/x86_64/multiarch/strlen-avx2.S: Use RSI_LP for length. + Clear the upper 32 bits of RSI register. + * sysdeps/x86_64/strlen.S: Use RSI_LP for length. + * sysdeps/x86_64/x32/Makefile (tests): Add tst-size_t-strnlen + and tst-size_t-wcsnlen. + * sysdeps/x86_64/x32/tst-size_t-strnlen.c: New file. + * sysdeps/x86_64/x32/tst-size_t-wcsnlen.c: Likewise. +--- + sysdeps/x86_64/multiarch/strlen-avx2.S | 9 ++-- + sysdeps/x86_64/strlen.S | 12 ++--- + sysdeps/x86_64/x32/Makefile | 4 +- + sysdeps/x86_64/x32/tst-size_t-strnlen.c | 72 +++++++++++++++++++++++++ + sysdeps/x86_64/x32/tst-size_t-wcsnlen.c | 20 +++++++ + 5 files changed, 106 insertions(+), 11 deletions(-) + create mode 100644 sysdeps/x86_64/x32/tst-size_t-strnlen.c + create mode 100644 sysdeps/x86_64/x32/tst-size_t-wcsnlen.c + +Conflicts: + ChangeLog + (removed) + +diff --git a/sysdeps/x86_64/multiarch/strlen-avx2.S b/sysdeps/x86_64/multiarch/strlen-avx2.S +index fb2418cd..645e0446 100644 +--- a/sysdeps/x86_64/multiarch/strlen-avx2.S ++++ b/sysdeps/x86_64/multiarch/strlen-avx2.S +@@ -42,12 +42,15 @@ + ENTRY (STRLEN) + # ifdef USE_AS_STRNLEN + /* Check for zero length. */ +- testq %rsi, %rsi ++ test %RSI_LP, %RSI_LP + jz L(zero) + # ifdef USE_AS_WCSLEN +- shl $2, %rsi ++ shl $2, %RSI_LP ++# elif defined __ILP32__ ++ /* Clear the upper 32 bits. */ ++ movl %esi, %esi + # endif +- movq %rsi, %r8 ++ mov %RSI_LP, %R8_LP + # endif + movl %edi, %ecx + movq %rdi, %rdx +diff --git a/sysdeps/x86_64/strlen.S b/sysdeps/x86_64/strlen.S +index 01cb5fa8..f845f3d4 100644 +--- a/sysdeps/x86_64/strlen.S ++++ b/sysdeps/x86_64/strlen.S +@@ -59,21 +59,21 @@ ENTRY(strlen) + + #ifdef AS_STRNLEN + /* Do not read anything when n==0. */ +- test %rsi, %rsi ++ test %RSI_LP, %RSI_LP + jne L(n_nonzero) + xor %rax, %rax + ret + L(n_nonzero): + # ifdef AS_WCSLEN +- shlq $2, %rsi ++ shl $2, %RSI_LP + # endif + + /* Initialize long lived registers. */ + +- add %rdi, %rsi +- mov %rsi, %r10 +- and $-64, %r10 +- mov %rsi, %r11 ++ add %RDI_LP, %RSI_LP ++ mov %RSI_LP, %R10_LP ++ and $-64, %R10_LP ++ mov %RSI_LP, %R11_LP + #endif + + pxor %xmm0, %xmm0 +diff --git a/sysdeps/x86_64/x32/Makefile b/sysdeps/x86_64/x32/Makefile +index 2a9e20a9..1557724b 100644 +--- a/sysdeps/x86_64/x32/Makefile ++++ b/sysdeps/x86_64/x32/Makefile +@@ -8,10 +8,10 @@ endif + ifeq ($(subdir),string) + tests += tst-size_t-memchr tst-size_t-memcmp tst-size_t-memcpy \ + tst-size_t-memrchr tst-size_t-memset tst-size_t-strncasecmp \ +- tst-size_t-strncmp tst-size_t-strncpy ++ tst-size_t-strncmp tst-size_t-strncpy tst-size_t-strnlen + endif + + ifeq ($(subdir),wcsmbs) + tests += tst-size_t-wmemchr tst-size_t-wmemcmp tst-size_t-wmemset \ +- tst-size_t-wcsncmp ++ tst-size_t-wcsncmp tst-size_t-wcsnlen + endif +diff --git a/sysdeps/x86_64/x32/tst-size_t-strnlen.c b/sysdeps/x86_64/x32/tst-size_t-strnlen.c +new file mode 100644 +index 00000000..690a4a8a +--- /dev/null ++++ b/sysdeps/x86_64/x32/tst-size_t-strnlen.c +@@ -0,0 +1,72 @@ ++/* Test strnlen with size_t in the lower 32 bits of 64-bit register. ++ 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, see ++ . */ ++ ++#ifdef WIDE ++# define TEST_NAME "wcsnlen" ++#else ++# define TEST_NAME "strnlen" ++#endif /* WIDE */ ++ ++#include "test-size_t.h" ++ ++#ifdef WIDE ++# include ++# define STRNLEN wcsnlen ++# define CHAR wchar_t ++#else ++# define STRNLEN strnlen ++# define CHAR char ++#endif /* WIDE */ ++ ++IMPL (STRNLEN, 1) ++ ++typedef size_t (*proto_t) (const CHAR *, size_t); ++ ++static size_t ++__attribute__ ((noinline, noclone)) ++do_strnlen (parameter_t a, parameter_t b) ++{ ++ return CALL (&a, a.p, b.len); ++} ++ ++static int ++test_main (void) ++{ ++ test_init (); ++ ++ size_t size = page_size / sizeof (CHAR); ++ parameter_t src = { { 0 }, buf2 }; ++ parameter_t c = { { size }, (void *) (uintptr_t) 'a' }; ++ ++ int ret = 0; ++ FOR_EACH_IMPL (impl, 0) ++ { ++ src.fn = impl->fn; ++ size_t res = do_strnlen (src, c); ++ if (res != size) ++ { ++ error (0, 0, "Wrong result in function %s: 0x%x != 0x%x", ++ impl->name, res, size); ++ ret = 1; ++ } ++ } ++ ++ return ret ? EXIT_FAILURE : EXIT_SUCCESS; ++} ++ ++#include +diff --git a/sysdeps/x86_64/x32/tst-size_t-wcsnlen.c b/sysdeps/x86_64/x32/tst-size_t-wcsnlen.c +new file mode 100644 +index 00000000..093b4bbe +--- /dev/null ++++ b/sysdeps/x86_64/x32/tst-size_t-wcsnlen.c +@@ -0,0 +1,20 @@ ++/* Test wcsnlen with size_t in the lower 32 bits of 64-bit register. ++ 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, see ++ . */ ++ ++#define WIDE 1 ++#include "tst-size_t-strnlen.c" +-- +GitLab + diff --git a/SOURCES/glibc-RHEL-15696-80.patch b/SOURCES/glibc-RHEL-15696-80.patch new file mode 100644 index 0000000..53a3e7e --- /dev/null +++ b/SOURCES/glibc-RHEL-15696-80.patch @@ -0,0 +1,753 @@ +From 3d9f171bfb5325bd5f427e9fc386453358c6e840 Mon Sep 17 00:00:00 2001 +From: "H.J. Lu" +Date: Mon, 7 Feb 2022 05:55:15 -0800 +Subject: [PATCH] x86-64: Optimize bzero +Content-type: text/plain; charset=UTF-8 + +memset with zero as the value to set is by far the majority value (99%+ +for Python3 and GCC). + +bzero can be slightly more optimized for this case by using a zero-idiom +xor for broadcasting the set value to a register (vector or GPR). + +Co-developed-by: Noah Goldstein +--- + sysdeps/generic/ifunc-init.h | 5 +- + sysdeps/x86_64/memset.S | 8 + + sysdeps/x86_64/multiarch/Makefile | 205 +++++++++++------- + sysdeps/x86_64/multiarch/bzero.c | 106 +++++++++ + sysdeps/x86_64/multiarch/ifunc-impl-list.c | 42 ++++ + .../memset-avx2-unaligned-erms-rtm.S | 1 + + .../multiarch/memset-avx2-unaligned-erms.S | 6 + + .../multiarch/memset-avx512-unaligned-erms.S | 3 + + .../multiarch/memset-evex-unaligned-erms.S | 3 + + .../multiarch/memset-sse2-unaligned-erms.S | 1 + + .../multiarch/memset-vec-unaligned-erms.S | 110 +++++++--- + 11 files changed, 384 insertions(+), 106 deletions(-) + create mode 100644 sysdeps/x86_64/multiarch/bzero.c + +Conflicts: + sysdeps/generic/ifunc-init.h + (needs macros from cf4fd28ea453d1a9cec93939bc88b58ccef5437a (memcmpeq)) + sysdeps/x86_64/multiarch/Makefile + (file ordering) + +diff --git a/sysdeps/generic/ifunc-init.h b/sysdeps/generic/ifunc-init.h +index 241e4161..f7a72375 100644 +--- a/sysdeps/generic/ifunc-init.h ++++ b/sysdeps/generic/ifunc-init.h +@@ -50,5 +50,8 @@ + '___' as the optimized implementation and + '_ifunc_selector' as the IFUNC selector. */ + #define REDIRECT_NAME EVALUATOR1 (__redirect, SYMBOL_NAME) +-#define OPTIMIZE(name) EVALUATOR2 (SYMBOL_NAME, name) ++#define OPTIMIZE1(name) EVALUATOR1 (SYMBOL_NAME, name) ++#define OPTIMIZE2(name) EVALUATOR2 (SYMBOL_NAME, name) ++/* Default is to use OPTIMIZE2. */ ++#define OPTIMIZE(name) OPTIMIZE2(name) + #define IFUNC_SELECTOR EVALUATOR1 (SYMBOL_NAME, ifunc_selector) +diff --git a/sysdeps/x86_64/memset.S b/sysdeps/x86_64/memset.S +index 4cb4aa71..a1353f89 100644 +--- a/sysdeps/x86_64/memset.S ++++ b/sysdeps/x86_64/memset.S +@@ -35,6 +35,9 @@ + punpcklwd %xmm0, %xmm0; \ + pshufd $0, %xmm0, %xmm0 + ++# define BZERO_ZERO_VEC0() \ ++ pxor %xmm0, %xmm0 ++ + # define WMEMSET_SET_VEC0_AND_SET_RETURN(d, r) \ + movd d, %xmm0; \ + pshufd $0, %xmm0, %xmm0; \ +@@ -53,6 +56,10 @@ + # define MEMSET_SYMBOL(p,s) memset + #endif + ++#ifndef BZERO_SYMBOL ++# define BZERO_SYMBOL(p,s) __bzero ++#endif ++ + #ifndef WMEMSET_SYMBOL + # define WMEMSET_CHK_SYMBOL(p,s) p + # define WMEMSET_SYMBOL(p,s) __wmemset +@@ -63,6 +70,7 @@ + libc_hidden_builtin_def (memset) + + #if IS_IN (libc) ++weak_alias (__bzero, bzero) + libc_hidden_def (__wmemset) + weak_alias (__wmemset, wmemset) + libc_hidden_weak (wmemset) +diff --git a/sysdeps/x86_64/multiarch/Makefile b/sysdeps/x86_64/multiarch/Makefile +index 26be4095..37d8d6f0 100644 +--- a/sysdeps/x86_64/multiarch/Makefile ++++ b/sysdeps/x86_64/multiarch/Makefile +@@ -1,85 +1,130 @@ + ifeq ($(subdir),string) + +-sysdep_routines += strncat-c stpncpy-c strncpy-c \ +- strcmp-sse2 strcmp-sse2-unaligned strcmp-ssse3 \ +- strcmp-sse4_2 strcmp-avx2 \ +- strncmp-sse2 strncmp-ssse3 strncmp-sse4_2 strncmp-avx2 \ +- memchr-sse2 rawmemchr-sse2 memchr-avx2 rawmemchr-avx2 \ +- memrchr-sse2 memrchr-avx2 \ +- memcmp-sse2 \ +- memcmp-avx2-movbe \ +- memcmp-sse4 memcpy-ssse3 \ +- memmove-ssse3 \ +- memcpy-ssse3-back \ +- memmove-ssse3-back \ +- memmove-avx512-no-vzeroupper \ +- strcasecmp_l-sse2 strcasecmp_l-ssse3 \ +- strcasecmp_l-sse4_2 strcasecmp_l-avx \ +- strncase_l-sse2 strncase_l-ssse3 \ +- strncase_l-sse4_2 strncase_l-avx \ +- strchr-sse2 strchrnul-sse2 strchr-avx2 strchrnul-avx2 \ +- strrchr-sse2 strrchr-avx2 \ +- strlen-sse2 strnlen-sse2 strlen-avx2 strnlen-avx2 \ +- strcat-avx2 strncat-avx2 \ +- strcat-ssse3 strncat-ssse3\ +- strcpy-avx2 strncpy-avx2 \ +- strcpy-sse2 stpcpy-sse2 \ +- strcpy-ssse3 strncpy-ssse3 stpcpy-ssse3 stpncpy-ssse3 \ +- strcpy-sse2-unaligned strncpy-sse2-unaligned \ +- stpcpy-sse2-unaligned stpncpy-sse2-unaligned \ +- stpcpy-avx2 stpncpy-avx2 \ +- strcat-sse2 \ +- strcat-sse2-unaligned strncat-sse2-unaligned \ +- strchr-sse2-no-bsf memcmp-ssse3 strstr-sse2-unaligned \ +- strcspn-sse2 strpbrk-sse2 strspn-sse2 \ +- strcspn-c strpbrk-c strspn-c varshift \ +- memset-avx512-no-vzeroupper \ +- memmove-sse2-unaligned-erms \ +- memmove-avx-unaligned-erms \ +- memmove-avx512-unaligned-erms \ +- memset-sse2-unaligned-erms \ +- memset-avx2-unaligned-erms \ +- memset-avx512-unaligned-erms \ +- memchr-avx2-rtm \ +- memcmp-avx2-movbe-rtm \ +- memmove-avx-unaligned-erms-rtm \ +- memrchr-avx2-rtm \ +- memset-avx2-unaligned-erms-rtm \ +- rawmemchr-avx2-rtm \ +- strchr-avx2-rtm \ +- strcmp-avx2-rtm \ +- strchrnul-avx2-rtm \ +- stpcpy-avx2-rtm \ +- stpncpy-avx2-rtm \ +- strcat-avx2-rtm \ +- strcpy-avx2-rtm \ +- strlen-avx2-rtm \ +- strncat-avx2-rtm \ +- strncmp-avx2-rtm \ +- strncpy-avx2-rtm \ +- strnlen-avx2-rtm \ +- strrchr-avx2-rtm \ +- memchr-evex \ +- memcmp-evex-movbe \ +- memmove-evex-unaligned-erms \ +- memrchr-evex \ +- memset-evex-unaligned-erms \ +- rawmemchr-evex \ +- stpcpy-evex \ +- stpncpy-evex \ +- strcat-evex \ +- strchr-evex \ +- strchrnul-evex \ +- strcmp-evex \ +- strcpy-evex \ +- strlen-evex \ +- strncat-evex \ +- strncmp-evex \ +- strncpy-evex \ +- strnlen-evex \ +- strrchr-evex \ +- memchr-evex-rtm \ +- rawmemchr-evex-rtm ++sysdep_routines += \ ++ bzero \ ++ memchr-avx2 \ ++ memchr-avx2-rtm \ ++ memchr-evex \ ++ memchr-evex-rtm \ ++ memchr-sse2 \ ++ memcmp-avx2-movbe \ ++ memcmp-avx2-movbe-rtm \ ++ memcmp-evex-movbe \ ++ memcmp-sse2 \ ++ memcmp-sse4 \ ++ memcmp-ssse3 \ ++ memcpy-ssse3 \ ++ memcpy-ssse3-back \ ++ memmove-avx-unaligned-erms \ ++ memmove-avx-unaligned-erms-rtm \ ++ memmove-avx512-no-vzeroupper \ ++ memmove-avx512-unaligned-erms \ ++ memmove-evex-unaligned-erms \ ++ memmove-sse2-unaligned-erms \ ++ memmove-ssse3 \ ++ memmove-ssse3-back \ ++ memrchr-avx2 \ ++ memrchr-avx2-rtm \ ++ memrchr-evex \ ++ memrchr-sse2 \ ++ memset-avx2-unaligned-erms \ ++ memset-avx2-unaligned-erms-rtm \ ++ memset-avx512-no-vzeroupper \ ++ memset-avx512-unaligned-erms \ ++ memset-evex-unaligned-erms \ ++ memset-sse2-unaligned-erms \ ++ rawmemchr-avx2 \ ++ rawmemchr-avx2-rtm \ ++ rawmemchr-evex \ ++ rawmemchr-evex-rtm \ ++ rawmemchr-sse2 \ ++ stpcpy-avx2 \ ++ stpcpy-avx2-rtm \ ++ stpcpy-evex \ ++ stpcpy-sse2 \ ++ stpcpy-sse2-unaligned \ ++ stpcpy-ssse3 \ ++ stpncpy-avx2 \ ++ stpncpy-avx2-rtm \ ++ stpncpy-c \ ++ stpncpy-evex \ ++ stpncpy-sse2-unaligned \ ++ stpncpy-ssse3 \ ++ strcasecmp_l-avx \ ++ strcasecmp_l-sse2 \ ++ strcasecmp_l-sse4_2 \ ++ strcasecmp_l-ssse3 \ ++ strcat-avx2 \ ++ strcat-avx2-rtm \ ++ strcat-evex \ ++ strcat-sse2 \ ++ strcat-sse2-unaligned \ ++ strcat-ssse3 \ ++ strchr-avx2 \ ++ strchr-avx2-rtm \ ++ strchr-evex \ ++ strchr-sse2 \ ++ strchr-sse2-no-bsf \ ++ strchrnul-avx2 \ ++ strchrnul-avx2-rtm \ ++ strchrnul-evex \ ++ strchrnul-sse2 \ ++ strcmp-avx2 \ ++ strcmp-avx2-rtm \ ++ strcmp-evex \ ++ strcmp-sse2 \ ++ strcmp-sse2-unaligned \ ++ strcmp-sse4_2 \ ++ strcmp-ssse3 \ ++ strcpy-avx2 \ ++ strcpy-avx2-rtm \ ++ strcpy-evex \ ++ strcpy-sse2 \ ++ strcpy-sse2-unaligned \ ++ strcpy-ssse3 \ ++ strcspn-c \ ++ strcspn-sse2 \ ++ strlen-avx2 \ ++ strlen-avx2-rtm \ ++ strlen-evex \ ++ strlen-sse2 \ ++ strncase_l-avx \ ++ strncase_l-sse2 \ ++ strncase_l-sse4_2 \ ++ strncase_l-ssse3 \ ++ strncat-avx2 \ ++ strncat-avx2-rtm \ ++ strncat-c \ ++ strncat-evex \ ++ strncat-sse2-unaligned \ ++ strncat-ssse3 \ ++ strncmp-avx2 \ ++ strncmp-avx2-rtm \ ++ strncmp-evex \ ++ strncmp-sse2 \ ++ strncmp-sse4_2 \ ++ strncmp-ssse3 \ ++ strncpy-avx2 \ ++ strncpy-avx2-rtm \ ++ strncpy-c \ ++ strncpy-evex \ ++ strncpy-sse2-unaligned \ ++ strncpy-ssse3 \ ++ strnlen-avx2 \ ++ strnlen-avx2-rtm \ ++ strnlen-evex \ ++ strnlen-sse2 \ ++ strpbrk-c \ ++ strpbrk-sse2 \ ++ strrchr-avx2 \ ++ strrchr-avx2-rtm \ ++ strrchr-evex \ ++ strrchr-sse2 \ ++ strspn-c \ ++ strspn-sse2 \ ++ strstr-sse2-unaligned \ ++ varshift \ ++# sysdep_routines + CFLAGS-varshift.c += -msse4 + CFLAGS-strcspn-c.c += -msse4 + CFLAGS-strpbrk-c.c += -msse4 +diff --git a/sysdeps/x86_64/multiarch/bzero.c b/sysdeps/x86_64/multiarch/bzero.c +new file mode 100644 +index 00000000..58a14b2c +--- /dev/null ++++ b/sysdeps/x86_64/multiarch/bzero.c +@@ -0,0 +1,106 @@ ++/* Multiple versions of bzero. ++ All versions must be listed in ifunc-impl-list.c. ++ 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 multiple versions only for the definition in libc. */ ++#if IS_IN (libc) ++# define __bzero __redirect___bzero ++# include ++# undef __bzero ++ ++# define SYMBOL_NAME __bzero ++# include ++ ++extern __typeof (REDIRECT_NAME) OPTIMIZE1 (sse2_unaligned) ++ attribute_hidden; ++extern __typeof (REDIRECT_NAME) OPTIMIZE1 (sse2_unaligned_erms) ++ attribute_hidden; ++extern __typeof (REDIRECT_NAME) OPTIMIZE1 (avx2_unaligned) attribute_hidden; ++extern __typeof (REDIRECT_NAME) OPTIMIZE1 (avx2_unaligned_erms) ++ attribute_hidden; ++extern __typeof (REDIRECT_NAME) OPTIMIZE1 (avx2_unaligned_rtm) ++ attribute_hidden; ++extern __typeof (REDIRECT_NAME) OPTIMIZE1 (avx2_unaligned_erms_rtm) ++ attribute_hidden; ++extern __typeof (REDIRECT_NAME) OPTIMIZE1 (evex_unaligned) ++ attribute_hidden; ++extern __typeof (REDIRECT_NAME) OPTIMIZE1 (evex_unaligned_erms) ++ attribute_hidden; ++extern __typeof (REDIRECT_NAME) OPTIMIZE1 (avx512_unaligned) ++ attribute_hidden; ++extern __typeof (REDIRECT_NAME) OPTIMIZE1 (avx512_unaligned_erms) ++ attribute_hidden; ++ ++static inline void * ++IFUNC_SELECTOR (void) ++{ ++ const struct cpu_features* cpu_features = __get_cpu_features (); ++ ++ if (CPU_FEATURE_USABLE_P (cpu_features, AVX512F) ++ && !CPU_FEATURES_ARCH_P (cpu_features, Prefer_No_AVX512)) ++ { ++ if (CPU_FEATURE_USABLE_P (cpu_features, AVX512VL) ++ && CPU_FEATURE_USABLE_P (cpu_features, AVX512BW) ++ && CPU_FEATURE_USABLE_P (cpu_features, BMI2)) ++ { ++ if (CPU_FEATURE_USABLE_P (cpu_features, ERMS)) ++ return OPTIMIZE1 (avx512_unaligned_erms); ++ ++ return OPTIMIZE1 (avx512_unaligned); ++ } ++ } ++ ++ if (CPU_FEATURE_USABLE_P (cpu_features, AVX2)) ++ { ++ if (CPU_FEATURE_USABLE_P (cpu_features, AVX512VL) ++ && CPU_FEATURE_USABLE_P (cpu_features, AVX512BW) ++ && CPU_FEATURE_USABLE_P (cpu_features, BMI2)) ++ { ++ if (CPU_FEATURE_USABLE_P (cpu_features, ERMS)) ++ return OPTIMIZE1 (evex_unaligned_erms); ++ ++ return OPTIMIZE1 (evex_unaligned); ++ } ++ ++ if (CPU_FEATURE_USABLE_P (cpu_features, RTM)) ++ { ++ if (CPU_FEATURE_USABLE_P (cpu_features, ERMS)) ++ return OPTIMIZE1 (avx2_unaligned_erms_rtm); ++ ++ return OPTIMIZE1 (avx2_unaligned_rtm); ++ } ++ ++ if (!CPU_FEATURES_ARCH_P (cpu_features, Prefer_No_VZEROUPPER)) ++ { ++ if (CPU_FEATURE_USABLE_P (cpu_features, ERMS)) ++ return OPTIMIZE1 (avx2_unaligned_erms); ++ ++ return OPTIMIZE1 (avx2_unaligned); ++ } ++ } ++ ++ if (CPU_FEATURE_USABLE_P (cpu_features, ERMS)) ++ return OPTIMIZE1 (sse2_unaligned_erms); ++ ++ return OPTIMIZE1 (sse2_unaligned); ++} ++ ++libc_ifunc_redirected (__redirect___bzero, __bzero, IFUNC_SELECTOR ()); ++ ++weak_alias (__bzero, bzero) ++#endif +diff --git a/sysdeps/x86_64/multiarch/ifunc-impl-list.c b/sysdeps/x86_64/multiarch/ifunc-impl-list.c +index 8be0d78a..c963d391 100644 +--- a/sysdeps/x86_64/multiarch/ifunc-impl-list.c ++++ b/sysdeps/x86_64/multiarch/ifunc-impl-list.c +@@ -282,6 +282,48 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + __memset_avx512_no_vzeroupper) + ) + ++ /* Support sysdeps/x86_64/multiarch/bzero.c. */ ++ IFUNC_IMPL (i, name, bzero, ++ IFUNC_IMPL_ADD (array, i, bzero, 1, ++ __bzero_sse2_unaligned) ++ IFUNC_IMPL_ADD (array, i, bzero, 1, ++ __bzero_sse2_unaligned_erms) ++ IFUNC_IMPL_ADD (array, i, bzero, ++ CPU_FEATURE_USABLE (AVX2), ++ __bzero_avx2_unaligned) ++ IFUNC_IMPL_ADD (array, i, bzero, ++ CPU_FEATURE_USABLE (AVX2), ++ __bzero_avx2_unaligned_erms) ++ IFUNC_IMPL_ADD (array, i, bzero, ++ (CPU_FEATURE_USABLE (AVX2) ++ && CPU_FEATURE_USABLE (RTM)), ++ __bzero_avx2_unaligned_rtm) ++ IFUNC_IMPL_ADD (array, i, bzero, ++ (CPU_FEATURE_USABLE (AVX2) ++ && CPU_FEATURE_USABLE (RTM)), ++ __bzero_avx2_unaligned_erms_rtm) ++ IFUNC_IMPL_ADD (array, i, bzero, ++ (CPU_FEATURE_USABLE (AVX512VL) ++ && CPU_FEATURE_USABLE (AVX512BW) ++ && CPU_FEATURE_USABLE (BMI2)), ++ __bzero_evex_unaligned) ++ IFUNC_IMPL_ADD (array, i, bzero, ++ (CPU_FEATURE_USABLE (AVX512VL) ++ && CPU_FEATURE_USABLE (AVX512BW) ++ && CPU_FEATURE_USABLE (BMI2)), ++ __bzero_evex_unaligned_erms) ++ IFUNC_IMPL_ADD (array, i, bzero, ++ (CPU_FEATURE_USABLE (AVX512VL) ++ && CPU_FEATURE_USABLE (AVX512BW) ++ && CPU_FEATURE_USABLE (BMI2)), ++ __bzero_avx512_unaligned_erms) ++ IFUNC_IMPL_ADD (array, i, bzero, ++ (CPU_FEATURE_USABLE (AVX512VL) ++ && CPU_FEATURE_USABLE (AVX512BW) ++ && CPU_FEATURE_USABLE (BMI2)), ++ __bzero_avx512_unaligned) ++ ) ++ + /* Support sysdeps/x86_64/multiarch/rawmemchr.c. */ + IFUNC_IMPL (i, name, rawmemchr, + IFUNC_IMPL_ADD (array, i, rawmemchr, +diff --git a/sysdeps/x86_64/multiarch/memset-avx2-unaligned-erms-rtm.S b/sysdeps/x86_64/multiarch/memset-avx2-unaligned-erms-rtm.S +index 8ac3e479..5a5ee6f6 100644 +--- a/sysdeps/x86_64/multiarch/memset-avx2-unaligned-erms-rtm.S ++++ b/sysdeps/x86_64/multiarch/memset-avx2-unaligned-erms-rtm.S +@@ -5,6 +5,7 @@ + + #define SECTION(p) p##.avx.rtm + #define MEMSET_SYMBOL(p,s) p##_avx2_##s##_rtm ++#define BZERO_SYMBOL(p,s) p##_avx2_##s##_rtm + #define WMEMSET_SYMBOL(p,s) p##_avx2_##s##_rtm + + #include "memset-avx2-unaligned-erms.S" +diff --git a/sysdeps/x86_64/multiarch/memset-avx2-unaligned-erms.S b/sysdeps/x86_64/multiarch/memset-avx2-unaligned-erms.S +index c0bf2875..a093a283 100644 +--- a/sysdeps/x86_64/multiarch/memset-avx2-unaligned-erms.S ++++ b/sysdeps/x86_64/multiarch/memset-avx2-unaligned-erms.S +@@ -14,6 +14,9 @@ + vmovd d, %xmm0; \ + movq r, %rax; + ++# define BZERO_ZERO_VEC0() \ ++ vpxor %xmm0, %xmm0, %xmm0 ++ + # define WMEMSET_SET_VEC0_AND_SET_RETURN(d, r) \ + MEMSET_SET_VEC0_AND_SET_RETURN(d, r) + +@@ -29,6 +32,9 @@ + # ifndef MEMSET_SYMBOL + # define MEMSET_SYMBOL(p,s) p##_avx2_##s + # endif ++# ifndef BZERO_SYMBOL ++# define BZERO_SYMBOL(p,s) p##_avx2_##s ++# endif + # ifndef WMEMSET_SYMBOL + # define WMEMSET_SYMBOL(p,s) p##_avx2_##s + # endif +diff --git a/sysdeps/x86_64/multiarch/memset-avx512-unaligned-erms.S b/sysdeps/x86_64/multiarch/memset-avx512-unaligned-erms.S +index 5241216a..727c9213 100644 +--- a/sysdeps/x86_64/multiarch/memset-avx512-unaligned-erms.S ++++ b/sysdeps/x86_64/multiarch/memset-avx512-unaligned-erms.S +@@ -19,6 +19,9 @@ + vpbroadcastb d, %VEC0; \ + movq r, %rax + ++# define BZERO_ZERO_VEC0() \ ++ vpxorq %XMM0, %XMM0, %XMM0 ++ + # define WMEMSET_SET_VEC0_AND_SET_RETURN(d, r) \ + vpbroadcastd d, %VEC0; \ + movq r, %rax +diff --git a/sysdeps/x86_64/multiarch/memset-evex-unaligned-erms.S b/sysdeps/x86_64/multiarch/memset-evex-unaligned-erms.S +index 63700215..5d8fa78f 100644 +--- a/sysdeps/x86_64/multiarch/memset-evex-unaligned-erms.S ++++ b/sysdeps/x86_64/multiarch/memset-evex-unaligned-erms.S +@@ -19,6 +19,9 @@ + vpbroadcastb d, %VEC0; \ + movq r, %rax + ++# define BZERO_ZERO_VEC0() \ ++ vpxorq %XMM0, %XMM0, %XMM0 ++ + # define WMEMSET_SET_VEC0_AND_SET_RETURN(d, r) \ + vpbroadcastd d, %VEC0; \ + movq r, %rax +diff --git a/sysdeps/x86_64/multiarch/memset-sse2-unaligned-erms.S b/sysdeps/x86_64/multiarch/memset-sse2-unaligned-erms.S +index 56b81f5c..8f579ad6 100644 +--- a/sysdeps/x86_64/multiarch/memset-sse2-unaligned-erms.S ++++ b/sysdeps/x86_64/multiarch/memset-sse2-unaligned-erms.S +@@ -22,6 +22,7 @@ + + #if IS_IN (libc) + # define MEMSET_SYMBOL(p,s) p##_sse2_##s ++# define BZERO_SYMBOL(p,s) MEMSET_SYMBOL (p, s) + # define WMEMSET_SYMBOL(p,s) p##_sse2_##s + + # ifdef SHARED +diff --git a/sysdeps/x86_64/multiarch/memset-vec-unaligned-erms.S b/sysdeps/x86_64/multiarch/memset-vec-unaligned-erms.S +index a67f9833..06f5f5d7 100644 +--- a/sysdeps/x86_64/multiarch/memset-vec-unaligned-erms.S ++++ b/sysdeps/x86_64/multiarch/memset-vec-unaligned-erms.S +@@ -26,6 +26,10 @@ + + #include + ++#ifndef BZERO_SYMBOL ++# define BZERO_SYMBOL(p,s) MEMSET_SYMBOL (p, s) ++#endif ++ + #ifndef MEMSET_CHK_SYMBOL + # define MEMSET_CHK_SYMBOL(p,s) MEMSET_SYMBOL(p, s) + #endif +@@ -87,6 +91,18 @@ + # define XMM_SMALL 0 + #endif + ++#ifdef USE_LESS_VEC_MASK_STORE ++# define SET_REG64 rcx ++# define SET_REG32 ecx ++# define SET_REG16 cx ++# define SET_REG8 cl ++#else ++# define SET_REG64 rsi ++# define SET_REG32 esi ++# define SET_REG16 si ++# define SET_REG8 sil ++#endif ++ + #define PAGE_SIZE 4096 + + /* Macro to calculate size of small memset block for aligning +@@ -96,18 +112,6 @@ + + #ifndef SECTION + # error SECTION is not defined! +-#endif +- +- .section SECTION(.text),"ax",@progbits +-#if VEC_SIZE == 16 && IS_IN (libc) +-ENTRY (__bzero) +- mov %RDI_LP, %RAX_LP /* Set return value. */ +- mov %RSI_LP, %RDX_LP /* Set n. */ +- xorl %esi, %esi +- pxor %XMM0, %XMM0 +- jmp L(entry_from_bzero) +-END (__bzero) +-weak_alias (__bzero, bzero) + #endif + + #if IS_IN (libc) +@@ -123,12 +127,37 @@ ENTRY (WMEMSET_SYMBOL (__wmemset, unaligned)) + WMEMSET_SET_VEC0_AND_SET_RETURN (%esi, %rdi) + WMEMSET_VDUP_TO_VEC0_LOW() + cmpq $VEC_SIZE, %rdx +- jb L(less_vec_no_vdup) ++ jb L(less_vec_from_wmemset) + WMEMSET_VDUP_TO_VEC0_HIGH() + jmp L(entry_from_wmemset) + END (WMEMSET_SYMBOL (__wmemset, unaligned)) + #endif + ++ENTRY (BZERO_SYMBOL(__bzero, unaligned)) ++#if VEC_SIZE > 16 ++ BZERO_ZERO_VEC0 () ++#endif ++ mov %RDI_LP, %RAX_LP ++ mov %RSI_LP, %RDX_LP ++#ifndef USE_LESS_VEC_MASK_STORE ++ xorl %esi, %esi ++#endif ++ cmp $VEC_SIZE, %RDX_LP ++ jb L(less_vec_no_vdup) ++#ifdef USE_LESS_VEC_MASK_STORE ++ xorl %esi, %esi ++#endif ++#if VEC_SIZE <= 16 ++ BZERO_ZERO_VEC0 () ++#endif ++ cmp $(VEC_SIZE * 2), %RDX_LP ++ ja L(more_2x_vec) ++ /* From VEC and to 2 * VEC. No branch when size == VEC_SIZE. */ ++ VMOVU %VEC(0), (%rdi) ++ VMOVU %VEC(0), (VEC_SIZE * -1)(%rdi, %rdx) ++ VZEROUPPER_RETURN ++END (BZERO_SYMBOL(__bzero, unaligned)) ++ + #if defined SHARED && IS_IN (libc) + ENTRY_CHK (MEMSET_CHK_SYMBOL (__memset_chk, unaligned)) + cmp %RDX_LP, %RCX_LP +@@ -142,7 +171,6 @@ ENTRY (MEMSET_SYMBOL (__memset, unaligned)) + /* Clear the upper 32 bits. */ + mov %edx, %edx + # endif +-L(entry_from_bzero): + cmpq $VEC_SIZE, %rdx + jb L(less_vec) + MEMSET_VDUP_TO_VEC0_HIGH() +@@ -187,6 +215,31 @@ END (__memset_erms) + END (MEMSET_SYMBOL (__memset, erms)) + # endif + ++ENTRY_P2ALIGN (BZERO_SYMBOL(__bzero, unaligned_erms), 6) ++# if VEC_SIZE > 16 ++ BZERO_ZERO_VEC0 () ++# endif ++ mov %RDI_LP, %RAX_LP ++ mov %RSI_LP, %RDX_LP ++# ifndef USE_LESS_VEC_MASK_STORE ++ xorl %esi, %esi ++# endif ++ cmp $VEC_SIZE, %RDX_LP ++ jb L(less_vec_no_vdup) ++# ifdef USE_LESS_VEC_MASK_STORE ++ xorl %esi, %esi ++# endif ++# if VEC_SIZE <= 16 ++ BZERO_ZERO_VEC0 () ++# endif ++ cmp $(VEC_SIZE * 2), %RDX_LP ++ ja L(stosb_more_2x_vec) ++ /* From VEC and to 2 * VEC. No branch when size == VEC_SIZE. */ ++ VMOVU %VEC(0), (%rdi) ++ VMOVU %VEC(0), (VEC_SIZE * -1)(%rdi, %rdx) ++ VZEROUPPER_RETURN ++END (BZERO_SYMBOL(__bzero, unaligned_erms)) ++ + # if defined SHARED && IS_IN (libc) + ENTRY_CHK (MEMSET_CHK_SYMBOL (__memset_chk, unaligned_erms)) + cmp %RDX_LP, %RCX_LP +@@ -229,6 +282,7 @@ L(last_2x_vec): + .p2align 4,, 10 + L(less_vec): + L(less_vec_no_vdup): ++L(less_vec_from_wmemset): + /* Less than 1 VEC. */ + # if VEC_SIZE != 16 && VEC_SIZE != 32 && VEC_SIZE != 64 + # error Unsupported VEC_SIZE! +@@ -374,8 +428,11 @@ L(less_vec): + /* Broadcast esi to partial register (i.e VEC_SIZE == 32 broadcast to + xmm). This is only does anything for AVX2. */ + MEMSET_VDUP_TO_VEC0_LOW () ++L(less_vec_from_wmemset): ++#if VEC_SIZE > 16 + L(less_vec_no_vdup): + #endif ++#endif + L(cross_page): + #if VEC_SIZE > 32 + cmpl $32, %edx +@@ -386,7 +443,10 @@ L(cross_page): + jge L(between_16_31) + #endif + #ifndef USE_XMM_LESS_VEC +- MOVQ %XMM0, %rcx ++ MOVQ %XMM0, %SET_REG64 ++#endif ++#if VEC_SIZE <= 16 ++L(less_vec_no_vdup): + #endif + cmpl $8, %edx + jge L(between_8_15) +@@ -395,7 +455,7 @@ L(cross_page): + cmpl $1, %edx + jg L(between_2_3) + jl L(between_0_0) +- movb %sil, (%LESS_VEC_REG) ++ movb %SET_REG8, (%LESS_VEC_REG) + L(between_0_0): + ret + +@@ -428,8 +488,8 @@ L(between_8_15): + MOVQ %XMM0, (%rdi) + MOVQ %XMM0, -8(%rdi, %rdx) + #else +- movq %rcx, (%LESS_VEC_REG) +- movq %rcx, -8(%LESS_VEC_REG, %rdx) ++ movq %SET_REG64, (%LESS_VEC_REG) ++ movq %SET_REG64, -8(%LESS_VEC_REG, %rdx) + #endif + ret + +@@ -442,8 +502,8 @@ L(between_4_7): + MOVD %XMM0, (%rdi) + MOVD %XMM0, -4(%rdi, %rdx) + #else +- movl %ecx, (%LESS_VEC_REG) +- movl %ecx, -4(%LESS_VEC_REG, %rdx) ++ movl %SET_REG32, (%LESS_VEC_REG) ++ movl %SET_REG32, -4(%LESS_VEC_REG, %rdx) + #endif + ret + +@@ -452,12 +512,12 @@ L(between_4_7): + L(between_2_3): + /* From 2 to 3. No branch when size == 2. */ + #ifdef USE_XMM_LESS_VEC +- movb %sil, (%rdi) +- movb %sil, 1(%rdi) +- movb %sil, -1(%rdi, %rdx) ++ movb %SET_REG8, (%rdi) ++ movb %SET_REG8, 1(%rdi) ++ movb %SET_REG8, -1(%rdi, %rdx) + #else +- movw %cx, (%LESS_VEC_REG) +- movb %sil, -1(%LESS_VEC_REG, %rdx) ++ movw %SET_REG16, (%LESS_VEC_REG) ++ movb %SET_REG8, -1(%LESS_VEC_REG, %rdx) + #endif + ret + END (MEMSET_SYMBOL (__memset, unaligned_erms)) +-- +GitLab + diff --git a/SOURCES/glibc-RHEL-15696-81.patch b/SOURCES/glibc-RHEL-15696-81.patch new file mode 100644 index 0000000..960a4cc --- /dev/null +++ b/SOURCES/glibc-RHEL-15696-81.patch @@ -0,0 +1,33 @@ +From 7912236f4a597deb092650ca79f33504ddb4af28 Mon Sep 17 00:00:00 2001 +From: Noah Goldstein +Date: Sat, 12 Feb 2022 00:45:00 -0600 +Subject: [PATCH] x86: Set .text section in memset-vec-unaligned-erms +Content-type: text/plain; charset=UTF-8 + +commit 3d9f171bfb5325bd5f427e9fc386453358c6e840 +Author: H.J. Lu +Date: Mon Feb 7 05:55:15 2022 -0800 + + x86-64: Optimize bzero + +Remove setting the .text section for the code. This commit +adds that back. +--- + sysdeps/x86_64/multiarch/memset-vec-unaligned-erms.S | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/sysdeps/x86_64/multiarch/memset-vec-unaligned-erms.S b/sysdeps/x86_64/multiarch/memset-vec-unaligned-erms.S +index 06f5f5d7..4fb475c0 100644 +--- a/sysdeps/x86_64/multiarch/memset-vec-unaligned-erms.S ++++ b/sysdeps/x86_64/multiarch/memset-vec-unaligned-erms.S +@@ -114,6 +114,7 @@ + # error SECTION is not defined! + #endif + ++ .section SECTION(.text), "ax", @progbits + #if IS_IN (libc) + # if defined SHARED + ENTRY_CHK (WMEMSET_CHK_SYMBOL (__wmemset_chk, unaligned)) +-- +GitLab + diff --git a/SOURCES/glibc-RHEL-15696-82.patch b/SOURCES/glibc-RHEL-15696-82.patch new file mode 100644 index 0000000..23ee46e --- /dev/null +++ b/SOURCES/glibc-RHEL-15696-82.patch @@ -0,0 +1,90 @@ +From e108c02a5e23c8c88ce66d8705d4a24bb6b9a8bf Mon Sep 17 00:00:00 2001 +From: Noah Goldstein +Date: Tue, 15 Feb 2022 20:27:21 -0600 +Subject: [PATCH] x86: Fix bug in strncmp-evex and strncmp-avx2 [BZ #28895] +Content-type: text/plain; charset=UTF-8 + +Logic can read before the start of `s1` / `s2` if both `s1` and `s2` +are near the start of a page. To avoid having the result contimated by +these comparisons the `strcmp` variants would mask off these +comparisons. This was missing in the `strncmp` variants causing +the bug. This commit adds the masking to `strncmp` so that out of +range comparisons don't affect the result. + +test-strcmp, test-strncmp, test-wcscmp, and test-wcsncmp all pass as +well a full xcheck on x86_64 linux. +Reviewed-by: H.J. Lu +--- + string/test-strncmp.c | 23 +++++++++++++++++++++++ + sysdeps/x86_64/multiarch/strcmp-avx2.S | 1 + + sysdeps/x86_64/multiarch/strcmp-evex.S | 1 + + 3 files changed, 25 insertions(+) + +diff --git a/string/test-strncmp.c b/string/test-strncmp.c +index 927a6daa..e61fffd9 100644 +--- a/string/test-strncmp.c ++++ b/string/test-strncmp.c +@@ -403,6 +403,28 @@ check2 (void) + free (s2); + } + ++static void ++check4 (void) ++{ ++ /* To trigger bug 28895; We need 1) both s1 and s2 to be within 32 bytes of ++ the end of the page. 2) For there to be no mismatch/null byte before the ++ first page cross. 3) For length (`n`) to be large enough for one string to ++ cross the page. And 4) for there to be either mismatch/null bytes before ++ the start of the strings. */ ++ ++ size_t size = 10; ++ size_t addr_mask = (getpagesize () - 1) ^ (sizeof (CHAR) - 1); ++ CHAR *s1 = (CHAR *)(buf1 + (addr_mask & 0xffa)); ++ CHAR *s2 = (CHAR *)(buf2 + (addr_mask & 0xfed)); ++ int exp_result; ++ ++ STRCPY (s1, L ("tst-tlsmod%")); ++ STRCPY (s2, L ("tst-tls-manydynamic73mod")); ++ exp_result = SIMPLE_STRNCMP (s1, s2, size); ++ FOR_EACH_IMPL (impl, 0) ++ check_result (impl, s1, s2, size, exp_result); ++} ++ + static void + check3 (void) + { +@@ -445,6 +467,7 @@ test_main (void) + check1 (); + check2 (); + check3 (); ++ check4 (); + + printf ("%23s", ""); + FOR_EACH_IMPL (impl, 0) +diff --git a/sysdeps/x86_64/multiarch/strcmp-avx2.S b/sysdeps/x86_64/multiarch/strcmp-avx2.S +index 04675aa4..179cc0e3 100644 +--- a/sysdeps/x86_64/multiarch/strcmp-avx2.S ++++ b/sysdeps/x86_64/multiarch/strcmp-avx2.S +@@ -661,6 +661,7 @@ L(ret8): + # ifdef USE_AS_STRNCMP + .p2align 4,, 10 + L(return_page_cross_end_check): ++ andl %r10d, %ecx + tzcntl %ecx, %ecx + leal -VEC_SIZE(%rax, %rcx), %ecx + cmpl %ecx, %edx +diff --git a/sysdeps/x86_64/multiarch/strcmp-evex.S b/sysdeps/x86_64/multiarch/strcmp-evex.S +index ed56af8e..0dfa62bd 100644 +--- a/sysdeps/x86_64/multiarch/strcmp-evex.S ++++ b/sysdeps/x86_64/multiarch/strcmp-evex.S +@@ -689,6 +689,7 @@ L(ret8): + # ifdef USE_AS_STRNCMP + .p2align 4,, 10 + L(return_page_cross_end_check): ++ andl %r10d, %ecx + tzcntl %ecx, %ecx + leal -VEC_SIZE(%rax, %rcx, SIZE_OF_CHAR), %ecx + # ifdef USE_AS_WCSCMP +-- +GitLab + diff --git a/SOURCES/glibc-RHEL-15696-83.patch b/SOURCES/glibc-RHEL-15696-83.patch new file mode 100644 index 0000000..e7475a8 --- /dev/null +++ b/SOURCES/glibc-RHEL-15696-83.patch @@ -0,0 +1,77 @@ +From 9fef7039a7d04947bc89296ee0d187bc8d89b772 Mon Sep 17 00:00:00 2001 +From: Noah Goldstein +Date: Thu, 24 Mar 2022 15:50:33 -0500 +Subject: [PATCH] x86: Fix fallback for wcsncmp_avx2 in strcmp-avx2.S [BZ + #28896] +Content-type: text/plain; charset=UTF-8 + +Overflow case for __wcsncmp_avx2_rtm should be __wcscmp_avx2_rtm not +__wcscmp_avx2. + +commit ddf0992cf57a93200e0c782e2a94d0733a5a0b87 +Author: Noah Goldstein +Date: Sun Jan 9 16:02:21 2022 -0600 + + x86: Fix __wcsncmp_avx2 in strcmp-avx2.S [BZ# 28755] + +Set the wrong fallback function for `__wcsncmp_avx2_rtm`. It was set +to fallback on to `__wcscmp_avx2` instead of `__wcscmp_avx2_rtm` which +can cause spurious aborts. + +This change will need to be backported. + +All string/memory tests pass. +Reviewed-by: H.J. Lu +--- + sysdeps/x86/tst-strncmp-rtm.c | 15 +++++++++++++++ + sysdeps/x86_64/multiarch/strcmp-avx2.S | 2 +- + 2 files changed, 16 insertions(+), 1 deletion(-) + +diff --git a/sysdeps/x86/tst-strncmp-rtm.c b/sysdeps/x86/tst-strncmp-rtm.c +index aef9866c..ba6543be 100644 +--- a/sysdeps/x86/tst-strncmp-rtm.c ++++ b/sysdeps/x86/tst-strncmp-rtm.c +@@ -70,6 +70,16 @@ function_overflow (void) + return 1; + } + ++__attribute__ ((noinline, noclone)) ++static int ++function_overflow2 (void) ++{ ++ if (STRNCMP (string1, string2, SIZE_MAX >> 4) == 0) ++ return 0; ++ else ++ return 1; ++} ++ + static int + do_test (void) + { +@@ -77,5 +87,10 @@ do_test (void) + if (status != EXIT_SUCCESS) + return status; + status = do_test_1 (TEST_NAME, LOOP, prepare, function_overflow); ++ if (status != EXIT_SUCCESS) ++ return status; ++ status = do_test_1 (TEST_NAME, LOOP, prepare, function_overflow2); ++ if (status != EXIT_SUCCESS) ++ return status; + return status; + } +diff --git a/sysdeps/x86_64/multiarch/strcmp-avx2.S b/sysdeps/x86_64/multiarch/strcmp-avx2.S +index 179cc0e3..782f9472 100644 +--- a/sysdeps/x86_64/multiarch/strcmp-avx2.S ++++ b/sysdeps/x86_64/multiarch/strcmp-avx2.S +@@ -122,7 +122,7 @@ ENTRY(STRCMP) + are cases where length is large enough that it can never be a + bound on valid memory so just use wcscmp. */ + shrq $56, %rcx +- jnz __wcscmp_avx2 ++ jnz OVERFLOW_STRCMP + + leaq (, %rdx, 4), %rdx + # endif +-- +GitLab + diff --git a/SOURCES/glibc-RHEL-15696-84.patch b/SOURCES/glibc-RHEL-15696-84.patch new file mode 100644 index 0000000..e998eff --- /dev/null +++ b/SOURCES/glibc-RHEL-15696-84.patch @@ -0,0 +1,27 @@ +From 1283948f236f209b7d3f44b69a42b96806fa6da0 Mon Sep 17 00:00:00 2001 +From: "H.J. Lu" +Date: Sat, 5 Feb 2022 11:06:01 -0800 +Subject: [PATCH] x86: Improve L to support L(XXX_SYMBOL (YYY, ZZZ)) +Content-type: text/plain; charset=UTF-8 + +--- + sysdeps/x86/sysdep.h | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/sysdeps/x86/sysdep.h b/sysdeps/x86/sysdep.h +index a70bb3a2..49b0efe2 100644 +--- a/sysdeps/x86/sysdep.h ++++ b/sysdeps/x86/sysdep.h +@@ -111,7 +111,8 @@ enum cf_protection_level + /* Local label name for asm code. */ + #ifndef L + /* ELF-like local names start with `.L'. */ +-# define L(name) .L##name ++# define LOCAL_LABEL(name) .L##name ++# define L(name) LOCAL_LABEL(name) + #endif + + #define atom_text_section .section ".text.atom", "ax" +-- +GitLab + diff --git a/SOURCES/glibc-RHEL-15696-85.patch b/SOURCES/glibc-RHEL-15696-85.patch new file mode 100644 index 0000000..18f8a47 --- /dev/null +++ b/SOURCES/glibc-RHEL-15696-85.patch @@ -0,0 +1,108 @@ +From c328d0152d4b14cca58407ec68143894c8863004 Mon Sep 17 00:00:00 2001 +From: "H.J. Lu" +Date: Sat, 5 Feb 2022 11:52:33 -0800 +Subject: [PATCH] x86_64/multiarch: Sort sysdep_routines and put one entry per + line +Content-type: text/plain; charset=UTF-8 + +Conflicts: + sysdeps/x86_64/multiarch/Makefile + (test order changed) + +--- + sysdeps/x86_64/multiarch/Makefile | 78 +++++++++++++++++++------------ + 1 file changed, 48 insertions(+), 30 deletions(-) + +diff --git a/sysdeps/x86_64/multiarch/Makefile b/sysdeps/x86_64/multiarch/Makefile +index 37d8d6f0..8c9e7812 100644 +--- a/sysdeps/x86_64/multiarch/Makefile ++++ b/sysdeps/x86_64/multiarch/Makefile +@@ -132,37 +132,55 @@ CFLAGS-strspn-c.c += -msse4 + endif + + ifeq ($(subdir),wcsmbs) +-sysdep_routines += wmemcmp-sse4 wmemcmp-ssse3 wmemcmp-c \ +- wmemcmp-avx2-movbe \ +- wmemchr-sse2 wmemchr-avx2 \ +- wcscmp-sse2 wcscmp-avx2 \ +- wcsncmp-sse2 wcsncmp-avx2 \ +- wcscpy-ssse3 wcscpy-c \ +- wcschr-sse2 wcschr-avx2 \ +- wcsrchr-sse2 wcsrchr-avx2 \ +- wcslen-sse2 wcslen-sse4_1 wcslen-avx2 \ +- wcsnlen-c wcsnlen-sse4_1 wcsnlen-avx2 \ +- wcschr-avx2-rtm \ +- wcscmp-avx2-rtm \ +- wcslen-avx2-rtm \ +- wcsncmp-avx2-rtm \ +- wcsnlen-avx2-rtm \ +- wcsrchr-avx2-rtm \ +- wmemchr-avx2-rtm \ +- wmemcmp-avx2-movbe-rtm \ +- wcschr-evex \ +- wcscmp-evex \ +- wcslen-evex \ +- wcsncmp-evex \ +- wcsnlen-evex \ +- wcsrchr-evex \ +- wmemchr-evex \ +- wmemcmp-evex-movbe \ +- wmemchr-evex-rtm ++sysdep_routines += \ ++ wcschr-avx2 \ ++ wcschr-avx2-rtm \ ++ wcschr-evex \ ++ wcschr-sse2 \ ++ wcscmp-avx2 \ ++ wcscmp-avx2-rtm \ ++ wcscmp-evex \ ++ wcscmp-sse2 \ ++ wcscpy-c \ ++ wcscpy-ssse3 \ ++ wcslen-avx2 \ ++ wcslen-avx2-rtm \ ++ wcslen-evex \ ++ wcslen-sse2 \ ++ wcslen-sse4_1 \ ++ wcsncmp-avx2 \ ++ wcsncmp-avx2-rtm \ ++ wcsncmp-evex \ ++ wcsncmp-sse2 \ ++ wcsnlen-avx2 \ ++ wcsnlen-avx2-rtm \ ++ wcsnlen-c \ ++ wcsnlen-evex \ ++ wcsnlen-sse4_1 \ ++ wcsrchr-avx2 \ ++ wcsrchr-avx2-rtm \ ++ wcsrchr-evex \ ++ wcsrchr-sse2 \ ++ wmemchr-avx2 \ ++ wmemchr-avx2-rtm \ ++ wmemchr-evex \ ++ wmemchr-evex-rtm \ ++ wmemchr-sse2 \ ++ wmemcmp-avx2-movbe \ ++ wmemcmp-avx2-movbe-rtm \ ++ wmemcmp-c \ ++ wmemcmp-evex-movbe \ ++ wmemcmp-sse4 \ ++ wmemcmp-ssse3 \ ++# sysdep_routines + endif + + ifeq ($(subdir),debug) +-sysdep_routines += memcpy_chk-nonshared mempcpy_chk-nonshared \ +- memmove_chk-nonshared memset_chk-nonshared \ +- wmemset_chk-nonshared ++sysdep_routines += \ ++ memcpy_chk-nonshared \ ++ memmove_chk-nonshared \ ++ mempcpy_chk-nonshared \ ++ memset_chk-nonshared \ ++ wmemset_chk-nonshared \ ++# sysdep_routines + endif +-- +GitLab + diff --git a/SOURCES/glibc-RHEL-15696-86.patch b/SOURCES/glibc-RHEL-15696-86.patch new file mode 100644 index 0000000..d4fb42f --- /dev/null +++ b/SOURCES/glibc-RHEL-15696-86.patch @@ -0,0 +1,36 @@ +From 0fb8800029d230b3711bf722b2a47db92d0e273f Mon Sep 17 00:00:00 2001 +From: "H.J. Lu" +Date: Thu, 10 Feb 2022 11:52:50 -0800 +Subject: [PATCH] x86-64: Remove bzero weak alias in SS2 memset +Content-type: text/plain; charset=UTF-8 + +commit 3d9f171bfb5325bd5f427e9fc386453358c6e840 +Author: H.J. Lu +Date: Mon Feb 7 05:55:15 2022 -0800 + + x86-64: Optimize bzero + +added the optimized bzero. Remove bzero weak alias in SS2 memset to +avoid undefined __bzero in memset-sse2-unaligned-erms. +--- + sysdeps/x86_64/multiarch/memset-sse2-unaligned-erms.S | 4 +--- + 1 file changed, 1 insertion(+), 3 deletions(-) + +diff --git a/sysdeps/x86_64/multiarch/memset-sse2-unaligned-erms.S b/sysdeps/x86_64/multiarch/memset-sse2-unaligned-erms.S +index 8f579ad6..af51362b 100644 +--- a/sysdeps/x86_64/multiarch/memset-sse2-unaligned-erms.S ++++ b/sysdeps/x86_64/multiarch/memset-sse2-unaligned-erms.S +@@ -31,9 +31,7 @@ + # endif + + # undef weak_alias +-# define weak_alias(original, alias) \ +- .weak bzero; bzero = __bzero +- ++# define weak_alias(original, alias) + # undef strong_alias + # define strong_alias(ignored1, ignored2) + #endif +-- +GitLab + diff --git a/SOURCES/glibc-RHEL-15696-87.patch b/SOURCES/glibc-RHEL-15696-87.patch new file mode 100644 index 0000000..4882613 --- /dev/null +++ b/SOURCES/glibc-RHEL-15696-87.patch @@ -0,0 +1,29 @@ +From bf92893a14ebc161b08b28acc24fa06ae6be19cb Mon Sep 17 00:00:00 2001 +From: Adhemerval Zanella +Date: Thu, 10 Feb 2022 11:23:24 -0300 +Subject: [PATCH] x86_64: Remove bcopy optimizations +Content-type: text/plain; charset=UTF-8 + +The symbols is not present in current POSIX specification and compiler +already generates memmove call. +--- + sysdeps/x86_64/multiarch/bcopy.S | 7 ------- + 1 file changed, 7 deletions(-) + delete mode 100644 sysdeps/x86_64/multiarch/bcopy.S + +diff --git a/sysdeps/x86_64/multiarch/bcopy.S b/sysdeps/x86_64/multiarch/bcopy.S +deleted file mode 100644 +index 639f02bd..00000000 +--- a/sysdeps/x86_64/multiarch/bcopy.S ++++ /dev/null +@@ -1,7 +0,0 @@ +-#include +- +- .text +-ENTRY(bcopy) +- xchg %rdi, %rsi +- jmp __libc_memmove /* Branch to IFUNC memmove. */ +-END(bcopy) +-- +GitLab + diff --git a/SOURCES/glibc-RHEL-15696-88.patch b/SOURCES/glibc-RHEL-15696-88.patch new file mode 100644 index 0000000..d075f80 --- /dev/null +++ b/SOURCES/glibc-RHEL-15696-88.patch @@ -0,0 +1,372 @@ +From a6fbf4d51e9ba8063c4f8331564892ead9c67344 Mon Sep 17 00:00:00 2001 +From: Noah Goldstein +Date: Wed, 23 Mar 2022 16:57:16 -0500 +Subject: [PATCH] x86: Code cleanup in strchr-avx2 and comment justifying + branch +Content-type: text/plain; charset=UTF-8 + +Small code cleanup for size: -53 bytes. + +Add comment justifying using a branch to do NULL/non-null return. + +All string/memory tests pass and no regressions in benchtests. + +geometric_mean(N=20) of all benchmarks Original / New: 1.00 +Reviewed-by: H.J. Lu +--- + sysdeps/x86_64/multiarch/strchr-avx2.S | 204 +++++++++++++------------ + 1 file changed, 107 insertions(+), 97 deletions(-) + +diff --git a/sysdeps/x86_64/multiarch/strchr-avx2.S b/sysdeps/x86_64/multiarch/strchr-avx2.S +index 5884726b..89dd2bf7 100644 +--- a/sysdeps/x86_64/multiarch/strchr-avx2.S ++++ b/sysdeps/x86_64/multiarch/strchr-avx2.S +@@ -48,13 +48,13 @@ + # define PAGE_SIZE 4096 + + .section SECTION(.text),"ax",@progbits +-ENTRY (STRCHR) ++ENTRY_P2ALIGN (STRCHR, 5) + /* Broadcast CHAR to YMM0. */ + vmovd %esi, %xmm0 + movl %edi, %eax + andl $(PAGE_SIZE - 1), %eax + VPBROADCAST %xmm0, %ymm0 +- vpxor %xmm9, %xmm9, %xmm9 ++ vpxor %xmm1, %xmm1, %xmm1 + + /* Check if we cross page boundary with one vector load. */ + cmpl $(PAGE_SIZE - VEC_SIZE), %eax +@@ -62,37 +62,29 @@ ENTRY (STRCHR) + + /* Check the first VEC_SIZE bytes. Search for both CHAR and the + null byte. */ +- vmovdqu (%rdi), %ymm8 +- VPCMPEQ %ymm8, %ymm0, %ymm1 +- VPCMPEQ %ymm8, %ymm9, %ymm2 +- vpor %ymm1, %ymm2, %ymm1 +- vpmovmskb %ymm1, %eax ++ vmovdqu (%rdi), %ymm2 ++ VPCMPEQ %ymm2, %ymm0, %ymm3 ++ VPCMPEQ %ymm2, %ymm1, %ymm2 ++ vpor %ymm3, %ymm2, %ymm3 ++ vpmovmskb %ymm3, %eax + testl %eax, %eax + jz L(aligned_more) + tzcntl %eax, %eax + # ifndef USE_AS_STRCHRNUL +- /* Found CHAR or the null byte. */ +- cmp (%rdi, %rax), %CHAR_REG +- jne L(zero) +-# endif +- addq %rdi, %rax +- VZEROUPPER_RETURN +- +- /* .p2align 5 helps keep performance more consistent if ENTRY() +- alignment % 32 was either 16 or 0. As well this makes the +- alignment % 32 of the loop_4x_vec fixed which makes tuning it +- easier. */ +- .p2align 5 +-L(first_vec_x4): +- tzcntl %eax, %eax +- addq $(VEC_SIZE * 3 + 1), %rdi +-# ifndef USE_AS_STRCHRNUL +- /* Found CHAR or the null byte. */ ++ /* Found CHAR or the null byte. */ + cmp (%rdi, %rax), %CHAR_REG ++ /* NB: Use a branch instead of cmovcc here. The expectation is ++ that with strchr the user will branch based on input being ++ null. Since this branch will be 100% predictive of the user ++ branch a branch miss here should save what otherwise would ++ be branch miss in the user code. Otherwise using a branch 1) ++ saves code size and 2) is faster in highly predictable ++ environments. */ + jne L(zero) + # endif + addq %rdi, %rax +- VZEROUPPER_RETURN ++L(return_vzeroupper): ++ ZERO_UPPER_VEC_REGISTERS_RETURN + + # ifndef USE_AS_STRCHRNUL + L(zero): +@@ -103,7 +95,8 @@ L(zero): + + .p2align 4 + L(first_vec_x1): +- tzcntl %eax, %eax ++ /* Use bsf to save code size. */ ++ bsfl %eax, %eax + incq %rdi + # ifndef USE_AS_STRCHRNUL + /* Found CHAR or the null byte. */ +@@ -113,9 +106,10 @@ L(first_vec_x1): + addq %rdi, %rax + VZEROUPPER_RETURN + +- .p2align 4 ++ .p2align 4,, 10 + L(first_vec_x2): +- tzcntl %eax, %eax ++ /* Use bsf to save code size. */ ++ bsfl %eax, %eax + addq $(VEC_SIZE + 1), %rdi + # ifndef USE_AS_STRCHRNUL + /* Found CHAR or the null byte. */ +@@ -125,9 +119,10 @@ L(first_vec_x2): + addq %rdi, %rax + VZEROUPPER_RETURN + +- .p2align 4 ++ .p2align 4,, 8 + L(first_vec_x3): +- tzcntl %eax, %eax ++ /* Use bsf to save code size. */ ++ bsfl %eax, %eax + addq $(VEC_SIZE * 2 + 1), %rdi + # ifndef USE_AS_STRCHRNUL + /* Found CHAR or the null byte. */ +@@ -137,6 +132,21 @@ L(first_vec_x3): + addq %rdi, %rax + VZEROUPPER_RETURN + ++ .p2align 4,, 10 ++L(first_vec_x4): ++ /* Use bsf to save code size. */ ++ bsfl %eax, %eax ++ addq $(VEC_SIZE * 3 + 1), %rdi ++# ifndef USE_AS_STRCHRNUL ++ /* Found CHAR or the null byte. */ ++ cmp (%rdi, %rax), %CHAR_REG ++ jne L(zero) ++# endif ++ addq %rdi, %rax ++ VZEROUPPER_RETURN ++ ++ ++ + .p2align 4 + L(aligned_more): + /* Align data to VEC_SIZE - 1. This is the same number of +@@ -146,90 +156,92 @@ L(aligned_more): + L(cross_page_continue): + /* Check the next 4 * VEC_SIZE. Only one VEC_SIZE at a time + since data is only aligned to VEC_SIZE. */ +- vmovdqa 1(%rdi), %ymm8 +- VPCMPEQ %ymm8, %ymm0, %ymm1 +- VPCMPEQ %ymm8, %ymm9, %ymm2 +- vpor %ymm1, %ymm2, %ymm1 +- vpmovmskb %ymm1, %eax ++ vmovdqa 1(%rdi), %ymm2 ++ VPCMPEQ %ymm2, %ymm0, %ymm3 ++ VPCMPEQ %ymm2, %ymm1, %ymm2 ++ vpor %ymm3, %ymm2, %ymm3 ++ vpmovmskb %ymm3, %eax + testl %eax, %eax + jnz L(first_vec_x1) + +- vmovdqa (VEC_SIZE + 1)(%rdi), %ymm8 +- VPCMPEQ %ymm8, %ymm0, %ymm1 +- VPCMPEQ %ymm8, %ymm9, %ymm2 +- vpor %ymm1, %ymm2, %ymm1 +- vpmovmskb %ymm1, %eax ++ vmovdqa (VEC_SIZE + 1)(%rdi), %ymm2 ++ VPCMPEQ %ymm2, %ymm0, %ymm3 ++ VPCMPEQ %ymm2, %ymm1, %ymm2 ++ vpor %ymm3, %ymm2, %ymm3 ++ vpmovmskb %ymm3, %eax + testl %eax, %eax + jnz L(first_vec_x2) + +- vmovdqa (VEC_SIZE * 2 + 1)(%rdi), %ymm8 +- VPCMPEQ %ymm8, %ymm0, %ymm1 +- VPCMPEQ %ymm8, %ymm9, %ymm2 +- vpor %ymm1, %ymm2, %ymm1 +- vpmovmskb %ymm1, %eax ++ vmovdqa (VEC_SIZE * 2 + 1)(%rdi), %ymm2 ++ VPCMPEQ %ymm2, %ymm0, %ymm3 ++ VPCMPEQ %ymm2, %ymm1, %ymm2 ++ vpor %ymm3, %ymm2, %ymm3 ++ vpmovmskb %ymm3, %eax + testl %eax, %eax + jnz L(first_vec_x3) + +- vmovdqa (VEC_SIZE * 3 + 1)(%rdi), %ymm8 +- VPCMPEQ %ymm8, %ymm0, %ymm1 +- VPCMPEQ %ymm8, %ymm9, %ymm2 +- vpor %ymm1, %ymm2, %ymm1 +- vpmovmskb %ymm1, %eax ++ vmovdqa (VEC_SIZE * 3 + 1)(%rdi), %ymm2 ++ VPCMPEQ %ymm2, %ymm0, %ymm3 ++ VPCMPEQ %ymm2, %ymm1, %ymm2 ++ vpor %ymm3, %ymm2, %ymm3 ++ vpmovmskb %ymm3, %eax + testl %eax, %eax + jnz L(first_vec_x4) +- /* Align data to VEC_SIZE * 4 - 1. */ +- addq $(VEC_SIZE * 4 + 1), %rdi +- andq $-(VEC_SIZE * 4), %rdi ++ /* Align data to VEC_SIZE * 4 - 1. */ ++ incq %rdi ++ orq $(VEC_SIZE * 4 - 1), %rdi + .p2align 4 + L(loop_4x_vec): + /* Compare 4 * VEC at a time forward. */ +- vmovdqa (%rdi), %ymm5 +- vmovdqa (VEC_SIZE)(%rdi), %ymm6 +- vmovdqa (VEC_SIZE * 2)(%rdi), %ymm7 +- vmovdqa (VEC_SIZE * 3)(%rdi), %ymm8 ++ vmovdqa 1(%rdi), %ymm6 ++ vmovdqa (VEC_SIZE + 1)(%rdi), %ymm7 + + /* Leaves only CHARS matching esi as 0. */ +- vpxor %ymm5, %ymm0, %ymm1 + vpxor %ymm6, %ymm0, %ymm2 + vpxor %ymm7, %ymm0, %ymm3 +- vpxor %ymm8, %ymm0, %ymm4 + +- VPMINU %ymm1, %ymm5, %ymm1 + VPMINU %ymm2, %ymm6, %ymm2 + VPMINU %ymm3, %ymm7, %ymm3 +- VPMINU %ymm4, %ymm8, %ymm4 + +- VPMINU %ymm1, %ymm2, %ymm5 +- VPMINU %ymm3, %ymm4, %ymm6 ++ vmovdqa (VEC_SIZE * 2 + 1)(%rdi), %ymm6 ++ vmovdqa (VEC_SIZE * 3 + 1)(%rdi), %ymm7 ++ ++ vpxor %ymm6, %ymm0, %ymm4 ++ vpxor %ymm7, %ymm0, %ymm5 ++ ++ VPMINU %ymm4, %ymm6, %ymm4 ++ VPMINU %ymm5, %ymm7, %ymm5 + +- VPMINU %ymm5, %ymm6, %ymm6 ++ VPMINU %ymm2, %ymm3, %ymm6 ++ VPMINU %ymm4, %ymm5, %ymm7 + +- VPCMPEQ %ymm6, %ymm9, %ymm6 +- vpmovmskb %ymm6, %ecx ++ VPMINU %ymm6, %ymm7, %ymm7 ++ ++ VPCMPEQ %ymm7, %ymm1, %ymm7 ++ vpmovmskb %ymm7, %ecx + subq $-(VEC_SIZE * 4), %rdi + testl %ecx, %ecx + jz L(loop_4x_vec) + +- +- VPCMPEQ %ymm1, %ymm9, %ymm1 +- vpmovmskb %ymm1, %eax ++ VPCMPEQ %ymm2, %ymm1, %ymm2 ++ vpmovmskb %ymm2, %eax + testl %eax, %eax + jnz L(last_vec_x0) + + +- VPCMPEQ %ymm5, %ymm9, %ymm2 +- vpmovmskb %ymm2, %eax ++ VPCMPEQ %ymm3, %ymm1, %ymm3 ++ vpmovmskb %ymm3, %eax + testl %eax, %eax + jnz L(last_vec_x1) + +- VPCMPEQ %ymm3, %ymm9, %ymm3 +- vpmovmskb %ymm3, %eax ++ VPCMPEQ %ymm4, %ymm1, %ymm4 ++ vpmovmskb %ymm4, %eax + /* rcx has combined result from all 4 VEC. It will only be used + if the first 3 other VEC all did not contain a match. */ + salq $32, %rcx + orq %rcx, %rax + tzcntq %rax, %rax +- subq $(VEC_SIZE * 2), %rdi ++ subq $(VEC_SIZE * 2 - 1), %rdi + # ifndef USE_AS_STRCHRNUL + /* Found CHAR or the null byte. */ + cmp (%rdi, %rax), %CHAR_REG +@@ -239,10 +251,11 @@ L(loop_4x_vec): + VZEROUPPER_RETURN + + +- .p2align 4 ++ .p2align 4,, 10 + L(last_vec_x0): +- tzcntl %eax, %eax +- addq $-(VEC_SIZE * 4), %rdi ++ /* Use bsf to save code size. */ ++ bsfl %eax, %eax ++ addq $-(VEC_SIZE * 4 - 1), %rdi + # ifndef USE_AS_STRCHRNUL + /* Found CHAR or the null byte. */ + cmp (%rdi, %rax), %CHAR_REG +@@ -251,16 +264,11 @@ L(last_vec_x0): + addq %rdi, %rax + VZEROUPPER_RETURN + +-# ifndef USE_AS_STRCHRNUL +-L(zero_end): +- xorl %eax, %eax +- VZEROUPPER_RETURN +-# endif + +- .p2align 4 ++ .p2align 4,, 10 + L(last_vec_x1): + tzcntl %eax, %eax +- subq $(VEC_SIZE * 3), %rdi ++ subq $(VEC_SIZE * 3 - 1), %rdi + # ifndef USE_AS_STRCHRNUL + /* Found CHAR or the null byte. */ + cmp (%rdi, %rax), %CHAR_REG +@@ -269,18 +277,23 @@ L(last_vec_x1): + addq %rdi, %rax + VZEROUPPER_RETURN + ++# ifndef USE_AS_STRCHRNUL ++L(zero_end): ++ xorl %eax, %eax ++ VZEROUPPER_RETURN ++# endif + + /* Cold case for crossing page with first load. */ +- .p2align 4 ++ .p2align 4,, 8 + L(cross_page_boundary): + movq %rdi, %rdx + /* Align rdi to VEC_SIZE - 1. */ + orq $(VEC_SIZE - 1), %rdi +- vmovdqa -(VEC_SIZE - 1)(%rdi), %ymm8 +- VPCMPEQ %ymm8, %ymm0, %ymm1 +- VPCMPEQ %ymm8, %ymm9, %ymm2 +- vpor %ymm1, %ymm2, %ymm1 +- vpmovmskb %ymm1, %eax ++ vmovdqa -(VEC_SIZE - 1)(%rdi), %ymm2 ++ VPCMPEQ %ymm2, %ymm0, %ymm3 ++ VPCMPEQ %ymm2, %ymm1, %ymm2 ++ vpor %ymm3, %ymm2, %ymm3 ++ vpmovmskb %ymm3, %eax + /* Remove the leading bytes. sarxl only uses bits [5:0] of COUNT + so no need to manually mod edx. */ + sarxl %edx, %eax, %eax +@@ -291,13 +304,10 @@ L(cross_page_boundary): + xorl %ecx, %ecx + /* Found CHAR or the null byte. */ + cmp (%rdx, %rax), %CHAR_REG +- leaq (%rdx, %rax), %rax +- cmovne %rcx, %rax +-# else +- addq %rdx, %rax ++ jne L(zero_end) + # endif +-L(return_vzeroupper): +- ZERO_UPPER_VEC_REGISTERS_RETURN ++ addq %rdx, %rax ++ VZEROUPPER_RETURN + + END (STRCHR) +-# endif ++#endif +-- +GitLab + diff --git a/SOURCES/glibc-RHEL-15696-89.patch b/SOURCES/glibc-RHEL-15696-89.patch new file mode 100644 index 0000000..45ee946 --- /dev/null +++ b/SOURCES/glibc-RHEL-15696-89.patch @@ -0,0 +1,343 @@ +From ec285ea90415458225623ddc0492ae3f705af043 Mon Sep 17 00:00:00 2001 +From: Noah Goldstein +Date: Wed, 23 Mar 2022 16:57:18 -0500 +Subject: [PATCH] x86: Code cleanup in strchr-evex and comment justifying + branch +Content-type: text/plain; charset=UTF-8 + +Small code cleanup for size: -81 bytes. + +Add comment justifying using a branch to do NULL/non-null return. + +All string/memory tests pass and no regressions in benchtests. + +geometric_mean(N=20) of all benchmarks New / Original: .985 +Reviewed-by: H.J. Lu +--- + sysdeps/x86_64/multiarch/strchr-evex.S | 146 ++++++++++++++----------- + 1 file changed, 80 insertions(+), 66 deletions(-) + +diff --git a/sysdeps/x86_64/multiarch/strchr-evex.S b/sysdeps/x86_64/multiarch/strchr-evex.S +index 7f9d4ee4..0b49e0ac 100644 +--- a/sysdeps/x86_64/multiarch/strchr-evex.S ++++ b/sysdeps/x86_64/multiarch/strchr-evex.S +@@ -30,6 +30,7 @@ + # ifdef USE_AS_WCSCHR + # define VPBROADCAST vpbroadcastd + # define VPCMP vpcmpd ++# define VPTESTN vptestnmd + # define VPMINU vpminud + # define CHAR_REG esi + # define SHIFT_REG ecx +@@ -37,6 +38,7 @@ + # else + # define VPBROADCAST vpbroadcastb + # define VPCMP vpcmpb ++# define VPTESTN vptestnmb + # define VPMINU vpminub + # define CHAR_REG sil + # define SHIFT_REG edx +@@ -61,13 +63,11 @@ + # define CHAR_PER_VEC (VEC_SIZE / CHAR_SIZE) + + .section .text.evex,"ax",@progbits +-ENTRY (STRCHR) ++ENTRY_P2ALIGN (STRCHR, 5) + /* Broadcast CHAR to YMM0. */ + VPBROADCAST %esi, %YMM0 + movl %edi, %eax + andl $(PAGE_SIZE - 1), %eax +- vpxorq %XMMZERO, %XMMZERO, %XMMZERO +- + /* Check if we cross page boundary with one vector load. + Otherwise it is safe to use an unaligned load. */ + cmpl $(PAGE_SIZE - VEC_SIZE), %eax +@@ -81,49 +81,35 @@ ENTRY (STRCHR) + vpxorq %YMM1, %YMM0, %YMM2 + VPMINU %YMM2, %YMM1, %YMM2 + /* Each bit in K0 represents a CHAR or a null byte in YMM1. */ +- VPCMP $0, %YMMZERO, %YMM2, %k0 ++ VPTESTN %YMM2, %YMM2, %k0 + kmovd %k0, %eax + testl %eax, %eax + jz L(aligned_more) + tzcntl %eax, %eax ++# ifndef USE_AS_STRCHRNUL ++ /* Found CHAR or the null byte. */ ++ cmp (%rdi, %rax, CHAR_SIZE), %CHAR_REG ++ /* NB: Use a branch instead of cmovcc here. The expectation is ++ that with strchr the user will branch based on input being ++ null. Since this branch will be 100% predictive of the user ++ branch a branch miss here should save what otherwise would ++ be branch miss in the user code. Otherwise using a branch 1) ++ saves code size and 2) is faster in highly predictable ++ environments. */ ++ jne L(zero) ++# endif + # ifdef USE_AS_WCSCHR + /* NB: Multiply wchar_t count by 4 to get the number of bytes. + */ + leaq (%rdi, %rax, CHAR_SIZE), %rax + # else + addq %rdi, %rax +-# endif +-# ifndef USE_AS_STRCHRNUL +- /* Found CHAR or the null byte. */ +- cmp (%rax), %CHAR_REG +- jne L(zero) + # endif + ret + +- /* .p2align 5 helps keep performance more consistent if ENTRY() +- alignment % 32 was either 16 or 0. As well this makes the +- alignment % 32 of the loop_4x_vec fixed which makes tuning it +- easier. */ +- .p2align 5 +-L(first_vec_x3): +- tzcntl %eax, %eax +-# ifndef USE_AS_STRCHRNUL +- /* Found CHAR or the null byte. */ +- cmp (VEC_SIZE * 3)(%rdi, %rax, CHAR_SIZE), %CHAR_REG +- jne L(zero) +-# endif +- /* NB: Multiply sizeof char type (1 or 4) to get the number of +- bytes. */ +- leaq (VEC_SIZE * 3)(%rdi, %rax, CHAR_SIZE), %rax +- ret + +-# ifndef USE_AS_STRCHRNUL +-L(zero): +- xorl %eax, %eax +- ret +-# endif + +- .p2align 4 ++ .p2align 4,, 10 + L(first_vec_x4): + # ifndef USE_AS_STRCHRNUL + /* Check to see if first match was CHAR (k0) or null (k1). */ +@@ -144,9 +130,18 @@ L(first_vec_x4): + leaq (VEC_SIZE * 4)(%rdi, %rax, CHAR_SIZE), %rax + ret + ++# ifndef USE_AS_STRCHRNUL ++L(zero): ++ xorl %eax, %eax ++ ret ++# endif ++ ++ + .p2align 4 + L(first_vec_x1): +- tzcntl %eax, %eax ++ /* Use bsf here to save 1-byte keeping keeping the block in 1x ++ fetch block. eax guranteed non-zero. */ ++ bsfl %eax, %eax + # ifndef USE_AS_STRCHRNUL + /* Found CHAR or the null byte. */ + cmp (VEC_SIZE)(%rdi, %rax, CHAR_SIZE), %CHAR_REG +@@ -158,7 +153,7 @@ L(first_vec_x1): + leaq (VEC_SIZE)(%rdi, %rax, CHAR_SIZE), %rax + ret + +- .p2align 4 ++ .p2align 4,, 10 + L(first_vec_x2): + # ifndef USE_AS_STRCHRNUL + /* Check to see if first match was CHAR (k0) or null (k1). */ +@@ -179,6 +174,21 @@ L(first_vec_x2): + leaq (VEC_SIZE * 2)(%rdi, %rax, CHAR_SIZE), %rax + ret + ++ .p2align 4,, 10 ++L(first_vec_x3): ++ /* Use bsf here to save 1-byte keeping keeping the block in 1x ++ fetch block. eax guranteed non-zero. */ ++ bsfl %eax, %eax ++# ifndef USE_AS_STRCHRNUL ++ /* Found CHAR or the null byte. */ ++ cmp (VEC_SIZE * 3)(%rdi, %rax, CHAR_SIZE), %CHAR_REG ++ jne L(zero) ++# endif ++ /* NB: Multiply sizeof char type (1 or 4) to get the number of ++ bytes. */ ++ leaq (VEC_SIZE * 3)(%rdi, %rax, CHAR_SIZE), %rax ++ ret ++ + .p2align 4 + L(aligned_more): + /* Align data to VEC_SIZE. */ +@@ -195,7 +205,7 @@ L(cross_page_continue): + vpxorq %YMM1, %YMM0, %YMM2 + VPMINU %YMM2, %YMM1, %YMM2 + /* Each bit in K0 represents a CHAR or a null byte in YMM1. */ +- VPCMP $0, %YMMZERO, %YMM2, %k0 ++ VPTESTN %YMM2, %YMM2, %k0 + kmovd %k0, %eax + testl %eax, %eax + jnz L(first_vec_x1) +@@ -206,7 +216,7 @@ L(cross_page_continue): + /* Each bit in K0 represents a CHAR in YMM1. */ + VPCMP $0, %YMM1, %YMM0, %k0 + /* Each bit in K1 represents a CHAR in YMM1. */ +- VPCMP $0, %YMM1, %YMMZERO, %k1 ++ VPTESTN %YMM1, %YMM1, %k1 + kortestd %k0, %k1 + jnz L(first_vec_x2) + +@@ -215,7 +225,7 @@ L(cross_page_continue): + vpxorq %YMM1, %YMM0, %YMM2 + VPMINU %YMM2, %YMM1, %YMM2 + /* Each bit in K0 represents a CHAR or a null byte in YMM1. */ +- VPCMP $0, %YMMZERO, %YMM2, %k0 ++ VPTESTN %YMM2, %YMM2, %k0 + kmovd %k0, %eax + testl %eax, %eax + jnz L(first_vec_x3) +@@ -224,7 +234,7 @@ L(cross_page_continue): + /* Each bit in K0 represents a CHAR in YMM1. */ + VPCMP $0, %YMM1, %YMM0, %k0 + /* Each bit in K1 represents a CHAR in YMM1. */ +- VPCMP $0, %YMM1, %YMMZERO, %k1 ++ VPTESTN %YMM1, %YMM1, %k1 + kortestd %k0, %k1 + jnz L(first_vec_x4) + +@@ -265,33 +275,33 @@ L(loop_4x_vec): + VPMINU %YMM3, %YMM4, %YMM4 + VPMINU %YMM2, %YMM4, %YMM4{%k4}{z} + +- VPCMP $0, %YMMZERO, %YMM4, %k1 ++ VPTESTN %YMM4, %YMM4, %k1 + kmovd %k1, %ecx + subq $-(VEC_SIZE * 4), %rdi + testl %ecx, %ecx + jz L(loop_4x_vec) + +- VPCMP $0, %YMMZERO, %YMM1, %k0 ++ VPTESTN %YMM1, %YMM1, %k0 + kmovd %k0, %eax + testl %eax, %eax + jnz L(last_vec_x1) + +- VPCMP $0, %YMMZERO, %YMM2, %k0 ++ VPTESTN %YMM2, %YMM2, %k0 + kmovd %k0, %eax + testl %eax, %eax + jnz L(last_vec_x2) + +- VPCMP $0, %YMMZERO, %YMM3, %k0 ++ VPTESTN %YMM3, %YMM3, %k0 + kmovd %k0, %eax + /* Combine YMM3 matches (eax) with YMM4 matches (ecx). */ + # ifdef USE_AS_WCSCHR + sall $8, %ecx + orl %ecx, %eax +- tzcntl %eax, %eax ++ bsfl %eax, %eax + # else + salq $32, %rcx + orq %rcx, %rax +- tzcntq %rax, %rax ++ bsfq %rax, %rax + # endif + # ifndef USE_AS_STRCHRNUL + /* Check if match was CHAR or null. */ +@@ -303,28 +313,28 @@ L(loop_4x_vec): + leaq (VEC_SIZE * 2)(%rdi, %rax, CHAR_SIZE), %rax + ret + +-# ifndef USE_AS_STRCHRNUL +-L(zero_end): +- xorl %eax, %eax +- ret ++ .p2align 4,, 8 ++L(last_vec_x1): ++ bsfl %eax, %eax ++# ifdef USE_AS_WCSCHR ++ /* NB: Multiply wchar_t count by 4 to get the number of bytes. ++ */ ++ leaq (%rdi, %rax, CHAR_SIZE), %rax ++# else ++ addq %rdi, %rax + # endif + +- .p2align 4 +-L(last_vec_x1): +- tzcntl %eax, %eax + # ifndef USE_AS_STRCHRNUL + /* Check if match was null. */ +- cmp (%rdi, %rax, CHAR_SIZE), %CHAR_REG ++ cmp (%rax), %CHAR_REG + jne L(zero_end) + # endif +- /* NB: Multiply sizeof char type (1 or 4) to get the number of +- bytes. */ +- leaq (%rdi, %rax, CHAR_SIZE), %rax ++ + ret + +- .p2align 4 ++ .p2align 4,, 8 + L(last_vec_x2): +- tzcntl %eax, %eax ++ bsfl %eax, %eax + # ifndef USE_AS_STRCHRNUL + /* Check if match was null. */ + cmp (VEC_SIZE)(%rdi, %rax, CHAR_SIZE), %CHAR_REG +@@ -336,7 +346,7 @@ L(last_vec_x2): + ret + + /* Cold case for crossing page with first load. */ +- .p2align 4 ++ .p2align 4,, 8 + L(cross_page_boundary): + movq %rdi, %rdx + /* Align rdi. */ +@@ -346,9 +356,9 @@ L(cross_page_boundary): + vpxorq %YMM1, %YMM0, %YMM2 + VPMINU %YMM2, %YMM1, %YMM2 + /* Each bit in K0 represents a CHAR or a null byte in YMM1. */ +- VPCMP $0, %YMMZERO, %YMM2, %k0 ++ VPTESTN %YMM2, %YMM2, %k0 + kmovd %k0, %eax +- /* Remove the leading bits. */ ++ /* Remove the leading bits. */ + # ifdef USE_AS_WCSCHR + movl %edx, %SHIFT_REG + /* NB: Divide shift count by 4 since each bit in K1 represent 4 +@@ -360,20 +370,24 @@ L(cross_page_boundary): + /* If eax is zero continue. */ + testl %eax, %eax + jz L(cross_page_continue) +- tzcntl %eax, %eax +-# ifndef USE_AS_STRCHRNUL +- /* Check to see if match was CHAR or null. */ +- cmp (%rdx, %rax, CHAR_SIZE), %CHAR_REG +- jne L(zero_end) +-# endif ++ bsfl %eax, %eax ++ + # ifdef USE_AS_WCSCHR + /* NB: Multiply wchar_t count by 4 to get the number of + bytes. */ + leaq (%rdx, %rax, CHAR_SIZE), %rax + # else + addq %rdx, %rax ++# endif ++# ifndef USE_AS_STRCHRNUL ++ /* Check to see if match was CHAR or null. */ ++ cmp (%rax), %CHAR_REG ++ je L(cross_page_ret) ++L(zero_end): ++ xorl %eax, %eax ++L(cross_page_ret): + # endif + ret + + END (STRCHR) +-# endif ++#endif +-- +GitLab + diff --git a/SOURCES/glibc-RHEL-15696-9.patch b/SOURCES/glibc-RHEL-15696-9.patch new file mode 100644 index 0000000..5aa3e7b --- /dev/null +++ b/SOURCES/glibc-RHEL-15696-9.patch @@ -0,0 +1,206 @@ +From 3f635fb43389b54f682fc9ed2acc0b2aaf4a923d Mon Sep 17 00:00:00 2001 +From: "H.J. Lu" +Date: Mon, 4 Feb 2019 06:31:01 -0800 +Subject: [PATCH] x86-64 memcmp: Use unsigned Jcc instructions on size [BZ + #24155] +Content-type: text/plain; charset=UTF-8 + +Since the size argument is unsigned. we should use unsigned Jcc +instructions, instead of signed, to check size. + +Tested on x86-64 and x32, with and without --disable-multi-arch. + + [BZ #24155] + CVE-2019-7309 + * NEWS: Updated for CVE-2019-7309. + * sysdeps/x86_64/memcmp.S: Use RDX_LP for size. Clear the + upper 32 bits of RDX register for x32. Use unsigned Jcc + instructions, instead of signed. + * sysdeps/x86_64/x32/Makefile (tests): Add tst-size_t-memcmp-2. + * sysdeps/x86_64/x32/tst-size_t-memcmp-2.c: New test. +--- + sysdeps/x86_64/memcmp.S | 20 +++--- + sysdeps/x86_64/x32/Makefile | 3 +- + sysdeps/x86_64/x32/tst-size_t-memcmp-2.c | 79 ++++++++++++++++++++++++ + 3 files changed, 93 insertions(+), 9 deletions(-) + create mode 100644 sysdeps/x86_64/x32/tst-size_t-memcmp-2.c + +Conflics: + ChangeLog + (removed) + NEWS + (removed) + +diff --git a/sysdeps/x86_64/memcmp.S b/sysdeps/x86_64/memcmp.S +index bcb4a2e8..45918d37 100644 +--- a/sysdeps/x86_64/memcmp.S ++++ b/sysdeps/x86_64/memcmp.S +@@ -21,14 +21,18 @@ + + .text + ENTRY (memcmp) +- test %rdx, %rdx ++#ifdef __ILP32__ ++ /* Clear the upper 32 bits. */ ++ movl %edx, %edx ++#endif ++ test %RDX_LP, %RDX_LP + jz L(finz) + cmpq $1, %rdx +- jle L(finr1b) ++ jbe L(finr1b) + subq %rdi, %rsi + movq %rdx, %r10 + cmpq $32, %r10 +- jge L(gt32) ++ jae L(gt32) + /* Handle small chunks and last block of less than 32 bytes. */ + L(small): + testq $1, %r10 +@@ -156,7 +160,7 @@ L(A32): + movq %r11, %r10 + andq $-32, %r10 + cmpq %r10, %rdi +- jge L(mt16) ++ jae L(mt16) + /* Pre-unroll to be ready for unrolled 64B loop. */ + testq $32, %rdi + jz L(A64) +@@ -178,7 +182,7 @@ L(A64): + movq %r11, %r10 + andq $-64, %r10 + cmpq %r10, %rdi +- jge L(mt32) ++ jae L(mt32) + + L(A64main): + movdqu (%rdi,%rsi), %xmm0 +@@ -216,7 +220,7 @@ L(mt32): + movq %r11, %r10 + andq $-32, %r10 + cmpq %r10, %rdi +- jge L(mt16) ++ jae L(mt16) + + L(A32main): + movdqu (%rdi,%rsi), %xmm0 +@@ -254,7 +258,7 @@ L(ATR): + movq %r11, %r10 + andq $-32, %r10 + cmpq %r10, %rdi +- jge L(mt16) ++ jae L(mt16) + testq $16, %rdi + jz L(ATR32) + +@@ -325,7 +329,7 @@ L(ATR64main): + movq %r11, %r10 + andq $-32, %r10 + cmpq %r10, %rdi +- jge L(mt16) ++ jae L(mt16) + + L(ATR32res): + movdqa (%rdi,%rsi), %xmm0 +diff --git a/sysdeps/x86_64/x32/Makefile b/sysdeps/x86_64/x32/Makefile +index 1557724b..87489565 100644 +--- a/sysdeps/x86_64/x32/Makefile ++++ b/sysdeps/x86_64/x32/Makefile +@@ -8,7 +8,8 @@ endif + ifeq ($(subdir),string) + tests += tst-size_t-memchr tst-size_t-memcmp tst-size_t-memcpy \ + tst-size_t-memrchr tst-size_t-memset tst-size_t-strncasecmp \ +- tst-size_t-strncmp tst-size_t-strncpy tst-size_t-strnlen ++ tst-size_t-strncmp tst-size_t-strncpy tst-size_t-strnlen \ ++ tst-size_t-memcmp-2 + endif + + ifeq ($(subdir),wcsmbs) +diff --git a/sysdeps/x86_64/x32/tst-size_t-memcmp-2.c b/sysdeps/x86_64/x32/tst-size_t-memcmp-2.c +new file mode 100644 +index 00000000..d8ae1a08 +--- /dev/null ++++ b/sysdeps/x86_64/x32/tst-size_t-memcmp-2.c +@@ -0,0 +1,79 @@ ++/* Test memcmp with size_t in the lower 32 bits of 64-bit register. ++ 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, see ++ . */ ++ ++#define TEST_MAIN ++#ifdef WIDE ++# define TEST_NAME "wmemcmp" ++#else ++# define TEST_NAME "memcmp" ++#endif ++ ++#include "test-size_t.h" ++ ++#ifdef WIDE ++# include ++# include ++ ++# define MEMCMP wmemcmp ++# define CHAR wchar_t ++#else ++# define MEMCMP memcmp ++# define CHAR char ++#endif ++ ++IMPL (MEMCMP, 1) ++ ++typedef int (*proto_t) (const CHAR *, const CHAR *, size_t); ++ ++static int ++__attribute__ ((noinline, noclone)) ++do_memcmp (parameter_t a, parameter_t b) ++{ ++ return CALL (&b, a.p, b.p, a.len); ++} ++ ++static int ++test_main (void) ++{ ++ test_init (); ++ ++ parameter_t dest = { { page_size / sizeof (CHAR) }, buf1 }; ++ parameter_t src = { { 0 }, buf2 }; ++ ++ memcpy (buf1, buf2, page_size); ++ ++ CHAR *p = (CHAR *) buf1; ++ p[page_size / sizeof (CHAR) - 1] = (CHAR) 1; ++ ++ int ret = 0; ++ FOR_EACH_IMPL (impl, 0) ++ { ++ src.fn = impl->fn; ++ int res = do_memcmp (dest, src); ++ if (res >= 0) ++ { ++ error (0, 0, "Wrong result in function %s: %i >= 0", ++ impl->name, res); ++ ret = 1; ++ } ++ } ++ ++ return ret ? EXIT_FAILURE : EXIT_SUCCESS; ++} ++ ++#include +-- +GitLab + diff --git a/SOURCES/glibc-RHEL-15696-90.patch b/SOURCES/glibc-RHEL-15696-90.patch new file mode 100644 index 0000000..11835aa --- /dev/null +++ b/SOURCES/glibc-RHEL-15696-90.patch @@ -0,0 +1,147 @@ +From 30d627d477d7255345a4b713cf352ac32d644d61 Mon Sep 17 00:00:00 2001 +From: Noah Goldstein +Date: Wed, 23 Mar 2022 16:57:22 -0500 +Subject: [PATCH] x86: Optimize strcspn and strpbrk in strcspn-c.c +Content-type: text/plain; charset=UTF-8 + +Use _mm_cmpeq_epi8 and _mm_movemask_epi8 to get strlen instead of +_mm_cmpistri. Also change offset to unsigned to avoid unnecessary +sign extensions. + +geometric_mean(N=20) of all benchmarks that dont fallback on +sse2/strlen; New / Original: .928 + +All string/memory tests pass. +Reviewed-by: H.J. Lu +--- + sysdeps/x86_64/multiarch/strcspn-c.c | 83 +++++++++++++--------------- + 1 file changed, 37 insertions(+), 46 deletions(-) + +diff --git a/sysdeps/x86_64/multiarch/strcspn-c.c b/sysdeps/x86_64/multiarch/strcspn-c.c +index 857af104..6cce4296 100644 +--- a/sysdeps/x86_64/multiarch/strcspn-c.c ++++ b/sysdeps/x86_64/multiarch/strcspn-c.c +@@ -85,83 +85,74 @@ STRCSPN_SSE42 (const char *s, const char *a) + RETURN (NULL, strlen (s)); + + const char *aligned; +- __m128i mask; +- int offset = (int) ((size_t) a & 15); ++ __m128i mask, maskz, zero; ++ unsigned int maskz_bits; ++ unsigned int offset = (unsigned int) ((size_t) a & 15); ++ zero = _mm_set1_epi8 (0); + if (offset != 0) + { + /* Load masks. */ + aligned = (const char *) ((size_t) a & -16L); + __m128i mask0 = _mm_load_si128 ((__m128i *) aligned); +- +- mask = __m128i_shift_right (mask0, offset); ++ maskz = _mm_cmpeq_epi8 (mask0, zero); + + /* Find where the NULL terminator is. */ +- int length = _mm_cmpistri (mask, mask, 0x3a); +- if (length == 16 - offset) +- { +- /* There is no NULL terminator. */ +- __m128i mask1 = _mm_load_si128 ((__m128i *) (aligned + 16)); +- int index = _mm_cmpistri (mask1, mask1, 0x3a); +- length += index; +- +- /* Don't use SSE4.2 if the length of A > 16. */ +- if (length > 16) +- return STRCSPN_SSE2 (s, a); +- +- if (index != 0) +- { +- /* Combine mask0 and mask1. We could play games with +- palignr, but frankly this data should be in L1 now +- so do the merge via an unaligned load. */ +- mask = _mm_loadu_si128 ((__m128i *) a); +- } +- } ++ maskz_bits = _mm_movemask_epi8 (maskz) >> offset; ++ if (maskz_bits != 0) ++ { ++ mask = __m128i_shift_right (mask0, offset); ++ offset = (unsigned int) ((size_t) s & 15); ++ if (offset) ++ goto start_unaligned; ++ ++ aligned = s; ++ goto start_loop; ++ } + } +- else +- { +- /* A is aligned. */ +- mask = _mm_load_si128 ((__m128i *) a); + +- /* Find where the NULL terminator is. */ +- int length = _mm_cmpistri (mask, mask, 0x3a); +- if (length == 16) +- { +- /* There is no NULL terminator. Don't use SSE4.2 if the length +- of A > 16. */ +- if (a[16] != 0) +- return STRCSPN_SSE2 (s, a); +- } ++ /* A is aligned. */ ++ mask = _mm_loadu_si128 ((__m128i *) a); ++ /* Find where the NULL terminator is. */ ++ maskz = _mm_cmpeq_epi8 (mask, zero); ++ maskz_bits = _mm_movemask_epi8 (maskz); ++ if (maskz_bits == 0) ++ { ++ /* There is no NULL terminator. Don't use SSE4.2 if the length ++ of A > 16. */ ++ if (a[16] != 0) ++ return STRCSPN_SSE2 (s, a); + } + +- offset = (int) ((size_t) s & 15); ++ aligned = s; ++ offset = (unsigned int) ((size_t) s & 15); + if (offset != 0) + { ++ start_unaligned: + /* Check partial string. */ + aligned = (const char *) ((size_t) s & -16L); + __m128i value = _mm_load_si128 ((__m128i *) aligned); + + value = __m128i_shift_right (value, offset); + +- int length = _mm_cmpistri (mask, value, 0x2); ++ unsigned int length = _mm_cmpistri (mask, value, 0x2); + /* No need to check ZFlag since ZFlag is always 1. */ +- int cflag = _mm_cmpistrc (mask, value, 0x2); ++ unsigned int cflag = _mm_cmpistrc (mask, value, 0x2); + if (cflag) + RETURN ((char *) (s + length), length); + /* Find where the NULL terminator is. */ +- int index = _mm_cmpistri (value, value, 0x3a); ++ unsigned int index = _mm_cmpistri (value, value, 0x3a); + if (index < 16 - offset) + RETURN (NULL, index); + aligned += 16; + } +- else +- aligned = s; + ++start_loop: + while (1) + { + __m128i value = _mm_load_si128 ((__m128i *) aligned); +- int index = _mm_cmpistri (mask, value, 0x2); +- int cflag = _mm_cmpistrc (mask, value, 0x2); +- int zflag = _mm_cmpistrz (mask, value, 0x2); ++ unsigned int index = _mm_cmpistri (mask, value, 0x2); ++ unsigned int cflag = _mm_cmpistrc (mask, value, 0x2); ++ unsigned int zflag = _mm_cmpistrz (mask, value, 0x2); + if (cflag) + RETURN ((char *) (aligned + index), (size_t) (aligned + index - s)); + if (zflag) +-- +GitLab + diff --git a/SOURCES/glibc-RHEL-15696-91.patch b/SOURCES/glibc-RHEL-15696-91.patch new file mode 100644 index 0000000..de3c8ec --- /dev/null +++ b/SOURCES/glibc-RHEL-15696-91.patch @@ -0,0 +1,147 @@ +From 412d10343168b05b8cf6c3683457cf9711d28046 Mon Sep 17 00:00:00 2001 +From: Noah Goldstein +Date: Wed, 23 Mar 2022 16:57:24 -0500 +Subject: [PATCH] x86: Optimize strspn in strspn-c.c +Content-type: text/plain; charset=UTF-8 + +Use _mm_cmpeq_epi8 and _mm_movemask_epi8 to get strlen instead of +_mm_cmpistri. Also change offset to unsigned to avoid unnecessary +sign extensions. + +geometric_mean(N=20) of all benchmarks that dont fallback on +sse2; New / Original: .901 + +All string/memory tests pass. +Reviewed-by: H.J. Lu +--- + sysdeps/x86_64/multiarch/strspn-c.c | 86 +++++++++++++---------------- + 1 file changed, 39 insertions(+), 47 deletions(-) + +diff --git a/sysdeps/x86_64/multiarch/strspn-c.c b/sysdeps/x86_64/multiarch/strspn-c.c +index 4554cff0..87c5e4bf 100644 +--- a/sysdeps/x86_64/multiarch/strspn-c.c ++++ b/sysdeps/x86_64/multiarch/strspn-c.c +@@ -63,81 +63,73 @@ __strspn_sse42 (const char *s, const char *a) + return 0; + + const char *aligned; +- __m128i mask; +- int offset = (int) ((size_t) a & 15); ++ __m128i mask, maskz, zero; ++ unsigned int maskz_bits; ++ unsigned int offset = (int) ((size_t) a & 15); ++ zero = _mm_set1_epi8 (0); + if (offset != 0) + { + /* Load masks. */ + aligned = (const char *) ((size_t) a & -16L); + __m128i mask0 = _mm_load_si128 ((__m128i *) aligned); +- +- mask = __m128i_shift_right (mask0, offset); ++ maskz = _mm_cmpeq_epi8 (mask0, zero); + + /* Find where the NULL terminator is. */ +- int length = _mm_cmpistri (mask, mask, 0x3a); +- if (length == 16 - offset) +- { +- /* There is no NULL terminator. */ +- __m128i mask1 = _mm_load_si128 ((__m128i *) (aligned + 16)); +- int index = _mm_cmpistri (mask1, mask1, 0x3a); +- length += index; +- +- /* Don't use SSE4.2 if the length of A > 16. */ +- if (length > 16) +- return __strspn_sse2 (s, a); +- +- if (index != 0) +- { +- /* Combine mask0 and mask1. We could play games with +- palignr, but frankly this data should be in L1 now +- so do the merge via an unaligned load. */ +- mask = _mm_loadu_si128 ((__m128i *) a); +- } +- } ++ maskz_bits = _mm_movemask_epi8 (maskz) >> offset; ++ if (maskz_bits != 0) ++ { ++ mask = __m128i_shift_right (mask0, offset); ++ offset = (unsigned int) ((size_t) s & 15); ++ if (offset) ++ goto start_unaligned; ++ ++ aligned = s; ++ goto start_loop; ++ } + } +- else +- { +- /* A is aligned. */ +- mask = _mm_load_si128 ((__m128i *) a); + +- /* Find where the NULL terminator is. */ +- int length = _mm_cmpistri (mask, mask, 0x3a); +- if (length == 16) +- { +- /* There is no NULL terminator. Don't use SSE4.2 if the length +- of A > 16. */ +- if (a[16] != 0) +- return __strspn_sse2 (s, a); +- } ++ /* A is aligned. */ ++ mask = _mm_loadu_si128 ((__m128i *) a); ++ ++ /* Find where the NULL terminator is. */ ++ maskz = _mm_cmpeq_epi8 (mask, zero); ++ maskz_bits = _mm_movemask_epi8 (maskz); ++ if (maskz_bits == 0) ++ { ++ /* There is no NULL terminator. Don't use SSE4.2 if the length ++ of A > 16. */ ++ if (a[16] != 0) ++ return __strspn_sse2 (s, a); + } ++ aligned = s; ++ offset = (unsigned int) ((size_t) s & 15); + +- offset = (int) ((size_t) s & 15); + if (offset != 0) + { ++ start_unaligned: + /* Check partial string. */ + aligned = (const char *) ((size_t) s & -16L); + __m128i value = _mm_load_si128 ((__m128i *) aligned); ++ __m128i adj_value = __m128i_shift_right (value, offset); + +- value = __m128i_shift_right (value, offset); +- +- int length = _mm_cmpistri (mask, value, 0x12); ++ unsigned int length = _mm_cmpistri (mask, adj_value, 0x12); + /* No need to check CFlag since it is always 1. */ + if (length < 16 - offset) + return length; + /* Find where the NULL terminator is. */ +- int index = _mm_cmpistri (value, value, 0x3a); +- if (index < 16 - offset) ++ maskz = _mm_cmpeq_epi8 (value, zero); ++ maskz_bits = _mm_movemask_epi8 (maskz) >> offset; ++ if (maskz_bits != 0) + return length; + aligned += 16; + } +- else +- aligned = s; + ++start_loop: + while (1) + { + __m128i value = _mm_load_si128 ((__m128i *) aligned); +- int index = _mm_cmpistri (mask, value, 0x12); +- int cflag = _mm_cmpistrc (mask, value, 0x12); ++ unsigned int index = _mm_cmpistri (mask, value, 0x12); ++ unsigned int cflag = _mm_cmpistrc (mask, value, 0x12); + if (cflag) + return (size_t) (aligned + index - s); + aligned += 16; +-- +GitLab + diff --git a/SOURCES/glibc-RHEL-15696-92.patch b/SOURCES/glibc-RHEL-15696-92.patch new file mode 100644 index 0000000..f19914e --- /dev/null +++ b/SOURCES/glibc-RHEL-15696-92.patch @@ -0,0 +1,175 @@ +From fe28e7d9d9535ebab4081d195c553b4fbf39d9ae Mon Sep 17 00:00:00 2001 +From: Noah Goldstein +Date: Wed, 23 Mar 2022 16:57:26 -0500 +Subject: [PATCH] x86: Remove strcspn-sse2.S and use the generic implementation +Content-type: text/plain; charset=UTF-8 + +The generic implementation is faster. + +geometric_mean(N=20) of all benchmarks New / Original: .678 + +All string/memory tests pass. +Reviewed-by: H.J. Lu +--- + .../{strcspn-sse2.S => strcspn-sse2.c} | 6 +- + sysdeps/x86_64/strcspn.S | 122 ------------------ + 2 files changed, 3 insertions(+), 125 deletions(-) + rename sysdeps/x86_64/multiarch/{strcspn-sse2.S => strcspn-sse2.c} (89%) + delete mode 100644 sysdeps/x86_64/strcspn.S + +Conflicts: + sysdeps/x86_64/multiarch/strcspn-sse2.S + (copyright header) + +diff --git a/sysdeps/x86_64/multiarch/strcspn-sse2.S b/sysdeps/x86_64/multiarch/strcspn-sse2.c +similarity index 89% +rename from sysdeps/x86_64/multiarch/strcspn-sse2.S +rename to sysdeps/x86_64/multiarch/strcspn-sse2.c +index 8a0c69d7..32debee4 100644 +--- a/sysdeps/x86_64/multiarch/strcspn-sse2.S ++++ b/sysdeps/x86_64/multiarch/strcspn-sse2.c +@@ -19,10 +19,10 @@ + #if IS_IN (libc) + + # include +-# define strcspn __strcspn_sse2 ++# define STRCSPN __strcspn_sse2 + + # undef libc_hidden_builtin_def +-# define libc_hidden_builtin_def(strcspn) ++# define libc_hidden_builtin_def(STRCSPN) + #endif + +-#include ++#include +diff --git a/sysdeps/x86_64/strcspn.S b/sysdeps/x86_64/strcspn.S +deleted file mode 100644 +index 7f9202d6..00000000 +--- a/sysdeps/x86_64/strcspn.S ++++ /dev/null +@@ -1,122 +0,0 @@ +-/* strcspn (str, ss) -- Return the length of the initial segment of STR +- which contains no characters from SS. +- For AMD x86-64. +- Copyright (C) 1994-2018 Free Software Foundation, Inc. +- This file is part of the GNU C Library. +- Contributed by Ulrich Drepper . +- Bug fixes by Alan Modra . +- Adopted for x86-64 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 +- . */ +- +-#include +-#include "asm-syntax.h" +- +- .text +-ENTRY (strcspn) +- +- movq %rdi, %rdx /* Save SRC. */ +- +- /* First we create a table with flags for all possible characters. +- For the ASCII (7bit/8bit) or ISO-8859-X character sets which are +- supported by the C string functions we have 256 characters. +- Before inserting marks for the stop characters we clear the whole +- table. */ +- movq %rdi, %r8 /* Save value. */ +- subq $256, %rsp /* Make space for 256 bytes. */ +- cfi_adjust_cfa_offset(256) +- movl $32, %ecx /* 32*8 bytes = 256 bytes. */ +- movq %rsp, %rdi +- xorl %eax, %eax /* We store 0s. */ +- cld +- rep +- stosq +- +- movq %rsi, %rax /* Setup skipset. */ +- +-/* For understanding the following code remember that %rcx == 0 now. +- Although all the following instruction only modify %cl we always +- have a correct zero-extended 64-bit value in %rcx. */ +- +- .p2align 4 +-L(2): movb (%rax), %cl /* get byte from skipset */ +- testb %cl, %cl /* is NUL char? */ +- jz L(1) /* yes => start compare loop */ +- movb %cl, (%rsp,%rcx) /* set corresponding byte in skipset table */ +- +- movb 1(%rax), %cl /* get byte from skipset */ +- testb $0xff, %cl /* is NUL char? */ +- jz L(1) /* yes => start compare loop */ +- movb %cl, (%rsp,%rcx) /* set corresponding byte in skipset table */ +- +- movb 2(%rax), %cl /* get byte from skipset */ +- testb $0xff, %cl /* is NUL char? */ +- jz L(1) /* yes => start compare loop */ +- movb %cl, (%rsp,%rcx) /* set corresponding byte in skipset table */ +- +- movb 3(%rax), %cl /* get byte from skipset */ +- addq $4, %rax /* increment skipset pointer */ +- movb %cl, (%rsp,%rcx) /* set corresponding byte in skipset table */ +- testb $0xff, %cl /* is NUL char? */ +- jnz L(2) /* no => process next dword from skipset */ +- +-L(1): leaq -4(%rdx), %rax /* prepare loop */ +- +- /* We use a neat trick for the following loop. Normally we would +- have to test for two termination conditions +- 1. a character in the skipset was found +- and +- 2. the end of the string was found +- But as a sign that the character is in the skipset we store its +- value in the table. But the value of NUL is NUL so the loop +- terminates for NUL in every case. */ +- +- .p2align 4 +-L(3): addq $4, %rax /* adjust pointer for full loop round */ +- +- movb (%rax), %cl /* get byte from string */ +- cmpb %cl, (%rsp,%rcx) /* is it contained in skipset? */ +- je L(4) /* yes => return */ +- +- movb 1(%rax), %cl /* get byte from string */ +- cmpb %cl, (%rsp,%rcx) /* is it contained in skipset? */ +- je L(5) /* yes => return */ +- +- movb 2(%rax), %cl /* get byte from string */ +- cmpb %cl, (%rsp,%rcx) /* is it contained in skipset? */ +- jz L(6) /* yes => return */ +- +- movb 3(%rax), %cl /* get byte from string */ +- cmpb %cl, (%rsp,%rcx) /* is it contained in skipset? */ +- jne L(3) /* no => start loop again */ +- +- incq %rax /* adjust pointer */ +-L(6): incq %rax +-L(5): incq %rax +- +-L(4): addq $256, %rsp /* remove skipset */ +- cfi_adjust_cfa_offset(-256) +-#ifdef USE_AS_STRPBRK +- xorl %edx,%edx +- orb %cl, %cl /* was last character NUL? */ +- cmovzq %rdx, %rax /* Yes: return NULL */ +-#else +- subq %rdx, %rax /* we have to return the number of valid +- characters, so compute distance to first +- non-valid character */ +-#endif +- ret +-END (strcspn) +-libc_hidden_builtin_def (strcspn) +-- +GitLab + diff --git a/SOURCES/glibc-RHEL-15696-93.patch b/SOURCES/glibc-RHEL-15696-93.patch new file mode 100644 index 0000000..45c8527 --- /dev/null +++ b/SOURCES/glibc-RHEL-15696-93.patch @@ -0,0 +1,55 @@ +From 653358535280a599382cb6c77538a187dac6a87f Mon Sep 17 00:00:00 2001 +From: Noah Goldstein +Date: Wed, 23 Mar 2022 16:57:27 -0500 +Subject: [PATCH] x86: Remove strpbrk-sse2.S and use the generic implementation +Content-type: text/plain; charset=UTF-8 + +The generic implementation is faster (see strcspn commit). + +All string/memory tests pass. +Reviewed-by: H.J. Lu +--- + .../x86_64/multiarch/{strpbrk-sse2.S => strpbrk-sse2.c} | 7 +++---- + sysdeps/x86_64/strpbrk.S | 3 --- + 2 files changed, 3 insertions(+), 7 deletions(-) + rename sysdeps/x86_64/multiarch/{strpbrk-sse2.S => strpbrk-sse2.c} (87%) + delete mode 100644 sysdeps/x86_64/strpbrk.S + +Conflicts: + sysdeps/x86_64/multiarch/strpbrk-sse2.S + (copyright header) + +diff --git a/sysdeps/x86_64/multiarch/strpbrk-sse2.S b/sysdeps/x86_64/multiarch/strpbrk-sse2.c +similarity index 87% +rename from sysdeps/x86_64/multiarch/strpbrk-sse2.S +rename to sysdeps/x86_64/multiarch/strpbrk-sse2.c +index 3c6a74db..ec0b6fda 100644 +--- a/sysdeps/x86_64/multiarch/strpbrk-sse2.S ++++ b/sysdeps/x86_64/multiarch/strpbrk-sse2.c +@@ -19,11 +19,10 @@ + #if IS_IN (libc) + + # include +-# define strcspn __strpbrk_sse2 ++# define STRPBRK __strpbrk_sse2 + + # undef libc_hidden_builtin_def +-# define libc_hidden_builtin_def(strpbrk) ++# define libc_hidden_builtin_def(STRPBRK) + #endif + +-#define USE_AS_STRPBRK +-#include ++#include +diff --git a/sysdeps/x86_64/strpbrk.S b/sysdeps/x86_64/strpbrk.S +deleted file mode 100644 +index 21888a5b..00000000 +--- a/sysdeps/x86_64/strpbrk.S ++++ /dev/null +@@ -1,3 +0,0 @@ +-#define strcspn strpbrk +-#define USE_AS_STRPBRK +-#include +-- +GitLab + diff --git a/SOURCES/glibc-RHEL-15696-94.patch b/SOURCES/glibc-RHEL-15696-94.patch new file mode 100644 index 0000000..2fa86da --- /dev/null +++ b/SOURCES/glibc-RHEL-15696-94.patch @@ -0,0 +1,168 @@ +From 9c8a6ad620b49a27120ecdd7049c26bf05900397 Mon Sep 17 00:00:00 2001 +From: Noah Goldstein +Date: Wed, 23 Mar 2022 16:57:29 -0500 +Subject: [PATCH] x86: Remove strspn-sse2.S and use the generic implementation +Content-type: text/plain; charset=UTF-8 + +The generic implementation is faster. + +geometric_mean(N=20) of all benchmarks New / Original: .710 + +All string/memory tests pass. +Reviewed-by: H.J. Lu +--- + .../{strspn-sse2.S => strspn-sse2.c} | 6 +- + sysdeps/x86_64/strspn.S | 115 ------------------ + 2 files changed, 3 insertions(+), 118 deletions(-) + rename sysdeps/x86_64/multiarch/{strspn-sse2.S => strspn-sse2.c} (89%) + delete mode 100644 sysdeps/x86_64/strspn.S + +Conflicts: + sysdeps/x86_64/multiarch/strspn-sse2.c + (copyright header) + +diff --git a/sysdeps/x86_64/multiarch/strspn-sse2.S b/sysdeps/x86_64/multiarch/strspn-sse2.c +similarity index 89% +rename from sysdeps/x86_64/multiarch/strspn-sse2.S +rename to sysdeps/x86_64/multiarch/strspn-sse2.c +index 4686cdd5..ab0dae40 100644 +--- a/sysdeps/x86_64/multiarch/strspn-sse2.S ++++ b/sysdeps/x86_64/multiarch/strspn-sse2.c +@@ -19,10 +19,10 @@ + #if IS_IN (libc) + + # include +-# define strspn __strspn_sse2 ++# define STRSPN __strspn_sse2 + + # undef libc_hidden_builtin_def +-# define libc_hidden_builtin_def(strspn) ++# define libc_hidden_builtin_def(STRSPN) + #endif + +-#include ++#include +diff --git a/sysdeps/x86_64/strspn.S b/sysdeps/x86_64/strspn.S +deleted file mode 100644 +index 635f1bc6..00000000 +--- a/sysdeps/x86_64/strspn.S ++++ /dev/null +@@ -1,115 +0,0 @@ +-/* strspn (str, ss) -- Return the length of the initial segment of STR +- which contains only characters from SS. +- For AMD x86-64. +- Copyright (C) 1994-2018 Free Software Foundation, Inc. +- This file is part of the GNU C Library. +- Contributed by Ulrich Drepper . +- Bug fixes by Alan Modra . +- Adopted for x86-64 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 +- . */ +- +-#include +- +- .text +-ENTRY (strspn) +- +- movq %rdi, %rdx /* Save SRC. */ +- +- /* First we create a table with flags for all possible characters. +- For the ASCII (7bit/8bit) or ISO-8859-X character sets which are +- supported by the C string functions we have 256 characters. +- Before inserting marks for the stop characters we clear the whole +- table. */ +- movq %rdi, %r8 /* Save value. */ +- subq $256, %rsp /* Make space for 256 bytes. */ +- cfi_adjust_cfa_offset(256) +- movl $32, %ecx /* 32*8 bytes = 256 bytes. */ +- movq %rsp, %rdi +- xorl %eax, %eax /* We store 0s. */ +- cld +- rep +- stosq +- +- movq %rsi, %rax /* Setup stopset. */ +- +-/* For understanding the following code remember that %rcx == 0 now. +- Although all the following instruction only modify %cl we always +- have a correct zero-extended 64-bit value in %rcx. */ +- +- .p2align 4 +-L(2): movb (%rax), %cl /* get byte from stopset */ +- testb %cl, %cl /* is NUL char? */ +- jz L(1) /* yes => start compare loop */ +- movb %cl, (%rsp,%rcx) /* set corresponding byte in stopset table */ +- +- movb 1(%rax), %cl /* get byte from stopset */ +- testb $0xff, %cl /* is NUL char? */ +- jz L(1) /* yes => start compare loop */ +- movb %cl, (%rsp,%rcx) /* set corresponding byte in stopset table */ +- +- movb 2(%rax), %cl /* get byte from stopset */ +- testb $0xff, %cl /* is NUL char? */ +- jz L(1) /* yes => start compare loop */ +- movb %cl, (%rsp,%rcx) /* set corresponding byte in stopset table */ +- +- movb 3(%rax), %cl /* get byte from stopset */ +- addq $4, %rax /* increment stopset pointer */ +- movb %cl, (%rsp,%rcx) /* set corresponding byte in stopset table */ +- testb $0xff, %cl /* is NUL char? */ +- jnz L(2) /* no => process next dword from stopset */ +- +-L(1): leaq -4(%rdx), %rax /* prepare loop */ +- +- /* We use a neat trick for the following loop. Normally we would +- have to test for two termination conditions +- 1. a character in the stopset was found +- and +- 2. the end of the string was found +- But as a sign that the character is in the stopset we store its +- value in the table. But the value of NUL is NUL so the loop +- terminates for NUL in every case. */ +- +- .p2align 4 +-L(3): addq $4, %rax /* adjust pointer for full loop round */ +- +- movb (%rax), %cl /* get byte from string */ +- testb %cl, (%rsp,%rcx) /* is it contained in skipset? */ +- jz L(4) /* no => return */ +- +- movb 1(%rax), %cl /* get byte from string */ +- testb %cl, (%rsp,%rcx) /* is it contained in skipset? */ +- jz L(5) /* no => return */ +- +- movb 2(%rax), %cl /* get byte from string */ +- testb %cl, (%rsp,%rcx) /* is it contained in skipset? */ +- jz L(6) /* no => return */ +- +- movb 3(%rax), %cl /* get byte from string */ +- testb %cl, (%rsp,%rcx) /* is it contained in skipset? */ +- jnz L(3) /* yes => start loop again */ +- +- incq %rax /* adjust pointer */ +-L(6): incq %rax +-L(5): incq %rax +- +-L(4): addq $256, %rsp /* remove stopset */ +- cfi_adjust_cfa_offset(-256) +- subq %rdx, %rax /* we have to return the number of valid +- characters, so compute distance to first +- non-valid character */ +- ret +-END (strspn) +-libc_hidden_builtin_def (strspn) +-- +GitLab + diff --git a/SOURCES/glibc-RHEL-15696-95.patch b/SOURCES/glibc-RHEL-15696-95.patch new file mode 100644 index 0000000..cf21b96 --- /dev/null +++ b/SOURCES/glibc-RHEL-15696-95.patch @@ -0,0 +1,122 @@ +From 670b54bc585ea4a94f3b2e9272ba44aa6b730b73 Mon Sep 17 00:00:00 2001 +From: Noah Goldstein +Date: Wed, 23 Mar 2022 16:57:36 -0500 +Subject: [PATCH] x86: Optimize str{n}casecmp TOLOWER logic in strcmp.S +Content-type: text/plain; charset=UTF-8 + +Slightly faster method of doing TOLOWER that saves an +instruction. + +Also replace the hard coded 5-byte no with .p2align 4. On builds with +CET enabled this misaligned entry to strcasecmp. + +geometric_mean(N=40) of all benchmarks New / Original: .894 + +All string/memory tests pass. +Reviewed-by: H.J. Lu +--- + sysdeps/x86_64/strcmp.S | 64 +++++++++++++++++++---------------------- + 1 file changed, 29 insertions(+), 35 deletions(-) + +diff --git a/sysdeps/x86_64/strcmp.S b/sysdeps/x86_64/strcmp.S +index aa6df898..f454ce5b 100644 +--- a/sysdeps/x86_64/strcmp.S ++++ b/sysdeps/x86_64/strcmp.S +@@ -78,9 +78,8 @@ ENTRY2 (__strcasecmp) + movq __libc_tsd_LOCALE@gottpoff(%rip),%rax + mov %fs:(%rax),%RDX_LP + +- // XXX 5 byte should be before the function +- /* 5-byte NOP. */ +- .byte 0x0f,0x1f,0x44,0x00,0x00 ++ /* Either 1 or 5 bytes (dependeing if CET is enabled). */ ++ .p2align 4 + END2 (__strcasecmp) + # ifndef NO_NOLOCALE_ALIAS + weak_alias (__strcasecmp, strcasecmp) +@@ -97,9 +96,8 @@ ENTRY2 (__strncasecmp) + movq __libc_tsd_LOCALE@gottpoff(%rip),%rax + mov %fs:(%rax),%RCX_LP + +- // XXX 5 byte should be before the function +- /* 5-byte NOP. */ +- .byte 0x0f,0x1f,0x44,0x00,0x00 ++ /* Either 1 or 5 bytes (dependeing if CET is enabled). */ ++ .p2align 4 + END2 (__strncasecmp) + # ifndef NO_NOLOCALE_ALIAS + weak_alias (__strncasecmp, strncasecmp) +@@ -149,22 +147,22 @@ ENTRY (STRCMP) + #if defined USE_AS_STRCASECMP_L || defined USE_AS_STRNCASECMP_L + .section .rodata.cst16,"aM",@progbits,16 + .align 16 +-.Lbelowupper: +- .quad 0x4040404040404040 +- .quad 0x4040404040404040 +-.Ltopupper: +- .quad 0x5b5b5b5b5b5b5b5b +- .quad 0x5b5b5b5b5b5b5b5b +-.Ltouppermask: ++.Llcase_min: ++ .quad 0x3f3f3f3f3f3f3f3f ++ .quad 0x3f3f3f3f3f3f3f3f ++.Llcase_max: ++ .quad 0x9999999999999999 ++ .quad 0x9999999999999999 ++.Lcase_add: + .quad 0x2020202020202020 + .quad 0x2020202020202020 + .previous +- movdqa .Lbelowupper(%rip), %xmm5 +-# define UCLOW_reg %xmm5 +- movdqa .Ltopupper(%rip), %xmm6 +-# define UCHIGH_reg %xmm6 +- movdqa .Ltouppermask(%rip), %xmm7 +-# define LCQWORD_reg %xmm7 ++ movdqa .Llcase_min(%rip), %xmm5 ++# define LCASE_MIN_reg %xmm5 ++ movdqa .Llcase_max(%rip), %xmm6 ++# define LCASE_MAX_reg %xmm6 ++ movdqa .Lcase_add(%rip), %xmm7 ++# define CASE_ADD_reg %xmm7 + #endif + cmp $0x30, %ecx + ja LABEL(crosscache) /* rsi: 16-byte load will cross cache line */ +@@ -175,22 +173,18 @@ ENTRY (STRCMP) + movhpd 8(%rdi), %xmm1 + movhpd 8(%rsi), %xmm2 + #if defined USE_AS_STRCASECMP_L || defined USE_AS_STRNCASECMP_L +-# define TOLOWER(reg1, reg2) \ +- movdqa reg1, %xmm8; \ +- movdqa UCHIGH_reg, %xmm9; \ +- movdqa reg2, %xmm10; \ +- movdqa UCHIGH_reg, %xmm11; \ +- pcmpgtb UCLOW_reg, %xmm8; \ +- pcmpgtb reg1, %xmm9; \ +- pcmpgtb UCLOW_reg, %xmm10; \ +- pcmpgtb reg2, %xmm11; \ +- pand %xmm9, %xmm8; \ +- pand %xmm11, %xmm10; \ +- pand LCQWORD_reg, %xmm8; \ +- pand LCQWORD_reg, %xmm10; \ +- por %xmm8, reg1; \ +- por %xmm10, reg2 +- TOLOWER (%xmm1, %xmm2) ++# define TOLOWER(reg1, reg2) \ ++ movdqa LCASE_MIN_reg, %xmm8; \ ++ movdqa LCASE_MIN_reg, %xmm9; \ ++ paddb reg1, %xmm8; \ ++ paddb reg2, %xmm9; \ ++ pcmpgtb LCASE_MAX_reg, %xmm8; \ ++ pcmpgtb LCASE_MAX_reg, %xmm9; \ ++ pandn CASE_ADD_reg, %xmm8; \ ++ pandn CASE_ADD_reg, %xmm9; \ ++ paddb %xmm8, reg1; \ ++ paddb %xmm9, reg2 ++ TOLOWER (%xmm1, %xmm2) + #else + # define TOLOWER(reg1, reg2) + #endif +-- +GitLab + diff --git a/SOURCES/glibc-RHEL-15696-96.patch b/SOURCES/glibc-RHEL-15696-96.patch new file mode 100644 index 0000000..2d3b891 --- /dev/null +++ b/SOURCES/glibc-RHEL-15696-96.patch @@ -0,0 +1,143 @@ +From d154758e618ec9324f5d339c46db0aa27e8b1226 Mon Sep 17 00:00:00 2001 +From: Noah Goldstein +Date: Wed, 23 Mar 2022 16:57:38 -0500 +Subject: [PATCH] x86: Optimize str{n}casecmp TOLOWER logic in strcmp-sse42.S +Content-type: text/plain; charset=UTF-8 + +Slightly faster method of doing TOLOWER that saves an +instruction. + +Also replace the hard coded 5-byte no with .p2align 4. On builds with +CET enabled this misaligned entry to strcasecmp. + +geometric_mean(N=40) of all benchmarks New / Original: .920 + +All string/memory tests pass. +Reviewed-by: H.J. Lu +--- + sysdeps/x86_64/multiarch/strcmp-sse42.S | 83 +++++++++++-------------- + 1 file changed, 35 insertions(+), 48 deletions(-) + +diff --git a/sysdeps/x86_64/multiarch/strcmp-sse42.S b/sysdeps/x86_64/multiarch/strcmp-sse42.S +index d8fdeb3a..59e8ddfc 100644 +--- a/sysdeps/x86_64/multiarch/strcmp-sse42.S ++++ b/sysdeps/x86_64/multiarch/strcmp-sse42.S +@@ -89,9 +89,8 @@ ENTRY (GLABEL(__strcasecmp)) + movq __libc_tsd_LOCALE@gottpoff(%rip),%rax + mov %fs:(%rax),%RDX_LP + +- // XXX 5 byte should be before the function +- /* 5-byte NOP. */ +- .byte 0x0f,0x1f,0x44,0x00,0x00 ++ /* Either 1 or 5 bytes (dependeing if CET is enabled). */ ++ .p2align 4 + END (GLABEL(__strcasecmp)) + /* FALLTHROUGH to strcasecmp_l. */ + #endif +@@ -100,9 +99,8 @@ ENTRY (GLABEL(__strncasecmp)) + movq __libc_tsd_LOCALE@gottpoff(%rip),%rax + mov %fs:(%rax),%RCX_LP + +- // XXX 5 byte should be before the function +- /* 5-byte NOP. */ +- .byte 0x0f,0x1f,0x44,0x00,0x00 ++ /* Either 1 or 5 bytes (dependeing if CET is enabled). */ ++ .p2align 4 + END (GLABEL(__strncasecmp)) + /* FALLTHROUGH to strncasecmp_l. */ + #endif +@@ -170,27 +168,22 @@ STRCMP_SSE42: + #if defined USE_AS_STRCASECMP_L || defined USE_AS_STRNCASECMP_L + .section .rodata.cst16,"aM",@progbits,16 + .align 16 +-LABEL(belowupper): +- .quad 0x4040404040404040 +- .quad 0x4040404040404040 +-LABEL(topupper): +-# ifdef USE_AVX +- .quad 0x5a5a5a5a5a5a5a5a +- .quad 0x5a5a5a5a5a5a5a5a +-# else +- .quad 0x5b5b5b5b5b5b5b5b +- .quad 0x5b5b5b5b5b5b5b5b +-# endif +-LABEL(touppermask): ++LABEL(lcase_min): ++ .quad 0x3f3f3f3f3f3f3f3f ++ .quad 0x3f3f3f3f3f3f3f3f ++LABEL(lcase_max): ++ .quad 0x9999999999999999 ++ .quad 0x9999999999999999 ++LABEL(case_add): + .quad 0x2020202020202020 + .quad 0x2020202020202020 + .previous +- movdqa LABEL(belowupper)(%rip), %xmm4 +-# define UCLOW_reg %xmm4 +- movdqa LABEL(topupper)(%rip), %xmm5 +-# define UCHIGH_reg %xmm5 +- movdqa LABEL(touppermask)(%rip), %xmm6 +-# define LCQWORD_reg %xmm6 ++ movdqa LABEL(lcase_min)(%rip), %xmm4 ++# define LCASE_MIN_reg %xmm4 ++ movdqa LABEL(lcase_max)(%rip), %xmm5 ++# define LCASE_MAX_reg %xmm5 ++ movdqa LABEL(case_add)(%rip), %xmm6 ++# define CASE_ADD_reg %xmm6 + #endif + cmp $0x30, %ecx + ja LABEL(crosscache)/* rsi: 16-byte load will cross cache line */ +@@ -201,32 +194,26 @@ LABEL(touppermask): + #if defined USE_AS_STRCASECMP_L || defined USE_AS_STRNCASECMP_L + # ifdef USE_AVX + # define TOLOWER(reg1, reg2) \ +- vpcmpgtb UCLOW_reg, reg1, %xmm7; \ +- vpcmpgtb UCHIGH_reg, reg1, %xmm8; \ +- vpcmpgtb UCLOW_reg, reg2, %xmm9; \ +- vpcmpgtb UCHIGH_reg, reg2, %xmm10; \ +- vpandn %xmm7, %xmm8, %xmm8; \ +- vpandn %xmm9, %xmm10, %xmm10; \ +- vpand LCQWORD_reg, %xmm8, %xmm8; \ +- vpand LCQWORD_reg, %xmm10, %xmm10; \ +- vpor reg1, %xmm8, reg1; \ +- vpor reg2, %xmm10, reg2 ++ vpaddb LCASE_MIN_reg, reg1, %xmm7; \ ++ vpaddb LCASE_MIN_reg, reg2, %xmm8; \ ++ vpcmpgtb LCASE_MAX_reg, %xmm7, %xmm7; \ ++ vpcmpgtb LCASE_MAX_reg, %xmm8, %xmm8; \ ++ vpandn CASE_ADD_reg, %xmm7, %xmm7; \ ++ vpandn CASE_ADD_reg, %xmm8, %xmm8; \ ++ vpaddb %xmm7, reg1, reg1; \ ++ vpaddb %xmm8, reg2, reg2 + # else + # define TOLOWER(reg1, reg2) \ +- movdqa reg1, %xmm7; \ +- movdqa UCHIGH_reg, %xmm8; \ +- movdqa reg2, %xmm9; \ +- movdqa UCHIGH_reg, %xmm10; \ +- pcmpgtb UCLOW_reg, %xmm7; \ +- pcmpgtb reg1, %xmm8; \ +- pcmpgtb UCLOW_reg, %xmm9; \ +- pcmpgtb reg2, %xmm10; \ +- pand %xmm8, %xmm7; \ +- pand %xmm10, %xmm9; \ +- pand LCQWORD_reg, %xmm7; \ +- pand LCQWORD_reg, %xmm9; \ +- por %xmm7, reg1; \ +- por %xmm9, reg2 ++ movdqa LCASE_MIN_reg, %xmm7; \ ++ movdqa LCASE_MIN_reg, %xmm8; \ ++ paddb reg1, %xmm7; \ ++ paddb reg2, %xmm8; \ ++ pcmpgtb LCASE_MAX_reg, %xmm7; \ ++ pcmpgtb LCASE_MAX_reg, %xmm8; \ ++ pandn CASE_ADD_reg, %xmm7; \ ++ pandn CASE_ADD_reg, %xmm8; \ ++ paddb %xmm7, reg1; \ ++ paddb %xmm8, reg2 + # endif + TOLOWER (%xmm1, %xmm2) + #else +-- +GitLab + diff --git a/SOURCES/glibc-RHEL-15696-97.patch b/SOURCES/glibc-RHEL-15696-97.patch new file mode 100644 index 0000000..9592795 --- /dev/null +++ b/SOURCES/glibc-RHEL-15696-97.patch @@ -0,0 +1,759 @@ +From bbf81222343fed5cd704001a2ae0d86c71544151 Mon Sep 17 00:00:00 2001 +From: Noah Goldstein +Date: Thu, 24 Mar 2022 18:56:12 -0500 +Subject: [PATCH] x86: Add AVX2 optimized str{n}casecmp +Content-type: text/plain; charset=UTF-8 + +geometric_mean(N=40) of all benchmarks AVX2 / SSE42: .702 + +All string/memory tests pass. +Reviewed-by: H.J. Lu +--- + sysdeps/x86_64/multiarch/Makefile | 4 + + sysdeps/x86_64/multiarch/ifunc-impl-list.c | 28 +++ + sysdeps/x86_64/multiarch/ifunc-strcasecmp.h | 12 + + .../x86_64/multiarch/strcasecmp_l-avx2-rtm.S | 15 ++ + sysdeps/x86_64/multiarch/strcasecmp_l-avx2.S | 23 ++ + sysdeps/x86_64/multiarch/strcmp-avx2.S | 237 +++++++++++++++--- + .../x86_64/multiarch/strncase_l-avx2-rtm.S | 16 ++ + sysdeps/x86_64/multiarch/strncase_l-avx2.S | 27 ++ + 8 files changed, 331 insertions(+), 31 deletions(-) + create mode 100644 sysdeps/x86_64/multiarch/strcasecmp_l-avx2-rtm.S + create mode 100644 sysdeps/x86_64/multiarch/strcasecmp_l-avx2.S + create mode 100644 sysdeps/x86_64/multiarch/strncase_l-avx2-rtm.S + create mode 100644 sysdeps/x86_64/multiarch/strncase_l-avx2.S + +diff --git a/sysdeps/x86_64/multiarch/Makefile b/sysdeps/x86_64/multiarch/Makefile +index 8c9e7812..711ecf2e 100644 +--- a/sysdeps/x86_64/multiarch/Makefile ++++ b/sysdeps/x86_64/multiarch/Makefile +@@ -51,6 +51,8 @@ sysdep_routines += \ + stpncpy-sse2-unaligned \ + stpncpy-ssse3 \ + strcasecmp_l-avx \ ++ strcasecmp_l-avx2 \ ++ strcasecmp_l-avx2-rtm \ + strcasecmp_l-sse2 \ + strcasecmp_l-sse4_2 \ + strcasecmp_l-ssse3 \ +@@ -89,6 +91,8 @@ sysdep_routines += \ + strlen-evex \ + strlen-sse2 \ + strncase_l-avx \ ++ strncase_l-avx2 \ ++ strncase_l-avx2-rtm \ + strncase_l-sse2 \ + strncase_l-sse4_2 \ + strncase_l-ssse3 \ +diff --git a/sysdeps/x86_64/multiarch/ifunc-impl-list.c b/sysdeps/x86_64/multiarch/ifunc-impl-list.c +index c963d391..d873e1be 100644 +--- a/sysdeps/x86_64/multiarch/ifunc-impl-list.c ++++ b/sysdeps/x86_64/multiarch/ifunc-impl-list.c +@@ -418,6 +418,13 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + + /* Support sysdeps/x86_64/multiarch/strcasecmp_l.c. */ + IFUNC_IMPL (i, name, strcasecmp, ++ IFUNC_IMPL_ADD (array, i, strcasecmp, ++ CPU_FEATURE_USABLE (AVX2), ++ __strcasecmp_avx2) ++ IFUNC_IMPL_ADD (array, i, strcasecmp, ++ (CPU_FEATURE_USABLE (AVX2) ++ && CPU_FEATURE_USABLE (RTM)), ++ __strcasecmp_avx2_rtm) + IFUNC_IMPL_ADD (array, i, strcasecmp, + CPU_FEATURE_USABLE (AVX), + __strcasecmp_avx) +@@ -431,6 +438,13 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + + /* Support sysdeps/x86_64/multiarch/strcasecmp_l.c. */ + IFUNC_IMPL (i, name, strcasecmp_l, ++ IFUNC_IMPL_ADD (array, i, strcasecmp, ++ CPU_FEATURE_USABLE (AVX2), ++ __strcasecmp_l_avx2) ++ IFUNC_IMPL_ADD (array, i, strcasecmp, ++ (CPU_FEATURE_USABLE (AVX2) ++ && CPU_FEATURE_USABLE (RTM)), ++ __strcasecmp_l_avx2_rtm) + IFUNC_IMPL_ADD (array, i, strcasecmp_l, + CPU_FEATURE_USABLE (AVX), + __strcasecmp_l_avx) +@@ -558,6 +572,13 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + + /* Support sysdeps/x86_64/multiarch/strncase_l.c. */ + IFUNC_IMPL (i, name, strncasecmp, ++ IFUNC_IMPL_ADD (array, i, strncasecmp, ++ CPU_FEATURE_USABLE (AVX2), ++ __strncasecmp_avx2) ++ IFUNC_IMPL_ADD (array, i, strncasecmp, ++ (CPU_FEATURE_USABLE (AVX2) ++ && CPU_FEATURE_USABLE (RTM)), ++ __strncasecmp_avx2_rtm) + IFUNC_IMPL_ADD (array, i, strncasecmp, + CPU_FEATURE_USABLE (AVX), + __strncasecmp_avx) +@@ -572,6 +593,13 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + + /* Support sysdeps/x86_64/multiarch/strncase_l.c. */ + IFUNC_IMPL (i, name, strncasecmp_l, ++ IFUNC_IMPL_ADD (array, i, strncasecmp, ++ CPU_FEATURE_USABLE (AVX2), ++ __strncasecmp_l_avx2) ++ IFUNC_IMPL_ADD (array, i, strncasecmp, ++ (CPU_FEATURE_USABLE (AVX2) ++ && CPU_FEATURE_USABLE (RTM)), ++ __strncasecmp_l_avx2_rtm) + IFUNC_IMPL_ADD (array, i, strncasecmp_l, + CPU_FEATURE_USABLE (AVX), + __strncasecmp_l_avx) +diff --git a/sysdeps/x86_64/multiarch/ifunc-strcasecmp.h b/sysdeps/x86_64/multiarch/ifunc-strcasecmp.h +index 6a4bb078..926508c4 100644 +--- a/sysdeps/x86_64/multiarch/ifunc-strcasecmp.h ++++ b/sysdeps/x86_64/multiarch/ifunc-strcasecmp.h +@@ -23,12 +23,24 @@ extern __typeof (REDIRECT_NAME) OPTIMIZE (sse2) attribute_hidden; + extern __typeof (REDIRECT_NAME) OPTIMIZE (ssse3) attribute_hidden; + extern __typeof (REDIRECT_NAME) OPTIMIZE (sse42) attribute_hidden; + extern __typeof (REDIRECT_NAME) OPTIMIZE (avx) attribute_hidden; ++extern __typeof (REDIRECT_NAME) OPTIMIZE (avx2) attribute_hidden; ++extern __typeof (REDIRECT_NAME) OPTIMIZE (avx2_rtm) attribute_hidden; + + static inline void * + IFUNC_SELECTOR (void) + { + const struct cpu_features* cpu_features = __get_cpu_features (); + ++ if (CPU_FEATURE_USABLE_P (cpu_features, AVX2) ++ && CPU_FEATURES_ARCH_P (cpu_features, AVX_Fast_Unaligned_Load)) ++ { ++ if (CPU_FEATURE_USABLE_P (cpu_features, RTM)) ++ return OPTIMIZE (avx2_rtm); ++ ++ if (!CPU_FEATURES_ARCH_P (cpu_features, Prefer_No_VZEROUPPER)) ++ return OPTIMIZE (avx2); ++ } ++ + if (CPU_FEATURE_USABLE_P (cpu_features, AVX)) + return OPTIMIZE (avx); + +diff --git a/sysdeps/x86_64/multiarch/strcasecmp_l-avx2-rtm.S b/sysdeps/x86_64/multiarch/strcasecmp_l-avx2-rtm.S +new file mode 100644 +index 00000000..09957fc3 +--- /dev/null ++++ b/sysdeps/x86_64/multiarch/strcasecmp_l-avx2-rtm.S +@@ -0,0 +1,15 @@ ++#ifndef STRCMP ++# define STRCMP __strcasecmp_l_avx2_rtm ++#endif ++ ++#define _GLABEL(x) x ## _rtm ++#define GLABEL(x) _GLABEL(x) ++ ++#define ZERO_UPPER_VEC_REGISTERS_RETURN \ ++ ZERO_UPPER_VEC_REGISTERS_RETURN_XTEST ++ ++#define VZEROUPPER_RETURN jmp L(return_vzeroupper) ++ ++#define SECTION(p) p##.avx.rtm ++ ++#include "strcasecmp_l-avx2.S" +diff --git a/sysdeps/x86_64/multiarch/strcasecmp_l-avx2.S b/sysdeps/x86_64/multiarch/strcasecmp_l-avx2.S +new file mode 100644 +index 00000000..e2762f2a +--- /dev/null ++++ b/sysdeps/x86_64/multiarch/strcasecmp_l-avx2.S +@@ -0,0 +1,23 @@ ++/* strcasecmp_l optimized with AVX2. ++ Copyright (C) 2017-2022 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#ifndef STRCMP ++# define STRCMP __strcasecmp_l_avx2 ++#endif ++#define USE_AS_STRCASECMP_L ++#include "strcmp-avx2.S" +diff --git a/sysdeps/x86_64/multiarch/strcmp-avx2.S b/sysdeps/x86_64/multiarch/strcmp-avx2.S +index 782f9472..28cc98b6 100644 +--- a/sysdeps/x86_64/multiarch/strcmp-avx2.S ++++ b/sysdeps/x86_64/multiarch/strcmp-avx2.S +@@ -20,6 +20,10 @@ + + # include + ++# if defined USE_AS_STRCASECMP_L ++# include "locale-defines.h" ++# endif ++ + # ifndef STRCMP + # define STRCMP __strcmp_avx2 + # endif +@@ -74,13 +78,88 @@ + # define VEC_OFFSET (-VEC_SIZE) + # endif + ++# ifdef USE_AS_STRCASECMP_L ++# define BYTE_LOOP_REG OFFSET_REG ++# else ++# define BYTE_LOOP_REG ecx ++# endif ++ ++# ifdef USE_AS_STRCASECMP_L ++# ifdef USE_AS_STRNCMP ++# define STRCASECMP __strncasecmp_avx2 ++# define LOCALE_REG rcx ++# define LOCALE_REG_LP RCX_LP ++# define STRCASECMP_NONASCII __strncasecmp_l_nonascii ++# else ++# define STRCASECMP __strcasecmp_avx2 ++# define LOCALE_REG rdx ++# define LOCALE_REG_LP RDX_LP ++# define STRCASECMP_NONASCII __strcasecmp_l_nonascii ++# endif ++# endif ++ + # define xmmZERO xmm15 + # define ymmZERO ymm15 + ++# define LCASE_MIN_ymm %ymm10 ++# define LCASE_MAX_ymm %ymm11 ++# define CASE_ADD_ymm %ymm12 ++ ++# define LCASE_MIN_xmm %xmm10 ++# define LCASE_MAX_xmm %xmm11 ++# define CASE_ADD_xmm %xmm12 ++ ++ /* r11 is never use elsewhere so this is safe to maintain. */ ++# define TOLOWER_BASE %r11 ++ + # ifndef SECTION + # define SECTION(p) p##.avx + # endif + ++# ifdef USE_AS_STRCASECMP_L ++# define REG(x, y) x ## y ++# define TOLOWER(reg1_in, reg1_out, reg2_in, reg2_out, ext) \ ++ vpaddb REG(LCASE_MIN_, ext), reg1_in, REG(%ext, 8); \ ++ vpaddb REG(LCASE_MIN_, ext), reg2_in, REG(%ext, 9); \ ++ vpcmpgtb REG(LCASE_MAX_, ext), REG(%ext, 8), REG(%ext, 8); \ ++ vpcmpgtb REG(LCASE_MAX_, ext), REG(%ext, 9), REG(%ext, 9); \ ++ vpandn REG(CASE_ADD_, ext), REG(%ext, 8), REG(%ext, 8); \ ++ vpandn REG(CASE_ADD_, ext), REG(%ext, 9), REG(%ext, 9); \ ++ vpaddb REG(%ext, 8), reg1_in, reg1_out; \ ++ vpaddb REG(%ext, 9), reg2_in, reg2_out ++ ++# define TOLOWER_gpr(src, dst) movl (TOLOWER_BASE, src, 4), dst ++# define TOLOWER_ymm(...) TOLOWER(__VA_ARGS__, ymm) ++# define TOLOWER_xmm(...) TOLOWER(__VA_ARGS__, xmm) ++ ++# define CMP_R1_R2(s1_reg, s2_reg, scratch_reg, reg_out, ext) \ ++ TOLOWER (s1_reg, scratch_reg, s2_reg, s2_reg, ext); \ ++ VPCMPEQ scratch_reg, s2_reg, reg_out ++ ++# define CMP_R1_S2(s1_reg, s2_mem, scratch_reg, reg_out, ext) \ ++ VMOVU s2_mem, reg_out; \ ++ CMP_R1_R2(s1_reg, reg_out, scratch_reg, reg_out, ext) ++ ++# define CMP_R1_R2_ymm(...) CMP_R1_R2(__VA_ARGS__, ymm) ++# define CMP_R1_R2_xmm(...) CMP_R1_R2(__VA_ARGS__, xmm) ++ ++# define CMP_R1_S2_ymm(...) CMP_R1_S2(__VA_ARGS__, ymm) ++# define CMP_R1_S2_xmm(...) CMP_R1_S2(__VA_ARGS__, xmm) ++ ++# else ++# define TOLOWER_gpr(...) ++# define TOLOWER_ymm(...) ++# define TOLOWER_xmm(...) ++ ++# define CMP_R1_R2_ymm(s1_reg, s2_reg, scratch_reg, reg_out) \ ++ VPCMPEQ s2_reg, s1_reg, reg_out ++ ++# define CMP_R1_R2_xmm(...) CMP_R1_R2_ymm(__VA_ARGS__) ++ ++# define CMP_R1_S2_ymm(...) CMP_R1_R2_ymm(__VA_ARGS__) ++# define CMP_R1_S2_xmm(...) CMP_R1_R2_xmm(__VA_ARGS__) ++# endif ++ + /* Warning! + wcscmp/wcsncmp have to use SIGNED comparison for elements. + strcmp/strncmp have to use UNSIGNED comparison for elements. +@@ -102,8 +181,49 @@ + returned. */ + + .section SECTION(.text), "ax", @progbits +-ENTRY(STRCMP) ++ .align 16 ++ .type STRCMP, @function ++ .globl STRCMP ++ .hidden STRCMP ++ ++# ifndef GLABEL ++# define GLABEL(...) __VA_ARGS__ ++# endif ++ ++# ifdef USE_AS_STRCASECMP_L ++ENTRY (GLABEL(STRCASECMP)) ++ movq __libc_tsd_LOCALE@gottpoff(%rip), %rax ++ mov %fs:(%rax), %LOCALE_REG_LP ++ ++ /* Either 1 or 5 bytes (dependeing if CET is enabled). */ ++ .p2align 4 ++END (GLABEL(STRCASECMP)) ++ /* FALLTHROUGH to strcasecmp/strncasecmp_l. */ ++# endif ++ ++ .p2align 4 ++STRCMP: ++ cfi_startproc ++ _CET_ENDBR ++ CALL_MCOUNT ++ ++# if defined USE_AS_STRCASECMP_L ++ /* We have to fall back on the C implementation for locales with ++ encodings not matching ASCII for single bytes. */ ++# if LOCALE_T___LOCALES != 0 || LC_CTYPE != 0 ++ mov LOCALE_T___LOCALES + LC_CTYPE * LP_SIZE(%LOCALE_REG), %RAX_LP ++# else ++ mov (%LOCALE_REG), %RAX_LP ++# endif ++ testl $1, LOCALE_DATA_VALUES + _NL_CTYPE_NONASCII_CASE * SIZEOF_VALUES(%rax) ++ jne STRCASECMP_NONASCII ++ leaq _nl_C_LC_CTYPE_tolower + 128 * 4(%rip), TOLOWER_BASE ++# endif ++ + # ifdef USE_AS_STRNCMP ++ /* Don't overwrite LOCALE_REG (rcx) until we have pass ++ L(one_or_less). Otherwise we might use the wrong locale in ++ the OVERFLOW_STRCMP (strcasecmp_l). */ + # ifdef __ILP32__ + /* Clear the upper 32 bits. */ + movl %edx, %edx +@@ -128,6 +248,30 @@ ENTRY(STRCMP) + # endif + # endif + vpxor %xmmZERO, %xmmZERO, %xmmZERO ++# if defined USE_AS_STRCASECMP_L ++ .section .rodata.cst32, "aM", @progbits, 32 ++ .align 32 ++L(lcase_min): ++ .quad 0x3f3f3f3f3f3f3f3f ++ .quad 0x3f3f3f3f3f3f3f3f ++ .quad 0x3f3f3f3f3f3f3f3f ++ .quad 0x3f3f3f3f3f3f3f3f ++L(lcase_max): ++ .quad 0x9999999999999999 ++ .quad 0x9999999999999999 ++ .quad 0x9999999999999999 ++ .quad 0x9999999999999999 ++L(case_add): ++ .quad 0x2020202020202020 ++ .quad 0x2020202020202020 ++ .quad 0x2020202020202020 ++ .quad 0x2020202020202020 ++ .previous ++ ++ vmovdqa L(lcase_min)(%rip), LCASE_MIN_ymm ++ vmovdqa L(lcase_max)(%rip), LCASE_MAX_ymm ++ vmovdqa L(case_add)(%rip), CASE_ADD_ymm ++# endif + movl %edi, %eax + orl %esi, %eax + sall $20, %eax +@@ -138,8 +282,10 @@ ENTRY(STRCMP) + L(no_page_cross): + /* Safe to compare 4x vectors. */ + VMOVU (%rdi), %ymm0 +- /* 1s where s1 and s2 equal. */ +- VPCMPEQ (%rsi), %ymm0, %ymm1 ++ /* 1s where s1 and s2 equal. Just VPCMPEQ if its not strcasecmp. ++ Otherwise converts ymm0 and load from rsi to lower. ymm2 is ++ scratch and ymm1 is the return. */ ++ CMP_R1_S2_ymm (%ymm0, (%rsi), %ymm2, %ymm1) + /* 1s at null CHAR. */ + VPCMPEQ %ymm0, %ymmZERO, %ymm2 + /* 1s where s1 and s2 equal AND not null CHAR. */ +@@ -172,6 +318,8 @@ L(return_vec_0): + # else + movzbl (%rdi, %rcx), %eax + movzbl (%rsi, %rcx), %ecx ++ TOLOWER_gpr (%rax, %eax) ++ TOLOWER_gpr (%rcx, %ecx) + subl %ecx, %eax + # endif + L(ret0): +@@ -192,6 +340,10 @@ L(ret_zero): + + .p2align 4,, 5 + L(one_or_less): ++# ifdef USE_AS_STRCASECMP_L ++ /* Set locale argument for strcasecmp. */ ++ movq %LOCALE_REG, %rdx ++# endif + jb L(ret_zero) + # ifdef USE_AS_WCSCMP + /* 'nbe' covers the case where length is negative (large +@@ -211,6 +363,8 @@ L(one_or_less): + jnbe __strcmp_avx2 + movzbl (%rdi), %eax + movzbl (%rsi), %ecx ++ TOLOWER_gpr (%rax, %eax) ++ TOLOWER_gpr (%rcx, %ecx) + subl %ecx, %eax + # endif + L(ret1): +@@ -238,6 +392,8 @@ L(return_vec_1): + # else + movzbl VEC_SIZE(%rdi, %rcx), %eax + movzbl VEC_SIZE(%rsi, %rcx), %ecx ++ TOLOWER_gpr (%rax, %eax) ++ TOLOWER_gpr (%rcx, %ecx) + subl %ecx, %eax + # endif + L(ret2): +@@ -269,6 +425,8 @@ L(return_vec_2): + # else + movzbl (VEC_SIZE * 2)(%rdi, %rcx), %eax + movzbl (VEC_SIZE * 2)(%rsi, %rcx), %ecx ++ TOLOWER_gpr (%rax, %eax) ++ TOLOWER_gpr (%rcx, %ecx) + subl %ecx, %eax + # endif + L(ret3): +@@ -289,6 +447,8 @@ L(return_vec_3): + # else + movzbl (VEC_SIZE * 3)(%rdi, %rcx), %eax + movzbl (VEC_SIZE * 3)(%rsi, %rcx), %ecx ++ TOLOWER_gpr (%rax, %eax) ++ TOLOWER_gpr (%rcx, %ecx) + subl %ecx, %eax + # endif + L(ret4): +@@ -299,7 +459,7 @@ L(ret4): + L(more_3x_vec): + /* Safe to compare 4x vectors. */ + VMOVU VEC_SIZE(%rdi), %ymm0 +- VPCMPEQ VEC_SIZE(%rsi), %ymm0, %ymm1 ++ CMP_R1_S2_ymm (%ymm0, VEC_SIZE(%rsi), %ymm2, %ymm1) + VPCMPEQ %ymm0, %ymmZERO, %ymm2 + vpandn %ymm1, %ymm2, %ymm1 + vpmovmskb %ymm1, %ecx +@@ -312,7 +472,7 @@ L(more_3x_vec): + # endif + + VMOVU (VEC_SIZE * 2)(%rdi), %ymm0 +- VPCMPEQ (VEC_SIZE * 2)(%rsi), %ymm0, %ymm1 ++ CMP_R1_S2_ymm (%ymm0, (VEC_SIZE * 2)(%rsi), %ymm2, %ymm1) + VPCMPEQ %ymm0, %ymmZERO, %ymm2 + vpandn %ymm1, %ymm2, %ymm1 + vpmovmskb %ymm1, %ecx +@@ -320,7 +480,7 @@ L(more_3x_vec): + jnz L(return_vec_2) + + VMOVU (VEC_SIZE * 3)(%rdi), %ymm0 +- VPCMPEQ (VEC_SIZE * 3)(%rsi), %ymm0, %ymm1 ++ CMP_R1_S2_ymm (%ymm0, (VEC_SIZE * 3)(%rsi), %ymm2, %ymm1) + VPCMPEQ %ymm0, %ymmZERO, %ymm2 + vpandn %ymm1, %ymm2, %ymm1 + vpmovmskb %ymm1, %ecx +@@ -395,12 +555,10 @@ L(loop_skip_page_cross_check): + VMOVA (VEC_SIZE * 3)(%rdi), %ymm6 + + /* ymm1 all 1s where s1 and s2 equal. All 0s otherwise. */ +- VPCMPEQ (VEC_SIZE * 0)(%rsi), %ymm0, %ymm1 +- +- VPCMPEQ (VEC_SIZE * 1)(%rsi), %ymm2, %ymm3 +- VPCMPEQ (VEC_SIZE * 2)(%rsi), %ymm4, %ymm5 +- VPCMPEQ (VEC_SIZE * 3)(%rsi), %ymm6, %ymm7 +- ++ CMP_R1_S2_ymm (%ymm0, (VEC_SIZE * 0)(%rsi), %ymm3, %ymm1) ++ CMP_R1_S2_ymm (%ymm2, (VEC_SIZE * 1)(%rsi), %ymm5, %ymm3) ++ CMP_R1_S2_ymm (%ymm4, (VEC_SIZE * 2)(%rsi), %ymm7, %ymm5) ++ CMP_R1_S2_ymm (%ymm6, (VEC_SIZE * 3)(%rsi), %ymm13, %ymm7) + + /* If any mismatches or null CHAR then 0 CHAR, otherwise non- + zero. */ +@@ -469,6 +627,8 @@ L(return_vec_2_3_end): + # else + movzbl (VEC_SIZE * 2 - VEC_OFFSET)(%rdi, %LOOP_REG64), %eax + movzbl (VEC_SIZE * 2 - VEC_OFFSET)(%rsi, %LOOP_REG64), %ecx ++ TOLOWER_gpr (%rax, %eax) ++ TOLOWER_gpr (%rcx, %ecx) + subl %ecx, %eax + xorl %r8d, %eax + subl %r8d, %eax +@@ -512,6 +672,8 @@ L(return_vec_0_end): + # else + movzbl (%rdi, %rcx), %eax + movzbl (%rsi, %rcx), %ecx ++ TOLOWER_gpr (%rax, %eax) ++ TOLOWER_gpr (%rcx, %ecx) + subl %ecx, %eax + xorl %r8d, %eax + subl %r8d, %eax +@@ -534,6 +696,8 @@ L(return_vec_1_end): + # else + movzbl VEC_SIZE(%rdi, %rcx), %eax + movzbl VEC_SIZE(%rsi, %rcx), %ecx ++ TOLOWER_gpr (%rax, %eax) ++ TOLOWER_gpr (%rcx, %ecx) + subl %ecx, %eax + xorl %r8d, %eax + subl %r8d, %eax +@@ -560,6 +724,8 @@ L(return_vec_2_end): + # else + movzbl (VEC_SIZE * 2)(%rdi, %rcx), %eax + movzbl (VEC_SIZE * 2)(%rsi, %rcx), %ecx ++ TOLOWER_gpr (%rax, %eax) ++ TOLOWER_gpr (%rcx, %ecx) + subl %ecx, %eax + xorl %r8d, %eax + subl %r8d, %eax +@@ -587,7 +753,7 @@ L(page_cross_during_loop): + jle L(less_1x_vec_till_page_cross) + + VMOVA (%rdi), %ymm0 +- VPCMPEQ (%rsi), %ymm0, %ymm1 ++ CMP_R1_S2_ymm (%ymm0, (%rsi), %ymm2, %ymm1) + VPCMPEQ %ymm0, %ymmZERO, %ymm2 + vpandn %ymm1, %ymm2, %ymm1 + vpmovmskb %ymm1, %ecx +@@ -609,7 +775,7 @@ L(less_1x_vec_till_page_cross): + here, it means the previous page (rdi - VEC_SIZE) has already + been loaded earlier so must be valid. */ + VMOVU -VEC_SIZE(%rdi, %rax), %ymm0 +- VPCMPEQ -VEC_SIZE(%rsi, %rax), %ymm0, %ymm1 ++ CMP_R1_S2_ymm (%ymm0, -VEC_SIZE(%rsi, %rax), %ymm2, %ymm1) + VPCMPEQ %ymm0, %ymmZERO, %ymm2 + vpandn %ymm1, %ymm2, %ymm1 + vpmovmskb %ymm1, %ecx +@@ -651,6 +817,8 @@ L(return_page_cross_cmp_mem): + # else + movzbl VEC_OFFSET(%rdi, %rcx), %eax + movzbl VEC_OFFSET(%rsi, %rcx), %ecx ++ TOLOWER_gpr (%rax, %eax) ++ TOLOWER_gpr (%rcx, %ecx) + subl %ecx, %eax + xorl %r8d, %eax + subl %r8d, %eax +@@ -677,7 +845,7 @@ L(more_2x_vec_till_page_cross): + iteration here. */ + + VMOVU VEC_SIZE(%rdi), %ymm0 +- VPCMPEQ VEC_SIZE(%rsi), %ymm0, %ymm1 ++ CMP_R1_S2_ymm (%ymm0, VEC_SIZE(%rsi), %ymm2, %ymm1) + VPCMPEQ %ymm0, %ymmZERO, %ymm2 + vpandn %ymm1, %ymm2, %ymm1 + vpmovmskb %ymm1, %ecx +@@ -693,7 +861,7 @@ L(more_2x_vec_till_page_cross): + + /* Safe to include comparisons from lower bytes. */ + VMOVU -(VEC_SIZE * 2)(%rdi, %rax), %ymm0 +- VPCMPEQ -(VEC_SIZE * 2)(%rsi, %rax), %ymm0, %ymm1 ++ CMP_R1_S2_ymm (%ymm0, -(VEC_SIZE * 2)(%rsi, %rax), %ymm2, %ymm1) + VPCMPEQ %ymm0, %ymmZERO, %ymm2 + vpandn %ymm1, %ymm2, %ymm1 + vpmovmskb %ymm1, %ecx +@@ -701,7 +869,7 @@ L(more_2x_vec_till_page_cross): + jnz L(return_vec_page_cross_0) + + VMOVU -(VEC_SIZE * 1)(%rdi, %rax), %ymm0 +- VPCMPEQ -(VEC_SIZE * 1)(%rsi, %rax), %ymm0, %ymm1 ++ CMP_R1_S2_ymm (%ymm0, -(VEC_SIZE * 1)(%rsi, %rax), %ymm2, %ymm1) + VPCMPEQ %ymm0, %ymmZERO, %ymm2 + vpandn %ymm1, %ymm2, %ymm1 + vpmovmskb %ymm1, %ecx +@@ -719,8 +887,8 @@ L(more_2x_vec_till_page_cross): + VMOVA (VEC_SIZE * 2)(%rdi), %ymm4 + VMOVA (VEC_SIZE * 3)(%rdi), %ymm6 + +- VPCMPEQ (VEC_SIZE * 2)(%rsi), %ymm4, %ymm5 +- VPCMPEQ (VEC_SIZE * 3)(%rsi), %ymm6, %ymm7 ++ CMP_R1_S2_ymm (%ymm4, (VEC_SIZE * 2)(%rsi), %ymm7, %ymm5) ++ CMP_R1_S2_ymm (%ymm6, (VEC_SIZE * 3)(%rsi), %ymm13, %ymm7) + vpand %ymm4, %ymm5, %ymm5 + vpand %ymm6, %ymm7, %ymm7 + VPMINU %ymm5, %ymm7, %ymm7 +@@ -771,6 +939,8 @@ L(return_vec_page_cross_1): + # else + movzbl VEC_OFFSET(%rdi, %rcx), %eax + movzbl VEC_OFFSET(%rsi, %rcx), %ecx ++ TOLOWER_gpr (%rax, %eax) ++ TOLOWER_gpr (%rcx, %ecx) + subl %ecx, %eax + xorl %r8d, %eax + subl %r8d, %eax +@@ -826,7 +996,7 @@ L(page_cross): + L(page_cross_loop): + + VMOVU (%rdi, %OFFSET_REG64), %ymm0 +- VPCMPEQ (%rsi, %OFFSET_REG64), %ymm0, %ymm1 ++ CMP_R1_S2_ymm (%ymm0, (%rsi, %OFFSET_REG64), %ymm2, %ymm1) + VPCMPEQ %ymm0, %ymmZERO, %ymm2 + vpandn %ymm1, %ymm2, %ymm1 + vpmovmskb %ymm1, %ecx +@@ -844,11 +1014,11 @@ L(page_cross_loop): + subl %eax, %OFFSET_REG + /* OFFSET_REG has distance to page cross - VEC_SIZE. Guranteed + to not cross page so is safe to load. Since we have already +- loaded at least 1 VEC from rsi it is also guranteed to be safe. +- */ ++ loaded at least 1 VEC from rsi it is also guranteed to be ++ safe. */ + + VMOVU (%rdi, %OFFSET_REG64), %ymm0 +- VPCMPEQ (%rsi, %OFFSET_REG64), %ymm0, %ymm1 ++ CMP_R1_S2_ymm (%ymm0, (%rsi, %OFFSET_REG64), %ymm2, %ymm1) + VPCMPEQ %ymm0, %ymmZERO, %ymm2 + vpandn %ymm1, %ymm2, %ymm1 + vpmovmskb %ymm1, %ecx +@@ -881,6 +1051,8 @@ L(ret_vec_page_cross_cont): + # else + movzbl (%rdi, %rcx), %eax + movzbl (%rsi, %rcx), %ecx ++ TOLOWER_gpr (%rax, %eax) ++ TOLOWER_gpr (%rcx, %ecx) + subl %ecx, %eax + xorl %r8d, %eax + subl %r8d, %eax +@@ -934,7 +1106,7 @@ L(less_1x_vec_till_page): + ja L(less_16_till_page) + + VMOVU (%rdi), %xmm0 +- VPCMPEQ (%rsi), %xmm0, %xmm1 ++ CMP_R1_S2_xmm (%xmm0, (%rsi), %xmm2, %xmm1) + VPCMPEQ %xmm0, %xmmZERO, %xmm2 + vpandn %xmm1, %xmm2, %xmm1 + vpmovmskb %ymm1, %ecx +@@ -952,7 +1124,7 @@ L(less_1x_vec_till_page): + # endif + + VMOVU (%rdi, %OFFSET_REG64), %xmm0 +- VPCMPEQ (%rsi, %OFFSET_REG64), %xmm0, %xmm1 ++ CMP_R1_S2_xmm (%xmm0, (%rsi, %OFFSET_REG64), %xmm2, %xmm1) + VPCMPEQ %xmm0, %xmmZERO, %xmm2 + vpandn %xmm1, %xmm2, %xmm1 + vpmovmskb %ymm1, %ecx +@@ -990,7 +1162,7 @@ L(less_16_till_page): + vmovq (%rdi), %xmm0 + vmovq (%rsi), %xmm1 + VPCMPEQ %xmm0, %xmmZERO, %xmm2 +- VPCMPEQ %xmm1, %xmm0, %xmm1 ++ CMP_R1_R2_xmm (%xmm0, %xmm1, %xmm3, %xmm1) + vpandn %xmm1, %xmm2, %xmm1 + vpmovmskb %ymm1, %ecx + incb %cl +@@ -1010,7 +1182,7 @@ L(less_16_till_page): + vmovq (%rdi, %OFFSET_REG64), %xmm0 + vmovq (%rsi, %OFFSET_REG64), %xmm1 + VPCMPEQ %xmm0, %xmmZERO, %xmm2 +- VPCMPEQ %xmm1, %xmm0, %xmm1 ++ CMP_R1_R2_xmm (%xmm0, %xmm1, %xmm3, %xmm1) + vpandn %xmm1, %xmm2, %xmm1 + vpmovmskb %ymm1, %ecx + incb %cl +@@ -1066,7 +1238,7 @@ L(ret_less_8_wcs): + vmovd (%rdi), %xmm0 + vmovd (%rsi), %xmm1 + VPCMPEQ %xmm0, %xmmZERO, %xmm2 +- VPCMPEQ %xmm1, %xmm0, %xmm1 ++ CMP_R1_R2_xmm (%xmm0, %xmm1, %xmm3, %xmm1) + vpandn %xmm1, %xmm2, %xmm1 + vpmovmskb %ymm1, %ecx + subl $0xf, %ecx +@@ -1085,7 +1257,7 @@ L(ret_less_8_wcs): + vmovd (%rdi, %OFFSET_REG64), %xmm0 + vmovd (%rsi, %OFFSET_REG64), %xmm1 + VPCMPEQ %xmm0, %xmmZERO, %xmm2 +- VPCMPEQ %xmm1, %xmm0, %xmm1 ++ CMP_R1_R2_xmm (%xmm0, %xmm1, %xmm3, %xmm1) + vpandn %xmm1, %xmm2, %xmm1 + vpmovmskb %ymm1, %ecx + subl $0xf, %ecx +@@ -1119,7 +1291,9 @@ L(less_4_till_page): + L(less_4_loop): + movzbl (%rdi), %eax + movzbl (%rsi, %rdi), %ecx +- subl %ecx, %eax ++ TOLOWER_gpr (%rax, %eax) ++ TOLOWER_gpr (%rcx, %BYTE_LOOP_REG) ++ subl %BYTE_LOOP_REG, %eax + jnz L(ret_less_4_loop) + testl %ecx, %ecx + jz L(ret_zero_4_loop) +@@ -1146,5 +1320,6 @@ L(ret_less_4_loop): + subl %r8d, %eax + ret + # endif +-END(STRCMP) ++ cfi_endproc ++ .size STRCMP, .-STRCMP + #endif +diff --git a/sysdeps/x86_64/multiarch/strncase_l-avx2-rtm.S b/sysdeps/x86_64/multiarch/strncase_l-avx2-rtm.S +new file mode 100644 +index 00000000..58c05dcf +--- /dev/null ++++ b/sysdeps/x86_64/multiarch/strncase_l-avx2-rtm.S +@@ -0,0 +1,16 @@ ++#ifndef STRCMP ++# define STRCMP __strncasecmp_l_avx2_rtm ++#endif ++ ++#define _GLABEL(x) x ## _rtm ++#define GLABEL(x) _GLABEL(x) ++ ++#define ZERO_UPPER_VEC_REGISTERS_RETURN \ ++ ZERO_UPPER_VEC_REGISTERS_RETURN_XTEST ++ ++#define VZEROUPPER_RETURN jmp L(return_vzeroupper) ++ ++#define SECTION(p) p##.avx.rtm ++#define OVERFLOW_STRCMP __strcasecmp_l_avx2_rtm ++ ++#include "strncase_l-avx2.S" +diff --git a/sysdeps/x86_64/multiarch/strncase_l-avx2.S b/sysdeps/x86_64/multiarch/strncase_l-avx2.S +new file mode 100644 +index 00000000..48c0aa21 +--- /dev/null ++++ b/sysdeps/x86_64/multiarch/strncase_l-avx2.S +@@ -0,0 +1,27 @@ ++/* strncasecmp_l optimized with AVX2. ++ Copyright (C) 2017-2022 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#ifndef STRCMP ++# define STRCMP __strncasecmp_l_avx2 ++#endif ++#define USE_AS_STRCASECMP_L ++#define USE_AS_STRNCMP ++#ifndef OVERFLOW_STRCMP ++# define OVERFLOW_STRCMP __strcasecmp_l_avx2 ++#endif ++#include "strcmp-avx2.S" +-- +GitLab + diff --git a/SOURCES/glibc-RHEL-15696-98.patch b/SOURCES/glibc-RHEL-15696-98.patch new file mode 100644 index 0000000..9941bcc --- /dev/null +++ b/SOURCES/glibc-RHEL-15696-98.patch @@ -0,0 +1,814 @@ +From 84e7c46df4086873eae28a1fb87d2cf5388b1e16 Mon Sep 17 00:00:00 2001 +From: Noah Goldstein +Date: Thu, 24 Mar 2022 18:56:13 -0500 +Subject: [PATCH] x86: Add EVEX optimized str{n}casecmp +Content-type: text/plain; charset=UTF-8 + +geometric_mean(N=40) of all benchmarks EVEX / SSE42: .621 + +All string/memory tests pass. +Reviewed-by: H.J. Lu +--- + sysdeps/x86_64/multiarch/Makefile | 2 + + sysdeps/x86_64/multiarch/ifunc-impl-list.c | 16 + + sysdeps/x86_64/multiarch/ifunc-strcasecmp.h | 5 + + sysdeps/x86_64/multiarch/strcasecmp_l-evex.S | 23 ++ + sysdeps/x86_64/multiarch/strcmp-evex.S | 290 ++++++++++++++++--- + sysdeps/x86_64/multiarch/strncase_l-evex.S | 25 ++ + 6 files changed, 321 insertions(+), 40 deletions(-) + create mode 100644 sysdeps/x86_64/multiarch/strcasecmp_l-evex.S + create mode 100644 sysdeps/x86_64/multiarch/strncase_l-evex.S + +diff --git a/sysdeps/x86_64/multiarch/Makefile b/sysdeps/x86_64/multiarch/Makefile +index 711ecf2e..359712c1 100644 +--- a/sysdeps/x86_64/multiarch/Makefile ++++ b/sysdeps/x86_64/multiarch/Makefile +@@ -53,6 +53,7 @@ sysdep_routines += \ + strcasecmp_l-avx \ + strcasecmp_l-avx2 \ + strcasecmp_l-avx2-rtm \ ++ strcasecmp_l-evex \ + strcasecmp_l-sse2 \ + strcasecmp_l-sse4_2 \ + strcasecmp_l-ssse3 \ +@@ -93,6 +94,7 @@ sysdep_routines += \ + strncase_l-avx \ + strncase_l-avx2 \ + strncase_l-avx2-rtm \ ++ strncase_l-evex \ + strncase_l-sse2 \ + strncase_l-sse4_2 \ + strncase_l-ssse3 \ +diff --git a/sysdeps/x86_64/multiarch/ifunc-impl-list.c b/sysdeps/x86_64/multiarch/ifunc-impl-list.c +index d873e1be..1dedc637 100644 +--- a/sysdeps/x86_64/multiarch/ifunc-impl-list.c ++++ b/sysdeps/x86_64/multiarch/ifunc-impl-list.c +@@ -418,6 +418,10 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + + /* Support sysdeps/x86_64/multiarch/strcasecmp_l.c. */ + IFUNC_IMPL (i, name, strcasecmp, ++ IFUNC_IMPL_ADD (array, i, strcasecmp, ++ (CPU_FEATURE_USABLE (AVX512VL) ++ && CPU_FEATURE_USABLE (AVX512BW)), ++ __strcasecmp_evex) + IFUNC_IMPL_ADD (array, i, strcasecmp, + CPU_FEATURE_USABLE (AVX2), + __strcasecmp_avx2) +@@ -438,6 +442,10 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + + /* Support sysdeps/x86_64/multiarch/strcasecmp_l.c. */ + IFUNC_IMPL (i, name, strcasecmp_l, ++ IFUNC_IMPL_ADD (array, i, strcasecmp, ++ (CPU_FEATURE_USABLE (AVX512VL) ++ && CPU_FEATURE_USABLE (AVX512BW)), ++ __strcasecmp_l_evex) + IFUNC_IMPL_ADD (array, i, strcasecmp, + CPU_FEATURE_USABLE (AVX2), + __strcasecmp_l_avx2) +@@ -572,6 +580,10 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + + /* Support sysdeps/x86_64/multiarch/strncase_l.c. */ + IFUNC_IMPL (i, name, strncasecmp, ++ IFUNC_IMPL_ADD (array, i, strncasecmp, ++ (CPU_FEATURE_USABLE (AVX512VL) ++ && CPU_FEATURE_USABLE (AVX512BW)), ++ __strncasecmp_evex) + IFUNC_IMPL_ADD (array, i, strncasecmp, + CPU_FEATURE_USABLE (AVX2), + __strncasecmp_avx2) +@@ -593,6 +605,10 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + + /* Support sysdeps/x86_64/multiarch/strncase_l.c. */ + IFUNC_IMPL (i, name, strncasecmp_l, ++ IFUNC_IMPL_ADD (array, i, strncasecmp, ++ (CPU_FEATURE_USABLE (AVX512VL) ++ && CPU_FEATURE_USABLE (AVX512BW)), ++ __strncasecmp_l_evex) + IFUNC_IMPL_ADD (array, i, strncasecmp, + CPU_FEATURE_USABLE (AVX2), + __strncasecmp_l_avx2) +diff --git a/sysdeps/x86_64/multiarch/ifunc-strcasecmp.h b/sysdeps/x86_64/multiarch/ifunc-strcasecmp.h +index 926508c4..6dd49a21 100644 +--- a/sysdeps/x86_64/multiarch/ifunc-strcasecmp.h ++++ b/sysdeps/x86_64/multiarch/ifunc-strcasecmp.h +@@ -25,6 +25,7 @@ extern __typeof (REDIRECT_NAME) OPTIMIZE (sse42) attribute_hidden; + extern __typeof (REDIRECT_NAME) OPTIMIZE (avx) attribute_hidden; + extern __typeof (REDIRECT_NAME) OPTIMIZE (avx2) attribute_hidden; + extern __typeof (REDIRECT_NAME) OPTIMIZE (avx2_rtm) attribute_hidden; ++extern __typeof (REDIRECT_NAME) OPTIMIZE (evex) attribute_hidden; + + static inline void * + IFUNC_SELECTOR (void) +@@ -34,6 +35,10 @@ IFUNC_SELECTOR (void) + if (CPU_FEATURE_USABLE_P (cpu_features, AVX2) + && CPU_FEATURES_ARCH_P (cpu_features, AVX_Fast_Unaligned_Load)) + { ++ if (CPU_FEATURE_USABLE_P (cpu_features, AVX512VL) ++ && CPU_FEATURE_USABLE_P (cpu_features, AVX512BW)) ++ return OPTIMIZE (evex); ++ + if (CPU_FEATURE_USABLE_P (cpu_features, RTM)) + return OPTIMIZE (avx2_rtm); + +diff --git a/sysdeps/x86_64/multiarch/strcasecmp_l-evex.S b/sysdeps/x86_64/multiarch/strcasecmp_l-evex.S +new file mode 100644 +index 00000000..58642db7 +--- /dev/null ++++ b/sysdeps/x86_64/multiarch/strcasecmp_l-evex.S +@@ -0,0 +1,23 @@ ++/* strcasecmp_l optimized with EVEX. ++ Copyright (C) 2017-2022 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#ifndef STRCMP ++# define STRCMP __strcasecmp_l_evex ++#endif ++#define USE_AS_STRCASECMP_L ++#include "strcmp-evex.S" +diff --git a/sysdeps/x86_64/multiarch/strcmp-evex.S b/sysdeps/x86_64/multiarch/strcmp-evex.S +index 0dfa62bd..b81b5775 100644 +--- a/sysdeps/x86_64/multiarch/strcmp-evex.S ++++ b/sysdeps/x86_64/multiarch/strcmp-evex.S +@@ -19,6 +19,9 @@ + #if IS_IN (libc) + + # include ++# if defined USE_AS_STRCASECMP_L ++# include "locale-defines.h" ++# endif + + # ifndef STRCMP + # define STRCMP __strcmp_evex +@@ -34,19 +37,29 @@ + # define VMOVA vmovdqa64 + + # ifdef USE_AS_WCSCMP +-# define TESTEQ subl $0xff, ++# ifndef OVERFLOW_STRCMP ++# define OVERFLOW_STRCMP __wcscmp_evex ++# endif ++ ++# define TESTEQ subl $0xff, + /* Compare packed dwords. */ + # define VPCMP vpcmpd + # define VPMINU vpminud + # define VPTESTM vptestmd ++# define VPTESTNM vptestnmd + /* 1 dword char == 4 bytes. */ + # define SIZE_OF_CHAR 4 + # else ++# ifndef OVERFLOW_STRCMP ++# define OVERFLOW_STRCMP __strcmp_evex ++# endif ++ + # define TESTEQ incl + /* Compare packed bytes. */ + # define VPCMP vpcmpb + # define VPMINU vpminub + # define VPTESTM vptestmb ++# define VPTESTNM vptestnmb + /* 1 byte char == 1 byte. */ + # define SIZE_OF_CHAR 1 + # endif +@@ -73,11 +86,16 @@ + # define VEC_OFFSET (-VEC_SIZE) + # endif + +-# define XMMZERO xmm16 + # define XMM0 xmm17 + # define XMM1 xmm18 + +-# define YMMZERO ymm16 ++# define XMM10 xmm27 ++# define XMM11 xmm28 ++# define XMM12 xmm29 ++# define XMM13 xmm30 ++# define XMM14 xmm31 ++ ++ + # define YMM0 ymm17 + # define YMM1 ymm18 + # define YMM2 ymm19 +@@ -89,6 +107,87 @@ + # define YMM8 ymm25 + # define YMM9 ymm26 + # define YMM10 ymm27 ++# define YMM11 ymm28 ++# define YMM12 ymm29 ++# define YMM13 ymm30 ++# define YMM14 ymm31 ++ ++# ifdef USE_AS_STRCASECMP_L ++# define BYTE_LOOP_REG OFFSET_REG ++# else ++# define BYTE_LOOP_REG ecx ++# endif ++ ++# ifdef USE_AS_STRCASECMP_L ++# ifdef USE_AS_STRNCMP ++# define STRCASECMP __strncasecmp_evex ++# define LOCALE_REG rcx ++# define LOCALE_REG_LP RCX_LP ++# define STRCASECMP_NONASCII __strncasecmp_l_nonascii ++# else ++# define STRCASECMP __strcasecmp_evex ++# define LOCALE_REG rdx ++# define LOCALE_REG_LP RDX_LP ++# define STRCASECMP_NONASCII __strcasecmp_l_nonascii ++# endif ++# endif ++ ++# define LCASE_MIN_YMM %YMM12 ++# define LCASE_MAX_YMM %YMM13 ++# define CASE_ADD_YMM %YMM14 ++ ++# define LCASE_MIN_XMM %XMM12 ++# define LCASE_MAX_XMM %XMM13 ++# define CASE_ADD_XMM %XMM14 ++ ++ /* NB: wcsncmp uses r11 but strcasecmp is never used in ++ conjunction with wcscmp. */ ++# define TOLOWER_BASE %r11 ++ ++# ifdef USE_AS_STRCASECMP_L ++# define _REG(x, y) x ## y ++# define REG(x, y) _REG(x, y) ++# define TOLOWER(reg1, reg2, ext) \ ++ vpsubb REG(LCASE_MIN_, ext), reg1, REG(%ext, 10); \ ++ vpsubb REG(LCASE_MIN_, ext), reg2, REG(%ext, 11); \ ++ vpcmpub $1, REG(LCASE_MAX_, ext), REG(%ext, 10), %k5; \ ++ vpcmpub $1, REG(LCASE_MAX_, ext), REG(%ext, 11), %k6; \ ++ vpaddb reg1, REG(CASE_ADD_, ext), reg1{%k5}; \ ++ vpaddb reg2, REG(CASE_ADD_, ext), reg2{%k6} ++ ++# define TOLOWER_gpr(src, dst) movl (TOLOWER_BASE, src, 4), dst ++# define TOLOWER_YMM(...) TOLOWER(__VA_ARGS__, YMM) ++# define TOLOWER_XMM(...) TOLOWER(__VA_ARGS__, XMM) ++ ++# define CMP_R1_R2(s1_reg, s2_reg, reg_out, ext) \ ++ TOLOWER (s1_reg, s2_reg, ext); \ ++ VPCMP $0, s1_reg, s2_reg, reg_out ++ ++# define CMP_R1_S2(s1_reg, s2_mem, s2_reg, reg_out, ext) \ ++ VMOVU s2_mem, s2_reg; \ ++ CMP_R1_R2(s1_reg, s2_reg, reg_out, ext) ++ ++# define CMP_R1_R2_YMM(...) CMP_R1_R2(__VA_ARGS__, YMM) ++# define CMP_R1_R2_XMM(...) CMP_R1_R2(__VA_ARGS__, XMM) ++ ++# define CMP_R1_S2_YMM(...) CMP_R1_S2(__VA_ARGS__, YMM) ++# define CMP_R1_S2_XMM(...) CMP_R1_S2(__VA_ARGS__, XMM) ++ ++# else ++# define TOLOWER_gpr(...) ++# define TOLOWER_YMM(...) ++# define TOLOWER_XMM(...) ++ ++# define CMP_R1_R2_YMM(s1_reg, s2_reg, reg_out) \ ++ VPCMP $0, s2_reg, s1_reg, reg_out ++ ++# define CMP_R1_R2_XMM(...) CMP_R1_R2_YMM(__VA_ARGS__) ++ ++# define CMP_R1_S2_YMM(s1_reg, s2_mem, unused, reg_out) \ ++ VPCMP $0, s2_mem, s1_reg, reg_out ++ ++# define CMP_R1_S2_XMM(...) CMP_R1_S2_YMM(__VA_ARGS__) ++# endif + + /* Warning! + wcscmp/wcsncmp have to use SIGNED comparison for elements. +@@ -112,8 +211,45 @@ + returned. */ + + .section .text.evex, "ax", @progbits +-ENTRY(STRCMP) ++ .align 16 ++ .type STRCMP, @function ++ .globl STRCMP ++ .hidden STRCMP ++ ++# ifdef USE_AS_STRCASECMP_L ++ENTRY (STRCASECMP) ++ movq __libc_tsd_LOCALE@gottpoff(%rip), %rax ++ mov %fs:(%rax), %LOCALE_REG_LP ++ ++ /* Either 1 or 5 bytes (dependeing if CET is enabled). */ ++ .p2align 4 ++END (STRCASECMP) ++ /* FALLTHROUGH to strcasecmp/strncasecmp_l. */ ++# endif ++ ++ .p2align 4 ++STRCMP: ++ cfi_startproc ++ _CET_ENDBR ++ CALL_MCOUNT ++ ++# if defined USE_AS_STRCASECMP_L ++ /* We have to fall back on the C implementation for locales with ++ encodings not matching ASCII for single bytes. */ ++# if LOCALE_T___LOCALES != 0 || LC_CTYPE != 0 ++ mov LOCALE_T___LOCALES + LC_CTYPE * LP_SIZE(%LOCALE_REG), %RAX_LP ++# else ++ mov (%LOCALE_REG), %RAX_LP ++# endif ++ testl $1, LOCALE_DATA_VALUES + _NL_CTYPE_NONASCII_CASE * SIZEOF_VALUES(%rax) ++ jne STRCASECMP_NONASCII ++ leaq _nl_C_LC_CTYPE_tolower + 128 * 4(%rip), TOLOWER_BASE ++# endif ++ + # ifdef USE_AS_STRNCMP ++ /* Don't overwrite LOCALE_REG (rcx) until we have pass ++ L(one_or_less). Otherwise we might use the wrong locale in ++ the OVERFLOW_STRCMP (strcasecmp_l). */ + # ifdef __ILP32__ + /* Clear the upper 32 bits. */ + movl %edx, %edx +@@ -125,6 +261,32 @@ ENTRY(STRCMP) + actually bound the buffer. */ + jle L(one_or_less) + # endif ++ ++# if defined USE_AS_STRCASECMP_L ++ .section .rodata.cst32, "aM", @progbits, 32 ++ .align 32 ++L(lcase_min): ++ .quad 0x4141414141414141 ++ .quad 0x4141414141414141 ++ .quad 0x4141414141414141 ++ .quad 0x4141414141414141 ++L(lcase_max): ++ .quad 0x1a1a1a1a1a1a1a1a ++ .quad 0x1a1a1a1a1a1a1a1a ++ .quad 0x1a1a1a1a1a1a1a1a ++ .quad 0x1a1a1a1a1a1a1a1a ++L(case_add): ++ .quad 0x2020202020202020 ++ .quad 0x2020202020202020 ++ .quad 0x2020202020202020 ++ .quad 0x2020202020202020 ++ .previous ++ ++ vmovdqa64 L(lcase_min)(%rip), LCASE_MIN_YMM ++ vmovdqa64 L(lcase_max)(%rip), LCASE_MAX_YMM ++ vmovdqa64 L(case_add)(%rip), CASE_ADD_YMM ++# endif ++ + movl %edi, %eax + orl %esi, %eax + /* Shift out the bits irrelivant to page boundary ([63:12]). */ +@@ -139,7 +301,7 @@ L(no_page_cross): + VPTESTM %YMM0, %YMM0, %k2 + /* Each bit cleared in K1 represents a mismatch or a null CHAR + in YMM0 and 32 bytes at (%rsi). */ +- VPCMP $0, (%rsi), %YMM0, %k1{%k2} ++ CMP_R1_S2_YMM (%YMM0, (%rsi), %YMM1, %k1){%k2} + kmovd %k1, %ecx + # ifdef USE_AS_STRNCMP + cmpq $CHAR_PER_VEC, %rdx +@@ -169,6 +331,8 @@ L(return_vec_0): + # else + movzbl (%rdi, %rcx), %eax + movzbl (%rsi, %rcx), %ecx ++ TOLOWER_gpr (%rax, %eax) ++ TOLOWER_gpr (%rcx, %ecx) + subl %ecx, %eax + # endif + L(ret0): +@@ -188,11 +352,15 @@ L(ret_zero): + + .p2align 4,, 5 + L(one_or_less): ++# ifdef USE_AS_STRCASECMP_L ++ /* Set locale argument for strcasecmp. */ ++ movq %LOCALE_REG, %rdx ++# endif + jb L(ret_zero) +-# ifdef USE_AS_WCSCMP + /* 'nbe' covers the case where length is negative (large + unsigned). */ +- jnbe __wcscmp_evex ++ jnbe OVERFLOW_STRCMP ++# ifdef USE_AS_WCSCMP + movl (%rdi), %edx + xorl %eax, %eax + cmpl (%rsi), %edx +@@ -201,11 +369,10 @@ L(one_or_less): + negl %eax + orl $1, %eax + # else +- /* 'nbe' covers the case where length is negative (large +- unsigned). */ +- jnbe __strcmp_evex + movzbl (%rdi), %eax + movzbl (%rsi), %ecx ++ TOLOWER_gpr (%rax, %eax) ++ TOLOWER_gpr (%rcx, %ecx) + subl %ecx, %eax + # endif + L(ret1): +@@ -233,6 +400,8 @@ L(return_vec_1): + # else + movzbl VEC_SIZE(%rdi, %rcx), %eax + movzbl VEC_SIZE(%rsi, %rcx), %ecx ++ TOLOWER_gpr (%rax, %eax) ++ TOLOWER_gpr (%rcx, %ecx) + subl %ecx, %eax + # endif + L(ret2): +@@ -270,6 +439,8 @@ L(return_vec_2): + # else + movzbl (VEC_SIZE * 2)(%rdi, %rcx), %eax + movzbl (VEC_SIZE * 2)(%rsi, %rcx), %ecx ++ TOLOWER_gpr (%rax, %eax) ++ TOLOWER_gpr (%rcx, %ecx) + subl %ecx, %eax + # endif + L(ret3): +@@ -290,6 +461,8 @@ L(return_vec_3): + # else + movzbl (VEC_SIZE * 3)(%rdi, %rcx), %eax + movzbl (VEC_SIZE * 3)(%rsi, %rcx), %ecx ++ TOLOWER_gpr (%rax, %eax) ++ TOLOWER_gpr (%rcx, %ecx) + subl %ecx, %eax + # endif + L(ret4): +@@ -303,7 +476,7 @@ L(more_3x_vec): + /* Safe to compare 4x vectors. */ + VMOVU (VEC_SIZE)(%rdi), %YMM0 + VPTESTM %YMM0, %YMM0, %k2 +- VPCMP $0, (VEC_SIZE)(%rsi), %YMM0, %k1{%k2} ++ CMP_R1_S2_YMM (%YMM0, VEC_SIZE(%rsi), %YMM1, %k1){%k2} + kmovd %k1, %ecx + TESTEQ %ecx + jnz L(return_vec_1) +@@ -315,14 +488,14 @@ L(more_3x_vec): + + VMOVU (VEC_SIZE * 2)(%rdi), %YMM0 + VPTESTM %YMM0, %YMM0, %k2 +- VPCMP $0, (VEC_SIZE * 2)(%rsi), %YMM0, %k1{%k2} ++ CMP_R1_S2_YMM (%YMM0, (VEC_SIZE * 2)(%rsi), %YMM1, %k1){%k2} + kmovd %k1, %ecx + TESTEQ %ecx + jnz L(return_vec_2) + + VMOVU (VEC_SIZE * 3)(%rdi), %YMM0 + VPTESTM %YMM0, %YMM0, %k2 +- VPCMP $0, (VEC_SIZE * 3)(%rsi), %YMM0, %k1{%k2} ++ CMP_R1_S2_YMM (%YMM0, (VEC_SIZE * 3)(%rsi), %YMM1, %k1){%k2} + kmovd %k1, %ecx + TESTEQ %ecx + jnz L(return_vec_3) +@@ -381,7 +554,6 @@ L(prepare_loop_aligned): + subl %esi, %eax + andl $(PAGE_SIZE - 1), %eax + +- vpxorq %YMMZERO, %YMMZERO, %YMMZERO + + /* Loop 4x comparisons at a time. */ + .p2align 4 +@@ -413,22 +585,35 @@ L(loop_skip_page_cross_check): + /* A zero CHAR in YMM9 means that there is a null CHAR. */ + VPMINU %YMM8, %YMM9, %YMM9 + +- /* Each bit set in K1 represents a non-null CHAR in YMM8. */ ++ /* Each bit set in K1 represents a non-null CHAR in YMM9. */ + VPTESTM %YMM9, %YMM9, %k1 +- ++# ifndef USE_AS_STRCASECMP_L + vpxorq (VEC_SIZE * 0)(%rsi), %YMM0, %YMM1 + vpxorq (VEC_SIZE * 1)(%rsi), %YMM2, %YMM3 + vpxorq (VEC_SIZE * 2)(%rsi), %YMM4, %YMM5 + /* Ternary logic to xor (VEC_SIZE * 3)(%rsi) with YMM6 while + oring with YMM1. Result is stored in YMM6. */ + vpternlogd $0xde, (VEC_SIZE * 3)(%rsi), %YMM1, %YMM6 +- ++# else ++ VMOVU (VEC_SIZE * 0)(%rsi), %YMM1 ++ TOLOWER_YMM (%YMM0, %YMM1) ++ VMOVU (VEC_SIZE * 1)(%rsi), %YMM3 ++ TOLOWER_YMM (%YMM2, %YMM3) ++ VMOVU (VEC_SIZE * 2)(%rsi), %YMM5 ++ TOLOWER_YMM (%YMM4, %YMM5) ++ VMOVU (VEC_SIZE * 3)(%rsi), %YMM7 ++ TOLOWER_YMM (%YMM6, %YMM7) ++ vpxorq %YMM0, %YMM1, %YMM1 ++ vpxorq %YMM2, %YMM3, %YMM3 ++ vpxorq %YMM4, %YMM5, %YMM5 ++ vpternlogd $0xde, %YMM7, %YMM1, %YMM6 ++# endif + /* Or together YMM3, YMM5, and YMM6. */ + vpternlogd $0xfe, %YMM3, %YMM5, %YMM6 + + + /* A non-zero CHAR in YMM6 represents a mismatch. */ +- VPCMP $0, %YMMZERO, %YMM6, %k0{%k1} ++ VPTESTNM %YMM6, %YMM6, %k0{%k1} + kmovd %k0, %LOOP_REG + + TESTEQ %LOOP_REG +@@ -437,13 +622,13 @@ L(loop_skip_page_cross_check): + + /* Find which VEC has the mismatch of end of string. */ + VPTESTM %YMM0, %YMM0, %k1 +- VPCMP $0, %YMMZERO, %YMM1, %k0{%k1} ++ VPTESTNM %YMM1, %YMM1, %k0{%k1} + kmovd %k0, %ecx + TESTEQ %ecx + jnz L(return_vec_0_end) + + VPTESTM %YMM2, %YMM2, %k1 +- VPCMP $0, %YMMZERO, %YMM3, %k0{%k1} ++ VPTESTNM %YMM3, %YMM3, %k0{%k1} + kmovd %k0, %ecx + TESTEQ %ecx + jnz L(return_vec_1_end) +@@ -457,7 +642,7 @@ L(return_vec_2_3_end): + # endif + + VPTESTM %YMM4, %YMM4, %k1 +- VPCMP $0, %YMMZERO, %YMM5, %k0{%k1} ++ VPTESTNM %YMM5, %YMM5, %k0{%k1} + kmovd %k0, %ecx + TESTEQ %ecx + # if CHAR_PER_VEC <= 16 +@@ -493,6 +678,8 @@ L(return_vec_3_end): + # else + movzbl (VEC_SIZE * 2)(%rdi, %LOOP_REG64), %eax + movzbl (VEC_SIZE * 2)(%rsi, %LOOP_REG64), %ecx ++ TOLOWER_gpr (%rax, %eax) ++ TOLOWER_gpr (%rcx, %ecx) + subl %ecx, %eax + xorl %r8d, %eax + subl %r8d, %eax +@@ -545,6 +732,8 @@ L(return_vec_0_end): + # else + movzbl (%rdi, %rcx), %eax + movzbl (%rsi, %rcx), %ecx ++ TOLOWER_gpr (%rax, %eax) ++ TOLOWER_gpr (%rcx, %ecx) + subl %ecx, %eax + /* Flip `eax` if `rdi` and `rsi` where swapped in page cross + logic. Subtract `r8d` after xor for zero case. */ +@@ -569,6 +758,8 @@ L(return_vec_1_end): + # else + movzbl VEC_SIZE(%rdi, %rcx), %eax + movzbl VEC_SIZE(%rsi, %rcx), %ecx ++ TOLOWER_gpr (%rax, %eax) ++ TOLOWER_gpr (%rcx, %ecx) + subl %ecx, %eax + xorl %r8d, %eax + subl %r8d, %eax +@@ -598,7 +789,7 @@ L(page_cross_during_loop): + + VMOVA (%rdi), %YMM0 + VPTESTM %YMM0, %YMM0, %k2 +- VPCMP $0, (%rsi), %YMM0, %k1{%k2} ++ CMP_R1_S2_YMM (%YMM0, (%rsi), %YMM1, %k1){%k2} + kmovd %k1, %ecx + TESTEQ %ecx + jnz L(return_vec_0_end) +@@ -619,8 +810,7 @@ L(less_1x_vec_till_page_cross): + been loaded earlier so must be valid. */ + VMOVU -VEC_SIZE(%rdi, %rax), %YMM0 + VPTESTM %YMM0, %YMM0, %k2 +- VPCMP $0, -VEC_SIZE(%rsi, %rax), %YMM0, %k1{%k2} +- ++ CMP_R1_S2_YMM (%YMM0, -VEC_SIZE(%rsi, %rax), %YMM1, %k1){%k2} + /* Mask of potentially valid bits. The lower bits can be out of + range comparisons (but safe regarding page crosses). */ + +@@ -642,6 +832,8 @@ L(less_1x_vec_till_page_cross): + + # ifdef USE_AS_STRNCMP + # ifdef USE_AS_WCSCMP ++ /* NB: strcasecmp not used with WCSCMP so this access to r11 is ++ safe. */ + movl %eax, %r11d + shrl $2, %r11d + cmpq %r11, %rdx +@@ -679,6 +871,8 @@ L(return_page_cross_cmp_mem): + # else + movzbl VEC_OFFSET(%rdi, %rcx), %eax + movzbl VEC_OFFSET(%rsi, %rcx), %ecx ++ TOLOWER_gpr (%rax, %eax) ++ TOLOWER_gpr (%rcx, %ecx) + subl %ecx, %eax + xorl %r8d, %eax + subl %r8d, %eax +@@ -709,7 +903,7 @@ L(more_2x_vec_till_page_cross): + + VMOVA VEC_SIZE(%rdi), %YMM0 + VPTESTM %YMM0, %YMM0, %k2 +- VPCMP $0, VEC_SIZE(%rsi), %YMM0, %k1{%k2} ++ CMP_R1_S2_YMM (%YMM0, VEC_SIZE(%rsi), %YMM1, %k1){%k2} + kmovd %k1, %ecx + TESTEQ %ecx + jnz L(return_vec_1_end) +@@ -724,14 +918,14 @@ L(more_2x_vec_till_page_cross): + /* Safe to include comparisons from lower bytes. */ + VMOVU -(VEC_SIZE * 2)(%rdi, %rax), %YMM0 + VPTESTM %YMM0, %YMM0, %k2 +- VPCMP $0, -(VEC_SIZE * 2)(%rsi, %rax), %YMM0, %k1{%k2} ++ CMP_R1_S2_YMM (%YMM0, -(VEC_SIZE * 2)(%rsi, %rax), %YMM1, %k1){%k2} + kmovd %k1, %ecx + TESTEQ %ecx + jnz L(return_vec_page_cross_0) + + VMOVU -(VEC_SIZE * 1)(%rdi, %rax), %YMM0 + VPTESTM %YMM0, %YMM0, %k2 +- VPCMP $0, -(VEC_SIZE * 1)(%rsi, %rax), %YMM0, %k1{%k2} ++ CMP_R1_S2_YMM (%YMM0, -(VEC_SIZE * 1)(%rsi, %rax), %YMM1, %k1){%k2} + kmovd %k1, %ecx + TESTEQ %ecx + jnz L(return_vec_page_cross_1) +@@ -740,6 +934,8 @@ L(more_2x_vec_till_page_cross): + /* Must check length here as length might proclude reading next + page. */ + # ifdef USE_AS_WCSCMP ++ /* NB: strcasecmp not used with WCSCMP so this access to r11 is ++ safe. */ + movl %eax, %r11d + shrl $2, %r11d + cmpq %r11, %rdx +@@ -754,12 +950,19 @@ L(more_2x_vec_till_page_cross): + VMOVA (VEC_SIZE * 3)(%rdi), %YMM6 + VPMINU %YMM4, %YMM6, %YMM9 + VPTESTM %YMM9, %YMM9, %k1 +- ++# ifndef USE_AS_STRCASECMP_L + vpxorq (VEC_SIZE * 2)(%rsi), %YMM4, %YMM5 + /* YMM6 = YMM5 | ((VEC_SIZE * 3)(%rsi) ^ YMM6). */ + vpternlogd $0xde, (VEC_SIZE * 3)(%rsi), %YMM5, %YMM6 +- +- VPCMP $0, %YMMZERO, %YMM6, %k0{%k1} ++# else ++ VMOVU (VEC_SIZE * 2)(%rsi), %YMM5 ++ TOLOWER_YMM (%YMM4, %YMM5) ++ VMOVU (VEC_SIZE * 3)(%rsi), %YMM7 ++ TOLOWER_YMM (%YMM6, %YMM7) ++ vpxorq %YMM4, %YMM5, %YMM5 ++ vpternlogd $0xde, %YMM7, %YMM5, %YMM6 ++# endif ++ VPTESTNM %YMM6, %YMM6, %k0{%k1} + kmovd %k0, %LOOP_REG + TESTEQ %LOOP_REG + jnz L(return_vec_2_3_end) +@@ -815,6 +1018,8 @@ L(return_vec_page_cross_1): + # else + movzbl VEC_OFFSET(%rdi, %rcx), %eax + movzbl VEC_OFFSET(%rsi, %rcx), %ecx ++ TOLOWER_gpr (%rax, %eax) ++ TOLOWER_gpr (%rcx, %ecx) + subl %ecx, %eax + xorl %r8d, %eax + subl %r8d, %eax +@@ -871,7 +1076,7 @@ L(page_cross): + L(page_cross_loop): + VMOVU (%rdi, %OFFSET_REG64, SIZE_OF_CHAR), %YMM0 + VPTESTM %YMM0, %YMM0, %k2 +- VPCMP $0, (%rsi, %OFFSET_REG64, SIZE_OF_CHAR), %YMM0, %k1{%k2} ++ CMP_R1_S2_YMM (%YMM0, (%rsi, %OFFSET_REG64, SIZE_OF_CHAR), %YMM1, %k1){%k2} + kmovd %k1, %ecx + TESTEQ %ecx + jnz L(check_ret_vec_page_cross) +@@ -895,7 +1100,7 @@ L(page_cross_loop): + */ + VMOVU (%rdi, %OFFSET_REG64, SIZE_OF_CHAR), %YMM0 + VPTESTM %YMM0, %YMM0, %k2 +- VPCMP $0, (%rsi, %OFFSET_REG64, SIZE_OF_CHAR), %YMM0, %k1{%k2} ++ CMP_R1_S2_YMM (%YMM0, (%rsi, %OFFSET_REG64, SIZE_OF_CHAR), %YMM1, %k1){%k2} + + kmovd %k1, %ecx + # ifdef USE_AS_STRNCMP +@@ -930,6 +1135,8 @@ L(ret_vec_page_cross_cont): + # else + movzbl (%rdi, %rcx, SIZE_OF_CHAR), %eax + movzbl (%rsi, %rcx, SIZE_OF_CHAR), %ecx ++ TOLOWER_gpr (%rax, %eax) ++ TOLOWER_gpr (%rcx, %ecx) + subl %ecx, %eax + xorl %r8d, %eax + subl %r8d, %eax +@@ -989,7 +1196,7 @@ L(less_1x_vec_till_page): + /* Use 16 byte comparison. */ + vmovdqu (%rdi), %xmm0 + VPTESTM %xmm0, %xmm0, %k2 +- VPCMP $0, (%rsi), %xmm0, %k1{%k2} ++ CMP_R1_S2_XMM (%xmm0, (%rsi), %xmm1, %k1){%k2} + kmovd %k1, %ecx + # ifdef USE_AS_WCSCMP + subl $0xf, %ecx +@@ -1009,7 +1216,7 @@ L(less_1x_vec_till_page): + # endif + vmovdqu (%rdi, %OFFSET_REG64, SIZE_OF_CHAR), %xmm0 + VPTESTM %xmm0, %xmm0, %k2 +- VPCMP $0, (%rsi, %OFFSET_REG64, SIZE_OF_CHAR), %xmm0, %k1{%k2} ++ CMP_R1_S2_XMM (%xmm0, (%rsi, %OFFSET_REG64, SIZE_OF_CHAR), %xmm1, %k1){%k2} + kmovd %k1, %ecx + # ifdef USE_AS_WCSCMP + subl $0xf, %ecx +@@ -1048,7 +1255,7 @@ L(less_16_till_page): + vmovq (%rdi), %xmm0 + vmovq (%rsi), %xmm1 + VPTESTM %xmm0, %xmm0, %k2 +- VPCMP $0, %xmm1, %xmm0, %k1{%k2} ++ CMP_R1_R2_XMM (%xmm0, %xmm1, %k1){%k2} + kmovd %k1, %ecx + # ifdef USE_AS_WCSCMP + subl $0x3, %ecx +@@ -1068,7 +1275,7 @@ L(less_16_till_page): + vmovq (%rdi, %OFFSET_REG64, SIZE_OF_CHAR), %xmm0 + vmovq (%rsi, %OFFSET_REG64, SIZE_OF_CHAR), %xmm1 + VPTESTM %xmm0, %xmm0, %k2 +- VPCMP $0, %xmm1, %xmm0, %k1{%k2} ++ CMP_R1_R2_XMM (%xmm0, %xmm1, %k1){%k2} + kmovd %k1, %ecx + # ifdef USE_AS_WCSCMP + subl $0x3, %ecx +@@ -1128,7 +1335,7 @@ L(ret_less_8_wcs): + vmovd (%rdi), %xmm0 + vmovd (%rsi), %xmm1 + VPTESTM %xmm0, %xmm0, %k2 +- VPCMP $0, %xmm1, %xmm0, %k1{%k2} ++ CMP_R1_R2_XMM (%xmm0, %xmm1, %k1){%k2} + kmovd %k1, %ecx + subl $0xf, %ecx + jnz L(check_ret_vec_page_cross) +@@ -1143,7 +1350,7 @@ L(ret_less_8_wcs): + vmovd (%rdi, %OFFSET_REG64, SIZE_OF_CHAR), %xmm0 + vmovd (%rsi, %OFFSET_REG64, SIZE_OF_CHAR), %xmm1 + VPTESTM %xmm0, %xmm0, %k2 +- VPCMP $0, %xmm1, %xmm0, %k1{%k2} ++ CMP_R1_R2_XMM (%xmm0, %xmm1, %k1){%k2} + kmovd %k1, %ecx + subl $0xf, %ecx + jnz L(check_ret_vec_page_cross) +@@ -1176,7 +1383,9 @@ L(less_4_till_page): + L(less_4_loop): + movzbl (%rdi), %eax + movzbl (%rsi, %rdi), %ecx +- subl %ecx, %eax ++ TOLOWER_gpr (%rax, %eax) ++ TOLOWER_gpr (%rcx, %BYTE_LOOP_REG) ++ subl %BYTE_LOOP_REG, %eax + jnz L(ret_less_4_loop) + testl %ecx, %ecx + jz L(ret_zero_4_loop) +@@ -1203,5 +1412,6 @@ L(ret_less_4_loop): + subl %r8d, %eax + ret + # endif +-END(STRCMP) ++ cfi_endproc ++ .size STRCMP, .-STRCMP + #endif +diff --git a/sysdeps/x86_64/multiarch/strncase_l-evex.S b/sysdeps/x86_64/multiarch/strncase_l-evex.S +new file mode 100644 +index 00000000..8a5af369 +--- /dev/null ++++ b/sysdeps/x86_64/multiarch/strncase_l-evex.S +@@ -0,0 +1,25 @@ ++/* strncasecmp_l optimized with EVEX. ++ Copyright (C) 2017-2022 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#ifndef STRCMP ++# define STRCMP __strncasecmp_l_evex ++#endif ++#define OVERFLOW_STRCMP __strcasecmp_l_evex ++#define USE_AS_STRCASECMP_L ++#define USE_AS_STRNCMP ++#include "strcmp-evex.S" +-- +GitLab + diff --git a/SOURCES/glibc-RHEL-15696-99.patch b/SOURCES/glibc-RHEL-15696-99.patch new file mode 100644 index 0000000..06d5d53 --- /dev/null +++ b/SOURCES/glibc-RHEL-15696-99.patch @@ -0,0 +1,913 @@ +From 305769b2a15c2e96f9e1b5195d3c4e0d6f0f4b68 Mon Sep 17 00:00:00 2001 +From: Noah Goldstein +Date: Wed, 23 Mar 2022 16:57:46 -0500 +Subject: [PATCH] x86: Remove AVX str{n}casecmp +Content-type: text/plain; charset=UTF-8 + +The rational is: + +1. SSE42 has nearly identical logic so any benefit is minimal (3.4% + regression on Tigerlake using SSE42 versus AVX across the + benchtest suite). +2. AVX2 version covers the majority of targets that previously + prefered it. +3. The targets where AVX would still be best (SnB and IVB) are + becoming outdated. + +All in all the saving the code size is worth it. + +All string/memory tests pass. +Reviewed-by: H.J. Lu +--- + sysdeps/x86_64/multiarch/Makefile | 2 - + sysdeps/x86_64/multiarch/ifunc-impl-list.c | 12 - + sysdeps/x86_64/multiarch/ifunc-strcasecmp.h | 4 - + sysdeps/x86_64/multiarch/strcasecmp_l-avx.S | 22 -- + sysdeps/x86_64/multiarch/strcmp-sse42.S | 240 +++++++++----------- + sysdeps/x86_64/multiarch/strncase_l-avx.S | 22 -- + 6 files changed, 105 insertions(+), 197 deletions(-) + delete mode 100644 sysdeps/x86_64/multiarch/strcasecmp_l-avx.S + delete mode 100644 sysdeps/x86_64/multiarch/strncase_l-avx.S + +diff --git a/sysdeps/x86_64/multiarch/Makefile b/sysdeps/x86_64/multiarch/Makefile +index 359712c1..bca82e38 100644 +--- a/sysdeps/x86_64/multiarch/Makefile ++++ b/sysdeps/x86_64/multiarch/Makefile +@@ -50,7 +50,6 @@ sysdep_routines += \ + stpncpy-evex \ + stpncpy-sse2-unaligned \ + stpncpy-ssse3 \ +- strcasecmp_l-avx \ + strcasecmp_l-avx2 \ + strcasecmp_l-avx2-rtm \ + strcasecmp_l-evex \ +@@ -91,7 +90,6 @@ sysdep_routines += \ + strlen-avx2-rtm \ + strlen-evex \ + strlen-sse2 \ +- strncase_l-avx \ + strncase_l-avx2 \ + strncase_l-avx2-rtm \ + strncase_l-evex \ +diff --git a/sysdeps/x86_64/multiarch/ifunc-impl-list.c b/sysdeps/x86_64/multiarch/ifunc-impl-list.c +index 1dedc637..14314367 100644 +--- a/sysdeps/x86_64/multiarch/ifunc-impl-list.c ++++ b/sysdeps/x86_64/multiarch/ifunc-impl-list.c +@@ -429,9 +429,6 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + (CPU_FEATURE_USABLE (AVX2) + && CPU_FEATURE_USABLE (RTM)), + __strcasecmp_avx2_rtm) +- IFUNC_IMPL_ADD (array, i, strcasecmp, +- CPU_FEATURE_USABLE (AVX), +- __strcasecmp_avx) + IFUNC_IMPL_ADD (array, i, strcasecmp, + CPU_FEATURE_USABLE (SSE4_2), + __strcasecmp_sse42) +@@ -453,9 +450,6 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + (CPU_FEATURE_USABLE (AVX2) + && CPU_FEATURE_USABLE (RTM)), + __strcasecmp_l_avx2_rtm) +- IFUNC_IMPL_ADD (array, i, strcasecmp_l, +- CPU_FEATURE_USABLE (AVX), +- __strcasecmp_l_avx) + IFUNC_IMPL_ADD (array, i, strcasecmp_l, + CPU_FEATURE_USABLE (SSE4_2), + __strcasecmp_l_sse42) +@@ -591,9 +585,6 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + (CPU_FEATURE_USABLE (AVX2) + && CPU_FEATURE_USABLE (RTM)), + __strncasecmp_avx2_rtm) +- IFUNC_IMPL_ADD (array, i, strncasecmp, +- CPU_FEATURE_USABLE (AVX), +- __strncasecmp_avx) + IFUNC_IMPL_ADD (array, i, strncasecmp, + CPU_FEATURE_USABLE (SSE4_2), + __strncasecmp_sse42) +@@ -616,9 +607,6 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + (CPU_FEATURE_USABLE (AVX2) + && CPU_FEATURE_USABLE (RTM)), + __strncasecmp_l_avx2_rtm) +- IFUNC_IMPL_ADD (array, i, strncasecmp_l, +- CPU_FEATURE_USABLE (AVX), +- __strncasecmp_l_avx) + IFUNC_IMPL_ADD (array, i, strncasecmp_l, + CPU_FEATURE_USABLE (SSE4_2), + __strncasecmp_l_sse42) +diff --git a/sysdeps/x86_64/multiarch/ifunc-strcasecmp.h b/sysdeps/x86_64/multiarch/ifunc-strcasecmp.h +index 6dd49a21..34cfbb8f 100644 +--- a/sysdeps/x86_64/multiarch/ifunc-strcasecmp.h ++++ b/sysdeps/x86_64/multiarch/ifunc-strcasecmp.h +@@ -22,7 +22,6 @@ + extern __typeof (REDIRECT_NAME) OPTIMIZE (sse2) attribute_hidden; + extern __typeof (REDIRECT_NAME) OPTIMIZE (ssse3) attribute_hidden; + extern __typeof (REDIRECT_NAME) OPTIMIZE (sse42) attribute_hidden; +-extern __typeof (REDIRECT_NAME) OPTIMIZE (avx) attribute_hidden; + extern __typeof (REDIRECT_NAME) OPTIMIZE (avx2) attribute_hidden; + extern __typeof (REDIRECT_NAME) OPTIMIZE (avx2_rtm) attribute_hidden; + extern __typeof (REDIRECT_NAME) OPTIMIZE (evex) attribute_hidden; +@@ -46,9 +45,6 @@ IFUNC_SELECTOR (void) + return OPTIMIZE (avx2); + } + +- if (CPU_FEATURE_USABLE_P (cpu_features, AVX)) +- return OPTIMIZE (avx); +- + if (CPU_FEATURE_USABLE_P (cpu_features, SSE4_2) + && !CPU_FEATURES_ARCH_P (cpu_features, Slow_SSE4_2)) + return OPTIMIZE (sse42); +diff --git a/sysdeps/x86_64/multiarch/strcasecmp_l-avx.S b/sysdeps/x86_64/multiarch/strcasecmp_l-avx.S +deleted file mode 100644 +index 56a03547..00000000 +--- a/sysdeps/x86_64/multiarch/strcasecmp_l-avx.S ++++ /dev/null +@@ -1,22 +0,0 @@ +-/* strcasecmp_l optimized with AVX. +- 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 +- . */ +- +-#define STRCMP_SSE42 __strcasecmp_l_avx +-#define USE_AVX 1 +-#define USE_AS_STRCASECMP_L +-#include "strcmp-sse42.S" +diff --git a/sysdeps/x86_64/multiarch/strcmp-sse42.S b/sysdeps/x86_64/multiarch/strcmp-sse42.S +index 59e8ddfc..0a42b7a4 100644 +--- a/sysdeps/x86_64/multiarch/strcmp-sse42.S ++++ b/sysdeps/x86_64/multiarch/strcmp-sse42.S +@@ -42,13 +42,8 @@ + # define UPDATE_STRNCMP_COUNTER + #endif + +-#ifdef USE_AVX +-# define SECTION avx +-# define GLABEL(l) l##_avx +-#else +-# define SECTION sse4.2 +-# define GLABEL(l) l##_sse42 +-#endif ++#define SECTION sse4.2 ++#define GLABEL(l) l##_sse42 + + #define LABEL(l) .L##l + +@@ -106,21 +101,7 @@ END (GLABEL(__strncasecmp)) + #endif + + +-#ifdef USE_AVX +-# define movdqa vmovdqa +-# define movdqu vmovdqu +-# define pmovmskb vpmovmskb +-# define pcmpistri vpcmpistri +-# define psubb vpsubb +-# define pcmpeqb vpcmpeqb +-# define psrldq vpsrldq +-# define pslldq vpslldq +-# define palignr vpalignr +-# define pxor vpxor +-# define D(arg) arg, arg +-#else +-# define D(arg) arg +-#endif ++#define arg arg + + STRCMP_SSE42: + cfi_startproc +@@ -192,18 +173,7 @@ LABEL(case_add): + movdqu (%rdi), %xmm1 + movdqu (%rsi), %xmm2 + #if defined USE_AS_STRCASECMP_L || defined USE_AS_STRNCASECMP_L +-# ifdef USE_AVX +-# define TOLOWER(reg1, reg2) \ +- vpaddb LCASE_MIN_reg, reg1, %xmm7; \ +- vpaddb LCASE_MIN_reg, reg2, %xmm8; \ +- vpcmpgtb LCASE_MAX_reg, %xmm7, %xmm7; \ +- vpcmpgtb LCASE_MAX_reg, %xmm8, %xmm8; \ +- vpandn CASE_ADD_reg, %xmm7, %xmm7; \ +- vpandn CASE_ADD_reg, %xmm8, %xmm8; \ +- vpaddb %xmm7, reg1, reg1; \ +- vpaddb %xmm8, reg2, reg2 +-# else +-# define TOLOWER(reg1, reg2) \ ++# define TOLOWER(reg1, reg2) \ + movdqa LCASE_MIN_reg, %xmm7; \ + movdqa LCASE_MIN_reg, %xmm8; \ + paddb reg1, %xmm7; \ +@@ -214,15 +184,15 @@ LABEL(case_add): + pandn CASE_ADD_reg, %xmm8; \ + paddb %xmm7, reg1; \ + paddb %xmm8, reg2 +-# endif ++ + TOLOWER (%xmm1, %xmm2) + #else + # define TOLOWER(reg1, reg2) + #endif +- pxor %xmm0, D(%xmm0) /* clear %xmm0 for null char checks */ +- pcmpeqb %xmm1, D(%xmm0) /* Any null chars? */ +- pcmpeqb %xmm2, D(%xmm1) /* compare first 16 bytes for equality */ +- psubb %xmm0, D(%xmm1) /* packed sub of comparison results*/ ++ pxor %xmm0, %xmm0 /* clear %xmm0 for null char checks */ ++ pcmpeqb %xmm1, %xmm0 /* Any null chars? */ ++ pcmpeqb %xmm2, %xmm1 /* compare first 16 bytes for equality */ ++ psubb %xmm0, %xmm1 /* packed sub of comparison results*/ + pmovmskb %xmm1, %edx + sub $0xffff, %edx /* if first 16 bytes are same, edx == 0xffff */ + jnz LABEL(less16bytes)/* If not, find different value or null char */ +@@ -246,7 +216,7 @@ LABEL(crosscache): + xor %r8d, %r8d + and $0xf, %ecx /* offset of rsi */ + and $0xf, %eax /* offset of rdi */ +- pxor %xmm0, D(%xmm0) /* clear %xmm0 for null char check */ ++ pxor %xmm0, %xmm0 /* clear %xmm0 for null char check */ + cmp %eax, %ecx + je LABEL(ashr_0) /* rsi and rdi relative offset same */ + ja LABEL(bigger) +@@ -260,7 +230,7 @@ LABEL(bigger): + sub %rcx, %r9 + lea LABEL(unaligned_table)(%rip), %r10 + movslq (%r10, %r9,4), %r9 +- pcmpeqb %xmm1, D(%xmm0) /* Any null chars? */ ++ pcmpeqb %xmm1, %xmm0 /* Any null chars? */ + lea (%r10, %r9), %r10 + _CET_NOTRACK jmp *%r10 /* jump to corresponding case */ + +@@ -273,15 +243,15 @@ LABEL(bigger): + LABEL(ashr_0): + + movdqa (%rsi), %xmm1 +- pcmpeqb %xmm1, D(%xmm0) /* Any null chars? */ ++ pcmpeqb %xmm1, %xmm0 /* Any null chars? */ + #if !defined USE_AS_STRCASECMP_L && !defined USE_AS_STRNCASECMP_L +- pcmpeqb (%rdi), D(%xmm1) /* compare 16 bytes for equality */ ++ pcmpeqb (%rdi), %xmm1 /* compare 16 bytes for equality */ + #else + movdqa (%rdi), %xmm2 + TOLOWER (%xmm1, %xmm2) +- pcmpeqb %xmm2, D(%xmm1) /* compare 16 bytes for equality */ ++ pcmpeqb %xmm2, %xmm1 /* compare 16 bytes for equality */ + #endif +- psubb %xmm0, D(%xmm1) /* packed sub of comparison results*/ ++ psubb %xmm0, %xmm1 /* packed sub of comparison results*/ + pmovmskb %xmm1, %r9d + shr %cl, %edx /* adjust 0xffff for offset */ + shr %cl, %r9d /* adjust for 16-byte offset */ +@@ -361,10 +331,10 @@ LABEL(ashr_0_exit_use): + */ + .p2align 4 + LABEL(ashr_1): +- pslldq $15, D(%xmm2) /* shift first string to align with second */ ++ pslldq $15, %xmm2 /* shift first string to align with second */ + TOLOWER (%xmm1, %xmm2) +- pcmpeqb %xmm1, D(%xmm2) /* compare 16 bytes for equality */ +- psubb %xmm0, D(%xmm2) /* packed sub of comparison results*/ ++ pcmpeqb %xmm1, %xmm2 /* compare 16 bytes for equality */ ++ psubb %xmm0, %xmm2 /* packed sub of comparison results*/ + pmovmskb %xmm2, %r9d + shr %cl, %edx /* adjust 0xffff for offset */ + shr %cl, %r9d /* adjust for 16-byte offset */ +@@ -392,7 +362,7 @@ LABEL(loop_ashr_1_use): + + LABEL(nibble_ashr_1_restart_use): + movdqa (%rdi, %rdx), %xmm0 +- palignr $1, -16(%rdi, %rdx), D(%xmm0) ++ palignr $1, -16(%rdi, %rdx), %xmm0 + #if !defined USE_AS_STRCASECMP_L && !defined USE_AS_STRNCASECMP_L + pcmpistri $0x1a,(%rsi,%rdx), %xmm0 + #else +@@ -411,7 +381,7 @@ LABEL(nibble_ashr_1_restart_use): + jg LABEL(nibble_ashr_1_use) + + movdqa (%rdi, %rdx), %xmm0 +- palignr $1, -16(%rdi, %rdx), D(%xmm0) ++ palignr $1, -16(%rdi, %rdx), %xmm0 + #if !defined USE_AS_STRCASECMP_L && !defined USE_AS_STRNCASECMP_L + pcmpistri $0x1a,(%rsi,%rdx), %xmm0 + #else +@@ -431,7 +401,7 @@ LABEL(nibble_ashr_1_restart_use): + LABEL(nibble_ashr_1_use): + sub $0x1000, %r10 + movdqa -16(%rdi, %rdx), %xmm0 +- psrldq $1, D(%xmm0) ++ psrldq $1, %xmm0 + pcmpistri $0x3a,%xmm0, %xmm0 + #if defined USE_AS_STRNCMP || defined USE_AS_STRNCASECMP_L + cmp %r11, %rcx +@@ -449,10 +419,10 @@ LABEL(nibble_ashr_1_use): + */ + .p2align 4 + LABEL(ashr_2): +- pslldq $14, D(%xmm2) ++ pslldq $14, %xmm2 + TOLOWER (%xmm1, %xmm2) +- pcmpeqb %xmm1, D(%xmm2) +- psubb %xmm0, D(%xmm2) ++ pcmpeqb %xmm1, %xmm2 ++ psubb %xmm0, %xmm2 + pmovmskb %xmm2, %r9d + shr %cl, %edx + shr %cl, %r9d +@@ -480,7 +450,7 @@ LABEL(loop_ashr_2_use): + + LABEL(nibble_ashr_2_restart_use): + movdqa (%rdi, %rdx), %xmm0 +- palignr $2, -16(%rdi, %rdx), D(%xmm0) ++ palignr $2, -16(%rdi, %rdx), %xmm0 + #if !defined USE_AS_STRCASECMP_L && !defined USE_AS_STRNCASECMP_L + pcmpistri $0x1a,(%rsi,%rdx), %xmm0 + #else +@@ -499,7 +469,7 @@ LABEL(nibble_ashr_2_restart_use): + jg LABEL(nibble_ashr_2_use) + + movdqa (%rdi, %rdx), %xmm0 +- palignr $2, -16(%rdi, %rdx), D(%xmm0) ++ palignr $2, -16(%rdi, %rdx), %xmm0 + #if !defined USE_AS_STRCASECMP_L && !defined USE_AS_STRNCASECMP_L + pcmpistri $0x1a,(%rsi,%rdx), %xmm0 + #else +@@ -519,7 +489,7 @@ LABEL(nibble_ashr_2_restart_use): + LABEL(nibble_ashr_2_use): + sub $0x1000, %r10 + movdqa -16(%rdi, %rdx), %xmm0 +- psrldq $2, D(%xmm0) ++ psrldq $2, %xmm0 + pcmpistri $0x3a,%xmm0, %xmm0 + #if defined USE_AS_STRNCMP || defined USE_AS_STRNCASECMP_L + cmp %r11, %rcx +@@ -537,10 +507,10 @@ LABEL(nibble_ashr_2_use): + */ + .p2align 4 + LABEL(ashr_3): +- pslldq $13, D(%xmm2) ++ pslldq $13, %xmm2 + TOLOWER (%xmm1, %xmm2) +- pcmpeqb %xmm1, D(%xmm2) +- psubb %xmm0, D(%xmm2) ++ pcmpeqb %xmm1, %xmm2 ++ psubb %xmm0, %xmm2 + pmovmskb %xmm2, %r9d + shr %cl, %edx + shr %cl, %r9d +@@ -568,7 +538,7 @@ LABEL(loop_ashr_3_use): + + LABEL(nibble_ashr_3_restart_use): + movdqa (%rdi, %rdx), %xmm0 +- palignr $3, -16(%rdi, %rdx), D(%xmm0) ++ palignr $3, -16(%rdi, %rdx), %xmm0 + #if !defined USE_AS_STRCASECMP_L && !defined USE_AS_STRNCASECMP_L + pcmpistri $0x1a,(%rsi,%rdx), %xmm0 + #else +@@ -587,7 +557,7 @@ LABEL(nibble_ashr_3_restart_use): + jg LABEL(nibble_ashr_3_use) + + movdqa (%rdi, %rdx), %xmm0 +- palignr $3, -16(%rdi, %rdx), D(%xmm0) ++ palignr $3, -16(%rdi, %rdx), %xmm0 + #if !defined USE_AS_STRCASECMP_L && !defined USE_AS_STRNCASECMP_L + pcmpistri $0x1a,(%rsi,%rdx), %xmm0 + #else +@@ -607,7 +577,7 @@ LABEL(nibble_ashr_3_restart_use): + LABEL(nibble_ashr_3_use): + sub $0x1000, %r10 + movdqa -16(%rdi, %rdx), %xmm0 +- psrldq $3, D(%xmm0) ++ psrldq $3, %xmm0 + pcmpistri $0x3a,%xmm0, %xmm0 + #if defined USE_AS_STRNCMP || defined USE_AS_STRNCASECMP_L + cmp %r11, %rcx +@@ -625,10 +595,10 @@ LABEL(nibble_ashr_3_use): + */ + .p2align 4 + LABEL(ashr_4): +- pslldq $12, D(%xmm2) ++ pslldq $12, %xmm2 + TOLOWER (%xmm1, %xmm2) +- pcmpeqb %xmm1, D(%xmm2) +- psubb %xmm0, D(%xmm2) ++ pcmpeqb %xmm1, %xmm2 ++ psubb %xmm0, %xmm2 + pmovmskb %xmm2, %r9d + shr %cl, %edx + shr %cl, %r9d +@@ -657,7 +627,7 @@ LABEL(loop_ashr_4_use): + + LABEL(nibble_ashr_4_restart_use): + movdqa (%rdi, %rdx), %xmm0 +- palignr $4, -16(%rdi, %rdx), D(%xmm0) ++ palignr $4, -16(%rdi, %rdx), %xmm0 + #if !defined USE_AS_STRCASECMP_L && !defined USE_AS_STRNCASECMP_L + pcmpistri $0x1a,(%rsi,%rdx), %xmm0 + #else +@@ -676,7 +646,7 @@ LABEL(nibble_ashr_4_restart_use): + jg LABEL(nibble_ashr_4_use) + + movdqa (%rdi, %rdx), %xmm0 +- palignr $4, -16(%rdi, %rdx), D(%xmm0) ++ palignr $4, -16(%rdi, %rdx), %xmm0 + #if !defined USE_AS_STRCASECMP_L && !defined USE_AS_STRNCASECMP_L + pcmpistri $0x1a,(%rsi,%rdx), %xmm0 + #else +@@ -696,7 +666,7 @@ LABEL(nibble_ashr_4_restart_use): + LABEL(nibble_ashr_4_use): + sub $0x1000, %r10 + movdqa -16(%rdi, %rdx), %xmm0 +- psrldq $4, D(%xmm0) ++ psrldq $4, %xmm0 + pcmpistri $0x3a,%xmm0, %xmm0 + #if defined USE_AS_STRNCMP || defined USE_AS_STRNCASECMP_L + cmp %r11, %rcx +@@ -714,10 +684,10 @@ LABEL(nibble_ashr_4_use): + */ + .p2align 4 + LABEL(ashr_5): +- pslldq $11, D(%xmm2) ++ pslldq $11, %xmm2 + TOLOWER (%xmm1, %xmm2) +- pcmpeqb %xmm1, D(%xmm2) +- psubb %xmm0, D(%xmm2) ++ pcmpeqb %xmm1, %xmm2 ++ psubb %xmm0, %xmm2 + pmovmskb %xmm2, %r9d + shr %cl, %edx + shr %cl, %r9d +@@ -746,7 +716,7 @@ LABEL(loop_ashr_5_use): + + LABEL(nibble_ashr_5_restart_use): + movdqa (%rdi, %rdx), %xmm0 +- palignr $5, -16(%rdi, %rdx), D(%xmm0) ++ palignr $5, -16(%rdi, %rdx), %xmm0 + #if !defined USE_AS_STRCASECMP_L && !defined USE_AS_STRNCASECMP_L + pcmpistri $0x1a,(%rsi,%rdx), %xmm0 + #else +@@ -766,7 +736,7 @@ LABEL(nibble_ashr_5_restart_use): + + movdqa (%rdi, %rdx), %xmm0 + +- palignr $5, -16(%rdi, %rdx), D(%xmm0) ++ palignr $5, -16(%rdi, %rdx), %xmm0 + #if !defined USE_AS_STRCASECMP_L && !defined USE_AS_STRNCASECMP_L + pcmpistri $0x1a,(%rsi,%rdx), %xmm0 + #else +@@ -786,7 +756,7 @@ LABEL(nibble_ashr_5_restart_use): + LABEL(nibble_ashr_5_use): + sub $0x1000, %r10 + movdqa -16(%rdi, %rdx), %xmm0 +- psrldq $5, D(%xmm0) ++ psrldq $5, %xmm0 + pcmpistri $0x3a,%xmm0, %xmm0 + #if defined USE_AS_STRNCMP || defined USE_AS_STRNCASECMP_L + cmp %r11, %rcx +@@ -804,10 +774,10 @@ LABEL(nibble_ashr_5_use): + */ + .p2align 4 + LABEL(ashr_6): +- pslldq $10, D(%xmm2) ++ pslldq $10, %xmm2 + TOLOWER (%xmm1, %xmm2) +- pcmpeqb %xmm1, D(%xmm2) +- psubb %xmm0, D(%xmm2) ++ pcmpeqb %xmm1, %xmm2 ++ psubb %xmm0, %xmm2 + pmovmskb %xmm2, %r9d + shr %cl, %edx + shr %cl, %r9d +@@ -836,7 +806,7 @@ LABEL(loop_ashr_6_use): + + LABEL(nibble_ashr_6_restart_use): + movdqa (%rdi, %rdx), %xmm0 +- palignr $6, -16(%rdi, %rdx), D(%xmm0) ++ palignr $6, -16(%rdi, %rdx), %xmm0 + #if !defined USE_AS_STRCASECMP_L && !defined USE_AS_STRNCASECMP_L + pcmpistri $0x1a,(%rsi,%rdx), %xmm0 + #else +@@ -855,7 +825,7 @@ LABEL(nibble_ashr_6_restart_use): + jg LABEL(nibble_ashr_6_use) + + movdqa (%rdi, %rdx), %xmm0 +- palignr $6, -16(%rdi, %rdx), D(%xmm0) ++ palignr $6, -16(%rdi, %rdx), %xmm0 + #if !defined USE_AS_STRCASECMP_L && !defined USE_AS_STRNCASECMP_L + pcmpistri $0x1a,(%rsi,%rdx), %xmm0 + #else +@@ -875,7 +845,7 @@ LABEL(nibble_ashr_6_restart_use): + LABEL(nibble_ashr_6_use): + sub $0x1000, %r10 + movdqa -16(%rdi, %rdx), %xmm0 +- psrldq $6, D(%xmm0) ++ psrldq $6, %xmm0 + pcmpistri $0x3a,%xmm0, %xmm0 + #if defined USE_AS_STRNCMP || defined USE_AS_STRNCASECMP_L + cmp %r11, %rcx +@@ -893,10 +863,10 @@ LABEL(nibble_ashr_6_use): + */ + .p2align 4 + LABEL(ashr_7): +- pslldq $9, D(%xmm2) ++ pslldq $9, %xmm2 + TOLOWER (%xmm1, %xmm2) +- pcmpeqb %xmm1, D(%xmm2) +- psubb %xmm0, D(%xmm2) ++ pcmpeqb %xmm1, %xmm2 ++ psubb %xmm0, %xmm2 + pmovmskb %xmm2, %r9d + shr %cl, %edx + shr %cl, %r9d +@@ -925,7 +895,7 @@ LABEL(loop_ashr_7_use): + + LABEL(nibble_ashr_7_restart_use): + movdqa (%rdi, %rdx), %xmm0 +- palignr $7, -16(%rdi, %rdx), D(%xmm0) ++ palignr $7, -16(%rdi, %rdx), %xmm0 + #if !defined USE_AS_STRCASECMP_L && !defined USE_AS_STRNCASECMP_L + pcmpistri $0x1a,(%rsi,%rdx), %xmm0 + #else +@@ -944,7 +914,7 @@ LABEL(nibble_ashr_7_restart_use): + jg LABEL(nibble_ashr_7_use) + + movdqa (%rdi, %rdx), %xmm0 +- palignr $7, -16(%rdi, %rdx), D(%xmm0) ++ palignr $7, -16(%rdi, %rdx), %xmm0 + #if !defined USE_AS_STRCASECMP_L && !defined USE_AS_STRNCASECMP_L + pcmpistri $0x1a,(%rsi,%rdx), %xmm0 + #else +@@ -964,7 +934,7 @@ LABEL(nibble_ashr_7_restart_use): + LABEL(nibble_ashr_7_use): + sub $0x1000, %r10 + movdqa -16(%rdi, %rdx), %xmm0 +- psrldq $7, D(%xmm0) ++ psrldq $7, %xmm0 + pcmpistri $0x3a,%xmm0, %xmm0 + #if defined USE_AS_STRNCMP || defined USE_AS_STRNCASECMP_L + cmp %r11, %rcx +@@ -982,10 +952,10 @@ LABEL(nibble_ashr_7_use): + */ + .p2align 4 + LABEL(ashr_8): +- pslldq $8, D(%xmm2) ++ pslldq $8, %xmm2 + TOLOWER (%xmm1, %xmm2) +- pcmpeqb %xmm1, D(%xmm2) +- psubb %xmm0, D(%xmm2) ++ pcmpeqb %xmm1, %xmm2 ++ psubb %xmm0, %xmm2 + pmovmskb %xmm2, %r9d + shr %cl, %edx + shr %cl, %r9d +@@ -1014,7 +984,7 @@ LABEL(loop_ashr_8_use): + + LABEL(nibble_ashr_8_restart_use): + movdqa (%rdi, %rdx), %xmm0 +- palignr $8, -16(%rdi, %rdx), D(%xmm0) ++ palignr $8, -16(%rdi, %rdx), %xmm0 + #if !defined USE_AS_STRCASECMP_L && !defined USE_AS_STRNCASECMP_L + pcmpistri $0x1a, (%rsi,%rdx), %xmm0 + #else +@@ -1033,7 +1003,7 @@ LABEL(nibble_ashr_8_restart_use): + jg LABEL(nibble_ashr_8_use) + + movdqa (%rdi, %rdx), %xmm0 +- palignr $8, -16(%rdi, %rdx), D(%xmm0) ++ palignr $8, -16(%rdi, %rdx), %xmm0 + #if !defined USE_AS_STRCASECMP_L && !defined USE_AS_STRNCASECMP_L + pcmpistri $0x1a, (%rsi,%rdx), %xmm0 + #else +@@ -1053,7 +1023,7 @@ LABEL(nibble_ashr_8_restart_use): + LABEL(nibble_ashr_8_use): + sub $0x1000, %r10 + movdqa -16(%rdi, %rdx), %xmm0 +- psrldq $8, D(%xmm0) ++ psrldq $8, %xmm0 + pcmpistri $0x3a,%xmm0, %xmm0 + #if defined USE_AS_STRNCMP || defined USE_AS_STRNCASECMP_L + cmp %r11, %rcx +@@ -1071,10 +1041,10 @@ LABEL(nibble_ashr_8_use): + */ + .p2align 4 + LABEL(ashr_9): +- pslldq $7, D(%xmm2) ++ pslldq $7, %xmm2 + TOLOWER (%xmm1, %xmm2) +- pcmpeqb %xmm1, D(%xmm2) +- psubb %xmm0, D(%xmm2) ++ pcmpeqb %xmm1, %xmm2 ++ psubb %xmm0, %xmm2 + pmovmskb %xmm2, %r9d + shr %cl, %edx + shr %cl, %r9d +@@ -1104,7 +1074,7 @@ LABEL(loop_ashr_9_use): + LABEL(nibble_ashr_9_restart_use): + movdqa (%rdi, %rdx), %xmm0 + +- palignr $9, -16(%rdi, %rdx), D(%xmm0) ++ palignr $9, -16(%rdi, %rdx), %xmm0 + #if !defined USE_AS_STRCASECMP_L && !defined USE_AS_STRNCASECMP_L + pcmpistri $0x1a, (%rsi,%rdx), %xmm0 + #else +@@ -1123,7 +1093,7 @@ LABEL(nibble_ashr_9_restart_use): + jg LABEL(nibble_ashr_9_use) + + movdqa (%rdi, %rdx), %xmm0 +- palignr $9, -16(%rdi, %rdx), D(%xmm0) ++ palignr $9, -16(%rdi, %rdx), %xmm0 + #if !defined USE_AS_STRCASECMP_L && !defined USE_AS_STRNCASECMP_L + pcmpistri $0x1a, (%rsi,%rdx), %xmm0 + #else +@@ -1143,7 +1113,7 @@ LABEL(nibble_ashr_9_restart_use): + LABEL(nibble_ashr_9_use): + sub $0x1000, %r10 + movdqa -16(%rdi, %rdx), %xmm0 +- psrldq $9, D(%xmm0) ++ psrldq $9, %xmm0 + pcmpistri $0x3a,%xmm0, %xmm0 + #if defined USE_AS_STRNCMP || defined USE_AS_STRNCASECMP_L + cmp %r11, %rcx +@@ -1161,10 +1131,10 @@ LABEL(nibble_ashr_9_use): + */ + .p2align 4 + LABEL(ashr_10): +- pslldq $6, D(%xmm2) ++ pslldq $6, %xmm2 + TOLOWER (%xmm1, %xmm2) +- pcmpeqb %xmm1, D(%xmm2) +- psubb %xmm0, D(%xmm2) ++ pcmpeqb %xmm1, %xmm2 ++ psubb %xmm0, %xmm2 + pmovmskb %xmm2, %r9d + shr %cl, %edx + shr %cl, %r9d +@@ -1193,7 +1163,7 @@ LABEL(loop_ashr_10_use): + + LABEL(nibble_ashr_10_restart_use): + movdqa (%rdi, %rdx), %xmm0 +- palignr $10, -16(%rdi, %rdx), D(%xmm0) ++ palignr $10, -16(%rdi, %rdx), %xmm0 + #if !defined USE_AS_STRCASECMP_L && !defined USE_AS_STRNCASECMP_L + pcmpistri $0x1a, (%rsi,%rdx), %xmm0 + #else +@@ -1212,7 +1182,7 @@ LABEL(nibble_ashr_10_restart_use): + jg LABEL(nibble_ashr_10_use) + + movdqa (%rdi, %rdx), %xmm0 +- palignr $10, -16(%rdi, %rdx), D(%xmm0) ++ palignr $10, -16(%rdi, %rdx), %xmm0 + #if !defined USE_AS_STRCASECMP_L && !defined USE_AS_STRNCASECMP_L + pcmpistri $0x1a, (%rsi,%rdx), %xmm0 + #else +@@ -1232,7 +1202,7 @@ LABEL(nibble_ashr_10_restart_use): + LABEL(nibble_ashr_10_use): + sub $0x1000, %r10 + movdqa -16(%rdi, %rdx), %xmm0 +- psrldq $10, D(%xmm0) ++ psrldq $10, %xmm0 + pcmpistri $0x3a,%xmm0, %xmm0 + #if defined USE_AS_STRNCMP || defined USE_AS_STRNCASECMP_L + cmp %r11, %rcx +@@ -1250,10 +1220,10 @@ LABEL(nibble_ashr_10_use): + */ + .p2align 4 + LABEL(ashr_11): +- pslldq $5, D(%xmm2) ++ pslldq $5, %xmm2 + TOLOWER (%xmm1, %xmm2) +- pcmpeqb %xmm1, D(%xmm2) +- psubb %xmm0, D(%xmm2) ++ pcmpeqb %xmm1, %xmm2 ++ psubb %xmm0, %xmm2 + pmovmskb %xmm2, %r9d + shr %cl, %edx + shr %cl, %r9d +@@ -1282,7 +1252,7 @@ LABEL(loop_ashr_11_use): + + LABEL(nibble_ashr_11_restart_use): + movdqa (%rdi, %rdx), %xmm0 +- palignr $11, -16(%rdi, %rdx), D(%xmm0) ++ palignr $11, -16(%rdi, %rdx), %xmm0 + #if !defined USE_AS_STRCASECMP_L && !defined USE_AS_STRNCASECMP_L + pcmpistri $0x1a, (%rsi,%rdx), %xmm0 + #else +@@ -1301,7 +1271,7 @@ LABEL(nibble_ashr_11_restart_use): + jg LABEL(nibble_ashr_11_use) + + movdqa (%rdi, %rdx), %xmm0 +- palignr $11, -16(%rdi, %rdx), D(%xmm0) ++ palignr $11, -16(%rdi, %rdx), %xmm0 + #if !defined USE_AS_STRCASECMP_L && !defined USE_AS_STRNCASECMP_L + pcmpistri $0x1a, (%rsi,%rdx), %xmm0 + #else +@@ -1321,7 +1291,7 @@ LABEL(nibble_ashr_11_restart_use): + LABEL(nibble_ashr_11_use): + sub $0x1000, %r10 + movdqa -16(%rdi, %rdx), %xmm0 +- psrldq $11, D(%xmm0) ++ psrldq $11, %xmm0 + pcmpistri $0x3a,%xmm0, %xmm0 + #if defined USE_AS_STRNCMP || defined USE_AS_STRNCASECMP_L + cmp %r11, %rcx +@@ -1339,10 +1309,10 @@ LABEL(nibble_ashr_11_use): + */ + .p2align 4 + LABEL(ashr_12): +- pslldq $4, D(%xmm2) ++ pslldq $4, %xmm2 + TOLOWER (%xmm1, %xmm2) +- pcmpeqb %xmm1, D(%xmm2) +- psubb %xmm0, D(%xmm2) ++ pcmpeqb %xmm1, %xmm2 ++ psubb %xmm0, %xmm2 + pmovmskb %xmm2, %r9d + shr %cl, %edx + shr %cl, %r9d +@@ -1371,7 +1341,7 @@ LABEL(loop_ashr_12_use): + + LABEL(nibble_ashr_12_restart_use): + movdqa (%rdi, %rdx), %xmm0 +- palignr $12, -16(%rdi, %rdx), D(%xmm0) ++ palignr $12, -16(%rdi, %rdx), %xmm0 + #if !defined USE_AS_STRCASECMP_L && !defined USE_AS_STRNCASECMP_L + pcmpistri $0x1a, (%rsi,%rdx), %xmm0 + #else +@@ -1390,7 +1360,7 @@ LABEL(nibble_ashr_12_restart_use): + jg LABEL(nibble_ashr_12_use) + + movdqa (%rdi, %rdx), %xmm0 +- palignr $12, -16(%rdi, %rdx), D(%xmm0) ++ palignr $12, -16(%rdi, %rdx), %xmm0 + #if !defined USE_AS_STRCASECMP_L && !defined USE_AS_STRNCASECMP_L + pcmpistri $0x1a, (%rsi,%rdx), %xmm0 + #else +@@ -1410,7 +1380,7 @@ LABEL(nibble_ashr_12_restart_use): + LABEL(nibble_ashr_12_use): + sub $0x1000, %r10 + movdqa -16(%rdi, %rdx), %xmm0 +- psrldq $12, D(%xmm0) ++ psrldq $12, %xmm0 + pcmpistri $0x3a,%xmm0, %xmm0 + #if defined USE_AS_STRNCMP || defined USE_AS_STRNCASECMP_L + cmp %r11, %rcx +@@ -1428,10 +1398,10 @@ LABEL(nibble_ashr_12_use): + */ + .p2align 4 + LABEL(ashr_13): +- pslldq $3, D(%xmm2) ++ pslldq $3, %xmm2 + TOLOWER (%xmm1, %xmm2) +- pcmpeqb %xmm1, D(%xmm2) +- psubb %xmm0, D(%xmm2) ++ pcmpeqb %xmm1, %xmm2 ++ psubb %xmm0, %xmm2 + pmovmskb %xmm2, %r9d + shr %cl, %edx + shr %cl, %r9d +@@ -1461,7 +1431,7 @@ LABEL(loop_ashr_13_use): + + LABEL(nibble_ashr_13_restart_use): + movdqa (%rdi, %rdx), %xmm0 +- palignr $13, -16(%rdi, %rdx), D(%xmm0) ++ palignr $13, -16(%rdi, %rdx), %xmm0 + #if !defined USE_AS_STRCASECMP_L && !defined USE_AS_STRNCASECMP_L + pcmpistri $0x1a, (%rsi,%rdx), %xmm0 + #else +@@ -1480,7 +1450,7 @@ LABEL(nibble_ashr_13_restart_use): + jg LABEL(nibble_ashr_13_use) + + movdqa (%rdi, %rdx), %xmm0 +- palignr $13, -16(%rdi, %rdx), D(%xmm0) ++ palignr $13, -16(%rdi, %rdx), %xmm0 + #if !defined USE_AS_STRCASECMP_L && !defined USE_AS_STRNCASECMP_L + pcmpistri $0x1a, (%rsi,%rdx), %xmm0 + #else +@@ -1500,7 +1470,7 @@ LABEL(nibble_ashr_13_restart_use): + LABEL(nibble_ashr_13_use): + sub $0x1000, %r10 + movdqa -16(%rdi, %rdx), %xmm0 +- psrldq $13, D(%xmm0) ++ psrldq $13, %xmm0 + pcmpistri $0x3a,%xmm0, %xmm0 + #if defined USE_AS_STRNCMP || defined USE_AS_STRNCASECMP_L + cmp %r11, %rcx +@@ -1518,10 +1488,10 @@ LABEL(nibble_ashr_13_use): + */ + .p2align 4 + LABEL(ashr_14): +- pslldq $2, D(%xmm2) ++ pslldq $2, %xmm2 + TOLOWER (%xmm1, %xmm2) +- pcmpeqb %xmm1, D(%xmm2) +- psubb %xmm0, D(%xmm2) ++ pcmpeqb %xmm1, %xmm2 ++ psubb %xmm0, %xmm2 + pmovmskb %xmm2, %r9d + shr %cl, %edx + shr %cl, %r9d +@@ -1551,7 +1521,7 @@ LABEL(loop_ashr_14_use): + + LABEL(nibble_ashr_14_restart_use): + movdqa (%rdi, %rdx), %xmm0 +- palignr $14, -16(%rdi, %rdx), D(%xmm0) ++ palignr $14, -16(%rdi, %rdx), %xmm0 + #if !defined USE_AS_STRCASECMP_L && !defined USE_AS_STRNCASECMP_L + pcmpistri $0x1a, (%rsi,%rdx), %xmm0 + #else +@@ -1570,7 +1540,7 @@ LABEL(nibble_ashr_14_restart_use): + jg LABEL(nibble_ashr_14_use) + + movdqa (%rdi, %rdx), %xmm0 +- palignr $14, -16(%rdi, %rdx), D(%xmm0) ++ palignr $14, -16(%rdi, %rdx), %xmm0 + #if !defined USE_AS_STRCASECMP_L && !defined USE_AS_STRNCASECMP_L + pcmpistri $0x1a, (%rsi,%rdx), %xmm0 + #else +@@ -1590,7 +1560,7 @@ LABEL(nibble_ashr_14_restart_use): + LABEL(nibble_ashr_14_use): + sub $0x1000, %r10 + movdqa -16(%rdi, %rdx), %xmm0 +- psrldq $14, D(%xmm0) ++ psrldq $14, %xmm0 + pcmpistri $0x3a,%xmm0, %xmm0 + #if defined USE_AS_STRNCMP || defined USE_AS_STRNCASECMP_L + cmp %r11, %rcx +@@ -1608,10 +1578,10 @@ LABEL(nibble_ashr_14_use): + */ + .p2align 4 + LABEL(ashr_15): +- pslldq $1, D(%xmm2) ++ pslldq $1, %xmm2 + TOLOWER (%xmm1, %xmm2) +- pcmpeqb %xmm1, D(%xmm2) +- psubb %xmm0, D(%xmm2) ++ pcmpeqb %xmm1, %xmm2 ++ psubb %xmm0, %xmm2 + pmovmskb %xmm2, %r9d + shr %cl, %edx + shr %cl, %r9d +@@ -1643,7 +1613,7 @@ LABEL(loop_ashr_15_use): + + LABEL(nibble_ashr_15_restart_use): + movdqa (%rdi, %rdx), %xmm0 +- palignr $15, -16(%rdi, %rdx), D(%xmm0) ++ palignr $15, -16(%rdi, %rdx), %xmm0 + #if !defined USE_AS_STRCASECMP_L && !defined USE_AS_STRNCASECMP_L + pcmpistri $0x1a, (%rsi,%rdx), %xmm0 + #else +@@ -1662,7 +1632,7 @@ LABEL(nibble_ashr_15_restart_use): + jg LABEL(nibble_ashr_15_use) + + movdqa (%rdi, %rdx), %xmm0 +- palignr $15, -16(%rdi, %rdx), D(%xmm0) ++ palignr $15, -16(%rdi, %rdx), %xmm0 + #if !defined USE_AS_STRCASECMP_L && !defined USE_AS_STRNCASECMP_L + pcmpistri $0x1a, (%rsi,%rdx), %xmm0 + #else +@@ -1682,7 +1652,7 @@ LABEL(nibble_ashr_15_restart_use): + LABEL(nibble_ashr_15_use): + sub $0x1000, %r10 + movdqa -16(%rdi, %rdx), %xmm0 +- psrldq $15, D(%xmm0) ++ psrldq $15, %xmm0 + pcmpistri $0x3a,%xmm0, %xmm0 + #if defined USE_AS_STRNCMP || defined USE_AS_STRNCASECMP_L + cmp %r11, %rcx +diff --git a/sysdeps/x86_64/multiarch/strncase_l-avx.S b/sysdeps/x86_64/multiarch/strncase_l-avx.S +deleted file mode 100644 +index 0c4e525b..00000000 +--- a/sysdeps/x86_64/multiarch/strncase_l-avx.S ++++ /dev/null +@@ -1,22 +0,0 @@ +-/* strncasecmp_l optimized with AVX. +- 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 +- . */ +- +-#define STRCMP_SSE42 __strncasecmp_l_avx +-#define USE_AVX 1 +-#define USE_AS_STRNCASECMP_L +-#include "strcmp-sse42.S" +-- +GitLab + diff --git a/SOURCES/glibc-RHEL-15867.patch b/SOURCES/glibc-RHEL-15867.patch new file mode 100644 index 0000000..7df2fb8 --- /dev/null +++ b/SOURCES/glibc-RHEL-15867.patch @@ -0,0 +1,47 @@ +commit 2337e04e21ba6040926ec871e403533f77043c40 +Author: Siddhesh Poyarekar +Date: Thu Feb 2 07:49:02 2023 -0500 + + cdefs: Limit definition of fortification macros + + Define the __glibc_fortify and other macros only when __FORTIFY_LEVEL > + 0. This has the effect of not defining these macros on older C90 + compilers that do not have support for variable length argument lists. + + Also trim off the trailing backslashes from the definition of + __glibc_fortify and __glibc_fortify_n macros. + + Signed-off-by: Siddhesh Poyarekar + Reviewed-by: Florian Weimer + +diff --git a/misc/sys/cdefs.h b/misc/sys/cdefs.h +index f3d7efdd2a9320f7..46ec4ef71e14c569 100644 +--- a/misc/sys/cdefs.h ++++ b/misc/sys/cdefs.h +@@ -133,6 +133,7 @@ + # define __glibc_objsize(__o) __bos (__o) + #endif + ++#if __USE_FORTIFY_LEVEL > 0 + /* Compile time conditions to choose between the regular, _chk and _chk_warn + variants. These conditions should get evaluated to constant and optimized + away. */ +@@ -168,7 +169,7 @@ + ? __ ## f ## _alias (__VA_ARGS__) \ + : (__glibc_unsafe_len (__l, __s, __osz) \ + ? __ ## f ## _chk_warn (__VA_ARGS__, __osz) \ +- : __ ## f ## _chk (__VA_ARGS__, __osz))) \ ++ : __ ## f ## _chk (__VA_ARGS__, __osz))) + + /* Fortify function f, where object size argument passed to f is the number of + elements and not total size. */ +@@ -178,7 +179,8 @@ + ? __ ## f ## _alias (__VA_ARGS__) \ + : (__glibc_unsafe_len (__l, __s, __osz) \ + ? __ ## f ## _chk_warn (__VA_ARGS__, (__osz) / (__s)) \ +- : __ ## f ## _chk (__VA_ARGS__, (__osz) / (__s)))) \ ++ : __ ## f ## _chk (__VA_ARGS__, (__osz) / (__s)))) ++#endif + + #if __GNUC_PREREQ (4,3) + # define __warndecl(name, msg) \ diff --git a/SOURCES/glibc-RHEL-16825-1.patch b/SOURCES/glibc-RHEL-16825-1.patch new file mode 100644 index 0000000..c13cfb3 --- /dev/null +++ b/SOURCES/glibc-RHEL-16825-1.patch @@ -0,0 +1,35 @@ +commit b893410be304ddcea0bd43f537a13e8b18d37cf2 +Author: Florian Weimer +Date: Mon Nov 27 11:28:07 2023 +0100 + + elf: In _dl_relocate_object, skip processing if object is relocated + + This is just a minor optimization. It also makes it more obvious that + _dl_relocate_object can be called multiple times. + + Reviewed-by: Carlos O'Donell + +diff --git a/elf/dl-reloc.c b/elf/dl-reloc.c +index 7d8b2bd2336eecb6..66c9266d7f9d65af 100644 +--- a/elf/dl-reloc.c ++++ b/elf/dl-reloc.c +@@ -165,6 +165,9 @@ void + _dl_relocate_object (struct link_map *l, struct r_scope_elem *scope[], + int reloc_mode, int consider_profiling) + { ++ if (l->l_relocated) ++ return; ++ + struct textrels + { + caddr_t start; +@@ -202,9 +205,6 @@ _dl_relocate_object (struct link_map *l, struct r_scope_elem *scope[], + # define consider_symbind 0 + #endif + +- if (l->l_relocated) +- return; +- + /* If DT_BIND_NOW is set relocate all references in this object. We + do not do this if we are profiling, of course. */ + // XXX Correct for auditing? diff --git a/SOURCES/glibc-RHEL-16825-2.patch b/SOURCES/glibc-RHEL-16825-2.patch new file mode 100644 index 0000000..37d2bf9 --- /dev/null +++ b/SOURCES/glibc-RHEL-16825-2.patch @@ -0,0 +1,121 @@ +commit a74c2e1cbc8673dd7e97aae2f2705392e2ccc3f6 +Author: Florian Weimer +Date: Mon Nov 27 11:28:10 2023 +0100 + + elf: Introduce the _dl_open_relocate_one_object function + + It is extracted from dl_open_worker_begin. + + Reviewed-by: Carlos O'Donell + +diff --git a/elf/dl-open.c b/elf/dl-open.c +index 7dfb6b680c108c0b..160451790bb88447 100644 +--- a/elf/dl-open.c ++++ b/elf/dl-open.c +@@ -466,6 +466,50 @@ activate_nodelete (struct link_map *new) + } + } + ++/* Relocate the object L. *RELOCATION_IN_PROGRESS controls whether ++ the debugger is notified of the start of relocation processing. */ ++static void ++_dl_open_relocate_one_object (struct dl_open_args *args, struct r_debug *r, ++ struct link_map *l, int reloc_mode, ++ bool *relocation_in_progress) ++{ ++ if (l->l_real->l_relocated) ++ return; ++ ++ if (!*relocation_in_progress) ++ { ++ /* Notify the debugger that relocations are about to happen. */ ++ LIBC_PROBE (reloc_start, 2, args->nsid, r); ++ *relocation_in_progress = true; ++ } ++ ++#ifdef SHARED ++ if (__glibc_unlikely (GLRO(dl_profile) != NULL)) ++ { ++ /* If this here is the shared object which we want to profile ++ make sure the profile is started. We can find out whether ++ this is necessary or not by observing the `_dl_profile_map' ++ variable. If it was NULL but is not NULL afterwards we must ++ start the profiling. */ ++ struct link_map *old_profile_map = GL(dl_profile_map); ++ ++ _dl_relocate_object (l, l->l_scope, reloc_mode | RTLD_LAZY, 1); ++ ++ if (old_profile_map == NULL && GL(dl_profile_map) != NULL) ++ { ++ /* We must prepare the profiling. */ ++ _dl_start_profile (); ++ ++ /* Prevent unloading the object. */ ++ GL(dl_profile_map)->l_nodelete_active = true; ++ } ++ } ++ else ++#endif ++ _dl_relocate_object (l, l->l_scope, reloc_mode, 0); ++} ++ ++ + /* struct dl_init_args and call_dl_init are used to call _dl_init with + exception handling disabled. */ + struct dl_init_args +@@ -638,7 +682,7 @@ dl_open_worker_begin (void *a) + } + while (l != NULL); + +- int relocation_in_progress = 0; ++ bool relocation_in_progress = false; + + /* Perform relocation. This can trigger lazy binding in IFUNC + resolvers. For NODELETE mappings, these dependencies are not +@@ -649,44 +693,8 @@ dl_open_worker_begin (void *a) + are undefined anyway, so this is not a problem. */ + + for (unsigned int i = last; i-- > first; ) +- { +- l = new->l_initfini[i]; +- +- if (l->l_real->l_relocated) +- continue; +- +- if (! relocation_in_progress) +- { +- /* Notify the debugger that relocations are about to happen. */ +- LIBC_PROBE (reloc_start, 2, args->nsid, r); +- relocation_in_progress = 1; +- } +- +-#ifdef SHARED +- if (__glibc_unlikely (GLRO(dl_profile) != NULL)) +- { +- /* If this here is the shared object which we want to profile +- make sure the profile is started. We can find out whether +- this is necessary or not by observing the `_dl_profile_map' +- variable. If it was NULL but is not NULL afterwards we must +- start the profiling. */ +- struct link_map *old_profile_map = GL(dl_profile_map); +- +- _dl_relocate_object (l, l->l_scope, reloc_mode | RTLD_LAZY, 1); +- +- if (old_profile_map == NULL && GL(dl_profile_map) != NULL) +- { +- /* We must prepare the profiling. */ +- _dl_start_profile (); +- +- /* Prevent unloading the object. */ +- GL(dl_profile_map)->l_nodelete_active = true; +- } +- } +- else +-#endif +- _dl_relocate_object (l, l->l_scope, reloc_mode, 0); +- } ++ _dl_open_relocate_one_object (args, r, new->l_initfini[i], reloc_mode, ++ &relocation_in_progress); + + /* This only performs the memory allocations. The actual update of + the scopes happens below, after failure is impossible. */ diff --git a/SOURCES/glibc-RHEL-16825-3.patch b/SOURCES/glibc-RHEL-16825-3.patch new file mode 100644 index 0000000..758e156 --- /dev/null +++ b/SOURCES/glibc-RHEL-16825-3.patch @@ -0,0 +1,223 @@ +commit 78ca44da0160a0b442f0ca1f253e3360f044b2ec +Author: Florian Weimer +Date: Mon Nov 27 11:28:13 2023 +0100 + + elf: Relocate libc.so early during startup and dlmopen (bug 31083) + + This makes it more likely that objects without dependencies can + use IFUNC resolvers in libc.so. + + Reviewed-by: Carlos O'Donell + +Conflicts: + elf/Makefile + (differences in test backports) + elf/rtld.c + (removal of prelink support upstream) + + +diff --git a/elf/Makefile b/elf/Makefile +index 42dc878209b11d29..ebf46a297d241d8f 100644 +--- a/elf/Makefile ++++ b/elf/Makefile +@@ -387,6 +387,8 @@ tests += \ + tst-nodelete2 \ + tst-nodelete-dlclose \ + tst-nodelete-opened \ ++ tst-nodeps1 \ ++ tst-nodeps2 \ + tst-noload \ + tst-null-argv \ + tst-relsort1 \ +@@ -743,6 +745,8 @@ modules-names = \ + tst-nodelete-dlclose-dso \ + tst-nodelete-dlclose-plugin \ + tst-nodelete-opened-lib \ ++ tst-nodeps1-mod \ ++ tst-nodeps2-mod \ + tst-null-argv-lib \ + tst-relsort1mod1 \ + tst-relsort1mod2 \ +@@ -889,8 +893,13 @@ modules-execstack-yes = tst-execstack-mod + extra-test-objs += $(addsuffix .os,$(strip $(modules-names))) + + # filtmod1.so has a special rule +-modules-names-nobuild := filtmod1 \ +- tst-audit24bmod1 tst-audit24bmod2 ++modules-names-nobuild += \ ++ filtmod1 \ ++ tst-audit24bmod1 \ ++ tst-audit24bmod2 \ ++ tst-nodeps1-mod \ ++ tst-nodeps2-mod \ ++ # modules-names-nobuild + + tests += $(tests-static) + +@@ -2707,3 +2716,18 @@ $(objpfx)tst-dlclose-lazy: $(libdl) + $(objpfx)tst-dlclose-lazy.out: \ + $(objpfx)tst-dlclose-lazy-mod1.so $(objpfx)tst-dlclose-lazy-mod2.so + ++# The object tst-nodeps1-mod.so has no explicit dependencies on libc.so. ++$(objpfx)tst-nodeps1-mod.so: $(objpfx)tst-nodeps1-mod.os ++ $(LINK.o) -nostartfiles -nostdlib -shared -o $@ $^ ++tst-nodeps1.so-no-z-defs = yes ++# Link libc.so before the test module with the IFUNC resolver reference. ++LDFLAGS-tst-nodeps1 = $(common-objpfx)libc.so $(objpfx)tst-nodeps1-mod.so ++$(objpfx)tst-nodeps1: $(objpfx)tst-nodeps1-mod.so ++# Reuse the tst-nodeps1 module. Link libc.so before the test module ++# with the IFUNC resolver reference. ++$(objpfx)tst-nodeps2-mod.so: $(common-objpfx)libc.so \ ++ $(objpfx)tst-nodeps1-mod.so $(objpfx)tst-nodeps2-mod.os ++ $(LINK.o) -Wl,--no-as-needed -nostartfiles -nostdlib -shared -o $@ $^ ++$(objpfx)tst-nodeps2: $(libdl) ++$(objpfx)tst-nodeps2.out: \ ++ $(objpfx)tst-nodeps1-mod.so $(objpfx)tst-nodeps2-mod.so +diff --git a/elf/dl-open.c b/elf/dl-open.c +index 160451790bb88447..f32e2fd4ee39db93 100644 +--- a/elf/dl-open.c ++++ b/elf/dl-open.c +@@ -692,6 +692,17 @@ dl_open_worker_begin (void *a) + them. However, such relocation dependencies in IFUNC resolvers + are undefined anyway, so this is not a problem. */ + ++ /* Ensure that libc is relocated first. This helps with the ++ execution of IFUNC resolvers in libc, and matters only to newly ++ created dlmopen namespaces. Do not do this for static dlopen ++ because libc has relocations against ld.so, which may not have ++ been relocated at this point. */ ++#ifdef SHARED ++ if (GL(dl_ns)[args->nsid].libc_map != NULL) ++ _dl_open_relocate_one_object (args, r, GL(dl_ns)[args->nsid].libc_map, ++ reloc_mode, &relocation_in_progress); ++#endif ++ + for (unsigned int i = last; i-- > first; ) + _dl_open_relocate_one_object (args, r, new->l_initfini[i], reloc_mode, + &relocation_in_progress); +diff --git a/elf/rtld.c b/elf/rtld.c +index cd2cc4024a3581c2..502d2a1c58505d88 100644 +--- a/elf/rtld.c ++++ b/elf/rtld.c +@@ -2414,11 +2414,17 @@ ERROR: '%s': cannot process note segment.\n", _dl_argv[0]); + objects. We do not re-relocate the dynamic linker itself in this + loop because that could result in the GOT entries for functions we + call being changed, and that would break us. It is safe to relocate +- the dynamic linker out of order because it has no copy relocs (we +- know that because it is self-contained). */ ++ the dynamic linker out of order because it has no copy relocations. ++ Likewise for libc, which is relocated early to ensure that IFUNC ++ resolvers in libc work. */ + + int consider_profiling = GLRO(dl_profile) != NULL; + ++ if (GL(dl_ns)[LM_ID_BASE].libc_map != NULL) ++ _dl_relocate_object (GL(dl_ns)[LM_ID_BASE].libc_map, ++ GL(dl_ns)[LM_ID_BASE].libc_map->l_scope, ++ GLRO(dl_lazy) ? RTLD_LAZY : 0, consider_profiling); ++ + /* If we are profiling we also must do lazy reloaction. */ + GLRO(dl_lazy) |= consider_profiling; + +diff --git a/elf/tst-nodeps1-mod.c b/elf/tst-nodeps1-mod.c +new file mode 100644 +index 0000000000000000..45c8e3c631251a89 +--- /dev/null ++++ b/elf/tst-nodeps1-mod.c +@@ -0,0 +1,25 @@ ++/* Test module with no libc.so dependency and string function references. ++ Copyright (C) 2023 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#include ++ ++/* Some references to libc symbols which are likely to have IFUNC ++ resolvers. If they do not, this module does not exercise bug 31083. */ ++void *memcpy_pointer = memcpy; ++void *memmove_pointer = memmove; ++void *memset_pointer = memset; +diff --git a/elf/tst-nodeps1.c b/elf/tst-nodeps1.c +new file mode 100644 +index 0000000000000000..1a8bde36cdb71446 +--- /dev/null ++++ b/elf/tst-nodeps1.c +@@ -0,0 +1,23 @@ ++/* Test initially loaded module with implicit libc.so dependency (bug 31083). ++ Copyright (C) 2023 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++/* Testing happens before main. */ ++int ++main (void) ++{ ++} +diff --git a/elf/tst-nodeps2-mod.c b/elf/tst-nodeps2-mod.c +new file mode 100644 +index 0000000000000000..4913feee9b56e0e1 +--- /dev/null ++++ b/elf/tst-nodeps2-mod.c +@@ -0,0 +1 @@ ++/* Empty test module which depends on tst-nodeps1-mod.so. */ +diff --git a/elf/tst-nodeps2.c b/elf/tst-nodeps2.c +new file mode 100644 +index 0000000000000000..0bdc8eeb8cba3a99 +--- /dev/null ++++ b/elf/tst-nodeps2.c +@@ -0,0 +1,29 @@ ++/* Test dlmopen with implicit libc.so dependency (bug 31083). ++ Copyright (C) 2023 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#include ++ ++static int ++do_test (void) ++{ ++ void *handle = xdlmopen (LM_ID_NEWLM, "tst-nodeps2-mod.so", RTLD_NOW); ++ xdlclose (handle); ++ return 0; ++} ++ ++#include diff --git a/SOURCES/glibc-RHEL-16825-4.patch b/SOURCES/glibc-RHEL-16825-4.patch new file mode 100644 index 0000000..ffa3ec5 --- /dev/null +++ b/SOURCES/glibc-RHEL-16825-4.patch @@ -0,0 +1,41 @@ +commit b3bee76c5f59498b9c189608f0a3132e2013fa1a +Author: Florian Weimer +Date: Fri Dec 8 09:51:34 2023 +0100 + + elf: Initialize GLRO(dl_lazy) before relocating libc in dynamic startup + + GLRO(dl_lazy) is used to set the parameters for the early + _dl_relocate_object call, so the consider_profiling setting has to + be applied before the call. + + Fixes commit 78ca44da0160a0b442f0ca1f253e3360f044b2ec ("elf: Relocate + libc.so early during startup and dlmopen (bug 31083)"). + + Reviewed-by: Carlos O'Donell + +Conflicts: + elf/rtld.c + (removal of prelink support upstream) + +diff --git a/elf/rtld.c b/elf/rtld.c +index 502d2a1c58505d88..4f317a2a874e6af7 100644 +--- a/elf/rtld.c ++++ b/elf/rtld.c +@@ -2420,14 +2420,14 @@ ERROR: '%s': cannot process note segment.\n", _dl_argv[0]); + + int consider_profiling = GLRO(dl_profile) != NULL; + ++ /* If we are profiling we also must do lazy reloaction. */ ++ GLRO(dl_lazy) |= consider_profiling; ++ + if (GL(dl_ns)[LM_ID_BASE].libc_map != NULL) + _dl_relocate_object (GL(dl_ns)[LM_ID_BASE].libc_map, + GL(dl_ns)[LM_ID_BASE].libc_map->l_scope, + GLRO(dl_lazy) ? RTLD_LAZY : 0, consider_profiling); + +- /* If we are profiling we also must do lazy reloaction. */ +- GLRO(dl_lazy) |= consider_profiling; +- + RTLD_TIMING_VAR (start); + rtld_timer_start (&start); + unsigned i = main_map->l_searchlist.r_nlist; diff --git a/SOURCES/glibc-RHEL-17468-1.patch b/SOURCES/glibc-RHEL-17468-1.patch new file mode 100644 index 0000000..7d7209a --- /dev/null +++ b/SOURCES/glibc-RHEL-17468-1.patch @@ -0,0 +1,47 @@ +commit 3921c5b40f293c57cb326f58713c924b0662ef59 +Author: Hector Martin +Date: Tue Nov 28 15:23:07 2023 +0900 + + elf: Fix TLS modid reuse generation assignment (BZ 29039) + + _dl_assign_tls_modid() assigns a slotinfo entry for a new module, but + does *not* do anything to the generation counter. The first time this + happens, the generation is zero and map_generation() returns the current + generation to be used during relocation processing. However, if + a slotinfo entry is later reused, it will already have a generation + assigned. If this generation has fallen behind the current global max + generation, then this causes an obsolete generation to be assigned + during relocation processing, as map_generation() returns this + generation if nonzero. _dl_add_to_slotinfo() eventually resets the + generation, but by then it is too late. This causes DTV updates to be + skipped, leading to NULL or broken TLS slot pointers and segfaults. + + Fix this by resetting the generation to zero in _dl_assign_tls_modid(), + so it behaves the same as the first time a slot is assigned. + _dl_add_to_slotinfo() will still assign the correct static generation + later during module load, but relocation processing will no longer use + an obsolete generation. + + Note that slotinfo entry (aka modid) reuse typically happens after a + dlclose and only TLS access via dynamic tlsdesc is affected. Because + tlsdesc is optimized to use the optional part of static TLS, dynamic + tlsdesc can be avoided by increasing the glibc.rtld.optional_static_tls + tunable to a large enough value, or by LD_PRELOAD-ing the affected + modules. + + Fixes bug 29039. + + Reviewed-by: Szabolcs Nagy + +diff --git a/elf/dl-tls.c b/elf/dl-tls.c +index a21276732968d88b..c8104078b2aa0aa2 100644 +--- a/elf/dl-tls.c ++++ b/elf/dl-tls.c +@@ -156,6 +156,7 @@ _dl_assign_tls_modid (struct link_map *l) + { + /* Mark the entry as used, so any dependency see it. */ + atomic_store_relaxed (&runp->slotinfo[result - disp].map, l); ++ atomic_store_relaxed (&runp->slotinfo[result - disp].gen, 0); + break; + } + diff --git a/SOURCES/glibc-RHEL-17468-2.patch b/SOURCES/glibc-RHEL-17468-2.patch new file mode 100644 index 0000000..3722477 --- /dev/null +++ b/SOURCES/glibc-RHEL-17468-2.patch @@ -0,0 +1,198 @@ +commit 980450f12685326729d63ff72e93a996113bf073 +Author: Szabolcs Nagy +Date: Wed Nov 29 11:31:37 2023 +0000 + + elf: Add TLS modid reuse test for bug 29039 + + This is a minimal regression test for bug 29039 which only affects + targets with TLSDESC and a reproducer requires that + + 1) Have modid gaps (closed modules) with old generation. + 2) Update a DTV to a newer generation (needs a newer dlopen). + 3) But do not update the closed gap entry in that DTV. + 4) Reuse the modid gap for a new module (another dlopen). + 5) Use dynamic TLSDESC in that new module with old generation (bug). + 6) Access TLS via this TLSDESC and the now outdated DTV. + + However step (3) in practice rarely happens: during DTV update the + entries for closed modids are initialized to "unallocated" and then + dynamic TLSDESC calls __tls_get_addr independently of its generation. + The only exception to this is DTV setup at thread creation (gaps are + initialized to NULL instead of unallocated) or DTV resize where the + gap entries are outside the previous DTV array (again NULL instead + of unallocated, and this requires loading > DTV_SURPLUS modules). + + So the bug can only cause NULL (+ offset) dereference, not use after + free. And the easiest way to get (3) is via thread creation. + + Note that step (5) requires that the newly loaded module has larger + TLS than the remaining optional static TLS. And for (6) there cannot + be other TLS access or dlopen in the thread that updates the DTV. + + Tested on aarch64-linux-gnu. + + Reviewed-by: Adhemerval Zanella + +Conflicts: + elf/Makefile + (Add $(libdl), Resolve test case ordering conflict.) + +diff --git a/elf/Makefile b/elf/Makefile +index ebf46a297d241d8f..b8fdee7c0d37137e 100644 +--- a/elf/Makefile ++++ b/elf/Makefile +@@ -416,6 +416,7 @@ tests += \ + tst-tls-ie \ + tst-tls-ie-dlmopen \ + tst-tls-manydynamic \ ++ tst-tlsgap \ + tst-unique1 \ + tst-unique2 \ + unload3 \ +@@ -759,6 +760,9 @@ modules-names = \ + tst-tls20mod-bad \ + tst-tls21mod \ + tst-tlsalign-lib \ ++ tst-tlsgap-mod0 \ ++ tst-tlsgap-mod1 \ ++ tst-tlsgap-mod2 \ + tst-tls-ie-mod0 \ + tst-tls-ie-mod1 \ + tst-tls-ie-mod2 \ +@@ -2731,3 +2735,14 @@ $(objpfx)tst-nodeps2-mod.so: $(common-objpfx)libc.so \ + $(objpfx)tst-nodeps2: $(libdl) + $(objpfx)tst-nodeps2.out: \ + $(objpfx)tst-nodeps1-mod.so $(objpfx)tst-nodeps2-mod.so ++ ++$(objpfx)tst-tlsgap: $(libdl) $(shared-thread-library) ++$(objpfx)tst-tlsgap.out: \ ++ $(objpfx)tst-tlsgap-mod0.so \ ++ $(objpfx)tst-tlsgap-mod1.so \ ++ $(objpfx)tst-tlsgap-mod2.so ++ifeq (yes,$(have-mtls-dialect-gnu2)) ++CFLAGS-tst-tlsgap-mod0.c += -mtls-dialect=gnu2 ++CFLAGS-tst-tlsgap-mod1.c += -mtls-dialect=gnu2 ++CFLAGS-tst-tlsgap-mod2.c += -mtls-dialect=gnu2 ++endif +diff --git a/elf/tst-tlsgap-mod0.c b/elf/tst-tlsgap-mod0.c +new file mode 100644 +index 0000000000000000..1478b0beac5faf98 +--- /dev/null ++++ b/elf/tst-tlsgap-mod0.c +@@ -0,0 +1,2 @@ ++int __thread tls0; ++int *f0(void) { return &tls0; } +diff --git a/elf/tst-tlsgap-mod1.c b/elf/tst-tlsgap-mod1.c +new file mode 100644 +index 0000000000000000..b10fc3702c43e478 +--- /dev/null ++++ b/elf/tst-tlsgap-mod1.c +@@ -0,0 +1,2 @@ ++int __thread tls1[100]; /* Size > glibc.rtld.optional_static_tls / 2. */ ++int *f1(void) { return tls1; } +diff --git a/elf/tst-tlsgap-mod2.c b/elf/tst-tlsgap-mod2.c +new file mode 100644 +index 0000000000000000..166c27d7f3fac252 +--- /dev/null ++++ b/elf/tst-tlsgap-mod2.c +@@ -0,0 +1,2 @@ ++int __thread tls2; ++int *f2(void) { return &tls2; } +diff --git a/elf/tst-tlsgap.c b/elf/tst-tlsgap.c +new file mode 100644 +index 0000000000000000..49328850769c5609 +--- /dev/null ++++ b/elf/tst-tlsgap.c +@@ -0,0 +1,92 @@ ++/* TLS modid gap reuse regression test for bug 29039. ++ Copyright (C) 2023 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++static void *mod[3]; ++#define MOD(i) "tst-tlsgap-mod" #i ".so" ++static const char *modname[3] = { MOD(0), MOD(1), MOD(2) }; ++#undef MOD ++ ++static void ++open_mod (int i) ++{ ++ mod[i] = xdlopen (modname[i], RTLD_LAZY); ++ printf ("open %s\n", modname[i]); ++} ++ ++static void ++close_mod (int i) ++{ ++ xdlclose (mod[i]); ++ mod[i] = NULL; ++ printf ("close %s\n", modname[i]); ++} ++ ++static void ++access_mod (int i, const char *sym) ++{ ++ int *(*f) (void) = xdlsym (mod[i], sym); ++ int *p = f (); ++ printf ("access %s: %s() = %p\n", modname[i], sym, p); ++ TEST_VERIFY_EXIT (p != NULL); ++ ++*p; ++} ++ ++static void * ++start (void *arg) ++{ ++ /* The DTV generation is at the last dlopen of mod0 and the ++ entry for mod1 is NULL. */ ++ ++ open_mod (1); /* Reuse modid of mod1. Uses dynamic TLS. */ ++ ++ /* DTV is unchanged: dlopen only updates the DTV to the latest ++ generation if static TLS is allocated for a loaded module. ++ ++ With bug 29039, the TLSDESC relocation in mod1 uses the old ++ dlclose generation of mod1 instead of the new dlopen one so ++ DTV is not updated on TLS access. */ ++ ++ access_mod (1, "f1"); ++ ++ return arg; ++} ++ ++static int ++do_test (void) ++{ ++ open_mod (0); ++ open_mod (1); ++ open_mod (2); ++ close_mod (0); ++ close_mod (1); /* Create modid gap at mod1. */ ++ open_mod (0); /* Reuse modid of mod0, bump generation count. */ ++ ++ /* Create a thread where DTV of mod1 is NULL. */ ++ pthread_t t = xpthread_create (NULL, start, NULL); ++ xpthread_join (t); ++ return 0; ++} ++ ++#include diff --git a/SOURCES/glibc-RHEL-19445.patch b/SOURCES/glibc-RHEL-19445.patch new file mode 100644 index 0000000..b3769d3 --- /dev/null +++ b/SOURCES/glibc-RHEL-19445.patch @@ -0,0 +1,31 @@ +Based on the following commit, adjusted for glibc-2.28 in RHEL-8: + +commit 5eabdb6a6ac1599d23dd5966a37417215950245f +Author: Andreas Schwab +Date: Wed Dec 6 14:48:22 2023 +0100 + + getaddrinfo: translate ENOMEM to EAI_MEMORY (bug 31163) + + When __resolv_context_get returns NULL due to out of memory, translate it + to a return value of EAI_MEMORY. + +diff --git a/sysdeps/posix/getaddrinfo.c b/sysdeps/posix/getaddrinfo.c +index 46046504a6858f2e..d0708f3e84e20025 100644 +--- a/sysdeps/posix/getaddrinfo.c ++++ b/sysdeps/posix/getaddrinfo.c +@@ -777,7 +777,14 @@ gaih_inet (const char *name, const struct gaih_service *service, + res_ctx = __resolv_context_get (); + res_enable_inet6 = __resolv_context_disable_inet6 (res_ctx); + if (res_ctx == NULL) +- no_more = 1; ++ { ++ if (errno == ENOMEM) ++ { ++ result = -EAI_MEMORY; ++ goto free_and_return; ++ } ++ no_more = 1; ++ } + + while (!no_more) + { diff --git a/SOURCES/glibc-RHEL-19824.patch b/SOURCES/glibc-RHEL-19824.patch new file mode 100644 index 0000000..538a9d0 --- /dev/null +++ b/SOURCES/glibc-RHEL-19824.patch @@ -0,0 +1,27 @@ +commit ecc7c3deb9f347649c2078fcc0f94d4cedf92d60 +Author: Florian Weimer +Date: Tue Jan 2 14:36:17 2024 +0100 + + libio: Check remaining buffer size in _IO_wdo_write (bug 31183) + + The multibyte character needs to fit into the remaining buffer space, + not the already-written buffer space. Without the fix, we were never + moving the write pointer from the start of the buffer, always using + the single-character fallback buffer. + + Fixes commit 04b76b5aa8b2d1d19066e42dd1 ("Don't error out writing + a multibyte character to an unbuffered stream (bug 17522)"). + +diff --git a/libio/wfileops.c b/libio/wfileops.c +index d3deb34ba058ca39..6a6421f8880f9356 100644 +--- a/libio/wfileops.c ++++ b/libio/wfileops.c +@@ -57,7 +57,7 @@ _IO_wdo_write (FILE *fp, const wchar_t *data, size_t to_do) + char mb_buf[MB_LEN_MAX]; + char *write_base, *write_ptr, *buf_end; + +- if (fp->_IO_write_ptr - fp->_IO_write_base < sizeof (mb_buf)) ++ if (fp->_IO_buf_end - fp->_IO_write_ptr < sizeof (mb_buf)) + { + /* Make sure we have room for at least one multibyte + character. */ diff --git a/SOURCES/glibc-RHEL-2122.patch b/SOURCES/glibc-RHEL-2122.patch new file mode 100644 index 0000000..69a294f --- /dev/null +++ b/SOURCES/glibc-RHEL-2122.patch @@ -0,0 +1,312 @@ +From d2123d68275acc0f061e73d5f86ca504e0d5a344 Mon Sep 17 00:00:00 2001 +From: Szabolcs Nagy +Date: Tue, 16 Feb 2021 12:55:13 +0000 +Subject: elf: Fix slow tls access after dlopen [BZ #19924] + +In short: __tls_get_addr checks the global generation counter and if +the current dtv is older then _dl_update_slotinfo updates dtv up to the +generation of the accessed module. So if the global generation is newer +than generation of the module then __tls_get_addr keeps hitting the +slow dtv update path. The dtv update path includes a number of checks +to see if any update is needed and this already causes measurable tls +access slow down after dlopen. + +It may be possible to detect up-to-date dtv faster. But if there are +many modules loaded (> TLS_SLOTINFO_SURPLUS) then this requires at +least walking the slotinfo list. + +This patch tries to update the dtv to the global generation instead, so +after a dlopen the tls access slow path is only hit once. The modules +with larger generation than the accessed one were not necessarily +synchronized before, so additional synchronization is needed. + +This patch uses acquire/release synchronization when accessing the +generation counter. + +Note: in the x86_64 version of dl-tls.c the generation is only loaded +once, since relaxed mo is not faster than acquire mo load. + +I have not benchmarked this. Tested by Adhemerval Zanella on aarch64, +powerpc, sparc, x86 who reported that it fixes the performance issue +of bug 19924. + +Reviewed-by: Adhemerval Zanella + +[rebased to c8s by DJ] + +diff -rup a/elf/dl-close.c b/elf/dl-close.c +--- a/elf/dl-close.c 2023-10-13 16:24:27.068217519 -0400 ++++ b/elf/dl-close.c 2023-10-13 16:28:59.936019397 -0400 +@@ -739,7 +739,7 @@ _dl_close_worker (struct link_map *map, + if (__glibc_unlikely (newgen == 0)) + _dl_fatal_printf ("TLS generation counter wrapped! Please report as described in "REPORT_BUGS_TO".\n"); + /* Can be read concurrently. */ +- atomic_store_relaxed (&GL(dl_tls_generation), newgen); ++ atomic_store_release (&GL(dl_tls_generation), newgen); + + if (tls_free_end == GL(dl_tls_static_used)) + GL(dl_tls_static_used) = tls_free_start; +diff -rup a/elf/dl-open.c b/elf/dl-open.c +--- a/elf/dl-open.c 2023-10-13 16:24:26.930212160 -0400 ++++ b/elf/dl-open.c 2023-10-13 16:28:59.936019397 -0400 +@@ -403,7 +403,7 @@ update_tls_slotinfo (struct link_map *ne + _dl_fatal_printf (N_("\ + TLS generation counter wrapped! Please report this.")); + /* Can be read concurrently. */ +- atomic_store_relaxed (&GL(dl_tls_generation), newgen); ++ atomic_store_release (&GL(dl_tls_generation), newgen); + + /* We need a second pass for static tls data, because + _dl_update_slotinfo must not be run while calls to +@@ -420,8 +420,8 @@ TLS generation counter wrapped! Please + now, but we can delay updating the DTV. */ + imap->l_need_tls_init = 0; + #ifdef SHARED +- /* Update the slot information data for at least the +- generation of the DSO we are allocating data for. */ ++ /* Update the slot information data for the current ++ generation. */ + + /* FIXME: This can terminate the process on memory + allocation failure. It is not possible to raise +@@ -429,7 +429,7 @@ TLS generation counter wrapped! Please + _dl_update_slotinfo would have to be split into two + operations, similar to resize_scopes and update_scopes + above. This is related to bug 16134. */ +- _dl_update_slotinfo (imap->l_tls_modid); ++ _dl_update_slotinfo (imap->l_tls_modid, newgen); + #endif + + GL(dl_init_static_tls) (imap); +diff -rup a/elf/dl-reloc.c b/elf/dl-reloc.c +--- a/elf/dl-reloc.c 2023-10-13 16:24:26.390191189 -0400 ++++ b/elf/dl-reloc.c 2023-10-13 16:28:59.937019438 -0400 +@@ -111,11 +111,11 @@ _dl_try_allocate_static_tls (struct link + if (map->l_real->l_relocated) + { + #ifdef SHARED ++ /* Update the DTV of the current thread. Note: GL(dl_load_tls_lock) ++ is held here so normal load of the generation counter is valid. */ + if (__builtin_expect (THREAD_DTV()[0].counter != GL(dl_tls_generation), + 0)) +- /* Update the slot information data for at least the generation of +- the DSO we are allocating data for. */ +- (void) _dl_update_slotinfo (map->l_tls_modid); ++ (void) _dl_update_slotinfo (map->l_tls_modid, GL(dl_tls_generation)); + #endif + + GL(dl_init_static_tls) (map); +diff -rup a/elf/dl-tls.c b/elf/dl-tls.c +--- a/elf/dl-tls.c 2023-10-13 16:24:26.564197946 -0400 ++++ b/elf/dl-tls.c 2023-10-13 16:28:59.937019438 -0400 +@@ -716,57 +716,57 @@ allocate_and_init (struct link_map *map) + + + struct link_map * +-_dl_update_slotinfo (unsigned long int req_modid) ++_dl_update_slotinfo (unsigned long int req_modid, size_t new_gen) + { + struct link_map *the_map = NULL; + dtv_t *dtv = THREAD_DTV (); + +- /* The global dl_tls_dtv_slotinfo array contains for each module +- index the generation counter current when the entry was created. ++ /* CONCURRENCY NOTES: ++ ++ The global dl_tls_dtv_slotinfo_list array contains for each module ++ index the generation counter current when that entry was updated. + This array never shrinks so that all module indices which were +- valid at some time can be used to access it. Before the first +- use of a new module index in this function the array was extended +- appropriately. Access also does not have to be guarded against +- modifications of the array. It is assumed that pointer-size +- values can be read atomically even in SMP environments. It is +- possible that other threads at the same time dynamically load +- code and therefore add to the slotinfo list. This is a problem +- since we must not pick up any information about incomplete work. +- The solution to this is to ignore all dtv slots which were +- created after the one we are currently interested. We know that +- dynamic loading for this module is completed and this is the last +- load operation we know finished. */ +- unsigned long int idx = req_modid; ++ valid at some time can be used to access it. Concurrent loading ++ and unloading of modules can update slotinfo entries or extend ++ the array. The updates happen under the GL(dl_load_tls_lock) and ++ finish with the release store of the generation counter to ++ GL(dl_tls_generation) which is synchronized with the load of ++ new_gen in the caller. So updates up to new_gen are synchronized ++ but updates for later generations may not be. ++ ++ Here we update the thread dtv from old_gen (== dtv[0].counter) to ++ new_gen generation. For this, each dtv[i] entry is either set to ++ an unallocated state (set), or left unmodified (nop). Where (set) ++ may resize the dtv first if modid i >= dtv[-1].counter. The rules ++ for the decision between (set) and (nop) are ++ ++ (1) If slotinfo entry i is concurrently updated then either (set) ++ or (nop) is valid: TLS access cannot use dtv[i] unless it is ++ synchronized with a generation > new_gen. ++ ++ Otherwise, if the generation of slotinfo entry i is gen and the ++ loaded module for this entry is map then ++ ++ (2) If gen <= old_gen then do (nop). ++ ++ (3) If old_gen < gen <= new_gen then ++ (3.1) if map != 0 then (set) ++ (3.2) if map == 0 then either (set) or (nop). ++ ++ Note that (1) cannot be reliably detected, but since both actions ++ are valid it does not have to be. Only (2) and (3.1) cases need ++ to be distinguished for which relaxed mo access of gen and map is ++ enough: their value is synchronized when it matters. ++ ++ Note that a relaxed mo load may give an out-of-thin-air value since ++ it is used in decisions that can affect concurrent stores. But this ++ should only happen if the OOTA value causes UB that justifies the ++ concurrent store of the value. This is not expected to be an issue ++ in practice. */ + struct dtv_slotinfo_list *listp = GL(dl_tls_dtv_slotinfo_list); + +- while (idx >= listp->len) ++ if (dtv[0].counter < new_gen) + { +- idx -= listp->len; +- listp = listp->next; +- } +- +- if (dtv[0].counter < listp->slotinfo[idx].gen) +- { +- /* CONCURRENCY NOTES: +- +- Here the dtv needs to be updated to new_gen generation count. +- +- This code may be called during TLS access when GL(dl_load_tls_lock) +- is not held. In that case the user code has to synchronize with +- dlopen and dlclose calls of relevant modules. A module m is +- relevant if the generation of m <= new_gen and dlclose of m is +- synchronized: a memory access here happens after the dlopen and +- before the dlclose of relevant modules. The dtv entries for +- relevant modules need to be updated, other entries can be +- arbitrary. +- +- This e.g. means that the first part of the slotinfo list can be +- accessed race free, but the tail may be concurrently extended. +- Similarly relevant slotinfo entries can be read race free, but +- other entries are racy. However updating a non-relevant dtv +- entry does not affect correctness. For a relevant module m, +- max_modid >= modid of m. */ +- size_t new_gen = listp->slotinfo[idx].gen; + size_t total = 0; + size_t max_modid = atomic_load_relaxed (&GL(dl_tls_max_dtv_idx)); + assert (max_modid >= req_modid); +@@ -779,31 +779,33 @@ _dl_update_slotinfo (unsigned long int r + { + size_t modid = total + cnt; + +- /* Later entries are not relevant. */ ++ /* Case (1) for all later modids. */ + if (modid > max_modid) + break; + + size_t gen = atomic_load_relaxed (&listp->slotinfo[cnt].gen); + ++ /* Case (1). */ + if (gen > new_gen) +- /* Not relevant. */ + continue; + +- /* If the entry is older than the current dtv layout we +- know we don't have to handle it. */ ++ /* Case (2) or (1). */ + if (gen <= dtv[0].counter) + continue; + ++ /* Case (3) or (1). */ ++ + /* If there is no map this means the entry is empty. */ + struct link_map *map + = atomic_load_relaxed (&listp->slotinfo[cnt].map); + /* Check whether the current dtv array is large enough. */ + if (dtv[-1].counter < modid) + { ++ /* Case (3.2) or (1). */ + if (map == NULL) + continue; + +- /* Resize the dtv. */ ++ /* Resizing the dtv aborts on failure: bug 16134. */ + dtv = _dl_resize_dtv (dtv, max_modid); + + assert (modid <= dtv[-1].counter); +@@ -814,7 +816,7 @@ _dl_update_slotinfo (unsigned long int r + } + + /* If there is currently memory allocate for this +- dtv entry free it. */ ++ dtv entry free it. Note: this is not AS-safe. */ + /* XXX Ideally we will at some point create a memory + pool. */ + free (dtv[modid].pointer.to_free); +@@ -909,9 +911,9 @@ tls_get_addr_tail (GET_ADDR_ARGS, dtv_t + + static struct link_map * + __attribute_noinline__ +-update_get_addr (GET_ADDR_ARGS) ++update_get_addr (GET_ADDR_ARGS, size_t gen) + { +- struct link_map *the_map = _dl_update_slotinfo (GET_ADDR_MODULE); ++ struct link_map *the_map = _dl_update_slotinfo (GET_ADDR_MODULE, gen); + dtv_t *dtv = THREAD_DTV (); + + void *p = dtv[GET_ADDR_MODULE].pointer.val; +@@ -941,12 +943,17 @@ __tls_get_addr (GET_ADDR_ARGS) + dtv_t *dtv = THREAD_DTV (); + + /* Update is needed if dtv[0].counter < the generation of the accessed +- module. The global generation counter is used here as it is easier +- to check. Synchronization for the relaxed MO access is guaranteed +- by user code, see CONCURRENCY NOTES in _dl_update_slotinfo. */ ++ module, but the global generation counter is easier to check (which ++ must be synchronized up to the generation of the accessed module by ++ user code doing the TLS access so relaxed mo read is enough). */ + size_t gen = atomic_load_relaxed (&GL(dl_tls_generation)); + if (__glibc_unlikely (dtv[0].counter != gen)) +- return update_get_addr (GET_ADDR_PARAM); ++ { ++ /* Update DTV up to the global generation, see CONCURRENCY NOTES ++ in _dl_update_slotinfo. */ ++ gen = atomic_load_acquire (&GL(dl_tls_generation)); ++ return update_get_addr (GET_ADDR_PARAM, gen); ++ } + + void *p = dtv[GET_ADDR_MODULE].pointer.val; + +diff -rup a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h +--- a/sysdeps/generic/ldsodefs.h 2023-10-13 16:24:27.136220160 -0400 ++++ b/sysdeps/generic/ldsodefs.h 2023-10-13 16:28:59.937019438 -0400 +@@ -1231,7 +1231,8 @@ extern void _dl_add_to_slotinfo (struct + + /* Update slot information data for at least the generation of the + module with the given index. */ +-extern struct link_map *_dl_update_slotinfo (unsigned long int req_modid) ++extern struct link_map *_dl_update_slotinfo (unsigned long int req_modid, ++ size_t gen) + attribute_hidden; + + /* Look up the module's TLS block as for __tls_get_addr, +diff -rup a/sysdeps/x86_64/dl-tls.c b/sysdeps/x86_64/dl-tls.c +--- a/sysdeps/x86_64/dl-tls.c 2023-10-13 16:24:24.948135189 -0400 ++++ b/sysdeps/x86_64/dl-tls.c 2023-10-13 16:28:59.938019479 -0400 +@@ -40,9 +40,9 @@ __tls_get_addr_slow (GET_ADDR_ARGS) + { + dtv_t *dtv = THREAD_DTV (); + +- size_t gen = atomic_load_relaxed (&GL(dl_tls_generation)); ++ size_t gen = atomic_load_acquire (&GL(dl_tls_generation)); + if (__glibc_unlikely (dtv[0].counter != gen)) +- return update_get_addr (GET_ADDR_PARAM); ++ return update_get_addr (GET_ADDR_PARAM, gen); + + return tls_get_addr_tail (GET_ADDR_PARAM, dtv, NULL); + } diff --git a/SOURCES/glibc-RHEL-21997.patch b/SOURCES/glibc-RHEL-21997.patch new file mode 100644 index 0000000..865c508 --- /dev/null +++ b/SOURCES/glibc-RHEL-21997.patch @@ -0,0 +1,112 @@ +This downstream-only patch compensates for the missing backport of +commit 2d651eb9265d1366d7b9e881bfddd46db9c1ecc4 ("x86: Move +x86 processor cache info to cpu_features"). Without it, +ld.so --list-diagnostics prints values that have not been properly +initalized from CPUID data. + +diff --git a/sysdeps/x86/cacheinfo.h b/sysdeps/x86/cacheinfo.h +index 10ebadd819d9efff..d8421fab83ab08ac 100644 +--- a/sysdeps/x86/cacheinfo.h ++++ b/sysdeps/x86/cacheinfo.h +@@ -19,31 +19,42 @@ + #include + #include + ++/* When building ld.so, do not export any of the variables. They are ++ only used for diagnostics and are not initialized during regular ++ operation. */ ++#if IS_IN (rtld) ++# define CACHEINFO_VARIABLE(name, initializer) \ ++ static long int name = initializer ++#else ++# define CACHEINFO_VARIABLE(name, initializer) \ ++ long int name attribute_hidden = initializer ++#endif ++ + /* Data cache size for use in memory and string routines, typically + L1 size, rounded to multiple of 256 bytes. */ +-long int __x86_data_cache_size_half attribute_hidden = 32 * 1024 / 2; +-long int __x86_data_cache_size attribute_hidden = 32 * 1024; ++CACHEINFO_VARIABLE (__x86_data_cache_size_half, 32 * 1024 / 2); ++CACHEINFO_VARIABLE (__x86_data_cache_size, 32 * 1024); + /* Similar to __x86_data_cache_size_half, but not rounded. */ +-long int __x86_raw_data_cache_size_half attribute_hidden = 32 * 1024 / 2; ++CACHEINFO_VARIABLE (__x86_raw_data_cache_size_half, 32 * 1024 / 2); + /* Similar to __x86_data_cache_size, but not rounded. */ +-long int __x86_raw_data_cache_size attribute_hidden = 32 * 1024; ++CACHEINFO_VARIABLE (__x86_raw_data_cache_size, 32 * 1024); + /* Shared cache size for use in memory and string routines, typically + L2 or L3 size, rounded to multiple of 256 bytes. */ +-long int __x86_shared_cache_size_half attribute_hidden = 1024 * 1024 / 2; +-long int __x86_shared_cache_size attribute_hidden = 1024 * 1024; ++CACHEINFO_VARIABLE (__x86_shared_cache_size_half, 1024 * 1024 / 2); ++CACHEINFO_VARIABLE (__x86_shared_cache_size, 1024 * 1024); + /* Similar to __x86_shared_cache_size_half, but not rounded. */ +-long int __x86_raw_shared_cache_size_half attribute_hidden = 1024 * 1024 / 2; ++CACHEINFO_VARIABLE (__x86_raw_shared_cache_size_half, 1024 * 1024 / 2); + /* Similar to __x86_shared_cache_size, but not rounded. */ +-long int __x86_raw_shared_cache_size attribute_hidden = 1024 * 1024; ++CACHEINFO_VARIABLE (__x86_raw_shared_cache_size, 1024 * 1024); + + /* Threshold to use non temporal store. */ +-long int __x86_shared_non_temporal_threshold attribute_hidden; ++CACHEINFO_VARIABLE (__x86_shared_non_temporal_threshold, 0); + + /* Threshold to use Enhanced REP MOVSB. */ +-long int __x86_rep_movsb_threshold attribute_hidden = 2048; ++CACHEINFO_VARIABLE (__x86_rep_movsb_threshold, 2048); + + /* Threshold to use Enhanced REP STOSB. */ +-long int __x86_rep_stosb_threshold attribute_hidden = 2048; ++CACHEINFO_VARIABLE (__x86_rep_stosb_threshold, 2048); + + static void + get_common_cache_info (long int *shared_ptr, long int * shared_per_thread_ptr, unsigned int *threads_ptr, +diff --git a/sysdeps/x86/dl-diagnostics-cpu.c b/sysdeps/x86/dl-diagnostics-cpu.c +index 0ba286a828b69937..9215604ecf22344c 100644 +--- a/sysdeps/x86/dl-diagnostics-cpu.c ++++ b/sysdeps/x86/dl-diagnostics-cpu.c +@@ -19,6 +19,13 @@ + #include + #include + ++#include ++#include ++#include ++#include ++#include ++#include ++ + static void + print_cpu_features_value (const char *label, uint64_t value) + { +@@ -81,19 +88,21 @@ _dl_diagnostics_cpu (void) + #include "cpu-features-preferred_feature_index_1.def" + #undef BIT + ++ /* The cache information variables are only used for diagnostics and ++ are not initialized during startup. The values used at run time ++ are only in libc.so.6. */ ++ init_cacheinfo (); ++ + print_cpu_features_value ("xsave_state_size", + cpu_features->xsave_state_size); + print_cpu_features_value ("xsave_state_full_size", + cpu_features->xsave_state_full_size); +- print_cpu_features_value ("data_cache_size", cpu_features->data_cache_size); +- print_cpu_features_value ("shared_cache_size", +- cpu_features->shared_cache_size); ++ print_cpu_features_value ("data_cache_size", __x86_data_cache_size); ++ print_cpu_features_value ("shared_cache_size", __x86_shared_cache_size); + print_cpu_features_value ("non_temporal_threshold", +- cpu_features->non_temporal_threshold); +- print_cpu_features_value ("rep_movsb_threshold", +- cpu_features->rep_movsb_threshold); +- print_cpu_features_value ("rep_stosb_threshold", +- cpu_features->rep_stosb_threshold); ++ __x86_shared_non_temporal_threshold); ++ print_cpu_features_value ("rep_movsb_threshold", __x86_rep_movsb_threshold); ++ print_cpu_features_value ("rep_stosb_threshold", __x86_rep_stosb_threshold); + _Static_assert (offsetof (struct cpu_features, rep_stosb_threshold) + + sizeof (cpu_features->rep_stosb_threshold) + == sizeof (*cpu_features), diff --git a/SOURCES/glibc-RHEL-2423.patch b/SOURCES/glibc-RHEL-2423.patch new file mode 100644 index 0000000..476ea12 --- /dev/null +++ b/SOURCES/glibc-RHEL-2423.patch @@ -0,0 +1,347 @@ +Avoid UAF in getcanonname (CVE-2023-4806) + +When an NSS plugin only implements the _gethostbyname2_r and +_getcanonname_r callbacks, getaddrinfo could use memory that was freed +during tmpbuf resizing, through h_name in a previous query response. + +The backing store for res->at->name when doing a query with +gethostbyname3_r or gethostbyname2_r is tmpbuf, which is reallocated in +gethosts during the query. For AF_INET6 lookup with AI_ALL | +AI_V4MAPPED, gethosts gets called twice, once for a v6 lookup and second +for a v4 lookup. In this case, if the first call reallocates tmpbuf +enough number of times, resulting in a malloc, th->h_name (that +res->at->name refers to) ends up on a heap allocated storage in tmpbuf. +Now if the second call to gethosts also causes the plugin callback to +return NSS_STATUS_TRYAGAIN, tmpbuf will get freed, resulting in a UAF +reference in res->at->name. This then gets dereferenced in the +getcanonname_r plugin call, resulting in the use after free. + +Fix this by copying h_name over and freeing it at the end. This +resolves BZ #30843, which is assigned CVE-2023-4806. This is a minimal +RHEL-8-specific fix. Test case differences from upstream: + +- The test module needs to explicitly link against libnss_files on + RHEL-8; upstream libnss_files is built into libc.so. + +- Test module code was adapted to not use the upstream NSS module + convenience macros. + +This change is adapted from the following commit from upstream: + +commit 973fe93a5675c42798b2161c6f29c01b0e243994 +Author: Siddhesh Poyarekar +Date: Fri Sep 15 13:51:12 2023 -0400 + + getaddrinfo: Fix use after free in getcanonname (CVE-2023-4806) + + When an NSS plugin only implements the _gethostbyname2_r and + _getcanonname_r callbacks, getaddrinfo could use memory that was freed + during tmpbuf resizing, through h_name in a previous query response. + + The backing store for res->at->name when doing a query with + gethostbyname3_r or gethostbyname2_r is tmpbuf, which is reallocated in + gethosts during the query. For AF_INET6 lookup with AI_ALL | + AI_V4MAPPED, gethosts gets called twice, once for a v6 lookup and second + for a v4 lookup. In this case, if the first call reallocates tmpbuf + enough number of times, resulting in a malloc, th->h_name (that + res->at->name refers to) ends up on a heap allocated storage in tmpbuf. + Now if the second call to gethosts also causes the plugin callback to + return NSS_STATUS_TRYAGAIN, tmpbuf will get freed, resulting in a UAF + reference in res->at->name. This then gets dereferenced in the + getcanonname_r plugin call, resulting in the use after free. + + Fix this by copying h_name over and freeing it at the end. This + resolves BZ #30843, which is assigned CVE-2023-4806. + + Signed-off-by: Siddhesh Poyarekar + +diff --git a/nss/Makefile b/nss/Makefile +index cfb255c6e7a3a4de..5829a2539306ddb5 100644 +--- a/nss/Makefile ++++ b/nss/Makefile +@@ -66,7 +66,8 @@ xtests = bug-erange + tests-container = \ + tst-nss-db-endpwent \ + tst-nss-db-endgrent \ +- tst-nss-gai-actions ++ tst-nss-gai-actions \ ++ tst-nss-gai-hv2-canonname + + # Tests which need libdl + ifeq (yes,$(build-shared)) +@@ -132,7 +133,8 @@ routines += $(libnss_files-routines) + static-only-routines += $(libnss_files-routines) + tests-static += tst-nss-static + endif +-extra-test-objs += nss_test1.os nss_test2.os nss_test_errno.os ++extra-test-objs += nss_test1.os nss_test2.os nss_test_errno.os \ ++ nss_test_gai_hv2_canonname.os + + include ../Rules + +@@ -169,12 +171,17 @@ rtld-tests-LDFLAGS += -Wl,--dynamic-list=nss_test.ver + libof-nss_test1 = extramodules + libof-nss_test2 = extramodules + libof-nss_test_errno = extramodules ++libof-nss_test_gai_hv2_canonname = extramodules + $(objpfx)/libnss_test1.so: $(objpfx)nss_test1.os $(link-libc-deps) + $(build-module) + $(objpfx)/libnss_test2.so: $(objpfx)nss_test2.os $(link-libc-deps) + $(build-module) + $(objpfx)/libnss_test_errno.so: $(objpfx)nss_test_errno.os $(link-libc-deps) + $(build-module) ++$(objpfx)/libnss_test_gai_hv2_canonname.so: \ ++ $(objpfx)nss_test_gai_hv2_canonname.os $(link-libc-deps) \ ++ $(objpfx)/libnss_files.so ++ $(build-module) + $(objpfx)nss_test2.os : nss_test1.c + ifdef libnss_test1.so-version + $(objpfx)/libnss_test1.so$(libnss_test1.so-version): $(objpfx)/libnss_test1.so +@@ -187,10 +194,14 @@ endif + $(objpfx)/libnss_test_errno.so$(libnss_files.so-version): \ + $(objpfx)/libnss_test_errno.so + $(make-link) ++$(objpfx)/libnss_test_gai_hv2_canonname.so$(libnss_files.so-version): \ ++ $(objpfx)/libnss_test_gai_hv2_canonname.so ++ $(make-link) + $(patsubst %,$(objpfx)%.out,$(tests)) : \ + $(objpfx)/libnss_test1.so$(libnss_test1.so-version) \ + $(objpfx)/libnss_test2.so$(libnss_test2.so-version) \ +- $(objpfx)/libnss_test_errno.so$(libnss_files.so-version) ++ $(objpfx)/libnss_test_errno.so$(libnss_files.so-version) \ ++ $(objpfx)/libnss_test_gai_hv2_canonname.so$(libnss_files.so-version) + + ifeq (yes,$(have-thread-library)) + $(objpfx)tst-cancel-getpwuid_r: $(shared-thread-library) +diff --git a/nss/nss_test_gai_hv2_canonname.c b/nss/nss_test_gai_hv2_canonname.c +new file mode 100644 +index 0000000000000000..4195d7d24fdd5f6d +--- /dev/null ++++ b/nss/nss_test_gai_hv2_canonname.c +@@ -0,0 +1,64 @@ ++/* NSS service provider that only provides gethostbyname2_r. ++ Copyright The GNU Toolchain Authors. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#include ++#include ++#include ++#include ++#include "nss/tst-nss-gai-hv2-canonname.h" ++ ++/* Catch misnamed and functions. */ ++#pragma GCC diagnostic error "-Wmissing-prototypes" ++ ++extern enum nss_status _nss_files_gethostbyname2_r (const char *, int, ++ struct hostent *, char *, ++ size_t, int *, int *); ++ ++enum nss_status ++_nss_test_gai_hv2_canonname_gethostbyname2_r (const char *, int, struct hostent ++ *, char *, size_t, int *, int *); ++ ++enum nss_status ++_nss_test_gai_hv2_canonname_getcanonname_r (const char *, char *, size_t, char ++ **, int *, int *); ++ ++enum nss_status ++_nss_test_gai_hv2_canonname_gethostbyname2_r (const char *name, int af, ++ struct hostent *result, ++ char *buffer, size_t buflen, ++ int *errnop, int *herrnop) ++{ ++ return _nss_files_gethostbyname2_r (name, af, result, buffer, buflen, errnop, ++ herrnop); ++} ++ ++enum nss_status ++_nss_test_gai_hv2_canonname_getcanonname_r (const char *name, char *buffer, ++ size_t buflen, char **result, ++ int *errnop, int *h_errnop) ++{ ++ /* We expect QUERYNAME, which is a small enough string that it shouldn't fail ++ the test. */ ++ if (memcmp (QUERYNAME, name, sizeof (QUERYNAME)) ++ || buflen < sizeof (QUERYNAME)) ++ abort (); ++ ++ strncpy (buffer, name, buflen); ++ *result = buffer; ++ return NSS_STATUS_SUCCESS; ++} +diff --git a/nss/tst-nss-gai-hv2-canonname.c b/nss/tst-nss-gai-hv2-canonname.c +new file mode 100644 +index 0000000000000000..d5f10c07d6a90773 +--- /dev/null ++++ b/nss/tst-nss-gai-hv2-canonname.c +@@ -0,0 +1,63 @@ ++/* Test NSS query path for plugins that only implement gethostbyname2 ++ (#30843). ++ Copyright The GNU Toolchain Authors. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include "nss/tst-nss-gai-hv2-canonname.h" ++ ++#define PREPARE do_prepare ++ ++static void do_prepare (int a, char **av) ++{ ++ FILE *hosts = xfopen ("/etc/hosts", "w"); ++ for (unsigned i = 2; i < 255; i++) ++ { ++ fprintf (hosts, "ff01::ff02:ff03:%u:2\ttest.example.com\n", i); ++ fprintf (hosts, "192.168.0.%u\ttest.example.com\n", i); ++ } ++ xfclose (hosts); ++} ++ ++static int ++do_test (void) ++{ ++ __nss_configure_lookup ("hosts", "test_gai_hv2_canonname"); ++ ++ struct addrinfo hints = {}; ++ struct addrinfo *result = NULL; ++ ++ hints.ai_family = AF_INET6; ++ hints.ai_flags = AI_ALL | AI_V4MAPPED | AI_CANONNAME; ++ ++ int ret = getaddrinfo (QUERYNAME, NULL, &hints, &result); ++ ++ if (ret != 0) ++ FAIL_EXIT1 ("getaddrinfo failed: %s\n", gai_strerror (ret)); ++ ++ TEST_COMPARE_STRING (result->ai_canonname, QUERYNAME); ++ ++ freeaddrinfo(result); ++ return 0; ++} ++ ++#include +diff --git a/nss/tst-nss-gai-hv2-canonname.h b/nss/tst-nss-gai-hv2-canonname.h +new file mode 100644 +index 0000000000000000..14f2a9cb0867dff9 +--- /dev/null ++++ b/nss/tst-nss-gai-hv2-canonname.h +@@ -0,0 +1 @@ ++#define QUERYNAME "test.example.com" +diff --git a/nss/tst-nss-gai-hv2-canonname.root/postclean.req b/nss/tst-nss-gai-hv2-canonname.root/postclean.req +new file mode 100644 +index 0000000000000000..e69de29bb2d1d643 +diff --git a/nss/tst-nss-gai-hv2-canonname.root/tst-nss-gai-hv2-canonname.script b/nss/tst-nss-gai-hv2-canonname.root/tst-nss-gai-hv2-canonname.script +new file mode 100644 +index 0000000000000000..31848b4a28524af6 +--- /dev/null ++++ b/nss/tst-nss-gai-hv2-canonname.root/tst-nss-gai-hv2-canonname.script +@@ -0,0 +1,2 @@ ++cp $B/nss/libnss_test_gai_hv2_canonname.so $L/libnss_test_gai_hv2_canonname.so.2 ++su +diff --git a/sysdeps/posix/getaddrinfo.c b/sysdeps/posix/getaddrinfo.c +index 4fa963644af8b7d5..46046504a6858f2e 100644 +--- a/sysdeps/posix/getaddrinfo.c ++++ b/sysdeps/posix/getaddrinfo.c +@@ -233,7 +233,6 @@ convert_hostent_to_gaih_addrtuple (const struct addrinfo *req, + } + array[i].next = array + i + 1; + } +- array[0].name = h->h_name; + array[count - 1].next = NULL; + + *result = array; +@@ -287,6 +286,18 @@ convert_hostent_to_gaih_addrtuple (const struct addrinfo *req, + } \ + *pat = addrmem; \ + \ ++ /* Store h_name so that it survives accidental deallocation when \ ++ gethosts is called again and tmpbuf gets reallocated. */ \ ++ if (h_name == NULL && th.h_name != NULL) \ ++ { \ ++ h_name = __strdup (th.h_name); \ ++ if (h_name == NULL) \ ++ { \ ++ __resolv_context_put (res_ctx); \ ++ result = -EAI_SYSTEM; \ ++ goto free_and_return; \ ++ } \ ++ } \ + if (localcanon != NULL && canon == NULL) \ + { \ + canonbuf = __strdup (localcanon); \ +@@ -323,15 +334,15 @@ typedef enum nss_status (*nss_getcanonname_r) + memory allocation failure. The returned string is allocated on the + heap; the caller has to free it. */ + static char * +-getcanonname (service_user *nip, struct gaih_addrtuple *at, const char *name) ++getcanonname (service_user *nip, const char *hname, const char *name) + { + nss_getcanonname_r cfct = __nss_lookup_function (nip, "getcanonname_r"); + char *s = (char *) name; + if (cfct != NULL) + { + char buf[256]; +- if (DL_CALL_FCT (cfct, (at->name ?: name, buf, sizeof (buf), +- &s, &errno, &h_errno)) != NSS_STATUS_SUCCESS) ++ if (DL_CALL_FCT (cfct, (hname ?: name, buf, sizeof (buf), &s, &errno, ++ &h_errno)) != NSS_STATUS_SUCCESS) + /* If the canonical name cannot be determined, use the passed + string. */ + s = (char *) name; +@@ -349,6 +360,7 @@ gaih_inet (const char *name, const struct gaih_service *service, + struct gaih_addrtuple *at = NULL; + bool got_ipv6 = false; + const char *canon = NULL; ++ char *h_name = NULL; + const char *orig_name = name; + + /* Reserve stack memory for the scratch buffer in the getaddrinfo +@@ -919,7 +931,7 @@ gaih_inet (const char *name, const struct gaih_service *service, + if ((req->ai_flags & AI_CANONNAME) != 0 + && canon == NULL) + { +- canonbuf = getcanonname (nip, at, name); ++ canonbuf = getcanonname (nip, h_name, name); + if (canonbuf == NULL) + { + __resolv_context_enable_inet6 +@@ -1169,6 +1181,7 @@ gaih_inet (const char *name, const struct gaih_service *service, + free ((char *) name); + free (addrmem); + free (canonbuf); ++ free (h_name); + + return result; + } diff --git a/SOURCES/glibc-RHEL-2435-2.patch b/SOURCES/glibc-RHEL-2435-2.patch new file mode 100644 index 0000000..8d2a8de --- /dev/null +++ b/SOURCES/glibc-RHEL-2435-2.patch @@ -0,0 +1,22 @@ +Work around in the test case, the fact that RHEL-8 NSS modules +infrastructure incorrectly allows merging in the hosts database. This +is a RHEL-8 only fix. + +diff --git a/nss/tst-nss-gai-actions.c b/nss/tst-nss-gai-actions.c +index efca6cd1837a172a..c35e752896eceb2a 100644 +--- a/nss/tst-nss-gai-actions.c ++++ b/nss/tst-nss-gai-actions.c +@@ -87,6 +87,13 @@ do_one_test (int action, int family, bool canon) + case ACTION_MERGE: + if (ret == 0) + { ++ if (hints.ai_flags == 0 && hints.ai_family == AF_INET) ++ { ++ printf ("***** RHEL-8 limitation: " ++ "NSS modules infrastructure incorrectly allows MERGE\n"); ++ return; ++ } ++ + char *formatted = support_format_addrinfo (ai, ret); + + printf ("merge unexpectedly succeeded:\n %s\n", formatted); diff --git a/SOURCES/glibc-RHEL-2435.patch b/SOURCES/glibc-RHEL-2435.patch new file mode 100644 index 0000000..721cbff --- /dev/null +++ b/SOURCES/glibc-RHEL-2435.patch @@ -0,0 +1,979 @@ +commit 228cdb00a045ae3b68a91b35c7548bab6029446e +Author: Siddhesh Poyarekar +Date: Thu Mar 17 11:44:34 2022 +0530 + + Simplify allocations and fix merge and continue actions [BZ #28931] + + Allocations for address tuples is currently a bit confusing because of + the pointer chasing through PAT, making it hard to observe the sequence + in which allocations have been made. Narrow scope of the pointer + chasing through PAT so that it is only used where necessary. + + This also tightens actions behaviour with the hosts database in + getaddrinfo to comply with the manual text. The "continue" action + discards previous results and the "merge" action results in an immedate + lookup failure. Consequently, chaining of allocations across modules is + no longer necessary, thus opening up cleanup opportunities. + + A test has been added that checks some combinations to ensure that they + work correctly. + + Resolves: BZ #28931 + + Signed-off-by: Siddhesh Poyarekar + Reviewed-by: DJ Delorie + (cherry picked from commit 1c37b8022e8763fedbb3f79c02e05c6acfe5a215) + +Conflicts: + nss/Makefile + (Missing test cases) + sysdeps/posix/getaddrinfo.c + (RES_USE_INET6 still present in RHEL-8 and NSS module traversal rewrite + not in RHEL-8) + +diff --git a/nss/Makefile b/nss/Makefile +index e8a7d9c7b3cefcdf..cfb255c6e7a3a4de 100644 +--- a/nss/Makefile ++++ b/nss/Makefile +@@ -65,7 +65,8 @@ xtests = bug-erange + + tests-container = \ + tst-nss-db-endpwent \ +- tst-nss-db-endgrent ++ tst-nss-db-endgrent \ ++ tst-nss-gai-actions + + # Tests which need libdl + ifeq (yes,$(build-shared)) +diff --git a/nss/tst-nss-gai-actions.c b/nss/tst-nss-gai-actions.c +new file mode 100644 +index 0000000000000000..efca6cd1837a172a +--- /dev/null ++++ b/nss/tst-nss-gai-actions.c +@@ -0,0 +1,149 @@ ++/* Test continue and merge NSS actions for getaddrinfo. ++ 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 ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++ ++enum ++{ ++ ACTION_MERGE = 0, ++ ACTION_CONTINUE, ++}; ++ ++static const char * ++family_str (int family) ++{ ++ switch (family) ++ { ++ case AF_UNSPEC: ++ return "AF_UNSPEC"; ++ case AF_INET: ++ return "AF_INET"; ++ default: ++ __builtin_unreachable (); ++ } ++} ++ ++static const char * ++action_str (int action) ++{ ++ switch (action) ++ { ++ case ACTION_MERGE: ++ return "merge"; ++ case ACTION_CONTINUE: ++ return "continue"; ++ default: ++ __builtin_unreachable (); ++ } ++} ++ ++static void ++do_one_test (int action, int family, bool canon) ++{ ++ struct addrinfo hints = ++ { ++ .ai_family = family, ++ }; ++ ++ struct addrinfo *ai; ++ ++ if (canon) ++ hints.ai_flags = AI_CANONNAME; ++ ++ printf ("***** Testing \"files [SUCCESS=%s] files\" for family %s, %s\n", ++ action_str (action), family_str (family), ++ canon ? "AI_CANONNAME" : ""); ++ ++ int ret = getaddrinfo ("example.org", "80", &hints, &ai); ++ ++ switch (action) ++ { ++ case ACTION_MERGE: ++ if (ret == 0) ++ { ++ char *formatted = support_format_addrinfo (ai, ret); ++ ++ printf ("merge unexpectedly succeeded:\n %s\n", formatted); ++ support_record_failure (); ++ free (formatted); ++ } ++ else ++ return; ++ case ACTION_CONTINUE: ++ { ++ char *formatted = support_format_addrinfo (ai, ret); ++ ++ /* Verify that the result appears exactly once. */ ++ const char *expected = "address: STREAM/TCP 192.0.0.1 80\n" ++ "address: DGRAM/UDP 192.0.0.1 80\n" ++ "address: RAW/IP 192.0.0.1 80\n"; ++ ++ const char *contains = strstr (formatted, expected); ++ const char *contains2 = NULL; ++ ++ if (contains != NULL) ++ contains2 = strstr (contains + strlen (expected), expected); ++ ++ if (contains == NULL || contains2 != NULL) ++ { ++ printf ("continue failed:\n%s\n", formatted); ++ support_record_failure (); ++ } ++ ++ free (formatted); ++ break; ++ } ++ default: ++ __builtin_unreachable (); ++ } ++} ++ ++static void ++do_one_test_set (int action) ++{ ++ char buf[32]; ++ ++ snprintf (buf, sizeof (buf), "files [SUCCESS=%s] files", ++ action_str (action)); ++ __nss_configure_lookup ("hosts", buf); ++ ++ do_one_test (action, AF_UNSPEC, false); ++ do_one_test (action, AF_INET, false); ++ do_one_test (action, AF_INET, true); ++} ++ ++static int ++do_test (void) ++{ ++ do_one_test_set (ACTION_CONTINUE); ++ do_one_test_set (ACTION_MERGE); ++ return 0; ++} ++ ++#include +diff --git a/nss/tst-nss-gai-actions.root/etc/host.conf b/nss/tst-nss-gai-actions.root/etc/host.conf +new file mode 100644 +index 0000000000000000..d1a59f73a90f2993 +--- /dev/null ++++ b/nss/tst-nss-gai-actions.root/etc/host.conf +@@ -0,0 +1 @@ ++multi on +diff --git a/nss/tst-nss-gai-actions.root/etc/hosts b/nss/tst-nss-gai-actions.root/etc/hosts +new file mode 100644 +index 0000000000000000..50ce9774dc2c21d9 +--- /dev/null ++++ b/nss/tst-nss-gai-actions.root/etc/hosts +@@ -0,0 +1,508 @@ ++192.0.0.1 example.org ++192.0.0.2 example.org ++192.0.0.3 example.org ++192.0.0.4 example.org ++192.0.0.5 example.org ++192.0.0.6 example.org ++192.0.0.7 example.org ++192.0.0.8 example.org ++192.0.0.9 example.org ++192.0.0.10 example.org ++192.0.0.11 example.org ++192.0.0.12 example.org ++192.0.0.13 example.org ++192.0.0.14 example.org ++192.0.0.15 example.org ++192.0.0.16 example.org ++192.0.0.17 example.org ++192.0.0.18 example.org ++192.0.0.19 example.org ++192.0.0.20 example.org ++192.0.0.21 example.org ++192.0.0.22 example.org ++192.0.0.23 example.org ++192.0.0.24 example.org ++192.0.0.25 example.org ++192.0.0.26 example.org ++192.0.0.27 example.org ++192.0.0.28 example.org ++192.0.0.29 example.org ++192.0.0.30 example.org ++192.0.0.31 example.org ++192.0.0.32 example.org ++192.0.0.33 example.org ++192.0.0.34 example.org ++192.0.0.35 example.org ++192.0.0.36 example.org ++192.0.0.37 example.org ++192.0.0.38 example.org ++192.0.0.39 example.org ++192.0.0.40 example.org ++192.0.0.41 example.org ++192.0.0.42 example.org ++192.0.0.43 example.org ++192.0.0.44 example.org ++192.0.0.45 example.org ++192.0.0.46 example.org ++192.0.0.47 example.org ++192.0.0.48 example.org ++192.0.0.49 example.org ++192.0.0.50 example.org ++192.0.0.51 example.org ++192.0.0.52 example.org ++192.0.0.53 example.org ++192.0.0.54 example.org ++192.0.0.55 example.org ++192.0.0.56 example.org ++192.0.0.57 example.org ++192.0.0.58 example.org ++192.0.0.59 example.org ++192.0.0.60 example.org ++192.0.0.61 example.org ++192.0.0.62 example.org ++192.0.0.63 example.org ++192.0.0.64 example.org ++192.0.0.65 example.org ++192.0.0.66 example.org ++192.0.0.67 example.org ++192.0.0.68 example.org ++192.0.0.69 example.org ++192.0.0.70 example.org ++192.0.0.71 example.org ++192.0.0.72 example.org ++192.0.0.73 example.org ++192.0.0.74 example.org ++192.0.0.75 example.org ++192.0.0.76 example.org ++192.0.0.77 example.org ++192.0.0.78 example.org ++192.0.0.79 example.org ++192.0.0.80 example.org ++192.0.0.81 example.org ++192.0.0.82 example.org ++192.0.0.83 example.org ++192.0.0.84 example.org ++192.0.0.85 example.org ++192.0.0.86 example.org ++192.0.0.87 example.org ++192.0.0.88 example.org ++192.0.0.89 example.org ++192.0.0.90 example.org ++192.0.0.91 example.org ++192.0.0.92 example.org ++192.0.0.93 example.org ++192.0.0.94 example.org ++192.0.0.95 example.org ++192.0.0.96 example.org ++192.0.0.97 example.org ++192.0.0.98 example.org ++192.0.0.99 example.org ++192.0.0.100 example.org ++192.0.0.101 example.org ++192.0.0.102 example.org ++192.0.0.103 example.org ++192.0.0.104 example.org ++192.0.0.105 example.org ++192.0.0.106 example.org ++192.0.0.107 example.org ++192.0.0.108 example.org ++192.0.0.109 example.org ++192.0.0.110 example.org ++192.0.0.111 example.org ++192.0.0.112 example.org ++192.0.0.113 example.org ++192.0.0.114 example.org ++192.0.0.115 example.org ++192.0.0.116 example.org ++192.0.0.117 example.org ++192.0.0.118 example.org ++192.0.0.119 example.org ++192.0.0.120 example.org ++192.0.0.121 example.org ++192.0.0.122 example.org ++192.0.0.123 example.org ++192.0.0.124 example.org ++192.0.0.125 example.org ++192.0.0.126 example.org ++192.0.0.127 example.org ++192.0.0.128 example.org ++192.0.0.129 example.org ++192.0.0.130 example.org ++192.0.0.131 example.org ++192.0.0.132 example.org ++192.0.0.133 example.org ++192.0.0.134 example.org ++192.0.0.135 example.org ++192.0.0.136 example.org ++192.0.0.137 example.org ++192.0.0.138 example.org ++192.0.0.139 example.org ++192.0.0.140 example.org ++192.0.0.141 example.org ++192.0.0.142 example.org ++192.0.0.143 example.org ++192.0.0.144 example.org ++192.0.0.145 example.org ++192.0.0.146 example.org ++192.0.0.147 example.org ++192.0.0.148 example.org ++192.0.0.149 example.org ++192.0.0.150 example.org ++192.0.0.151 example.org ++192.0.0.152 example.org ++192.0.0.153 example.org ++192.0.0.154 example.org ++192.0.0.155 example.org ++192.0.0.156 example.org ++192.0.0.157 example.org ++192.0.0.158 example.org ++192.0.0.159 example.org ++192.0.0.160 example.org ++192.0.0.161 example.org ++192.0.0.162 example.org ++192.0.0.163 example.org ++192.0.0.164 example.org ++192.0.0.165 example.org ++192.0.0.166 example.org ++192.0.0.167 example.org ++192.0.0.168 example.org ++192.0.0.169 example.org ++192.0.0.170 example.org ++192.0.0.171 example.org ++192.0.0.172 example.org ++192.0.0.173 example.org ++192.0.0.174 example.org ++192.0.0.175 example.org ++192.0.0.176 example.org ++192.0.0.177 example.org ++192.0.0.178 example.org ++192.0.0.179 example.org ++192.0.0.180 example.org ++192.0.0.181 example.org ++192.0.0.182 example.org ++192.0.0.183 example.org ++192.0.0.184 example.org ++192.0.0.185 example.org ++192.0.0.186 example.org ++192.0.0.187 example.org ++192.0.0.188 example.org ++192.0.0.189 example.org ++192.0.0.190 example.org ++192.0.0.191 example.org ++192.0.0.192 example.org ++192.0.0.193 example.org ++192.0.0.194 example.org ++192.0.0.195 example.org ++192.0.0.196 example.org ++192.0.0.197 example.org ++192.0.0.198 example.org ++192.0.0.199 example.org ++192.0.0.200 example.org ++192.0.0.201 example.org ++192.0.0.202 example.org ++192.0.0.203 example.org ++192.0.0.204 example.org ++192.0.0.205 example.org ++192.0.0.206 example.org ++192.0.0.207 example.org ++192.0.0.208 example.org ++192.0.0.209 example.org ++192.0.0.210 example.org ++192.0.0.211 example.org ++192.0.0.212 example.org ++192.0.0.213 example.org ++192.0.0.214 example.org ++192.0.0.215 example.org ++192.0.0.216 example.org ++192.0.0.217 example.org ++192.0.0.218 example.org ++192.0.0.219 example.org ++192.0.0.220 example.org ++192.0.0.221 example.org ++192.0.0.222 example.org ++192.0.0.223 example.org ++192.0.0.224 example.org ++192.0.0.225 example.org ++192.0.0.226 example.org ++192.0.0.227 example.org ++192.0.0.228 example.org ++192.0.0.229 example.org ++192.0.0.230 example.org ++192.0.0.231 example.org ++192.0.0.232 example.org ++192.0.0.233 example.org ++192.0.0.234 example.org ++192.0.0.235 example.org ++192.0.0.236 example.org ++192.0.0.237 example.org ++192.0.0.238 example.org ++192.0.0.239 example.org ++192.0.0.240 example.org ++192.0.0.241 example.org ++192.0.0.242 example.org ++192.0.0.243 example.org ++192.0.0.244 example.org ++192.0.0.245 example.org ++192.0.0.246 example.org ++192.0.0.247 example.org ++192.0.0.248 example.org ++192.0.0.249 example.org ++192.0.0.250 example.org ++192.0.0.251 example.org ++192.0.0.252 example.org ++192.0.0.253 example.org ++192.0.0.254 example.org ++192.0.1.1 example.org ++192.0.1.2 example.org ++192.0.1.3 example.org ++192.0.1.4 example.org ++192.0.1.5 example.org ++192.0.1.6 example.org ++192.0.1.7 example.org ++192.0.1.8 example.org ++192.0.1.9 example.org ++192.0.1.10 example.org ++192.0.1.11 example.org ++192.0.1.12 example.org ++192.0.1.13 example.org ++192.0.1.14 example.org ++192.0.1.15 example.org ++192.0.1.16 example.org ++192.0.1.17 example.org ++192.0.1.18 example.org ++192.0.1.19 example.org ++192.0.1.20 example.org ++192.0.1.21 example.org ++192.0.1.22 example.org ++192.0.1.23 example.org ++192.0.1.24 example.org ++192.0.1.25 example.org ++192.0.1.26 example.org ++192.0.1.27 example.org ++192.0.1.28 example.org ++192.0.1.29 example.org ++192.0.1.30 example.org ++192.0.1.31 example.org ++192.0.1.32 example.org ++192.0.1.33 example.org ++192.0.1.34 example.org ++192.0.1.35 example.org ++192.0.1.36 example.org ++192.0.1.37 example.org ++192.0.1.38 example.org ++192.0.1.39 example.org ++192.0.1.40 example.org ++192.0.1.41 example.org ++192.0.1.42 example.org ++192.0.1.43 example.org ++192.0.1.44 example.org ++192.0.1.45 example.org ++192.0.1.46 example.org ++192.0.1.47 example.org ++192.0.1.48 example.org ++192.0.1.49 example.org ++192.0.1.50 example.org ++192.0.1.51 example.org ++192.0.1.52 example.org ++192.0.1.53 example.org ++192.0.1.54 example.org ++192.0.1.55 example.org ++192.0.1.56 example.org ++192.0.1.57 example.org ++192.0.1.58 example.org ++192.0.1.59 example.org ++192.0.1.60 example.org ++192.0.1.61 example.org ++192.0.1.62 example.org ++192.0.1.63 example.org ++192.0.1.64 example.org ++192.0.1.65 example.org ++192.0.1.66 example.org ++192.0.1.67 example.org ++192.0.1.68 example.org ++192.0.1.69 example.org ++192.0.1.70 example.org ++192.0.1.71 example.org ++192.0.1.72 example.org ++192.0.1.73 example.org ++192.0.1.74 example.org ++192.0.1.75 example.org ++192.0.1.76 example.org ++192.0.1.77 example.org ++192.0.1.78 example.org ++192.0.1.79 example.org ++192.0.1.80 example.org ++192.0.1.81 example.org ++192.0.1.82 example.org ++192.0.1.83 example.org ++192.0.1.84 example.org ++192.0.1.85 example.org ++192.0.1.86 example.org ++192.0.1.87 example.org ++192.0.1.88 example.org ++192.0.1.89 example.org ++192.0.1.90 example.org ++192.0.1.91 example.org ++192.0.1.92 example.org ++192.0.1.93 example.org ++192.0.1.94 example.org ++192.0.1.95 example.org ++192.0.1.96 example.org ++192.0.1.97 example.org ++192.0.1.98 example.org ++192.0.1.99 example.org ++192.0.1.100 example.org ++192.0.1.101 example.org ++192.0.1.102 example.org ++192.0.1.103 example.org ++192.0.1.104 example.org ++192.0.1.105 example.org ++192.0.1.106 example.org ++192.0.1.107 example.org ++192.0.1.108 example.org ++192.0.1.109 example.org ++192.0.1.110 example.org ++192.0.1.111 example.org ++192.0.1.112 example.org ++192.0.1.113 example.org ++192.0.1.114 example.org ++192.0.1.115 example.org ++192.0.1.116 example.org ++192.0.1.117 example.org ++192.0.1.118 example.org ++192.0.1.119 example.org ++192.0.1.120 example.org ++192.0.1.121 example.org ++192.0.1.122 example.org ++192.0.1.123 example.org ++192.0.1.124 example.org ++192.0.1.125 example.org ++192.0.1.126 example.org ++192.0.1.127 example.org ++192.0.1.128 example.org ++192.0.1.129 example.org ++192.0.1.130 example.org ++192.0.1.131 example.org ++192.0.1.132 example.org ++192.0.1.133 example.org ++192.0.1.134 example.org ++192.0.1.135 example.org ++192.0.1.136 example.org ++192.0.1.137 example.org ++192.0.1.138 example.org ++192.0.1.139 example.org ++192.0.1.140 example.org ++192.0.1.141 example.org ++192.0.1.142 example.org ++192.0.1.143 example.org ++192.0.1.144 example.org ++192.0.1.145 example.org ++192.0.1.146 example.org ++192.0.1.147 example.org ++192.0.1.148 example.org ++192.0.1.149 example.org ++192.0.1.150 example.org ++192.0.1.151 example.org ++192.0.1.152 example.org ++192.0.1.153 example.org ++192.0.1.154 example.org ++192.0.1.155 example.org ++192.0.1.156 example.org ++192.0.1.157 example.org ++192.0.1.158 example.org ++192.0.1.159 example.org ++192.0.1.160 example.org ++192.0.1.161 example.org ++192.0.1.162 example.org ++192.0.1.163 example.org ++192.0.1.164 example.org ++192.0.1.165 example.org ++192.0.1.166 example.org ++192.0.1.167 example.org ++192.0.1.168 example.org ++192.0.1.169 example.org ++192.0.1.170 example.org ++192.0.1.171 example.org ++192.0.1.172 example.org ++192.0.1.173 example.org ++192.0.1.174 example.org ++192.0.1.175 example.org ++192.0.1.176 example.org ++192.0.1.177 example.org ++192.0.1.178 example.org ++192.0.1.179 example.org ++192.0.1.180 example.org ++192.0.1.181 example.org ++192.0.1.182 example.org ++192.0.1.183 example.org ++192.0.1.184 example.org ++192.0.1.185 example.org ++192.0.1.186 example.org ++192.0.1.187 example.org ++192.0.1.188 example.org ++192.0.1.189 example.org ++192.0.1.190 example.org ++192.0.1.191 example.org ++192.0.1.192 example.org ++192.0.1.193 example.org ++192.0.1.194 example.org ++192.0.1.195 example.org ++192.0.1.196 example.org ++192.0.1.197 example.org ++192.0.1.198 example.org ++192.0.1.199 example.org ++192.0.1.200 example.org ++192.0.1.201 example.org ++192.0.1.202 example.org ++192.0.1.203 example.org ++192.0.1.204 example.org ++192.0.1.205 example.org ++192.0.1.206 example.org ++192.0.1.207 example.org ++192.0.1.208 example.org ++192.0.1.209 example.org ++192.0.1.210 example.org ++192.0.1.211 example.org ++192.0.1.212 example.org ++192.0.1.213 example.org ++192.0.1.214 example.org ++192.0.1.215 example.org ++192.0.1.216 example.org ++192.0.1.217 example.org ++192.0.1.218 example.org ++192.0.1.219 example.org ++192.0.1.220 example.org ++192.0.1.221 example.org ++192.0.1.222 example.org ++192.0.1.223 example.org ++192.0.1.224 example.org ++192.0.1.225 example.org ++192.0.1.226 example.org ++192.0.1.227 example.org ++192.0.1.228 example.org ++192.0.1.229 example.org ++192.0.1.230 example.org ++192.0.1.231 example.org ++192.0.1.232 example.org ++192.0.1.233 example.org ++192.0.1.234 example.org ++192.0.1.235 example.org ++192.0.1.236 example.org ++192.0.1.237 example.org ++192.0.1.238 example.org ++192.0.1.239 example.org ++192.0.1.240 example.org ++192.0.1.241 example.org ++192.0.1.242 example.org ++192.0.1.243 example.org ++192.0.1.244 example.org ++192.0.1.245 example.org ++192.0.1.246 example.org ++192.0.1.247 example.org ++192.0.1.248 example.org ++192.0.1.249 example.org ++192.0.1.250 example.org ++192.0.1.251 example.org ++192.0.1.252 example.org ++192.0.1.253 example.org ++192.0.1.254 example.org +diff --git a/sysdeps/posix/getaddrinfo.c b/sysdeps/posix/getaddrinfo.c +index fae3dea81f19dba6..4fa963644af8b7d5 100644 +--- a/sysdeps/posix/getaddrinfo.c ++++ b/sysdeps/posix/getaddrinfo.c +@@ -474,11 +474,6 @@ gaih_inet (const char *name, const struct gaih_service *service, + + if (name != NULL) + { +- at = alloca_account (sizeof (struct gaih_addrtuple), alloca_used); +- at->family = AF_UNSPEC; +- at->scopeid = 0; +- at->next = NULL; +- + if (req->ai_flags & AI_IDN) + { + char *out; +@@ -489,13 +484,21 @@ gaih_inet (const char *name, const struct gaih_service *service, + malloc_name = true; + } + +- if (__inet_aton_exact (name, (struct in_addr *) at->addr) != 0) ++ uint32_t addr[4]; ++ if (__inet_aton_exact (name, (struct in_addr *) addr) != 0) + { ++ at = alloca_account (sizeof (struct gaih_addrtuple), alloca_used); ++ at->scopeid = 0; ++ at->next = NULL; ++ + if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET) +- at->family = AF_INET; ++ { ++ memcpy (at->addr, addr, sizeof (at->addr)); ++ at->family = AF_INET; ++ } + else if (req->ai_family == AF_INET6 && (req->ai_flags & AI_V4MAPPED)) + { +- at->addr[3] = at->addr[0]; ++ at->addr[3] = addr[0]; + at->addr[2] = htonl (0xffff); + at->addr[1] = 0; + at->addr[0] = 0; +@@ -509,49 +512,62 @@ gaih_inet (const char *name, const struct gaih_service *service, + + if (req->ai_flags & AI_CANONNAME) + canon = name; ++ ++ goto process_list; + } +- else if (at->family == AF_UNSPEC) ++ ++ char *scope_delim = strchr (name, SCOPE_DELIMITER); ++ int e; ++ ++ if (scope_delim == NULL) ++ e = inet_pton (AF_INET6, name, addr); ++ else ++ e = __inet_pton_length (AF_INET6, name, scope_delim - name, addr); ++ ++ if (e > 0) + { +- char *scope_delim = strchr (name, SCOPE_DELIMITER); +- int e; +- if (scope_delim == NULL) +- e = inet_pton (AF_INET6, name, at->addr); ++ at = alloca_account (sizeof (struct gaih_addrtuple), ++ alloca_used); ++ at->scopeid = 0; ++ at->next = NULL; ++ ++ if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET6) ++ { ++ memcpy (at->addr, addr, sizeof (at->addr)); ++ at->family = AF_INET6; ++ } ++ else if (req->ai_family == AF_INET ++ && IN6_IS_ADDR_V4MAPPED (addr)) ++ { ++ at->addr[0] = addr[3]; ++ at->addr[1] = addr[1]; ++ at->addr[2] = addr[2]; ++ at->addr[3] = addr[3]; ++ at->family = AF_INET; ++ } + else +- e = __inet_pton_length (AF_INET6, name, scope_delim - name, +- at->addr); +- if (e > 0) + { +- if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET6) +- at->family = AF_INET6; +- else if (req->ai_family == AF_INET +- && IN6_IS_ADDR_V4MAPPED (at->addr)) +- { +- at->addr[0] = at->addr[3]; +- at->family = AF_INET; +- } +- else +- { +- result = -EAI_ADDRFAMILY; +- goto free_and_return; +- } +- +- if (scope_delim != NULL +- && __inet6_scopeid_pton ((struct in6_addr *) at->addr, +- scope_delim + 1, +- &at->scopeid) != 0) +- { +- result = -EAI_NONAME; +- goto free_and_return; +- } ++ result = -EAI_ADDRFAMILY; ++ goto free_and_return; ++ } + +- if (req->ai_flags & AI_CANONNAME) +- canon = name; ++ if (scope_delim != NULL ++ && __inet6_scopeid_pton ((struct in6_addr *) at->addr, ++ scope_delim + 1, ++ &at->scopeid) != 0) ++ { ++ result = -EAI_NONAME; ++ goto free_and_return; + } ++ ++ if (req->ai_flags & AI_CANONNAME) ++ canon = name; ++ ++ goto process_list; + } + +- if (at->family == AF_UNSPEC && (req->ai_flags & AI_NUMERICHOST) == 0) ++ if ((req->ai_flags & AI_NUMERICHOST) == 0) + { +- struct gaih_addrtuple **pat = &at; + int no_data = 0; + int no_inet6_data = 0; + service_user *nip; +@@ -560,6 +576,7 @@ gaih_inet (const char *name, const struct gaih_service *service, + int no_more; + struct resolv_context *res_ctx = NULL; + bool res_enable_inet6 = false; ++ bool do_merge = false; + + /* If we do not have to look for IPv6 addresses or the canonical + name, use the simple, old functions, which do not support +@@ -596,7 +613,7 @@ gaih_inet (const char *name, const struct gaih_service *service, + result = -EAI_MEMORY; + goto free_and_return; + } +- *pat = addrmem; ++ at = addrmem; + } + else + { +@@ -649,6 +666,8 @@ gaih_inet (const char *name, const struct gaih_service *service, + } + + struct gaih_addrtuple *addrfree = addrmem; ++ struct gaih_addrtuple **pat = &at; ++ + for (int i = 0; i < air->naddrs; ++i) + { + socklen_t size = (air->family[i] == AF_INET +@@ -712,12 +731,6 @@ gaih_inet (const char *name, const struct gaih_service *service, + + free (air); + +- if (at->family == AF_UNSPEC) +- { +- result = -EAI_NONAME; +- goto free_and_return; +- } +- + goto process_list; + } + else if (err == 0) +@@ -756,6 +769,22 @@ gaih_inet (const char *name, const struct gaih_service *service, + + while (!no_more) + { ++ /* Always start afresh; continue should discard previous results ++ and the hosts database does not support merge. */ ++ at = NULL; ++ free (canonbuf); ++ free (addrmem); ++ canon = canonbuf = NULL; ++ addrmem = NULL; ++ got_ipv6 = false; ++ ++ if (do_merge) ++ { ++ __set_h_errno (NETDB_INTERNAL); ++ __set_errno (EBUSY); ++ break; ++ } ++ + no_data = 0; + nss_gethostbyname4_r fct4 = NULL; + +@@ -768,12 +797,14 @@ gaih_inet (const char *name, const struct gaih_service *service, + { + while (1) + { +- status = DL_CALL_FCT (fct4, (name, pat, ++ status = DL_CALL_FCT (fct4, (name, &at, + tmpbuf->data, tmpbuf->length, + &errno, &h_errno, + NULL)); + if (status == NSS_STATUS_SUCCESS) + break; ++ /* gethostbyname4_r may write into AT, so reset it. */ ++ at = NULL; + if (status != NSS_STATUS_TRYAGAIN + || errno != ERANGE || h_errno != NETDB_INTERNAL) + { +@@ -800,7 +831,9 @@ gaih_inet (const char *name, const struct gaih_service *service, + no_data = 1; + + if ((req->ai_flags & AI_CANONNAME) != 0 && canon == NULL) +- canon = (*pat)->name; ++ canon = at->name; ++ ++ struct gaih_addrtuple **pat = &at; + + while (*pat != NULL) + { +@@ -852,6 +885,8 @@ gaih_inet (const char *name, const struct gaih_service *service, + + if (fct != NULL) + { ++ struct gaih_addrtuple **pat = &at; ++ + if (req->ai_family == AF_INET6 + || req->ai_family == AF_UNSPEC) + { +@@ -927,6 +962,10 @@ gaih_inet (const char *name, const struct gaih_service *service, + if (nss_next_action (nip, status) == NSS_ACTION_RETURN) + break; + ++ /* The hosts database does not support MERGE. */ ++ if (nss_next_action (nip, status) == NSS_ACTION_MERGE) ++ do_merge = true; ++ + if (nip->next == NULL) + no_more = -1; + else +@@ -960,7 +999,7 @@ gaih_inet (const char *name, const struct gaih_service *service, + } + + process_list: +- if (at->family == AF_UNSPEC) ++ if (at == NULL) + { + result = -EAI_NONAME; + goto free_and_return; diff --git a/SOURCES/glibc-RHEL-3010-1.patch b/SOURCES/glibc-RHEL-3010-1.patch new file mode 100644 index 0000000..494ebfd --- /dev/null +++ b/SOURCES/glibc-RHEL-3010-1.patch @@ -0,0 +1,247 @@ +commit 103a469dc7755fd9e8ccf362f3dd4c55dc761908 +Author: Sajan Karumanchi +Date: Wed Jan 18 18:29:04 2023 +0100 + + x86: Cache computation for AMD architecture. + + All AMD architectures cache details will be computed based on + __cpuid__ `0x8000_001D` and the reference to __cpuid__ `0x8000_0006` will be + zeroed out for future architectures. + + Reviewed-by: Premachandra Mallappa + +Conflicts: + sysdeps/x86/dl-cacheinfo.h + (missing backport of commit 2d651eb9265d1366d7b9e881bfddd4 + ("x86: Move x86 processor cache info to cpu_features")) + +diff --git a/sysdeps/x86/cacheinfo.h b/sysdeps/x86/cacheinfo.h +index 572f753474ee0610..b6f111e6668cc212 100644 +--- a/sysdeps/x86/cacheinfo.h ++++ b/sysdeps/x86/cacheinfo.h +@@ -266,10 +266,6 @@ static void + init_cacheinfo (void) + { + /* Find out what brand of processor. */ +- unsigned int ebx; +- unsigned int ecx; +- unsigned int edx; +- int max_cpuid_ex; + long int data = -1; + long int shared = -1; + long int shared_per_thread = -1; +@@ -303,62 +299,14 @@ init_cacheinfo (void) + } + else if (cpu_features->basic.kind == arch_kind_amd) + { +- data = handle_amd (_SC_LEVEL1_DCACHE_SIZE); +- long int core = handle_amd (_SC_LEVEL2_CACHE_SIZE); +- shared = handle_amd (_SC_LEVEL3_CACHE_SIZE); ++ data = handle_amd (_SC_LEVEL1_DCACHE_SIZE, cpu_features); ++ long int core = handle_amd (_SC_LEVEL2_CACHE_SIZE, cpu_features); ++ shared = handle_amd (_SC_LEVEL3_CACHE_SIZE, cpu_features); + shared_per_thread = shared; + +- /* Get maximum extended function. */ +- __cpuid (0x80000000, max_cpuid_ex, ebx, ecx, edx); +- + if (shared <= 0) + /* No shared L3 cache. All we have is the L2 cache. */ + shared = core; +- else +- { +- /* Figure out the number of logical threads that share L3. */ +- if (max_cpuid_ex >= 0x80000008) +- { +- /* Get width of APIC ID. */ +- __cpuid (0x80000008, max_cpuid_ex, ebx, ecx, edx); +- threads = 1 << ((ecx >> 12) & 0x0f); +- } +- +- if (threads == 0 || cpu_features->basic.family >= 0x17) +- { +- /* If APIC ID width is not available, use logical +- processor count. */ +- __cpuid (0x00000001, max_cpuid_ex, ebx, ecx, edx); +- +- if ((edx & (1 << 28)) != 0) +- threads = (ebx >> 16) & 0xff; +- } +- +- /* Cap usage of highest cache level to the number of +- supported threads. */ +- if (threads > 0) +- shared /= threads; +- +- /* Get shared cache per ccx for Zen architectures. */ +- if (cpu_features->basic.family >= 0x17) +- { +- unsigned int eax; +- +- /* Get number of threads share the L3 cache in CCX. */ +- __cpuid_count (0x8000001D, 0x3, eax, ebx, ecx, edx); +- +- unsigned int threads_per_ccx = ((eax >> 14) & 0xfff) + 1; +- shared *= threads_per_ccx; +- } +- else +- { +- /* Account for exclusive L2 and L3 caches. */ +- shared += core; +- } +- } +- +- if (shared_per_thread <= 0) +- shared_per_thread = shared; + } + + if (cpu_features->data_cache_size != 0) +diff --git a/sysdeps/x86/dl-cacheinfo.h b/sysdeps/x86/dl-cacheinfo.h +index b2b90074b0e98a60..294a7d8bfc564aef 100644 +--- a/sysdeps/x86/dl-cacheinfo.h ++++ b/sysdeps/x86/dl-cacheinfo.h +@@ -311,117 +311,47 @@ handle_intel (int name, const struct cpu_features *cpu_features) + + + static long int __attribute__ ((noinline)) +-handle_amd (int name) ++handle_amd (int name, const struct cpu_features *cpu_features) + { + unsigned int eax; + unsigned int ebx; + unsigned int ecx; + unsigned int edx; +- __cpuid (0x80000000, eax, ebx, ecx, edx); ++ unsigned int count = 0x1; + + /* No level 4 cache (yet). */ + if (name > _SC_LEVEL3_CACHE_LINESIZE) + return 0; + +- unsigned int fn = 0x80000005 + (name >= _SC_LEVEL2_CACHE_SIZE); +- if (eax < fn) +- return 0; ++ if (name >= _SC_LEVEL3_CACHE_SIZE) ++ count = 0x3; ++ else if (name >= _SC_LEVEL2_CACHE_SIZE) ++ count = 0x2; ++ else if (name >= _SC_LEVEL1_DCACHE_SIZE) ++ count = 0x0; + +- __cpuid (fn, eax, ebx, ecx, edx); +- +- if (name < _SC_LEVEL1_DCACHE_SIZE) +- { +- name += _SC_LEVEL1_DCACHE_SIZE - _SC_LEVEL1_ICACHE_SIZE; +- ecx = edx; +- } ++ __cpuid_count (0x8000001D, count, eax, ebx, ecx, edx); + + switch (name) + { +- case _SC_LEVEL1_DCACHE_SIZE: +- return (ecx >> 14) & 0x3fc00; +- +- case _SC_LEVEL1_DCACHE_ASSOC: +- ecx >>= 16; +- if ((ecx & 0xff) == 0xff) +- /* Fully associative. */ +- return (ecx << 2) & 0x3fc00; +- return ecx & 0xff; +- +- case _SC_LEVEL1_DCACHE_LINESIZE: +- return ecx & 0xff; +- +- case _SC_LEVEL2_CACHE_SIZE: +- return (ecx & 0xf000) == 0 ? 0 : (ecx >> 6) & 0x3fffc00; +- +- case _SC_LEVEL2_CACHE_ASSOC: +- switch ((ecx >> 12) & 0xf) +- { +- case 0: +- case 1: +- case 2: +- case 4: +- return (ecx >> 12) & 0xf; +- case 6: +- return 8; +- case 8: +- return 16; +- case 10: +- return 32; +- case 11: +- return 48; +- case 12: +- return 64; +- case 13: +- return 96; +- case 14: +- return 128; +- case 15: +- return ((ecx >> 6) & 0x3fffc00) / (ecx & 0xff); +- default: +- return 0; +- } +- /* NOTREACHED */ +- +- case _SC_LEVEL2_CACHE_LINESIZE: +- return (ecx & 0xf000) == 0 ? 0 : ecx & 0xff; +- +- case _SC_LEVEL3_CACHE_SIZE: +- return (edx & 0xf000) == 0 ? 0 : (edx & 0x3ffc0000) << 1; +- +- case _SC_LEVEL3_CACHE_ASSOC: +- switch ((edx >> 12) & 0xf) +- { +- case 0: +- case 1: +- case 2: +- case 4: +- return (edx >> 12) & 0xf; +- case 6: +- return 8; +- case 8: +- return 16; +- case 10: +- return 32; +- case 11: +- return 48; +- case 12: +- return 64; +- case 13: +- return 96; +- case 14: +- return 128; +- case 15: +- return ((edx & 0x3ffc0000) << 1) / (edx & 0xff); +- default: +- return 0; +- } +- /* NOTREACHED */ +- +- case _SC_LEVEL3_CACHE_LINESIZE: +- return (edx & 0xf000) == 0 ? 0 : edx & 0xff; +- +- default: +- assert (! "cannot happen"); ++ case _SC_LEVEL1_ICACHE_ASSOC: ++ case _SC_LEVEL1_DCACHE_ASSOC: ++ case _SC_LEVEL2_CACHE_ASSOC: ++ case _SC_LEVEL3_CACHE_ASSOC: ++ return ecx?((ebx >> 22) & 0x3ff) + 1 : 0; ++ case _SC_LEVEL1_ICACHE_LINESIZE: ++ case _SC_LEVEL1_DCACHE_LINESIZE: ++ case _SC_LEVEL2_CACHE_LINESIZE: ++ case _SC_LEVEL3_CACHE_LINESIZE: ++ return ecx?(ebx & 0xfff) + 1 : 0; ++ case _SC_LEVEL1_ICACHE_SIZE: ++ case _SC_LEVEL1_DCACHE_SIZE: ++ case _SC_LEVEL2_CACHE_SIZE: ++ case _SC_LEVEL3_CACHE_SIZE: ++ return ecx?(((ebx >> 22) & 0x3ff) + 1)*((ebx & 0xfff) + 1)\ ++ *(ecx + 1):0; ++ default: ++ assert (! "cannot happen"); + } + return -1; + } diff --git a/SOURCES/glibc-RHEL-3010-2.patch b/SOURCES/glibc-RHEL-3010-2.patch new file mode 100644 index 0000000..26a42d9 --- /dev/null +++ b/SOURCES/glibc-RHEL-3010-2.patch @@ -0,0 +1,85 @@ +commit 856bab7717ef6d1033fd7cbf7cfb2ddefbfffb07 +Author: Andreas Schwab +Date: Thu Feb 9 14:56:21 2023 +0100 + + x86/dl-cacheinfo: remove unsused parameter from handle_amd + + Also replace an unreachable assert with __builtin_unreachable. + +Conflicts: + sysdeps/x86/dl-cacheinfo.h + (missing backport of commit 2d651eb9265d1366d7b9e881bfddd4 + ("x86: Move x86 processor cache info to cpu_features")) + +diff --git a/sysdeps/x86/cacheinfo.h b/sysdeps/x86/cacheinfo.h +index b6f111e6668cc212..85e5731281c62503 100644 +--- a/sysdeps/x86/cacheinfo.h ++++ b/sysdeps/x86/cacheinfo.h +@@ -299,9 +299,9 @@ init_cacheinfo (void) + } + else if (cpu_features->basic.kind == arch_kind_amd) + { +- data = handle_amd (_SC_LEVEL1_DCACHE_SIZE, cpu_features); +- long int core = handle_amd (_SC_LEVEL2_CACHE_SIZE, cpu_features); +- shared = handle_amd (_SC_LEVEL3_CACHE_SIZE, cpu_features); ++ data = handle_amd (_SC_LEVEL1_DCACHE_SIZE); ++ long int core = handle_amd (_SC_LEVEL2_CACHE_SIZE); ++ shared = handle_amd (_SC_LEVEL3_CACHE_SIZE); + shared_per_thread = shared; + + if (shared <= 0) +diff --git a/sysdeps/x86/dl-cacheinfo.h b/sysdeps/x86/dl-cacheinfo.h +index 294a7d8bfc564aef..74cd5072a9d10756 100644 +--- a/sysdeps/x86/dl-cacheinfo.h ++++ b/sysdeps/x86/dl-cacheinfo.h +@@ -311,7 +311,7 @@ handle_intel (int name, const struct cpu_features *cpu_features) + + + static long int __attribute__ ((noinline)) +-handle_amd (int name, const struct cpu_features *cpu_features) ++handle_amd (int name) + { + unsigned int eax; + unsigned int ebx; +@@ -334,24 +334,23 @@ handle_amd (int name, const struct cpu_features *cpu_features) + + switch (name) + { +- case _SC_LEVEL1_ICACHE_ASSOC: +- case _SC_LEVEL1_DCACHE_ASSOC: +- case _SC_LEVEL2_CACHE_ASSOC: +- case _SC_LEVEL3_CACHE_ASSOC: +- return ecx?((ebx >> 22) & 0x3ff) + 1 : 0; +- case _SC_LEVEL1_ICACHE_LINESIZE: +- case _SC_LEVEL1_DCACHE_LINESIZE: +- case _SC_LEVEL2_CACHE_LINESIZE: +- case _SC_LEVEL3_CACHE_LINESIZE: +- return ecx?(ebx & 0xfff) + 1 : 0; +- case _SC_LEVEL1_ICACHE_SIZE: +- case _SC_LEVEL1_DCACHE_SIZE: +- case _SC_LEVEL2_CACHE_SIZE: +- case _SC_LEVEL3_CACHE_SIZE: +- return ecx?(((ebx >> 22) & 0x3ff) + 1)*((ebx & 0xfff) + 1)\ +- *(ecx + 1):0; +- default: +- assert (! "cannot happen"); ++ case _SC_LEVEL1_ICACHE_ASSOC: ++ case _SC_LEVEL1_DCACHE_ASSOC: ++ case _SC_LEVEL2_CACHE_ASSOC: ++ case _SC_LEVEL3_CACHE_ASSOC: ++ return ecx ? ((ebx >> 22) & 0x3ff) + 1 : 0; ++ case _SC_LEVEL1_ICACHE_LINESIZE: ++ case _SC_LEVEL1_DCACHE_LINESIZE: ++ case _SC_LEVEL2_CACHE_LINESIZE: ++ case _SC_LEVEL3_CACHE_LINESIZE: ++ return ecx ? (ebx & 0xfff) + 1 : 0; ++ case _SC_LEVEL1_ICACHE_SIZE: ++ case _SC_LEVEL1_DCACHE_SIZE: ++ case _SC_LEVEL2_CACHE_SIZE: ++ case _SC_LEVEL3_CACHE_SIZE: ++ return ecx ? (((ebx >> 22) & 0x3ff) + 1) * ((ebx & 0xfff) + 1) * (ecx + 1): 0; ++ default: ++ __builtin_unreachable (); + } + return -1; + } diff --git a/SOURCES/glibc-RHEL-3010-3.patch b/SOURCES/glibc-RHEL-3010-3.patch new file mode 100644 index 0000000..05022a2 --- /dev/null +++ b/SOURCES/glibc-RHEL-3010-3.patch @@ -0,0 +1,280 @@ +commit dcad5c8578130dec7f35fd5b0885304b59f9f543 +Author: Sajan Karumanchi +Date: Tue Aug 1 15:20:55 2023 +0000 + + x86: Fix for cache computation on AMD legacy cpus. + + Some legacy AMD CPUs and hypervisors have the _cpuid_ '0x8000_001D' + set to Zero, thus resulting in zeroed-out computed cache values. + This patch reintroduces the old way of cache computation as a + fail-safe option to handle these exceptions. + Fixed 'level4_cache_size' value through handle_amd(). + + Reviewed-by: Premachandra Mallappa + Tested-by: Florian Weimer + +Conflicts: + sysdeps/x86/dl-cacheinfo.h + (missing backport of commit 2d651eb9265d1366d7b9e881bfddd4 + ("x86: Move x86 processor cache info to cpu_features")) + +diff --git a/sysdeps/x86/cacheinfo.h b/sysdeps/x86/cacheinfo.h +index 85e5731281c62503..10ebadd819d9efff 100644 +--- a/sysdeps/x86/cacheinfo.h ++++ b/sysdeps/x86/cacheinfo.h +@@ -302,11 +302,19 @@ init_cacheinfo (void) + data = handle_amd (_SC_LEVEL1_DCACHE_SIZE); + long int core = handle_amd (_SC_LEVEL2_CACHE_SIZE); + shared = handle_amd (_SC_LEVEL3_CACHE_SIZE); +- shared_per_thread = shared; + + if (shared <= 0) +- /* No shared L3 cache. All we have is the L2 cache. */ +- shared = core; ++ { ++ /* No shared L3 cache. All we have is the L2 cache. */ ++ shared = core; ++ } ++ else if (cpu_features->basic.family < 0x17) ++ { ++ /* Account for exclusive L2 and L3 caches. */ ++ shared += core; ++ } ++ ++ shared_per_thread = shared; + } + + if (cpu_features->data_cache_size != 0) +diff --git a/sysdeps/x86/dl-cacheinfo.h b/sysdeps/x86/dl-cacheinfo.h +index 74cd5072a9d10756..75a6b1dfde199dd7 100644 +--- a/sysdeps/x86/dl-cacheinfo.h ++++ b/sysdeps/x86/dl-cacheinfo.h +@@ -315,40 +315,206 @@ handle_amd (int name) + { + unsigned int eax; + unsigned int ebx; +- unsigned int ecx; ++ unsigned int ecx = 0; + unsigned int edx; +- unsigned int count = 0x1; ++ unsigned int max_cpuid = 0; ++ unsigned int fn = 0; + + /* No level 4 cache (yet). */ + if (name > _SC_LEVEL3_CACHE_LINESIZE) + return 0; + +- if (name >= _SC_LEVEL3_CACHE_SIZE) +- count = 0x3; +- else if (name >= _SC_LEVEL2_CACHE_SIZE) +- count = 0x2; +- else if (name >= _SC_LEVEL1_DCACHE_SIZE) +- count = 0x0; ++ __cpuid (0x80000000, max_cpuid, ebx, ecx, edx); ++ ++ if (max_cpuid >= 0x8000001D) ++ /* Use __cpuid__ '0x8000_001D' to compute cache details. */ ++ { ++ unsigned int count = 0x1; ++ ++ if (name >= _SC_LEVEL3_CACHE_SIZE) ++ count = 0x3; ++ else if (name >= _SC_LEVEL2_CACHE_SIZE) ++ count = 0x2; ++ else if (name >= _SC_LEVEL1_DCACHE_SIZE) ++ count = 0x0; ++ ++ __cpuid_count (0x8000001D, count, eax, ebx, ecx, edx); ++ ++ if (ecx != 0) ++ { ++ switch (name) ++ { ++ case _SC_LEVEL1_ICACHE_ASSOC: ++ case _SC_LEVEL1_DCACHE_ASSOC: ++ case _SC_LEVEL2_CACHE_ASSOC: ++ case _SC_LEVEL3_CACHE_ASSOC: ++ return ((ebx >> 22) & 0x3ff) + 1; ++ case _SC_LEVEL1_ICACHE_LINESIZE: ++ case _SC_LEVEL1_DCACHE_LINESIZE: ++ case _SC_LEVEL2_CACHE_LINESIZE: ++ case _SC_LEVEL3_CACHE_LINESIZE: ++ return (ebx & 0xfff) + 1; ++ case _SC_LEVEL1_ICACHE_SIZE: ++ case _SC_LEVEL1_DCACHE_SIZE: ++ case _SC_LEVEL2_CACHE_SIZE: ++ case _SC_LEVEL3_CACHE_SIZE: ++ return (((ebx >> 22) & 0x3ff) + 1) * ((ebx & 0xfff) + 1) * (ecx + 1); ++ default: ++ __builtin_unreachable (); ++ } ++ return -1; ++ } ++ } + +- __cpuid_count (0x8000001D, count, eax, ebx, ecx, edx); ++ /* Legacy cache computation for CPUs prior to Bulldozer family. ++ This is also a fail-safe mechanism for some hypervisors that ++ accidentally configure __cpuid__ '0x8000_001D' to Zero. */ ++ ++ fn = 0x80000005 + (name >= _SC_LEVEL2_CACHE_SIZE); ++ ++ if (max_cpuid < fn) ++ return 0; ++ ++ __cpuid (fn, eax, ebx, ecx, edx); ++ ++ if (name < _SC_LEVEL1_DCACHE_SIZE) ++ { ++ name += _SC_LEVEL1_DCACHE_SIZE - _SC_LEVEL1_ICACHE_SIZE; ++ ecx = edx; ++ } + + switch (name) + { +- case _SC_LEVEL1_ICACHE_ASSOC: +- case _SC_LEVEL1_DCACHE_ASSOC: +- case _SC_LEVEL2_CACHE_ASSOC: ++ case _SC_LEVEL1_DCACHE_SIZE: ++ return (ecx >> 14) & 0x3fc00; ++ ++ case _SC_LEVEL1_DCACHE_ASSOC: ++ ecx >>= 16; ++ if ((ecx & 0xff) == 0xff) ++ { ++ /* Fully associative. */ ++ return (ecx << 2) & 0x3fc00; ++ } ++ return ecx & 0xff; ++ ++ case _SC_LEVEL1_DCACHE_LINESIZE: ++ return ecx & 0xff; ++ ++ case _SC_LEVEL2_CACHE_SIZE: ++ return (ecx & 0xf000) == 0 ? 0 : (ecx >> 6) & 0x3fffc00; ++ ++ case _SC_LEVEL2_CACHE_ASSOC: ++ switch ((ecx >> 12) & 0xf) ++ { ++ case 0: ++ case 1: ++ case 2: ++ case 4: ++ return (ecx >> 12) & 0xf; ++ case 6: ++ return 8; ++ case 8: ++ return 16; ++ case 10: ++ return 32; ++ case 11: ++ return 48; ++ case 12: ++ return 64; ++ case 13: ++ return 96; ++ case 14: ++ return 128; ++ case 15: ++ return ((ecx >> 6) & 0x3fffc00) / (ecx & 0xff); ++ default: ++ return 0; ++ } ++ ++ case _SC_LEVEL2_CACHE_LINESIZE: ++ return (ecx & 0xf000) == 0 ? 0 : ecx & 0xff; ++ ++ case _SC_LEVEL3_CACHE_SIZE: ++ { ++ long int total_l3_cache = 0, l3_cache_per_thread = 0; ++ unsigned int threads = 0; ++ const struct cpu_features *cpu_features; ++ ++ if ((edx & 0xf000) == 0) ++ return 0; ++ ++ total_l3_cache = (edx & 0x3ffc0000) << 1; ++ cpu_features = __get_cpu_features (); ++ ++ /* Figure out the number of logical threads that share L3. */ ++ if (max_cpuid >= 0x80000008) ++ { ++ /* Get width of APIC ID. */ ++ __cpuid (0x80000008, eax, ebx, ecx, edx); ++ threads = (ecx & 0xff) + 1; ++ } ++ ++ if (threads == 0) ++ { ++ /* If APIC ID width is not available, use logical ++ processor count. */ ++ __cpuid (0x00000001, eax, ebx, ecx, edx); ++ if ((edx & (1 << 28)) != 0) ++ threads = (ebx >> 16) & 0xff; ++ } ++ ++ /* Cap usage of highest cache level to the number of ++ supported threads. */ ++ if (threads > 0) ++ l3_cache_per_thread = total_l3_cache/threads; ++ ++ /* Get shared cache per ccx for Zen architectures. */ ++ if (cpu_features->basic.family >= 0x17) ++ { ++ long int l3_cache_per_ccx = 0; ++ /* Get number of threads share the L3 cache in CCX. */ ++ __cpuid_count (0x8000001D, 0x3, eax, ebx, ecx, edx); ++ unsigned int threads_per_ccx = ((eax >> 14) & 0xfff) + 1; ++ l3_cache_per_ccx = l3_cache_per_thread * threads_per_ccx; ++ return l3_cache_per_ccx; ++ } ++ else ++ { ++ return l3_cache_per_thread; ++ } ++ } ++ + case _SC_LEVEL3_CACHE_ASSOC: +- return ecx ? ((ebx >> 22) & 0x3ff) + 1 : 0; +- case _SC_LEVEL1_ICACHE_LINESIZE: +- case _SC_LEVEL1_DCACHE_LINESIZE: +- case _SC_LEVEL2_CACHE_LINESIZE: ++ switch ((edx >> 12) & 0xf) ++ { ++ case 0: ++ case 1: ++ case 2: ++ case 4: ++ return (edx >> 12) & 0xf; ++ case 6: ++ return 8; ++ case 8: ++ return 16; ++ case 10: ++ return 32; ++ case 11: ++ return 48; ++ case 12: ++ return 64; ++ case 13: ++ return 96; ++ case 14: ++ return 128; ++ case 15: ++ return ((edx & 0x3ffc0000) << 1) / (edx & 0xff); ++ default: ++ return 0; ++ } ++ + case _SC_LEVEL3_CACHE_LINESIZE: +- return ecx ? (ebx & 0xfff) + 1 : 0; +- case _SC_LEVEL1_ICACHE_SIZE: +- case _SC_LEVEL1_DCACHE_SIZE: +- case _SC_LEVEL2_CACHE_SIZE: +- case _SC_LEVEL3_CACHE_SIZE: +- return ecx ? (((ebx >> 22) & 0x3ff) + 1) * ((ebx & 0xfff) + 1) * (ecx + 1): 0; ++ return (edx & 0xf000) == 0 ? 0 : edx & 0xff; ++ + default: + __builtin_unreachable (); + } diff --git a/SOURCES/glibc-RHEL-3036.patch b/SOURCES/glibc-RHEL-3036.patch new file mode 100644 index 0000000..c7f9f8f --- /dev/null +++ b/SOURCES/glibc-RHEL-3036.patch @@ -0,0 +1,157 @@ +This patch was developed under embargo and cannot reference an upstream +commit. To find the associated commit please review the upstream git +log for CVE-2023-4911 to identify the relevant commits. + +Author: Siddhesh Poyarekar +Date: Tue Sep 19 18:39:32 2023 -0400 + + tunables: Terminate if end of input is reached (CVE-2023-4911) + + The string parsing routine may end up writing beyond bounds of tunestr + if the input tunable string is malformed, of the form name=name=val. + This gets processed twice, first as name=name=val and next as name=val, + resulting in tunestr being name=name=val:name=val, thus overflowing + tunestr. + + Terminate the parsing loop at the first instance itself so that tunestr + does not overflow. + + This also fixes up tst-env-setuid-tunables to actually handle failures + correct and add new tests to validate the fix for this CVE. + + Signed-off-by: Siddhesh Poyarekar + Reviewed-by: Carlos O'Donell + +Conflicts: + NEWS + (Dropped) + elf/tst-env-setuid-tunables.c + (Trivial conflict at HAVE_TUNABLES) + +diff --git a/elf/dl-tunables.c b/elf/dl-tunables.c +index 3c84809d44381241..2c878e08ea197b29 100644 +--- a/elf/dl-tunables.c ++++ b/elf/dl-tunables.c +@@ -193,11 +193,7 @@ parse_tunables (char *tunestr, char *valstring) + /* If we reach the end of the string before getting a valid name-value + pair, bail out. */ + if (p[len] == '\0') +- { +- if (__libc_enable_secure) +- tunestr[off] = '\0'; +- return; +- } ++ break; + + /* We did not find a valid name-value pair before encountering the + colon. */ +@@ -257,9 +253,16 @@ parse_tunables (char *tunestr, char *valstring) + } + } + +- if (p[len] != '\0') +- p += len + 1; ++ /* We reached the end while processing the tunable string. */ ++ if (p[len] == '\0') ++ break; ++ ++ p += len + 1; + } ++ ++ /* Terminate tunestr before we leave. */ ++ if (__libc_enable_secure) ++ tunestr[off] = '\0'; + } + #endif + +diff --git a/elf/tst-env-setuid-tunables.c b/elf/tst-env-setuid-tunables.c +index 0b9b075c40598c6f..8b0861c4ad853040 100644 +--- a/elf/tst-env-setuid-tunables.c ++++ b/elf/tst-env-setuid-tunables.c +@@ -52,6 +52,8 @@ const char *teststrings[] = + "glibc.malloc.perturb=0x800:not_valid.malloc.check=2:glibc.malloc.mmap_threshold=4096", + "glibc.not_valid.check=2:glibc.malloc.mmap_threshold=4096", + "not_valid.malloc.check=2:glibc.malloc.mmap_threshold=4096", ++ "glibc.malloc.mmap_threshold=glibc.malloc.mmap_threshold=4096", ++ "glibc.malloc.check=2", + "glibc.malloc.garbage=2:glibc.maoc.mmap_threshold=4096:glibc.malloc.check=2", + "glibc.malloc.check=4:glibc.malloc.garbage=2:glibc.maoc.mmap_threshold=4096", + ":glibc.malloc.garbage=2:glibc.malloc.check=1", +@@ -70,6 +72,8 @@ const char *resultstrings[] = + "glibc.malloc.perturb=0x800:glibc.malloc.mmap_threshold=4096", + "glibc.malloc.mmap_threshold=4096", + "glibc.malloc.mmap_threshold=4096", ++ "glibc.malloc.mmap_threshold=glibc.malloc.mmap_threshold=4096", ++ "", + "", + "", + "", +@@ -84,11 +88,18 @@ test_child (int off) + const char *val = getenv ("GLIBC_TUNABLES"); + + #if HAVE_TUNABLES ++ printf (" [%d] GLIBC_TUNABLES is %s\n", off, val); ++ fflush (stdout); + if (val != NULL && strcmp (val, resultstrings[off]) == 0) + return 0; + + if (val != NULL) +- printf ("[%d] Unexpected GLIBC_TUNABLES VALUE %s\n", off, val); ++ printf (" [%d] Unexpected GLIBC_TUNABLES VALUE %s, expected %s\n", ++ off, val, resultstrings[off]); ++ else ++ printf (" [%d] GLIBC_TUNABLES environment variable absent\n", off); ++ ++ fflush (stdout); + + return 1; + #else +@@ -117,21 +128,26 @@ do_test (int argc, char **argv) + if (ret != 0) + exit (1); + +- exit (EXIT_SUCCESS); ++ /* Special return code to make sure that the child executed all the way ++ through. */ ++ exit (42); + } + else + { +- int ret = 0; +- + /* Spawn tests. */ + for (int i = 0; i < array_length (teststrings); i++) + { + char buf[INT_BUFSIZE_BOUND (int)]; + +- printf ("Spawned test for %s (%d)\n", teststrings[i], i); ++ printf ("[%d] Spawned test for %s\n", i, teststrings[i]); + snprintf (buf, sizeof (buf), "%d\n", i); ++ fflush (stdout); + if (setenv ("GLIBC_TUNABLES", teststrings[i], 1) != 0) +- exit (1); ++ { ++ printf (" [%d] Failed to set GLIBC_TUNABLES: %m", i); ++ support_record_failure (); ++ continue; ++ } + + int status = support_capture_subprogram_self_sgid (buf); + +@@ -139,9 +155,14 @@ do_test (int argc, char **argv) + if (WEXITSTATUS (status) == EXIT_UNSUPPORTED) + return EXIT_UNSUPPORTED; + +- ret |= status; ++ if (WEXITSTATUS (status) != 42) ++ { ++ printf (" [%d] child failed with status %d\n", i, ++ WEXITSTATUS (status)); ++ support_record_failure (); ++ } + } +- return ret; ++ return 0; + } + } + diff --git a/SOURCES/glibc-RHEL-3639.patch b/SOURCES/glibc-RHEL-3639.patch new file mode 100644 index 0000000..e51ab13 --- /dev/null +++ b/SOURCES/glibc-RHEL-3639.patch @@ -0,0 +1,235 @@ +commit d0f07f7df8d9758c838674b70144ac73bcbd1634 +Author: Florian Weimer +Date: Tue May 30 13:25:50 2023 +0200 + + elf: Make more functions available for binding during dlclose (bug 30425) + + Previously, after destructors for a DSO have been invoked, ld.so refused + to bind against that DSO in all cases. Relax this restriction somewhat + if the referencing object is itself a DSO that is being unloaded. This + assumes that the symbol reference is not going to be stored anywhere. + + The situation in the test case can arise fairly easily with C++ and + objects that are built with different optimization levels and therefore + define different functions with vague linkage. + + Reviewed-by: Carlos O'Donell + +Conflicts: + elf/Makefile + (usual test differences, link test with -ldl) + +diff --git a/elf/Makefile b/elf/Makefile +index 634c3113227d64a6..42dc878209b11d29 100644 +--- a/elf/Makefile ++++ b/elf/Makefile +@@ -362,6 +362,7 @@ tests += \ + tst-big-note \ + tst-debug1 \ + tst-deep1 \ ++ tst-dlclose-lazy \ + tst-dlmodcount \ + tst-dlmopen1 \ + tst-dlmopen3 \ +@@ -709,6 +710,8 @@ modules-names = \ + tst-deep1mod2 \ + tst-deep1mod3 \ + tst-dlmopen1mod \ ++ tst-dlclose-lazy-mod1 \ ++ tst-dlclose-lazy-mod2 \ + tst-dlmopen-dlerror-mod \ + tst-dlmopen-gethostbyname-mod \ + tst-dlmopen-twice-mod1 \ +@@ -2697,3 +2700,10 @@ $(objpfx)tst-dlmopen-twice: $(libdl) + $(objpfx)tst-dlmopen-twice.out: \ + $(objpfx)tst-dlmopen-twice-mod1.so \ + $(objpfx)tst-dlmopen-twice-mod2.so ++ ++LDFLAGS-tst-dlclose-lazy-mod1.so = -Wl,-z,lazy,--no-as-needed ++$(objpfx)tst-dlclose-lazy-mod1.so: $(objpfx)tst-dlclose-lazy-mod2.so ++$(objpfx)tst-dlclose-lazy: $(libdl) ++$(objpfx)tst-dlclose-lazy.out: \ ++ $(objpfx)tst-dlclose-lazy-mod1.so $(objpfx)tst-dlclose-lazy-mod2.so ++ +diff --git a/elf/dl-lookup.c b/elf/dl-lookup.c +index 47acd134600b44b5..9e8f14b8483f5eba 100644 +--- a/elf/dl-lookup.c ++++ b/elf/dl-lookup.c +@@ -380,8 +380,25 @@ do_lookup_x (const char *undef_name, uint_fast32_t new_hash, + if ((type_class & ELF_RTYPE_CLASS_COPY) && map->l_type == lt_executable) + continue; + +- /* Do not look into objects which are going to be removed. */ +- if (map->l_removed) ++ /* Do not look into objects which are going to be removed, ++ except when the referencing object itself is being removed. ++ ++ The second part covers the situation when an object lazily ++ binds to another object while running its destructor, but the ++ destructor of the other object has already run, so that ++ dlclose has set l_removed. It may not always be obvious how ++ to avoid such a scenario to programmers creating DSOs, ++ particularly if C++ vague linkage is involved and triggers ++ symbol interposition. ++ ++ Accepting these to-be-removed objects makes the lazy and ++ BIND_NOW cases more similar. (With BIND_NOW, the symbol is ++ resolved early, before the destructor call, so the issue does ++ not arise.). Behavior matches the constructor scenario: the ++ implementation allows binding to symbols of objects whose ++ constructors have not run. In fact, not doing this would be ++ mostly incompatible with symbol interposition. */ ++ if (map->l_removed && !(undef_map != NULL && undef_map->l_removed)) + continue; + + /* Print some debugging info if wanted. */ +diff --git a/elf/tst-dlclose-lazy-mod1.c b/elf/tst-dlclose-lazy-mod1.c +new file mode 100644 +index 0000000000000000..8439dc1925cc8b41 +--- /dev/null ++++ b/elf/tst-dlclose-lazy-mod1.c +@@ -0,0 +1,36 @@ ++/* Lazy binding during dlclose. Directly loaded module. ++ Copyright (C) 2023 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++/* This function is called from exported_function below. It is only ++ defined in this module. The weak attribute mimics how G++ ++ implements vague linkage for C++. */ ++void __attribute__ ((weak)) ++lazily_bound_exported_function (void) ++{ ++} ++ ++/* Called from tst-dlclose-lazy-mod2.so. */ ++void ++exported_function (int call_it) ++{ ++ if (call_it) ++ /* Previous to the fix this would crash when called during dlclose ++ since symbols from the DSO were no longer available for binding ++ (bug 30425) after the DSO started being closed by dlclose. */ ++ lazily_bound_exported_function (); ++} +diff --git a/elf/tst-dlclose-lazy-mod2.c b/elf/tst-dlclose-lazy-mod2.c +new file mode 100644 +index 0000000000000000..767f69ffdb23a685 +--- /dev/null ++++ b/elf/tst-dlclose-lazy-mod2.c +@@ -0,0 +1,49 @@ ++/* Lazy binding during dlclose. Indirectly loaded module. ++ Copyright (C) 2023 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#include ++#include ++ ++void ++exported_function (int ignored) ++{ ++ /* This function is interposed from tst-dlclose-lazy-mod1.so and ++ thus never called. */ ++ abort (); ++} ++ ++static void __attribute__ ((constructor)) ++init (void) ++{ ++ puts ("info: tst-dlclose-lazy-mod2.so constructor called"); ++ ++ /* Trigger lazy binding to the definition in ++ tst-dlclose-lazy-mod1.so, but not for ++ lazily_bound_exported_function in that module. */ ++ exported_function (0); ++} ++ ++static void __attribute__ ((destructor)) ++fini (void) ++{ ++ puts ("info: tst-dlclose-lazy-mod2.so destructor called"); ++ ++ /* Trigger the lazily_bound_exported_function call in ++ exported_function in tst-dlclose-lazy-mod1.so. */ ++ exported_function (1); ++} +diff --git a/elf/tst-dlclose-lazy.c b/elf/tst-dlclose-lazy.c +new file mode 100644 +index 0000000000000000..976a6bb6f64fa981 +--- /dev/null ++++ b/elf/tst-dlclose-lazy.c +@@ -0,0 +1,47 @@ ++/* Test lazy binding during dlclose (bug 30425). ++ Copyright (C) 2023 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++/* This test re-creates a situation that can arise naturally for C++ ++ applications due to the use of vague linkage and differences in the ++ set of compiler-emitted functions. A function in ++ tst-dlclose-lazy-mod1.so (exported_function) interposes a function ++ in tst-dlclose-lazy-mod2.so. This function is called from the ++ destructor in tst-dlclose-lazy-mod2.so, after the destructor for ++ tst-dlclose-lazy-mod1.so has already completed. Prior to the fix ++ for bug 30425, this would lead to a lazy binding failure in ++ tst-dlclose-lazy-mod1.so because dlclose had already marked the DSO ++ as unavailable for binding (by setting l_removed). */ ++ ++#include ++#include ++#include ++ ++int ++main (void) ++{ ++ /* Load tst-dlclose-lazy-mod1.so, indirectly loading ++ tst-dlclose-lazy-mod2.so. */ ++ void *handle = xdlopen ("tst-dlclose-lazy-mod1.so", RTLD_GLOBAL | RTLD_LAZY); ++ ++ /* Invoke the destructor of tst-dlclose-lazy-mod2.so, which calls ++ into tst-dlclose-lazy-mod1.so after its destructor has been ++ called. */ ++ xdlclose (handle); ++ ++ return 0; ++} diff --git a/SOURCES/glibc-RHEL-3757.patch b/SOURCES/glibc-RHEL-3757.patch new file mode 100644 index 0000000..8902823 --- /dev/null +++ b/SOURCES/glibc-RHEL-3757.patch @@ -0,0 +1,97 @@ +commit 2ac579f9c25388a7734948d77b03e4dd10f35334 +Author: DJ Delorie +Date: Mon Sep 30 16:04:52 2019 -0400 + + Add run-one-test convenience target and makefile help text + + Adds "make test" for re-running just one test. Also adds + "make help" for help with our Makefile targets, and adds a + mini-help when you just run "make". + + Reviewed-by: Carlos O'Donell + +diff --git a/Makefile b/Makefile +index 6d73241bbc811c13..6518f62ee0676b0d 100644 +--- a/Makefile ++++ b/Makefile +@@ -26,8 +26,17 @@ include Makeconfig + + + # This is the default target; it makes everything except the tests. +-.PHONY: all +-all: lib others ++.PHONY: all help minihelp ++all: minihelp lib others ++ ++help: ++ @sed '0,/^help-starts-here$$/d' Makefile.help ++ ++minihelp: ++ @echo ++ @echo type \"make help\" for help with common glibc makefile targets ++ @echo ++ + + ifneq ($(AUTOCONF),no) + +@@ -503,3 +512,12 @@ FORCE: + + iconvdata/% localedata/% po/%: FORCE + $(MAKE) $(PARALLELMFLAGS) -C $(@D) $(@F) ++ ++# Convenience target to rerun one test, from the top of the build tree ++# Example: make test t=wcsmbs/test-wcsnlen ++.PHONY: test ++test : ++ @-rm -f $(objpfx)$t.out ++ $(MAKE) subdir=$(dir $t) -C $(dir $t) ..=../ $(objpfx)$t.out ++ @cat $(objpfx)$t.test-result ++ @cat $(objpfx)$t.out +diff --git a/Makefile.help b/Makefile.help +new file mode 100644 +index 0000000000000000..3b043bce013cc2b4 +--- /dev/null ++++ b/Makefile.help +@@ -0,0 +1,42 @@ ++# 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, see ++# . ++ ++This is the file that gets printed when the user runs "make help", ++starting just after the "help-starts-here" line. ++ ++help-starts-here ++ ++all ++ The usual default; builds everything but doesn't run the ++ tests. ++ ++check (or tests) ++ Runs the standard set of tests. ++ ++test ++ Runs one test. Use like this: ++ make test t=wcsmbs/test-wcsnlen ++ Note that this will rebuild the test if needed, but will not ++ rebuild what "make all" would have rebuilt. ++ ++-- ++Other useful hints: ++ ++builddir$ rm testroot.pristine/install.stamp ++ Forces the testroot to be reinstalled the next time you run ++ the testsuite (or just rm -rf testroot.pristine) ++ diff --git a/SOURCES/glibc-asflags.patch b/SOURCES/glibc-asflags.patch new file mode 100644 index 0000000..9bd733f --- /dev/null +++ b/SOURCES/glibc-asflags.patch @@ -0,0 +1,25 @@ +Author: Florian Weimer +Date: Wed Jul 4 16:16:57 2018 +0200 + + Makeconfig (ASFLAGS): Always append required assembler flags. + +Submitted upstream here: + + https://sourceware.org/ml/libc-alpha/2018-07/msg00077.html + +Otherwise, we lose essential flags such as -Wa,--noexecstack due to +the way += works in make due to the ASFLAGS command line override. + +diff --git a/Makeconfig b/Makeconfig +index b0b27f0113ac18b8..92e76d6200bbcd5b 100644 +--- a/Makeconfig ++++ b/Makeconfig +@@ -1047,7 +1047,7 @@ endif + ifndef ASFLAGS + ASFLAGS := $(filter -g% -fdebug-prefix-map=%,$(CFLAGS)) + endif +-ASFLAGS += -Werror=undef $(ASFLAGS-config) $(asflags-cpu) ++override ASFLAGS += -Werror=undef $(ASFLAGS-config) $(asflags-cpu) + + ifndef BUILD_CC + BUILD_CC = $(CC) diff --git a/SOURCES/glibc-bench-compare b/SOURCES/glibc-bench-compare new file mode 100755 index 0000000..84e3aba --- /dev/null +++ b/SOURCES/glibc-bench-compare @@ -0,0 +1,153 @@ +#!/usr/bin/bash +# This script can be invoked as follows: +# +# glibc-bench-compare [options] [BUILD] +# +# Options may be one of the following: +# +# -t The BUILD arguments are task ids and not a version-release string +# -a ARCH Do comparison for ARCH architecture +# +# If any of the above options are given, both BUILD arguments must be given. +# Otherwise, if only one BUILD is specified, then it is compared against the +# installed glibc. + +# Silence the pushd/popd messages +pushd() { + command pushd "$@" > /dev/null 2>&1 +} + +popd() { + command popd "$@" > /dev/null 2>&1 +} + +# Clean up any downloaded files before we exit +trap "rm -rf /tmp/glibc-bench-compare.$BASHPID.*" EXIT + +task=0 +arch=$(uname -i) +options=0 +path=0 +installed= + +# Look for any commandline options +while getopts ":tpa:" opt; do + case $opt in + p) + path=1 + ;; + t) + task=1 + options=1 + echo "Not implemented." + exit 1 + ;; + a) + arch=$OPTARG + options=1 + ;; + *) + ;; + esac +done + +# Done, now shift all option arguments out. +shift $((OPTIND-1)) + +if [ $# -gt 2 ] || [ $# -eq 0 ] || [ $# -lt 2 -a $options -eq 1 ]; then + echo "Usage: $0 [OPTIONS] [new]" + echo + echo "OPTIONS:" + echo -e "\t-t\tCompare two brew tasks" + echo -e "\t-a ARCH\tGet rpms for the ARCH architecture" + echo -e "\t-p\tCompare built rpms in two paths." + echo -e "\t\tThis minimally needs glibc, glibc-common and glibc-benchtests" + exit 1 +fi + +if [ -z $2 ]; then + new="$1" + old=$(rpm --queryformat "%{VERSION}-%{RELEASE}\n" -q glibc | head -1) + installed=$old +else + new="$2" + old="$1" +fi + +decompress_rpms() { + # We were given a path to the rpms. Figure out the version-release and + # decompress the rpms. + if [ -n $1 ]; then + vr=$(rpm --queryformat="%{VERSION}-%{RELEASE}" -qp $1/glibc-2*.rpm | head -1) + mkdir $vr && pushd $vr + fi + + for r in $1*.rpm; do + ( rpm2cpio $r | cpio -di ) > /dev/null + done + + if [ -n $1 ]; then + popd + echo $vr + fi +} + +# Get rpms for a build and decompress them +get_build() { + echo "Processing build $1" + mkdir $1 && pushd $1 + brew buildinfo "glibc-$1" | + sed -n -e "s|/mnt/koji\(.\+$arch.\+\)|http://kojipkgs.fedoraproject.org\1|p" | + while read url; do + echo "Downloading $url" + wget -q $url + done + decompress_rpms + + echo "Removing rpms" + rm -f $1/*.rpm + + popd +} + +# Run benchmarks for a build +run_bench() { + if [ -z $1 ]; then + make DETAILED=1 ver=$installed prefix= -f /usr/libexec/glibc-benchtests/bench.mk bench + else + make DETAILED=1 ver=$1 prefix=$PWD -f $1/usr/libexec/glibc-benchtests/bench.mk bench + fi +} + +# Get absolute paths if needed, since we will change into the working directory +# next. +if [ $path -eq 1 ]; then + old_path=$(realpath $old)/ + new_path=$(realpath $new)/ +fi + +tmpdir=$(mktemp -p /tmp -d glibc-bench-compare.$$.XXXX) +pushd $tmpdir + +# Get both builds. +if [ $path -eq 0 ]; then + if [ -z $installed ]; then + get_build $old + fi + get_build $new +else + old=$(decompress_rpms $old_path) + new=$(decompress_rpms $new_path) +fi + +# make bench for each of those. +if [ -z $installed ]; then + run_bench $old +else + run_bench +fi +run_bench $new + +# Now run the comparison script. +$old/usr/libexec/glibc-benchtests/compare_bench.py $old/usr/libexec/glibc-benchtests/benchout.schema.json \ + bench.$old.out bench.$new.out diff --git a/SOURCES/glibc-c-utf8-locale.patch b/SOURCES/glibc-c-utf8-locale.patch new file mode 100644 index 0000000..7215e15 --- /dev/null +++ b/SOURCES/glibc-c-utf8-locale.patch @@ -0,0 +1,286 @@ +Short description: Add C.UTF-8 support. +Author(s): Fedora glibc team +Origin: PATCH +Upstream status: not-submitted + +This patch needs to upstream as part of Carlos O'Donell +'s work on enabling upstream C.UTF-8 support. This +work is currently blocked on cleaning up the test results to prove that +full code-point sorting is working as intended. + +Note that this patch does not provide full code-point sorting as +expected. + +This patch needs to upstream as soon as possible since it would be nice +to have this in F29 and fixed. + +From 2eda7b462b415105f5a05c1323372d4e39d46439 Mon Sep 17 00:00:00 2001 +From: Mike FABIAN +Date: Mon, 10 Aug 2015 15:58:12 +0200 +Subject: [PATCH] Add a C.UTF-8 locale + +--- + localedata/SUPPORTED | 1 + + localedata/locales/C | 238 +++++++++++++++++++++++++++++++++++++++++++++++++++ + 2 files changed, 239 insertions(+) + create mode 100644 localedata/locales/C + +diff --git a/localedata/SUPPORTED b/localedata/SUPPORTED +index 8ca023e..2a78391 100644 +--- a/localedata/SUPPORTED ++++ b/localedata/SUPPORTED +@@ -1,6 +1,7 @@ + # This file names the currently supported and somewhat tested locales. + # If you have any additions please file a glibc bug report. + SUPPORTED-LOCALES=\ ++C.UTF-8/UTF-8 \ + aa_DJ.UTF-8/UTF-8 \ + aa_DJ/ISO-8859-1 \ + aa_ER/UTF-8 \ +diff --git a/localedata/locales/C b/localedata/locales/C +new file mode 100644 +index 0000000..fdf460e +--- /dev/null ++++ b/localedata/locales/C +@@ -0,0 +1,238 @@ ++escape_char / ++comment_char % ++% Locale for C locale in UTF-8 ++ ++LC_IDENTIFICATION ++title "C locale" ++source "" ++address "" ++contact "" ++email "mfabian@redhat.com" ++tel "" ++fax "" ++language "C" ++territory "" ++revision "1.0" ++date "2015-08-10" ++% ++category "i18n:2012";LC_IDENTIFICATION ++category "i18n:2012";LC_CTYPE ++category "i18n:2012";LC_COLLATE ++category "i18n:2012";LC_TIME ++category "i18n:2012";LC_NUMERIC ++category "i18n:2012";LC_MONETARY ++category "i18n:2012";LC_MESSAGES ++category "i18n:2012";LC_PAPER ++category "i18n:2012";LC_NAME ++category "i18n:2012";LC_ADDRESS ++category "i18n:2012";LC_TELEPHONE ++category "i18n:2012";LC_MEASUREMENT ++END LC_IDENTIFICATION ++ ++LC_CTYPE ++copy "i18n" ++ ++translit_start ++include "translit_combining";"" ++translit_end ++ ++END LC_CTYPE ++ ++LC_COLLATE ++order_start forward ++ ++.. ++ ++ ++.. ++ ++ ++.. ++ ++ ++.. ++ ++ ++.. ++ ++ ++.. ++ ++UNDEFINED ++order_end ++END LC_COLLATE ++ ++LC_MONETARY ++% This is the 14652 i18n fdcc-set definition for ++% the LC_MONETARY category ++% (except for the int_curr_symbol and currency_symbol, they are empty in ++% the 14652 i18n fdcc-set definition and also empty in ++% glibc/locale/C-monetary.c. But localedef complains in that case). ++% ++% Using "USD" for int_curr_symbol. But maybe "XXX" would be better? ++% XXX is "No currency" (https://en.wikipedia.org/wiki/ISO_4217) ++int_curr_symbol "" ++% Using "$" for currency_symbol. But maybe would be better? ++% U+00A4 is the "generic currency symbol" ++% (https://en.wikipedia.org/wiki/Currency_sign_%28typography%29) ++currency_symbol "" ++mon_decimal_point "" ++mon_thousands_sep "" ++mon_grouping -1 ++positive_sign "" ++negative_sign "" ++int_frac_digits -1 ++frac_digits -1 ++p_cs_precedes -1 ++int_p_sep_by_space -1 ++p_sep_by_space -1 ++n_cs_precedes -1 ++int_n_sep_by_space -1 ++n_sep_by_space -1 ++p_sign_posn -1 ++n_sign_posn -1 ++% ++END LC_MONETARY ++ ++LC_NUMERIC ++% This is the POSIX Locale definition for ++% the LC_NUMERIC category. ++% ++decimal_point "" ++thousands_sep "" ++grouping -1 ++END LC_NUMERIC ++ ++LC_TIME ++% This is the POSIX Locale definition for ++% the LC_TIME category. ++% ++% Abbreviated weekday names (%a) ++abday "";"";/ ++ "";"";/ ++ "";"";/ ++ "" ++ ++% Full weekday names (%A) ++day "";/ ++ "";/ ++ "";/ ++ "";/ ++ "";/ ++ "";/ ++ "" ++ ++% Abbreviated month names (%b) ++abmon "";"";/ ++ "";"";/ ++ "";"";/ ++ "";"";/ ++ "";"";/ ++ "";"" ++ ++% Full month names (%B) ++mon "";/ ++ "";/ ++ "";/ ++ "";/ ++ "";/ ++ "";/ ++ "";/ ++ "";/ ++ "";/ ++ "";/ ++ "";/ ++ "" ++ ++% Week description, consists of three fields: ++% 1. Number of days in a week. ++% 2. Gregorian date that is a first weekday (19971130 for Sunday, 19971201 for Monday). ++% 3. The weekday number to be contained in the first week of the year. ++% ++% ISO 8601 conforming applications should use the values 7, 19971201 (a ++% Monday), and 4 (Thursday), respectively. ++week 7;19971201;4 ++first_weekday 1 ++first_workday 1 ++ ++% Appropriate date and time representation (%c) ++% "%a %b %e %H:%M:%S %Y" ++d_t_fmt "" ++ ++% Appropriate date representation (%x) ++% "%m/%d/%y" ++d_fmt "" ++ ++% Appropriate time representation (%X) ++% "%H:%M:%S" ++t_fmt "" ++ ++% Appropriate AM/PM time representation (%r) ++% "%I:%M:%S %p" ++t_fmt_ampm "" ++ ++% Equivalent of AM/PM (%p) "AM"/"PM" ++% ++am_pm "";"" ++ ++% Appropriate date representation (date(1)) "%a %b %e %H:%M:%S %Z %Y" ++date_fmt "" ++END LC_TIME ++ ++LC_MESSAGES ++% This is the POSIX Locale definition for ++% the LC_NUMERIC category. ++% ++yesexpr "" ++noexpr "" ++yesstr "" ++nostr "" ++END LC_MESSAGES ++ ++LC_PAPER ++% This is the ISO/IEC 14652 "i18n" definition for ++% the LC_PAPER category. ++% (A4 paper, this is also used in the built in C/POSIX ++% locale in glibc/locale/C-paper.c) ++height 297 ++width 210 ++END LC_PAPER ++ ++LC_NAME ++% This is the ISO/IEC 14652 "i18n" definition for ++% the LC_NAME category. ++% "%p%t%g%t%m%t%f" ++% (also used in the built in C/POSIX locale in glibc/locale/C-name.c) ++name_fmt "/ ++" ++END LC_NAME ++ ++LC_ADDRESS ++% This is the ISO/IEC 14652 "i18n" definition for ++% the LC_ADDRESS category. ++% "%a%N%f%N%d%N%b%N%s %h %e %r%N%C-%z %T%N%c%N" ++% (also used in the built in C/POSIX locale in glibc/locale/C-address.c) ++postal_fmt "/ ++/ ++/ ++/ ++" ++END LC_ADDRESS ++ ++LC_TELEPHONE ++% This is the ISO/IEC 14652 "i18n" definition for ++% the LC_TELEPHONE category. ++% "+%c %a %l" ++tel_int_fmt "/ ++" ++% (also used in the built in C/POSIX locale in glibc/locale/C-telephone.c) ++END LC_TELEPHONE ++ ++LC_MEASUREMENT ++% This is the ISO/IEC 14652 "i18n" definition for ++% the LC_MEASUREMENT category. ++% (same as in the built in C/POSIX locale in glibc/locale/C-measurement.c) ++%metric ++measurement 1 ++END LC_MEASUREMENT ++ +-- +2.4.3 + diff --git a/SOURCES/glibc-cs-path.patch b/SOURCES/glibc-cs-path.patch new file mode 100644 index 0000000..aafa741 --- /dev/null +++ b/SOURCES/glibc-cs-path.patch @@ -0,0 +1,15 @@ +Short description: Adjust CS_PATH return value. +Author(s): Fedora glibc team +Origin: PATCH +Upstream status: not-needed + +In Fedora we should return only /usr/bin because /bin is just a symlink +to /usr/bin after MoveToUsr transition (which glibc has not really +completed). + +diff -pruN a/sysdeps/unix/confstr.h b/sysdeps/unix/confstr.h +--- a/sysdeps/unix/confstr.h 2012-12-25 08:32:13.000000000 +0530 ++++ b/sysdeps/unix/confstr.h 2014-09-05 20:02:55.698275219 +0530 +@@ -1 +1 @@ +-#define CS_PATH "/bin:/usr/bin" ++#define CS_PATH "/usr/bin" diff --git a/SOURCES/glibc-fedora-__libc_multiple_libcs.patch b/SOURCES/glibc-fedora-__libc_multiple_libcs.patch new file mode 100644 index 0000000..256ef20 --- /dev/null +++ b/SOURCES/glibc-fedora-__libc_multiple_libcs.patch @@ -0,0 +1,91 @@ +Short description: Cleanup use of _dl_starting_up. +Author(s): Fedora glibc team +Origin: PATCH +Upstream status: https://sourceware.org/ml/libc-alpha/2014-02/msg00589.html + +Upstream discussions: +https://sourceware.org/ml/libc-alpha/2014-02/msg00580.html + +Based on the following commit: +~~~ +From 16552c01a66633c9e412984d9d92616bd4e5303c Mon Sep 17 00:00:00 2001 +From: Andreas Schwab +Date: Fri, 11 Jun 2010 11:04:11 +0200 +Subject: [PATCH] Properly set __libc_multiple_libcs + + * elf/rtld.c (_dl_starting_up): Always define. + (dl_main): Always set _dl_starting_up. + * elf/dl-support.c (_dl_starting_up): Always define. + * elf/dl-init.c (_dl_init): Always clear _dl_starting_up. + +--- +ChangeLog | 7 +++++++ +elf/dl-init.c | 4 ---- +elf/dl-support.c | 2 -- +elf/rtld.c | 4 ---- +4 files changed, 7 insertions(+), 10 deletions(-) +~~~ + +This patch needs to go upstream to get cleaned up, but has always involed +analysis of the GNU/Hurd parts of the change and that stalled out, but +perhaps with build-many-glibcs we can now test these changes more easily. + +Index: b/elf/dl-init.c +=================================================================== +--- a/elf/dl-init.c ++++ b/elf/dl-init.c +@@ -119,8 +119,6 @@ _dl_init (struct link_map *main_map, int + while (i-- > 0) + call_init (main_map->l_initfini[i], argc, argv, env); + +-#ifndef HAVE_INLINED_SYSCALLS + /* Finished starting up. */ + _dl_starting_up = 0; +-#endif + } +Index: b/elf/dl-support.c +=================================================================== +--- a/elf/dl-support.c ++++ b/elf/dl-support.c +@@ -117,10 +117,8 @@ struct r_scope_elem _dl_initial_searchli + .r_nlist = 1, + }; + +-#ifndef HAVE_INLINED_SYSCALLS + /* Nonzero during startup. */ + int _dl_starting_up = 1; +-#endif + + /* Random data provided by the kernel. */ + void *_dl_random; +Index: b/elf/rtld.c +=================================================================== +--- a/elf/rtld.c ++++ b/elf/rtld.c +@@ -214,7 +214,6 @@ audit_list_iter_next (struct audit_list_ + return iter->previous->name; + } + +-#ifndef HAVE_INLINED_SYSCALLS + /* Set nonzero during loading and initialization of executable and + libraries, cleared before the executable's entry point runs. This + must not be initialized to nonzero, because the unused dynamic +@@ -224,7 +223,6 @@ audit_list_iter_next (struct audit_list_ + never be called. */ + int _dl_starting_up = 0; + rtld_hidden_def (_dl_starting_up) +-#endif + + /* This is the structure which defines all variables global to ld.so + (except those which cannot be added for some reason). */ +@@ -898,10 +896,8 @@ dl_main (const ElfW(Phdr) *phdr, + /* Process the environment variable which control the behaviour. */ + process_envvars (&mode); + +-#ifndef HAVE_INLINED_SYSCALLS + /* Set up a flag which tells we are just starting. */ + _dl_starting_up = 1; +-#endif + + if (*user_entry == (ElfW(Addr)) ENTRY_POINT) + { diff --git a/SOURCES/glibc-fedora-linux-tcsetattr.patch b/SOURCES/glibc-fedora-linux-tcsetattr.patch new file mode 100644 index 0000000..3ae7e27 --- /dev/null +++ b/SOURCES/glibc-fedora-linux-tcsetattr.patch @@ -0,0 +1,61 @@ +Short description: Fedora-specific workaround for kernel pty bug. +Author(s): Fedora glibc team +Origin: PATCH +Upstream status: not-submitted + +This is a Fedora-specific workaround for a kernel bug where calling +ioctl on a pty will silently ignore the invalid c_cflag. The +workaround is to use TCGETS to verify the setting matches. This is +not upstream and needs to either be removed or submitted upstream +after analysis. + +Index: b/sysdeps/unix/sysv/linux/tcsetattr.c +=================================================================== +--- a/sysdeps/unix/sysv/linux/tcsetattr.c ++++ b/sysdeps/unix/sysv/linux/tcsetattr.c +@@ -45,6 +45,7 @@ __tcsetattr (int fd, int optional_action + { + struct __kernel_termios k_termios; + unsigned long int cmd; ++ int retval; + + switch (optional_actions) + { +@@ -75,7 +76,36 @@ __tcsetattr (int fd, int optional_action + memcpy (&k_termios.c_cc[0], &termios_p->c_cc[0], + __KERNEL_NCCS * sizeof (cc_t)); + +- return INLINE_SYSCALL (ioctl, 3, fd, cmd, &k_termios); ++ retval = INLINE_SYSCALL (ioctl, 3, fd, cmd, &k_termios); ++ ++ if (retval == 0 && cmd == TCSETS) ++ { ++ /* The Linux kernel has a bug which silently ignore the invalid ++ c_cflag on pty. We have to check it here. */ ++ int save = errno; ++ retval = INLINE_SYSCALL (ioctl, 3, fd, TCGETS, &k_termios); ++ if (retval) ++ { ++ /* We cannot verify if the setting is ok. We don't return ++ an error (?). */ ++ __set_errno (save); ++ retval = 0; ++ } ++ else if ((termios_p->c_cflag & (PARENB | CREAD)) ++ != (k_termios.c_cflag & (PARENB | CREAD)) ++ || ((termios_p->c_cflag & CSIZE) ++ && ((termios_p->c_cflag & CSIZE) ++ != (k_termios.c_cflag & CSIZE)))) ++ { ++ /* It looks like the Linux kernel silently changed the ++ PARENB/CREAD/CSIZE bits in c_cflag. Report it as an ++ error. */ ++ __set_errno (EINVAL); ++ retval = -1; ++ } ++ } ++ ++ return retval; + } + weak_alias (__tcsetattr, tcsetattr) + libc_hidden_def (tcsetattr) diff --git a/SOURCES/glibc-fedora-localedata-rh61908.patch b/SOURCES/glibc-fedora-localedata-rh61908.patch new file mode 100644 index 0000000..518253d --- /dev/null +++ b/SOURCES/glibc-fedora-localedata-rh61908.patch @@ -0,0 +1,49 @@ +Short description: Add 4 ISO-8859-15 locales to SUPPORTED for Euro symbol. +Author(s): Fedora glibc team +Origin: PATCH +Bug-RHEL: #61908 +Upstream status: not-needed + +Very early RHL 7.3 requirement to add these locales so users can +get access to Euro symbol. We should review this bug and decide if +the UTF-8 locales are now serving the same purpose and drop the +additional locales. + +* Tue Mar 26 2002 Jakub Jelinek 2.2.5-28 +- add a couple of .ISO-8859-15 locales (#61908) + +diff -Nrup a/localedata/SUPPORTED b/localedata/SUPPORTED +--- a/localedata/SUPPORTED 2012-11-25 12:59:31.000000000 -0700 ++++ b/localedata/SUPPORTED 2012-11-26 12:58:43.298223018 -0700 +@@ -89,6 +89,7 @@ cy_GB.UTF-8/UTF-8 \ + cy_GB/ISO-8859-14 \ + da_DK.UTF-8/UTF-8 \ + da_DK/ISO-8859-1 \ ++da_DK.ISO-8859-15/ISO-8859-15 \ + de_AT.UTF-8/UTF-8 \ + de_AT/ISO-8859-1 \ + de_AT@euro/ISO-8859-15 \ +@@ -121,6 +122,7 @@ en_DK.UTF-8/UTF-8 \ + en_DK/ISO-8859-1 \ + en_GB.UTF-8/UTF-8 \ + en_GB/ISO-8859-1 \ ++en_GB.ISO-8859-15/ISO-8859-15 \ + en_HK.UTF-8/UTF-8 \ + en_HK/ISO-8859-1 \ + en_IE.UTF-8/UTF-8 \ +@@ -136,6 +138,7 @@ en_SG.UTF-8/UTF-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_ZA.UTF-8/UTF-8 \ + en_ZA/ISO-8859-1 \ + en_ZM/UTF-8 \ +@@ -385,6 +388,7 @@ sv_FI/ISO-8859-1 \ + sv_FI@euro/ISO-8859-15 \ + sv_SE.UTF-8/UTF-8 \ + sv_SE/ISO-8859-1 \ ++sv_SE.ISO-8859-15/ISO-8859-15 \ + sw_KE/UTF-8 \ + sw_TZ/UTF-8 \ + szl_PL/UTF-8 \ diff --git a/SOURCES/glibc-fedora-localedef.patch b/SOURCES/glibc-fedora-localedef.patch new file mode 100644 index 0000000..787951f --- /dev/null +++ b/SOURCES/glibc-fedora-localedef.patch @@ -0,0 +1,21 @@ +Short description: Fedora-specific glibc install locale changes. +Author(s): Fedora glibc team +Origin: PATCH +Upstream status: not-needed + +The Fedora glibc build and install does not need the normal install +behaviour which updates the locale archive. The Fedora install phase +in the spec file of the rpm will handle this manually. + +diff --git a/localedata/Makefile b/localedata/Makefile +index a5f3c92d58954dfc..56719c7c714aa0f1 100644 +--- a/localedata/Makefile ++++ b/localedata/Makefile +@@ -218,6 +218,7 @@ $(INSTALL-SUPPORTED-LOCALES): install-locales-dir + echo -n '...'; \ + input=`echo $$locale | sed 's/\([^.]*\)[^@]*\(.*\)/\1\2/'`; \ + $(LOCALEDEF) $$flags --alias-file=../intl/locale.alias \ ++ --no-archive \ + -i locales/$$input -f charmaps/$$charset \ + $(addprefix --prefix=,$(install_root)) $$locale \ + && echo ' done'; \ diff --git a/SOURCES/glibc-fedora-locarchive.patch b/SOURCES/glibc-fedora-locarchive.patch new file mode 100644 index 0000000..299b0f0 --- /dev/null +++ b/SOURCES/glibc-fedora-locarchive.patch @@ -0,0 +1,46 @@ +Short description: Allow access to internal locale archive functions. +Author(s): Fedora glibc team +Origin: PATCH +Upstream status: not-needed + +This is a part of commit glibc-2.3.3-1492-ga891c7b, +needed for fedora/build-locale-archive.c only. + +2007-04-16 Jakub Jelinek + + * locale/programs/locarchive.c (add_alias, insert_name): Remove static. + +diff -Nrup a/locale/programs/locarchive.c b/locale/programs/locarchive.c +--- a/locale/programs/locarchive.c 2012-06-05 07:42:49.000000000 -0600 ++++ b/locale/programs/locarchive.c 2012-06-07 12:15:21.585319540 -0600 +@@ -252,9 +252,9 @@ oldlocrecentcmp (const void *a, const vo + /* forward decls for below */ + static uint32_t add_locale (struct locarhandle *ah, const char *name, + locale_data_t data, bool replace); +-static void add_alias (struct locarhandle *ah, const char *alias, +- bool replace, const char *oldname, +- uint32_t *locrec_offset_p); ++void add_alias (struct locarhandle *ah, const char *alias, ++ bool replace, const char *oldname, ++ uint32_t *locrec_offset_p); + + + static bool +@@ -635,7 +635,7 @@ close_archive (struct locarhandle *ah) + #include "../../intl/explodename.c" + #include "../../intl/l10nflist.c" + +-static struct namehashent * ++struct namehashent * + insert_name (struct locarhandle *ah, + const char *name, size_t name_len, bool replace) + { +@@ -693,7 +693,7 @@ insert_name (struct locarhandle *ah, + return &namehashtab[idx]; + } + +-static void ++void + add_alias (struct locarhandle *ah, const char *alias, bool replace, + const char *oldname, uint32_t *locrec_offset_p) + { diff --git a/SOURCES/glibc-fedora-manual-dircategory.patch b/SOURCES/glibc-fedora-manual-dircategory.patch new file mode 100644 index 0000000..11c2656 --- /dev/null +++ b/SOURCES/glibc-fedora-manual-dircategory.patch @@ -0,0 +1,31 @@ +Short description: Place glibc info into "Libraries" category. +Author(s): Fedora glibc team +Origin: PATCH +Upstream status: not-needed + +The category names for libraries is completely random including +"Libraries", "GNU Libraries", "GNU libraries", and "Software libraries." +In the GNU info manual the "Software libraries" category is given as an +example, but really we need to standardize on a category for upstream. +I suggest we drop this change after some upstream discussion. + +From 4820b9175535e13df79ce816106016040014916e Mon Sep 17 00:00:00 2001 +From: Jakub Jelinek +Date: Fri, 3 Nov 2006 16:31:21 +0000 +Subject: [PATCH] Change @dircategory. + +--- + manual/libc.texinfo | 2 +- + 1 files changed, 1 insertions(+), 1 deletions(-) + +--- a/manual/libc.texinfo ++++ b/manual/libc.texinfo +@@ -7,7 +7,7 @@ + @include macros.texi + + @comment Tell install-info what to do. +-@dircategory Software libraries ++@dircategory Libraries + @direntry + * Libc: (libc). C library. + @end direntry diff --git a/SOURCES/glibc-fedora-nis-rh188246.patch b/SOURCES/glibc-fedora-nis-rh188246.patch new file mode 100644 index 0000000..5ec2237 --- /dev/null +++ b/SOURCES/glibc-fedora-nis-rh188246.patch @@ -0,0 +1,31 @@ +Short description: Fedora-specific enabling batch read in NSS. +Author(s): Fedora glibc team +Origin: PATCH +Bug-RHEL: #188246 +Upstream status: not-submitted + +Enable batch read in NSS. It's not clear if this is always a win or +just a win for NIS+, this needs to be analyzed and sent upstream or +removed. + +From baba5d9461d4e8a581ac26fe4412ad783ffc73e7 Mon Sep 17 00:00:00 2001 +From: Jakub Jelinek +Date: Mon, 1 May 2006 08:02:53 +0000 +Subject: [PATCH] Enable SETENT_BATCH_READ nis/nss option by default + +* Mon May 1 2006 Jakub Jelinek 2.4.90-4 +- SETENT_BATCH_READ /etc/default/nss option for speeding up + some usages of NIS+ (#188246) + +diff --git a/nis/nss b/nis/nss +--- a/nis/nss ++++ b/nis/nss +@@ -25,7 +25,7 @@ + # memory with every getXXent() call. Otherwise each getXXent() call + # might result into a network communication with the server to get + # the next entry. +-#SETENT_BATCH_READ=TRUE ++SETENT_BATCH_READ=TRUE + # + # ADJUNCT_AS_SHADOW + # If set to TRUE, the passwd routines in the NIS NSS module will not diff --git a/SOURCES/glibc-fedora-nscd.patch b/SOURCES/glibc-fedora-nscd.patch new file mode 100644 index 0000000..6f8f764 --- /dev/null +++ b/SOURCES/glibc-fedora-nscd.patch @@ -0,0 +1,20 @@ +Short description: NSCD must use nscd user. +Author(s): Fedora glibc team +Origin: PATCH +Upstream status: not-needed + +Fedora-specific configuration adjustment to introduce the nscd user. +(Upstream does not assume this user exists.) + +diff -Nrup a/nscd/nscd.conf b/nscd/nscd.conf +--- a/nscd/nscd.conf 2012-06-05 07:42:49.000000000 -0600 ++++ b/nscd/nscd.conf 2012-06-07 12:15:21.818318670 -0600 +@@ -33,7 +33,7 @@ + # logfile /var/log/nscd.log + # threads 4 + # max-threads 32 +-# server-user nobody ++ server-user nscd + # stat-user somebody + debug-level 0 + # reload-count 5 diff --git a/SOURCES/glibc-fedora-streams-rh436349.patch b/SOURCES/glibc-fedora-streams-rh436349.patch new file mode 100644 index 0000000..0d8f7d9 --- /dev/null +++ b/SOURCES/glibc-fedora-streams-rh436349.patch @@ -0,0 +1,38 @@ +Short description: Do not define _XOPEN_STREAMS. +Author(s): Fedora glibc team +Origin: PATCH +Bug-Fedora: #436349 +Upstream status: not-submitted + +This patch should go upstream. Not defining _XOPEN_STREAMS is the +same as setting it to -1 for POSIX conformance. The headers setting +needs to be reviewed indepedently. + +This is part of commit glibc-2.3.3-1564-gd0b6ac6 + +* Fri Mar 14 2008 Jakub Jelinek 2.7.90-11 +- remove , define _XOPEN_STREAMS -1 (#436349) + +diff -Nrup a/nptl/sysdeps/unix/sysv/linux/bits/posix_opt.h b/nptl/sysdeps/unix/sysv/linux/bits/posix_opt.h +--- a/sysdeps/unix/sysv/linux/bits/posix_opt.h 2012-06-05 07:42:49.000000000 -0600 ++++ b/sysdeps/unix/sysv/linux/bits/posix_opt.h 2012-06-07 12:15:21.817318674 -0600 +@@ -188,4 +188,7 @@ + /* Typed memory objects are not available. */ + #define _POSIX_TYPED_MEMORY_OBJECTS -1 + ++/* Streams are not available. */ ++#define _XOPEN_STREAMS -1 ++ + #endif /* bits/posix_opt.h */ +diff -Nrup a/streams/Makefile b/streams/Makefile +--- a/streams/Makefile 2012-06-05 07:42:49.000000000 -0600 ++++ b/streams/Makefile 2012-06-07 12:15:21.824318649 -0600 +@@ -20,7 +20,7 @@ + + include ../Makeconfig + +-headers = stropts.h sys/stropts.h bits/stropts.h bits/xtitypes.h ++#headers = stropts.h sys/stropts.h bits/stropts.h bits/xtitypes.h + routines = isastream getmsg getpmsg putmsg putpmsg fattach fdetach + + include ../Rules diff --git a/SOURCES/glibc-nscd-sysconfig.patch b/SOURCES/glibc-nscd-sysconfig.patch new file mode 100644 index 0000000..03dee9e --- /dev/null +++ b/SOURCES/glibc-nscd-sysconfig.patch @@ -0,0 +1,21 @@ +Short description: Provide options to nscd startup. +Author(s): Fedora glibc team +Origin: PATCH +Upstream status: not-needed + +Fedora-specific nscd startup configuration file. + +diff --git a/nscd/nscd.service b/nscd/nscd.service +index b7428a3..19ba185 100644 +--- a/nscd/nscd.service ++++ b/nscd/nscd.service +@@ -5,7 +5,8 @@ Description=Name Service Cache Daemon + + [Service] + Type=forking +-ExecStart=/usr/sbin/nscd ++EnvironmentFile=-/etc/sysconfig/nscd ++ExecStart=/usr/sbin/nscd $NSCD_OPTIONS + ExecStop=/usr/sbin/nscd --shutdown + ExecReload=/usr/sbin/nscd -i passwd + ExecReload=/usr/sbin/nscd -i group diff --git a/SOURCES/glibc-python3.patch b/SOURCES/glibc-python3.patch new file mode 100644 index 0000000..a9a7a4f --- /dev/null +++ b/SOURCES/glibc-python3.patch @@ -0,0 +1,40 @@ +Use python3 for installed executable python scripts. + +Fedora is a Python3-only distribution: +https://fedoraproject.org/wiki/FinalizingFedoraSwitchtoPython3 + +This fixes build failures where builders may strictly enforce only +python3 during a transitional phase. + +Author: Carlos O'Donell + +diff --git a/benchtests/scripts/compare_bench.py b/benchtests/scripts/compare_bench.py +index ea25f778c09bba9d..b53beb3c6e32c3cf 100755 +--- a/benchtests/scripts/compare_bench.py ++++ b/benchtests/scripts/compare_bench.py +@@ -1,4 +1,4 @@ +-#!/usr/bin/python ++#!/usr/bin/python3 + # Copyright (C) 2015-2018 Free Software Foundation, Inc. + # This file is part of the GNU C Library. + # +diff --git a/benchtests/scripts/import_bench.py b/benchtests/scripts/import_bench.py +index 602b3f954d4801a6..76bf1528a5418748 100644 +--- a/benchtests/scripts/import_bench.py ++++ b/benchtests/scripts/import_bench.py +@@ -1,4 +1,4 @@ +-#!/usr/bin/python ++#!/usr/bin/python3 + # Copyright (C) 2015-2018 Free Software Foundation, Inc. + # This file is part of the GNU C Library. + # +diff --git a/benchtests/scripts/validate_benchout.py b/benchtests/scripts/validate_benchout.py +index 6147f05bec3a4844..9a5c7947ee4ed7e9 100755 +--- a/benchtests/scripts/validate_benchout.py ++++ b/benchtests/scripts/validate_benchout.py +@@ -1,4 +1,4 @@ +-#!/usr/bin/python ++#!/usr/bin/python3 + # Copyright (C) 2014-2018 Free Software Foundation, Inc. + # This file is part of the GNU C Library. + # diff --git a/SOURCES/glibc-rh1070416.patch b/SOURCES/glibc-rh1070416.patch new file mode 100644 index 0000000..0975e0f --- /dev/null +++ b/SOURCES/glibc-rh1070416.patch @@ -0,0 +1,38 @@ +Short description: Add syslog.target dependency. +Author(s): Fedora glibc team +Origin: PATCH +Bug-Fedora: #1070416 +Upstream status: not-needed + +Fedora-specific changes to the nscd.service file. +See also: glibc-nscd-sysconfig.patch. + +--- a/nscd/nscd.service ++++ b/nscd/nscd.service +@@ -2,6 +2,7 @@ + + [Unit] + Description=Name Service Cache Daemon ++After=syslog.target + + [Service] + Type=forking +@@ -17,3 +18,4 @@ + + [Install] + WantedBy=multi-user.target ++Also=nscd.socket +diff --git a/nscd/nscd.socket b/nscd/nscd.socket +new file mode 100644 +index 0000000..7e512d5 +--- /dev/null ++++ b/nscd/nscd.socket +@@ -0,0 +1,8 @@ ++[Unit] ++Description=Name Service Cache Daemon Socket ++ ++[Socket] ++ListenDatagram=/var/run/nscd/socket ++ ++[Install] ++WantedBy=sockets.target diff --git a/SOURCES/glibc-rh1159809-1.patch b/SOURCES/glibc-rh1159809-1.patch new file mode 100644 index 0000000..fb15043 --- /dev/null +++ b/SOURCES/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/SOURCES/glibc-rh1159809-10.patch b/SOURCES/glibc-rh1159809-10.patch new file mode 100644 index 0000000..4713f8a --- /dev/null +++ b/SOURCES/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/SOURCES/glibc-rh1159809-11.patch b/SOURCES/glibc-rh1159809-11.patch new file mode 100644 index 0000000..fc4a7e1 --- /dev/null +++ b/SOURCES/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/SOURCES/glibc-rh1159809-2.patch b/SOURCES/glibc-rh1159809-2.patch new file mode 100644 index 0000000..1c415d4 --- /dev/null +++ b/SOURCES/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/SOURCES/glibc-rh1159809-3.patch b/SOURCES/glibc-rh1159809-3.patch new file mode 100644 index 0000000..fa39efe --- /dev/null +++ b/SOURCES/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/SOURCES/glibc-rh1159809-4.patch b/SOURCES/glibc-rh1159809-4.patch new file mode 100644 index 0000000..e47b934 --- /dev/null +++ b/SOURCES/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/SOURCES/glibc-rh1159809-5.patch b/SOURCES/glibc-rh1159809-5.patch new file mode 100644 index 0000000..dcd7703 --- /dev/null +++ b/SOURCES/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/SOURCES/glibc-rh1159809-6.patch b/SOURCES/glibc-rh1159809-6.patch new file mode 100644 index 0000000..df6d0e2 --- /dev/null +++ b/SOURCES/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/SOURCES/glibc-rh1159809-7.patch b/SOURCES/glibc-rh1159809-7.patch new file mode 100644 index 0000000..c396a5c --- /dev/null +++ b/SOURCES/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/SOURCES/glibc-rh1159809-8.patch b/SOURCES/glibc-rh1159809-8.patch new file mode 100644 index 0000000..4c76782 --- /dev/null +++ b/SOURCES/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/SOURCES/glibc-rh1159809-9.patch b/SOURCES/glibc-rh1159809-9.patch new file mode 100644 index 0000000..b621c3e --- /dev/null +++ b/SOURCES/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/SOURCES/glibc-rh1361965.patch b/SOURCES/glibc-rh1361965.patch new file mode 100644 index 0000000..cfbf09c --- /dev/null +++ b/SOURCES/glibc-rh1361965.patch @@ -0,0 +1,49 @@ +Backport of this Fedora Rawhide commit but split out into a distinct +patch. + +commit 72195d44855ab96875f117acb75c37f98dcb26a9 +Author: Carlos O'Donell +Date: Thu Jun 6 23:58:21 2019 -0400 + + locale: Fix C.UTF-8 ranges. + + The ellipsis range support only allows or as + valid unicode code points, otherwise it treats it as a symbol and + since we don't define the symbol the entire range is unused. + +diff --git a/localedata/locales/C b/localedata/locales/C +index b2c2d1dc417cde69..30d9563213b8cb0f 100644 +--- a/localedata/locales/C ++++ b/localedata/locales/C +@@ -43,21 +43,21 @@ order_start forward + + .. + +- ++ + .. +- +- ++ ++ + .. +- +- ++ ++ + .. +- +- ++ ++ + .. +- +- ++ ++ + .. +- ++ + UNDEFINED + order_end + END LC_COLLATE diff --git a/SOURCES/glibc-rh1410154-1.patch b/SOURCES/glibc-rh1410154-1.patch new file mode 100644 index 0000000..6acd167 --- /dev/null +++ b/SOURCES/glibc-rh1410154-1.patch @@ -0,0 +1,185 @@ +commit 96cd0558bcd69481ccc42e1b392f0c0b36fce2b0 +Author: Florian Weimer +Date: Wed Nov 28 19:59:45 2018 +0100 + + support: Add signal support to support_capture_subprocess_check + + Signal zero does not terminate a process, so it is safe to use negative + values for signal numbers. + + Adjust libio/tst-vtables-common.c to use this new functionality, + instead of determining the termination status for a signal indirectly. + +diff --git a/libio/tst-vtables-common.c b/libio/tst-vtables-common.c +index 5e3101206919fa1b..85e246cd1131f8e8 100644 +--- a/libio/tst-vtables-common.c ++++ b/libio/tst-vtables-common.c +@@ -380,21 +380,6 @@ without_compatibility_fflush (void *closure) + _exit (1); + } + +-/* Exit status after abnormal termination. */ +-static int termination_status; +- +-static void +-init_termination_status (void) +-{ +- pid_t pid = xfork (); +- if (pid == 0) +- abort (); +- xwaitpid (pid, &termination_status, 0); +- +- TEST_VERIFY (WIFSIGNALED (termination_status)); +- TEST_COMPARE (WTERMSIG (termination_status), SIGABRT); +-} +- + static void + check_for_termination (const char *name, void (*callback) (void *)) + { +@@ -404,7 +389,7 @@ check_for_termination (const char *name, void (*callback) (void *)) + shared->calls = 0; + struct support_capture_subprocess proc + = support_capture_subprocess (callback, NULL); +- support_capture_subprocess_check (&proc, name, termination_status, ++ support_capture_subprocess_check (&proc, name, -SIGABRT, + sc_allow_stderr); + const char *message + = "Fatal error: glibc detected an invalid stdio handle\n"; +@@ -491,7 +476,6 @@ run_tests (bool initially_disabled) + + shared = support_shared_allocate (sizeof (*shared)); + shared->initially_disabled = initially_disabled; +- init_termination_status (); + + if (initially_disabled) + { +diff --git a/support/capture_subprocess.h b/support/capture_subprocess.h +index d5eac84d09ae325f..2d2384e73df0d2d0 100644 +--- a/support/capture_subprocess.h ++++ b/support/capture_subprocess.h +@@ -55,13 +55,16 @@ enum support_capture_allow + sc_allow_stderr = 0x04, + }; + +-/* Check that the subprocess exited with STATUS and that only the +- allowed outputs happened. ALLOWED is a combination of +- support_capture_allow flags. Report errors under the CONTEXT +- message. */ ++/* Check that the subprocess exited and that only the allowed outputs ++ happened. If STATUS_OR_SIGNAL is nonnegative, it is the expected ++ (decoded) exit status of the process, as returned by WEXITSTATUS. ++ If STATUS_OR_SIGNAL is negative, -STATUS_OR_SIGNAL is the expected ++ termination signal, as returned by WTERMSIG. ALLOWED is a ++ combination of support_capture_allow flags. Report errors under ++ the CONTEXT message. */ + void support_capture_subprocess_check (struct support_capture_subprocess *, +- const char *context, int status, +- int allowed) ++ const char *context, ++ int status_or_signal, int allowed) + __attribute__ ((nonnull (1, 2))); + + #endif /* SUPPORT_CAPTURE_SUBPROCESS_H */ +diff --git a/support/support_capture_subprocess_check.c b/support/support_capture_subprocess_check.c +index ff5ee89fb02599ae..8b4c352c96227b78 100644 +--- a/support/support_capture_subprocess_check.c ++++ b/support/support_capture_subprocess_check.c +@@ -20,6 +20,7 @@ + #include + #include + #include ++#include + + static void + print_context (const char *context, bool *failed) +@@ -31,9 +32,22 @@ print_context (const char *context, bool *failed) + printf ("error: subprocess failed: %s\n", context); + } + ++static void ++print_actual_status (struct support_capture_subprocess *proc) ++{ ++ if (WIFEXITED (proc->status)) ++ printf ("error: actual exit status: %d [0x%x]\n", ++ WEXITSTATUS (proc->status), proc->status); ++ else if (WIFSIGNALED (proc->status)) ++ printf ("error: actual termination signal: %d [0x%x]\n", ++ WTERMSIG (proc->status), proc->status); ++ else ++ printf ("error: actual undecoded exit status: [0x%x]\n", proc->status); ++} ++ + void + support_capture_subprocess_check (struct support_capture_subprocess *proc, +- const char *context, int status, ++ const char *context, int status_or_signal, + int allowed) + { + TEST_VERIFY ((allowed & sc_allow_none) +@@ -44,11 +58,28 @@ support_capture_subprocess_check (struct support_capture_subprocess *proc, + || (allowed & sc_allow_stderr)))); + + bool failed = false; +- if (proc->status != status) ++ if (status_or_signal >= 0) + { +- print_context (context, &failed); +- printf ("error: expected exit status: %d\n", status); +- printf ("error: actual exit status: %d\n", proc->status); ++ /* Expect regular termination. */ ++ if (!(WIFEXITED (proc->status) ++ && WEXITSTATUS (proc->status) == status_or_signal)) ++ { ++ print_context (context, &failed); ++ printf ("error: expected exit status: %d\n", status_or_signal); ++ print_actual_status (proc); ++ } ++ } ++ else ++ { ++ /* status_or_signal < 0. Expect termination by signal. */ ++ if (!(WIFSIGNALED (proc->status) ++ && WTERMSIG (proc->status) == -status_or_signal)) ++ { ++ print_context (context, &failed); ++ printf ("error: expected termination signal: %d\n", ++ -status_or_signal); ++ print_actual_status (proc); ++ } + } + if (!(allowed & sc_allow_stdout) && proc->out.length != 0) + { +diff --git a/support/tst-support_capture_subprocess.c b/support/tst-support_capture_subprocess.c +index 63b6699622f97fcc..99570879eedd65b1 100644 +--- a/support/tst-support_capture_subprocess.c ++++ b/support/tst-support_capture_subprocess.c +@@ -285,15 +285,29 @@ do_multiple_tests (enum test_type type) + + check_stream ("stdout", &result.out, test.out); + check_stream ("stderr", &result.err, test.err); ++ ++ /* Allowed output for support_capture_subprocess_check. */ ++ int check_allow = 0; ++ if (lengths[length_idx_stdout] > 0) ++ check_allow |= sc_allow_stdout; ++ if (lengths[length_idx_stderr] > 0) ++ check_allow |= sc_allow_stderr; ++ if (check_allow == 0) ++ check_allow = sc_allow_none; ++ + if (test.signal != 0) + { + TEST_VERIFY (WIFSIGNALED (result.status)); + TEST_VERIFY (WTERMSIG (result.status) == test.signal); ++ support_capture_subprocess_check (&result, "signal", ++ -SIGTERM, check_allow); + } + else + { + TEST_VERIFY (WIFEXITED (result.status)); + TEST_VERIFY (WEXITSTATUS (result.status) == test.status); ++ support_capture_subprocess_check (&result, "exit", ++ test.status, check_allow); + } + support_capture_subprocess_free (&result); + free (test.out); diff --git a/SOURCES/glibc-rh1410154-10.patch b/SOURCES/glibc-rh1410154-10.patch new file mode 100644 index 0000000..9025c9e --- /dev/null +++ b/SOURCES/glibc-rh1410154-10.patch @@ -0,0 +1,42 @@ +commit e37c2cf299b61ce18f62852f6c5624c27829b610 +Author: Florian Weimer +Date: Thu Oct 31 18:48:43 2019 +0100 + + Move _dl_open_check to its original place in dl_open_worker + + This reverts the non-test change from commit d0093c5cefb7f7a4143f + ("Call _dl_open_check after relocation [BZ #24259]"), given that + the underlying bug has been fixed properly in commit 61b74477fa7f63 + ("Remove all loaded objects if dlopen fails, ignoring NODELETE + [BZ #20839]"). + + Tested on x86-64-linux-gnu, with and without --enable-cet. + + Change-Id: I995a6cfb89f25d2b0cf5e606428c2a93eb48fc33 + +diff --git a/elf/dl-open.c b/elf/dl-open.c +index 25838b073ac1edaf..e13968d4d7c4c83f 100644 +--- a/elf/dl-open.c ++++ b/elf/dl-open.c +@@ -619,6 +619,8 @@ dl_open_worker (void *a) + _dl_debug_state (); + LIBC_PROBE (map_complete, 3, args->nsid, r, new); + ++ _dl_open_check (new); ++ + /* Print scope information. */ + if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_SCOPES)) + _dl_show_scope (new, 0); +@@ -699,12 +701,6 @@ dl_open_worker (void *a) + _dl_relocate_object (l, l->l_scope, reloc_mode, 0); + } + +- /* NB: Workaround for [BZ #20839] which doesn't remove the NODELETE +- object when _dl_open_check throws an exception. Move it after +- relocation to avoid leaving the NODELETE object mapped without +- relocation. */ +- _dl_open_check (new); +- + /* This only performs the memory allocations. The actual update of + the scopes happens below, after failure is impossible. */ + resize_scopes (new); diff --git a/SOURCES/glibc-rh1410154-11.patch b/SOURCES/glibc-rh1410154-11.patch new file mode 100644 index 0000000..c3a16f3 --- /dev/null +++ b/SOURCES/glibc-rh1410154-11.patch @@ -0,0 +1,27 @@ +commit 61a7c9df71ee4e6f94b56c20f0d37c6e17d5f284 +Author: Florian Weimer +Date: Mon Dec 2 14:53:16 2019 +0100 + + elf/tst-dlopenfail: Disable --no-as-needed for tst-dlopenfailmod1.so + + Otherwise, the shared object dependency which triggers the load + failure is dropped, invalidating the test. + +diff --git a/elf/Makefile b/elf/Makefile +index bf7c41f38be42184..467e810e784bb96d 100644 +--- a/elf/Makefile ++++ b/elf/Makefile +@@ -1543,8 +1543,11 @@ LDFLAGS-tst-finilazyfailmod.so = \ + $(objpfx)tst-dlopenfail: $(libdl) + $(objpfx)tst-dlopenfail.out: \ + $(objpfx)tst-dlopenfailmod1.so $(objpfx)tst-dlopenfailmod2.so +-# Order matters here. tst-dlopenfaillinkmod.so's soname ensures +-# a run-time loader failure. ++# Order matters here. tst-dlopenfaillinkmod.so's soname ensures a ++# run-time loader failure. --as-needed breaks this test because ++# nothing actually references tst-dlopenfailmod2.so (with its soname ++# tst-dlopenfail-missingmod.so). ++LDFLAGS-tst-dlopenfailmod1.so = -Wl,--no-as-needed + $(objpfx)tst-dlopenfailmod1.so: \ + $(shared-thread-library) $(objpfx)tst-dlopenfaillinkmod.so + LDFLAGS-tst-dlopenfaillinkmod.so = -Wl,-soname,tst-dlopenfail-missingmod.so diff --git a/SOURCES/glibc-rh1410154-12.patch b/SOURCES/glibc-rh1410154-12.patch new file mode 100644 index 0000000..48dcfc3 --- /dev/null +++ b/SOURCES/glibc-rh1410154-12.patch @@ -0,0 +1,1229 @@ +commit 365624e2d2a342cdb693b4cc35d2312169959e28 +Author: Florian Weimer +Date: Fri Dec 13 10:18:24 2019 +0100 + + dlopen: Fix issues related to NODELETE handling and relocations + + The assumption behind the assert in activate_nodelete was wrong: + + Inconsistency detected by ld.so: dl-open.c: 459: activate_nodelete: + Assertion `!imap->l_init_called || imap->l_type != lt_loaded' failed! (edit) + + It can happen that an already-loaded object that is in the local + scope is promoted to NODELETE status, via binding to a unique + symbol. + + Similarly, it is possible that such NODELETE promotion occurs to + an already-loaded object from the global scope. This is why the + loop in activate_nodelete has to cover all objects in the namespace + of the new object. + + In do_lookup_unique, it could happen that the NODELETE status of + an already-loaded object was overwritten with a pending NODELETE + status. As a result, if dlopen fails, this could cause a loss of + the NODELETE status of the affected object, eventually resulting + in an incorrect unload. + + Fixes commit f63b73814f74032c0e5d0a83300e3d864ef905e5 ("Remove all + loaded objects if dlopen fails, ignoring NODELETE [BZ #20839]"). + +diff --git a/elf/Makefile b/elf/Makefile +index 467e810e784bb96d..16a3e8dcda19b4ba 100644 +--- a/elf/Makefile ++++ b/elf/Makefile +@@ -185,7 +185,7 @@ tests += restest1 preloadtest loadfail multiload origtest resolvfail \ + 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-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 \ +@@ -266,7 +266,24 @@ modules-names = testobj1 testobj2 testobj3 testobj4 testobj5 testobj6 \ + tst-auditmod9a tst-auditmod9b \ + $(if $(CXX),tst-unique3lib tst-unique3lib2 tst-unique4lib \ + tst-nodelete-uniquemod tst-nodelete-rtldmod \ +- tst-nodelete-zmod) \ ++ 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 \ +@@ -1552,3 +1569,48 @@ $(objpfx)tst-dlopenfailmod1.so: \ + $(shared-thread-library) $(objpfx)tst-dlopenfaillinkmod.so + LDFLAGS-tst-dlopenfaillinkmod.so = -Wl,-soname,tst-dlopenfail-missingmod.so + $(objpfx)tst-dlopenfailmod2.so: $(shared-thread-library) ++ ++$(objpfx)tst-dlopen-nodelete-reloc: $(libdl) ++$(objpfx)tst-dlopen-nodelete-reloc.out: \ ++ $(objpfx)tst-dlopen-nodelete-reloc-mod1.so \ ++ $(objpfx)tst-dlopen-nodelete-reloc-mod2.so \ ++ $(objpfx)tst-dlopen-nodelete-reloc-mod3.so \ ++ $(objpfx)tst-dlopen-nodelete-reloc-mod4.so \ ++ $(objpfx)tst-dlopen-nodelete-reloc-mod5.so \ ++ $(objpfx)tst-dlopen-nodelete-reloc-mod6.so \ ++ $(objpfx)tst-dlopen-nodelete-reloc-mod7.so \ ++ $(objpfx)tst-dlopen-nodelete-reloc-mod8.so \ ++ $(objpfx)tst-dlopen-nodelete-reloc-mod9.so \ ++ $(objpfx)tst-dlopen-nodelete-reloc-mod10.so \ ++ $(objpfx)tst-dlopen-nodelete-reloc-mod11.so \ ++ $(objpfx)tst-dlopen-nodelete-reloc-mod12.so \ ++ $(objpfx)tst-dlopen-nodelete-reloc-mod13.so \ ++ $(objpfx)tst-dlopen-nodelete-reloc-mod14.so \ ++ $(objpfx)tst-dlopen-nodelete-reloc-mod15.so \ ++ $(objpfx)tst-dlopen-nodelete-reloc-mod16.so \ ++ $(objpfx)tst-dlopen-nodelete-reloc-mod17.so ++tst-dlopen-nodelete-reloc-mod2.so-no-z-defs = yes ++LDFLAGS-tst-dlopen-nodelete-reloc-mod2.so = -Wl,-z,nodelete ++$(objpfx)tst-dlopen-nodelete-reloc-mod4.so: \ ++ $(objpfx)tst-dlopen-nodelete-reloc-mod3.so ++LDFLAGS-tst-dlopen-nodelete-reloc-mod4.so = -Wl,--no-as-needed ++$(objpfx)tst-dlopen-nodelete-reloc-mod5.so: \ ++ $(objpfx)tst-dlopen-nodelete-reloc-mod4.so ++LDFLAGS-tst-dlopen-nodelete-reloc-mod5.so = -Wl,-z,nodelete,--no-as-needed ++tst-dlopen-nodelete-reloc-mod5.so-no-z-defs = yes ++tst-dlopen-nodelete-reloc-mod7.so-no-z-defs = yes ++$(objpfx)tst-dlopen-nodelete-reloc-mod8.so: $(libdl) ++$(objpfx)tst-dlopen-nodelete-reloc-mod10.so: $(libdl) ++tst-dlopen-nodelete-reloc-mod11.so-no-z-defs = yes ++$(objpfx)tst-dlopen-nodelete-reloc-mod13.so: \ ++ $(objpfx)tst-dlopen-nodelete-reloc-mod12.so ++$(objpfx)tst-dlopen-nodelete-reloc-mod15.so: \ ++ $(objpfx)tst-dlopen-nodelete-reloc-mod14.so ++tst-dlopen-nodelete-reloc-mod16.so-no-z-defs = yes ++$(objpfx)tst-dlopen-nodelete-reloc-mod16.so: \ ++ $(objpfx)tst-dlopen-nodelete-reloc-mod15.so ++LDFLAGS-tst-dlopen-nodelete-reloc-mod16.so = -Wl,--no-as-needed ++$(objpfx)tst-dlopen-nodelete-reloc-mod17.so: \ ++ $(objpfx)tst-dlopen-nodelete-reloc-mod15.so \ ++ $(objpfx)tst-dlopen-nodelete-reloc-mod16.so ++LDFLAGS-tst-dlopen-nodelete-reloc-mod17.so = -Wl,--no-as-needed +diff --git a/elf/dl-lookup.c b/elf/dl-lookup.c +index c5e5857fb1fe2808..35a3f96a6296294a 100644 +--- a/elf/dl-lookup.c ++++ b/elf/dl-lookup.c +@@ -311,12 +311,12 @@ do_lookup_unique (const char *undef_name, uint_fast32_t new_hash, + enter_unique_sym (entries, size, + new_hash, strtab + sym->st_name, sym, map); + +- if (map->l_type == lt_loaded) ++ if (map->l_type == lt_loaded ++ && map->l_nodelete == link_map_nodelete_inactive) + { + /* Make sure we don't unload this object by + setting the appropriate flag. */ +- if (__glibc_unlikely (GLRO (dl_debug_mask) & DL_DEBUG_BINDINGS) +- && map->l_nodelete == link_map_nodelete_inactive) ++ if (__glibc_unlikely (GLRO (dl_debug_mask) & DL_DEBUG_BINDINGS)) + _dl_debug_printf ("\ + marking %s [%lu] as NODELETE due to unique symbol\n", + map->l_name, map->l_ns); +diff --git a/elf/dl-open.c b/elf/dl-open.c +index e13968d4d7c4c83f..c7ed85b7ee99a296 100644 +--- a/elf/dl-open.c ++++ b/elf/dl-open.c +@@ -433,34 +433,21 @@ TLS generation counter wrapped! Please report this.")); + after dlopen failure is not possible, so that _dl_close can clean + up objects if necessary. */ + static void +-activate_nodelete (struct link_map *new, int mode) ++activate_nodelete (struct link_map *new) + { +- if (mode & RTLD_NODELETE || new->l_nodelete == link_map_nodelete_pending) +- { +- if (__glibc_unlikely (GLRO (dl_debug_mask) & DL_DEBUG_FILES)) +- _dl_debug_printf ("activating NODELETE for %s [%lu]\n", +- new->l_name, new->l_ns); +- new->l_nodelete = link_map_nodelete_active; +- } +- +- for (unsigned int i = 0; i < new->l_searchlist.r_nlist; ++i) +- { +- struct link_map *imap = new->l_searchlist.r_list[i]; +- if (imap->l_nodelete == link_map_nodelete_pending) +- { +- if (__glibc_unlikely (GLRO (dl_debug_mask) & DL_DEBUG_FILES)) +- _dl_debug_printf ("activating NODELETE for %s [%lu]\n", +- imap->l_name, imap->l_ns); +- +- /* Only new objects should have set +- link_map_nodelete_pending. Existing objects should not +- have gained any new dependencies and therefore cannot +- reach NODELETE status. */ +- assert (!imap->l_init_called || imap->l_type != lt_loaded); ++ /* It is necessary to traverse the entire namespace. References to ++ objects in the global scope and unique symbol bindings can force ++ NODELETE status for objects outside the local scope. */ ++ for (struct link_map *l = GL (dl_ns)[new->l_ns]._ns_loaded; l != NULL; ++ l = l->l_next) ++ if (l->l_nodelete == link_map_nodelete_pending) ++ { ++ if (__glibc_unlikely (GLRO (dl_debug_mask) & DL_DEBUG_FILES)) ++ _dl_debug_printf ("activating NODELETE for %s [%lu]\n", ++ l->l_name, l->l_ns); + +- imap->l_nodelete = link_map_nodelete_active; +- } +- } ++ l->l_nodelete = link_map_nodelete_active; ++ } + } + + /* struct dl_init_args and call_dl_init are used to call _dl_init with +@@ -718,7 +705,7 @@ dl_open_worker (void *a) + All memory allocations for new objects must have happened + before. */ + +- activate_nodelete (new, mode); ++ activate_nodelete (new); + + /* Second stage after resize_scopes: Actually perform the scope + update. After this, dlsym and lazy binding can bind to new +diff --git a/elf/tst-dlopen-nodelete-reloc-mod1.c b/elf/tst-dlopen-nodelete-reloc-mod1.c +new file mode 100644 +index 0000000000000000..397d60a2d5ea62d9 +--- /dev/null ++++ b/elf/tst-dlopen-nodelete-reloc-mod1.c +@@ -0,0 +1,39 @@ ++/* Test propagation of NODELETE to an already-loaded object via relocation. ++ Non-NODELETE helper module. ++ 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, see ++ . */ ++ ++#include ++#include ++#include ++ ++/* Globally exported. Set by the main program to true before ++ termination, and used by tst-dlopen-nodelete-reloc-mod2.so to ++ trigger marking this module as NODELETE (and also for its destructor ++ check). */ ++bool may_finalize_mod1 = false; ++ ++static void __attribute__ ((destructor)) ++fini (void) ++{ ++ if (!may_finalize_mod1) ++ { ++ puts ("error: tst-dlopen-nodelete-reloc-mod1.so destructor" ++ " called too early"); ++ _exit (1); ++ } ++} +diff --git a/elf/tst-dlopen-nodelete-reloc-mod10.c b/elf/tst-dlopen-nodelete-reloc-mod10.c +new file mode 100644 +index 0000000000000000..30748b73ec7daed3 +--- /dev/null ++++ b/elf/tst-dlopen-nodelete-reloc-mod10.c +@@ -0,0 +1,41 @@ ++/* Helper module to load tst-dlopen-nodelete-reloc-mod11.so. ++ 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, see ++ . */ ++ ++#include ++#include ++#include ++#include ++ ++static void *handle; ++ ++static void __attribute__ ((constructor)) ++init (void) ++{ ++ handle = dlopen ("tst-dlopen-nodelete-reloc-mod11.so", RTLD_NOW); ++ if (handle == NULL) ++ { ++ printf ("error: dlopen in module 10: %s\n", dlerror ()); ++ _exit (1); ++ } ++} ++ ++static void __attribute__ ((destructor)) ++fini (void) ++{ ++ dlclose (handle); ++} +diff --git a/elf/tst-dlopen-nodelete-reloc-mod11.cc b/elf/tst-dlopen-nodelete-reloc-mod11.cc +new file mode 100644 +index 0000000000000000..48c910403e782c83 +--- /dev/null ++++ b/elf/tst-dlopen-nodelete-reloc-mod11.cc +@@ -0,0 +1,49 @@ ++/* Second module defining a unique symbol (loaded indirectly). ++ 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, see ++ . */ ++ ++#include "tst-dlopen-nodelete-reloc.h" ++ ++#include ++#include ++#include ++ ++/* Just a flag here, not used for NODELETE processing. */ ++bool may_finalize_mod11 = false; ++ ++/* Trigger the creation of a unique symbol reference. This should ++ cause tst-dlopen-nodelete-reloc-mod9.so to be marked as ++ NODELETE. */ ++ ++extern template struct unique_symbol<9>; ++ ++int ++global_function_mod11 (void) ++{ ++ return unique_symbol<9>::value; ++} ++ ++static void __attribute__ ((destructor)) ++fini (void) ++{ ++ if (!may_finalize_mod11) ++ { ++ puts ("error: tst-dlopen-nodelete-reloc-mod11.so destructor" ++ " called too early"); ++ _exit (1); ++ } ++} +diff --git a/elf/tst-dlopen-nodelete-reloc-mod12.cc b/elf/tst-dlopen-nodelete-reloc-mod12.cc +new file mode 100644 +index 0000000000000000..5c093fd02d1fd0c7 +--- /dev/null ++++ b/elf/tst-dlopen-nodelete-reloc-mod12.cc +@@ -0,0 +1,42 @@ ++/* First module for NODELETE test defining a unique symbol (with DT_NEEDED). ++ 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, see ++ . */ ++ ++#include "tst-dlopen-nodelete-reloc.h" ++ ++#include ++#include ++#include ++ ++/* Just a flag here, not used for NODELETE processing. */ ++bool may_finalize_mod12 = false; ++ ++/* Explicit instantiation. This produces a unique symbol definition ++ which is not referenced by the library itself, so the library is ++ not marked NODELETE. */ ++template struct unique_symbol<12>; ++ ++static void __attribute__ ((destructor)) ++fini (void) ++{ ++ if (!may_finalize_mod12) ++ { ++ puts ("error: tst-dlopen-nodelete-reloc-mod12.so destructor" ++ " called too early"); ++ _exit (1); ++ } ++} +diff --git a/elf/tst-dlopen-nodelete-reloc-mod13.cc b/elf/tst-dlopen-nodelete-reloc-mod13.cc +new file mode 100644 +index 0000000000000000..caf4fd1cc9e1c1e1 +--- /dev/null ++++ b/elf/tst-dlopen-nodelete-reloc-mod13.cc +@@ -0,0 +1,48 @@ ++/* Second module for NODELETE test defining a unique symbol (with DT_NEEDED). ++ 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, see ++ . */ ++ ++#include "tst-dlopen-nodelete-reloc.h" ++ ++#include ++#include ++#include ++ ++/* Just a flag here, not used for NODELETE processing. */ ++bool may_finalize_mod13 = false; ++ ++extern template struct unique_symbol<12>; ++ ++/* Trigger the creation of a unique symbol reference. This should ++ cause tst-dlopen-nodelete-reloc-mod12.so to be marked as ++ NODELETE. */ ++int ++global_function_mod13 (void) ++{ ++ return unique_symbol<12>::value; ++} ++ ++static void __attribute__ ((destructor)) ++fini (void) ++{ ++ if (!may_finalize_mod13) ++ { ++ puts ("error: tst-dlopen-nodelete-reloc-mod13.so destructor" ++ " called too early"); ++ _exit (1); ++ } ++} +diff --git a/elf/tst-dlopen-nodelete-reloc-mod13.h b/elf/tst-dlopen-nodelete-reloc-mod13.h +new file mode 100644 +index 0000000000000000..5d338481a34a5714 +--- /dev/null ++++ b/elf/tst-dlopen-nodelete-reloc-mod13.h +@@ -0,0 +1,24 @@ ++/* Inline function which produces a unique symbol. ++ 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, see ++ . */ ++ ++inline char * ++third_function_with_local_static (void) ++{ ++ static char local; ++ return &local; ++} +diff --git a/elf/tst-dlopen-nodelete-reloc-mod14.cc b/elf/tst-dlopen-nodelete-reloc-mod14.cc +new file mode 100644 +index 0000000000000000..e67621a2a2f8509a +--- /dev/null ++++ b/elf/tst-dlopen-nodelete-reloc-mod14.cc +@@ -0,0 +1,42 @@ ++/* This object must retain NODELETE status after a dlopen failure. ++ 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, see ++ . */ ++ ++#include "tst-dlopen-nodelete-reloc.h" ++ ++#include ++#include ++#include ++ ++/* Just a flag here, not used for NODELETE processing. */ ++bool may_finalize_mod14 = false; ++ ++/* Explicit instantiation. This produces a unique symbol definition ++ which is not referenced by the library itself, so the library is ++ not marked NODELETE. */ ++template struct unique_symbol<14>; ++ ++static void __attribute__ ((destructor)) ++fini (void) ++{ ++ if (!may_finalize_mod14) ++ { ++ puts ("error: tst-dlopen-nodelete-reloc-mod14.so destructor" ++ " called too early"); ++ _exit (1); ++ } ++} +diff --git a/elf/tst-dlopen-nodelete-reloc-mod15.cc b/elf/tst-dlopen-nodelete-reloc-mod15.cc +new file mode 100644 +index 0000000000000000..ead362bfdbb90eef +--- /dev/null ++++ b/elf/tst-dlopen-nodelete-reloc-mod15.cc +@@ -0,0 +1,42 @@ ++/* Helper object to mark tst-dlopen-nodelete-reloc-mod14.so as NODELETE. ++ 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, see ++ . */ ++ ++#include "tst-dlopen-nodelete-reloc.h" ++ ++#include ++#include ++#include ++ ++extern template struct unique_symbol<14>; ++ ++/* Trigger the creation of a unique symbol reference. This should ++ cause tst-dlopen-nodelete-reloc-mod14.so to be marked as ++ NODELETE. */ ++int ++global_function_mod15 (void) ++{ ++ return unique_symbol<14>::value; ++} ++ ++static void __attribute__ ((destructor)) ++fini (void) ++{ ++ /* This object is never loaded completely. */ ++ puts ("error: tst-dlopen-nodelete-reloc-mod15.so destructor invoked"); ++ _exit (1); ++} +diff --git a/elf/tst-dlopen-nodelete-reloc-mod16.c b/elf/tst-dlopen-nodelete-reloc-mod16.c +new file mode 100644 +index 0000000000000000..fa2ed1461b42c82c +--- /dev/null ++++ b/elf/tst-dlopen-nodelete-reloc-mod16.c +@@ -0,0 +1,27 @@ ++/* Object with an undefined symbol to trigger a relocation failure. ++ 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, see ++ . */ ++ ++/* The reference to undefined_mod16 triggers a relocation failure. */ ++ ++extern int undefined_mod16; ++ ++int ++global_function_mod16 (void) ++{ ++ return undefined_mod16; ++} +diff --git a/elf/tst-dlopen-nodelete-reloc-mod17.c b/elf/tst-dlopen-nodelete-reloc-mod17.c +new file mode 100644 +index 0000000000000000..426562edd9a3ffee +--- /dev/null ++++ b/elf/tst-dlopen-nodelete-reloc-mod17.c +@@ -0,0 +1,19 @@ ++/* Top-level object with dependency on an object that fails relocation. ++ 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, see ++ . */ ++ ++/* The dependencies do all the work. */ +diff --git a/elf/tst-dlopen-nodelete-reloc-mod2.c b/elf/tst-dlopen-nodelete-reloc-mod2.c +new file mode 100644 +index 0000000000000000..81ea8e5af2d00b93 +--- /dev/null ++++ b/elf/tst-dlopen-nodelete-reloc-mod2.c +@@ -0,0 +1,38 @@ ++/* Test propagation of NODELETE to an already-loaded object via relocation. ++ NODELETE helper module. ++ 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, see ++ . */ ++ ++#include ++#include ++#include ++ ++/* Defined in tst-dlopen-nodelete-reloc-mod1.so. This dependency is ++ not expressed via DT_NEEDED, so this reference marks the other ++ object as NODELETE dynamically, during initially relocation. */ ++extern bool may_finalize_mod1; ++ ++static void __attribute__ ((destructor)) ++fini (void) ++{ ++ if (!may_finalize_mod1) ++ { ++ puts ("error: tst-dlopen-nodelete-reloc-mod2.so destructor" ++ " called too early"); ++ _exit (1); ++ } ++} +diff --git a/elf/tst-dlopen-nodelete-reloc-mod3.c b/elf/tst-dlopen-nodelete-reloc-mod3.c +new file mode 100644 +index 0000000000000000..d33f4ec7630c6a1e +--- /dev/null ++++ b/elf/tst-dlopen-nodelete-reloc-mod3.c +@@ -0,0 +1,38 @@ ++/* Test propagation of NODELETE to an already-loaded object via relocation. ++ Non-NODELETE helper module. ++ 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, see ++ . */ ++ ++#include ++#include ++#include ++ ++/* Globally exported. Set by the main program to true before ++ termination, and used by tst-dlopen-nodelete-reloc-mod4.so, ++ tst-dlopen-nodelete-reloc-mod5.so. */ ++bool may_finalize_mod3 = false; ++ ++static void __attribute__ ((destructor)) ++fini (void) ++{ ++ if (!may_finalize_mod3) ++ { ++ puts ("error: tst-dlopen-nodelete-reloc-mod3.so destructor" ++ " called too early"); ++ _exit (1); ++ } ++} +diff --git a/elf/tst-dlopen-nodelete-reloc-mod4.c b/elf/tst-dlopen-nodelete-reloc-mod4.c +new file mode 100644 +index 0000000000000000..7e6633aebb1e2f00 +--- /dev/null ++++ b/elf/tst-dlopen-nodelete-reloc-mod4.c +@@ -0,0 +1,37 @@ ++/* Test propagation of NODELETE to an already-loaded object via relocation. ++ Intermediate helper module. ++ 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, see ++ . */ ++ ++#include ++#include ++#include ++ ++/* Defined in tst-dlopen-nodelete-reloc-mod3.so. The dependency is ++ expressed via DT_NEEDED. */ ++extern bool may_finalize_mod3; ++ ++static void __attribute__ ((destructor)) ++fini (void) ++{ ++ if (!may_finalize_mod3) ++ { ++ puts ("error: tst-dlopen-nodelete-reloc-mod4.so destructor" ++ " called too early"); ++ _exit (1); ++ } ++} +diff --git a/elf/tst-dlopen-nodelete-reloc-mod5.c b/elf/tst-dlopen-nodelete-reloc-mod5.c +new file mode 100644 +index 0000000000000000..22aa16f855dc75a8 +--- /dev/null ++++ b/elf/tst-dlopen-nodelete-reloc-mod5.c +@@ -0,0 +1,38 @@ ++/* Test propagation of NODELETE to an already-loaded object via relocation. ++ NODELETE helper module. ++ 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, see ++ . */ ++ ++#include ++#include ++#include ++ ++/* Defined in tst-dlopen-nodelete-reloc-mod3.so. The dependency is ++ expressed via DT_NEEDED on the intermediate DSO ++ tst-dlopen-nodelete-reloc-mod3.so. */ ++extern bool may_finalize_mod3; ++ ++static void __attribute__ ((destructor)) ++fini (void) ++{ ++ if (!may_finalize_mod3) ++ { ++ puts ("error: tst-dlopen-nodelete-reloc-mod5.so destructor" ++ " called too early"); ++ _exit (1); ++ } ++} +diff --git a/elf/tst-dlopen-nodelete-reloc-mod6.cc b/elf/tst-dlopen-nodelete-reloc-mod6.cc +new file mode 100644 +index 0000000000000000..180f5b5842f1c2b0 +--- /dev/null ++++ b/elf/tst-dlopen-nodelete-reloc-mod6.cc +@@ -0,0 +1,42 @@ ++/* First module for NODELETE test defining a unique symbol. ++ 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, see ++ . */ ++ ++#include "tst-dlopen-nodelete-reloc.h" ++ ++#include ++#include ++#include ++ ++/* Just a flag here, not used for NODELETE processing. */ ++bool may_finalize_mod6 = false; ++ ++/* Explicit instantiation. This produces a unique symbol definition ++ which is not referenced by the library itself, so the library is ++ not marked NODELETE. */ ++template struct unique_symbol<6>; ++ ++static void __attribute__ ((destructor)) ++fini (void) ++{ ++ if (!may_finalize_mod6) ++ { ++ puts ("error: tst-dlopen-nodelete-reloc-mod6.so destructor" ++ " called too early"); ++ _exit (1); ++ } ++} +diff --git a/elf/tst-dlopen-nodelete-reloc-mod7.cc b/elf/tst-dlopen-nodelete-reloc-mod7.cc +new file mode 100644 +index 0000000000000000..c85e7c991b098bf5 +--- /dev/null ++++ b/elf/tst-dlopen-nodelete-reloc-mod7.cc +@@ -0,0 +1,48 @@ ++/* Second module for NODELETE test defining a unique symbol. ++ 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, see ++ . */ ++ ++#include "tst-dlopen-nodelete-reloc.h" ++ ++#include ++#include ++#include ++ ++/* Just a flag here, not used for NODELETE processing. */ ++bool may_finalize_mod7 = false; ++ ++extern template struct unique_symbol<6>; ++ ++/* Trigger the creation of a unique symbol reference. This should ++ cause tst-dlopen-nodelete-reloc-mod6.so to be marked as ++ NODELETE. */ ++int ++global_function_mod7 (void) ++{ ++ return unique_symbol<6>::value; ++} ++ ++static void __attribute__ ((destructor)) ++fini (void) ++{ ++ if (!may_finalize_mod7) ++ { ++ puts ("error: tst-dlopen-nodelete-reloc-mod7.so destructor" ++ " called too early"); ++ _exit (1); ++ } ++} +diff --git a/elf/tst-dlopen-nodelete-reloc-mod8.c b/elf/tst-dlopen-nodelete-reloc-mod8.c +new file mode 100644 +index 0000000000000000..ebb1c35fab57e319 +--- /dev/null ++++ b/elf/tst-dlopen-nodelete-reloc-mod8.c +@@ -0,0 +1,41 @@ ++/* Helper module to load tst-dlopen-nodelete-reloc-mod9.so. ++ 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, see ++ . */ ++ ++#include ++#include ++#include ++#include ++ ++static void *handle; ++ ++static void __attribute__ ((constructor)) ++init (void) ++{ ++ handle = dlopen ("tst-dlopen-nodelete-reloc-mod9.so", RTLD_NOW); ++ if (handle == NULL) ++ { ++ printf ("error: dlopen in module 8: %s\n", dlerror ()); ++ _exit (1); ++ } ++} ++ ++static void __attribute__ ((destructor)) ++fini (void) ++{ ++ dlclose (handle); ++} +diff --git a/elf/tst-dlopen-nodelete-reloc-mod9.cc b/elf/tst-dlopen-nodelete-reloc-mod9.cc +new file mode 100644 +index 0000000000000000..06fb49cdf753cb41 +--- /dev/null ++++ b/elf/tst-dlopen-nodelete-reloc-mod9.cc +@@ -0,0 +1,42 @@ ++/* First module defining a unique symbol (loaded indirectly). ++ 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, see ++ . */ ++ ++#include "tst-dlopen-nodelete-reloc.h" ++ ++#include ++#include ++#include ++ ++/* Just a flag here, not used for NODELETE processing. */ ++bool may_finalize_mod9 = false; ++ ++/* Explicit instantiation. This produces a unique symbol definition ++ which is not referenced by the library itself, so the library is ++ not marked NODELETE. */ ++template struct unique_symbol<9>; ++ ++static void __attribute__ ((destructor)) ++fini (void) ++{ ++ if (!may_finalize_mod9) ++ { ++ puts ("error: tst-dlopen-nodelete-reloc-mod9.so destructor" ++ " called too early"); ++ _exit (1); ++ } ++} +diff --git a/elf/tst-dlopen-nodelete-reloc.c b/elf/tst-dlopen-nodelete-reloc.c +new file mode 100644 +index 0000000000000000..291ac9eb8385a92e +--- /dev/null ++++ b/elf/tst-dlopen-nodelete-reloc.c +@@ -0,0 +1,179 @@ ++/* Test interactions of dlopen, NODELETE, and relocations. ++ 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, see ++ . */ ++ ++/* This test exercises NODELETE propagation due to data relocations ++ and unique symbols, and the interaction with already-loaded ++ objects. Some test objects are written in C++, to produce unique ++ symbol definitions. ++ ++ First test: Global scope variant, data relocation as the NODELETE ++ trigger. mod1 is loaded first with a separate dlopen call. ++ ++ mod2 ---(may_finalize_mod1 relocation dependency)---> mod1 ++ (NODELETE) (marked as NODELETE) ++ ++ Second test: Local scope variant, data relocation. mod3 is loaded ++ first, then mod5. ++ ++ mod5 ---(DT_NEEDED)---> mod4 ---(DT_NEEDED)---> mod3 ++ (NODELETE) (not NODELETE) ^ ++ \ / (marked as ++ `--(may_finalize_mod3 relocation dependency)--/ NODELETE) ++ ++ Third test: Shared local scope with unique symbol. mod6 is loaded ++ first, then mod7. No explicit dependencies between the two ++ objects, so first object has to be opened with RTLD_GLOBAL. ++ ++ mod7 ---(unique symbol)---> mod6 ++ (marked as NODELETE) ++ ++ Forth test: Non-shared scopes with unique symbol. mod8 and mod10 ++ are loaded from the main program. mod8 loads mod9 from an ELF ++ constructor, mod10 loads mod11. There are no DT_NEEDED ++ dependencies. mod9 is promoted to the global scope form the main ++ program. The unique symbol dependency is: ++ ++ mod9 ---(unique symbol)---> mod11 ++ (marked as NODELETE) ++ ++ Fifth test: Shared local scope with unique symbol, like test 3, but ++ this time, there is also a DT_NEEDED dependency (so no RTLD_GLOBAL ++ needed): ++ ++ DT_NEEDED ++ mod13 ---(unique symbol)---> mod12 ++ (marked as NODELETE) ++ ++ Sixth test: NODELETE status is retained after relocation failure ++ with unique symbol dependency. The object graph ensures that the ++ unique symbol binding is processed before the dlopen failure. ++ ++ DT_NEEDED ++ mod17 --(DT_NEEDED)--> mod15 --(unique symbol)--> mod14 ++ \ ^ (RTLD_NODELETE) ++ \ (DT_NEEDED) ++ \ | ++ `---(DT_NEEDED)--> mod16 ++ (fails to relocate) ++ ++ mod14 is loaded first, and the loading mod17 is attempted. ++ mod14 must remain NODELETE after opening mod17 failed. */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++static int ++do_test (void) ++{ ++ /* First case: global scope, regular data symbol. Open the object ++ which is not NODELETE initially. */ ++ void *mod1 = xdlopen ("tst-dlopen-nodelete-reloc-mod1.so", ++ RTLD_NOW | RTLD_GLOBAL); ++ /* This is used to indicate that the ELF destructor may be ++ called. */ ++ bool *may_finalize_mod1 = xdlsym (mod1, "may_finalize_mod1"); ++ /* Open the NODELETE object. */ ++ void *mod2 = xdlopen ("tst-dlopen-nodelete-reloc-mod2.so", RTLD_NOW); ++ /* This has no effect because the DSO is directly marked as ++ NODELETE. */ ++ xdlclose (mod2); ++ /* This has no effect because the DSO has been indirectly marked as ++ NODELETE due to a relocation dependency. */ ++ xdlclose (mod1); ++ ++ /* Second case: local scope, regular data symbol. Open the object ++ which is not NODELETE initially. */ ++ void *mod3 = xdlopen ("tst-dlopen-nodelete-reloc-mod3.so", RTLD_NOW); ++ bool *may_finalize_mod3 = xdlsym (mod3, "may_finalize_mod3"); ++ /* Open the NODELETE object. */ ++ void *mod5 = xdlopen ("tst-dlopen-nodelete-reloc-mod5.so", RTLD_NOW); ++ /* Again those have no effect because of NODELETE. */ ++ xdlclose (mod5); ++ xdlclose (mod3); ++ ++ /* Third case: Unique symbol. */ ++ void *mod6 = xdlopen ("tst-dlopen-nodelete-reloc-mod6.so", ++ RTLD_NOW | RTLD_GLOBAL); ++ bool *may_finalize_mod6 = xdlsym (mod6, "may_finalize_mod6"); ++ void *mod7 = xdlopen ("tst-dlopen-nodelete-reloc-mod7.so", RTLD_NOW); ++ bool *may_finalize_mod7 = xdlsym (mod7, "may_finalize_mod7"); ++ /* This should not have any effect because of the unique symbol and ++ the resulting NODELETE status. */ ++ xdlclose (mod6); ++ /* mod7 is not NODELETE and can be closed. */ ++ *may_finalize_mod7 = true; ++ xdlclose (mod7); ++ ++ /* Fourth case: Unique symbol, indirect loading. */ ++ void *mod8 = xdlopen ("tst-dlopen-nodelete-reloc-mod8.so", RTLD_NOW); ++ /* Also promote to global scope. */ ++ void *mod9 = xdlopen ("tst-dlopen-nodelete-reloc-mod9.so", ++ RTLD_NOW | RTLD_NOLOAD | RTLD_GLOBAL); ++ bool *may_finalize_mod9 = xdlsym (mod9, "may_finalize_mod9"); ++ xdlclose (mod9); /* Drop mod9 reference. */ ++ void *mod10 = xdlopen ("tst-dlopen-nodelete-reloc-mod10.so", RTLD_NOW); ++ void *mod11 = xdlopen ("tst-dlopen-nodelete-reloc-mod11.so", ++ RTLD_NOW | RTLD_NOLOAD); ++ bool *may_finalize_mod11 = xdlsym (mod11, "may_finalize_mod11"); ++ xdlclose (mod11); /* Drop mod11 reference. */ ++ /* mod11 is not NODELETE and can be closed. */ ++ *may_finalize_mod11 = true; ++ /* Trigger closing of mod11, too. */ ++ xdlclose (mod10); ++ /* Does not trigger closing of mod9. */ ++ xdlclose (mod8); ++ ++ /* Fifth case: Unique symbol, with DT_NEEDED dependency. */ ++ void *mod12 = xdlopen ("tst-dlopen-nodelete-reloc-mod12.so", RTLD_NOW); ++ bool *may_finalize_mod12 = xdlsym (mod12, "may_finalize_mod12"); ++ void *mod13 = xdlopen ("tst-dlopen-nodelete-reloc-mod13.so", RTLD_NOW); ++ bool *may_finalize_mod13 = xdlsym (mod13, "may_finalize_mod13"); ++ /* This should not have any effect because of the unique symbol. */ ++ xdlclose (mod12); ++ /* mod13 is not NODELETE and can be closed. */ ++ *may_finalize_mod13 = true; ++ xdlclose (mod13); ++ ++ /* Sixth case: Unique symbol binding must not cause loss of NODELETE ++ status. */ ++ void *mod14 = xdlopen ("tst-dlopen-nodelete-reloc-mod14.so", ++ RTLD_NOW | RTLD_NODELETE); ++ bool *may_finalize_mod14 = xdlsym (mod14, "may_finalize_mod14"); ++ TEST_VERIFY (dlopen ("tst-dlopen-nodelete-reloc-mod17.so", RTLD_NOW) ++ == NULL); ++ const char *message = dlerror (); ++ printf ("info: test 6 message: %s\n", message); ++ /* This must not close the object, it must still be NODELETE. */ ++ xdlclose (mod14); ++ xdlopen ("tst-dlopen-nodelete-reloc-mod14.so", RTLD_NOW | RTLD_NOLOAD); ++ ++ /* Prepare for process exit. Destructors for NODELETE objects will ++ be invoked. */ ++ *may_finalize_mod1 = true; ++ *may_finalize_mod3 = true; ++ *may_finalize_mod6 = true; ++ *may_finalize_mod9 = true; ++ *may_finalize_mod12 = true; ++ *may_finalize_mod14 = true; ++ return 0; ++} ++ ++#include +diff --git a/elf/tst-dlopen-nodelete-reloc.h b/elf/tst-dlopen-nodelete-reloc.h +new file mode 100644 +index 0000000000000000..8844de622631f575 +--- /dev/null ++++ b/elf/tst-dlopen-nodelete-reloc.h +@@ -0,0 +1,35 @@ ++/* Template to produce unique symbols. ++ 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, see ++ . */ ++ ++/* This template produces a unique symbol definition for an explicit ++ template instantiation (without also incorporating a reference), ++ and an extern template declaration can be used to reference that ++ symbol from another object. The modid parameter is just a ++ placeholder to create different symbols (because it affects the ++ name mangling of the static value member). By convention, it ++ should match the number of the module that contains the ++ definition. */ ++ ++template ++struct unique_symbol ++{ ++ static int value; ++}; ++ ++template ++int unique_symbol::value; diff --git a/SOURCES/glibc-rh1410154-13.patch b/SOURCES/glibc-rh1410154-13.patch new file mode 100644 index 0000000..1ec1768 --- /dev/null +++ b/SOURCES/glibc-rh1410154-13.patch @@ -0,0 +1,328 @@ +commit f8ed116aa574435c6e28260f21963233682d3b57 +Author: Florian Weimer +Date: Fri Dec 13 10:18:46 2019 +0100 + + dlopen: Rework handling of pending NODELETE status + + Commit a2e8aa0d9ea648068d8be52dd7b15f1b6a008e23 ("Block signals during + the initial part of dlopen") was deemed necessary because of + read-modify-write operations like the one in add_dependency in + elf/dl-lookup.c. In the old code, we check for any kind of NODELETE + status and bail out: + + /* Redo the NODELETE check, as when dl_load_lock wasn't held + yet this could have changed. */ + if (map->l_nodelete != link_map_nodelete_inactive) + goto out; + + And then set pending status (during relocation): + + if (flags & DL_LOOKUP_FOR_RELOCATE) + map->l_nodelete = link_map_nodelete_pending; + else + map->l_nodelete = link_map_nodelete_active; + + If a signal arrives during relocation and the signal handler, through + lazy binding, adds a global scope dependency on the same map, it will + set map->l_nodelete to link_map_nodelete_active. This will be + overwritten with link_map_nodelete_pending by the dlopen relocation + code. + + To avoid such problems in relation to the l_nodelete member, this + commit introduces two flags for active NODELETE status (irrevocable) + and pending NODELETE status (revocable until activate_nodelete is + invoked). As a result, NODELETE processing in dlopen does not + introduce further reasons why lazy binding from signal handlers + is unsafe during dlopen, and a subsequent commit can remove signal + blocking from dlopen. + + This does not address pre-existing issues (unrelated to the NODELETE + changes) which make lazy binding in a signal handler during dlopen + unsafe, such as the use of malloc in both cases. + + Reviewed-by: Adhemerval Zanella + Reviewed-by: Carlos O'Donell + +diff --git a/elf/dl-close.c b/elf/dl-close.c +index 243a028c443173c1..fa7f3e8174576e46 100644 +--- a/elf/dl-close.c ++++ b/elf/dl-close.c +@@ -197,7 +197,7 @@ _dl_close_worker (struct link_map *map, bool force) + /* Check whether this object is still used. */ + if (l->l_type == lt_loaded + && l->l_direct_opencount == 0 +- && l->l_nodelete != link_map_nodelete_active ++ && !l->l_nodelete_active + /* 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 +@@ -279,8 +279,7 @@ _dl_close_worker (struct link_map *map, bool force) + + if (!used[i]) + { +- assert (imap->l_type == lt_loaded +- && imap->l_nodelete != link_map_nodelete_active); ++ assert (imap->l_type == lt_loaded && !imap->l_nodelete_active); + + /* Call its termination function. Do not do it for + half-cooked objects. Temporarily disable exception +@@ -820,7 +819,7 @@ _dl_close (void *_map) + before we took the lock. There is no way to detect this (see below) + so we proceed assuming this isn't the case. First see whether we + can remove the object at all. */ +- if (__glibc_unlikely (map->l_nodelete == link_map_nodelete_active)) ++ if (__glibc_unlikely (map->l_nodelete_active)) + { + /* Nope. Do nothing. */ + __rtld_lock_unlock_recursive (GL(dl_load_lock)); +diff --git a/elf/dl-lookup.c b/elf/dl-lookup.c +index 35a3f96a6296294a..01724a54f8840f9f 100644 +--- a/elf/dl-lookup.c ++++ b/elf/dl-lookup.c +@@ -187,6 +187,28 @@ enter_unique_sym (struct unique_sym *table, size_t size, + table[idx].map = map; + } + ++/* Mark MAP as NODELETE according to the lookup mode in FLAGS. During ++ initial relocation, NODELETE state is pending only. */ ++static void ++mark_nodelete (struct link_map *map, int flags) ++{ ++ if (flags & DL_LOOKUP_FOR_RELOCATE) ++ map->l_nodelete_pending = true; ++ else ++ map->l_nodelete_active = true; ++} ++ ++/* Return true if MAP is marked as NODELETE according to the lookup ++ mode in FLAGS> */ ++static bool ++is_nodelete (struct link_map *map, int flags) ++{ ++ /* Non-pending NODELETE always counts. Pending NODELETE only counts ++ during initial relocation processing. */ ++ return map->l_nodelete_active ++ || ((flags & DL_LOOKUP_FOR_RELOCATE) && map->l_nodelete_pending); ++} ++ + /* Utility function for do_lookup_x. Lookup an STB_GNU_UNIQUE symbol + in the unique symbol table, creating a new entry if necessary. + Return the matching symbol in RESULT. */ +@@ -311,8 +333,7 @@ do_lookup_unique (const char *undef_name, uint_fast32_t new_hash, + enter_unique_sym (entries, size, + new_hash, strtab + sym->st_name, sym, map); + +- if (map->l_type == lt_loaded +- && map->l_nodelete == link_map_nodelete_inactive) ++ if (map->l_type == lt_loaded && !is_nodelete (map, flags)) + { + /* Make sure we don't unload this object by + setting the appropriate flag. */ +@@ -320,10 +341,7 @@ do_lookup_unique (const char *undef_name, uint_fast32_t new_hash, + _dl_debug_printf ("\ + marking %s [%lu] as NODELETE due to unique symbol\n", + map->l_name, map->l_ns); +- if (flags & DL_LOOKUP_FOR_RELOCATE) +- map->l_nodelete = link_map_nodelete_pending; +- else +- map->l_nodelete = link_map_nodelete_active; ++ mark_nodelete (map, flags); + } + } + ++tab->n_elements; +@@ -586,7 +604,7 @@ add_dependency (struct link_map *undef_map, struct link_map *map, int flags) + dependencies may pick an dependency which can be dlclose'd, but + such IFUNC resolvers are undefined anyway. */ + assert (map->l_type == lt_loaded); +- if (map->l_nodelete != link_map_nodelete_inactive) ++ if (is_nodelete (map, flags)) + return 0; + + struct link_map_reldeps *l_reldeps +@@ -694,17 +712,16 @@ add_dependency (struct link_map *undef_map, struct link_map *map, int flags) + + /* Redo the NODELETE check, as when dl_load_lock wasn't held + yet this could have changed. */ +- if (map->l_nodelete != link_map_nodelete_inactive) ++ if (is_nodelete (map, flags)) + goto out; + + /* If the object with the undefined reference cannot be removed ever + just make sure the same is true for the object which contains the + definition. */ +- if (undef_map->l_type != lt_loaded +- || (undef_map->l_nodelete != link_map_nodelete_inactive)) ++ if (undef_map->l_type != lt_loaded || is_nodelete (map, flags)) + { + if (__glibc_unlikely (GLRO (dl_debug_mask) & DL_DEBUG_BINDINGS) +- && map->l_nodelete == link_map_nodelete_inactive) ++ && !is_nodelete (map, flags)) + { + if (undef_map->l_name[0] == '\0') + _dl_debug_printf ("\ +@@ -716,11 +733,7 @@ marking %s [%lu] as NODELETE due to reference to %s [%lu]\n", + map->l_name, map->l_ns, + undef_map->l_name, undef_map->l_ns); + } +- +- if (flags & DL_LOOKUP_FOR_RELOCATE) +- map->l_nodelete = link_map_nodelete_pending; +- else +- map->l_nodelete = link_map_nodelete_active; ++ mark_nodelete (map, flags); + goto out; + } + +@@ -746,17 +759,14 @@ marking %s [%lu] as NODELETE due to reference to %s [%lu]\n", + cannot be unloaded. This is semantically the correct + behavior. */ + if (__glibc_unlikely (GLRO (dl_debug_mask) & DL_DEBUG_BINDINGS) +- && map->l_nodelete == link_map_nodelete_inactive) ++ && !is_nodelete (map, flags)) + _dl_debug_printf ("\ + marking %s [%lu] as NODELETE due to memory allocation failure\n", + map->l_name, map->l_ns); +- if (flags & DL_LOOKUP_FOR_RELOCATE) +- /* In case of non-lazy binding, we could actually +- report the memory allocation error, but for now, we +- use the conservative approximation as well. */ +- map->l_nodelete = link_map_nodelete_pending; +- else +- map->l_nodelete = link_map_nodelete_active; ++ /* In case of non-lazy binding, we could actually report ++ the memory allocation error, but for now, we use the ++ conservative approximation as well. */ ++ mark_nodelete (map, flags); + goto out; + } + else +diff --git a/elf/dl-open.c b/elf/dl-open.c +index c7ed85b7ee99a296..a382bfae8aa3a2f8 100644 +--- a/elf/dl-open.c ++++ b/elf/dl-open.c +@@ -440,13 +440,17 @@ activate_nodelete (struct link_map *new) + NODELETE status for objects outside the local scope. */ + for (struct link_map *l = GL (dl_ns)[new->l_ns]._ns_loaded; l != NULL; + l = l->l_next) +- if (l->l_nodelete == link_map_nodelete_pending) ++ if (l->l_nodelete_pending) + { + if (__glibc_unlikely (GLRO (dl_debug_mask) & DL_DEBUG_FILES)) + _dl_debug_printf ("activating NODELETE for %s [%lu]\n", + l->l_name, l->l_ns); + +- l->l_nodelete = link_map_nodelete_active; ++ l->l_nodelete_active = true; ++ ++ /* This is just a debugging aid, to indicate that ++ activate_nodelete has run for this map. */ ++ l->l_nodelete_pending = false; + } + } + +@@ -549,10 +553,10 @@ dl_open_worker (void *a) + if (__glibc_unlikely (mode & RTLD_NODELETE)) + { + if (__glibc_unlikely (GLRO (dl_debug_mask) & DL_DEBUG_FILES) +- && new->l_nodelete == link_map_nodelete_inactive) ++ && !new->l_nodelete_active) + _dl_debug_printf ("marking %s [%lu] as NODELETE\n", + new->l_name, new->l_ns); +- new->l_nodelete = link_map_nodelete_active; ++ new->l_nodelete_active = true; + } + + /* Finalize the addition to the global scope. */ +@@ -568,7 +572,7 @@ dl_open_worker (void *a) + /* Schedule NODELETE marking for the directly loaded object if + requested. */ + if (__glibc_unlikely (mode & RTLD_NODELETE)) +- new->l_nodelete = link_map_nodelete_pending; ++ new->l_nodelete_pending = true; + + /* Load that object's dependencies. */ + _dl_map_object_deps (new, NULL, 0, 0, +@@ -680,7 +684,7 @@ dl_open_worker (void *a) + _dl_start_profile (); + + /* Prevent unloading the object. */ +- GL(dl_profile_map)->l_nodelete = link_map_nodelete_active; ++ GL(dl_profile_map)->l_nodelete_active = true; + } + } + else +@@ -879,9 +883,9 @@ no more namespaces available for dlmopen()")); + happens inside dl_open_worker. */ + __libc_signal_restore_set (&args.original_signal_mask); + +- /* All link_map_nodelete_pending objects should have been +- deleted at this point, which is why it is not necessary +- to reset the flag here. */ ++ /* All l_nodelete_pending objects should have been deleted ++ at this point, which is why it is not necessary to reset ++ the flag here. */ + } + else + __libc_signal_restore_set (&args.original_signal_mask); +diff --git a/elf/get-dynamic-info.h b/elf/get-dynamic-info.h +index ea286abaea0128d1..78ba7e76db9706cc 100644 +--- a/elf/get-dynamic-info.h ++++ b/elf/get-dynamic-info.h +@@ -164,7 +164,7 @@ elf_get_dynamic_info (struct link_map *l, ElfW(Dyn) *temp) + { + l->l_flags_1 = info[VERSYMIDX (DT_FLAGS_1)]->d_un.d_val; + if (l->l_flags_1 & DF_1_NODELETE) +- l->l_nodelete = link_map_nodelete_pending; ++ l->l_nodelete_pending = true; + + /* Only DT_1_SUPPORTED_MASK bits are supported, and we would like + to assert this, but we can't. Users have been setting +diff --git a/include/link.h b/include/link.h +index a277b77cad6b52b1..e90fa79a0b332087 100644 +--- a/include/link.h ++++ b/include/link.h +@@ -79,22 +79,6 @@ struct r_search_path_struct + int malloced; + }; + +-/* Type used by the l_nodelete member. */ +-enum link_map_nodelete +-{ +- /* This link map can be deallocated. */ +- link_map_nodelete_inactive = 0, /* Zero-initialized in _dl_new_object. */ +- +- /* This link map cannot be deallocated. */ +- link_map_nodelete_active, +- +- /* This link map cannot be deallocated after dlopen has succeded. +- dlopen turns this into link_map_nodelete_active. dlclose treats +- this intermediate state as link_map_nodelete_active. */ +- link_map_nodelete_pending, +-}; +- +- + /* Structure describing a loaded shared object. The `l_next' and `l_prev' + members form a chain of all the shared objects loaded at startup. + +@@ -218,10 +202,17 @@ struct link_map + freed, ie. not allocated with + the dummy malloc in ld.so. */ + +- /* Actually of type enum link_map_nodelete. Separate byte due to +- a read in add_dependency in elf/dl-lookup.c outside the loader +- lock. Only valid for l_type == lt_loaded. */ +- unsigned char l_nodelete; ++ /* NODELETE status of the map. Only valid for maps of type ++ lt_loaded. Lazy binding sets l_nodelete_active directly, ++ potentially from signal handlers. Initial loading of an ++ DF_1_NODELETE object set l_nodelete_pending. Relocation may ++ set l_nodelete_pending as well. l_nodelete_pending maps are ++ promoted to l_nodelete_active status in the final stages of ++ dlopen, prior to calling ELF constructors. dlclose only ++ refuses to unload l_nodelete_active maps, the pending status is ++ ignored. */ ++ bool l_nodelete_active; ++ bool l_nodelete_pending; + + #include + diff --git a/SOURCES/glibc-rh1410154-14.patch b/SOURCES/glibc-rh1410154-14.patch new file mode 100644 index 0000000..ac4d1e2 --- /dev/null +++ b/SOURCES/glibc-rh1410154-14.patch @@ -0,0 +1,134 @@ +commit f7649d5780aa4682393b9daedd653e4d9c12784c +Author: Florian Weimer +Date: Fri Dec 13 10:23:10 2019 +0100 + + dlopen: Do not block signals + + Blocking signals causes issues with certain anti-malware solutions + which rely on an unblocked SIGSYS signal for system calls they + intercept. + + This reverts commit a2e8aa0d9ea648068d8be52dd7b15f1b6a008e23 + ("Block signals during the initial part of dlopen") and adds + comments related to async signal safety to active_nodelete and + its caller. + + Note that this does not make lazy binding async-signal-safe with regards + to dlopen. It merely avoids introducing new async-signal-safety hazards + as part of the NODELETE changes. + + Reviewed-by: Adhemerval Zanella + Reviewed-by: Carlos O'Donell + +diff --git a/elf/dl-open.c b/elf/dl-open.c +index a382bfae8aa3a2f8..d834b89754d2b073 100644 +--- a/elf/dl-open.c ++++ b/elf/dl-open.c +@@ -34,7 +34,6 @@ + #include + #include + #include +-#include + + #include + #include +@@ -53,10 +52,6 @@ struct dl_open_args + /* Namespace ID. */ + Lmid_t nsid; + +- /* Original signal mask. Used for unblocking signal handlers before +- running ELF constructors. */ +- sigset_t original_signal_mask; +- + /* Original value of _ns_global_scope_pending_adds. Set by + dl_open_worker. Only valid if nsid is a real namespace + (non-negative). */ +@@ -446,6 +441,9 @@ activate_nodelete (struct link_map *new) + _dl_debug_printf ("activating NODELETE for %s [%lu]\n", + l->l_name, l->l_ns); + ++ /* The flag can already be true at this point, e.g. a signal ++ handler may have triggered lazy binding and set NODELETE ++ status immediately. */ + l->l_nodelete_active = true; + + /* This is just a debugging aid, to indicate that +@@ -520,16 +518,12 @@ dl_open_worker (void *a) + if (new == NULL) + { + assert (mode & RTLD_NOLOAD); +- __libc_signal_restore_set (&args->original_signal_mask); + return; + } + + if (__glibc_unlikely (mode & __RTLD_SPROF)) +- { +- /* This happens only if we load a DSO for 'sprof'. */ +- __libc_signal_restore_set (&args->original_signal_mask); +- return; +- } ++ /* This happens only if we load a DSO for 'sprof'. */ ++ return; + + /* This object is directly loaded. */ + ++new->l_direct_opencount; +@@ -565,7 +559,6 @@ dl_open_worker (void *a) + + assert (_dl_debug_initialize (0, args->nsid)->r_state == RT_CONSISTENT); + +- __libc_signal_restore_set (&args->original_signal_mask); + return; + } + +@@ -709,6 +702,12 @@ dl_open_worker (void *a) + All memory allocations for new objects must have happened + before. */ + ++ /* Finalize the NODELETE status first. This comes before ++ update_scopes, so that lazy binding will not see pending NODELETE ++ state for newly loaded objects. There is a compiler barrier in ++ update_scopes which ensures that the changes from ++ activate_nodelete are visible before new objects show up in the ++ local scope. */ + activate_nodelete (new); + + /* Second stage after resize_scopes: Actually perform the scope +@@ -742,10 +741,6 @@ dl_open_worker (void *a) + if (mode & RTLD_GLOBAL) + add_to_global_resize (new); + +- /* Unblock signals. Data structures are now consistent, and +- application code may run. */ +- __libc_signal_restore_set (&args->original_signal_mask); +- + /* Run the initializer functions of new objects. Temporarily + disable the exception handler, so that lazy binding failures are + fatal. */ +@@ -835,10 +830,6 @@ no more namespaces available for dlmopen()")); + args.argv = argv; + args.env = env; + +- /* Recursive lazy binding during manipulation of the dynamic loader +- structures may result in incorrect behavior. */ +- __libc_signal_block_all (&args.original_signal_mask); +- + struct dl_exception exception; + int errcode = _dl_catch_exception (&exception, dl_open_worker, &args); + +@@ -879,16 +870,10 @@ no more namespaces available for dlmopen()")); + + _dl_close_worker (args.map, true); + +- /* Restore the signal mask. In the success case, this +- happens inside dl_open_worker. */ +- __libc_signal_restore_set (&args.original_signal_mask); +- + /* All l_nodelete_pending objects should have been deleted + at this point, which is why it is not necessary to reset + the flag here. */ + } +- else +- __libc_signal_restore_set (&args.original_signal_mask); + + assert (_dl_debug_initialize (0, args.nsid)->r_state == RT_CONSISTENT); + diff --git a/SOURCES/glibc-rh1410154-15.patch b/SOURCES/glibc-rh1410154-15.patch new file mode 100644 index 0000000..bf58563 --- /dev/null +++ b/SOURCES/glibc-rh1410154-15.patch @@ -0,0 +1,27 @@ +commit 5177d85b0c050a2333a0c4165c938dd422013d05 +Author: H.J. Lu +Date: Thu Jan 16 06:45:36 2020 -0800 + + Clear GL(dl_initfirst) when freeing its link_map memory [BZ# 25396] + + We should clear GL(dl_initfirst) when freeing its link_map memory. + + Tested on Fedora 31/x86-64 with CET. + + Reviewed-by: Florian Weimer + +diff --git a/elf/dl-close.c b/elf/dl-close.c +index fa7f3e8174576e46..a9ecdff62dba88fb 100644 +--- a/elf/dl-close.c ++++ b/elf/dl-close.c +@@ -749,6 +749,10 @@ _dl_close_worker (struct link_map *map, bool force) + if (imap->l_runpath_dirs.dirs != (void *) -1) + free (imap->l_runpath_dirs.dirs); + ++ /* Clear GL(dl_initfirst) when freeing its link_map memory. */ ++ if (imap == GL(dl_initfirst)) ++ GL(dl_initfirst) = NULL; ++ + free (imap); + } + } diff --git a/SOURCES/glibc-rh1410154-16.patch b/SOURCES/glibc-rh1410154-16.patch new file mode 100644 index 0000000..d3e0386 --- /dev/null +++ b/SOURCES/glibc-rh1410154-16.patch @@ -0,0 +1,143 @@ +commit a332bd1518af518c984fad73eba6f46dc5b2b2d4 +Author: Florian Weimer +Date: Thu Jan 16 16:53:58 2020 +0100 + + elf: Add elf/tst-dlopenfail-2 [BZ #25396] + + Without CET, a jump into a newly loaded object through an overwritten + link map often does not crash, it just executes some random code. + CET detects this in some cases because the function pointer does not + point to the start of a function in the replacement shared object, + so there is no ENDBR instruction. + + The new test uses a small shared object and the existing dangling + link map to trigger the bug. + + Reviewed-by: Siddhesh Poyarekar + +Conflicts: + elf/Makefile + (Test backport differences.) + +diff --git a/elf/Makefile b/elf/Makefile +index 16a3e8dcda19b4ba..f1a16fe8ca594c57 100644 +--- a/elf/Makefile ++++ b/elf/Makefile +@@ -192,7 +192,7 @@ tests += restest1 preloadtest loadfail multiload origtest resolvfail \ + tst-latepthread tst-tls-manydynamic tst-nodelete-dlclose \ + tst-debug1 tst-main1 tst-absolute-sym tst-absolute-zero tst-big-note \ + tst-sonamemove-link tst-sonamemove-dlopen tst-initfinilazyfail \ +- tst-dlopenfail ++ tst-dlopenfail tst-dlopenfail-2 + # reldep9 + tests-internal += loadtest unload unload2 circleload1 \ + neededtest neededtest2 neededtest3 neededtest4 \ +@@ -301,7 +301,8 @@ modules-names = testobj1 testobj2 testobj3 testobj4 testobj5 testobj6 \ + tst-sonamemove-linkmod1 \ + tst-sonamemove-runmod1 tst-sonamemove-runmod2 \ + tst-initlazyfailmod tst-finilazyfailmod \ +- tst-dlopenfailmod1 tst-dlopenfaillinkmod tst-dlopenfailmod2 ++ tst-dlopenfailmod1 tst-dlopenfaillinkmod tst-dlopenfailmod2 \ ++ tst-dlopenfailmod3 + + ifeq (yes,$(have-mtls-dialect-gnu2)) + tests += tst-gnu2-tls1 +@@ -1569,6 +1570,10 @@ $(objpfx)tst-dlopenfailmod1.so: \ + $(shared-thread-library) $(objpfx)tst-dlopenfaillinkmod.so + LDFLAGS-tst-dlopenfaillinkmod.so = -Wl,-soname,tst-dlopenfail-missingmod.so + $(objpfx)tst-dlopenfailmod2.so: $(shared-thread-library) ++$(objpfx)tst-dlopenfail-2: $(libdl) ++$(objpfx)tst-dlopenfail.out: \ ++ $(objpfx)tst-dlopenfailmod1.so $(objpfx)tst-dlopenfailmod2.so \ ++ $(objpfx)tst-dlopenfailmod3.so + + $(objpfx)tst-dlopen-nodelete-reloc: $(libdl) + $(objpfx)tst-dlopen-nodelete-reloc.out: \ +diff --git a/elf/tst-dlopenfail-2.c b/elf/tst-dlopenfail-2.c +new file mode 100644 +index 0000000000000000..35bbde64abbb6603 +--- /dev/null ++++ b/elf/tst-dlopenfail-2.c +@@ -0,0 +1,59 @@ ++/* Test unrelated dlopen after dlopen failure involving NODELETE. ++ Copyright (C) 2019-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 ++ ++static int ++do_test (void) ++{ ++ /* This test uses libpthread as the canonical NODELETE module. If ++ libpthread is no longer NODELETE because it has been merged into ++ libc, the test needs to be updated. */ ++ TEST_VERIFY (dlsym (NULL, "pthread_create") == NULL); ++ ++ /* This is expected to fail because of the missing dependency. */ ++ puts ("info: attempting to load tst-dlopenfailmod1.so"); ++ TEST_VERIFY (dlopen ("tst-dlopenfailmod1.so", RTLD_LAZY) == NULL); ++ const char *message = dlerror (); ++ TEST_COMPARE_STRING (message, ++ "tst-dlopenfail-missingmod.so:" ++ " cannot open shared object file:" ++ " No such file or directory"); ++ ++ /* Open a small shared object. With a dangling GL (dl_initfirst) ++ pointer, this is likely to crash because there is no longer any ++ mapped text segment there (bug 25396). */ ++ ++ puts ("info: attempting to load tst-dlopenfailmod3.so"); ++ xdlclose (xdlopen ("tst-dlopenfailmod3.so", RTLD_NOW)); ++ ++ return 0; ++} ++ ++/* Do not perturb the dangling link map. With M_PERTURB, the link map ++ appears to have l_init_called set, so there are no constructor ++ calls and no crashes. */ ++#define TEST_NO_MALLOPT ++#include +diff --git a/elf/tst-dlopenfailmod3.c b/elf/tst-dlopenfailmod3.c +new file mode 100644 +index 0000000000000000..636e971264292110 +--- /dev/null ++++ b/elf/tst-dlopenfailmod3.c +@@ -0,0 +1,17 @@ ++/* Empty module for the tst-dlopenfail-2 test. ++ 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 ++ . */ diff --git a/SOURCES/glibc-rh1410154-2.patch b/SOURCES/glibc-rh1410154-2.patch new file mode 100644 index 0000000..84269e7 --- /dev/null +++ b/SOURCES/glibc-rh1410154-2.patch @@ -0,0 +1,33 @@ +commit ca136bb0a36d0a7056c926bfe5126873566efe40 +Author: Florian Weimer +Date: Thu Oct 31 13:28:26 2019 +0100 + + Clarify purpose of assert in _dl_lookup_symbol_x + + Only one of the currently defined flags is incompatible with versioned + symbol lookups, so it makes sense to check for that flag and not its + complement. + + Reviewed-by: Carlos O'Donell + Reviewed-by: Gabriel F. T. Gomes + Change-Id: I3384349cef90cfd91862ebc34a4053f0c0a99404 + +diff --git a/elf/dl-lookup.c b/elf/dl-lookup.c +index 1d046caf017b582b..efbdb8deb3c0a9d4 100644 +--- a/elf/dl-lookup.c ++++ b/elf/dl-lookup.c +@@ -792,11 +792,9 @@ _dl_lookup_symbol_x (const char *undef_name, struct link_map *undef_map, + + bump_num_relocations (); + +- /* No other flag than DL_LOOKUP_ADD_DEPENDENCY or DL_LOOKUP_GSCOPE_LOCK +- is allowed if we look up a versioned symbol. */ +- assert (version == NULL +- || (flags & ~(DL_LOOKUP_ADD_DEPENDENCY | DL_LOOKUP_GSCOPE_LOCK)) +- == 0); ++ /* DL_LOOKUP_RETURN_NEWEST does not make sense for versioned ++ lookups. */ ++ assert (version == NULL || !(flags & DL_LOOKUP_RETURN_NEWEST)); + + size_t i = 0; + if (__glibc_unlikely (skip_map != NULL)) diff --git a/SOURCES/glibc-rh1410154-3.patch b/SOURCES/glibc-rh1410154-3.patch new file mode 100644 index 0000000..34afb62 --- /dev/null +++ b/SOURCES/glibc-rh1410154-3.patch @@ -0,0 +1,54 @@ +commit 2a764c6ee848dfe92cb2921ed3b14085f15d9e79 +Author: Florian Weimer +Date: Thu Oct 31 13:23:06 2019 +0100 + + Enhance _dl_catch_exception to allow disabling exception handling + + In some cases, it is necessary to introduce noexcept regions + where raised dynamic loader exceptions (e.g., from lazy binding) + are fatal, despite being nested in a code region with an active + exception handler. This change enhances _dl_catch_exception with + to provide such a capability. The existing function is reused, + so that it is not necessary to introduce yet another function with + a similar purpose. + + Change-Id: Iec1bf642ff95a349fdde8040e9baf851ac7b8904 + +diff --git a/elf/dl-error-skeleton.c b/elf/dl-error-skeleton.c +index d5f418ab1848f0c4..9cb002ccfed2c7b4 100644 +--- a/elf/dl-error-skeleton.c ++++ b/elf/dl-error-skeleton.c +@@ -173,6 +173,18 @@ int + _dl_catch_exception (struct dl_exception *exception, + void (*operate) (void *), void *args) + { ++ /* If exception is NULL, temporarily disable exception handling. ++ Exceptions during operate (args) are fatal. */ ++ if (exception == NULL) ++ { ++ struct catch *const old = catch_hook; ++ catch_hook = NULL; ++ operate (args); ++ /* If we get here, the operation was successful. */ ++ catch_hook = old; ++ return 0; ++ } ++ + /* We need not handle `receiver' since setting a `catch' is handled + before it. */ + +diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h +index 95dc87519b80e0ec..cc2484033fe0d902 100644 +--- a/sysdeps/generic/ldsodefs.h ++++ b/sysdeps/generic/ldsodefs.h +@@ -852,7 +852,9 @@ libc_hidden_proto (_dl_catch_error) + + /* 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. */ ++ which has to be freed by _dl_exception_free. As a special case, if ++ EXCEPTION is null, call OPERATE (ARGS) with exception handling ++ disabled (so that exceptions are fatal). */ + int _dl_catch_exception (struct dl_exception *exception, + void (*operate) (void *), void *args); + libc_hidden_proto (_dl_catch_exception) diff --git a/SOURCES/glibc-rh1410154-4.patch b/SOURCES/glibc-rh1410154-4.patch new file mode 100644 index 0000000..fa3cc53 --- /dev/null +++ b/SOURCES/glibc-rh1410154-4.patch @@ -0,0 +1,42 @@ +commit fcb04b9aed26a737159ef7be9c5a6ad0994437dc +Author: Florian Weimer +Date: Thu Oct 31 13:28:49 2019 +0100 + + Introduce DL_LOOKUP_FOR_RELOCATE flag for _dl_lookup_symbol_x + + This will allow changes in dependency processing during non-lazy + binding, for more precise processing of NODELETE objects: During + initial relocation in dlopen, the fate of NODELETE objects is still + unclear, so objects which are depended upon by NODELETE objects + cannot immediately be marked as NODELETE. + + Change-Id: Ic7b94a3f7c4719a00ca8e6018088567824da0658 + +diff --git a/elf/dl-reloc.c b/elf/dl-reloc.c +index 053916eeae50467c..afeace4d3e49180c 100644 +--- a/elf/dl-reloc.c ++++ b/elf/dl-reloc.c +@@ -248,7 +248,8 @@ _dl_relocate_object (struct link_map *l, struct r_scope_elem *scope[], + v = (version); \ + _lr = _dl_lookup_symbol_x (strtab + (*ref)->st_name, l, (ref), \ + scope, v, _tc, \ +- DL_LOOKUP_ADD_DEPENDENCY, NULL); \ ++ DL_LOOKUP_ADD_DEPENDENCY \ ++ | DL_LOOKUP_FOR_RELOCATE, NULL); \ + l->l_lookup_cache.ret = (*ref); \ + l->l_lookup_cache.value = _lr; })) \ + : l) +diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h +index cc2484033fe0d902..6c5298a80bff8e96 100644 +--- a/sysdeps/generic/ldsodefs.h ++++ b/sysdeps/generic/ldsodefs.h +@@ -908,6 +908,9 @@ enum + DL_LOOKUP_RETURN_NEWEST = 2, + /* Set if dl_lookup* called with GSCOPE lock held. */ + DL_LOOKUP_GSCOPE_LOCK = 4, ++ /* Set if dl_lookup is called for non-lazy relocation processing ++ from _dl_relocate_object in elf/dl-reloc.c. */ ++ DL_LOOKUP_FOR_RELOCATE = 8, + }; + + /* Lookup versioned symbol. */ diff --git a/SOURCES/glibc-rh1410154-5.patch b/SOURCES/glibc-rh1410154-5.patch new file mode 100644 index 0000000..6879fb3 --- /dev/null +++ b/SOURCES/glibc-rh1410154-5.patch @@ -0,0 +1,343 @@ +commit 79e0cd7b3c997e211fad44a81fd839dc5b2546e8 +Author: Florian Weimer +Date: Wed Nov 27 16:20:47 2019 +0100 + + Lazy binding failures during dlopen/dlclose must be fatal [BZ #24304] + + If a lazy binding failure happens during the execution of an ELF + constructor or destructor, the dynamic loader catches the error + and reports it using the dlerror mechanism. This is undesirable + because there could be other constructors and destructors that + need processing (which are skipped), and the process is in an + inconsistent state at this point. Therefore, we have to issue + a fatal dynamic loader error error and terminate the process. + + Note that the _dl_catch_exception in _dl_open is just an inner catch, + to roll back some state locally. If called from dlopen, there is + still an outer catch, which is why calling _dl_init via call_dl_init + and a no-exception is required and cannot be avoiding by moving the + _dl_init call directly into _dl_open. + + _dl_fini does not need changes because it does not install an error + handler, so errors are already fatal there. + + Change-Id: I6b1addfe2e30f50a1781595f046f44173db9491a + +Conflicts: + elf/Makefile + (Usual conflicts due to test backport differences.) + +diff --git a/elf/Makefile b/elf/Makefile +index 74a240b3a68ff5e2..b752f6366400d221 100644 +--- a/elf/Makefile ++++ b/elf/Makefile +@@ -191,7 +191,7 @@ tests += restest1 preloadtest loadfail multiload origtest resolvfail \ + 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-sonamemove-link tst-sonamemove-dlopen ++ tst-sonamemove-link tst-sonamemove-dlopen tst-initfinilazyfail + # reldep9 + tests-internal += loadtest unload unload2 circleload1 \ + neededtest neededtest2 neededtest3 neededtest4 \ +@@ -281,7 +281,8 @@ modules-names = testobj1 testobj2 testobj3 testobj4 testobj5 testobj6 \ + tst-main1mod tst-libc_dlvsym-dso tst-absolute-sym-lib \ + tst-absolute-zero-lib tst-big-note-lib \ + tst-sonamemove-linkmod1 \ +- tst-sonamemove-runmod1 tst-sonamemove-runmod2 ++ tst-sonamemove-runmod1 tst-sonamemove-runmod2 \ ++ tst-initlazyfailmod tst-finilazyfailmod + + ifeq (yes,$(have-mtls-dialect-gnu2)) + tests += tst-gnu2-tls1 +@@ -1526,3 +1527,13 @@ tst-libc_dlvsym-static-ENV = \ + $(objpfx)tst-libc_dlvsym-static.out: $(objpfx)tst-libc_dlvsym-dso.so + + $(objpfx)tst-big-note: $(objpfx)tst-big-note-lib.so ++ ++$(objpfx)tst-initfinilazyfail: $(libdl) ++$(objpfx)tst-initfinilazyfail.out: \ ++ $(objpfx)tst-initlazyfailmod.so $(objpfx)tst-finilazyfailmod.so ++# Override -z defs, so that we can reference an undefined symbol. ++# Force lazy binding for the same reason. ++LDFLAGS-tst-initlazyfailmod.so = \ ++ -Wl,-z,lazy -Wl,--unresolved-symbols=ignore-all ++LDFLAGS-tst-finilazyfailmod.so = \ ++ -Wl,-z,lazy -Wl,--unresolved-symbols=ignore-all +diff --git a/elf/dl-close.c b/elf/dl-close.c +index ecd6729704ea3294..88aeea25839a34e0 100644 +--- a/elf/dl-close.c ++++ b/elf/dl-close.c +@@ -106,6 +106,30 @@ remove_slotinfo (size_t idx, struct dtv_slotinfo_list *listp, size_t disp, + return false; + } + ++/* Invoke dstructors for CLOSURE (a struct link_map *). Called with ++ exception handling temporarily disabled, to make errors fatal. */ ++static void ++call_destructors (void *closure) ++{ ++ struct link_map *map = closure; ++ ++ if (map->l_info[DT_FINI_ARRAY] != NULL) ++ { ++ ElfW(Addr) *array = ++ (ElfW(Addr) *) (map->l_addr ++ + map->l_info[DT_FINI_ARRAY]->d_un.d_ptr); ++ unsigned int sz = (map->l_info[DT_FINI_ARRAYSZ]->d_un.d_val ++ / sizeof (ElfW(Addr))); ++ ++ while (sz-- > 0) ++ ((fini_t) array[sz]) (); ++ } ++ ++ /* Next try the old-style destructor. */ ++ if (map->l_info[DT_FINI] != NULL) ++ DL_CALL_DT_FINI (map, ((void *) map->l_addr ++ + map->l_info[DT_FINI]->d_un.d_ptr)); ++} + + void + _dl_close_worker (struct link_map *map, bool force) +@@ -267,7 +291,8 @@ _dl_close_worker (struct link_map *map, bool force) + && (imap->l_flags_1 & DF_1_NODELETE) == 0); + + /* Call its termination function. Do not do it for +- half-cooked objects. */ ++ half-cooked objects. Temporarily disable exception ++ handling, so that errors are fatal. */ + if (imap->l_init_called) + { + /* When debugging print a message first. */ +@@ -276,22 +301,9 @@ _dl_close_worker (struct link_map *map, bool force) + _dl_debug_printf ("\ncalling fini: %s [%lu]\n\n", + imap->l_name, nsid); + +- if (imap->l_info[DT_FINI_ARRAY] != NULL) +- { +- ElfW(Addr) *array = +- (ElfW(Addr) *) (imap->l_addr +- + imap->l_info[DT_FINI_ARRAY]->d_un.d_ptr); +- unsigned int sz = (imap->l_info[DT_FINI_ARRAYSZ]->d_un.d_val +- / sizeof (ElfW(Addr))); +- +- while (sz-- > 0) +- ((fini_t) array[sz]) (); +- } +- +- /* Next try the old-style destructor. */ +- if (imap->l_info[DT_FINI] != NULL) +- DL_CALL_DT_FINI (imap, ((void *) imap->l_addr +- + imap->l_info[DT_FINI]->d_un.d_ptr)); ++ if (imap->l_info[DT_FINI_ARRAY] != NULL ++ || imap->l_info[DT_FINI] != NULL) ++ _dl_catch_exception (NULL, call_destructors, imap); + } + + #ifdef SHARED +diff --git a/elf/dl-open.c b/elf/dl-open.c +index 518a6cad699ec6d0..c9c0254ee74c4f4b 100644 +--- a/elf/dl-open.c ++++ b/elf/dl-open.c +@@ -177,6 +177,23 @@ _dl_find_dso_for_object (const ElfW(Addr) addr) + } + rtld_hidden_def (_dl_find_dso_for_object); + ++/* struct dl_init_args and call_dl_init are used to call _dl_init with ++ exception handling disabled. */ ++struct dl_init_args ++{ ++ struct link_map *new; ++ int argc; ++ char **argv; ++ char **env; ++}; ++ ++static void ++call_dl_init (void *closure) ++{ ++ struct dl_init_args *args = closure; ++ _dl_init (args->new, args->argc, args->argv, args->env); ++} ++ + static void + dl_open_worker (void *a) + { +@@ -506,8 +523,19 @@ TLS generation counter wrapped! Please report this.")); + DL_STATIC_INIT (new); + #endif + +- /* Run the initializer functions of new objects. */ +- _dl_init (new, args->argc, args->argv, args->env); ++ /* Run the initializer functions of new objects. Temporarily ++ disable the exception handler, so that lazy binding failures are ++ fatal. */ ++ { ++ struct dl_init_args init_args = ++ { ++ .new = new, ++ .argc = args->argc, ++ .argv = args->argv, ++ .env = args->env ++ }; ++ _dl_catch_exception (NULL, call_dl_init, &init_args); ++ } + + /* Now we can make the new map available in the global scope. */ + if (mode & RTLD_GLOBAL) +diff --git a/elf/tst-finilazyfailmod.c b/elf/tst-finilazyfailmod.c +new file mode 100644 +index 0000000000000000..2670bd1a9400d0ef +--- /dev/null ++++ b/elf/tst-finilazyfailmod.c +@@ -0,0 +1,27 @@ ++/* Helper module for tst-initfinilazyfail: lazy binding failure in destructor. ++ 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, see ++ . */ ++ ++/* An undefined function. Calling it will cause a lazy binding ++ failure. */ ++void undefined_function (void); ++ ++static void __attribute__ ((destructor)) ++fini (void) ++{ ++ undefined_function (); ++} +diff --git a/elf/tst-initfinilazyfail.c b/elf/tst-initfinilazyfail.c +new file mode 100644 +index 0000000000000000..9b4a3d0c0ffbb7c6 +--- /dev/null ++++ b/elf/tst-initfinilazyfail.c +@@ -0,0 +1,84 @@ ++/* Test that lazy binding failures in constructors and destructors are fatal. ++ 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, see ++ . */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++static void ++test_constructor (void *closure) ++{ ++ void *handle = dlopen ("tst-initlazyfailmod.so", RTLD_LAZY); ++ if (handle == NULL) ++ FAIL_EXIT (2, "dlopen did not terminate the process: %s", dlerror ()); ++ else ++ FAIL_EXIT (2, "dlopen did not terminate the process (%p)", handle); ++} ++ ++static void ++test_destructor (void *closure) ++{ ++ void *handle = xdlopen ("tst-finilazyfailmod.so", RTLD_LAZY); ++ int ret = dlclose (handle); ++ const char *message = dlerror (); ++ if (message != NULL) ++ FAIL_EXIT (2, "dlclose did not terminate the process: %d, %s", ++ ret, message); ++ else ++ FAIL_EXIT (2, "dlopen did not terminate the process: %d", ret); ++} ++ ++static int ++do_test (void) ++{ ++ { ++ struct support_capture_subprocess proc ++ = support_capture_subprocess (test_constructor, NULL); ++ support_capture_subprocess_check (&proc, "constructor", 127, ++ sc_allow_stderr); ++ printf ("info: constructor failure output: [[%s]]\n", proc.err.buffer); ++ TEST_VERIFY (strstr (proc.err.buffer, ++ "tst-initfinilazyfail: symbol lookup error: ") ++ != NULL); ++ TEST_VERIFY (strstr (proc.err.buffer, ++ "tst-initlazyfailmod.so: undefined symbol:" ++ " undefined_function\n") != NULL); ++ support_capture_subprocess_free (&proc); ++ } ++ ++ { ++ struct support_capture_subprocess proc ++ = support_capture_subprocess (test_destructor, NULL); ++ support_capture_subprocess_check (&proc, "destructor", 127, ++ sc_allow_stderr); ++ printf ("info: destructor failure output: [[%s]]\n", proc.err.buffer); ++ TEST_VERIFY (strstr (proc.err.buffer, ++ "tst-initfinilazyfail: symbol lookup error: ") ++ != NULL); ++ TEST_VERIFY (strstr (proc.err.buffer, ++ "tst-finilazyfailmod.so: undefined symbol:" ++ " undefined_function\n") != NULL); ++ support_capture_subprocess_free (&proc); ++ } ++ ++ return 0; ++} ++ ++#include +diff --git a/elf/tst-initlazyfailmod.c b/elf/tst-initlazyfailmod.c +new file mode 100644 +index 0000000000000000..36348b58d634d2bb +--- /dev/null ++++ b/elf/tst-initlazyfailmod.c +@@ -0,0 +1,27 @@ ++/* Helper module for tst-initfinilazyfail: lazy binding failure in constructor. ++ 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, see ++ . */ ++ ++/* An undefined function. Calling it will cause a lazy binding ++ failure. */ ++void undefined_function (void); ++ ++static void __attribute__ ((constructor)) ++init (void) ++{ ++ undefined_function (); ++} diff --git a/SOURCES/glibc-rh1410154-6.patch b/SOURCES/glibc-rh1410154-6.patch new file mode 100644 index 0000000..3b05076 --- /dev/null +++ b/SOURCES/glibc-rh1410154-6.patch @@ -0,0 +1,308 @@ +commit 440b7f8653e4ed8f6e1425145208050b795e9a6c +Author: Florian Weimer +Date: Thu Oct 31 18:25:39 2019 +0100 + + Avoid late failure in dlopen in global scope update [BZ #25112] + + The call to add_to_global in dl_open_worker happens after running ELF + constructors for new objects. At this point, proper recovery from + malloc failure would be quite complicated: We would have to run the + ELF destructors and close all opened objects, something that we + currently do not do. + + Instead, this change splits add_to_global into two phases, + add_to_global_resize (which can raise an exception, called before ELF + constructors run), and add_to_global_update (which cannot, called + after ELF constructors). A complication arises due to recursive + dlopen: After the inner dlopen consumes some space, the pre-allocation + in the outer dlopen may no longer be sufficient. A new member in the + namespace structure, _ns_global_scope_pending_adds keeps track of the + maximum number of objects that need to be added to the global scope. + This enables the inner add_to_global_resize call to take into account + the needs of an outer dlopen. + + Most code in the dynamic linker assumes that the number of global + scope entries fits into an unsigned int (matching the r_nlist member + of struct r_scop_elem). Therefore, change the type of + _ns_global_scope_alloc to unsigned int (from size_t), and add overflow + checks. + + Change-Id: Ie08e2f318510d5a6a4bcb1c315f46791b5b77524 + +diff --git a/elf/dl-open.c b/elf/dl-open.c +index c9c0254ee74c4f4b..85db4f0ecb5f29ce 100644 +--- a/elf/dl-open.c ++++ b/elf/dl-open.c +@@ -50,22 +50,38 @@ struct dl_open_args + struct link_map *map; + /* Namespace ID. */ + Lmid_t nsid; ++ ++ /* Original value of _ns_global_scope_pending_adds. Set by ++ dl_open_worker. Only valid if nsid is a real namespace ++ (non-negative). */ ++ unsigned int original_global_scope_pending_adds; ++ + /* Original parameters to the program and the current environment. */ + int argc; + char **argv; + char **env; + }; + ++/* Called in case the global scope cannot be extended. */ ++static void __attribute__ ((noreturn)) ++add_to_global_resize_failure (struct link_map *new) ++{ ++ _dl_signal_error (ENOMEM, new->l_libname->name, NULL, ++ N_ ("cannot extend global scope")); ++} + +-static int +-add_to_global (struct link_map *new) ++/* Grow the global scope array for the namespace, so that all the new ++ global objects can be added later in add_to_global_update, without ++ risk of memory allocation failure. add_to_global_resize raises ++ exceptions for memory allocation errors. */ ++static void ++add_to_global_resize (struct link_map *new) + { +- struct link_map **new_global; +- unsigned int to_add = 0; +- unsigned int cnt; ++ struct link_namespaces *ns = &GL (dl_ns)[new->l_ns]; + + /* Count the objects we have to put in the global scope. */ +- for (cnt = 0; cnt < new->l_searchlist.r_nlist; ++cnt) ++ unsigned int to_add = 0; ++ for (unsigned int cnt = 0; cnt < new->l_searchlist.r_nlist; ++cnt) + if (new->l_searchlist.r_list[cnt]->l_global == 0) + ++to_add; + +@@ -83,47 +99,51 @@ add_to_global (struct link_map *new) + in an realloc() call. Therefore we allocate a completely new + array the first time we have to add something to the locale scope. */ + +- struct link_namespaces *ns = &GL(dl_ns)[new->l_ns]; ++ if (__builtin_add_overflow (ns->_ns_global_scope_pending_adds, to_add, ++ &ns->_ns_global_scope_pending_adds)) ++ add_to_global_resize_failure (new); ++ ++ unsigned int new_size = 0; /* 0 means no new allocation. */ ++ void *old_global = NULL; /* Old allocation if free-able. */ ++ ++ /* Minimum required element count for resizing. Adjusted below for ++ an exponential resizing policy. */ ++ size_t required_new_size; ++ if (__builtin_add_overflow (ns->_ns_main_searchlist->r_nlist, ++ ns->_ns_global_scope_pending_adds, ++ &required_new_size)) ++ add_to_global_resize_failure (new); ++ + if (ns->_ns_global_scope_alloc == 0) + { +- /* This is the first dynamic object given global scope. */ +- ns->_ns_global_scope_alloc +- = ns->_ns_main_searchlist->r_nlist + to_add + 8; +- new_global = (struct link_map **) +- malloc (ns->_ns_global_scope_alloc * sizeof (struct link_map *)); +- if (new_global == NULL) +- { +- ns->_ns_global_scope_alloc = 0; +- nomem: +- _dl_signal_error (ENOMEM, new->l_libname->name, NULL, +- N_("cannot extend global scope")); +- return 1; +- } ++ if (__builtin_add_overflow (required_new_size, 8, &new_size)) ++ add_to_global_resize_failure (new); ++ } ++ else if (required_new_size > ns->_ns_global_scope_alloc) ++ { ++ if (__builtin_mul_overflow (required_new_size, 2, &new_size)) ++ add_to_global_resize_failure (new); + +- /* Copy over the old entries. */ +- ns->_ns_main_searchlist->r_list +- = memcpy (new_global, ns->_ns_main_searchlist->r_list, +- (ns->_ns_main_searchlist->r_nlist +- * sizeof (struct link_map *))); ++ /* The old array was allocated with our malloc, not the minimal ++ malloc. */ ++ old_global = ns->_ns_main_searchlist->r_list; + } +- else if (ns->_ns_main_searchlist->r_nlist + to_add +- > ns->_ns_global_scope_alloc) ++ ++ if (new_size > 0) + { +- /* We have to extend the existing array of link maps in the +- main map. */ +- struct link_map **old_global +- = GL(dl_ns)[new->l_ns]._ns_main_searchlist->r_list; +- size_t new_nalloc = ((ns->_ns_global_scope_alloc + to_add) * 2); +- +- new_global = (struct link_map **) +- malloc (new_nalloc * sizeof (struct link_map *)); ++ size_t allocation_size; ++ if (__builtin_mul_overflow (new_size, sizeof (struct link_map *), ++ &allocation_size)) ++ add_to_global_resize_failure (new); ++ struct link_map **new_global = malloc (allocation_size); + if (new_global == NULL) +- goto nomem; ++ add_to_global_resize_failure (new); + +- memcpy (new_global, old_global, +- ns->_ns_global_scope_alloc * sizeof (struct link_map *)); ++ /* Copy over the old entries. */ ++ memcpy (new_global, ns->_ns_main_searchlist->r_list, ++ ns->_ns_main_searchlist->r_nlist * sizeof (struct link_map *)); + +- ns->_ns_global_scope_alloc = new_nalloc; ++ ns->_ns_global_scope_alloc = new_size; + ns->_ns_main_searchlist->r_list = new_global; + + if (!RTLD_SINGLE_THREAD_P) +@@ -131,16 +151,28 @@ add_to_global (struct link_map *new) + + free (old_global); + } ++} ++ ++/* Actually add the new global objects to the global scope. Must be ++ called after add_to_global_resize. This function cannot fail. */ ++static void ++add_to_global_update (struct link_map *new) ++{ ++ struct link_namespaces *ns = &GL (dl_ns)[new->l_ns]; + + /* Now add the new entries. */ + unsigned int new_nlist = ns->_ns_main_searchlist->r_nlist; +- for (cnt = 0; cnt < new->l_searchlist.r_nlist; ++cnt) ++ for (unsigned int cnt = 0; cnt < new->l_searchlist.r_nlist; ++cnt) + { + struct link_map *map = new->l_searchlist.r_list[cnt]; + + if (map->l_global == 0) + { + map->l_global = 1; ++ ++ /* The array has been resized by add_to_global_resize. */ ++ assert (new_nlist < ns->_ns_global_scope_alloc); ++ + ns->_ns_main_searchlist->r_list[new_nlist++] = map; + + /* We modify the global scope. Report this. */ +@@ -149,10 +181,15 @@ add_to_global (struct link_map *new) + map->l_name, map->l_ns); + } + } ++ ++ /* Some of the pending adds have been performed by the loop above. ++ Adjust the counter accordingly. */ ++ unsigned int added = new_nlist - ns->_ns_main_searchlist->r_nlist; ++ assert (added <= ns->_ns_global_scope_pending_adds); ++ ns->_ns_global_scope_pending_adds -= added; ++ + atomic_write_barrier (); + ns->_ns_main_searchlist->r_nlist = new_nlist; +- +- return 0; + } + + /* Search link maps in all namespaces for the DSO that contains the object at +@@ -225,6 +262,10 @@ dl_open_worker (void *a) + args->nsid = call_map->l_ns; + } + ++ /* Retain the old value, so that it can be restored. */ ++ args->original_global_scope_pending_adds ++ = GL (dl_ns)[args->nsid]._ns_global_scope_pending_adds; ++ + /* One might be tempted to assert that we are RT_CONSISTENT at this point, but that + may not be true if this is a recursive call to dlopen. */ + _dl_debug_initialize (0, args->nsid); +@@ -266,7 +307,10 @@ dl_open_worker (void *a) + /* If the user requested the object to be in the global namespace + but it is not so far, add it now. */ + if ((mode & RTLD_GLOBAL) && new->l_global == 0) +- (void) add_to_global (new); ++ { ++ add_to_global_resize (new); ++ add_to_global_update (new); ++ } + + assert (_dl_debug_initialize (0, args->nsid)->r_state == RT_CONSISTENT); + +@@ -523,6 +567,11 @@ TLS generation counter wrapped! Please report this.")); + DL_STATIC_INIT (new); + #endif + ++ /* Perform the necessary allocations for adding new global objects ++ to the global scope below, via add_to_global_update. */ ++ if (mode & RTLD_GLOBAL) ++ add_to_global_resize (new); ++ + /* Run the initializer functions of new objects. Temporarily + disable the exception handler, so that lazy binding failures are + fatal. */ +@@ -539,10 +588,7 @@ TLS generation counter wrapped! Please report this.")); + + /* Now we can make the new map available in the global scope. */ + if (mode & RTLD_GLOBAL) +- /* Move the object in the global namespace. */ +- if (add_to_global (new) != 0) +- /* It failed. */ +- return; ++ add_to_global_update (new); + + #ifndef SHARED + /* We must be the static _dl_open in libc.a. A static program that +@@ -556,7 +602,6 @@ TLS generation counter wrapped! Please report this.")); + new->l_name, new->l_ns, new->l_direct_opencount); + } + +- + void * + _dl_open (const char *file, int mode, const void *caller_dlopen, Lmid_t nsid, + int argc, char *argv[], char *env[]) +@@ -624,6 +669,19 @@ no more namespaces available for dlmopen()")); + _dl_unload_cache (); + #endif + ++ /* Do this for both the error and success cases. The old value has ++ only been determined if the namespace ID was assigned (i.e., it ++ is not __LM_ID_CALLER). In the success case, we actually may ++ have consumed more pending adds than planned (because the local ++ scopes overlap in case of a recursive dlopen, the inner dlopen ++ doing some of the globalization work of the outer dlopen), so the ++ old pending adds value is larger than absolutely necessary. ++ Since it is just a conservative upper bound, this is harmless. ++ The top-level dlopen call will restore the field to zero. */ ++ if (args.nsid >= 0) ++ GL (dl_ns)[args.nsid]._ns_global_scope_pending_adds ++ = args.original_global_scope_pending_adds; ++ + /* See if an error occurred during loading. */ + if (__glibc_unlikely (exception.errstring != NULL)) + { +diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h +index 6c5298a80bff8e96..57fbefea3cb841e9 100644 +--- a/sysdeps/generic/ldsodefs.h ++++ b/sysdeps/generic/ldsodefs.h +@@ -311,7 +311,14 @@ struct rtld_global + /* This is zero at program start to signal that the global scope map is + allocated by rtld. Later it keeps the size of the map. It might be + reset if in _dl_close if the last global object is removed. */ +- size_t _ns_global_scope_alloc; ++ unsigned int _ns_global_scope_alloc; ++ ++ /* During dlopen, this is the number of objects that still need to ++ be added to the global scope map. It has to be taken into ++ account when resizing the map, for future map additions after ++ recursive dlopen calls from ELF constructors. */ ++ unsigned int _ns_global_scope_pending_adds; ++ + /* Search table for unique objects. */ + struct unique_sym_table + { diff --git a/SOURCES/glibc-rh1410154-7.patch b/SOURCES/glibc-rh1410154-7.patch new file mode 100644 index 0000000..977a011 --- /dev/null +++ b/SOURCES/glibc-rh1410154-7.patch @@ -0,0 +1,490 @@ +commit a509eb117fac1d764b15eba64993f4bdb63d7f3c +Author: Florian Weimer +Date: Wed Nov 27 16:37:17 2019 +0100 + + Avoid late dlopen failure due to scope, TLS slotinfo updates [BZ #25112] + + This change splits the scope and TLS slotinfo updates in dlopen into + two parts: one to resize the data structures, and one to actually apply + the update. The call to add_to_global_resize in dl_open_worker is moved + before the demarcation point at which no further memory allocations are + allowed. + + _dl_add_to_slotinfo is adjusted to make the list update optional. There + is some optimization possibility here because we could grow the slotinfo + list of arrays in a single call, one the largest TLS modid is known. + + This commit does not fix the fatal meory allocation failure in + _dl_update_slotinfo. Ideally, this error during dlopen should be + recoverable. + + The update order of scopes and TLS data structures is retained, although + it appears to be more correct to fully initialize TLS first, and then + expose symbols in the newly loaded objects via the scope update. + + Tested on x86_64-linux-gnu. + + Change-Id: I240c58387dabda3ca1bcab48b02115175fa83d6c + +diff --git a/elf/dl-open.c b/elf/dl-open.c +index 85db4f0ecb5f29ce..b330cff7d349224a 100644 +--- a/elf/dl-open.c ++++ b/elf/dl-open.c +@@ -33,6 +33,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -214,6 +215,215 @@ _dl_find_dso_for_object (const ElfW(Addr) addr) + } + rtld_hidden_def (_dl_find_dso_for_object); + ++/* Return true if NEW is found in the scope for MAP. */ ++static size_t ++scope_has_map (struct link_map *map, struct link_map *new) ++{ ++ size_t cnt; ++ for (cnt = 0; map->l_scope[cnt] != NULL; ++cnt) ++ if (map->l_scope[cnt] == &new->l_searchlist) ++ return true; ++ return false; ++} ++ ++/* Return the length of the scope for MAP. */ ++static size_t ++scope_size (struct link_map *map) ++{ ++ size_t cnt; ++ for (cnt = 0; map->l_scope[cnt] != NULL; ) ++ ++cnt; ++ return cnt; ++} ++ ++/* Resize the scopes of depended-upon objects, so that the new object ++ can be added later without further allocation of memory. This ++ function can raise an exceptions due to malloc failure. */ ++static void ++resize_scopes (struct link_map *new) ++{ ++ /* If the file is not loaded now as a dependency, add the search ++ list of the newly loaded object to the scope. */ ++ for (unsigned int i = 0; i < new->l_searchlist.r_nlist; ++i) ++ { ++ struct link_map *imap = new->l_searchlist.r_list[i]; ++ ++ /* If the initializer has been called already, the object has ++ not been loaded here and now. */ ++ if (imap->l_init_called && imap->l_type == lt_loaded) ++ { ++ if (scope_has_map (imap, new)) ++ /* Avoid duplicates. */ ++ continue; ++ ++ size_t cnt = scope_size (imap); ++ if (__glibc_unlikely (cnt + 1 >= imap->l_scope_max)) ++ { ++ /* The l_scope array is too small. Allocate a new one ++ dynamically. */ ++ size_t new_size; ++ struct r_scope_elem **newp; ++ ++ if (imap->l_scope != imap->l_scope_mem ++ && imap->l_scope_max < array_length (imap->l_scope_mem)) ++ { ++ /* If the current l_scope memory is not pointing to ++ the static memory in the structure, but the ++ static memory in the structure is large enough to ++ use for cnt + 1 scope entries, then switch to ++ using the static memory. */ ++ new_size = array_length (imap->l_scope_mem); ++ newp = imap->l_scope_mem; ++ } ++ else ++ { ++ new_size = imap->l_scope_max * 2; ++ newp = (struct r_scope_elem **) ++ malloc (new_size * sizeof (struct r_scope_elem *)); ++ if (newp == NULL) ++ _dl_signal_error (ENOMEM, "dlopen", NULL, ++ N_("cannot create scope list")); ++ } ++ ++ /* Copy the array and the terminating NULL. */ ++ memcpy (newp, imap->l_scope, ++ (cnt + 1) * sizeof (imap->l_scope[0])); ++ struct r_scope_elem **old = imap->l_scope; ++ ++ imap->l_scope = newp; ++ ++ if (old != imap->l_scope_mem) ++ _dl_scope_free (old); ++ ++ imap->l_scope_max = new_size; ++ } ++ } ++ } ++} ++ ++/* Second stage of resize_scopes: Add NEW to the scopes. Also print ++ debugging information about scopes if requested. ++ ++ This function cannot raise an exception because all required memory ++ has been allocated by a previous call to resize_scopes. */ ++static void ++update_scopes (struct link_map *new) ++{ ++ for (unsigned int i = 0; i < new->l_searchlist.r_nlist; ++i) ++ { ++ struct link_map *imap = new->l_searchlist.r_list[i]; ++ int from_scope = 0; ++ ++ if (imap->l_init_called && imap->l_type == lt_loaded) ++ { ++ if (scope_has_map (imap, new)) ++ /* Avoid duplicates. */ ++ continue; ++ ++ size_t cnt = scope_size (imap); ++ /* Assert that resize_scopes has sufficiently enlarged the ++ array. */ ++ assert (cnt + 1 < imap->l_scope_max); ++ ++ /* First terminate the extended list. Otherwise a thread ++ might use the new last element and then use the garbage ++ at offset IDX+1. */ ++ imap->l_scope[cnt + 1] = NULL; ++ atomic_write_barrier (); ++ imap->l_scope[cnt] = &new->l_searchlist; ++ ++ from_scope = cnt; ++ } ++ ++ /* Print scope information. */ ++ if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_SCOPES)) ++ _dl_show_scope (imap, from_scope); ++ } ++} ++ ++/* Call _dl_add_to_slotinfo with DO_ADD set to false, to allocate ++ space in GL (dl_tls_dtv_slotinfo_list). This can raise an ++ exception. The return value is true if any of the new objects use ++ TLS. */ ++static bool ++resize_tls_slotinfo (struct link_map *new) ++{ ++ bool any_tls = false; ++ for (unsigned int i = 0; i < new->l_searchlist.r_nlist; ++i) ++ { ++ struct link_map *imap = new->l_searchlist.r_list[i]; ++ ++ /* Only add TLS memory if this object is loaded now and ++ therefore is not yet initialized. */ ++ if (! imap->l_init_called && imap->l_tls_blocksize > 0) ++ { ++ _dl_add_to_slotinfo (imap, false); ++ any_tls = true; ++ } ++ } ++ return any_tls; ++} ++ ++/* Second stage of TLS update, after resize_tls_slotinfo. This ++ function does not raise any exception. It should only be called if ++ resize_tls_slotinfo returned true. */ ++static void ++update_tls_slotinfo (struct link_map *new) ++{ ++ unsigned int first_static_tls = new->l_searchlist.r_nlist; ++ for (unsigned int i = 0; i < new->l_searchlist.r_nlist; ++i) ++ { ++ struct link_map *imap = new->l_searchlist.r_list[i]; ++ ++ /* Only add TLS memory if this object is loaded now and ++ therefore is not yet initialized. */ ++ if (! imap->l_init_called && imap->l_tls_blocksize > 0) ++ { ++ _dl_add_to_slotinfo (imap, true); ++ ++ if (imap->l_need_tls_init ++ && first_static_tls == new->l_searchlist.r_nlist) ++ first_static_tls = i; ++ } ++ } ++ ++ if (__builtin_expect (++GL(dl_tls_generation) == 0, 0)) ++ _dl_fatal_printf (N_("\ ++TLS generation counter wrapped! Please report this.")); ++ ++ /* We need a second pass for static tls data, because ++ _dl_update_slotinfo must not be run while calls to ++ _dl_add_to_slotinfo are still pending. */ ++ for (unsigned int i = first_static_tls; i < new->l_searchlist.r_nlist; ++i) ++ { ++ struct link_map *imap = new->l_searchlist.r_list[i]; ++ ++ if (imap->l_need_tls_init ++ && ! imap->l_init_called ++ && imap->l_tls_blocksize > 0) ++ { ++ /* For static TLS we have to allocate the memory here and ++ now, but we can delay updating the DTV. */ ++ imap->l_need_tls_init = 0; ++#ifdef SHARED ++ /* Update the slot information data for at least the ++ generation of the DSO we are allocating data for. */ ++ ++ /* FIXME: This can terminate the process on memory ++ allocation failure. It is not possible to raise ++ exceptions from this context; to fix this bug, ++ _dl_update_slotinfo would have to be split into two ++ operations, similar to resize_scopes and update_scopes ++ above. This is related to bug 16134. */ ++ _dl_update_slotinfo (imap->l_tls_modid); ++#endif ++ ++ GL(dl_init_static_tls) (imap); ++ assert (imap->l_need_tls_init == 0); ++ } ++ } ++} ++ + /* struct dl_init_args and call_dl_init are used to call _dl_init with + exception handling disabled. */ + struct dl_init_args +@@ -431,133 +641,40 @@ dl_open_worker (void *a) + relocation. */ + _dl_open_check (new); + +- /* If the file is not loaded now as a dependency, add the search +- list of the newly loaded object to the scope. */ +- bool any_tls = false; +- unsigned int first_static_tls = new->l_searchlist.r_nlist; +- for (unsigned int i = 0; i < new->l_searchlist.r_nlist; ++i) +- { +- struct link_map *imap = new->l_searchlist.r_list[i]; +- int from_scope = 0; ++ /* This only performs the memory allocations. The actual update of ++ the scopes happens below, after failure is impossible. */ ++ resize_scopes (new); + +- /* If the initializer has been called already, the object has +- not been loaded here and now. */ +- if (imap->l_init_called && imap->l_type == lt_loaded) +- { +- struct r_scope_elem **runp = imap->l_scope; +- size_t cnt = 0; +- +- while (*runp != NULL) +- { +- if (*runp == &new->l_searchlist) +- break; +- ++cnt; +- ++runp; +- } +- +- if (*runp != NULL) +- /* Avoid duplicates. */ +- continue; +- +- if (__glibc_unlikely (cnt + 1 >= imap->l_scope_max)) +- { +- /* The 'r_scope' array is too small. Allocate a new one +- dynamically. */ +- size_t new_size; +- struct r_scope_elem **newp; +- +-#define SCOPE_ELEMS(imap) \ +- (sizeof (imap->l_scope_mem) / sizeof (imap->l_scope_mem[0])) ++ /* Increase the size of the GL (dl_tls_dtv_slotinfo_list) data ++ structure. */ ++ bool any_tls = resize_tls_slotinfo (new); + +- if (imap->l_scope != imap->l_scope_mem +- && imap->l_scope_max < SCOPE_ELEMS (imap)) +- { +- new_size = SCOPE_ELEMS (imap); +- newp = imap->l_scope_mem; +- } +- else +- { +- new_size = imap->l_scope_max * 2; +- newp = (struct r_scope_elem **) +- malloc (new_size * sizeof (struct r_scope_elem *)); +- if (newp == NULL) +- _dl_signal_error (ENOMEM, "dlopen", NULL, +- N_("cannot create scope list")); +- } +- +- memcpy (newp, imap->l_scope, cnt * sizeof (imap->l_scope[0])); +- struct r_scope_elem **old = imap->l_scope; +- +- imap->l_scope = newp; +- +- if (old != imap->l_scope_mem) +- _dl_scope_free (old); +- +- imap->l_scope_max = new_size; +- } +- +- /* First terminate the extended list. Otherwise a thread +- might use the new last element and then use the garbage +- at offset IDX+1. */ +- imap->l_scope[cnt + 1] = NULL; +- atomic_write_barrier (); +- imap->l_scope[cnt] = &new->l_searchlist; +- +- /* Print only new scope information. */ +- from_scope = cnt; +- } +- /* Only add TLS memory if this object is loaded now and +- therefore is not yet initialized. */ +- else if (! imap->l_init_called +- /* Only if the module defines thread local data. */ +- && __builtin_expect (imap->l_tls_blocksize > 0, 0)) +- { +- /* Now that we know the object is loaded successfully add +- modules containing TLS data to the slot info table. We +- might have to increase its size. */ +- _dl_add_to_slotinfo (imap); +- +- if (imap->l_need_tls_init +- && first_static_tls == new->l_searchlist.r_nlist) +- first_static_tls = i; +- +- /* We have to bump the generation counter. */ +- any_tls = true; +- } +- +- /* Print scope information. */ +- if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_SCOPES)) +- _dl_show_scope (imap, from_scope); +- } +- +- /* Bump the generation number if necessary. */ +- if (any_tls && __builtin_expect (++GL(dl_tls_generation) == 0, 0)) +- _dl_fatal_printf (N_("\ +-TLS generation counter wrapped! Please report this.")); +- +- /* We need a second pass for static tls data, because _dl_update_slotinfo +- must not be run while calls to _dl_add_to_slotinfo are still pending. */ +- for (unsigned int i = first_static_tls; i < new->l_searchlist.r_nlist; ++i) +- { +- struct link_map *imap = new->l_searchlist.r_list[i]; +- +- if (imap->l_need_tls_init +- && ! imap->l_init_called +- && imap->l_tls_blocksize > 0) +- { +- /* For static TLS we have to allocate the memory here and +- now, but we can delay updating the DTV. */ +- imap->l_need_tls_init = 0; +-#ifdef SHARED +- /* Update the slot information data for at least the +- generation of the DSO we are allocating data for. */ +- _dl_update_slotinfo (imap->l_tls_modid); +-#endif ++ /* Perform the necessary allocations for adding new global objects ++ to the global scope below. */ ++ if (mode & RTLD_GLOBAL) ++ add_to_global_resize (new); + +- GL(dl_init_static_tls) (imap); +- assert (imap->l_need_tls_init == 0); +- } +- } ++ /* Demarcation point: After this, no recoverable errors are allowed. ++ All memory allocations for new objects must have happened ++ before. */ ++ ++ /* Second stage after resize_scopes: Actually perform the scope ++ update. After this, dlsym and lazy binding can bind to new ++ objects. */ ++ update_scopes (new); ++ ++ /* FIXME: It is unclear whether the order here is correct. ++ Shouldn't new objects be made available for binding (and thus ++ execution) only after there TLS data has been set up fully? ++ Fixing bug 16134 will likely make this distinction less ++ important. */ ++ ++ /* Second stage after resize_tls_slotinfo: Update the slotinfo data ++ structures. */ ++ if (any_tls) ++ /* FIXME: This calls _dl_update_slotinfo, which aborts the process ++ on memory allocation failure. See bug 16134. */ ++ update_tls_slotinfo (new); + + /* Notify the debugger all new objects have been relocated. */ + if (relocation_in_progress) +diff --git a/elf/dl-tls.c b/elf/dl-tls.c +index c87caf13d6a97ba4..a2def280b7096960 100644 +--- a/elf/dl-tls.c ++++ b/elf/dl-tls.c +@@ -883,7 +883,7 @@ _dl_tls_get_addr_soft (struct link_map *l) + + + void +-_dl_add_to_slotinfo (struct link_map *l) ++_dl_add_to_slotinfo (struct link_map *l, bool do_add) + { + /* Now that we know the object is loaded successfully add + modules containing TLS data to the dtv info table. We +@@ -939,6 +939,9 @@ cannot create TLS data structures")); + } + + /* Add the information into the slotinfo data structure. */ +- listp->slotinfo[idx].map = l; +- listp->slotinfo[idx].gen = GL(dl_tls_generation) + 1; ++ if (do_add) ++ { ++ listp->slotinfo[idx].map = l; ++ listp->slotinfo[idx].gen = GL(dl_tls_generation) + 1; ++ } + } +diff --git a/elf/rtld.c b/elf/rtld.c +index 4ec26a79cbb0aa4f..0aa1a2a19f649e16 100644 +--- a/elf/rtld.c ++++ b/elf/rtld.c +@@ -2167,7 +2167,7 @@ ERROR: ld.so: object '%s' cannot be loaded as audit interface: %s; ignored.\n", + + /* Add object to slot information data if necessasy. */ + if (l->l_tls_blocksize != 0 && tls_init_tp_called) +- _dl_add_to_slotinfo (l); ++ _dl_add_to_slotinfo (l, true); + } + } + else +@@ -2215,7 +2215,7 @@ ERROR: ld.so: object '%s' cannot be loaded as audit interface: %s; ignored.\n", + + /* Add object to slot information data if necessasy. */ + if (l->l_tls_blocksize != 0 && tls_init_tp_called) +- _dl_add_to_slotinfo (l); ++ _dl_add_to_slotinfo (l, true); + } + HP_TIMING_NOW (stop); + +diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h +index 57fbefea3cb841e9..c6b7e61badbfd513 100644 +--- a/sysdeps/generic/ldsodefs.h ++++ b/sysdeps/generic/ldsodefs.h +@@ -1135,8 +1135,15 @@ extern void *_dl_open (const char *name, int mode, const void *caller, + old scope, OLD can't be freed until no thread is using it. */ + extern int _dl_scope_free (void *) attribute_hidden; + +-/* Add module to slot information data. */ +-extern void _dl_add_to_slotinfo (struct link_map *l) attribute_hidden; ++ ++/* Add module to slot information data. If DO_ADD is false, only the ++ required memory is allocated. Must be called with GL ++ (dl_load_lock) acquired. If the function has already been called ++ for the link map L with !do_add, then this function will not raise ++ an exception, otherwise it is possible that it encounters a memory ++ allocation failure. */ ++extern void _dl_add_to_slotinfo (struct link_map *l, bool do_add) ++ attribute_hidden; + + /* Update slot information data for at least the generation of the + module with the given index. */ diff --git a/SOURCES/glibc-rh1410154-8.patch b/SOURCES/glibc-rh1410154-8.patch new file mode 100644 index 0000000..c22f32a --- /dev/null +++ b/SOURCES/glibc-rh1410154-8.patch @@ -0,0 +1,619 @@ +commit f63b73814f74032c0e5d0a83300e3d864ef905e5 +Author: Florian Weimer +Date: Wed Nov 13 15:44:56 2019 +0100 + + Remove all loaded objects if dlopen fails, ignoring NODELETE [BZ #20839] + + This introduces a “pending NODELETE” state in the link map, which is + flipped to the persistent NODELETE state late in dlopen, via + activate_nodelete. During initial relocation, symbol binding + records pending NODELETE state only. dlclose ignores pending NODELETE + state. Taken together, this results that a partially completed dlopen + is rolled back completely because new NODELETE mappings are unloaded. + + Tested on x86_64-linux-gnu and i386-linux-gnu. + + Change-Id: Ib2a3d86af6f92d75baca65431d74783ee0dbc292 + +Conflicts: + elf/Makefile + (Usual conflicts due to test backport differences.) + +diff --git a/elf/Makefile b/elf/Makefile +index b752f6366400d221..bf7c41f38be42184 100644 +--- a/elf/Makefile ++++ b/elf/Makefile +@@ -191,7 +191,8 @@ tests += restest1 preloadtest loadfail multiload origtest resolvfail \ + 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-sonamemove-link tst-sonamemove-dlopen tst-initfinilazyfail ++ tst-sonamemove-link tst-sonamemove-dlopen tst-initfinilazyfail \ ++ tst-dlopenfail + # reldep9 + tests-internal += loadtest unload unload2 circleload1 \ + neededtest neededtest2 neededtest3 neededtest4 \ +@@ -282,7 +283,8 @@ modules-names = testobj1 testobj2 testobj3 testobj4 testobj5 testobj6 \ + tst-absolute-zero-lib tst-big-note-lib \ + tst-sonamemove-linkmod1 \ + tst-sonamemove-runmod1 tst-sonamemove-runmod2 \ +- tst-initlazyfailmod tst-finilazyfailmod ++ tst-initlazyfailmod tst-finilazyfailmod \ ++ tst-dlopenfailmod1 tst-dlopenfaillinkmod tst-dlopenfailmod2 + + ifeq (yes,$(have-mtls-dialect-gnu2)) + tests += tst-gnu2-tls1 +@@ -1537,3 +1539,13 @@ LDFLAGS-tst-initlazyfailmod.so = \ + -Wl,-z,lazy -Wl,--unresolved-symbols=ignore-all + LDFLAGS-tst-finilazyfailmod.so = \ + -Wl,-z,lazy -Wl,--unresolved-symbols=ignore-all ++ ++$(objpfx)tst-dlopenfail: $(libdl) ++$(objpfx)tst-dlopenfail.out: \ ++ $(objpfx)tst-dlopenfailmod1.so $(objpfx)tst-dlopenfailmod2.so ++# Order matters here. tst-dlopenfaillinkmod.so's soname ensures ++# a run-time loader failure. ++$(objpfx)tst-dlopenfailmod1.so: \ ++ $(shared-thread-library) $(objpfx)tst-dlopenfaillinkmod.so ++LDFLAGS-tst-dlopenfaillinkmod.so = -Wl,-soname,tst-dlopenfail-missingmod.so ++$(objpfx)tst-dlopenfailmod2.so: $(shared-thread-library) +diff --git a/elf/dl-close.c b/elf/dl-close.c +index 88aeea25839a34e0..243a028c443173c1 100644 +--- a/elf/dl-close.c ++++ b/elf/dl-close.c +@@ -168,14 +168,6 @@ _dl_close_worker (struct link_map *map, bool force) + char done[nloaded]; + struct link_map *maps[nloaded]; + +- /* Clear DF_1_NODELETE to force object deletion. We don't need to touch +- l_tls_dtor_count because forced object deletion only happens when an +- error occurs during object load. Destructor registration for TLS +- non-POD objects should not have happened till then for this +- object. */ +- if (force) +- map->l_flags_1 &= ~DF_1_NODELETE; +- + /* Run over the list and assign indexes to the link maps and enter + them into the MAPS array. */ + int idx = 0; +@@ -205,7 +197,7 @@ _dl_close_worker (struct link_map *map, bool force) + /* Check whether this object is still used. */ + if (l->l_type == lt_loaded + && l->l_direct_opencount == 0 +- && (l->l_flags_1 & DF_1_NODELETE) == 0 ++ && l->l_nodelete != link_map_nodelete_active + /* 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 +@@ -288,7 +280,7 @@ _dl_close_worker (struct link_map *map, bool force) + if (!used[i]) + { + assert (imap->l_type == lt_loaded +- && (imap->l_flags_1 & DF_1_NODELETE) == 0); ++ && imap->l_nodelete != link_map_nodelete_active); + + /* Call its termination function. Do not do it for + half-cooked objects. Temporarily disable exception +@@ -828,7 +820,7 @@ _dl_close (void *_map) + before we took the lock. There is no way to detect this (see below) + so we proceed assuming this isn't the case. First see whether we + can remove the object at all. */ +- if (__glibc_unlikely (map->l_flags_1 & DF_1_NODELETE)) ++ if (__glibc_unlikely (map->l_nodelete == link_map_nodelete_active)) + { + /* Nope. Do nothing. */ + __rtld_lock_unlock_recursive (GL(dl_load_lock)); +diff --git a/elf/dl-lookup.c b/elf/dl-lookup.c +index efbdb8deb3c0a9d4..c5e5857fb1fe2808 100644 +--- a/elf/dl-lookup.c ++++ b/elf/dl-lookup.c +@@ -192,9 +192,10 @@ enter_unique_sym (struct unique_sym *table, size_t size, + Return the matching symbol in RESULT. */ + static void + do_lookup_unique (const char *undef_name, uint_fast32_t new_hash, +- const struct link_map *map, struct sym_val *result, ++ struct link_map *map, struct sym_val *result, + int type_class, const ElfW(Sym) *sym, const char *strtab, +- const ElfW(Sym) *ref, const struct link_map *undef_map) ++ const ElfW(Sym) *ref, const struct link_map *undef_map, ++ int flags) + { + /* We have to determine whether we already found a symbol with this + name before. If not then we have to add it to the search table. +@@ -222,7 +223,7 @@ do_lookup_unique (const char *undef_name, uint_fast32_t new_hash, + copy from the copy addressed through the + relocation. */ + result->s = sym; +- result->m = (struct link_map *) map; ++ result->m = map; + } + else + { +@@ -311,9 +312,19 @@ do_lookup_unique (const char *undef_name, uint_fast32_t new_hash, + new_hash, strtab + sym->st_name, sym, map); + + if (map->l_type == lt_loaded) +- /* Make sure we don't unload this object by +- setting the appropriate flag. */ +- ((struct link_map *) map)->l_flags_1 |= DF_1_NODELETE; ++ { ++ /* Make sure we don't unload this object by ++ setting the appropriate flag. */ ++ if (__glibc_unlikely (GLRO (dl_debug_mask) & DL_DEBUG_BINDINGS) ++ && map->l_nodelete == link_map_nodelete_inactive) ++ _dl_debug_printf ("\ ++marking %s [%lu] as NODELETE due to unique symbol\n", ++ map->l_name, map->l_ns); ++ if (flags & DL_LOOKUP_FOR_RELOCATE) ++ map->l_nodelete = link_map_nodelete_pending; ++ else ++ map->l_nodelete = link_map_nodelete_active; ++ } + } + ++tab->n_elements; + +@@ -525,8 +536,9 @@ do_lookup_x (const char *undef_name, uint_fast32_t new_hash, + return 1; + + case STB_GNU_UNIQUE:; +- do_lookup_unique (undef_name, new_hash, map, result, type_class, +- sym, strtab, ref, undef_map); ++ do_lookup_unique (undef_name, new_hash, (struct link_map *) map, ++ result, type_class, sym, strtab, ref, ++ undef_map, flags); + return 1; + + default: +@@ -568,9 +580,13 @@ add_dependency (struct link_map *undef_map, struct link_map *map, int flags) + if (undef_map == map) + return 0; + +- /* Avoid references to objects which cannot be unloaded anyway. */ ++ /* Avoid references to objects which cannot be unloaded anyway. We ++ do not need to record dependencies if this object goes away ++ during dlopen failure, either. IFUNC resolvers with relocation ++ dependencies may pick an dependency which can be dlclose'd, but ++ such IFUNC resolvers are undefined anyway. */ + assert (map->l_type == lt_loaded); +- if ((map->l_flags_1 & DF_1_NODELETE) != 0) ++ if (map->l_nodelete != link_map_nodelete_inactive) + return 0; + + struct link_map_reldeps *l_reldeps +@@ -678,16 +694,33 @@ add_dependency (struct link_map *undef_map, struct link_map *map, int flags) + + /* Redo the NODELETE check, as when dl_load_lock wasn't held + yet this could have changed. */ +- if ((map->l_flags_1 & DF_1_NODELETE) != 0) ++ if (map->l_nodelete != link_map_nodelete_inactive) + goto out; + + /* If the object with the undefined reference cannot be removed ever + just make sure the same is true for the object which contains the + definition. */ + if (undef_map->l_type != lt_loaded +- || (undef_map->l_flags_1 & DF_1_NODELETE) != 0) ++ || (undef_map->l_nodelete != link_map_nodelete_inactive)) + { +- map->l_flags_1 |= DF_1_NODELETE; ++ if (__glibc_unlikely (GLRO (dl_debug_mask) & DL_DEBUG_BINDINGS) ++ && map->l_nodelete == link_map_nodelete_inactive) ++ { ++ if (undef_map->l_name[0] == '\0') ++ _dl_debug_printf ("\ ++marking %s [%lu] as NODELETE due to reference to main program\n", ++ map->l_name, map->l_ns); ++ else ++ _dl_debug_printf ("\ ++marking %s [%lu] as NODELETE due to reference to %s [%lu]\n", ++ map->l_name, map->l_ns, ++ undef_map->l_name, undef_map->l_ns); ++ } ++ ++ if (flags & DL_LOOKUP_FOR_RELOCATE) ++ map->l_nodelete = link_map_nodelete_pending; ++ else ++ map->l_nodelete = link_map_nodelete_active; + goto out; + } + +@@ -712,7 +745,18 @@ add_dependency (struct link_map *undef_map, struct link_map *map, int flags) + no fatal problem. We simply make sure the referenced object + cannot be unloaded. This is semantically the correct + behavior. */ +- map->l_flags_1 |= DF_1_NODELETE; ++ if (__glibc_unlikely (GLRO (dl_debug_mask) & DL_DEBUG_BINDINGS) ++ && map->l_nodelete == link_map_nodelete_inactive) ++ _dl_debug_printf ("\ ++marking %s [%lu] as NODELETE due to memory allocation failure\n", ++ map->l_name, map->l_ns); ++ if (flags & DL_LOOKUP_FOR_RELOCATE) ++ /* In case of non-lazy binding, we could actually ++ report the memory allocation error, but for now, we ++ use the conservative approximation as well. */ ++ map->l_nodelete = link_map_nodelete_pending; ++ else ++ map->l_nodelete = link_map_nodelete_active; + goto out; + } + else +diff --git a/elf/dl-open.c b/elf/dl-open.c +index b330cff7d349224a..79c6e4c8ed1c9dfa 100644 +--- a/elf/dl-open.c ++++ b/elf/dl-open.c +@@ -424,6 +424,40 @@ TLS generation counter wrapped! Please report this.")); + } + } + ++/* Mark the objects as NODELETE if required. This is delayed until ++ after dlopen failure is not possible, so that _dl_close can clean ++ up objects if necessary. */ ++static void ++activate_nodelete (struct link_map *new, int mode) ++{ ++ if (mode & RTLD_NODELETE || new->l_nodelete == link_map_nodelete_pending) ++ { ++ if (__glibc_unlikely (GLRO (dl_debug_mask) & DL_DEBUG_FILES)) ++ _dl_debug_printf ("activating NODELETE for %s [%lu]\n", ++ new->l_name, new->l_ns); ++ new->l_nodelete = link_map_nodelete_active; ++ } ++ ++ for (unsigned int i = 0; i < new->l_searchlist.r_nlist; ++i) ++ { ++ struct link_map *imap = new->l_searchlist.r_list[i]; ++ if (imap->l_nodelete == link_map_nodelete_pending) ++ { ++ if (__glibc_unlikely (GLRO (dl_debug_mask) & DL_DEBUG_FILES)) ++ _dl_debug_printf ("activating NODELETE for %s [%lu]\n", ++ imap->l_name, imap->l_ns); ++ ++ /* Only new objects should have set ++ link_map_nodelete_pending. Existing objects should not ++ have gained any new dependencies and therefore cannot ++ reach NODELETE status. */ ++ assert (!imap->l_init_called || imap->l_type != lt_loaded); ++ ++ imap->l_nodelete = link_map_nodelete_active; ++ } ++ } ++} ++ + /* struct dl_init_args and call_dl_init are used to call _dl_init with + exception handling disabled. */ + struct dl_init_args +@@ -493,12 +527,6 @@ dl_open_worker (void *a) + return; + } + +- /* Mark the object as not deletable if the RTLD_NODELETE flags was passed. +- Do this early so that we don't skip marking the object if it was +- already loaded. */ +- if (__glibc_unlikely (mode & RTLD_NODELETE)) +- new->l_flags_1 |= DF_1_NODELETE; +- + if (__glibc_unlikely (mode & __RTLD_SPROF)) + /* This happens only if we load a DSO for 'sprof'. */ + return; +@@ -514,19 +542,37 @@ dl_open_worker (void *a) + _dl_debug_printf ("opening file=%s [%lu]; direct_opencount=%u\n\n", + new->l_name, new->l_ns, new->l_direct_opencount); + +- /* If the user requested the object to be in the global namespace +- but it is not so far, add it now. */ ++ /* If the user requested the object to be in the global ++ namespace but it is not so far, prepare to add it now. This ++ can raise an exception to do a malloc failure. */ + if ((mode & RTLD_GLOBAL) && new->l_global == 0) ++ add_to_global_resize (new); ++ ++ /* Mark the object as not deletable if the RTLD_NODELETE flags ++ was passed. */ ++ if (__glibc_unlikely (mode & RTLD_NODELETE)) + { +- add_to_global_resize (new); +- add_to_global_update (new); ++ if (__glibc_unlikely (GLRO (dl_debug_mask) & DL_DEBUG_FILES) ++ && new->l_nodelete == link_map_nodelete_inactive) ++ _dl_debug_printf ("marking %s [%lu] as NODELETE\n", ++ new->l_name, new->l_ns); ++ new->l_nodelete = link_map_nodelete_active; + } + ++ /* Finalize the addition to the global scope. */ ++ if ((mode & RTLD_GLOBAL) && new->l_global == 0) ++ add_to_global_update (new); ++ + assert (_dl_debug_initialize (0, args->nsid)->r_state == RT_CONSISTENT); + + return; + } + ++ /* Schedule NODELETE marking for the directly loaded object if ++ requested. */ ++ if (__glibc_unlikely (mode & RTLD_NODELETE)) ++ new->l_nodelete = link_map_nodelete_pending; ++ + /* Load that object's dependencies. */ + _dl_map_object_deps (new, NULL, 0, 0, + mode & (__RTLD_DLOPEN | RTLD_DEEPBIND | __RTLD_AUDIT)); +@@ -598,6 +644,14 @@ dl_open_worker (void *a) + + int relocation_in_progress = 0; + ++ /* Perform relocation. This can trigger lazy binding in IFUNC ++ resolvers. For NODELETE mappings, these dependencies are not ++ recorded because the flag has not been applied to the newly ++ loaded objects. This means that upon dlopen failure, these ++ NODELETE objects can be unloaded despite existing references to ++ them. However, such relocation dependencies in IFUNC resolvers ++ are undefined anyway, so this is not a problem. */ ++ + for (unsigned int i = nmaps; i-- > 0; ) + { + l = maps[i]; +@@ -627,7 +681,7 @@ dl_open_worker (void *a) + _dl_start_profile (); + + /* Prevent unloading the object. */ +- GL(dl_profile_map)->l_flags_1 |= DF_1_NODELETE; ++ GL(dl_profile_map)->l_nodelete = link_map_nodelete_active; + } + } + else +@@ -658,6 +712,8 @@ dl_open_worker (void *a) + All memory allocations for new objects must have happened + before. */ + ++ activate_nodelete (new, mode); ++ + /* Second stage after resize_scopes: Actually perform the scope + update. After this, dlsym and lazy binding can bind to new + objects. */ +@@ -817,6 +873,10 @@ no more namespaces available for dlmopen()")); + GL(dl_tls_dtv_gaps) = true; + + _dl_close_worker (args.map, true); ++ ++ /* All link_map_nodelete_pending objects should have been ++ deleted at this point, which is why it is not necessary ++ to reset the flag here. */ + } + + assert (_dl_debug_initialize (0, args.nsid)->r_state == RT_CONSISTENT); +diff --git a/elf/get-dynamic-info.h b/elf/get-dynamic-info.h +index 4b1ea7c4078ee947..ea286abaea0128d1 100644 +--- a/elf/get-dynamic-info.h ++++ b/elf/get-dynamic-info.h +@@ -163,6 +163,8 @@ elf_get_dynamic_info (struct link_map *l, ElfW(Dyn) *temp) + if (info[VERSYMIDX (DT_FLAGS_1)] != NULL) + { + l->l_flags_1 = info[VERSYMIDX (DT_FLAGS_1)]->d_un.d_val; ++ if (l->l_flags_1 & DF_1_NODELETE) ++ l->l_nodelete = link_map_nodelete_pending; + + /* Only DT_1_SUPPORTED_MASK bits are supported, and we would like + to assert this, but we can't. Users have been setting +diff --git a/elf/tst-dlopenfail.c b/elf/tst-dlopenfail.c +new file mode 100644 +index 0000000000000000..ce3140c899562ca8 +--- /dev/null ++++ b/elf/tst-dlopenfail.c +@@ -0,0 +1,79 @@ ++/* Test dlopen rollback after failures involving NODELETE objects (bug 20839). ++ 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, see ++ . */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++static int ++do_test (void) ++{ ++ /* This test uses libpthread as the canonical NODELETE module. If ++ libpthread is no longer NODELETE because it has been merged into ++ libc, the test needs to be updated. */ ++ TEST_VERIFY (dlsym (NULL, "pthread_create") == NULL); ++ ++ /* This is expected to fail because of the missing dependency. */ ++ puts ("info: attempting to load tst-dlopenfailmod1.so"); ++ TEST_VERIFY (dlopen ("tst-dlopenfailmod1.so", RTLD_LAZY) == NULL); ++ const char *message = dlerror (); ++ TEST_COMPARE_STRING (message, ++ "tst-dlopenfail-missingmod.so:" ++ " cannot open shared object file:" ++ " No such file or directory"); ++ ++ /* Do not probe for the presence of libpthread at this point because ++ that might trigger relocation if bug 20839 is present, obscuring ++ a subsequent crash. */ ++ ++ /* This is expected to succeed. */ ++ puts ("info: loading tst-dlopenfailmod2.so"); ++ void *handle = xdlopen ("tst-dlopenfailmod2.so", RTLD_NOW); ++ xdlclose (handle); ++ ++ /* libpthread should remain loaded. */ ++ TEST_VERIFY (dlopen (LIBPTHREAD_SO, RTLD_LAZY | RTLD_NOLOAD) != NULL); ++ TEST_VERIFY (dlsym (NULL, "pthread_create") == NULL); ++ ++ /* We can make libpthread global, and then the symbol should become ++ available. */ ++ TEST_VERIFY (dlopen (LIBPTHREAD_SO, RTLD_LAZY | RTLD_GLOBAL) != NULL); ++ TEST_VERIFY (dlsym (NULL, "pthread_create") != NULL); ++ ++ /* sem_open is sufficiently complex to depend on relocations. */ ++ void *(*sem_open_ptr) (const char *, int flag, ...) ++ = dlsym (NULL, "sem_open"); ++ if (sem_open_ptr == NULL) ++ /* Hurd does not implement sem_open. */ ++ puts ("warning: sem_open not found, further testing not possible"); ++ else ++ { ++ errno = 0; ++ TEST_VERIFY (sem_open_ptr ("/", 0) == NULL); ++ TEST_COMPARE (errno, EINVAL); ++ } ++ ++ return 0; ++} ++ ++#include +diff --git a/elf/tst-dlopenfaillinkmod.c b/elf/tst-dlopenfaillinkmod.c +new file mode 100644 +index 0000000000000000..3b14b02bc9a12c0b +--- /dev/null ++++ b/elf/tst-dlopenfaillinkmod.c +@@ -0,0 +1,17 @@ ++/* Empty module with a soname which is not available at run time. ++ 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, see ++ . */ +diff --git a/elf/tst-dlopenfailmod1.c b/elf/tst-dlopenfailmod1.c +new file mode 100644 +index 0000000000000000..6ef48829899a5a64 +--- /dev/null ++++ b/elf/tst-dlopenfailmod1.c +@@ -0,0 +1,36 @@ ++/* Module which depends on two modules: one NODELETE, one missing. ++ 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, see ++ . */ ++ ++/* Note: Due to the missing second module, this object cannot be ++ loaded at run time. */ ++ ++#include ++#include ++#include ++ ++/* Force linking against libpthread. */ ++void *pthread_create_reference = pthread_create; ++ ++/* The constructor will never be executed because the module cannot be ++ loaded. */ ++static void __attribute__ ((constructor)) ++init (void) ++{ ++ puts ("tst-dlopenfailmod1 constructor executed"); ++ _exit (1); ++} +diff --git a/elf/tst-dlopenfailmod2.c b/elf/tst-dlopenfailmod2.c +new file mode 100644 +index 0000000000000000..7d600386c13b98bd +--- /dev/null ++++ b/elf/tst-dlopenfailmod2.c +@@ -0,0 +1,29 @@ ++/* Module which depends on on a NODELETE module, and can be loaded. ++ 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, see ++ . */ ++ ++#include ++#include ++ ++/* Force linking against libpthread. */ ++void *pthread_create_reference = pthread_create; ++ ++static void __attribute__ ((constructor)) ++init (void) ++{ ++ puts ("info: tst-dlopenfailmod2.so constructor invoked"); ++} +diff --git a/include/link.h b/include/link.h +index 83b1c34b7b4db8f3..a277b77cad6b52b1 100644 +--- a/include/link.h ++++ b/include/link.h +@@ -79,6 +79,21 @@ struct r_search_path_struct + int malloced; + }; + ++/* Type used by the l_nodelete member. */ ++enum link_map_nodelete ++{ ++ /* This link map can be deallocated. */ ++ link_map_nodelete_inactive = 0, /* Zero-initialized in _dl_new_object. */ ++ ++ /* This link map cannot be deallocated. */ ++ link_map_nodelete_active, ++ ++ /* This link map cannot be deallocated after dlopen has succeded. ++ dlopen turns this into link_map_nodelete_active. dlclose treats ++ this intermediate state as link_map_nodelete_active. */ ++ link_map_nodelete_pending, ++}; ++ + + /* Structure describing a loaded shared object. The `l_next' and `l_prev' + members form a chain of all the shared objects loaded at startup. +@@ -203,6 +218,11 @@ struct link_map + freed, ie. not allocated with + the dummy malloc in ld.so. */ + ++ /* Actually of type enum link_map_nodelete. Separate byte due to ++ a read in add_dependency in elf/dl-lookup.c outside the loader ++ lock. Only valid for l_type == lt_loaded. */ ++ unsigned char l_nodelete; ++ + #include + + /* Collected information about own RPATH directories. */ diff --git a/SOURCES/glibc-rh1410154-9.patch b/SOURCES/glibc-rh1410154-9.patch new file mode 100644 index 0000000..ab5a3df --- /dev/null +++ b/SOURCES/glibc-rh1410154-9.patch @@ -0,0 +1,104 @@ +commit a2e8aa0d9ea648068d8be52dd7b15f1b6a008e23 +Author: Florian Weimer +Date: Thu Oct 31 19:30:19 2019 +0100 + + Block signals during the initial part of dlopen + + Lazy binding in a signal handler that interrupts a dlopen sees + intermediate dynamic linker state. This has likely been always + unsafe, but with the new pending NODELETE state, this is clearly + incorrect. Other threads are excluded via the loader lock, but the + current thread is not. Blocking signals until right before ELF + constructors run is the safe thing to do. + + Change-Id: Iad079080ebe7442c13313ba11dc2797953faef35 + +diff --git a/elf/dl-open.c b/elf/dl-open.c +index 79c6e4c8ed1c9dfa..25838b073ac1edaf 100644 +--- a/elf/dl-open.c ++++ b/elf/dl-open.c +@@ -34,6 +34,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -52,6 +53,10 @@ struct dl_open_args + /* Namespace ID. */ + Lmid_t nsid; + ++ /* Original signal mask. Used for unblocking signal handlers before ++ running ELF constructors. */ ++ sigset_t original_signal_mask; ++ + /* Original value of _ns_global_scope_pending_adds. Set by + dl_open_worker. Only valid if nsid is a real namespace + (non-negative). */ +@@ -524,12 +529,16 @@ dl_open_worker (void *a) + if (new == NULL) + { + assert (mode & RTLD_NOLOAD); ++ __libc_signal_restore_set (&args->original_signal_mask); + return; + } + + if (__glibc_unlikely (mode & __RTLD_SPROF)) +- /* This happens only if we load a DSO for 'sprof'. */ +- return; ++ { ++ /* This happens only if we load a DSO for 'sprof'. */ ++ __libc_signal_restore_set (&args->original_signal_mask); ++ return; ++ } + + /* This object is directly loaded. */ + ++new->l_direct_opencount; +@@ -565,6 +574,7 @@ dl_open_worker (void *a) + + assert (_dl_debug_initialize (0, args->nsid)->r_state == RT_CONSISTENT); + ++ __libc_signal_restore_set (&args->original_signal_mask); + return; + } + +@@ -745,6 +755,10 @@ dl_open_worker (void *a) + if (mode & RTLD_GLOBAL) + add_to_global_resize (new); + ++ /* Unblock signals. Data structures are now consistent, and ++ application code may run. */ ++ __libc_signal_restore_set (&args->original_signal_mask); ++ + /* Run the initializer functions of new objects. Temporarily + disable the exception handler, so that lazy binding failures are + fatal. */ +@@ -834,6 +848,10 @@ no more namespaces available for dlmopen()")); + args.argv = argv; + args.env = env; + ++ /* Recursive lazy binding during manipulation of the dynamic loader ++ structures may result in incorrect behavior. */ ++ __libc_signal_block_all (&args.original_signal_mask); ++ + struct dl_exception exception; + int errcode = _dl_catch_exception (&exception, dl_open_worker, &args); + +@@ -874,10 +892,16 @@ no more namespaces available for dlmopen()")); + + _dl_close_worker (args.map, true); + ++ /* Restore the signal mask. In the success case, this ++ happens inside dl_open_worker. */ ++ __libc_signal_restore_set (&args.original_signal_mask); ++ + /* All link_map_nodelete_pending objects should have been + deleted at this point, which is why it is not necessary + to reset the flag here. */ + } ++ else ++ __libc_signal_restore_set (&args.original_signal_mask); + + assert (_dl_debug_initialize (0, args.nsid)->r_state == RT_CONSISTENT); + diff --git a/SOURCES/glibc-rh1577365.patch b/SOURCES/glibc-rh1577365.patch new file mode 100644 index 0000000..c1e30d4 --- /dev/null +++ b/SOURCES/glibc-rh1577365.patch @@ -0,0 +1,22 @@ +Please see the following bug for a complete summary: +https://bugzilla.redhat.com/show_bug.cgi?id=1615608 + +Index: glibc-2.28/manual/startup.texi +=================================================================== +--- glibc-2.28.orig/manual/startup.texi ++++ glibc-2.28/manual/startup.texi +@@ -1005,14 +1005,6 @@ This function actually terminates the pr + intercept this signal; see @ref{Signal Handling}. + @end deftypefun + +-@c Put in by rms. Don't remove. +-@cartouche +-@strong{Future Change Warning:} Proposed Federal censorship regulations +-may prohibit us from giving you information about the possibility of +-calling this function. We would be required to say that this is not an +-acceptable way of terminating a program. +-@end cartouche +- + @node Termination Internals + @subsection Termination Internals + diff --git a/SOURCES/glibc-rh1577438.patch b/SOURCES/glibc-rh1577438.patch new file mode 100644 index 0000000..aab01cc --- /dev/null +++ b/SOURCES/glibc-rh1577438.patch @@ -0,0 +1,24 @@ +Patch by Hanataka Shinya from +. Confirmed by TAMUKI +Shoichi's patch in +. + +The official announcement by the Japanese Prime Minister in + uses U+4EE4 U+548C +as well. + +diff --git a/localedata/locales/ja_JP b/localedata/locales/ja_JP +index 1fd2fee44b2879d9..30190b624856cc53 100644 +--- a/localedata/locales/ja_JP ++++ b/localedata/locales/ja_JP +@@ -14946,7 +14946,9 @@ am_pm "";"" + + t_fmt_ampm "%p%I%M%S" + +-era "+:2:1990//01//01:+*::%EC%Ey";/ ++era "+:2:2020//01//01:+*::%EC%Ey";/ ++ "+:1:2019//05//01:2019//12//31::%EC";/ ++ "+:2:1990//01//01:2019//04//30::%EC%Ey";/ + "+:1:1989//01//08:1989//12//31::%EC";/ + "+:2:1927//01//01:1989//01//07::%EC%Ey";/ + "+:1:1926//12//25:1926//12//31::%EC";/ diff --git a/SOURCES/glibc-rh1614253.patch b/SOURCES/glibc-rh1614253.patch new file mode 100644 index 0000000..ae4b43d --- /dev/null +++ b/SOURCES/glibc-rh1614253.patch @@ -0,0 +1,254 @@ +commit 4b25485f03158959cff45379eecc1d73c7dcdd11 +Author: Florian Weimer +Date: Fri Aug 10 11:19:26 2018 +0200 + + Linux: Rewrite __old_getdents64 [BZ #23497] + + Commit 298d0e3129c0b5137f4989275b13fe30d0733c4d ("Consolidate Linux + getdents{64} implementation") broke the implementation because it does + not take into account struct offset differences. + + The new implementation is close to the old one, before the + consolidation, but has been cleaned up slightly. + + (cherry picked from commit 690652882b499defb3d950dfeff8fe421d13cab5) + +diff --git a/sysdeps/unix/sysv/linux/Makefile b/sysdeps/unix/sysv/linux/Makefile +index f71cc39c7e257a0a..773aaea0e980bdd6 100644 +--- a/sysdeps/unix/sysv/linux/Makefile ++++ b/sysdeps/unix/sysv/linux/Makefile +@@ -161,6 +161,7 @@ inhibit-glue = yes + + ifeq ($(subdir),dirent) + sysdep_routines += getdirentries getdirentries64 ++tests-internal += tst-readdir64-compat + endif + + ifeq ($(subdir),nis) +diff --git a/sysdeps/unix/sysv/linux/getdents64.c b/sysdeps/unix/sysv/linux/getdents64.c +index 3bde0cf4f0226f95..bc140b5a7fac3040 100644 +--- a/sysdeps/unix/sysv/linux/getdents64.c ++++ b/sysdeps/unix/sysv/linux/getdents64.c +@@ -33,41 +33,80 @@ strong_alias (__getdents64, __getdents) + # include + + # if SHLIB_COMPAT(libc, GLIBC_2_1, GLIBC_2_2) +-# include ++# include ++# include + +-/* kernel definition of as of 3.2. */ +-struct compat_linux_dirent ++static ssize_t ++handle_overflow (int fd, __off64_t offset, ssize_t count) + { +- /* Both d_ino and d_off are compat_ulong_t which are defined in all +- architectures as 'u32'. */ +- uint32_t d_ino; +- uint32_t d_off; +- unsigned short d_reclen; +- char d_name[1]; +-}; ++ /* If this is the first entry in the buffer, we can report the ++ error. */ ++ if (count == 0) ++ { ++ __set_errno (EOVERFLOW); ++ return -1; ++ } ++ ++ /* Otherwise, seek to the overflowing entry, so that the next call ++ will report the error, and return the data read so far.. */ ++ if (__lseek64 (fd, offset, SEEK_SET) != 0) ++ return -1; ++ return count; ++} + + ssize_t + __old_getdents64 (int fd, char *buf, size_t nbytes) + { +- ssize_t retval = INLINE_SYSCALL_CALL (getdents, fd, buf, nbytes); ++ /* We do not move the individual directory entries. This is only ++ possible if the target type (struct __old_dirent64) is smaller ++ than the source type. */ ++ _Static_assert (offsetof (struct __old_dirent64, d_name) ++ <= offsetof (struct dirent64, d_name), ++ "__old_dirent64 is larger than dirent64"); ++ _Static_assert (__alignof__ (struct __old_dirent64) ++ <= __alignof__ (struct dirent64), ++ "alignment of __old_dirent64 is larger than dirent64"); + +- /* The kernel added the d_type value after the name. Change this now. */ +- if (retval != -1) ++ ssize_t retval = INLINE_SYSCALL_CALL (getdents64, fd, buf, nbytes); ++ if (retval > 0) + { +- union +- { +- struct compat_linux_dirent k; +- struct dirent u; +- } *kbuf = (void *) buf; +- +- while ((char *) kbuf < buf + retval) ++ char *p = buf; ++ char *end = buf + retval; ++ while (p < end) + { +- char d_type = *((char *) kbuf + kbuf->k.d_reclen - 1); +- memmove (kbuf->u.d_name, kbuf->k.d_name, +- strlen (kbuf->k.d_name) + 1); +- kbuf->u.d_type = d_type; ++ struct dirent64 *source = (struct dirent64 *) p; ++ ++ /* Copy out the fixed-size data. */ ++ __ino_t ino = source->d_ino; ++ __off64_t offset = source->d_off; ++ unsigned int reclen = source->d_reclen; ++ unsigned char type = source->d_type; ++ ++ /* Check for ino_t overflow. */ ++ if (__glibc_unlikely (ino != source->d_ino)) ++ return handle_overflow (fd, offset, p - buf); ++ ++ /* Convert to the target layout. Use a separate struct and ++ memcpy to side-step aliasing issues. */ ++ struct __old_dirent64 result; ++ result.d_ino = ino; ++ result.d_off = offset; ++ result.d_reclen = reclen; ++ result.d_type = type; ++ ++ /* Write the fixed-sized part of the result to the ++ buffer. */ ++ size_t result_name_offset = offsetof (struct __old_dirent64, d_name); ++ memcpy (p, &result, result_name_offset); ++ ++ /* Adjust the position of the name if necessary. Copy ++ everything until the end of the record, including the ++ terminating NUL byte. */ ++ if (result_name_offset != offsetof (struct dirent64, d_name)) ++ memmove (p + result_name_offset, source->d_name, ++ reclen - offsetof (struct dirent64, d_name)); + +- kbuf = (void *) ((char *) kbuf + kbuf->k.d_reclen); ++ p += reclen; + } + } + return retval; +diff --git a/sysdeps/unix/sysv/linux/tst-readdir64-compat.c b/sysdeps/unix/sysv/linux/tst-readdir64-compat.c +new file mode 100644 +index 0000000000000000..43c4a8477c7403c5 +--- /dev/null ++++ b/sysdeps/unix/sysv/linux/tst-readdir64-compat.c +@@ -0,0 +1,111 @@ ++/* Test readdir64 compatibility symbol. ++ 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 ++#include ++#include ++#include ++#include ++#include ++ ++/* Copied from . */ ++struct __old_dirent64 ++ { ++ __ino_t d_ino; ++ __off64_t d_off; ++ unsigned short int d_reclen; ++ unsigned char d_type; ++ char d_name[256]; ++ }; ++ ++typedef struct __old_dirent64 *(*compat_readdir64_type) (DIR *); ++ ++#if TEST_COMPAT (libc, GLIBC_2_1, GLIBC_2_2) ++struct __old_dirent64 *compat_readdir64 (DIR *); ++compat_symbol_reference (libc, compat_readdir64, readdir64, GLIBC_2_1); ++#endif ++ ++static int ++do_test (void) ++{ ++#if TEST_COMPAT (libc, GLIBC_2_1, GLIBC_2_2) ++ ++ /* Directory stream using the non-compat readdir64 symbol. The test ++ checks against this. */ ++ DIR *dir_reference = opendir ("."); ++ TEST_VERIFY_EXIT (dir_reference != NULL); ++ DIR *dir_test = opendir ("."); ++ TEST_VERIFY_EXIT (dir_test != NULL); ++ ++ /* This loop assumes that the enumeration order is consistent for ++ two different handles. Nothing should write to the current ++ directory (in the source tree) while this test runs, so there ++ should not be any difference due to races. */ ++ size_t count = 0; ++ while (true) ++ { ++ errno = 0; ++ struct dirent64 *entry_reference = readdir64 (dir_reference); ++ if (entry_reference == NULL && errno != 0) ++ FAIL_EXIT1 ("readdir64 entry %zu: %m\n", count); ++ struct __old_dirent64 *entry_test = compat_readdir64 (dir_test); ++ if (entry_reference == NULL) ++ { ++ if (errno == EOVERFLOW) ++ { ++ TEST_VERIFY (entry_reference->d_ino ++ != (__ino_t) entry_reference->d_ino); ++ printf ("info: inode number overflow at entry %zu\n", count); ++ break; ++ } ++ if (errno != 0) ++ FAIL_EXIT1 ("compat readdir64 entry %zu: %m\n", count); ++ } ++ ++ /* Check that both streams end at the same time. */ ++ if (entry_reference == NULL) ++ { ++ TEST_VERIFY (entry_test == NULL); ++ break; ++ } ++ else ++ TEST_VERIFY_EXIT (entry_test != NULL); ++ ++ /* Check that the entries are the same. */ ++ TEST_COMPARE_BLOB (entry_reference->d_name, ++ strlen (entry_reference->d_name), ++ entry_test->d_name, strlen (entry_test->d_name)); ++ TEST_COMPARE (entry_reference->d_ino, entry_test->d_ino); ++ TEST_COMPARE (entry_reference->d_off, entry_test->d_off); ++ TEST_COMPARE (entry_reference->d_type, entry_test->d_type); ++ TEST_COMPARE (entry_reference->d_reclen, entry_test->d_reclen); ++ ++ ++count; ++ } ++ printf ("info: %zu directory entries found\n", count); ++ TEST_VERIFY (count >= 3); /* ".", "..", and some source files. */ ++ ++ TEST_COMPARE (closedir (dir_test), 0); ++ TEST_COMPARE (closedir (dir_reference), 0); ++#endif ++ return 0; ++} ++ ++#include diff --git a/SOURCES/glibc-rh1614979.patch b/SOURCES/glibc-rh1614979.patch new file mode 100644 index 0000000..c97ae2c --- /dev/null +++ b/SOURCES/glibc-rh1614979.patch @@ -0,0 +1,154 @@ +commit d524fa6c35e675eedbd8fe6cdf4db0b49c658026 +Author: H.J. Lu +Date: Thu Nov 8 10:06:58 2018 -0800 + + Check multiple NT_GNU_PROPERTY_TYPE_0 notes [BZ #23509] + + Linkers group input note sections with the same name into one output + note section with the same name. One output note section is placed in + one PT_NOTE segment. Since new linkers merge input .note.gnu.property + sections into one output .note.gnu.property section, there is only + one NT_GNU_PROPERTY_TYPE_0 note in one PT_NOTE segment with new linkers. + Since older linkers treat input .note.gnu.property section as a generic + note section and just concatenate all input .note.gnu.property sections + into one output .note.gnu.property section without merging them, we may + see multiple NT_GNU_PROPERTY_TYPE_0 notes in one PT_NOTE segment with + older linkers. + + When an older linker is used to created the program on CET-enabled OS, + the linker output has a single .note.gnu.property section with multiple + NT_GNU_PROPERTY_TYPE_0 notes, some of which have IBT and SHSTK enable + bits set even if the program isn't CET enabled. Such programs will + crash on CET-enabled machines. This patch updates the note parser: + + 1. Skip note parsing if a NT_GNU_PROPERTY_TYPE_0 note has been processed. + 2. Check multiple NT_GNU_PROPERTY_TYPE_0 notes. + + [BZ #23509] + * sysdeps/x86/dl-prop.h (_dl_process_cet_property_note): Skip + note parsing if a NT_GNU_PROPERTY_TYPE_0 note has been processed. + Update the l_cet field when processing NT_GNU_PROPERTY_TYPE_0 note. + Check multiple NT_GNU_PROPERTY_TYPE_0 notes. + * sysdeps/x86/link_map.h (l_cet): Expand to 3 bits, Add + lc_unknown. + +diff --git a/sysdeps/x86/dl-prop.h b/sysdeps/x86/dl-prop.h +index 26c3131ac5e2d080..9ab890d12bb99133 100644 +--- a/sysdeps/x86/dl-prop.h ++++ b/sysdeps/x86/dl-prop.h +@@ -49,6 +49,10 @@ _dl_process_cet_property_note (struct link_map *l, + const ElfW(Addr) align) + { + #if CET_ENABLED ++ /* Skip if we have seen a NT_GNU_PROPERTY_TYPE_0 note before. */ ++ if (l->l_cet != lc_unknown) ++ return; ++ + /* The NT_GNU_PROPERTY_TYPE_0 note must be aliged to 4 bytes in + 32-bit objects and to 8 bytes in 64-bit objects. Skip notes + with incorrect alignment. */ +@@ -57,6 +61,9 @@ _dl_process_cet_property_note (struct link_map *l, + + const ElfW(Addr) start = (ElfW(Addr)) note; + ++ unsigned int feature_1 = 0; ++ unsigned int last_type = 0; ++ + while ((ElfW(Addr)) (note + 1) - start < size) + { + /* Find the NT_GNU_PROPERTY_TYPE_0 note. */ +@@ -64,10 +71,18 @@ _dl_process_cet_property_note (struct link_map *l, + && note->n_type == NT_GNU_PROPERTY_TYPE_0 + && memcmp (note + 1, "GNU", 4) == 0) + { ++ /* Stop if we see more than one GNU property note which may ++ be generated by the older linker. */ ++ if (l->l_cet != lc_unknown) ++ return; ++ ++ /* Check CET status now. */ ++ l->l_cet = lc_none; ++ + /* Check for invalid property. */ + if (note->n_descsz < 8 + || (note->n_descsz % sizeof (ElfW(Addr))) != 0) +- break; ++ return; + + /* Start and end of property array. */ + unsigned char *ptr = (unsigned char *) (note + 1) + 4; +@@ -78,9 +93,15 @@ _dl_process_cet_property_note (struct link_map *l, + unsigned int type = *(unsigned int *) ptr; + unsigned int datasz = *(unsigned int *) (ptr + 4); + ++ /* Property type must be in ascending order. */ ++ if (type < last_type) ++ return; ++ + ptr += 8; + if ((ptr + datasz) > ptr_end) +- break; ++ return; ++ ++ last_type = type; + + if (type == GNU_PROPERTY_X86_FEATURE_1_AND) + { +@@ -89,14 +110,18 @@ _dl_process_cet_property_note (struct link_map *l, + we stop the search regardless if its size is correct + or not. There is no point to continue if this note + is ill-formed. */ +- if (datasz == 4) +- { +- unsigned int feature_1 = *(unsigned int *) ptr; +- if ((feature_1 & GNU_PROPERTY_X86_FEATURE_1_IBT)) +- l->l_cet |= lc_ibt; +- if ((feature_1 & GNU_PROPERTY_X86_FEATURE_1_SHSTK)) +- l->l_cet |= lc_shstk; +- } ++ if (datasz != 4) ++ return; ++ ++ feature_1 = *(unsigned int *) ptr; ++ ++ /* Keep searching for the next GNU property note ++ generated by the older linker. */ ++ break; ++ } ++ else if (type > GNU_PROPERTY_X86_FEATURE_1_AND) ++ { ++ /* Stop since property type is in ascending order. */ + return; + } + +@@ -112,6 +137,12 @@ _dl_process_cet_property_note (struct link_map *l, + + ELF_NOTE_NEXT_OFFSET (note->n_namesz, note->n_descsz, + align)); + } ++ ++ /* We get here only if there is one or no GNU property note. */ ++ if ((feature_1 & GNU_PROPERTY_X86_FEATURE_1_IBT)) ++ l->l_cet |= lc_ibt; ++ if ((feature_1 & GNU_PROPERTY_X86_FEATURE_1_SHSTK)) ++ l->l_cet |= lc_shstk; + #endif + } + +diff --git a/sysdeps/x86/link_map.h b/sysdeps/x86/link_map.h +index ef1206a9d2396a6f..9367ed08896794a4 100644 +--- a/sysdeps/x86/link_map.h ++++ b/sysdeps/x86/link_map.h +@@ -19,8 +19,9 @@ + /* If this object is enabled with CET. */ + enum + { +- lc_none = 0, /* Not enabled with CET. */ +- lc_ibt = 1 << 0, /* Enabled with IBT. */ +- lc_shstk = 1 << 1, /* Enabled with STSHK. */ ++ lc_unknown = 0, /* Unknown CET status. */ ++ lc_none = 1 << 0, /* Not enabled with CET. */ ++ lc_ibt = 1 << 1, /* Enabled with IBT. */ ++ lc_shstk = 1 << 2, /* Enabled with STSHK. */ + lc_ibt_and_shstk = lc_ibt | lc_shstk /* Enabled with both. */ +- } l_cet:2; ++ } l_cet:3; diff --git a/SOURCES/glibc-rh1615781.patch b/SOURCES/glibc-rh1615781.patch new file mode 100644 index 0000000..a12ea17 --- /dev/null +++ b/SOURCES/glibc-rh1615781.patch @@ -0,0 +1,28 @@ +commit d05b05d1570ba3ae354a2f5a3cfeefb373b09979 +Author: Florian Weimer +Date: Mon Aug 13 14:28:07 2018 +0200 + + error, error_at_line: Add missing va_end calls + + (cherry picked from commit b7b52b9dec337a08a89bc67638773be652eba332) + +diff --git a/misc/error.c b/misc/error.c +index b4e8b6c93886b737..03378e2f2aa6251e 100644 +--- a/misc/error.c ++++ b/misc/error.c +@@ -319,6 +319,7 @@ error (int status, int errnum, const char *message, ...) + + va_start (args, message); + error_tail (status, errnum, message, args); ++ va_end (args); + + #ifdef _LIBC + _IO_funlockfile (stderr); +@@ -390,6 +391,7 @@ error_at_line (int status, int errnum, const char *file_name, + + va_start (args, message); + error_tail (status, errnum, message, args); ++ va_end (args); + + #ifdef _LIBC + _IO_funlockfile (stderr); diff --git a/SOURCES/glibc-rh1615784.patch b/SOURCES/glibc-rh1615784.patch new file mode 100644 index 0000000..0c12c9c --- /dev/null +++ b/SOURCES/glibc-rh1615784.patch @@ -0,0 +1,35 @@ +commit bfcfa22589f2b4277a65e60c6b736b6bbfbd87d0 +Author: Florian Weimer +Date: Tue Aug 14 10:51:07 2018 +0200 + + nscd: Deallocate existing user names in file parser + + This avoids a theoretical memory leak (theoretical because it depends on + multiple server-user/stat-user directives in the configuration file). + + (cherry picked from commit 2d7acfac3ebf266dcbc82d0d6cc576f626953a03) + +diff --git a/nscd/nscd_conf.c b/nscd/nscd_conf.c +index 265a02434dd26c29..7293b795b6bcf71e 100644 +--- a/nscd/nscd_conf.c ++++ b/nscd/nscd_conf.c +@@ -190,7 +190,10 @@ nscd_parse_file (const char *fname, struct database_dyn dbs[lastdb]) + if (!arg1) + error (0, 0, _("Must specify user name for server-user option")); + else +- server_user = xstrdup (arg1); ++ { ++ free ((char *) server_user); ++ server_user = xstrdup (arg1); ++ } + } + else if (strcmp (entry, "stat-user") == 0) + { +@@ -198,6 +201,7 @@ nscd_parse_file (const char *fname, struct database_dyn dbs[lastdb]) + error (0, 0, _("Must specify user name for stat-user option")); + else + { ++ free ((char *) stat_user); + stat_user = xstrdup (arg1); + + struct passwd *pw = getpwnam (stat_user); diff --git a/SOURCES/glibc-rh1615790.patch b/SOURCES/glibc-rh1615790.patch new file mode 100644 index 0000000..f0fbdc7 --- /dev/null +++ b/SOURCES/glibc-rh1615790.patch @@ -0,0 +1,306 @@ +commit 2f498f3d140ab5152bd784df2be7af7d9c5e63ed +Author: Florian Weimer +Date: Tue Aug 14 10:57:48 2018 +0200 + + nss_files: Fix file stream leak in aliases lookup [BZ #23521] + + In order to get a clean test case, it was necessary to fix partially + fixed bug 23522 as well. + + (cherry picked from commit e95c6f61920a0f9237cfb292fa44ad500e1df09b) + +diff --git a/nss/Makefile b/nss/Makefile +index 66fac7f5b8a4c0d8..5209fc0456dd6786 100644 +--- a/nss/Makefile ++++ b/nss/Makefile +@@ -65,6 +65,7 @@ ifeq (yes,$(build-shared)) + tests += tst-nss-files-hosts-erange + tests += tst-nss-files-hosts-multi + tests += tst-nss-files-hosts-getent ++tests += tst-nss-files-alias-leak + endif + + # If we have a thread library then we can test cancellation against +@@ -171,3 +172,5 @@ endif + $(objpfx)tst-nss-files-hosts-erange: $(libdl) + $(objpfx)tst-nss-files-hosts-multi: $(libdl) + $(objpfx)tst-nss-files-hosts-getent: $(libdl) ++$(objpfx)tst-nss-files-alias-leak: $(libdl) ++$(objpfx)tst-nss-files-alias-leak.out: $(objpfx)/libnss_files.so +diff --git a/nss/nss_files/files-alias.c b/nss/nss_files/files-alias.c +index cfd34b66b921bbff..35b0bfc5d2479ab6 100644 +--- a/nss/nss_files/files-alias.c ++++ b/nss/nss_files/files-alias.c +@@ -221,6 +221,13 @@ get_next_alias (FILE *stream, const char *match, struct aliasent *result, + { + while (! feof_unlocked (listfile)) + { ++ if (room_left < 2) ++ { ++ free (old_line); ++ fclose (listfile); ++ goto no_more_room; ++ } ++ + first_unused[room_left - 1] = '\xff'; + line = fgets_unlocked (first_unused, room_left, + listfile); +@@ -229,6 +236,7 @@ get_next_alias (FILE *stream, const char *match, struct aliasent *result, + if (first_unused[room_left - 1] != '\xff') + { + free (old_line); ++ fclose (listfile); + goto no_more_room; + } + +@@ -256,6 +264,7 @@ get_next_alias (FILE *stream, const char *match, struct aliasent *result, + + __alignof__ (char *))) + { + free (old_line); ++ fclose (listfile); + goto no_more_room; + } + room_left -= ((first_unused - cp) +diff --git a/nss/tst-nss-files-alias-leak.c b/nss/tst-nss-files-alias-leak.c +new file mode 100644 +index 0000000000000000..26d38e2dba1ddaf3 +--- /dev/null ++++ b/nss/tst-nss-files-alias-leak.c +@@ -0,0 +1,237 @@ ++/* Check for file descriptor leak in alias :include: processing (bug 23521). ++ 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 ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++static struct support_chroot *chroot_env; ++ ++/* Number of the aliases for the "many" user. This must be large ++ enough to trigger reallocation for the pointer array, but result in ++ answers below the maximum size tried in do_test. */ ++enum { many_aliases = 30 }; ++ ++static void ++prepare (int argc, char **argv) ++{ ++ chroot_env = support_chroot_create ++ ((struct support_chroot_configuration) { } ); ++ ++ char *path = xasprintf ("%s/etc/aliases", chroot_env->path_chroot); ++ add_temp_file (path); ++ support_write_file_string ++ (path, ++ "user1: :include:/etc/aliases.user1\n" ++ "user2: :include:/etc/aliases.user2\n" ++ "comment: comment1, :include:/etc/aliases.comment\n" ++ "many: :include:/etc/aliases.many\n"); ++ free (path); ++ ++ path = xasprintf ("%s/etc/aliases.user1", chroot_env->path_chroot); ++ add_temp_file (path); ++ support_write_file_string (path, "alias1\n"); ++ free (path); ++ ++ path = xasprintf ("%s/etc/aliases.user2", chroot_env->path_chroot); ++ add_temp_file (path); ++ support_write_file_string (path, "alias1a, alias2\n"); ++ free (path); ++ ++ path = xasprintf ("%s/etc/aliases.comment", chroot_env->path_chroot); ++ add_temp_file (path); ++ support_write_file_string ++ (path, ++ /* The line must be longer than the line with the :include: ++ directive in /etc/aliases. */ ++ "# Long line. ##############################################\n" ++ "comment2\n"); ++ free (path); ++ ++ path = xasprintf ("%s/etc/aliases.many", chroot_env->path_chroot); ++ add_temp_file (path); ++ FILE *fp = xfopen (path, "w"); ++ for (int i = 0; i < many_aliases; ++i) ++ fprintf (fp, "a%d\n", i); ++ TEST_VERIFY_EXIT (! ferror (fp)); ++ xfclose (fp); ++ free (path); ++} ++ ++/* The names of the users to test. */ ++static const char *users[] = { "user1", "user2", "comment", "many" }; ++ ++static void ++check_aliases (int id, const struct aliasent *e) ++{ ++ TEST_VERIFY_EXIT (id >= 0 || id < array_length (users)); ++ const char *name = users[id]; ++ TEST_COMPARE_BLOB (e->alias_name, strlen (e->alias_name), ++ name, strlen (name)); ++ ++ switch (id) ++ { ++ case 0: ++ TEST_COMPARE (e->alias_members_len, 1); ++ TEST_COMPARE_BLOB (e->alias_members[0], strlen (e->alias_members[0]), ++ "alias1", strlen ("alias1")); ++ break; ++ ++ case 1: ++ TEST_COMPARE (e->alias_members_len, 2); ++ TEST_COMPARE_BLOB (e->alias_members[0], strlen (e->alias_members[0]), ++ "alias1a", strlen ("alias1a")); ++ TEST_COMPARE_BLOB (e->alias_members[1], strlen (e->alias_members[1]), ++ "alias2", strlen ("alias2")); ++ break; ++ ++ case 2: ++ TEST_COMPARE (e->alias_members_len, 2); ++ TEST_COMPARE_BLOB (e->alias_members[0], strlen (e->alias_members[0]), ++ "comment1", strlen ("comment1")); ++ TEST_COMPARE_BLOB (e->alias_members[1], strlen (e->alias_members[1]), ++ "comment2", strlen ("comment2")); ++ break; ++ ++ case 3: ++ TEST_COMPARE (e->alias_members_len, many_aliases); ++ for (int i = 0; i < e->alias_members_len; ++i) ++ { ++ char alias[30]; ++ int len = snprintf (alias, sizeof (alias), "a%d", i); ++ TEST_VERIFY_EXIT (len > 0); ++ TEST_COMPARE_BLOB (e->alias_members[i], strlen (e->alias_members[i]), ++ alias, len); ++ } ++ break; ++ } ++} ++ ++static int ++do_test (void) ++{ ++ /* Make sure we don't try to load the module in the chroot. */ ++ if (dlopen (LIBNSS_FILES_SO, RTLD_NOW) == NULL) ++ FAIL_EXIT1 ("could not load " LIBNSS_FILES_SO ": %s", dlerror ()); ++ ++ /* Some of these descriptors will become unavailable if there is a ++ file descriptor leak. 10 is chosen somewhat arbitrarily. The ++ array must be longer than the number of files opened by nss_files ++ at the same time (currently that number is 2). */ ++ int next_descriptors[10]; ++ for (size_t i = 0; i < array_length (next_descriptors); ++i) ++ { ++ next_descriptors[i] = dup (0); ++ TEST_VERIFY_EXIT (next_descriptors[i] > 0); ++ } ++ for (size_t i = 0; i < array_length (next_descriptors); ++i) ++ xclose (next_descriptors[i]); ++ ++ support_become_root (); ++ if (!support_can_chroot ()) ++ return EXIT_UNSUPPORTED; ++ ++ __nss_configure_lookup ("aliases", "files"); ++ ++ xchroot (chroot_env->path_chroot); ++ ++ /* Attempt various buffer sizes. If the operation succeeds, we ++ expect correct data. */ ++ for (int id = 0; id < array_length (users); ++id) ++ { ++ bool found = false; ++ for (size_t size = 1; size <= 1000; ++size) ++ { ++ void *buffer = malloc (size); ++ struct aliasent result; ++ struct aliasent *res; ++ errno = EINVAL; ++ int ret = getaliasbyname_r (users[id], &result, buffer, size, &res); ++ if (ret == 0) ++ { ++ if (res != NULL) ++ { ++ found = true; ++ check_aliases (id, res); ++ } ++ else ++ { ++ support_record_failure (); ++ printf ("error: failed lookup for user \"%s\", size %zu\n", ++ users[id], size); ++ } ++ } ++ else if (ret != ERANGE) ++ { ++ support_record_failure (); ++ printf ("error: invalid return code %d (user \%s\", size %zu)\n", ++ ret, users[id], size); ++ } ++ free (buffer); ++ ++ /* Make sure that we did not have a file descriptor leak. */ ++ for (size_t i = 0; i < array_length (next_descriptors); ++i) ++ { ++ int new_fd = dup (0); ++ if (new_fd != next_descriptors[i]) ++ { ++ support_record_failure (); ++ printf ("error: descriptor %d at index %zu leaked" ++ " (user \"%s\", size %zu)\n", ++ next_descriptors[i], i, users[id], size); ++ ++ /* Close unexpected descriptor, the leak probing ++ descriptors, and the leaked descriptor ++ next_descriptors[i]. */ ++ xclose (new_fd); ++ for (size_t j = 0; j <= i; ++j) ++ xclose (next_descriptors[j]); ++ goto next_size; ++ } ++ } ++ for (size_t i = 0; i < array_length (next_descriptors); ++i) ++ xclose (next_descriptors[i]); ++ ++ next_size: ++ ; ++ } ++ if (!found) ++ { ++ support_record_failure (); ++ printf ("error: user %s not found\n", users[id]); ++ } ++ } ++ ++ support_chroot_free (chroot_env); ++ return 0; ++} ++ ++#define PREPARE prepare ++#include diff --git a/SOURCES/glibc-rh1622675.patch b/SOURCES/glibc-rh1622675.patch new file mode 100644 index 0000000..ba473cd --- /dev/null +++ b/SOURCES/glibc-rh1622675.patch @@ -0,0 +1,27 @@ +commit aa8a3e4cdef20c50cb20f008864fff05cbfbdf29 +Author: Martin Kuchta +Date: Mon Aug 27 18:54:46 2018 +0200 + + pthread_cond_broadcast: Fix waiters-after-spinning case [BZ #23538] + + (cherry picked from commit 99ea93ca31795469d2a1f1570f17a5c39c2eb7e2) + +diff --git a/nptl/pthread_cond_common.c b/nptl/pthread_cond_common.c +index 8e425eb01eceabec..479e54febb417675 100644 +--- a/nptl/pthread_cond_common.c ++++ b/nptl/pthread_cond_common.c +@@ -405,8 +405,12 @@ __condvar_quiesce_and_switch_g1 (pthread_cond_t *cond, uint64_t wseq, + { + /* There is still a waiter after spinning. Set the wake-request + flag and block. Relaxed MO is fine because this is just about +- this futex word. */ +- r = atomic_fetch_or_relaxed (cond->__data.__g_refs + g1, 1); ++ this futex word. ++ ++ Update r to include the set wake-request flag so that the upcoming ++ futex_wait only blocks if the flag is still set (otherwise, we'd ++ violate the basic client-side futex protocol). */ ++ r = atomic_fetch_or_relaxed (cond->__data.__g_refs + g1, 1) | 1; + + if ((r >> 1) > 0) + futex_wait_simple (cond->__data.__g_refs + g1, r, private); diff --git a/SOURCES/glibc-rh1622678-1.patch b/SOURCES/glibc-rh1622678-1.patch new file mode 100644 index 0000000..4d94590 --- /dev/null +++ b/SOURCES/glibc-rh1622678-1.patch @@ -0,0 +1,41 @@ +commit 58559f14437d2aa71753a29fed435efa06aa4576 +Author: Paul Eggert +Date: Tue Aug 28 21:54:28 2018 +0200 + + regex: fix uninitialized memory access + + I introduced this bug into gnulib in commit + 8335a4d6c7b4448cd0bcb6d0bebf1d456bcfdb17 dated 2006-04-10; + eventually it was merged into glibc. The bug was found by + project-repo and reported here: + https://lists.gnu.org/r/sed-devel/2018-08/msg00017.html + Diagnosis and draft fix reported by Assaf Gordon here: + https://lists.gnu.org/r/bug-gnulib/2018-08/msg00071.html + https://lists.gnu.org/r/bug-gnulib/2018-08/msg00142.html + * posix/regex_internal.c (build_wcs_upper_buffer): + Fix bug when mbrtowc returns 0. + + (cherry picked from commit bc680b336971305cb39896b30d72dc7101b62242) + +diff --git a/posix/regex_internal.c b/posix/regex_internal.c +index 7f0083b918de6530..b10588f1ccbb1992 100644 +--- a/posix/regex_internal.c ++++ b/posix/regex_internal.c +@@ -317,7 +317,7 @@ build_wcs_upper_buffer (re_string_t *pstr) + mbclen = __mbrtowc (&wc, + ((const char *) pstr->raw_mbs + pstr->raw_mbs_idx + + byte_idx), remain_len, &pstr->cur_state); +- if (BE (mbclen < (size_t) -2, 1)) ++ if (BE (0 < mbclen && mbclen < (size_t) -2, 1)) + { + wchar_t wcu = __towupper (wc); + if (wcu != wc) +@@ -386,7 +386,7 @@ build_wcs_upper_buffer (re_string_t *pstr) + else + p = (const char *) pstr->raw_mbs + pstr->raw_mbs_idx + src_idx; + mbclen = __mbrtowc (&wc, p, remain_len, &pstr->cur_state); +- if (BE (mbclen < (size_t) -2, 1)) ++ if (BE (0 < mbclen && mbclen < (size_t) -2, 1)) + { + wchar_t wcu = __towupper (wc); + if (wcu != wc) diff --git a/SOURCES/glibc-rh1622678-2.patch b/SOURCES/glibc-rh1622678-2.patch new file mode 100644 index 0000000..ecf37f7 --- /dev/null +++ b/SOURCES/glibc-rh1622678-2.patch @@ -0,0 +1,226 @@ +commit 0b79004569e5ce1669136b8c41564c3809730f15 +Author: Florian Weimer +Date: Tue Aug 28 12:57:46 2018 +0200 + + regex: Add test tst-regcomp-truncated [BZ #23578] + + (cherry picked from commit 761404b74d9853ce1608195e24f25b78a910591a) + +diff --git a/posix/Makefile b/posix/Makefile +index 00c62841a282f15a..83162123f9c927a0 100644 +--- a/posix/Makefile ++++ b/posix/Makefile +@@ -96,7 +96,7 @@ tests := test-errno tstgetopt testfnm runtests runptests \ + tst-posix_fadvise tst-posix_fadvise64 \ + tst-sysconf-empty-chroot tst-glob_symlinks tst-fexecve \ + tst-glob-tilde test-ssize-max tst-spawn4 bug-regex37 \ +- bug-regex38 ++ bug-regex38 tst-regcomp-truncated + tests-internal := bug-regex5 bug-regex20 bug-regex33 \ + tst-rfc3484 tst-rfc3484-2 tst-rfc3484-3 \ + tst-glob_lstat_compat tst-spawn4-compat +@@ -194,6 +194,7 @@ $(objpfx)tst-regex2.out: $(gen-locales) + $(objpfx)tst-regexloc.out: $(gen-locales) + $(objpfx)tst-rxspencer.out: $(gen-locales) + $(objpfx)tst-rxspencer-no-utf8.out: $(gen-locales) ++$(objpfx)tst-regcomp-truncated.out: $(gen-locales) + endif + + # If we will use the generic uname implementation, we must figure out what +diff --git a/posix/tst-regcomp-truncated.c b/posix/tst-regcomp-truncated.c +new file mode 100644 +index 0000000000000000..a4a1581bbc2b39eb +--- /dev/null ++++ b/posix/tst-regcomp-truncated.c +@@ -0,0 +1,191 @@ ++/* Test compilation of truncated regular 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 ++ . */ ++ ++/* This test constructs various patterns in an attempt to trigger ++ over-reading the regular expression compiler, such as bug ++ 23578. */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* Locales to test. */ ++static const char locales[][17] = ++ { ++ "C", ++ "en_US.UTF-8", ++ "de_DE.ISO-8859-1", ++ }; ++ ++/* Syntax options. Will be combined with other flags. */ ++static const reg_syntax_t syntaxes[] = ++ { ++ RE_SYNTAX_EMACS, ++ RE_SYNTAX_AWK, ++ RE_SYNTAX_GNU_AWK, ++ RE_SYNTAX_POSIX_AWK, ++ RE_SYNTAX_GREP, ++ RE_SYNTAX_EGREP, ++ RE_SYNTAX_POSIX_EGREP, ++ RE_SYNTAX_POSIX_BASIC, ++ RE_SYNTAX_POSIX_EXTENDED, ++ RE_SYNTAX_POSIX_MINIMAL_EXTENDED, ++ }; ++ ++/* Trailing characters placed after the initial character. */ ++static const char trailing_strings[][4] = ++ { ++ "", ++ "[", ++ "\\", ++ "[\\", ++ "(", ++ "(\\", ++ "\\(", ++ }; ++ ++static int ++do_test (void) ++{ ++ /* Staging buffer for the constructed regular expression. */ ++ char buffer[16]; ++ ++ /* Allocation used to detect over-reading by the regular expression ++ compiler. */ ++ struct support_next_to_fault ntf ++ = support_next_to_fault_allocate (sizeof (buffer)); ++ ++ /* Arbitrary Unicode codepoint at which we stop generating ++ characters. We do not probe the whole range because that would ++ take too long due to combinatorical exploision as the result of ++ combination with other flags. */ ++ static const wchar_t last_character = 0xfff; ++ ++ for (size_t locale_idx = 0; locale_idx < array_length (locales); ++ ++ locale_idx) ++ { ++ if (setlocale (LC_ALL, locales[locale_idx]) == NULL) ++ { ++ support_record_failure (); ++ printf ("error: setlocale (\"%s\"): %m", locales[locale_idx]); ++ continue; ++ } ++ if (test_verbose > 0) ++ printf ("info: testing locale \"%s\"\n", locales[locale_idx]); ++ ++ for (wchar_t wc = 0; wc <= last_character; ++wc) ++ { ++ char *after_wc; ++ if (wc == 0) ++ { ++ /* wcrtomb treats L'\0' in a special way. */ ++ *buffer = '\0'; ++ after_wc = &buffer[1]; ++ } ++ else ++ { ++ mbstate_t ps = { }; ++ size_t ret = wcrtomb (buffer, wc, &ps); ++ if (ret == (size_t) -1) ++ { ++ /* EILSEQ means that the target character set ++ cannot encode the character. */ ++ if (errno != EILSEQ) ++ { ++ support_record_failure (); ++ printf ("error: wcrtomb (0x%x) failed: %m\n", ++ (unsigned) wc); ++ } ++ continue; ++ } ++ TEST_VERIFY_EXIT (ret != 0); ++ after_wc = &buffer[ret]; ++ } ++ ++ for (size_t trailing_idx = 0; ++ trailing_idx < array_length (trailing_strings); ++ ++trailing_idx) ++ { ++ char *after_trailing ++ = stpcpy (after_wc, trailing_strings[trailing_idx]); ++ ++ for (int do_nul = 0; do_nul < 2; ++do_nul) ++ { ++ char *after_nul; ++ if (do_nul) ++ { ++ *after_trailing = '\0'; ++ after_nul = &after_trailing[1]; ++ } ++ else ++ after_nul = after_trailing; ++ ++ size_t length = after_nul - buffer; ++ ++ /* Make sure that the faulting region starts ++ after the used portion of the buffer. */ ++ char *ntf_start = ntf.buffer + sizeof (buffer) - length; ++ memcpy (ntf_start, buffer, length); ++ ++ for (const reg_syntax_t *psyntax = syntaxes; ++ psyntax < array_end (syntaxes); ++psyntax) ++ for (int do_icase = 0; do_icase < 2; ++do_icase) ++ { ++ re_syntax_options = *psyntax; ++ if (do_icase) ++ re_syntax_options |= RE_ICASE; ++ ++ regex_t reg; ++ memset (®, 0, sizeof (reg)); ++ const char *msg = re_compile_pattern ++ (ntf_start, length, ®); ++ if (msg != NULL) ++ { ++ if (test_verbose > 0) ++ { ++ char *quoted = support_quote_blob ++ (buffer, length); ++ printf ("info: compilation failed for pattern" ++ " \"%s\", syntax 0x%lx: %s\n", ++ quoted, re_syntax_options, msg); ++ free (quoted); ++ } ++ } ++ else ++ regfree (®); ++ } ++ } ++ } ++ } ++ } ++ ++ support_next_to_fault_free (&ntf); ++ ++ return 0; ++} ++ ++#include diff --git a/SOURCES/glibc-rh1623536-2.patch b/SOURCES/glibc-rh1623536-2.patch new file mode 100644 index 0000000..63d141b --- /dev/null +++ b/SOURCES/glibc-rh1623536-2.patch @@ -0,0 +1,34 @@ +commit 3a67c72c1512f778304a5644dea2fcf5bdece274 +Author: Andreas Schwab +Date: Thu Sep 27 12:37:06 2018 +0200 + + Fix stack overflow in tst-setcontext9 (bug 23717) + + The function f1a, executed on a stack of size 32k, allocates an object of + size 32k on the stack. Make the stack variables static to reduce + excessive stack usage. + + (cherry picked from commit f841c97e515a1673485a2b12b3c280073d737890) + +diff --git a/stdlib/tst-setcontext9.c b/stdlib/tst-setcontext9.c +index db8355766ca7b906..009928235dd5987e 100644 +--- a/stdlib/tst-setcontext9.c ++++ b/stdlib/tst-setcontext9.c +@@ -58,7 +58,7 @@ f1b (void) + static void + f1a (void) + { +- char st2[32768]; ++ static char st2[32768]; + puts ("start f1a"); + if (getcontext (&ctx[2]) != 0) + { +@@ -93,7 +93,7 @@ f1a (void) + static int + do_test (void) + { +- char st1[32768]; ++ static char st1[32768]; + puts ("making contexts"); + if (getcontext (&ctx[0]) != 0) + { diff --git a/SOURCES/glibc-rh1623536.patch b/SOURCES/glibc-rh1623536.patch new file mode 100644 index 0000000..8352b3d --- /dev/null +++ b/SOURCES/glibc-rh1623536.patch @@ -0,0 +1,100 @@ +commit a55e109709af55e6ed67d3f9536cac5d929c982e +Author: Carlos O'Donell +Date: Wed Sep 5 01:16:42 2018 -0400 + + Fix tst-setcontext9 for optimized small stacks. + + If the compiler reduces the stack usage in function f1 before calling + into function f2, then when we swapcontext back to f1 and continue + execution we may overwrite registers that were spilled to the stack + while f2 was executing. Later when we return to f2 the corrupt + registers will be reloaded from the stack and the test will crash. This + was most commonly observed on i686 with __x86.get_pc_thunk.dx and + needing to save and restore $edx. Overall i686 has few registers and + the spilling to the stack is bound to happen, therefore the solution to + making this test robust is to split function f1 into two parts f1a and + f1b, and allocate f1b it's own stack such that subsequent execution does + not overwrite the stack in use by function f2. + + Tested on i686 and x86_64. + + Signed-off-by: Carlos O'Donell + (cherry picked from commit 791b350dc725545e3f9b5db0f97ebdbc60c9735f) + +diff --git a/stdlib/tst-setcontext9.c b/stdlib/tst-setcontext9.c +index 4636ce9030fa38a7..db8355766ca7b906 100644 +--- a/stdlib/tst-setcontext9.c ++++ b/stdlib/tst-setcontext9.c +@@ -41,26 +41,55 @@ f2 (void) + } + + static void +-f1 (void) ++f1b (void) + { +- puts ("start f1"); +- if (getcontext (&ctx[2]) != 0) +- { +- printf ("%s: getcontext: %m\n", __FUNCTION__); +- exit (EXIT_FAILURE); +- } + if (done) + { +- puts ("set context in f1"); ++ puts ("set context in f1b"); + if (setcontext (&ctx[3]) != 0) + { + printf ("%s: setcontext: %m\n", __FUNCTION__); + exit (EXIT_FAILURE); + } + } ++ exit (EXIT_FAILURE); ++} ++ ++static void ++f1a (void) ++{ ++ char st2[32768]; ++ puts ("start f1a"); ++ if (getcontext (&ctx[2]) != 0) ++ { ++ printf ("%s: getcontext: %m\n", __FUNCTION__); ++ exit (EXIT_FAILURE); ++ } ++ ctx[2].uc_stack.ss_sp = st2; ++ ctx[2].uc_stack.ss_size = sizeof st2; ++ ctx[2].uc_link = &ctx[0]; ++ makecontext (&ctx[2], (void (*) (void)) f1b, 0); + f2 (); + } + ++/* The execution path through the test looks like this: ++ do_test (call) ++ -> "making contexts" ++ -> "swap contexts" ++ f1a (via swapcontext to ctx[1], with alternate stack) ++ -> "start f1a" ++ f2 (call) ++ -> "swap contexts in f2" ++ f1b (via swapcontext to ctx[2], with alternate stack) ++ -> "set context in f1b" ++ do_test (via setcontext to ctx[3], main stack) ++ -> "setcontext" ++ f2 (via setcontext to ctx[4], with alternate stack) ++ -> "end f2" ++ ++ We must use an alternate stack for f1b, because if we don't then the ++ result of executing an earlier caller may overwrite registers ++ spilled to the stack in f2. */ + static int + do_test (void) + { +@@ -79,7 +108,7 @@ do_test (void) + ctx[1].uc_stack.ss_sp = st1; + ctx[1].uc_stack.ss_size = sizeof st1; + ctx[1].uc_link = &ctx[0]; +- makecontext (&ctx[1], (void (*) (void)) f1, 0); ++ makecontext (&ctx[1], (void (*) (void)) f1a, 0); + puts ("swap contexts"); + if (swapcontext (&ctx[3], &ctx[1]) != 0) + { diff --git a/SOURCES/glibc-rh1623537.patch b/SOURCES/glibc-rh1623537.patch new file mode 100644 index 0000000..5165785 --- /dev/null +++ b/SOURCES/glibc-rh1623537.patch @@ -0,0 +1,61 @@ +commit b297581acb66f80b513996c1580158b0fb12d469 +Author: Tulio Magno Quites Machado Filho +Date: Mon Jan 14 17:54:44 2019 -0200 + + Add XFAIL_ROUNDING_IBM128_LIBGCC to more fma() tests + + Ignore 16 errors in math/test-ldouble-fma and 4 errors in + math/test-ildouble-fma when IBM 128-bit long double used. + These errors are caused by spurious overflows from libgcc. + + * math/libm-test-fma.inc (fma_test_data): Set + XFAIL_ROUNDING_IBM128_LIBGCC to more tests. + + Signed-off-by: Tulio Magno Quites Machado Filho + (cherry picked from commit ecdacd34a2ac3b6d5a529ff218b29261d9d98a7a) + +diff --git a/math/libm-test-fma.inc b/math/libm-test-fma.inc +index 5b29fb820194e055..a7ee40992420c1ab 100644 +--- a/math/libm-test-fma.inc ++++ b/math/libm-test-fma.inc +@@ -119,32 +119,32 @@ static const struct test_fff_f_data fma_test_data[] = + TEST_fff_f (fma, plus_infty, plus_infty, -min_value, plus_infty, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED), + TEST_fff_f (fma, plus_infty, plus_infty, min_subnorm_value, plus_infty, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED), + TEST_fff_f (fma, plus_infty, plus_infty, -min_subnorm_value, plus_infty, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED), +- TEST_fff_f (fma, plus_infty, plus_infty, max_value, plus_infty, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED), +- TEST_fff_f (fma, plus_infty, plus_infty, -max_value, plus_infty, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED), ++ TEST_fff_f (fma, plus_infty, plus_infty, max_value, plus_infty, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED|XFAIL_ROUNDING_IBM128_LIBGCC), ++ TEST_fff_f (fma, plus_infty, plus_infty, -max_value, plus_infty, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED|XFAIL_ROUNDING_IBM128_LIBGCC), + TEST_fff_f (fma, plus_infty, minus_infty, plus_zero, minus_infty, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED), + TEST_fff_f (fma, plus_infty, minus_infty, minus_zero, minus_infty, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED), + TEST_fff_f (fma, plus_infty, minus_infty, min_value, minus_infty, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED), + TEST_fff_f (fma, plus_infty, minus_infty, -min_value, minus_infty, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED), + TEST_fff_f (fma, plus_infty, minus_infty, min_subnorm_value, minus_infty, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED), + TEST_fff_f (fma, plus_infty, minus_infty, -min_subnorm_value, minus_infty, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED), +- TEST_fff_f (fma, plus_infty, minus_infty, max_value, minus_infty, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED), +- TEST_fff_f (fma, plus_infty, minus_infty, -max_value, minus_infty, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED), ++ TEST_fff_f (fma, plus_infty, minus_infty, max_value, minus_infty, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED|XFAIL_ROUNDING_IBM128_LIBGCC), ++ TEST_fff_f (fma, plus_infty, minus_infty, -max_value, minus_infty, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED|XFAIL_ROUNDING_IBM128_LIBGCC), + TEST_fff_f (fma, minus_infty, plus_infty, plus_zero, minus_infty, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED), + TEST_fff_f (fma, minus_infty, plus_infty, minus_zero, minus_infty, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED), + TEST_fff_f (fma, minus_infty, plus_infty, min_value, minus_infty, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED), + TEST_fff_f (fma, minus_infty, plus_infty, -min_value, minus_infty, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED), + TEST_fff_f (fma, minus_infty, plus_infty, min_subnorm_value, minus_infty, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED), + TEST_fff_f (fma, minus_infty, plus_infty, -min_subnorm_value, minus_infty, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED), +- TEST_fff_f (fma, minus_infty, plus_infty, max_value, minus_infty, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED), +- TEST_fff_f (fma, minus_infty, plus_infty, -max_value, minus_infty, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED), ++ TEST_fff_f (fma, minus_infty, plus_infty, max_value, minus_infty, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED|XFAIL_ROUNDING_IBM128_LIBGCC), ++ TEST_fff_f (fma, minus_infty, plus_infty, -max_value, minus_infty, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED|XFAIL_ROUNDING_IBM128_LIBGCC), + TEST_fff_f (fma, minus_infty, minus_infty, plus_zero, plus_infty, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED), + TEST_fff_f (fma, minus_infty, minus_infty, minus_zero, plus_infty, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED), + TEST_fff_f (fma, minus_infty, minus_infty, min_value, plus_infty, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED), + TEST_fff_f (fma, minus_infty, minus_infty, -min_value, plus_infty, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED), + TEST_fff_f (fma, minus_infty, minus_infty, min_subnorm_value, plus_infty, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED), + TEST_fff_f (fma, minus_infty, minus_infty, -min_subnorm_value, plus_infty, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED), +- TEST_fff_f (fma, minus_infty, minus_infty, max_value, plus_infty, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED), +- TEST_fff_f (fma, minus_infty, minus_infty, -max_value, plus_infty, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED), ++ TEST_fff_f (fma, minus_infty, minus_infty, max_value, plus_infty, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED|XFAIL_ROUNDING_IBM128_LIBGCC), ++ TEST_fff_f (fma, minus_infty, minus_infty, -max_value, plus_infty, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED|XFAIL_ROUNDING_IBM128_LIBGCC), + + AUTO_TESTS_fff_f (fma), + }; diff --git a/SOURCES/glibc-rh1631293-1.patch b/SOURCES/glibc-rh1631293-1.patch new file mode 100644 index 0000000..fc2a74e --- /dev/null +++ b/SOURCES/glibc-rh1631293-1.patch @@ -0,0 +1,29 @@ +commit e7d22db29cfdd2f1fb97a70a76fa53d151569945 +Author: Mingli Yu +Date: Thu Sep 20 12:41:13 2018 +0200 + + Linux gethostid: Check for NULL value from gethostbyname_r [BZ #23679] + + A NULL value can happen with certain gethostbyname_r failures. + + (cherry picked from commit 1214ba06e6771acb953a190091b0f6055c64fd25) + +diff --git a/sysdeps/unix/sysv/linux/gethostid.c b/sysdeps/unix/sysv/linux/gethostid.c +index 2e20f034dc134cc7..ee0190e7f945db1f 100644 +--- a/sysdeps/unix/sysv/linux/gethostid.c ++++ b/sysdeps/unix/sysv/linux/gethostid.c +@@ -102,12 +102,12 @@ gethostid (void) + { + int ret = __gethostbyname_r (hostname, &hostbuf, + tmpbuf.data, tmpbuf.length, &hp, &herr); +- if (ret == 0) ++ if (ret == 0 && hp != NULL) + break; + else + { + /* Enlarge the buffer on ERANGE. */ +- if (herr == NETDB_INTERNAL && errno == ERANGE) ++ if (ret != 0 && herr == NETDB_INTERNAL && errno == ERANGE) + { + if (!scratch_buffer_grow (&tmpbuf)) + return 0; diff --git a/SOURCES/glibc-rh1631293-2.patch b/SOURCES/glibc-rh1631293-2.patch new file mode 100644 index 0000000..4eef814 --- /dev/null +++ b/SOURCES/glibc-rh1631293-2.patch @@ -0,0 +1,146 @@ +commit 307d04334d516bb180f484a2b283f97310bfee66 +Author: Florian Weimer +Date: Thu Sep 20 12:03:01 2018 +0200 + + misc: New test misc/tst-gethostid + + The empty /etc/hosts file used to trigger bug 23679. + + (cherry picked from commit db9a8ad4ff3fc58e3773a9a4d0cabe3c1bc9c94c) + +diff --git a/misc/Makefile b/misc/Makefile +index b7be2bc19a6f7ed5..c9f81515ac9aef2c 100644 +--- a/misc/Makefile ++++ b/misc/Makefile +@@ -86,6 +86,11 @@ tests := tst-dirname tst-tsearch tst-fdset tst-efgcvt tst-mntent tst-hsearch \ + tst-preadvwritev tst-preadvwritev64 tst-makedev tst-empty \ + tst-preadvwritev2 tst-preadvwritev64v2 + ++# Tests which need libdl. ++ifeq (yes,$(build-shared)) ++tests += tst-gethostid ++endif ++ + tests-internal := tst-atomic tst-atomic-long tst-allocate_once + tests-static := tst-empty + +@@ -145,3 +150,5 @@ tst-allocate_once-ENV = MALLOC_TRACE=$(objpfx)tst-allocate_once.mtrace + $(objpfx)tst-allocate_once-mem.out: $(objpfx)tst-allocate_once.out + $(common-objpfx)malloc/mtrace $(objpfx)tst-allocate_once.mtrace > $@; \ + $(evaluate-test) ++ ++$(objpfx)tst-gethostid: $(libdl) +diff --git a/misc/tst-gethostid.c b/misc/tst-gethostid.c +new file mode 100644 +index 0000000000000000..1490aaf3f517ff1d +--- /dev/null ++++ b/misc/tst-gethostid.c +@@ -0,0 +1,108 @@ ++/* Basic test for gethostid. ++ 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 ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* Initial test is run outside a chroot, to increase the likelihood of ++ success. */ ++static void ++outside_chroot (void *closure) ++{ ++ long id = gethostid (); ++ printf ("info: host ID outside chroot: 0x%lx\n", id); ++} ++ ++/* The same, but this time perform a chroot operation. */ ++static void ++in_chroot (void *closure) ++{ ++ const char *chroot_path = closure; ++ xchroot (chroot_path); ++ long id = gethostid (); ++ printf ("info: host ID in chroot: 0x%lx\n", id); ++} ++ ++static int ++do_test (void) ++{ ++ support_isolate_in_subprocess (outside_chroot, NULL); ++ ++ /* Now run the test inside a chroot. */ ++ support_become_root (); ++ if (!support_can_chroot ()) ++ /* Cannot perform further tests. */ ++ return 0; ++ ++ /* Only use nss_files. */ ++ __nss_configure_lookup ("hosts", "files"); ++ ++ /* Load the DSO outside of the chroot. */ ++ xdlopen (LIBNSS_FILES_SO, RTLD_LAZY); ++ ++ char *chroot_dir = support_create_temp_directory ("tst-gethostid-"); ++ support_isolate_in_subprocess (in_chroot, chroot_dir); ++ ++ /* Tests with /etc/hosts in the chroot. */ ++ { ++ char *path = xasprintf ("%s/etc", chroot_dir); ++ add_temp_file (path); ++ xmkdir (path, 0777); ++ free (path); ++ path = xasprintf ("%s/etc/hosts", chroot_dir); ++ add_temp_file (path); ++ ++ FILE *fp = xfopen (path, "w"); ++ xfclose (fp); ++ printf ("info: chroot test with an empty /etc/hosts file\n"); ++ support_isolate_in_subprocess (in_chroot, chroot_dir); ++ ++ char hostname[1024]; ++ int ret = gethostname (hostname, sizeof (hostname)); ++ if (ret < 0) ++ printf ("warning: invalid result from gethostname: %d\n", ret); ++ else if (strlen (hostname) == 0) ++ puts ("warning: gethostname returned empty string"); ++ else ++ { ++ printf ("info: chroot test with IPv6 address in /etc/hosts for: %s\n", ++ hostname); ++ fp = xfopen (path, "w"); ++ /* Use an IPv6 address to induce another lookup failure. */ ++ fprintf (fp, "2001:db8::1 %s\n", hostname); ++ xfclose (fp); ++ support_isolate_in_subprocess (in_chroot, chroot_dir); ++ } ++ free (path); ++ } ++ free (chroot_dir); ++ ++ return 0; ++} ++ ++#include diff --git a/SOURCES/glibc-rh1631722.patch b/SOURCES/glibc-rh1631722.patch new file mode 100644 index 0000000..30d9ea5 --- /dev/null +++ b/SOURCES/glibc-rh1631722.patch @@ -0,0 +1,108 @@ +commit 0ef2f4400c06927af34c515555f68840a70ba409 +Author: Wilco Dijkstra +Date: Wed Sep 19 16:50:18 2018 +0100 + + Fix strstr bug with huge needles (bug 23637) + + The generic strstr in GLIBC 2.28 fails to match huge needles. The optimized + AVAILABLE macro reads ahead a large fixed amount to reduce the overhead of + repeatedly checking for the end of the string. However if the needle length + is larger than this, two_way_long_needle may confuse this as meaning the end + of the string and return NULL. This is fixed by adding the needle length to + the amount to read ahead. + + [BZ #23637] + * string/test-strstr.c (pr23637): New function. + (test_main): Add tests with longer needles. + * string/strcasestr.c (AVAILABLE): Fix readahead distance. + * string/strstr.c (AVAILABLE): Likewise. + + (cherry picked from commit 83a552b0bb9fc2a5e80a0ab3723c0a80ce1db9f2) + +diff --git a/string/strcasestr.c b/string/strcasestr.c +index 5909fe3cdba88e47..421764bd1b0ff22e 100644 +--- a/string/strcasestr.c ++++ b/string/strcasestr.c +@@ -37,8 +37,9 @@ + /* Two-Way algorithm. */ + #define RETURN_TYPE char * + #define AVAILABLE(h, h_l, j, n_l) \ +- (((j) + (n_l) <= (h_l)) || ((h_l) += __strnlen ((void*)((h) + (h_l)), 512), \ +- (j) + (n_l) <= (h_l))) ++ (((j) + (n_l) <= (h_l)) \ ++ || ((h_l) += __strnlen ((void*)((h) + (h_l)), (n_l) + 512), \ ++ (j) + (n_l) <= (h_l))) + #define CHECK_EOL (1) + #define RET0_IF_0(a) if (!a) goto ret0 + #define CANON_ELEMENT(c) TOLOWER (c) +diff --git a/string/strstr.c b/string/strstr.c +index 265e9f310ce507ce..79ebcc75329d0b17 100644 +--- a/string/strstr.c ++++ b/string/strstr.c +@@ -33,8 +33,9 @@ + + #define RETURN_TYPE char * + #define AVAILABLE(h, h_l, j, n_l) \ +- (((j) + (n_l) <= (h_l)) || ((h_l) += __strnlen ((void*)((h) + (h_l)), 512), \ +- (j) + (n_l) <= (h_l))) ++ (((j) + (n_l) <= (h_l)) \ ++ || ((h_l) += __strnlen ((void*)((h) + (h_l)), (n_l) + 512), \ ++ (j) + (n_l) <= (h_l))) + #define CHECK_EOL (1) + #define RET0_IF_0(a) if (!a) goto ret0 + #define FASTSEARCH(S,C,N) (void*) strchr ((void*)(S), (C)) +diff --git a/string/test-strstr.c b/string/test-strstr.c +index 8d99716ff39cc2c2..5861b01b73e4c315 100644 +--- a/string/test-strstr.c ++++ b/string/test-strstr.c +@@ -151,6 +151,32 @@ check2 (void) + } + } + ++#define N 1024 ++ ++static void ++pr23637 (void) ++{ ++ char *h = (char*) buf1; ++ char *n = (char*) buf2; ++ ++ for (int i = 0; i < N; i++) ++ { ++ n[i] = 'x'; ++ h[i] = ' '; ++ h[i + N] = 'x'; ++ } ++ ++ n[N] = '\0'; ++ h[N * 2] = '\0'; ++ ++ /* Ensure we don't match at the first 'x'. */ ++ h[0] = 'x'; ++ ++ char *exp_result = stupid_strstr (h, n); ++ FOR_EACH_IMPL (impl, 0) ++ check_result (impl, h, n, exp_result); ++} ++ + static int + test_main (void) + { +@@ -158,6 +184,7 @@ test_main (void) + + check1 (); + check2 (); ++ pr23637 (); + + printf ("%23s", ""); + FOR_EACH_IMPL (impl, 0) +@@ -202,6 +229,9 @@ test_main (void) + do_test (15, 9, hlen, klen, 1); + do_test (15, 15, hlen, klen, 0); + do_test (15, 15, hlen, klen, 1); ++ ++ do_test (15, 15, hlen + klen * 4, klen * 4, 0); ++ do_test (15, 15, hlen + klen * 4, klen * 4, 1); + } + + do_test (0, 0, page_size - 1, 16, 0); diff --git a/SOURCES/glibc-rh1631730.patch b/SOURCES/glibc-rh1631730.patch new file mode 100644 index 0000000..cc59bac --- /dev/null +++ b/SOURCES/glibc-rh1631730.patch @@ -0,0 +1,82 @@ +commit 2339d6a55eb7a7e040ae888e906adc49eeb59eab +Author: H.J. Lu +Date: Wed Sep 12 08:40:59 2018 -0700 + + i386: Use ENTRY and END in start.S [BZ #23606] + + Wrapping the _start function with ENTRY and END to insert ENDBR32 at + function entry when CET is enabled. Since _start now includes CFI, + without "cfi_undefined (eip)", unwinder may not terminate at _start + and we will get + + Program received signal SIGSEGV, Segmentation fault. + 0xf7dc661e in ?? () from /lib/libgcc_s.so.1 + Missing separate debuginfos, use: dnf debuginfo-install libgcc-8.2.1-3.0.fc28.i686 + (gdb) bt + #0 0xf7dc661e in ?? () from /lib/libgcc_s.so.1 + #1 0xf7dc7c18 in _Unwind_Backtrace () from /lib/libgcc_s.so.1 + #2 0xf7f0d809 in __GI___backtrace (array=array@entry=0xffffc7d0, + size=size@entry=20) at ../sysdeps/i386/backtrace.c:127 + #3 0x08049254 in compare (p1=p1@entry=0xffffcad0, p2=p2@entry=0xffffcad4) + at backtrace-tst.c:12 + #4 0xf7e2a28c in msort_with_tmp (p=p@entry=0xffffca5c, b=b@entry=0xffffcad0, + n=n@entry=2) at msort.c:65 + #5 0xf7e29f64 in msort_with_tmp (n=2, b=0xffffcad0, p=0xffffca5c) + at msort.c:53 + #6 msort_with_tmp (p=p@entry=0xffffca5c, b=b@entry=0xffffcad0, n=n@entry=5) + at msort.c:53 + #7 0xf7e29f64 in msort_with_tmp (n=5, b=0xffffcad0, p=0xffffca5c) + at msort.c:53 + #8 msort_with_tmp (p=p@entry=0xffffca5c, b=b@entry=0xffffcad0, n=n@entry=10) + at msort.c:53 + #9 0xf7e29f64 in msort_with_tmp (n=10, b=0xffffcad0, p=0xffffca5c) + at msort.c:53 + #10 msort_with_tmp (p=p@entry=0xffffca5c, b=b@entry=0xffffcad0, n=n@entry=20) + at msort.c:53 + #11 0xf7e2a5b6 in msort_with_tmp (n=20, b=0xffffcad0, p=0xffffca5c) + at msort.c:297 + #12 __GI___qsort_r (b=b@entry=0xffffcad0, n=n@entry=20, s=s@entry=4, + cmp=cmp@entry=0x8049230 , arg=arg@entry=0x0) at msort.c:297 + #13 0xf7e2a84d in __GI_qsort (b=b@entry=0xffffcad0, n=n@entry=20, s=s@entry=4, + cmp=cmp@entry=0x8049230 ) at msort.c:308 + #14 0x080490f6 in main (argc=2, argv=0xffffcbd4) at backtrace-tst.c:39 + + FAIL: debug/backtrace-tst + + [BZ #23606] + * sysdeps/i386/start.S: Include + (_start): Use ENTRY/END to insert ENDBR32 at entry when CET is + enabled. Add cfi_undefined (eip). + + Signed-off-by: H.J. Lu + + (cherry picked from commit 5a274db4ea363d6b0b92933f085a92daaf1be2f2) + +diff --git a/sysdeps/i386/start.S b/sysdeps/i386/start.S +index 91035fa83fb7ee38..e35e9bd31b2cea30 100644 +--- a/sysdeps/i386/start.S ++++ b/sysdeps/i386/start.S +@@ -52,10 +52,11 @@ + NULL + */ + +- .text +- .globl _start +- .type _start,@function +-_start: ++#include ++ ++ENTRY (_start) ++ /* Clearing frame pointer is insufficient, use CFI. */ ++ cfi_undefined (eip) + /* Clear the frame pointer. The ABI suggests this be done, to mark + the outermost frame obviously. */ + xorl %ebp, %ebp +@@ -131,6 +132,7 @@ _start: + 1: movl (%esp), %ebx + ret + #endif ++END (_start) + + /* To fulfill the System V/i386 ABI we need this symbol. Yuck, it's so + meaningless since we don't support machines < 80386. */ diff --git a/SOURCES/glibc-rh1635779.patch b/SOURCES/glibc-rh1635779.patch new file mode 100644 index 0000000..e79fc37 --- /dev/null +++ b/SOURCES/glibc-rh1635779.patch @@ -0,0 +1,483 @@ +commit e5d262effe3a87164308a3f37e61b32d0348692a +Author: Tulio Magno Quites Machado Filho +Date: Fri Nov 30 18:05:32 2018 -0200 + + Fix _dl_profile_fixup data-dependency issue (Bug 23690) + + There is a data-dependency between the fields of struct l_reloc_result + and the field used as the initialization guard. Users of the guard + expect writes to the structure to be observable when they also observe + the guard initialized. The solution for this problem is to use an acquire + and release load and store to ensure previous writes to the structure are + observable if the guard is initialized. + + The previous implementation used DL_FIXUP_VALUE_ADDR (l_reloc_result->addr) + as the initialization guard, making it impossible for some architectures + to load and store it atomically, i.e. hppa and ia64, due to its larger size. + + This commit adds an unsigned int to l_reloc_result to be used as the new + initialization guard of the struct, making it possible to load and store + it atomically in all architectures. The fix ensures that the values + observed in l_reloc_result are consistent and do not lead to crashes. + The algorithm is documented in the code in elf/dl-runtime.c + (_dl_profile_fixup). Not all data races have been eliminated. + + Tested with build-many-glibcs and on powerpc, powerpc64, and powerpc64le. + + [BZ #23690] + * elf/dl-runtime.c (_dl_profile_fixup): Guarantee memory + modification order when accessing reloc_result->addr. + * include/link.h (reloc_result): Add field init. + * nptl/Makefile (tests): Add tst-audit-threads. + (modules-names): Add tst-audit-threads-mod1 and + tst-audit-threads-mod2. + Add rules to build tst-audit-threads. + * nptl/tst-audit-threads-mod1.c: New file. + * nptl/tst-audit-threads-mod2.c: Likewise. + * nptl/tst-audit-threads.c: Likewise. + * nptl/tst-audit-threads.h: Likewise. + + Signed-off-by: Tulio Magno Quites Machado Filho + Reviewed-by: Carlos O'Donell + +diff --git a/elf/dl-runtime.c b/elf/dl-runtime.c +index 63bbc89776..3d2f4a7a76 100644 +--- a/elf/dl-runtime.c ++++ b/elf/dl-runtime.c +@@ -183,10 +183,36 @@ _dl_profile_fixup ( + /* 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]; +- DL_FIXUP_VALUE_TYPE *resultp = &reloc_result->addr; + +- DL_FIXUP_VALUE_TYPE value = *resultp; +- if (DL_FIXUP_VALUE_CODE_ADDR (value) == 0) ++ /* CONCURRENCY NOTES: ++ ++ Multiple threads may be calling the same PLT sequence and with ++ LD_AUDIT enabled they will be calling into _dl_profile_fixup to ++ update the reloc_result with the result of the lazy resolution. ++ The reloc_result guard variable is reloc_init, and we use ++ acquire/release loads and store to it to ensure that the results of ++ the structure are consistent with the loaded value of the guard. ++ This does not fix all of the data races that occur when two or more ++ threads read reloc_result->reloc_init with a value of zero and read ++ and write to that reloc_result concurrently. The expectation is ++ generally that while this is a data race it works because the ++ threads write the same values. Until the data races are fixed ++ there is a potential for problems to arise from these data races. ++ The reloc result updates should happen in parallel but there should ++ be an atomic RMW which does the final update to the real result ++ entry (see bug 23790). ++ ++ The following code uses reloc_result->init set to 0 to indicate if it is ++ the first time this object is being relocated, otherwise 1 which ++ indicates the object has already been relocated. ++ ++ Reading/Writing from/to reloc_result->reloc_init must not happen ++ before previous writes to reloc_result complete as they could ++ end-up with an incomplete struct. */ ++ DL_FIXUP_VALUE_TYPE value; ++ unsigned int init = atomic_load_acquire (&reloc_result->init); ++ ++ if (init == 0) + { + /* This is the first time we have to relocate this object. */ + const ElfW(Sym) *const symtab +@@ -346,19 +372,31 @@ _dl_profile_fixup ( + + /* Store the result for later runs. */ + if (__glibc_likely (! GLRO(dl_bind_not))) +- *resultp = value; ++ { ++ reloc_result->addr = value; ++ /* Guarantee all previous writes complete before ++ init is updated. See CONCURRENCY NOTES earlier */ ++ atomic_store_release (&reloc_result->init, 1); ++ } ++ init = 1; + } ++ else ++ value = reloc_result->addr; + + /* By default we do not call the pltexit function. */ + long int framesize = -1; + ++ + #ifdef SHARED + /* Auditing checkpoint: report the PLT entering and allow the + auditors to change the value. */ +- if (DL_FIXUP_VALUE_CODE_ADDR (value) != 0 && GLRO(dl_naudit) > 0 ++ 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); +diff --git a/include/link.h b/include/link.h +index 5924594548..83b1c34b7b 100644 +--- a/include/link.h ++++ b/include/link.h +@@ -216,6 +216,10 @@ struct link_map + unsigned int boundndx; + uint32_t enterexit; + unsigned int flags; ++ /* CONCURRENCY NOTE: This is used to guard the concurrent initialization ++ of the relocation result across multiple threads. See the more ++ detailed notes in elf/dl-runtime.c. */ ++ unsigned int init; + } *l_reloc_result; + + /* Pointer to the version information if available. */ +diff --git a/nptl/Makefile b/nptl/Makefile +index 982e43adfa..98b0aa01c7 100644 +--- a/nptl/Makefile ++++ b/nptl/Makefile +@@ -382,7 +382,8 @@ tests += tst-cancelx2 tst-cancelx3 tst-cancelx4 tst-cancelx5 \ + tst-cleanupx0 tst-cleanupx1 tst-cleanupx2 tst-cleanupx3 tst-cleanupx4 \ + tst-oncex3 tst-oncex4 + ifeq ($(build-shared),yes) +-tests += tst-atfork2 tst-tls4 tst-_res1 tst-fini1 tst-compat-forwarder ++tests += tst-atfork2 tst-tls4 tst-_res1 tst-fini1 tst-compat-forwarder \ ++ tst-audit-threads + tests-internal += tst-tls3 tst-tls3-malloc tst-tls5 tst-stackguard1 + tests-nolibpthread += tst-fini1 + ifeq ($(have-z-execstack),yes) +@@ -394,7 +395,8 @@ 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-join7mod tst-compat-forwarder-mod tst-audit-threads-mod1 \ ++ tst-audit-threads-mod2 + extra-test-objs += $(addsuffix .os,$(strip $(modules-names))) \ + tst-cleanup4aux.o tst-cleanupx4aux.o + test-extras += tst-cleanup4aux tst-cleanupx4aux +@@ -712,6 +714,14 @@ $(objpfx)tst-compat-forwarder: $(objpfx)tst-compat-forwarder-mod.so + + tst-mutex10-ENV = GLIBC_TUNABLES=glibc.elision.enable=1 + ++# Protect against a build using -Wl,-z,now. ++LDFLAGS-tst-audit-threads-mod1.so = -Wl,-z,lazy ++LDFLAGS-tst-audit-threads-mod2.so = -Wl,-z,lazy ++LDFLAGS-tst-audit-threads = -Wl,-z,lazy ++$(objpfx)tst-audit-threads: $(objpfx)tst-audit-threads-mod2.so ++$(objpfx)tst-audit-threads.out: $(objpfx)tst-audit-threads-mod1.so ++tst-audit-threads-ENV = LD_AUDIT=$(objpfx)tst-audit-threads-mod1.so ++ + # The tests here better do not run in parallel + ifneq ($(filter %tests,$(MAKECMDGOALS)),) + .NOTPARALLEL: +diff --git a/nptl/tst-audit-threads-mod1.c b/nptl/tst-audit-threads-mod1.c +new file mode 100644 +index 0000000000..615d5ee512 +--- /dev/null ++++ b/nptl/tst-audit-threads-mod1.c +@@ -0,0 +1,74 @@ ++/* Dummy audit library for test-audit-threads. ++ ++ 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 ++#include ++#include ++ ++/* We must use a dummy LD_AUDIT module to force the dynamic loader to ++ *not* update the real PLT, and instead use a cached value for the ++ lazy resolution result. It is the update of that cached value that ++ we are testing for correctness by doing this. */ ++ ++/* Library to be audited. */ ++#define LIB "tst-audit-threads-mod2.so" ++/* CALLNUM is the number of retNum functions. */ ++#define CALLNUM 7999 ++ ++#define CONCATX(a, b) __CONCAT (a, b) ++ ++static int previous = 0; ++ ++unsigned int ++la_version (unsigned int ver) ++{ ++ return 1; ++} ++ ++unsigned int ++la_objopen (struct link_map *map, Lmid_t lmid, uintptr_t *cookie) ++{ ++ return LA_FLG_BINDTO | LA_FLG_BINDFROM; ++} ++ ++uintptr_t ++CONCATX(la_symbind, __ELF_NATIVE_CLASS) (ElfW(Sym) *sym, ++ unsigned int ndx, ++ uintptr_t *refcook, ++ uintptr_t *defcook, ++ unsigned int *flags, ++ const char *symname) ++{ ++ const char * retnum = "retNum"; ++ char * num = strstr (symname, retnum); ++ int n; ++ /* Validate if the symbols are getting called in the correct order. ++ This code is here to verify binutils does not optimize out the PLT ++ entries that require the symbol binding. */ ++ if (num != NULL) ++ { ++ n = atoi (num); ++ assert (n >= previous); ++ assert (n <= CALLNUM); ++ previous = n; ++ } ++ return sym->st_value; ++} +diff --git a/nptl/tst-audit-threads-mod2.c b/nptl/tst-audit-threads-mod2.c +new file mode 100644 +index 0000000000..f9817dd3dc +--- /dev/null ++++ b/nptl/tst-audit-threads-mod2.c +@@ -0,0 +1,22 @@ ++/* Shared object with a huge number of functions for test-audit-threads. ++ ++ 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 ++ . */ ++ ++/* Define all the retNumN functions in a library. */ ++#define definenum ++#include "tst-audit-threads.h" +diff --git a/nptl/tst-audit-threads.c b/nptl/tst-audit-threads.c +new file mode 100644 +index 0000000000..e4bf433bd8 +--- /dev/null ++++ b/nptl/tst-audit-threads.c +@@ -0,0 +1,97 @@ ++/* Test multi-threading using LD_AUDIT. ++ ++ 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 ++ . */ ++ ++/* This test uses a dummy LD_AUDIT library (test-audit-threads-mod1) and a ++ library with a huge number of functions in order to validate lazy symbol ++ binding with an audit library. We use one thread per CPU to test that ++ concurrent lazy resolution does not have any defects which would cause ++ the process to fail. We use an LD_AUDIT library to force the testing of ++ the relocation resolution caching code in the dynamic loader i.e. ++ _dl_runtime_profile and _dl_profile_fixup. */ ++ ++#include ++#include ++#include ++#include ++ ++static int do_test (void); ++ ++/* This test usually takes less than 3s to run. However, there are cases that ++ take up to 30s. */ ++#define TIMEOUT 60 ++#define TEST_FUNCTION do_test () ++#include "../test-skeleton.c" ++ ++/* Declare the functions we are going to call. */ ++#define externnum ++#include "tst-audit-threads.h" ++#undef externnum ++ ++int num_threads; ++pthread_barrier_t barrier; ++ ++void ++sync_all (int num) ++{ ++ pthread_barrier_wait (&barrier); ++} ++ ++void ++call_all_ret_nums (void) ++{ ++ /* Call each function one at a time from all threads. */ ++#define callnum ++#include "tst-audit-threads.h" ++#undef callnum ++} ++ ++void * ++thread_main (void *unused) ++{ ++ call_all_ret_nums (); ++ return NULL; ++} ++ ++#define STR2(X) #X ++#define STR(X) STR2(X) ++ ++static int ++do_test (void) ++{ ++ int i; ++ pthread_t *threads; ++ ++ num_threads = get_nprocs (); ++ if (num_threads <= 1) ++ num_threads = 2; ++ ++ /* Used to synchronize all the threads after calling each retNumN. */ ++ xpthread_barrier_init (&barrier, NULL, num_threads); ++ ++ threads = (pthread_t *) xcalloc (num_threads, sizeof(pthread_t)); ++ for (i = 0; i < num_threads; i++) ++ threads[i] = xpthread_create(NULL, thread_main, NULL); ++ ++ for (i = 0; i < num_threads; i++) ++ xpthread_join(threads[i]); ++ ++ free (threads); ++ ++ return 0; ++} +diff --git a/nptl/tst-audit-threads.h b/nptl/tst-audit-threads.h +new file mode 100644 +index 0000000000..1c9ecc08df +--- /dev/null ++++ b/nptl/tst-audit-threads.h +@@ -0,0 +1,92 @@ ++/* Helper header for test-audit-threads. ++ ++ 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 ++ . */ ++ ++/* We use this helper to create a large number of functions, all of ++ which will be resolved lazily and thus have their PLT updated. ++ This is done to provide enough functions that we can statistically ++ observe a thread vs. PLT resolution failure if one exists. */ ++ ++#define CONCAT(a, b) a ## b ++#define NUM(x, y) CONCAT (x, y) ++ ++#define FUNC10(x) \ ++ FUNC (NUM (x, 0)); \ ++ FUNC (NUM (x, 1)); \ ++ FUNC (NUM (x, 2)); \ ++ FUNC (NUM (x, 3)); \ ++ FUNC (NUM (x, 4)); \ ++ FUNC (NUM (x, 5)); \ ++ FUNC (NUM (x, 6)); \ ++ FUNC (NUM (x, 7)); \ ++ FUNC (NUM (x, 8)); \ ++ FUNC (NUM (x, 9)) ++ ++#define FUNC100(x) \ ++ FUNC10 (NUM (x, 0)); \ ++ FUNC10 (NUM (x, 1)); \ ++ FUNC10 (NUM (x, 2)); \ ++ FUNC10 (NUM (x, 3)); \ ++ FUNC10 (NUM (x, 4)); \ ++ FUNC10 (NUM (x, 5)); \ ++ FUNC10 (NUM (x, 6)); \ ++ FUNC10 (NUM (x, 7)); \ ++ FUNC10 (NUM (x, 8)); \ ++ FUNC10 (NUM (x, 9)) ++ ++#define FUNC1000(x) \ ++ FUNC100 (NUM (x, 0)); \ ++ FUNC100 (NUM (x, 1)); \ ++ FUNC100 (NUM (x, 2)); \ ++ FUNC100 (NUM (x, 3)); \ ++ FUNC100 (NUM (x, 4)); \ ++ FUNC100 (NUM (x, 5)); \ ++ FUNC100 (NUM (x, 6)); \ ++ FUNC100 (NUM (x, 7)); \ ++ FUNC100 (NUM (x, 8)); \ ++ FUNC100 (NUM (x, 9)) ++ ++#define FUNC7000() \ ++ FUNC1000 (1); \ ++ FUNC1000 (2); \ ++ FUNC1000 (3); \ ++ FUNC1000 (4); \ ++ FUNC1000 (5); \ ++ FUNC1000 (6); \ ++ FUNC1000 (7); ++ ++#ifdef FUNC ++# undef FUNC ++#endif ++ ++#ifdef externnum ++# define FUNC(x) extern int CONCAT (retNum, x) (void) ++#endif ++ ++#ifdef definenum ++# define FUNC(x) int CONCAT (retNum, x) (void) { return x; } ++#endif ++ ++#ifdef callnum ++# define FUNC(x) CONCAT (retNum, x) (); sync_all (x) ++#endif ++ ++/* A value of 7000 functions is chosen as an arbitrarily large ++ number of functions that will allow us enough attempts to ++ verify lazy resolution operation. */ ++FUNC7000 (); diff --git a/SOURCES/glibc-rh1638520.patch b/SOURCES/glibc-rh1638520.patch new file mode 100644 index 0000000..e52b7e5 --- /dev/null +++ b/SOURCES/glibc-rh1638520.patch @@ -0,0 +1,35 @@ +commit ed643089cd3251038863d32e67ec47b94cd557f3 +Author: Szabolcs Nagy +Date: Tue Oct 9 14:31:28 2018 +0100 + + Increase timeout of libio/tst-readline + + Increase timeout from the default 20s to 100s. This test makes close to + 20 million syscalls with distribution: + + 12327675 read + 4143204 lseek + 929475 close + 929471 openat + 92817 fstat + 1431 write + ... + + The default timeout assumes each can finish in 1us on average which + is not true on slow machines. + + Reviewed-by: Carlos O'Donell + + * libio/tst-readline.c (TIMEOUT): Define. + +diff --git a/libio/tst-readline.c b/libio/tst-readline.c +index 9322ef68da5e38a9..63f5227760d88c63 100644 +--- a/libio/tst-readline.c ++++ b/libio/tst-readline.c +@@ -232,5 +232,6 @@ do_test (void) + return 0; + } + ++#define TIMEOUT 100 + #define PREPARE prepare + #include diff --git a/SOURCES/glibc-rh1638523-1.patch b/SOURCES/glibc-rh1638523-1.patch new file mode 100644 index 0000000..bee0ab0 --- /dev/null +++ b/SOURCES/glibc-rh1638523-1.patch @@ -0,0 +1,2823 @@ +This patch backports the support/ directory as of the upstream commit +below. (It does not include the required Makefile changes to enable +test-in-container builds.) + +commit 00c86a37d1b63044e3169d1f2ebec23447c73f79 +Author: Adhemerval Zanella +Date: Wed Nov 7 11:09:02 2018 -0200 + + support: Fix printf format for TEST_COMPARE_STRING + + Fix the following on 32 bits targets: + + support_test_compare_string.c: In function ‘support_test_compare_string’: + support_test_compare_string.c:80:37: error: format ‘%lu’ expects argument of + type ‘long unsigned int’, but argument 2 has type ‘size_t’ {aka ‘unsigned int’} + [-Werror=format=] + printf (" string length: %lu bytes\n", left_length); + ~~^ ~~~~~~~~~~~ + %u + Checked on arm-linux-gnueabihf. + + * support/support_test_compare_string.c + (support_test_compare_string): Fix printf format. + +diff --git a/support/Makefile b/support/Makefile +index 652d2cdf6945b2eb..2b663fbbfa334ea2 100644 +--- a/support/Makefile ++++ b/support/Makefile +@@ -25,6 +25,7 @@ extra-libs-others = $(extra-libs) + extra-libs-noinstall := $(extra-libs) + + libsupport-routines = \ ++ blob_repeat \ + check \ + check_addrinfo \ + check_dns_packet \ +@@ -43,6 +44,8 @@ libsupport-routines = \ + support_capture_subprocess \ + support_capture_subprocess_check \ + support_chroot \ ++ support_copy_file_range \ ++ support_descriptor_supports_holes \ + support_enter_mount_namespace \ + support_enter_network_namespace \ + support_format_address_family \ +@@ -53,12 +56,14 @@ libsupport-routines = \ + support_format_netent \ + support_isolate_in_subprocess \ + support_openpty \ ++ support_paths \ + support_quote_blob \ + support_record_failure \ + support_run_diff \ + support_shared_allocate \ + support_test_compare_blob \ + support_test_compare_failure \ ++ support_test_compare_string \ + support_write_file_string \ + support_test_main \ + support_test_verify_impl \ +@@ -72,6 +77,7 @@ libsupport-routines = \ + xchroot \ + xclose \ + xconnect \ ++ xcopy_file_range \ + xdlfcn \ + xdup2 \ + xfclose \ +@@ -84,6 +90,7 @@ libsupport-routines = \ + xmalloc \ + xmemstream \ + xmkdir \ ++ xmkdirp \ + xmmap \ + xmprotect \ + xmunmap \ +@@ -139,6 +146,7 @@ libsupport-routines = \ + xsocket \ + xstrdup \ + xstrndup \ ++ xsymlink \ + xsysconf \ + xunlink \ + xwaitpid \ +@@ -151,15 +159,47 @@ ifeq ($(build-shared),yes) + libsupport-inhibit-o += .o + endif + ++CFLAGS-support_paths.c = \ ++ -DSRCDIR_PATH=\"`cd .. ; pwd`\" \ ++ -DOBJDIR_PATH=\"`cd $(objpfx)/..; pwd`\" \ ++ -DOBJDIR_ELF_LDSO_PATH=\"`cd $(objpfx)/..; pwd`/elf/$(rtld-installed-name)\" \ ++ -DINSTDIR_PATH=\"$(prefix)\" \ ++ -DLIBDIR_PATH=\"$(libdir)\" ++ ++ifeq (,$(CXX)) ++LINKS_DSO_PROGRAM = links-dso-program-c ++else ++LINKS_DSO_PROGRAM = links-dso-program ++LDLIBS-links-dso-program = -lstdc++ -lgcc -lgcc_s $(libunwind) ++endif ++ ++LDLIBS-test-container = $(libsupport) ++ ++others += test-container ++others-noinstall += test-container ++ ++others += shell-container echo-container true-container ++others-noinstall += shell-container echo-container true-container ++ ++others += $(LINKS_DSO_PROGRAM) ++others-noinstall += $(LINKS_DSO_PROGRAM) ++ ++$(objpfx)test-container : $(libsupport) ++$(objpfx)shell-container : $(libsupport) ++$(objpfx)echo-container : $(libsupport) ++$(objpfx)true-container : $(libsupport) ++ + tests = \ + README-testing \ + tst-support-namespace \ ++ tst-support_blob_repeat \ + tst-support_capture_subprocess \ + tst-support_format_dns_packet \ + tst-support_quote_blob \ + tst-support_record_failure \ + tst-test_compare \ + tst-test_compare_blob \ ++ tst-test_compare_string \ + tst-xreadlink \ + + ifeq ($(run-built-tests),yes) +diff --git a/support/blob_repeat.c b/support/blob_repeat.c +new file mode 100644 +index 0000000000000000..16c1e448b990e386 +--- /dev/null ++++ b/support/blob_repeat.c +@@ -0,0 +1,282 @@ ++/* Repeating a memory blob, with alias mapping optimization. ++ 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 ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* Small allocations should use malloc directly instead of the mmap ++ optimization because mappings carry a lot of overhead. */ ++static const size_t maximum_small_size = 4 * 1024 * 1024; ++ ++/* Internal helper for fill. */ ++static void ++fill0 (char *target, const char *element, size_t element_size, ++ size_t count) ++{ ++ while (count > 0) ++ { ++ memcpy (target, element, element_size); ++ target += element_size; ++ --count; ++ } ++} ++ ++/* Fill the buffer at TARGET with COUNT copies of the ELEMENT_SIZE ++ bytes starting at ELEMENT. */ ++static void ++fill (char *target, const char *element, size_t element_size, ++ size_t count) ++{ ++ if (element_size == 0 || count == 0) ++ return; ++ else if (element_size == 1) ++ memset (target, element[0], count); ++ else if (element_size == sizeof (wchar_t)) ++ { ++ wchar_t wc; ++ memcpy (&wc, element, sizeof (wc)); ++ wmemset ((wchar_t *) target, wc, count); ++ } ++ else if (element_size < 1024 && count > 4096) ++ { ++ /* Use larger copies for really small element sizes. */ ++ char buffer[8192]; ++ size_t buffer_count = sizeof (buffer) / element_size; ++ fill0 (buffer, element, element_size, buffer_count); ++ while (count > 0) ++ { ++ size_t copy_count = buffer_count; ++ if (copy_count > count) ++ copy_count = count; ++ size_t copy_bytes = copy_count * element_size; ++ memcpy (target, buffer, copy_bytes); ++ target += copy_bytes; ++ count -= copy_count; ++ } ++ } ++ else ++ fill0 (target, element, element_size, count); ++} ++ ++/* Use malloc instead of mmap for small allocations and unusual size ++ combinations. */ ++static struct support_blob_repeat ++allocate_malloc (size_t total_size, const void *element, size_t element_size, ++ size_t count) ++{ ++ void *buffer = malloc (total_size); ++ if (buffer == NULL) ++ return (struct support_blob_repeat) { 0 }; ++ fill (buffer, element, element_size, count); ++ return (struct support_blob_repeat) ++ { ++ .start = buffer, ++ .size = total_size, ++ .use_malloc = true ++ }; ++} ++ ++/* Return the least common multiple of PAGE_SIZE and ELEMENT_SIZE, ++ avoiding overflow. This assumes that PAGE_SIZE is a power of ++ two. */ ++static size_t ++minimum_stride_size (size_t page_size, size_t element_size) ++{ ++ TEST_VERIFY_EXIT (page_size > 0); ++ TEST_VERIFY_EXIT (element_size > 0); ++ ++ /* Compute the number of trailing zeros common to both sizes. */ ++ unsigned int common_zeros = __builtin_ctzll (page_size | element_size); ++ ++ /* In the product, this power of two appears twice, but in the least ++ common multiple, it appears only once. Therefore, shift one ++ factor. */ ++ size_t multiple; ++ if (__builtin_mul_overflow (page_size >> common_zeros, element_size, ++ &multiple)) ++ return 0; ++ return multiple; ++} ++ ++/* Allocations larger than maximum_small_size potentially use mmap ++ with alias mappings. */ ++static struct support_blob_repeat ++allocate_big (size_t total_size, const void *element, size_t element_size, ++ size_t count) ++{ ++ unsigned long page_size = xsysconf (_SC_PAGESIZE); ++ size_t stride_size = minimum_stride_size (page_size, element_size); ++ if (stride_size == 0) ++ { ++ errno = EOVERFLOW; ++ return (struct support_blob_repeat) { 0 }; ++ } ++ ++ /* Ensure that the stride size is at least maximum_small_size. This ++ is necessary to reduce the number of distinct mappings. */ ++ if (stride_size < maximum_small_size) ++ stride_size ++ = ((maximum_small_size + stride_size - 1) / stride_size) * stride_size; ++ ++ if (stride_size > total_size) ++ /* The mmap optimization would not save anything. */ ++ return allocate_malloc (total_size, element, element_size, count); ++ ++ /* Reserve the memory region. If we cannot create the mapping, ++ there is no reason to set up the backing file. */ ++ void *target = mmap (NULL, total_size, PROT_NONE, ++ MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); ++ if (target == MAP_FAILED) ++ return (struct support_blob_repeat) { 0 }; ++ ++ /* Create the backing file for the repeated mapping. Call mkstemp ++ directly to remove the resources backing the temporary file ++ immediately, once support_blob_repeat_free is called. Using ++ create_temp_file would result in a warning during post-test ++ cleanup. */ ++ int fd; ++ { ++ char *temppath = xasprintf ("%s/support_blob_repeat-XXXXXX", test_dir); ++ fd = mkstemp (temppath); ++ if (fd < 0) ++ FAIL_EXIT1 ("mkstemp (\"%s\"): %m", temppath); ++ xunlink (temppath); ++ free (temppath); ++ } ++ ++ /* Make sure that there is backing storage, so that the fill ++ operation will not fault. */ ++ if (posix_fallocate (fd, 0, stride_size) != 0) ++ FAIL_EXIT1 ("posix_fallocate (%zu): %m", stride_size); ++ ++ /* The stride size must still be a multiple of the page size and ++ element size. */ ++ TEST_VERIFY_EXIT ((stride_size % page_size) == 0); ++ TEST_VERIFY_EXIT ((stride_size % element_size) == 0); ++ ++ /* Fill the backing store. */ ++ { ++ void *ptr = mmap (target, stride_size, PROT_READ | PROT_WRITE, ++ MAP_FIXED | MAP_FILE | MAP_SHARED, fd, 0); ++ if (ptr == MAP_FAILED) ++ { ++ int saved_errno = errno; ++ xmunmap (target, total_size); ++ xclose (fd); ++ errno = saved_errno; ++ return (struct support_blob_repeat) { 0 }; ++ } ++ if (ptr != target) ++ FAIL_EXIT1 ("mapping of %zu bytes moved from %p to %p", ++ stride_size, target, ptr); ++ ++ /* Write the repeating data. */ ++ fill (target, element, element_size, stride_size / element_size); ++ ++ /* Return to a PROT_NONE mapping, just to be on the safe side. */ ++ ptr = mmap (target, stride_size, PROT_NONE, ++ MAP_FIXED | MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); ++ if (ptr == MAP_FAILED) ++ FAIL_EXIT1 ("Failed to reinstate PROT_NONE mapping: %m"); ++ if (ptr != target) ++ FAIL_EXIT1 ("PROT_NONE mapping of %zu bytes moved from %p to %p", ++ stride_size, target, ptr); ++ } ++ ++ /* Create the alias mappings. */ ++ { ++ size_t remaining_size = total_size; ++ char *current = target; ++ int flags = MAP_FIXED | MAP_FILE | MAP_PRIVATE; ++#ifdef MAP_NORESERVE ++ flags |= MAP_NORESERVE; ++#endif ++ while (remaining_size > 0) ++ { ++ size_t to_map = stride_size; ++ if (to_map > remaining_size) ++ to_map = remaining_size; ++ void *ptr = mmap (current, to_map, PROT_READ | PROT_WRITE, ++ flags, fd, 0); ++ if (ptr == MAP_FAILED) ++ { ++ int saved_errno = errno; ++ xmunmap (target, total_size); ++ xclose (fd); ++ errno = saved_errno; ++ return (struct support_blob_repeat) { 0 }; ++ } ++ if (ptr != current) ++ FAIL_EXIT1 ("MAP_PRIVATE mapping of %zu bytes moved from %p to %p", ++ to_map, target, ptr); ++ remaining_size -= to_map; ++ current += to_map; ++ } ++ } ++ ++ xclose (fd); ++ ++ return (struct support_blob_repeat) ++ { ++ .start = target, ++ .size = total_size, ++ .use_malloc = false ++ }; ++} ++ ++struct support_blob_repeat ++support_blob_repeat_allocate (const void *element, size_t element_size, ++ size_t count) ++{ ++ size_t total_size; ++ if (__builtin_mul_overflow (element_size, count, &total_size)) ++ { ++ errno = EOVERFLOW; ++ return (struct support_blob_repeat) { 0 }; ++ } ++ if (total_size <= maximum_small_size) ++ return allocate_malloc (total_size, element, element_size, count); ++ else ++ return allocate_big (total_size, element, element_size, count); ++} ++ ++void ++support_blob_repeat_free (struct support_blob_repeat *blob) ++{ ++ if (blob->size > 0) ++ { ++ int saved_errno = errno; ++ if (blob->use_malloc) ++ free (blob->start); ++ else ++ xmunmap (blob->start, blob->size); ++ errno = saved_errno; ++ } ++ *blob = (struct support_blob_repeat) { 0 }; ++} +diff --git a/support/blob_repeat.h b/support/blob_repeat.h +new file mode 100644 +index 0000000000000000..8e9d7ff5f1e01f66 +--- /dev/null ++++ b/support/blob_repeat.h +@@ -0,0 +1,44 @@ ++/* Repeating a memory blob, with alias mapping optimization. ++ 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 SUPPORT_BLOB_REPEAT_H ++#define SUPPORT_BLOB_REPEAT_H ++ ++#include ++#include ++ ++struct support_blob_repeat ++{ ++ void *start; ++ size_t size; ++ bool use_malloc; ++}; ++ ++/* Return an allocation of COUNT elements, each of ELEMENT_SIZE bytes, ++ initialized with the bytes starting at ELEMENT. The memory is ++ writable (and thus counts towards the commit charge). In case of ++ on error, all members of the return struct are zero-initialized, ++ and errno is set accordingly. */ ++struct support_blob_repeat support_blob_repeat_allocate (const void *element, ++ size_t element_size, ++ size_t count); ++ ++/* Deallocate the blob created by support_blob_repeat_allocate. */ ++void support_blob_repeat_free (struct support_blob_repeat *); ++ ++#endif /* SUPPORT_BLOB_REPEAT_H */ +diff --git a/support/check.h b/support/check.h +index b3a4645e9255e90d..e6765289f2492501 100644 +--- a/support/check.h ++++ b/support/check.h +@@ -163,6 +163,19 @@ void support_test_compare_blob (const void *left, + const char *right_exp, + const char *right_len_exp); + ++/* Compare the strings LEFT and RIGHT and report a test failure if ++ they are different. Also report failure if one of the arguments is ++ a null pointer and the other is not. The strings should be ++ reasonably short because on mismatch, both are printed. */ ++#define TEST_COMPARE_STRING(left, right) \ ++ (support_test_compare_string (left, right, __FILE__, __LINE__, \ ++ #left, #right)) ++ ++void support_test_compare_string (const char *left, const char *right, ++ const char *file, int line, ++ const char *left_expr, ++ const char *right_expr); ++ + /* Internal function called by the test driver. */ + int support_report_failure (int status) + __attribute__ ((weak, warn_unused_result)); +diff --git a/support/echo-container.c b/support/echo-container.c +new file mode 100644 +index 0000000000000000..e4d48df95722af2e +--- /dev/null ++++ b/support/echo-container.c +@@ -0,0 +1,34 @@ ++/* Minimal /bin/echo for in-container use. ++ 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 ++ ++int ++main (int argc, const char **argv) ++{ ++ int i; ++ ++ for (i = 1; i < argc; i++) ++ { ++ if (i > 1) ++ putchar (' '); ++ fputs (argv[i], stdout); ++ } ++ putchar ('\n'); ++ return 0; ++} +diff --git a/support/links-dso-program-c.c b/support/links-dso-program-c.c +new file mode 100644 +index 0000000000000000..d28a28a0d09c743c +--- /dev/null ++++ b/support/links-dso-program-c.c +@@ -0,0 +1,9 @@ ++#include ++ ++int ++main (int argc, char **argv) ++{ ++ /* Complexity to keep gcc from optimizing this away. */ ++ printf ("This is a test %s.\n", argc > 1 ? argv[1] : "null"); ++ return 0; ++} +diff --git a/support/links-dso-program.cc b/support/links-dso-program.cc +new file mode 100644 +index 0000000000000000..dba6976c0609a332 +--- /dev/null ++++ b/support/links-dso-program.cc +@@ -0,0 +1,11 @@ ++#include ++ ++using namespace std; ++ ++int ++main (int argc, char **argv) ++{ ++ /* Complexity to keep gcc from optimizing this away. */ ++ cout << (argc > 1 ? argv[1] : "null"); ++ return 0; ++} +diff --git a/support/shell-container.c b/support/shell-container.c +new file mode 100644 +index 0000000000000000..9bd90d3f60529079 +--- /dev/null ++++ b/support/shell-container.c +@@ -0,0 +1,395 @@ ++/* Minimal /bin/sh for in-container use. ++ 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 ++ . */ ++ ++#define _FILE_OFFSET_BITS 64 ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++/* Design considerations ++ ++ General rule: optimize for developer time, not run time. ++ ++ Specifically: ++ ++ * Don't worry about slow algorithms ++ * Don't worry about free'ing memory ++ * Don't implement anything the testsuite doesn't need. ++ * Line and argument counts are limited, see below. ++ ++*/ ++ ++#define MAX_ARG_COUNT 100 ++#define MAX_LINE_LENGTH 1000 ++ ++/* Debugging is enabled via --debug, which must be the first argument. */ ++static int debug_mode = 0; ++#define dprintf if (debug_mode) fprintf ++ ++/* Emulate the "/bin/true" command. Arguments are ignored. */ ++static int ++true_func (char **argv) ++{ ++ return 0; ++} ++ ++/* Emulate the "/bin/echo" command. Options are ignored, arguments ++ are printed to stdout. */ ++static int ++echo_func (char **argv) ++{ ++ int i; ++ ++ for (i = 0; argv[i]; i++) ++ { ++ if (i > 0) ++ putchar (' '); ++ fputs (argv[i], stdout); ++ } ++ putchar ('\n'); ++ ++ return 0; ++} ++ ++/* Emulate the "/bin/cp" command. Options are ignored. Only copies ++ one source file to one destination file. Directory destinations ++ are not supported. */ ++static int ++copy_func (char **argv) ++{ ++ char *sname = argv[0]; ++ char *dname = argv[1]; ++ int sfd, dfd; ++ struct stat st; ++ ++ sfd = open (sname, O_RDONLY); ++ if (sfd < 0) ++ { ++ fprintf (stderr, "cp: unable to open %s for reading: %s\n", ++ sname, strerror (errno)); ++ return 1; ++ } ++ ++ if (fstat (sfd, &st) < 0) ++ { ++ fprintf (stderr, "cp: unable to fstat %s: %s\n", ++ sname, strerror (errno)); ++ return 1; ++ } ++ ++ dfd = open (dname, O_WRONLY | O_TRUNC | O_CREAT, 0600); ++ if (dfd < 0) ++ { ++ fprintf (stderr, "cp: unable to open %s for writing: %s\n", ++ dname, strerror (errno)); ++ return 1; ++ } ++ ++ if (support_copy_file_range (sfd, 0, dfd, 0, st.st_size, 0) != st.st_size) ++ { ++ fprintf (stderr, "cp: cannot copy file %s to %s: %s\n", ++ sname, dname, strerror (errno)); ++ return 1; ++ } ++ ++ close (sfd); ++ close (dfd); ++ ++ chmod (dname, st.st_mode & 0777); ++ ++ return 0; ++ ++} ++ ++/* This is a list of all the built-in commands we understand. */ ++static struct { ++ const char *name; ++ int (*func) (char **argv); ++} builtin_funcs[] = { ++ { "true", true_func }, ++ { "echo", echo_func }, ++ { "cp", copy_func }, ++ { NULL, NULL } ++}; ++ ++/* Run one tokenized command. argv[0] is the command. argv is ++ NULL-terminated. */ ++static void ++run_command_array (char **argv) ++{ ++ int i, j; ++ pid_t pid; ++ int status; ++ int (*builtin_func) (char **args); ++ ++ if (argv[0] == NULL) ++ return; ++ ++ builtin_func = NULL; ++ ++ int new_stdin = 0; ++ int new_stdout = 1; ++ int new_stderr = 2; ++ ++ dprintf (stderr, "run_command_array starting\n"); ++ for (i = 0; argv[i]; i++) ++ dprintf (stderr, " argv [%d] `%s'\n", i, argv[i]); ++ ++ for (j = i = 0; argv[i]; i++) ++ { ++ if (strcmp (argv[i], "<") == 0 && argv[i + 1]) ++ { ++ new_stdin = open (argv[i + 1], O_WRONLY|O_CREAT|O_TRUNC, 0777); ++ ++i; ++ continue; ++ } ++ if (strcmp (argv[i], ">") == 0 && argv[i + 1]) ++ { ++ new_stdout = open (argv[i + 1], O_WRONLY|O_CREAT|O_TRUNC, 0777); ++ ++i; ++ continue; ++ } ++ if (strcmp (argv[i], ">>") == 0 && argv[i + 1]) ++ { ++ new_stdout = open (argv[i + 1], O_WRONLY|O_CREAT|O_APPEND, 0777); ++ ++i; ++ continue; ++ } ++ if (strcmp (argv[i], "2>") == 0 && argv[i + 1]) ++ { ++ new_stderr = open (argv[i + 1], O_WRONLY|O_CREAT|O_TRUNC, 0777); ++ ++i; ++ continue; ++ } ++ argv[j++] = argv[i]; ++ } ++ argv[j] = NULL; ++ ++ ++ for (i = 0; builtin_funcs[i].name != NULL; i++) ++ if (strcmp (argv[0], builtin_funcs[i].name) == 0) ++ builtin_func = builtin_funcs[i].func; ++ ++ dprintf (stderr, "builtin %p argv0 `%s'\n", builtin_func, argv[0]); ++ ++ pid = fork (); ++ if (pid < 0) ++ { ++ fprintf (stderr, "sh: fork failed\n"); ++ exit (1); ++ } ++ ++ if (pid == 0) ++ { ++ if (new_stdin != 0) ++ { ++ dup2 (new_stdin, 0); ++ close (new_stdin); ++ } ++ if (new_stdout != 1) ++ { ++ dup2 (new_stdout, 1); ++ close (new_stdout); ++ } ++ if (new_stderr != 2) ++ { ++ dup2 (new_stderr, 2); ++ close (new_stdout); ++ } ++ ++ if (builtin_func != NULL) ++ exit (builtin_func (argv + 1)); ++ ++ execvp (argv[0], argv); ++ ++ fprintf (stderr, "sh: execing %s failed: %s", ++ argv[0], strerror (errno)); ++ exit (1); ++ } ++ ++ waitpid (pid, &status, 0); ++ ++ dprintf (stderr, "exiting run_command_array\n"); ++ ++ if (WIFEXITED (status)) ++ { ++ int rv = WEXITSTATUS (status); ++ if (rv) ++ exit (rv); ++ } ++ else ++ exit (1); ++} ++ ++/* Run one command-as-a-string, by tokenizing it. Limited to ++ MAX_ARG_COUNT arguments. Simple substitution is done of $1 to $9 ++ (as whole separate tokens) from iargs[]. Quoted strings work if ++ the quotes wrap whole tokens; i.e. "foo bar" but not foo" bar". */ ++static void ++run_command_string (const char *cmdline, const char **iargs) ++{ ++ char *args[MAX_ARG_COUNT+1]; ++ int ap = 0; ++ const char *start, *end; ++ int nargs; ++ ++ for (nargs = 0; iargs[nargs] != NULL; ++nargs) ++ ; ++ ++ dprintf (stderr, "run_command_string starting: '%s'\n", cmdline); ++ ++ while (ap < MAX_ARG_COUNT) ++ { ++ /* If the argument is quoted, this is the quote character, else NUL. */ ++ int in_quote = 0; ++ ++ /* Skip whitespace up to the next token. */ ++ while (*cmdline && isspace (*cmdline)) ++ cmdline ++; ++ if (*cmdline == 0) ++ break; ++ ++ start = cmdline; ++ /* Check for quoted argument. */ ++ in_quote = (*cmdline == '\'' || *cmdline == '"') ? *cmdline : 0; ++ ++ /* Skip to end of token; either by whitespace or matching quote. */ ++ dprintf (stderr, "in_quote %d\n", in_quote); ++ while (*cmdline ++ && (!isspace (*cmdline) || in_quote)) ++ { ++ if (*cmdline == in_quote ++ && cmdline != start) ++ in_quote = 0; ++ dprintf (stderr, "[%c]%d ", *cmdline, in_quote); ++ cmdline ++; ++ } ++ dprintf (stderr, "\n"); ++ ++ /* Allocate space for this token and store it in args[]. */ ++ end = cmdline; ++ dprintf (stderr, "start<%s> end<%s>\n", start, end); ++ args[ap] = (char *) xmalloc (end - start + 1); ++ memcpy (args[ap], start, end - start); ++ args[ap][end - start] = 0; ++ ++ /* Strip off quotes, if found. */ ++ dprintf (stderr, "args[%d] = <%s>\n", ap, args[ap]); ++ if (args[ap][0] == '\'' ++ && args[ap][strlen (args[ap])-1] == '\'') ++ { ++ args[ap][strlen (args[ap])-1] = 0; ++ args[ap] ++; ++ } ++ ++ else if (args[ap][0] == '"' ++ && args[ap][strlen (args[ap])-1] == '"') ++ { ++ args[ap][strlen (args[ap])-1] = 0; ++ args[ap] ++; ++ } ++ ++ /* Replace positional parameters like $4. */ ++ else if (args[ap][0] == '$' ++ && isdigit (args[ap][1]) ++ && args[ap][2] == 0) ++ { ++ int a = args[ap][1] - '1'; ++ if (0 <= a && a < nargs) ++ args[ap] = strdup (iargs[a]); ++ } ++ ++ ap ++; ++ ++ if (*cmdline == 0) ++ break; ++ } ++ ++ /* Lastly, NULL terminate the array and run it. */ ++ args[ap] = NULL; ++ run_command_array (args); ++} ++ ++/* Run a script by reading lines and passing them to the above ++ function. */ ++static void ++run_script (const char *filename, const char **args) ++{ ++ char line[MAX_LINE_LENGTH + 1]; ++ dprintf (stderr, "run_script starting: '%s'\n", filename); ++ FILE *f = fopen (filename, "r"); ++ if (f == NULL) ++ { ++ fprintf (stderr, "sh: %s: %s\n", filename, strerror (errno)); ++ exit (1); ++ } ++ while (fgets (line, sizeof (line), f) != NULL) ++ { ++ if (line[0] == '#') ++ { ++ dprintf (stderr, "comment: %s\n", line); ++ continue; ++ } ++ run_command_string (line, args); ++ } ++ fclose (f); ++} ++ ++int ++main (int argc, const char **argv) ++{ ++ int i; ++ ++ if (strcmp (argv[1], "--debug") == 0) ++ { ++ debug_mode = 1; ++ --argc; ++ ++argv; ++ } ++ ++ dprintf (stderr, "container-sh starting:\n"); ++ for (i = 0; i < argc; i++) ++ dprintf (stderr, " argv[%d] is `%s'\n", i, argv[i]); ++ ++ if (strcmp (argv[1], "-c") == 0) ++ run_command_string (argv[2], argv+3); ++ else ++ run_script (argv[1], argv+2); ++ ++ dprintf (stderr, "normal exit 0\n"); ++ return 0; ++} +diff --git a/support/support.h b/support/support.h +index b61fe0735c9204de..9418cd11ef6e684d 100644 +--- a/support/support.h ++++ b/support/support.h +@@ -25,6 +25,10 @@ + + #include + #include ++/* For mode_t. */ ++#include ++/* For ssize_t and off64_t. */ ++#include + + __BEGIN_DECLS + +@@ -65,6 +69,12 @@ void support_write_file_string (const char *path, const char *contents); + the result). */ + char *support_quote_blob (const void *blob, size_t length); + ++/* Returns non-zero if the file descriptor is a regular file on a file ++ system which supports holes (that is, seeking and writing does not ++ allocate storage for the range of zeros). FD must refer to a ++ regular file open for writing, and initially empty. */ ++int support_descriptor_supports_holes (int fd); ++ + /* Error-checking wrapper functions which terminate the process on + error. */ + +@@ -76,6 +86,23 @@ char *xasprintf (const char *format, ...) + char *xstrdup (const char *); + char *xstrndup (const char *, size_t); + ++/* These point to the TOP of the source/build tree, not your (or ++ support's) subdirectory. */ ++extern const char support_srcdir_root[]; ++extern const char support_objdir_root[]; ++ ++/* Corresponds to the path to the runtime linker used by the testsuite, ++ e.g. OBJDIR_PATH/elf/ld-linux-x86-64.so.2 */ ++extern const char support_objdir_elf_ldso[]; ++ ++/* Corresponds to the --prefix= passed to configure. */ ++extern const char support_install_prefix[]; ++/* Corresponds to the install's lib/ or lib64/ directory. */ ++extern const char support_libdir_prefix[]; ++ ++extern ssize_t support_copy_file_range (int, off64_t *, int, off64_t *, ++ size_t, unsigned int); ++ + __END_DECLS + + #endif /* SUPPORT_H */ +diff --git a/support/support_copy_file_range.c b/support/support_copy_file_range.c +new file mode 100644 +index 0000000000000000..9a1e39773e0481c9 +--- /dev/null ++++ b/support/support_copy_file_range.c +@@ -0,0 +1,143 @@ ++/* Simplified copy_file_range with cross-device copy. ++ 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 ++#include ++#include ++#include ++#include ++#include ++ ++ssize_t ++support_copy_file_range (int infd, __off64_t *pinoff, ++ int outfd, __off64_t *poutoff, ++ size_t length, unsigned int flags) ++{ ++ if (flags != 0) ++ { ++ errno = EINVAL; ++ return -1; ++ } ++ ++ struct stat64 instat; ++ struct stat64 outstat; ++ if (fstat64 (infd, &instat) != 0 || fstat64 (outfd, &outstat) != 0) ++ return -1; ++ if (S_ISDIR (instat.st_mode) || S_ISDIR (outstat.st_mode)) ++ { ++ errno = EISDIR; ++ return -1; ++ } ++ if (!S_ISREG (instat.st_mode) || !S_ISREG (outstat.st_mode)) ++ { ++ /* We need a regular input file so that the we can seek ++ backwards in case of a write failure. */ ++ errno = EINVAL; ++ return -1; ++ } ++ ++ /* The output descriptor must not have O_APPEND set. */ ++ if (fcntl (outfd, F_GETFL) & O_APPEND) ++ { ++ errno = EBADF; ++ return -1; ++ } ++ ++ /* Avoid an overflow in the result. */ ++ if (length > SSIZE_MAX) ++ length = SSIZE_MAX; ++ ++ /* Main copying loop. The buffer size is arbitrary and is a ++ trade-off between stack size consumption, cache usage, and ++ amortization of system call overhead. */ ++ size_t copied = 0; ++ char buf[8192]; ++ while (length > 0) ++ { ++ size_t to_read = length; ++ if (to_read > sizeof (buf)) ++ to_read = sizeof (buf); ++ ++ /* Fill the buffer. */ ++ ssize_t read_count; ++ if (pinoff == NULL) ++ read_count = read (infd, buf, to_read); ++ else ++ read_count = pread64 (infd, buf, to_read, *pinoff); ++ if (read_count == 0) ++ /* End of file reached prematurely. */ ++ return copied; ++ if (read_count < 0) ++ { ++ if (copied > 0) ++ /* Report the number of bytes copied so far. */ ++ return copied; ++ return -1; ++ } ++ if (pinoff != NULL) ++ *pinoff += read_count; ++ ++ /* Write the buffer part which was read to the destination. */ ++ char *end = buf + read_count; ++ for (char *p = buf; p < end; ) ++ { ++ ssize_t write_count; ++ if (poutoff == NULL) ++ write_count = write (outfd, p, end - p); ++ else ++ write_count = pwrite64 (outfd, p, end - p, *poutoff); ++ if (write_count < 0) ++ { ++ /* Adjust the input read position to match what we have ++ written, so that the caller can pick up after the ++ error. */ ++ size_t written = p - buf; ++ /* NB: This needs to be signed so that we can form the ++ negative value below. */ ++ ssize_t overread = read_count - written; ++ if (pinoff == NULL) ++ { ++ if (overread > 0) ++ { ++ /* We are on an error recovery path, so we ++ cannot deal with failure here. */ ++ int save_errno = errno; ++ (void) lseek64 (infd, -overread, SEEK_CUR); ++ errno = save_errno; ++ } ++ } ++ else /* pinoff != NULL */ ++ *pinoff -= overread; ++ ++ if (copied + written > 0) ++ /* Report the number of bytes copied so far. */ ++ return copied + written; ++ return -1; ++ } ++ p += write_count; ++ if (poutoff != NULL) ++ *poutoff += write_count; ++ } /* Write loop. */ ++ ++ copied += read_count; ++ length -= read_count; ++ } ++ return copied; ++} +diff --git a/support/support_descriptor_supports_holes.c b/support/support_descriptor_supports_holes.c +new file mode 100644 +index 0000000000000000..c7099ca67caf803c +--- /dev/null ++++ b/support/support_descriptor_supports_holes.c +@@ -0,0 +1,87 @@ ++/* Test for file system hole support. ++ 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 ++#include ++#include ++ ++int ++support_descriptor_supports_holes (int fd) ++{ ++ enum ++ { ++ /* Write offset for the enlarged file. This value is arbitrary ++ and hopefully large enough to trigger the creation of holes. ++ We cannot use the file system block size as a reference here ++ because it is incorrect for network file systems. */ ++ write_offset = 16 * 1024 * 1024, ++ ++ /* Our write may add this number of additional blocks (see ++ block_limit below). */ ++ block_headroom = 8, ++ }; ++ ++ struct stat64 st; ++ xfstat (fd, &st); ++ if (!S_ISREG (st.st_mode)) ++ FAIL_EXIT1 ("descriptor %d does not refer to a regular file", fd); ++ if (st.st_size != 0) ++ FAIL_EXIT1 ("descriptor %d does not refer to an empty file", fd); ++ if (st.st_blocks > block_headroom) ++ FAIL_EXIT1 ("descriptor %d refers to a pre-allocated file (%lld blocks)", ++ fd, (long long int) st.st_blocks); ++ ++ /* Write a single byte at the start of the file to compute the block ++ usage for a single byte. */ ++ xlseek (fd, 0, SEEK_SET); ++ char b = '@'; ++ xwrite (fd, &b, 1); ++ /* Attempt to bypass delayed allocation. */ ++ TEST_COMPARE (fsync (fd), 0); ++ xfstat (fd, &st); ++ ++ /* This limit is arbitrary. The file system needs to store ++ somewhere that data exists at the write offset, and this may ++ moderately increase the number of blocks used by the file, in ++ proportion to the initial block count, but not in proportion to ++ the write offset. */ ++ unsigned long long int block_limit = 2 * st.st_blocks + block_headroom; ++ ++ /* Write a single byte at 16 megabytes. */ ++ xlseek (fd, write_offset, SEEK_SET); ++ xwrite (fd, &b, 1); ++ /* Attempt to bypass delayed allocation. */ ++ TEST_COMPARE (fsync (fd), 0); ++ xfstat (fd, &st); ++ bool supports_holes = st.st_blocks <= block_limit; ++ ++ /* Also check that extending the file does not fill up holes. */ ++ xftruncate (fd, 2 * write_offset); ++ /* Attempt to bypass delayed allocation. */ ++ TEST_COMPARE (fsync (fd), 0); ++ xfstat (fd, &st); ++ supports_holes = supports_holes && st.st_blocks <= block_limit; ++ ++ /* Return to a zero-length file. */ ++ xftruncate (fd, 0); ++ xlseek (fd, 0, SEEK_SET); ++ ++ return supports_holes; ++} +diff --git a/support/support_paths.c b/support/support_paths.c +new file mode 100644 +index 0000000000000000..6d0beb102c9b4bed +--- /dev/null ++++ b/support/support_paths.c +@@ -0,0 +1,59 @@ ++/* Various paths that might be needed. ++ 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 ++ ++/* The idea here is to make various makefile-level paths available to ++ support programs, as canonicalized absolute paths. */ ++ ++/* These point to the TOP of the source/build tree, not your (or ++ support's) subdirectory. */ ++#ifdef SRCDIR_PATH ++const char support_srcdir_root[] = SRCDIR_PATH; ++#else ++# error please -DSRCDIR_PATH=something in the Makefile ++#endif ++ ++#ifdef OBJDIR_PATH ++const char support_objdir_root[] = OBJDIR_PATH; ++#else ++# error please -DOBJDIR_PATH=something in the Makefile ++#endif ++ ++#ifdef OBJDIR_ELF_LDSO_PATH ++/* Corresponds to the path to the runtime linker used by the testsuite, ++ e.g. OBJDIR_PATH/elf/ld-linux-x86-64.so.2 */ ++const char support_objdir_elf_ldso[] = OBJDIR_ELF_LDSO_PATH; ++#else ++# error please -DOBJDIR_ELF_LDSO_PATH=something in the Makefile ++#endif ++ ++#ifdef INSTDIR_PATH ++/* Corresponds to the --prefix= passed to configure. */ ++const char support_install_prefix[] = INSTDIR_PATH; ++#else ++# error please -DINSTDIR_PATH=something in the Makefile ++#endif ++ ++#ifdef LIBDIR_PATH ++/* Corresponds to the install's lib/ or lib64/ directory. */ ++const char support_libdir_prefix[] = LIBDIR_PATH; ++#else ++# error please -DLIBDIR_PATH=something in the Makefile ++#endif +diff --git a/support/support_test_compare_string.c b/support/support_test_compare_string.c +new file mode 100644 +index 0000000000000000..a76ba8eda7782d9d +--- /dev/null ++++ b/support/support_test_compare_string.c +@@ -0,0 +1,91 @@ ++/* Check two strings for equality. ++ 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 ++#include ++#include ++#include ++ ++static void ++report_length (const char *what, const char *str, size_t length) ++{ ++ if (str == NULL) ++ printf (" %s string: NULL\n", what); ++ else ++ printf (" %s string: %zu bytes\n", what, length); ++} ++ ++static void ++report_string (const char *what, const unsigned char *blob, ++ size_t length, const char *expr) ++{ ++ if (length > 0) ++ { ++ printf (" %s (evaluated from %s):\n", what, expr); ++ char *quoted = support_quote_blob (blob, length); ++ printf (" \"%s\"\n", quoted); ++ free (quoted); ++ ++ fputs (" ", stdout); ++ for (size_t i = 0; i < length; ++i) ++ printf (" %02X", blob[i]); ++ putc ('\n', stdout); ++ } ++} ++ ++static size_t ++string_length_or_zero (const char *str) ++{ ++ if (str == NULL) ++ return 0; ++ else ++ return strlen (str); ++} ++ ++void ++support_test_compare_string (const char *left, const char *right, ++ const char *file, int line, ++ const char *left_expr, const char *right_expr) ++{ ++ /* Two null pointers are accepted. */ ++ if (left == NULL && right == NULL) ++ return; ++ ++ size_t left_length = string_length_or_zero (left); ++ size_t right_length = string_length_or_zero (right); ++ ++ if (left_length != right_length || left == NULL || right == NULL ++ || memcmp (left, right, left_length) != 0) ++ { ++ support_record_failure (); ++ printf ("%s:%d: error: blob comparison failed\n", file, line); ++ if (left_length == right_length && right != NULL && left != NULL) ++ printf (" string length: %zu bytes\n", left_length); ++ else ++ { ++ report_length ("left", left, left_length); ++ report_length ("right", right, right_length); ++ } ++ report_string ("left", (const unsigned char *) left, ++ left_length, left_expr); ++ report_string ("right", (const unsigned char *) right, ++ right_length, right_expr); ++ } ++} +diff --git a/support/test-container.c b/support/test-container.c +new file mode 100644 +index 0000000000000000..b58f0f7b3d1d4859 +--- /dev/null ++++ b/support/test-container.c +@@ -0,0 +1,988 @@ ++/* Run a test case in an isolated namespace. ++ 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 ++ . */ ++ ++#define _FILE_OFFSET_BITS 64 ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#ifdef __linux__ ++#include ++#endif ++ ++#include ++#include ++#include "check.h" ++#include "test-driver.h" ++ ++#ifndef __linux__ ++#define mount(s,t,fs,f,d) no_mount() ++int no_mount (void) ++{ ++ FAIL_UNSUPPORTED("mount not supported; port needed"); ++} ++#endif ++ ++int verbose = 0; ++ ++/* Running a test in a container is tricky. There are two main ++ categories of things to do: ++ ++ 1. "Once" actions, like setting up the container and doing an ++ install into it. ++ ++ 2. "Per-test" actions, like copying in support files and ++ configuring the container. ++ ++ ++ "Once" actions: ++ ++ * mkdir $buildroot/testroot.pristine/ ++ * install into it ++ * rsync to $buildroot/testroot.root/ ++ ++ "Per-test" actions: ++ * maybe rsync to $buildroot/testroot.root/ ++ * copy support files and test binary ++ * chroot/unshare ++ * set up any mounts (like /proc) ++ ++ Magic files: ++ ++ For test $srcdir/foo/mytest.c we look for $srcdir/foo/mytest.root ++ and, if found... ++ ++ * mytest.root/ is rsync'd into container ++ * mytest.root/preclean.req causes fresh rsync (with delete) before ++ test if present ++ * mytest.root/mytset.script has a list of "commands" to run: ++ syntax: ++ # comment ++ mv FILE FILE ++ cp FILE FILE ++ rm FILE ++ FILE must start with $B/, $S/, $I/, $L/, or / ++ (expands to build dir, source dir, install dir, library dir ++ (in container), or container's root) ++ * mytest.root/postclean.req causes fresh rsync (with delete) after ++ test if present ++ ++ Note that $srcdir/foo/mytest.script may be used instead of a ++ $srcdir/foo/mytest.root/mytest.script in the sysroot template, if ++ there is no other reason for a sysroot. ++ ++ Design goals: ++ ++ * independent of other packages which may not be installed (like ++ rsync or Docker, or even "cp") ++ ++ * 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 ++ that it uses a lock to prevent parallel access to the testroot. */ ++ ++ ++/* Utility Functions */ ++ ++/* Like xunlink, but it's OK if the file already doesn't exist. */ ++void ++maybe_xunlink (const char *path) ++{ ++ int rv = unlink (path); ++ if (rv < 0 && errno != ENOENT) ++ FAIL_EXIT1 ("unlink (\"%s\"): %m", path); ++} ++ ++/* Like xmkdir, but it's OK if the directory already exists. */ ++void ++maybe_xmkdir (const char *path, mode_t mode) ++{ ++ struct stat st; ++ ++ if (stat (path, &st) == 0 ++ && S_ISDIR (st.st_mode)) ++ return; ++ xmkdir (path, mode); ++} ++ ++/* Temporarily concatenate multiple strings into one. Allows up to 10 ++ temporary results; use strdup () if you need them to be ++ permanent. */ ++static char * ++concat (const char *str, ...) ++{ ++ /* Assume initialized to NULL/zero. */ ++ static char *bufs[10]; ++ static size_t buflens[10]; ++ static int bufn = 0; ++ int n; ++ size_t len; ++ va_list ap, ap2; ++ char *cp; ++ char *next; ++ ++ va_start (ap, str); ++ va_copy (ap2, ap); ++ ++ n = bufn; ++ bufn = (bufn + 1) % 10; ++ len = strlen (str); ++ ++ while ((next = va_arg (ap, char *)) != NULL) ++ len = len + strlen (next); ++ ++ va_end (ap); ++ ++ if (bufs[n] == NULL) ++ { ++ bufs[n] = xmalloc (len + 1); /* NUL */ ++ buflens[n] = len + 1; ++ } ++ else if (buflens[n] < len + 1) ++ { ++ bufs[n] = xrealloc (bufs[n], len + 1); /* NUL */ ++ buflens[n] = len + 1; ++ } ++ ++ strcpy (bufs[n], str); ++ cp = strchr (bufs[n], '\0'); ++ while ((next = va_arg (ap2, char *)) != NULL) ++ { ++ strcpy (cp, next); ++ cp = strchr (cp, '\0'); ++ } ++ *cp = 0; ++ va_end (ap2); ++ ++ return bufs[n]; ++} ++ ++/* Try to mount SRC onto DEST. */ ++static void ++trymount (const char *src, const char *dest) ++{ ++ if (mount (src, dest, "", MS_BIND, NULL) < 0) ++ FAIL_EXIT1 ("can't mount %s onto %s\n", src, dest); ++} ++ ++/* Special case of above for devices like /dev/zero where we have to ++ mount a device over a device, not a directory over a directory. */ ++static void ++devmount (const char *new_root_path, const char *which) ++{ ++ int fd; ++ fd = open (concat (new_root_path, "/dev/", which, NULL), ++ O_CREAT | O_TRUNC | O_RDWR, 0777); ++ xclose (fd); ++ ++ trymount (concat ("/dev/", which, NULL), ++ concat (new_root_path, "/dev/", which, NULL)); ++} ++ ++/* Returns true if the string "looks like" an environement variable ++ being set. */ ++static int ++is_env_setting (const char *a) ++{ ++ int count_name = 0; ++ ++ while (*a) ++ { ++ if (isalnum (*a) || *a == '_') ++ ++count_name; ++ else if (*a == '=' && count_name > 0) ++ return 1; ++ else ++ return 0; ++ ++a; ++ } ++ return 0; ++} ++ ++/* Break the_line into words and store in the_words. Max nwords, ++ returns actual count. */ ++static int ++tokenize (char *the_line, char **the_words, int nwords) ++{ ++ int rv = 0; ++ ++ while (nwords > 0) ++ { ++ /* Skip leading whitespace, if any. */ ++ while (*the_line && isspace (*the_line)) ++ ++the_line; ++ ++ /* End of line? */ ++ if (*the_line == 0) ++ return rv; ++ ++ /* THE_LINE points to a non-whitespace character, so we have a ++ word. */ ++ *the_words = the_line; ++ ++the_words; ++ nwords--; ++ ++rv; ++ ++ /* Skip leading whitespace, if any. */ ++ while (*the_line && ! isspace (*the_line)) ++ ++the_line; ++ ++ /* We now point at the trailing NUL *or* some whitespace. */ ++ if (*the_line == 0) ++ return rv; ++ ++ /* It was whitespace, skip and keep tokenizing. */ ++ *the_line++ = 0; ++ } ++ ++ /* We get here if we filled the words buffer. */ ++ return rv; ++} ++ ++ ++/* Mini-RSYNC implementation. Optimize later. */ ++ ++/* A few routines for an "rsync buffer" which stores the paths we're ++ working on. We continuously grow and shrink the paths in each ++ buffer so there's lot of re-use. */ ++ ++/* We rely on "initialized to zero" to set these up. */ ++typedef struct ++{ ++ char *buf; ++ size_t len; ++ size_t size; ++} path_buf; ++ ++static path_buf spath, dpath; ++ ++static void ++r_setup (char *path, path_buf * pb) ++{ ++ size_t len = strlen (path); ++ if (pb->buf == NULL || pb->size < len + 1) ++ { ++ /* Round up. This is an arbitrary number, just to keep from ++ reallocing too often. */ ++ size_t sz = ALIGN_UP (len + 1, 512); ++ if (pb->buf == NULL) ++ pb->buf = (char *) xmalloc (sz); ++ else ++ pb->buf = (char *) xrealloc (pb->buf, sz); ++ if (pb->buf == NULL) ++ FAIL_EXIT1 ("Out of memory while rsyncing\n"); ++ ++ pb->size = sz; ++ } ++ strcpy (pb->buf, path); ++ pb->len = len; ++} ++ ++static void ++r_append (const char *path, path_buf * pb) ++{ ++ size_t len = strlen (path) + pb->len; ++ if (pb->size < len + 1) ++ { ++ /* Round up */ ++ size_t sz = ALIGN_UP (len + 1, 512); ++ pb->buf = (char *) xrealloc (pb->buf, sz); ++ if (pb->buf == NULL) ++ FAIL_EXIT1 ("Out of memory while rsyncing\n"); ++ ++ pb->size = sz; ++ } ++ strcpy (pb->buf + pb->len, path); ++ pb->len = len; ++} ++ ++static int ++file_exists (char *path) ++{ ++ struct stat st; ++ if (lstat (path, &st) == 0) ++ return 1; ++ return 0; ++} ++ ++static void ++recursive_remove (char *path) ++{ ++ pid_t child; ++ int status; ++ ++ child = fork (); ++ ++ switch (child) { ++ case -1: ++ FAIL_EXIT1 ("Unable to fork"); ++ case 0: ++ /* Child. */ ++ execlp ("rm", "rm", "-rf", path, NULL); ++ default: ++ /* Parent. */ ++ waitpid (child, &status, 0); ++ /* "rm" would have already printed a suitable error message. */ ++ if (! WIFEXITED (status) ++ || WEXITSTATUS (status) != 0) ++ exit (1); ++ ++ break; ++ } ++} ++ ++/* Used for both rsync and the mytest.script "cp" command. */ ++static void ++copy_one_file (const char *sname, const char *dname) ++{ ++ int sfd, dfd; ++ struct stat st; ++ struct utimbuf times; ++ ++ sfd = open (sname, O_RDONLY); ++ if (sfd < 0) ++ FAIL_EXIT1 ("unable to open %s for reading\n", sname); ++ ++ if (fstat (sfd, &st) < 0) ++ FAIL_EXIT1 ("unable to fstat %s\n", sname); ++ ++ dfd = open (dname, O_WRONLY | O_TRUNC | O_CREAT, 0600); ++ if (dfd < 0) ++ FAIL_EXIT1 ("unable to open %s for writing\n", dname); ++ ++ xcopy_file_range (sfd, 0, dfd, 0, st.st_size, 0); ++ ++ xclose (sfd); ++ xclose (dfd); ++ ++ if (chmod (dname, st.st_mode & 0777) < 0) ++ FAIL_EXIT1 ("chmod %s: %s\n", dname, strerror (errno)); ++ ++ times.actime = st.st_atime; ++ times.modtime = st.st_mtime; ++ if (utime (dname, ×) < 0) ++ FAIL_EXIT1 ("utime %s: %s\n", dname, strerror (errno)); ++} ++ ++/* We don't check *everything* about the two files to see if a copy is ++ needed, just the minimum to make sure we get the latest copy. */ ++static int ++need_sync (char *ap, char *bp, struct stat *a, struct stat *b) ++{ ++ if ((a->st_mode & S_IFMT) != (b->st_mode & S_IFMT)) ++ return 1; ++ ++ if (S_ISLNK (a->st_mode)) ++ { ++ int rv; ++ char *al, *bl; ++ ++ if (a->st_size != b->st_size) ++ return 1; ++ ++ al = xreadlink (ap); ++ bl = xreadlink (bp); ++ rv = strcmp (al, bl); ++ free (al); ++ free (bl); ++ if (rv == 0) ++ return 0; /* links are same */ ++ return 1; /* links differ */ ++ } ++ ++ if (verbose) ++ { ++ if (a->st_size != b->st_size) ++ printf ("SIZE\n"); ++ if ((a->st_mode & 0777) != (b->st_mode & 0777)) ++ printf ("MODE\n"); ++ if (a->st_mtime != b->st_mtime) ++ printf ("TIME\n"); ++ } ++ ++ if (a->st_size == b->st_size ++ && ((a->st_mode & 0777) == (b->st_mode & 0777)) ++ && a->st_mtime == b->st_mtime) ++ return 0; ++ ++ return 1; ++} ++ ++static void ++rsync_1 (path_buf * src, path_buf * dest, int and_delete) ++{ ++ DIR *dir; ++ struct dirent *de; ++ struct stat s, d; ++ ++ r_append ("/", src); ++ r_append ("/", dest); ++ ++ if (verbose) ++ printf ("sync %s to %s %s\n", src->buf, dest->buf, ++ and_delete ? "and delete" : ""); ++ ++ size_t staillen = src->len; ++ ++ size_t dtaillen = dest->len; ++ ++ dir = opendir (src->buf); ++ ++ while ((de = readdir (dir)) != NULL) ++ { ++ if (strcmp (de->d_name, ".") == 0 ++ || strcmp (de->d_name, "..") == 0) ++ continue; ++ ++ src->len = staillen; ++ r_append (de->d_name, src); ++ dest->len = dtaillen; ++ r_append (de->d_name, dest); ++ ++ s.st_mode = ~0; ++ d.st_mode = ~0; ++ ++ if (lstat (src->buf, &s) != 0) ++ FAIL_EXIT1 ("%s obtained by readdir, but stat failed.\n", src->buf); ++ ++ /* It's OK if this one fails, since we know the file might be ++ missing. */ ++ lstat (dest->buf, &d); ++ ++ if (! need_sync (src->buf, dest->buf, &s, &d)) ++ { ++ if (S_ISDIR (s.st_mode)) ++ rsync_1 (src, dest, and_delete); ++ continue; ++ } ++ ++ if (d.st_mode != ~0) ++ switch (d.st_mode & S_IFMT) ++ { ++ case S_IFDIR: ++ if (!S_ISDIR (s.st_mode)) ++ { ++ if (verbose) ++ printf ("-D %s\n", dest->buf); ++ recursive_remove (dest->buf); ++ } ++ break; ++ ++ default: ++ if (verbose) ++ printf ("-F %s\n", dest->buf); ++ maybe_xunlink (dest->buf); ++ break; ++ } ++ ++ switch (s.st_mode & S_IFMT) ++ { ++ case S_IFREG: ++ if (verbose) ++ printf ("+F %s\n", dest->buf); ++ copy_one_file (src->buf, dest->buf); ++ break; ++ ++ case S_IFDIR: ++ if (verbose) ++ printf ("+D %s\n", dest->buf); ++ maybe_xmkdir (dest->buf, (s.st_mode & 0777) | 0700); ++ rsync_1 (src, dest, and_delete); ++ break; ++ ++ case S_IFLNK: ++ { ++ char *lp; ++ if (verbose) ++ printf ("+L %s\n", dest->buf); ++ lp = xreadlink (src->buf); ++ xsymlink (lp, dest->buf); ++ free (lp); ++ break; ++ } ++ ++ default: ++ break; ++ } ++ } ++ ++ closedir (dir); ++ src->len = staillen; ++ src->buf[staillen] = 0; ++ dest->len = dtaillen; ++ dest->buf[dtaillen] = 0; ++ ++ if (!and_delete) ++ return; ++ ++ /* The rest of this function removes any files/directories in DEST ++ that do not exist in SRC. This is triggered as part of a ++ preclean or postsclean step. */ ++ ++ dir = opendir (dest->buf); ++ ++ while ((de = readdir (dir)) != NULL) ++ { ++ if (strcmp (de->d_name, ".") == 0 ++ || strcmp (de->d_name, "..") == 0) ++ continue; ++ ++ src->len = staillen; ++ r_append (de->d_name, src); ++ dest->len = dtaillen; ++ r_append (de->d_name, dest); ++ ++ s.st_mode = ~0; ++ d.st_mode = ~0; ++ ++ lstat (src->buf, &s); ++ ++ if (lstat (dest->buf, &d) != 0) ++ FAIL_EXIT1 ("%s obtained by readdir, but stat failed.\n", dest->buf); ++ ++ if (s.st_mode == ~0) ++ { ++ /* dest exists and src doesn't, clean it. */ ++ switch (d.st_mode & S_IFMT) ++ { ++ case S_IFDIR: ++ if (!S_ISDIR (s.st_mode)) ++ { ++ if (verbose) ++ printf ("-D %s\n", dest->buf); ++ recursive_remove (dest->buf); ++ } ++ break; ++ ++ default: ++ if (verbose) ++ printf ("-F %s\n", dest->buf); ++ maybe_xunlink (dest->buf); ++ break; ++ } ++ } ++ } ++ ++ closedir (dir); ++} ++ ++static void ++rsync (char *src, char *dest, int and_delete) ++{ ++ r_setup (src, &spath); ++ r_setup (dest, &dpath); ++ ++ rsync_1 (&spath, &dpath, and_delete); ++} ++ ++ ++int ++main (int argc, char **argv) ++{ ++ pid_t child; ++ char *pristine_root_path; ++ char *new_root_path; ++ char *new_cwd_path; ++ char *new_objdir_path; ++ char *new_srcdir_path; ++ char **new_child_proc; ++ char *command_root; ++ char *command_base; ++ char *command_basename; ++ char *so_base; ++ int do_postclean = 0; ++ ++ uid_t original_uid; ++ gid_t original_gid; ++ int UMAP; ++ int GMAP; ++ /* Used for "%lld %lld 1" so need not be large. */ ++ char tmp[100]; ++ struct stat st; ++ int lock_fd; ++ ++ setbuf (stdout, NULL); ++ ++ /* The command line we're expecting looks like this: ++ env ld.so test-binary ++ ++ We need to peel off any "env" or "ld.so" portion of the command ++ line, and keep track of which env vars we should preserve and ++ which we drop. */ ++ ++ if (argc < 2) ++ { ++ fprintf (stderr, "Usage: containerize \n"); ++ exit (1); ++ } ++ ++ if (strcmp (argv[1], "-v") == 0) ++ { ++ verbose = 1; ++ ++argv; ++ --argc; ++ } ++ ++ if (strcmp (argv[1], "env") == 0) ++ { ++ ++argv; ++ --argc; ++ while (is_env_setting (argv[1])) ++ { ++ /* If there are variables we do NOT want to propogate, this ++ is where the test for them goes. */ ++ { ++ /* Need to keep these. Note that putenv stores a ++ pointer to our argv. */ ++ putenv (argv[1]); ++ } ++ ++argv; ++ --argc; ++ } ++ } ++ ++ if (strcmp (argv[1], support_objdir_elf_ldso) == 0) ++ { ++ ++argv; ++ --argc; ++ while (argv[1][0] == '-') ++ { ++ if (strcmp (argv[1], "--library-path") == 0) ++ { ++ ++argv; ++ --argc; ++ } ++ ++argv; ++ --argc; ++ } ++ } ++ ++ pristine_root_path = strdup (concat (support_objdir_root, ++ "/testroot.pristine", NULL)); ++ new_root_path = strdup (concat (support_objdir_root, ++ "/testroot.root", NULL)); ++ new_cwd_path = get_current_dir_name (); ++ new_child_proc = argv + 1; ++ ++ lock_fd = open (concat (pristine_root_path, "/lock.fd", NULL), ++ O_CREAT | O_TRUNC | O_RDWR, 0666); ++ if (lock_fd < 0) ++ FAIL_EXIT1 ("Cannot create testroot lock.\n"); ++ ++ while (flock (lock_fd, LOCK_EX) != 0) ++ { ++ if (errno != EINTR) ++ FAIL_EXIT1 ("Cannot lock testroot.\n"); ++ } ++ ++ xmkdirp (new_root_path, 0755); ++ ++ /* We look for extra setup info in a subdir in the same spot as the ++ test, with the same name but a ".root" extension. This is that ++ directory. We try to look in the source tree if the path we're ++ given refers to the build tree, but we rely on the path to be ++ absolute. This is what the glibc makefiles do. */ ++ command_root = concat (argv[1], ".root", NULL); ++ if (strncmp (command_root, support_objdir_root, ++ strlen (support_objdir_root)) == 0 ++ && command_root[strlen (support_objdir_root)] == '/') ++ command_root = concat (support_srcdir_root, ++ argv[1] + strlen (support_objdir_root), ++ ".root", NULL); ++ command_root = strdup (command_root); ++ ++ /* This cuts off the ".root" we appended above. */ ++ command_base = strdup (command_root); ++ command_base[strlen (command_base) - 5] = 0; ++ ++ /* This is the basename of the test we're running. */ ++ command_basename = strrchr (command_base, '/'); ++ if (command_basename == NULL) ++ command_basename = command_base; ++ else ++ ++command_basename; ++ ++ /* Shared object base directory. */ ++ so_base = strdup (argv[1]); ++ if (strrchr (so_base, '/') != NULL) ++ strrchr (so_base, '/')[1] = 0; ++ ++ if (file_exists (concat (command_root, "/postclean.req", NULL))) ++ do_postclean = 1; ++ ++ rsync (pristine_root_path, new_root_path, ++ file_exists (concat (command_root, "/preclean.req", NULL))); ++ ++ if (stat (command_root, &st) >= 0 ++ && S_ISDIR (st.st_mode)) ++ rsync (command_root, new_root_path, 0); ++ ++ new_objdir_path = strdup (concat (new_root_path, ++ support_objdir_root, NULL)); ++ new_srcdir_path = strdup (concat (new_root_path, ++ support_srcdir_root, NULL)); ++ ++ /* new_cwd_path starts with '/' so no "/" needed between the two. */ ++ xmkdirp (concat (new_root_path, new_cwd_path, NULL), 0755); ++ xmkdirp (new_srcdir_path, 0755); ++ xmkdirp (new_objdir_path, 0755); ++ ++ original_uid = getuid (); ++ original_gid = getgid (); ++ ++ /* Handle the cp/mv/rm "script" here. */ ++ { ++ char *the_line = NULL; ++ size_t line_len = 0; ++ char *fname = concat (command_root, "/", ++ command_basename, ".script", NULL); ++ char *the_words[3]; ++ FILE *f = fopen (fname, "r"); ++ ++ if (verbose && f) ++ fprintf (stderr, "running %s\n", fname); ++ ++ if (f == NULL) ++ { ++ /* Try foo.script instead of foo.root/foo.script, as a shortcut. */ ++ fname = concat (command_base, ".script", NULL); ++ f = fopen (fname, "r"); ++ if (verbose && f) ++ fprintf (stderr, "running %s\n", fname); ++ } ++ ++ /* Note that we do NOT look for a Makefile-generated foo.script in ++ the build directory. If that is ever needed, this is the place ++ to add it. */ ++ ++ /* This is where we "interpret" the mini-script which is .script. */ ++ if (f != NULL) ++ { ++ while (getline (&the_line, &line_len, f) > 0) ++ { ++ int nt = tokenize (the_line, the_words, 3); ++ int i; ++ ++ for (i = 1; i < nt; ++i) ++ { ++ if (memcmp (the_words[i], "$B/", 3) == 0) ++ the_words[i] = concat (support_objdir_root, ++ the_words[i] + 2, NULL); ++ else if (memcmp (the_words[i], "$S/", 3) == 0) ++ the_words[i] = concat (support_srcdir_root, ++ the_words[i] + 2, NULL); ++ else if (memcmp (the_words[i], "$I/", 3) == 0) ++ the_words[i] = concat (new_root_path, ++ support_install_prefix, ++ the_words[i] + 2, NULL); ++ else if (memcmp (the_words[i], "$L/", 3) == 0) ++ the_words[i] = concat (new_root_path, ++ support_libdir_prefix, ++ the_words[i] + 2, NULL); ++ else if (the_words[i][0] == '/') ++ the_words[i] = concat (new_root_path, ++ the_words[i], NULL); ++ } ++ ++ if (nt == 3 && the_words[2][strlen (the_words[2]) - 1] == '/') ++ { ++ char *r = strrchr (the_words[1], '/'); ++ if (r) ++ the_words[2] = concat (the_words[2], r + 1, NULL); ++ else ++ the_words[2] = concat (the_words[2], the_words[1], NULL); ++ } ++ ++ if (nt == 2 && strcmp (the_words[0], "so") == 0) ++ { ++ the_words[2] = concat (new_root_path, support_libdir_prefix, ++ "/", the_words[1], NULL); ++ the_words[1] = concat (so_base, the_words[1], NULL); ++ copy_one_file (the_words[1], the_words[2]); ++ } ++ else if (nt == 3 && strcmp (the_words[0], "cp") == 0) ++ { ++ copy_one_file (the_words[1], the_words[2]); ++ } ++ else if (nt == 3 && strcmp (the_words[0], "mv") == 0) ++ { ++ if (rename (the_words[1], the_words[2]) < 0) ++ FAIL_EXIT1 ("rename %s -> %s: %s", the_words[1], ++ the_words[2], strerror (errno)); ++ } ++ else if (nt == 3 && strcmp (the_words[0], "chmod") == 0) ++ { ++ long int m; ++ m = strtol (the_words[1], NULL, 0); ++ if (chmod (the_words[2], m) < 0) ++ FAIL_EXIT1 ("chmod %s: %s\n", ++ the_words[2], strerror (errno)); ++ ++ } ++ else if (nt == 2 && strcmp (the_words[0], "rm") == 0) ++ { ++ maybe_xunlink (the_words[1]); ++ } ++ else if (nt > 0 && the_words[0][0] != '#') ++ { ++ printf ("\033[31minvalid [%s]\033[0m\n", the_words[0]); ++ } ++ } ++ fclose (f); ++ } ++ } ++ ++#ifdef CLONE_NEWNS ++ /* The unshare here gives us our own spaces and capabilities. */ ++ if (unshare (CLONE_NEWUSER | CLONE_NEWPID | CLONE_NEWNS) < 0) ++ { ++ /* Older kernels may not support all the options, or security ++ policy may block this call. */ ++ if (errno == EINVAL || errno == EPERM) ++ FAIL_UNSUPPORTED ("unable to unshare user/fs: %s", strerror (errno)); ++ else ++ FAIL_EXIT1 ("unable to unshare user/fs: %s", strerror (errno)); ++ } ++#else ++ /* Some targets may not support unshare at all. */ ++ FAIL_UNSUPPORTED ("unshare support missing"); ++#endif ++ ++ /* Some systems, by default, all mounts leak out of the namespace. */ ++ if (mount ("none", "/", NULL, MS_REC | MS_PRIVATE, NULL) != 0) ++ FAIL_EXIT1 ("could not create a private mount namespace\n"); ++ ++ trymount (support_srcdir_root, new_srcdir_path); ++ trymount (support_objdir_root, new_objdir_path); ++ ++ xmkdirp (concat (new_root_path, "/dev", NULL), 0755); ++ devmount (new_root_path, "null"); ++ devmount (new_root_path, "zero"); ++ devmount (new_root_path, "urandom"); ++ ++ /* We're done with the "old" root, switch to the new one. */ ++ if (chroot (new_root_path) < 0) ++ FAIL_EXIT1 ("Can't chroot to %s - ", new_root_path); ++ ++ if (chdir (new_cwd_path) < 0) ++ FAIL_EXIT1 ("Can't cd to new %s - ", new_cwd_path); ++ ++ /* To complete the containerization, we need to fork () at least ++ once. We can't exec, nor can we somehow link the new child to ++ our parent. So we run the child and propogate it's exit status ++ up. */ ++ child = fork (); ++ if (child < 0) ++ FAIL_EXIT1 ("Unable to fork"); ++ else if (child > 0) ++ { ++ /* Parent. */ ++ int status; ++ waitpid (child, &status, 0); ++ ++ /* There's a bit of magic here, since the buildroot is mounted ++ in our space, the paths are still valid, and since the mounts ++ aren't recursive, it sees *only* the built root, not anything ++ we would normally se if we rsync'd to "/" like mounted /dev ++ files. */ ++ if (do_postclean) ++ rsync (pristine_root_path, new_root_path, 1); ++ ++ if (WIFEXITED (status)) ++ exit (WEXITSTATUS (status)); ++ ++ if (WIFSIGNALED (status)) ++ { ++ printf ("%%SIGNALLED%%\n"); ++ exit (77); ++ } ++ ++ printf ("%%EXITERROR%%\n"); ++ exit (78); ++ } ++ ++ /* The rest is the child process, which is now PID 1 and "in" the ++ new root. */ ++ ++ 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) 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); ++ } ++ ++ /* 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) original_gid, (long long) original_gid); ++ write (GMAP, tmp, strlen (tmp)); ++ xclose (GMAP); ++ ++ /* Now run the child. */ ++ execvp (new_child_proc[0], new_child_proc); ++ ++ /* Or don't run the child? */ ++ FAIL_EXIT1 ("Unable to exec %s\n", new_child_proc[0]); ++ ++ /* Because gcc won't know error () never returns... */ ++ exit (EXIT_UNSUPPORTED); ++} +diff --git a/support/true-container.c b/support/true-container.c +new file mode 100644 +index 0000000000000000..57dc57e252a96acc +--- /dev/null ++++ b/support/true-container.c +@@ -0,0 +1,26 @@ ++/* Minimal /bin/true for in-container use. ++ 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 ++ . */ ++ ++/* Implements the in-container /bin/true, which always returns true ++ (0). */ ++ ++int ++main (void) ++{ ++ return 0; ++} +diff --git a/support/tst-support_blob_repeat.c b/support/tst-support_blob_repeat.c +new file mode 100644 +index 0000000000000000..1978c14488106ff2 +--- /dev/null ++++ b/support/tst-support_blob_repeat.c +@@ -0,0 +1,85 @@ ++/* Tests for ++ 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 ++ ++static int ++do_test (void) ++{ ++ struct support_blob_repeat repeat ++ = support_blob_repeat_allocate ("5", 1, 5); ++ TEST_COMPARE_BLOB (repeat.start, repeat.size, "55555", 5); ++ support_blob_repeat_free (&repeat); ++ ++ repeat = support_blob_repeat_allocate ("ABC", 3, 3); ++ TEST_COMPARE_BLOB (repeat.start, repeat.size, "ABCABCABC", 9); ++ support_blob_repeat_free (&repeat); ++ ++ repeat = support_blob_repeat_allocate ("abc", 4, 3); ++ TEST_COMPARE_BLOB (repeat.start, repeat.size, "abc\0abc\0abc", 12); ++ support_blob_repeat_free (&repeat); ++ ++ size_t gigabyte = 1U << 30; ++ repeat = support_blob_repeat_allocate ("X", 1, gigabyte + 1); ++ if (repeat.start == NULL) ++ puts ("warning: not enough memory for 1 GiB mapping"); ++ else ++ { ++ TEST_COMPARE (repeat.size, gigabyte + 1); ++ { ++ unsigned char *p = repeat.start; ++ for (size_t i = 0; i < gigabyte + 1; ++i) ++ if (p[i] != 'X') ++ FAIL_EXIT1 ("invalid byte 0x%02x at %zu", p[i], i); ++ ++ /* Check that there is no sharing across the mapping. */ ++ p[0] = 'Y'; ++ p[1U << 24] = 'Z'; ++ for (size_t i = 0; i < gigabyte + 1; ++i) ++ if (i == 0) ++ TEST_COMPARE (p[i], 'Y'); ++ else if (i == 1U << 24) ++ TEST_COMPARE (p[i], 'Z'); ++ else if (p[i] != 'X') ++ FAIL_EXIT1 ("invalid byte 0x%02x at %zu", p[i], i); ++ } ++ } ++ support_blob_repeat_free (&repeat); ++ ++ repeat = support_blob_repeat_allocate ("012345678", 9, 10 * 1000 * 1000); ++ if (repeat.start == NULL) ++ puts ("warning: not enough memory for large mapping"); ++ else ++ { ++ unsigned char *p = repeat.start; ++ for (int i = 0; i < 10 * 1000 * 1000; ++i) ++ for (int j = 0; j <= 8; ++j) ++ if (p[i * 9 + j] != '0' + j) ++ { ++ printf ("error: element %d index %d\n", i, j); ++ TEST_COMPARE (p[i * 9 + j], '0' + j); ++ } ++ } ++ support_blob_repeat_free (&repeat); ++ ++ return 0; ++} ++ ++#include +diff --git a/support/tst-test_compare_string.c b/support/tst-test_compare_string.c +new file mode 100644 +index 0000000000000000..2a4b258587a7c8ec +--- /dev/null ++++ b/support/tst-test_compare_string.c +@@ -0,0 +1,107 @@ ++/* Basic test for the TEST_COMPARE_STRING macro. ++ 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 ++ ++static void ++subprocess (void *closure) ++{ ++ /* These tests should fail. They were chosen to cover differences ++ in length (with the same contents), single-bit mismatches, and ++ mismatching null pointers. */ ++ TEST_COMPARE_STRING ("", NULL); /* Line 29. */ ++ TEST_COMPARE_STRING ("X", ""); /* Line 30. */ ++ TEST_COMPARE_STRING (NULL, "X"); /* Line 31. */ ++ TEST_COMPARE_STRING ("abcd", "abcD"); /* Line 32. */ ++ TEST_COMPARE_STRING ("abcd", NULL); /* Line 33. */ ++ TEST_COMPARE_STRING (NULL, "abcd"); /* Line 34. */ ++} ++ ++/* Same contents, different addresses. */ ++char buffer_abc_1[] = "abc"; ++char buffer_abc_2[] = "abc"; ++ ++static int ++do_test (void) ++{ ++ /* This should succeed. Even if the pointers and array contents are ++ different, zero-length inputs are not different. */ ++ TEST_COMPARE_STRING (NULL, NULL); ++ TEST_COMPARE_STRING ("", ""); ++ TEST_COMPARE_STRING (buffer_abc_1, buffer_abc_2); ++ TEST_COMPARE_STRING (buffer_abc_1, "abc"); ++ ++ struct support_capture_subprocess proc = support_capture_subprocess ++ (&subprocess, NULL); ++ ++ /* Discard the reported error. */ ++ support_record_failure_reset (); ++ ++ puts ("info: *** subprocess output starts ***"); ++ fputs (proc.out.buffer, stdout); ++ puts ("info: *** subprocess output ends ***"); ++ ++ TEST_VERIFY ++ (strcmp (proc.out.buffer, ++"tst-test_compare_string.c:29: error: blob comparison failed\n" ++" left string: 0 bytes\n" ++" right string: NULL\n" ++"tst-test_compare_string.c:30: error: blob comparison failed\n" ++" left string: 1 bytes\n" ++" right string: 0 bytes\n" ++" left (evaluated from \"X\"):\n" ++" \"X\"\n" ++" 58\n" ++"tst-test_compare_string.c:31: error: blob comparison failed\n" ++" left string: NULL\n" ++" right string: 1 bytes\n" ++" right (evaluated from \"X\"):\n" ++" \"X\"\n" ++" 58\n" ++"tst-test_compare_string.c:32: error: blob comparison failed\n" ++" string length: 4 bytes\n" ++" left (evaluated from \"abcd\"):\n" ++" \"abcd\"\n" ++" 61 62 63 64\n" ++" right (evaluated from \"abcD\"):\n" ++" \"abcD\"\n" ++" 61 62 63 44\n" ++"tst-test_compare_string.c:33: error: blob comparison failed\n" ++" left string: 4 bytes\n" ++" right string: NULL\n" ++" left (evaluated from \"abcd\"):\n" ++" \"abcd\"\n" ++" 61 62 63 64\n" ++"tst-test_compare_string.c:34: error: blob comparison failed\n" ++" left string: NULL\n" ++" right string: 4 bytes\n" ++" right (evaluated from \"abcd\"):\n" ++" \"abcd\"\n" ++" 61 62 63 64\n" ++ ) == 0); ++ ++ /* Check that there is no output on standard error. */ ++ support_capture_subprocess_check (&proc, "TEST_COMPARE_STRING", ++ 0, sc_allow_stdout); ++ ++ return 0; ++} ++ ++#include +diff --git a/support/xcopy_file_range.c b/support/xcopy_file_range.c +new file mode 100644 +index 0000000000000000..b3501a4d5ec3fdfd +--- /dev/null ++++ b/support/xcopy_file_range.c +@@ -0,0 +1,32 @@ ++/* copy_file_range with error checking. ++ 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 ++ ++ssize_t ++xcopy_file_range (int infd, off64_t *pinoff, int outfd, off64_t *poutoff, ++ size_t length, unsigned int flags) ++{ ++ ssize_t status = support_copy_file_range (infd, pinoff, outfd, ++ poutoff, length, flags); ++ if (status == -1) ++ FAIL_EXIT1 ("cannot copy file: %m\n"); ++ return status; ++} +diff --git a/support/xmkdirp.c b/support/xmkdirp.c +new file mode 100644 +index 0000000000000000..fada0452eafe269e +--- /dev/null ++++ b/support/xmkdirp.c +@@ -0,0 +1,66 @@ ++/* Error-checking replacement for "mkdir -p". ++ 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 ++ ++#include ++#include ++#include ++ ++/* Equivalent of "mkdir -p". Any failures cause FAIL_EXIT1 so no ++ return code is needed. */ ++ ++void ++xmkdirp (const char *path, mode_t mode) ++{ ++ struct stat s; ++ const char *slash_p; ++ int rv; ++ ++ if (path[0] == 0) ++ return; ++ ++ if (stat (path, &s) == 0) ++ { ++ if (S_ISDIR (s.st_mode)) ++ return; ++ errno = EEXIST; ++ FAIL_EXIT1 ("mkdir_p (\"%s\", 0%o): %m", path, mode); ++ } ++ ++ slash_p = strrchr (path, '/'); ++ if (slash_p != NULL) ++ { ++ while (slash_p > path && slash_p[-1] == '/') ++ --slash_p; ++ if (slash_p > path) ++ { ++ char *parent = xstrndup (path, slash_p - path); ++ xmkdirp (parent, mode); ++ free (parent); ++ } ++ } ++ ++ rv = mkdir (path, mode); ++ if (rv != 0) ++ FAIL_EXIT1 ("mkdir_p (\"%s\", 0%o): %m", path, mode); ++ ++ return; ++} +diff --git a/support/xsymlink.c b/support/xsymlink.c +new file mode 100644 +index 0000000000000000..0f3edf640a1a99a6 +--- /dev/null ++++ b/support/xsymlink.c +@@ -0,0 +1,29 @@ ++/* Error-checking replacement for "symlink". ++ 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 ++ ++void ++xsymlink (const char *target, const char *linkpath) ++{ ++ if (symlink (target, linkpath) < 0) ++ FAIL_EXIT1 ("symlink (\"%s\", \"%s\")", target, linkpath); ++} +diff --git a/support/xunistd.h b/support/xunistd.h +index 5fe5dae818def4ec..f99f362cb4763c5b 100644 +--- a/support/xunistd.h ++++ b/support/xunistd.h +@@ -43,6 +43,10 @@ void xunlink (const char *path); + long xsysconf (int name); + long long xlseek (int fd, long long offset, int whence); + void xftruncate (int fd, long long length); ++void xsymlink (const char *target, const char *linkpath); ++ ++/* Equivalent of "mkdir -p". */ ++void xmkdirp (const char *, mode_t); + + /* Read the link at PATH. The caller should free the returned string + with free. */ +@@ -60,6 +64,9 @@ void *xmmap (void *addr, size_t length, int prot, int flags, int fd); + void xmprotect (void *addr, size_t length, int prot); + void xmunmap (void *addr, size_t length); + ++ssize_t xcopy_file_range(int fd_in, loff_t *off_in, int fd_out, ++ loff_t *off_out, size_t len, unsigned int flags); ++ + __END_DECLS + + #endif /* SUPPORT_XUNISTD_H */ diff --git a/SOURCES/glibc-rh1638523-2.patch b/SOURCES/glibc-rh1638523-2.patch new file mode 100644 index 0000000..cf3ade5 --- /dev/null +++ b/SOURCES/glibc-rh1638523-2.patch @@ -0,0 +1,80 @@ +commit 6c3a8a9d868a8deddf0d6dcc785b6d120de90523 +Author: Paul Pluzhnikov +Date: Fri Aug 24 18:08:51 2018 -0700 + + Fix BZ#23400 (creating temporary files in source tree), and undefined behavior in test. + +diff --git a/stdlib/test-bz22786.c b/stdlib/test-bz22786.c +index e7837f98c19fc4bf..d1aa69106ccf6ac5 100644 +--- a/stdlib/test-bz22786.c ++++ b/stdlib/test-bz22786.c +@@ -26,28 +26,20 @@ + #include + #include + #include ++#include ++#include ++#include + #include + #include + + static int + do_test (void) + { +- const char dir[] = "bz22786"; +- const char lnk[] = "bz22786/symlink"; ++ const char *dir = support_create_temp_directory ("bz22786."); ++ const char *lnk = xasprintf ("%s/symlink", dir); ++ const size_t path_len = (size_t) INT_MAX + strlen (lnk) + 1; + +- rmdir (dir); +- if (mkdir (dir, 0755) != 0 && errno != EEXIST) +- { +- printf ("mkdir %s: %m\n", dir); +- return EXIT_FAILURE; +- } +- if (symlink (".", lnk) != 0 && errno != EEXIST) +- { +- printf ("symlink (%s, %s): %m\n", dir, lnk); +- return EXIT_FAILURE; +- } +- +- const size_t path_len = (size_t) INT_MAX + 1; ++ TEST_VERIFY_EXIT (symlink (".", lnk) == 0); + + DIAG_PUSH_NEEDS_COMMENT; + #if __GNUC_PREREQ (7, 0) +@@ -55,20 +47,14 @@ do_test (void) + allocation to succeed for the test to work. */ + DIAG_IGNORE_NEEDS_COMMENT (7, "-Walloc-size-larger-than="); + #endif +- char *path = malloc (path_len); ++ char *path = xmalloc (path_len); + DIAG_POP_NEEDS_COMMENT; + +- if (path == NULL) +- { +- printf ("malloc (%zu): %m\n", path_len); +- return EXIT_UNSUPPORTED; +- } +- +- /* Construct very long path = "bz22786/symlink/aaaa....." */ +- char *p = mempcpy (path, lnk, sizeof (lnk) - 1); ++ /* Construct very long path = "/tmp/bz22786.XXXX/symlink/aaaa....." */ ++ char *p = mempcpy (path, lnk, strlen (lnk)); + *(p++) = '/'; +- memset (p, 'a', path_len - (path - p) - 2); +- p[path_len - (path - p) - 1] = '\0'; ++ memset (p, 'a', path_len - (p - path) - 2); ++ p[path_len - (p - path) - 1] = '\0'; + + /* This call crashes before the fix for bz22786 on 32-bit platforms. */ + p = realpath (path, NULL); +@@ -81,7 +67,6 @@ do_test (void) + + /* Cleanup. */ + unlink (lnk); +- rmdir (dir); + + return 0; + } diff --git a/SOURCES/glibc-rh1638523-3.patch b/SOURCES/glibc-rh1638523-3.patch new file mode 100644 index 0000000..8ad2241 --- /dev/null +++ b/SOURCES/glibc-rh1638523-3.patch @@ -0,0 +1,55 @@ +commit 3bad2358d67d371497079bba4f8eca9c0096f4e2 +Author: Stefan Liebler +Date: Thu Aug 30 08:44:32 2018 +0200 + + Test stdlib/test-bz22786 exits now with unsupported if malloc fails. + + The test tries to allocate more than 2^31 bytes which will always fail on s390 + as it has maximum 2^31bit of memory. + Before commit 6c3a8a9d868a8deddf0d6dcc785b6d120de90523, this test returned + unsupported if malloc fails. This patch re enables this behaviour. + + Furthermore support_delete_temp_files() failed to remove the temp directory + in this case as it is not empty due to the created symlink. + Thus the creation of the symlink is moved behind malloc. + + Reviewed-by: Carlos O'Donell + + ChangeLog: + + * stdlib/test-bz22786.c (do_test): Return EXIT_UNSUPPORTED + if malloc fails. + +diff --git a/stdlib/test-bz22786.c b/stdlib/test-bz22786.c +index d1aa69106ccf6ac5..777bf9180f4b5022 100644 +--- a/stdlib/test-bz22786.c ++++ b/stdlib/test-bz22786.c +@@ -39,16 +39,25 @@ do_test (void) + const char *lnk = xasprintf ("%s/symlink", dir); + const size_t path_len = (size_t) INT_MAX + strlen (lnk) + 1; + +- TEST_VERIFY_EXIT (symlink (".", lnk) == 0); +- + DIAG_PUSH_NEEDS_COMMENT; + #if __GNUC_PREREQ (7, 0) + /* GCC 7 warns about too-large allocations; here we need such + allocation to succeed for the test to work. */ + DIAG_IGNORE_NEEDS_COMMENT (7, "-Walloc-size-larger-than="); + #endif +- char *path = xmalloc (path_len); ++ char *path = malloc (path_len); + DIAG_POP_NEEDS_COMMENT; ++ if (path == NULL) ++ { ++ printf ("malloc (%zu): %m\n", path_len); ++ /* On 31-bit s390 the malloc will always fail as we do not have ++ so much memory, and we want to mark the test unsupported. ++ Likewise on systems with little physical memory the test will ++ fail and should be unsupported. */ ++ return EXIT_UNSUPPORTED; ++ } ++ ++ TEST_VERIFY_EXIT (symlink (".", lnk) == 0); + + /* Construct very long path = "/tmp/bz22786.XXXX/symlink/aaaa....." */ + char *p = mempcpy (path, lnk, strlen (lnk)); diff --git a/SOURCES/glibc-rh1638523-4.patch b/SOURCES/glibc-rh1638523-4.patch new file mode 100644 index 0000000..d5e0efb --- /dev/null +++ b/SOURCES/glibc-rh1638523-4.patch @@ -0,0 +1,65 @@ +commit f5e7e95921847bd83186bfe621fc2b48c4de5477 +Author: Florian Weimer +Date: Tue Oct 30 13:11:47 2018 +0100 + + stdlib/test-bz22786: Avoid spurious test failures using alias mappings + + On systems without enough random-access memory, stdlib/test-bz22786 + will go deeply into swap and time out, even with a substantial + TIMEOUTFACTOR. This commit adds a facility to construct repeating + strings with alias mappings, so that the requirement for physical + memory, and uses it in stdlib/test-bz22786. + +Adjusted here for conflicts due to the previous support/ backport in +glibc-rh1638523-1.patch. + +diff --git a/stdlib/test-bz22786.c b/stdlib/test-bz22786.c +index 777bf9180f4b5022..bb1e04f2debe9042 100644 +--- a/stdlib/test-bz22786.c ++++ b/stdlib/test-bz22786.c +@@ -26,6 +26,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -39,17 +40,12 @@ do_test (void) + const char *lnk = xasprintf ("%s/symlink", dir); + const size_t path_len = (size_t) INT_MAX + strlen (lnk) + 1; + +- DIAG_PUSH_NEEDS_COMMENT; +-#if __GNUC_PREREQ (7, 0) +- /* GCC 7 warns about too-large allocations; here we need such +- allocation to succeed for the test to work. */ +- DIAG_IGNORE_NEEDS_COMMENT (7, "-Walloc-size-larger-than="); +-#endif +- char *path = malloc (path_len); +- DIAG_POP_NEEDS_COMMENT; ++ struct support_blob_repeat repeat ++ = support_blob_repeat_allocate ("a", 1, path_len); ++ char *path = repeat.start; + if (path == NULL) + { +- printf ("malloc (%zu): %m\n", path_len); ++ printf ("Repeated allocation (%zu bytes): %m\n", path_len); + /* On 31-bit s390 the malloc will always fail as we do not have + so much memory, and we want to mark the test unsupported. + Likewise on systems with little physical memory the test will +@@ -62,7 +58,6 @@ do_test (void) + /* Construct very long path = "/tmp/bz22786.XXXX/symlink/aaaa....." */ + char *p = mempcpy (path, lnk, strlen (lnk)); + *(p++) = '/'; +- memset (p, 'a', path_len - (p - path) - 2); + p[path_len - (p - path) - 1] = '\0'; + + /* This call crashes before the fix for bz22786 on 32-bit platforms. */ +@@ -76,6 +71,7 @@ do_test (void) + + /* Cleanup. */ + unlink (lnk); ++ support_blob_repeat_free (&repeat); + + return 0; + } diff --git a/SOURCES/glibc-rh1638523-5.patch b/SOURCES/glibc-rh1638523-5.patch new file mode 100644 index 0000000..c0ed47d --- /dev/null +++ b/SOURCES/glibc-rh1638523-5.patch @@ -0,0 +1,51 @@ +commit 07da99aad93c9364acb7efdab47c27ba698f6313 +Author: Florian Weimer +Date: Tue Oct 30 13:55:01 2018 +0100 + + stdlib/tst-strtod-overflow: Switch to support_blob_repeat + + This is another test with an avoidable large memory allocation. + +diff --git a/stdlib/tst-strtod-overflow.c b/stdlib/tst-strtod-overflow.c +index d14638d68ef4f471..dc53c1e521443e1d 100644 +--- a/stdlib/tst-strtod-overflow.c ++++ b/stdlib/tst-strtod-overflow.c +@@ -19,6 +19,8 @@ + #include + #include + #include ++#include ++#include + + #define EXPONENT "e-2147483649" + #define SIZE 214748364 +@@ -26,21 +28,23 @@ + static int + do_test (void) + { +- char *p = malloc (1 + SIZE + sizeof (EXPONENT)); +- if (p == NULL) ++ struct support_blob_repeat repeat = support_blob_repeat_allocate ++ ("0", 1, 1 + SIZE + sizeof (EXPONENT)); ++ if (repeat.size == 0) + { +- puts ("malloc failed, cannot test for overflow"); +- return 0; ++ puts ("warning: memory allocation failed, cannot test for overflow"); ++ return EXIT_UNSUPPORTED; + } ++ char *p = repeat.start; + p[0] = '1'; +- memset (p + 1, '0', SIZE); + memcpy (p + 1 + SIZE, EXPONENT, sizeof (EXPONENT)); + double d = strtod (p, NULL); + if (d != 0) + { +- printf ("strtod returned wrong value: %a\n", d); ++ printf ("error: strtod returned wrong value: %a\n", d); + return 1; + } ++ support_blob_repeat_free (&repeat); + return 0; + } + diff --git a/SOURCES/glibc-rh1638523-6.patch b/SOURCES/glibc-rh1638523-6.patch new file mode 100644 index 0000000..ea8509f --- /dev/null +++ b/SOURCES/glibc-rh1638523-6.patch @@ -0,0 +1,30 @@ +commit 60708030536df82616c16aa2f14f533c4362b969 +Author: Florian Weimer +Date: Tue Oct 30 13:56:40 2018 +0100 + + stdlib/test-bz22786: Avoid memory leaks in the test itself + +diff --git a/stdlib/test-bz22786.c b/stdlib/test-bz22786.c +index bb1e04f2debe9042..8035e8a394e7d034 100644 +--- a/stdlib/test-bz22786.c ++++ b/stdlib/test-bz22786.c +@@ -36,8 +36,8 @@ + static int + do_test (void) + { +- const char *dir = support_create_temp_directory ("bz22786."); +- const char *lnk = xasprintf ("%s/symlink", dir); ++ char *dir = support_create_temp_directory ("bz22786."); ++ char *lnk = xasprintf ("%s/symlink", dir); + const size_t path_len = (size_t) INT_MAX + strlen (lnk) + 1; + + struct support_blob_repeat repeat +@@ -72,6 +72,8 @@ do_test (void) + /* Cleanup. */ + unlink (lnk); + support_blob_repeat_free (&repeat); ++ free (lnk); ++ free (dir); + + return 0; + } diff --git a/SOURCES/glibc-rh1639343-1.patch b/SOURCES/glibc-rh1639343-1.patch new file mode 100644 index 0000000..51d2226 --- /dev/null +++ b/SOURCES/glibc-rh1639343-1.patch @@ -0,0 +1,35 @@ +commit f9b645b4b0a10c43753296ce3fa40053fa44606a +Author: Mike Frysinger +Date: Wed Apr 24 13:32:22 2019 +0200 + + memusagestat: use local glibc when linking [BZ #18465] + + The memusagestat is the only binary that has its own link line which + causes it to be linked against the existing installed C library. It + has been this way since it was originally committed in 1999, but I + don't see any reason as to why. Since we want all the programs we + build locally to be against the new copy of glibc, change the build + to be like all other programs. + +diff --git a/malloc/Makefile b/malloc/Makefile +index 388cf7e9ee3a2569..228a1279a5960d8c 100644 +--- a/malloc/Makefile ++++ b/malloc/Makefile +@@ -131,6 +131,7 @@ ifneq ($(cross-compiling),yes) + # If the gd library is available we build the `memusagestat' program. + ifneq ($(LIBGD),no) + others: $(objpfx)memusage ++others += memusagestat + install-bin = memusagestat + install-bin-script += memusage + generated += memusagestat memusage +@@ -154,8 +155,7 @@ cpp-srcs-left := $(memusagestat-modules) + lib := memusagestat + include $(patsubst %,$(..)libof-iterator.mk,$(cpp-srcs-left)) + +-$(objpfx)memusagestat: $(memusagestat-modules:%=$(objpfx)%.o) +- $(LINK.o) -o $@ $^ $(libgd-LDFLAGS) -lgd -lpng -lz -lm ++LDLIBS-memusagestat = $(libgd-LDFLAGS) -lgd -lpng -lz -lm + + ifeq ($(run-built-tests),yes) + ifeq (yes,$(build-shared)) diff --git a/SOURCES/glibc-rh1639343-2.patch b/SOURCES/glibc-rh1639343-2.patch new file mode 100644 index 0000000..c5e4aa5 --- /dev/null +++ b/SOURCES/glibc-rh1639343-2.patch @@ -0,0 +1,90 @@ +commit 94a4e9e4f401ffe829a992820439977ead0a0ce7 +Author: Florian Weimer +Date: Thu Apr 25 10:41:43 2019 +0200 + + Extend BIND_NOW to installed programs with --enable-bind-now + + Commit 2d6ab5df3b675e96ee587ae6a8c2ce004c6b1ba9 ("Document and fix + --enable-bind-now [BZ #21015]") extended BIND_NOW to all installed + shared objects. This change also covers installed programs. + + Reviewed-by: Carlos O'Donell + +diff --git a/INSTALL b/INSTALL +index d6c8e899fbb47dac..d56e102ec9ed3281 100644 +--- a/INSTALL ++++ b/INSTALL +@@ -169,10 +169,10 @@ if 'CFLAGS' is specified it must enable optimization. For example: + protection. + + '--enable-bind-now' +- Disable lazy binding for installed shared objects. This provides +- additional security hardening because it enables full RELRO and a +- read-only global offset table (GOT), at the cost of slightly +- increased program load times. ++ Disable lazy binding for installed shared objects and programs. ++ This provides additional security hardening because it enables full ++ RELRO and a read-only global offset table (GOT), at the cost of ++ slightly increased program load times. + + '--enable-pt_chown' + The file 'pt_chown' is a helper binary for 'grantpt' (*note +diff --git a/Makeconfig b/Makeconfig +index 8dc2fec9dc683416..742c0c0783a14bfa 100644 +--- a/Makeconfig ++++ b/Makeconfig +@@ -398,6 +398,8 @@ endif + # test modules. + ifeq ($(bind-now),yes) + LDFLAGS-lib.so += -Wl,-z,now ++# Extra flags for dynamically linked non-test main programs. ++link-extra-flags += -Wl,-z,now + endif + + # Command to run after every final link (executable or shared object). +@@ -426,7 +428,7 @@ ifndef +link-pie + $(link-extra-libs) + +link-pie-after-libc = $(+postctorS) $(+postinit) + define +link-pie +-$(+link-pie-before-libc) $(rtld-LDFLAGS) $(link-libc) $(+link-pie-after-libc) ++$(+link-pie-before-libc) $(rtld-LDFLAGS) $(link-extra-flags) $(link-libc) $(+link-pie-after-libc) + $(call after-link,$@) + endef + define +link-pie-tests +@@ -454,7 +456,7 @@ ifndef +link-static + $(link-extra-libs-static) + +link-static-after-libc = $(+postctorT) $(+postinit) + define +link-static +-$(+link-static-before-libc) $(link-libc-static) $(+link-static-after-libc) ++$(+link-static-before-libc) $(link-extra-flags) $(link-libc-static) $(+link-static-after-libc) + $(call after-link,$@) + endef + define +link-static-tests +@@ -485,7 +487,7 @@ else # not build-pie-default + $(link-extra-libs) + +link-after-libc = $(+postctor) $(+postinit) + define +link +-$(+link-before-libc) $(rtld-LDFLAGS) $(link-libc) $(+link-after-libc) ++$(+link-before-libc) $(rtld-LDFLAGS) $(link-extra-flags) $(link-libc) $(+link-after-libc) + $(call after-link,$@) + endef + define +link-tests +diff --git a/manual/install.texi b/manual/install.texi +index e757891dc2eebb2e..351d67c68b255f62 100644 +--- a/manual/install.texi ++++ b/manual/install.texi +@@ -199,10 +199,10 @@ number of routines called directly from assembler are excluded from this + protection. + + @item --enable-bind-now +-Disable lazy binding for installed shared objects. This provides +-additional security hardening because it enables full RELRO and a +-read-only global offset table (GOT), at the cost of slightly increased +-program load times. ++Disable lazy binding for installed shared objects and programs. This ++provides additional security hardening because it enables full RELRO ++and a read-only global offset table (GOT), at the cost of slightly ++increased program load times. + + @pindex pt_chown + @findex grantpt diff --git a/SOURCES/glibc-rh1639343-3.patch b/SOURCES/glibc-rh1639343-3.patch new file mode 100644 index 0000000..4e4e146 --- /dev/null +++ b/SOURCES/glibc-rh1639343-3.patch @@ -0,0 +1,43 @@ +commit b5ffdc48c20ae865b197b67e5a9068a528fbc198 +Author: Florian Weimer +Date: Thu Apr 25 10:41:52 2019 +0200 + + benchtests: Enable BIND_NOW if configured with --enable-bind-now + + Benchmarks should reflect distribution build policies, so it makes + sense to honor the BIND_NOW configuration for them. + + This commit keeps using $(+link-tests), so that the benchmarks are + linked according to the --enable-hardcoded-path-in-tests configure + option. + + Reviewed-by: Carlos O'Donell + +diff --git a/benchtests/Makefile b/benchtests/Makefile +index bcd6a9c26d9a0005..28d6b0c43f5bd390 100644 +--- a/benchtests/Makefile ++++ b/benchtests/Makefile +@@ -235,13 +235,21 @@ bench-func: $(binaries-bench) + scripts/benchout.schema.json; \ + fi + +-$(timing-type) $(binaries-bench) $(binaries-benchset) \ +- $(binaries-bench-malloc): %: %.o $(objpfx)json-lib.o \ ++ifeq ($(bind-now),yes) ++link-bench-bind-now = -Wl,-z,now ++endif ++ ++bench-link-targets = $(timing-type) $(binaries-bench) $(binaries-benchset) \ ++ $(binaries-bench-malloc) ++ ++$(bench-link-targets): %: %.o $(objpfx)json-lib.o \ + $(link-extra-libs-tests) \ + $(sort $(filter $(common-objpfx)lib%,$(link-libc))) \ + $(addprefix $(csu-objpfx),start.o) $(+preinit) $(+postinit) + $(+link-tests) + ++$(bench-link-targets): LDFLAGS += $(link-bench-bind-now) ++ + $(objpfx)bench-%.c: %-inputs $(bench-deps) + { if [ -n "$($*-INCLUDE)" ]; then \ + cat $($*-INCLUDE); \ diff --git a/SOURCES/glibc-rh1639343-4.patch b/SOURCES/glibc-rh1639343-4.patch new file mode 100644 index 0000000..10d4b48 --- /dev/null +++ b/SOURCES/glibc-rh1639343-4.patch @@ -0,0 +1,100 @@ +commit e30fb31c0ad8d31babd1d0d0f05e37c6579a870b +Author: Florian Weimer +Date: Fri Apr 26 07:16:47 2019 +0200 + + Makeconfig: Move $(CC) to +link command variables + + This change is needed to add linker flags which come very early in the + command linke (before LDFLAGS) and are not applied to test programs + (only to installed programs). + +diff --git a/Makeconfig b/Makeconfig +index 742c0c0783a14bfa..1ad25fc5a7251aea 100644 +--- a/Makeconfig ++++ b/Makeconfig +@@ -415,7 +415,7 @@ link-extra-libs-tests = $(libsupport) + + # Command for linking PIE programs with the C library. + ifndef +link-pie +-+link-pie-before-libc = $(CC) $(if $($(@F)-no-pie),$(no-pie-ldflag),-pie) \ +++link-pie-before-libc = $(if $($(@F)-no-pie),$(no-pie-ldflag),-pie) \ + -Wl,-O1 -nostdlib -nostartfiles -o $@ \ + $(sysdep-LDFLAGS) $(LDFLAGS) $(LDFLAGS-$(@F)) \ + $(combreloc-LDFLAGS) $(relro-LDFLAGS) $(hashstyle-LDFLAGS) \ +@@ -428,23 +428,24 @@ ifndef +link-pie + $(link-extra-libs) + +link-pie-after-libc = $(+postctorS) $(+postinit) + define +link-pie +-$(+link-pie-before-libc) $(rtld-LDFLAGS) $(link-extra-flags) $(link-libc) $(+link-pie-after-libc) ++$(CC) $(+link-pie-before-libc) $(rtld-LDFLAGS) $(link-extra-flags) \ ++ $(link-libc) $(+link-pie-after-libc) + $(call after-link,$@) + endef + define +link-pie-tests +-$(+link-pie-before-libc) $(rtld-tests-LDFLAGS) $(link-libc-tests) \ +- $(+link-pie-after-libc) ++$(CC) $(+link-pie-before-libc) $(rtld-tests-LDFLAGS) $(link-libc-tests) \ ++ $(+link-pie-after-libc) + $(call after-link,$@) + endef + define +link-pie-printers-tests +-$(+link-pie-before-libc) $(built-rtld-LDFLAGS) $(link-libc-printers-tests) \ +- $(+link-pie-after-libc) ++$(CC) $(+link-pie-before-libc) $(built-rtld-LDFLAGS) \ ++ $(link-libc-printers-tests) $(+link-pie-after-libc) + $(call after-link,$@) + endef + endif + # Command for statically linking programs with the C library. + ifndef +link-static +-+link-static-before-libc = $(CC) -nostdlib -nostartfiles -static -o $@ \ +++link-static-before-libc = -nostdlib -nostartfiles -static -o $@ \ + $(if $($(@F)-no-pie),$(no-pie-ldflag),$(default-pie-ldflag)) \ + $(sysdep-LDFLAGS) $(LDFLAGS) $(LDFLAGS-$(@F)) \ + $(firstword $(CRT-$(@F)) $(csu-objpfx)$(real-static-start-installed-name)) \ +@@ -456,11 +457,13 @@ ifndef +link-static + $(link-extra-libs-static) + +link-static-after-libc = $(+postctorT) $(+postinit) + define +link-static +-$(+link-static-before-libc) $(link-extra-flags) $(link-libc-static) $(+link-static-after-libc) ++$(CC) $(+link-static-before-libc) $(link-extra-flags) $(link-libc-static) \ ++ $(+link-static-after-libc) + $(call after-link,$@) + endef + define +link-static-tests +-$(+link-static-before-libc) $(link-libc-static-tests) $(+link-static-after-libc) ++$(CC) $(+link-static-before-libc) $(link-libc-static-tests) \ ++ $(+link-static-after-libc) + $(call after-link,$@) + endef + endif +@@ -475,7 +478,7 @@ ifeq (yes,$(build-pie-default)) + +link-tests = $(+link-pie-tests) + +link-printers-tests = $(+link-pie-printers-tests) + else # not build-pie-default +-+link-before-libc = $(CC) -nostdlib -nostartfiles -o $@ \ +++link-before-libc = -nostdlib -nostartfiles -o $@ \ + $(sysdep-LDFLAGS) $(LDFLAGS) $(LDFLAGS-$(@F)) \ + $(combreloc-LDFLAGS) $(relro-LDFLAGS) $(hashstyle-LDFLAGS) \ + $(firstword $(CRT-$(@F)) $(csu-objpfx)$(start-installed-name)) \ +@@ -487,16 +490,17 @@ else # not build-pie-default + $(link-extra-libs) + +link-after-libc = $(+postctor) $(+postinit) + define +link +-$(+link-before-libc) $(rtld-LDFLAGS) $(link-extra-flags) $(link-libc) $(+link-after-libc) ++$(CC) $(+link-before-libc) $(rtld-LDFLAGS) $(link-extra-flags) $(link-libc) \ ++ $(+link-after-libc) + $(call after-link,$@) + endef + define +link-tests +-$(+link-before-libc) $(rtld-tests-LDFLAGS) $(link-libc-tests) \ ++$(CC) $(+link-before-libc) $(rtld-tests-LDFLAGS) $(link-libc-tests) \ + $(+link-after-libc) + $(call after-link,$@) + endef + define +link-printers-tests +-$(+link-before-libc) $(built-rtld-LDFLAGS) $(link-libc-printers-tests) \ ++$(CC) $(+link-before-libc) $(built-rtld-LDFLAGS) $(link-libc-printers-tests) \ + $(+link-after-libc) + $(call after-link,$@) + endef diff --git a/SOURCES/glibc-rh1639343-5.patch b/SOURCES/glibc-rh1639343-5.patch new file mode 100644 index 0000000..cefd167 --- /dev/null +++ b/SOURCES/glibc-rh1639343-5.patch @@ -0,0 +1,74 @@ +commit a8ff215e56050a907189e713fd449bcafe99ff6b +Author: Florian Weimer +Date: Fri Apr 26 07:16:30 2019 +0200 + + Makeconfig: Move -Wl,-rpath-link options before library references + + Previously, the -Wl,-rpath-link options came after the libraries + injected using LDLIBS-* variables on the link editor command line for + main programs. As a result, it could happen that installed libraries + that reference glibc libraries used the installed glibc from the system + directories, instead of the glibc from the build tree. This can lead to + link failures if the wrong version of libpthread.so.0 is used, for + instance, due to differences in the internal GLIBC_PRIVATE interfaces, + as seen with memusagestat and -lgd after commit + f9b645b4b0a10c43753296ce3fa40053fa44606a ("memusagestat: use local glibc + when linking [BZ #18465]"). + + The isolation is necessarily imperfect because these installed + libraries are linked against the installed glibc in the system + directories. However, in most cases, the built glibc will be newer + than the installed glibc, and this link is permitted because of the + ABI backwards compatibility glibc provides. + +diff --git a/Makeconfig b/Makeconfig +index 1ad25fc5a7251aea..e315fb8a75ca5063 100644 +--- a/Makeconfig ++++ b/Makeconfig +@@ -428,8 +428,8 @@ ifndef +link-pie + $(link-extra-libs) + +link-pie-after-libc = $(+postctorS) $(+postinit) + define +link-pie +-$(CC) $(+link-pie-before-libc) $(rtld-LDFLAGS) $(link-extra-flags) \ +- $(link-libc) $(+link-pie-after-libc) ++$(CC) $(link-libc-rpath-link) $(+link-pie-before-libc) $(rtld-LDFLAGS) \ ++ $(link-extra-flags) $(link-libc) $(+link-pie-after-libc) + $(call after-link,$@) + endef + define +link-pie-tests +@@ -490,8 +490,8 @@ else # not build-pie-default + $(link-extra-libs) + +link-after-libc = $(+postctor) $(+postinit) + define +link +-$(CC) $(+link-before-libc) $(rtld-LDFLAGS) $(link-extra-flags) $(link-libc) \ +- $(+link-after-libc) ++$(CC) $(link-libc-rpath-link) $(+link-before-libc) $(rtld-LDFLAGS) \ ++ $(link-extra-flags) $(link-libc) $(+link-after-libc) + $(call after-link,$@) + endef + define +link-tests +@@ -552,6 +552,15 @@ ifeq (yes,$(build-shared)) + link-libc-rpath = -Wl,-rpath=$(rpath-link) + link-libc-rpath-link = -Wl,-rpath-link=$(rpath-link) + ++# For programs which are not tests, $(link-libc-rpath-link) is added ++# directly in $(+link), $(+link-pie) above, so that -Wl,-rpath-link ++# comes before the expansion of LDLIBS-* and affects libraries added ++# there. For shared objects, -Wl,-rpath-link is added via ++# $(build-shlib-helper) and $(build-module-helper) in Makerules (also ++# before the expansion of LDLIBS-* variables). ++ ++# Tests use -Wl,-rpath instead of -Wl,-rpath-link for ++# build-hardcoded-path-in-tests. + ifeq (yes,$(build-hardcoded-path-in-tests)) + link-libc-tests-rpath-link = $(link-libc-rpath) + else +@@ -562,7 +571,7 @@ link-libc-before-gnulib = $(common-objpfx)libc.so$(libc.so-version) \ + $(common-objpfx)$(patsubst %,$(libtype.oS),c) \ + $(as-needed) $(elf-objpfx)ld.so \ + $(no-as-needed) +-link-libc = $(link-libc-rpath-link) $(link-libc-before-gnulib) $(gnulib) ++link-libc = $(link-libc-before-gnulib) $(gnulib) + + link-libc-tests-after-rpath-link = $(link-libc-before-gnulib) $(gnulib-tests) + link-libc-tests = $(link-libc-tests-rpath-link) \ diff --git a/SOURCES/glibc-rh1639343-6.patch b/SOURCES/glibc-rh1639343-6.patch new file mode 100644 index 0000000..643e192 --- /dev/null +++ b/SOURCES/glibc-rh1639343-6.patch @@ -0,0 +1,25 @@ +commit c57afec0a9b318bb691e0f5fa4e9681cf30df7a4 +Author: Florian Weimer +Date: Fri Apr 26 07:16:56 2019 +0200 + + elf: Link sotruss-lib.so with BIND_NOW for --enable-bind-now + + The audit module itself can be linked with BIND_NOW; it does not + affect its functionality. + + This should complete the leftovers from commit + 2d6ab5df3b675e96ee587ae6a8c2ce004c6b1ba9 ("Document and fix + --enable-bind-now [BZ #21015]"). + +diff --git a/elf/Makefile b/elf/Makefile +index f5285b99e22fe84d..9194339836900b9d 100644 +--- a/elf/Makefile ++++ b/elf/Makefile +@@ -133,6 +133,7 @@ install-others += $(inst_auditdir)/sotruss-lib.so + install-bin-script += sotruss + generated += sotruss + libof-sotruss-lib = extramodules ++LDFLAGS-sotruss-lib.so += $(z-now-$(bind-now)) + $(objpfx)sotruss-lib.so: $(objpfx)sotruss-lib.os + $(build-module-asneeded) + $(objpfx)sotruss-lib.so: $(common-objpfx)libc.so $(objpfx)ld.so \ diff --git a/SOURCES/glibc-rh1641982.patch b/SOURCES/glibc-rh1641982.patch new file mode 100644 index 0000000..937abfd --- /dev/null +++ b/SOURCES/glibc-rh1641982.patch @@ -0,0 +1,41 @@ +commit c3d8dc45c9df199b8334599a6cbd98c9950dba62 +Author: Adhemerval Zanella +Date: Thu Oct 11 15:18:40 2018 -0300 + + x86: Fix Haswell strong flags (BZ#23709) + + Th commit 'Disable TSX on some Haswell processors.' (2702856bf4) changed the + default flags for Haswell models. Previously, new models were handled by the + default switch path, which assumed a Core i3/i5/i7 if AVX is available. After + the patch, Haswell models (0x3f, 0x3c, 0x45, 0x46) do not set the flags + Fast_Rep_String, Fast_Unaligned_Load, Fast_Unaligned_Copy, and + Prefer_PMINUB_for_stringop (only the TSX one). + + This patch fixes it by disentangle the TSX flag handling from the memory + optimization ones. The strstr case cited on patch now selects the + __strstr_sse2_unaligned as expected for the Haswell cpu. + + Checked on x86_64-linux-gnu. + + [BZ #23709] + * sysdeps/x86/cpu-features.c (init_cpu_features): Set TSX bits + independently of other flags. + +diff --git a/sysdeps/x86/cpu-features.c b/sysdeps/x86/cpu-features.c +index ea0b64fdb962a934..4695ac80d4148327 100644 +--- a/sysdeps/x86/cpu-features.c ++++ b/sysdeps/x86/cpu-features.c +@@ -316,7 +316,13 @@ init_cpu_features (struct cpu_features *cpu_features) + | bit_arch_Fast_Unaligned_Copy + | bit_arch_Prefer_PMINUB_for_stringop); + break; ++ } + ++ /* Disable TSX on some Haswell processors to avoid TSX on kernels that ++ weren't updated with the latest microcode package (which disables ++ broken feature by default). */ ++ switch (model) ++ { + case 0x3f: + /* Xeon E7 v3 with stepping >= 4 has working TSX. */ + if (stepping >= 4) diff --git a/SOURCES/glibc-rh1642094-1.patch b/SOURCES/glibc-rh1642094-1.patch new file mode 100644 index 0000000..2fd093c --- /dev/null +++ b/SOURCES/glibc-rh1642094-1.patch @@ -0,0 +1,230 @@ +commit bcdaad21d4635931d1bd3b54a7894276925d081d +Author: DJ Delorie +Date: Tue Nov 20 13:24:09 2018 -0500 + + malloc: tcache double free check + + * malloc/malloc.c (tcache_entry): Add key field. + (tcache_put): Set it. + (tcache_get): Likewise. + (_int_free): Check for double free in tcache. + * malloc/tst-tcfree1.c: New. + * malloc/tst-tcfree2.c: New. + * malloc/Makefile: Run the new tests. + * manual/probes.texi: Document memory_tcache_double_free probe. + + * dlfcn/dlerror.c (check_free): Prevent double frees. + +diff --git a/dlfcn/dlerror.c b/dlfcn/dlerror.c +index 33574faab65628ff..96bf92533335036b 100644 +--- a/dlfcn/dlerror.c ++++ b/dlfcn/dlerror.c +@@ -198,7 +198,10 @@ check_free (struct dl_action_result *rec) + Dl_info info; + if (_dl_addr (check_free, &info, &map, NULL) != 0 && map->l_ns == 0) + #endif +- free ((char *) rec->errstring); ++ { ++ free ((char *) rec->errstring); ++ rec->errstring = NULL; ++ } + } + } + +diff --git a/malloc/Makefile b/malloc/Makefile +index 7d54bad866f63cb8..e6dfbfc14cb3d140 100644 +--- a/malloc/Makefile ++++ b/malloc/Makefile +@@ -38,6 +38,7 @@ tests := mallocbug tst-malloc tst-valloc tst-calloc tst-obstack \ + tst-malloc_info \ + tst-malloc-too-large \ + tst-malloc-stats-cancellation \ ++ tst-tcfree1 tst-tcfree2 \ + + tests-static := \ + tst-interpose-static-nothread \ +diff --git a/malloc/malloc.c b/malloc/malloc.c +index e247c77b7d4de26e..c6b0282e783eaeea 100644 +--- a/malloc/malloc.c ++++ b/malloc/malloc.c +@@ -2888,6 +2888,8 @@ mremap_chunk (mchunkptr p, size_t new_size) + typedef struct tcache_entry + { + struct tcache_entry *next; ++ /* This field exists to detect double frees. */ ++ struct tcache_perthread_struct *key; + } tcache_entry; + + /* There is one of these for each thread, which contains the +@@ -2911,6 +2913,11 @@ tcache_put (mchunkptr chunk, size_t tc_idx) + { + tcache_entry *e = (tcache_entry *) chunk2mem (chunk); + assert (tc_idx < TCACHE_MAX_BINS); ++ ++ /* Mark this chunk as "in the tcache" so the test in _int_free will ++ detect a double free. */ ++ e->key = tcache; ++ + e->next = tcache->entries[tc_idx]; + tcache->entries[tc_idx] = e; + ++(tcache->counts[tc_idx]); +@@ -2926,6 +2933,7 @@ tcache_get (size_t tc_idx) + assert (tcache->entries[tc_idx] > 0); + tcache->entries[tc_idx] = e->next; + --(tcache->counts[tc_idx]); ++ e->key = NULL; + return (void *) e; + } + +@@ -4152,6 +4160,26 @@ _int_free (mstate av, mchunkptr p, int have_lock) + { + size_t tc_idx = csize2tidx (size); + ++ /* Check to see if it's already in the tcache. */ ++ tcache_entry *e = (tcache_entry *) chunk2mem (p); ++ ++ /* This test succeeds on double free. However, we don't 100% ++ 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 && tcache)) ++ { ++ tcache_entry *tmp; ++ LIBC_PROBE (memory_tcache_double_free, 2, e, tc_idx); ++ for (tmp = tcache->entries[tc_idx]; ++ tmp; ++ tmp = tmp->next) ++ 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 + && tc_idx < mp_.tcache_bins + && tcache->counts[tc_idx] < mp_.tcache_count) +diff --git a/malloc/tst-tcfree1.c b/malloc/tst-tcfree1.c +new file mode 100644 +index 0000000000000000..bc29375ce77304ac +--- /dev/null ++++ b/malloc/tst-tcfree1.c +@@ -0,0 +1,42 @@ ++/* Test that malloc tcache catches double free. ++ 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 ++#include ++#include ++#include ++#include ++ ++static int ++do_test (void) ++{ ++ /* Do one allocation of any size that fits in tcache. */ ++ char * volatile x = malloc (32); ++ ++ free (x); // puts in tcache ++ free (x); // should abort ++ ++ printf("FAIL: tcache double free not detected\n"); ++ return 1; ++} ++ ++#define TEST_FUNCTION do_test ++#define EXPECTED_SIGNAL SIGABRT ++#include +diff --git a/malloc/tst-tcfree2.c b/malloc/tst-tcfree2.c +new file mode 100644 +index 0000000000000000..17f06bacd411c315 +--- /dev/null ++++ b/malloc/tst-tcfree2.c +@@ -0,0 +1,48 @@ ++/* Test that malloc tcache catches double free. ++ 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 ++#include ++#include ++#include ++#include ++ ++static int ++do_test (void) ++{ ++ char * volatile ptrs[20]; ++ int i; ++ ++ /* Allocate enough small chunks so that when we free them all, the tcache ++ is full, and the first one we freed is at the end of its linked list. */ ++#define COUNT 20 ++ for (i=0; i +diff --git a/manual/probes.texi b/manual/probes.texi +index ab2a3102bb350ef4..0ea560ed78bcfd7e 100644 +--- a/manual/probes.texi ++++ b/manual/probes.texi +@@ -243,6 +243,18 @@ This probe is triggered when the + value of this tunable. + @end deftp + ++@deftp Probe memory_tcache_double_free (void *@var{$arg1}, int @var{$arg2}) ++This probe is triggered when @code{free} determines that the memory ++being freed has probably already been freed, and resides in the ++per-thread cache. Note that there is an extremely unlikely chance ++that this probe will trigger due to random payload data remaining in ++the allocated memory matching the key used to detect double frees. ++This probe actually indicates that an expensive linear search of the ++tcache, looking for a double free, has happened. Argument @var{$arg1} ++is the memory location as passed to @code{free}, Argument @var{$arg2} ++is the tcache bin it resides in. ++@end deftp ++ + @node Mathematical Function Probes + @section Mathematical Function Probes + diff --git a/SOURCES/glibc-rh1642094-2.patch b/SOURCES/glibc-rh1642094-2.patch new file mode 100644 index 0000000..aa3d2ea --- /dev/null +++ b/SOURCES/glibc-rh1642094-2.patch @@ -0,0 +1,73 @@ +commit affec03b713c82c43a5b025dddc21bde3334f41e +Author: Florian Weimer +Date: Mon Nov 26 20:06:37 2018 +0100 + + malloc: tcache: Validate tc_idx before checking for double-frees [BZ #23907] + + The previous check could read beyond the end of the tcache entry + array. If the e->key == tcache cookie check happened to pass, this + would result in crashes. + +diff --git a/malloc/malloc.c b/malloc/malloc.c +index c6b0282e783eaeea..13c52f376859562d 100644 +--- a/malloc/malloc.c ++++ b/malloc/malloc.c +@@ -4159,33 +4159,33 @@ _int_free (mstate av, mchunkptr p, int have_lock) + #if USE_TCACHE + { + size_t tc_idx = csize2tidx (size); +- +- /* Check to see if it's already in the tcache. */ +- tcache_entry *e = (tcache_entry *) chunk2mem (p); +- +- /* This test succeeds on double free. However, we don't 100% +- 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 && tcache)) ++ if (tcache != NULL && tc_idx < mp_.tcache_bins) + { +- tcache_entry *tmp; +- LIBC_PROBE (memory_tcache_double_free, 2, e, tc_idx); +- for (tmp = tcache->entries[tc_idx]; +- tmp; +- tmp = tmp->next) +- 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. */ +- } ++ /* Check to see if it's already in the tcache. */ ++ tcache_entry *e = (tcache_entry *) chunk2mem (p); ++ ++ /* This test succeeds on double free. However, we don't 100% ++ 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)) ++ { ++ tcache_entry *tmp; ++ LIBC_PROBE (memory_tcache_double_free, 2, e, tc_idx); ++ for (tmp = tcache->entries[tc_idx]; ++ tmp; ++ tmp = tmp->next) ++ 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 +- && tc_idx < mp_.tcache_bins +- && tcache->counts[tc_idx] < mp_.tcache_count) +- { +- tcache_put (p, tc_idx); +- return; ++ if (tcache->counts[tc_idx] < mp_.tcache_count) ++ { ++ tcache_put (p, tc_idx); ++ return; ++ } + } + } + #endif diff --git a/SOURCES/glibc-rh1642094-3.patch b/SOURCES/glibc-rh1642094-3.patch new file mode 100644 index 0000000..50a41ef --- /dev/null +++ b/SOURCES/glibc-rh1642094-3.patch @@ -0,0 +1,89 @@ +commit 7c9a7c68363051cfc5fa1ebb96b3b2c1f82dcb76 +Author: DJ Delorie +Date: Fri Nov 30 22:13:09 2018 -0500 + + malloc: Add another test for tcache double free check. + + This one tests for BZ#23907 where the double free + test didn't check the tcache bin bounds before dereferencing + the bin. + + [BZ #23907] + * malloc/tst-tcfree3.c: New. + * malloc/Makefile: Add it. + +diff --git a/malloc/Makefile b/malloc/Makefile +index e6dfbfc14cb3d140..388cf7e9ee3a2569 100644 +--- a/malloc/Makefile ++++ b/malloc/Makefile +@@ -38,7 +38,7 @@ tests := mallocbug tst-malloc tst-valloc tst-calloc tst-obstack \ + tst-malloc_info \ + tst-malloc-too-large \ + tst-malloc-stats-cancellation \ +- tst-tcfree1 tst-tcfree2 \ ++ tst-tcfree1 tst-tcfree2 tst-tcfree3 \ + + tests-static := \ + tst-interpose-static-nothread \ +diff --git a/malloc/tst-tcfree3.c b/malloc/tst-tcfree3.c +new file mode 100644 +index 0000000000000000..016d30ddd8114082 +--- /dev/null ++++ b/malloc/tst-tcfree3.c +@@ -0,0 +1,56 @@ ++/* Test that malloc tcache catches double free. ++ 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 ++ ++/* Prevent GCC from optimizing away any malloc/free pairs. */ ++#pragma GCC optimize ("O0") ++ ++static int ++do_test (void) ++{ ++ /* Do two allocation of any size that fit in tcache, and one that ++ doesn't. */ ++ int ** volatile a = malloc (32); ++ int ** volatile b = malloc (32); ++ /* This is just under the mmap threshold. */ ++ int ** volatile c = malloc (127 * 1024); ++ ++ /* The invalid "tcache bucket" we might dereference will likely end ++ up somewhere within this memory block, so make all the accidental ++ "next" pointers cause segfaults. BZ #23907. */ ++ memset (c, 0xff, 127 * 1024); ++ ++ free (a); // puts in tcache ++ ++ /* A is now free and contains the key we use to detect in-tcache. ++ Copy the key to the other chunks. */ ++ memcpy (b, a, 32); ++ memcpy (c, a, 32); ++ ++ /* This free tests the "are we in the tcache already" loop with a ++ VALID bin but "coincidental" matching key. */ ++ free (b); // should NOT abort ++ /* This free tests the "is it a valid tcache bin" test. */ ++ free (c); // should NOT abort ++ ++ return 0; ++} ++ ++#include diff --git a/SOURCES/glibc-rh1642150-1.patch b/SOURCES/glibc-rh1642150-1.patch new file mode 100644 index 0000000..381ad0b --- /dev/null +++ b/SOURCES/glibc-rh1642150-1.patch @@ -0,0 +1,176 @@ +commit a803367bab167f5ec4fde1f0d0ec447707c29520 +Author: Florian Weimer +Date: Fri Feb 14 20:55:39 2020 +0100 + + powerpc64: Add memory protection key support [BZ #23202] + + The 32-bit protection key behavior is somewhat unclear on 32-bit powerpc, + so this change is restricted to the 64-bit variants. + + Flag translation is needed because of hardware differences between the + POWER implementation (read and write flags) and the Intel implementation + (write and read+write flags). + +diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/arch-pkey.h b/sysdeps/unix/sysv/linux/powerpc/powerpc64/arch-pkey.h +new file mode 100644 +index 0000000000000000..623b073d5a585d51 +--- /dev/null ++++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/arch-pkey.h +@@ -0,0 +1,55 @@ ++/* Helper functions for manipulating memory protection keys, for powerpc64. ++ Copyright (C) 2017-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 ++ . */ ++ ++#ifndef _ARCH_PKEY_H ++#define _ARCH_PKEY_H ++ ++/* Read and write access bits in the AMR register. Needs to be ++ translated from and to PKEY_DISABLE_* flags. */ ++#define PKEY_AMR_READ 1UL ++#define PKEY_AMR_WRITE 2UL ++ ++/* Return the value of the AMR register. */ ++static inline unsigned long int ++pkey_read (void) ++{ ++ unsigned long int result; ++ __asm__ volatile ("mfspr %0, 13" : "=r" (result)); ++ return result; ++} ++ ++/* Overwrite the AMR register with VALUE. */ ++static inline void ++pkey_write (unsigned long int value) ++{ ++ __asm__ volatile ("mtspr 13, %0" : : "r" (value)); ++} ++ ++/* Number of the largest supported key. This depends on the width of ++ the AMR register. */ ++#define PKEY_MAX (sizeof (unsigned long int) * 8 / 2 - 1) ++_Static_assert (PKEY_MAX == 15 || PKEY_MAX == 31, "PKEY_MAX value"); ++ ++/* Translate key number into AMR index position. */ ++static inline int ++pkey_index (int key) ++{ ++ return 2 * (PKEY_MAX - key); ++} ++ ++#endif /* _ARCH_PKEY_H */ +diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/pkey_get.c b/sysdeps/unix/sysv/linux/powerpc/powerpc64/pkey_get.c +new file mode 100644 +index 0000000000000000..856ba061b90eabd2 +--- /dev/null ++++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/pkey_get.c +@@ -0,0 +1,42 @@ ++/* Reading the per-thread memory protection key, powerpc64 version. ++ Copyright (C) 2017-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 ++ ++int ++pkey_get (int key) ++{ ++ if (key < 0 || key > PKEY_MAX) ++ { ++ __set_errno (EINVAL); ++ return -1; ++ } ++ unsigned int index = pkey_index (key); ++ unsigned long int amr = pkey_read (); ++ unsigned int bits = (amr >> index) & 3; ++ ++ /* Translate from AMR values. PKEY_AMR_READ standing alone is not ++ currently representable. */ ++ if (bits & PKEY_AMR_READ) ++ return PKEY_DISABLE_ACCESS; ++ else if (bits == PKEY_AMR_WRITE) ++ return PKEY_DISABLE_WRITE; ++ return 0; ++} +diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/pkey_set.c b/sysdeps/unix/sysv/linux/powerpc/powerpc64/pkey_set.c +new file mode 100644 +index 0000000000000000..20b372ee2983abd5 +--- /dev/null ++++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/pkey_set.c +@@ -0,0 +1,48 @@ ++/* Changing the per-thread memory protection key, powerpc64 version. ++ Copyright (C) 2017-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 ++ ++int ++pkey_set (int key, unsigned int rights) ++{ ++ if (key < 0 || key > PKEY_MAX || rights > 3) ++ { ++ __set_errno (EINVAL); ++ return -1; ++ } ++ ++ /* Translate to AMR bit values. */ ++ unsigned long int bits; ++ if (rights & PKEY_DISABLE_ACCESS) ++ /* The PKEY_DISABLE_WRITE bit does not matter. */ ++ bits = PKEY_AMR_READ | PKEY_AMR_WRITE; ++ else if (rights == PKEY_DISABLE_WRITE) ++ bits = PKEY_AMR_WRITE; ++ else ++ bits = 0; ++ ++ unsigned int index = pkey_index (key); ++ unsigned long int mask = 3UL << index; ++ unsigned long int amr = pkey_read (); ++ amr = (amr & ~mask) | (bits << index); ++ pkey_write (amr); ++ return 0; ++} diff --git a/SOURCES/glibc-rh1642150-2.patch b/SOURCES/glibc-rh1642150-2.patch new file mode 100644 index 0000000..129ed9d --- /dev/null +++ b/SOURCES/glibc-rh1642150-2.patch @@ -0,0 +1,53 @@ +commit 8d42bf859a289944749d9f978c076cd318119867 +Author: Lucas A. M. Magalhaes +Date: Mon Feb 17 09:09:52 2020 -0300 + + Fix tst-pkey expectations on pkey_get [BZ #23202] + + From the GNU C Library manual, the pkey_set can receive a combination of + PKEY_DISABLE_WRITE and PKEY_DISABLE_ACCESS. However PKEY_DISABLE_ACCESS + is more restrictive than PKEY_DISABLE_WRITE and includes its behavior. + + The test expects that after setting + (PKEY_DISABLE_WRITE|PKEY_DISABLE_ACCESS) pkey_get should return the + same. This may not be true as PKEY_DISABLE_ACCESS will succeed in + describing the state of the key in this case. + + The pkey behavior during signal handling is different between x86 and + POWER. This change make the test compatible with both architectures. + + Reviewed-by: Tulio Magno Quites Machado Filho + +diff --git a/sysdeps/unix/sysv/linux/tst-pkey.c b/sysdeps/unix/sysv/linux/tst-pkey.c +index 5f721d4444490945..600b6f0098def773 100644 +--- a/sysdeps/unix/sysv/linux/tst-pkey.c ++++ b/sysdeps/unix/sysv/linux/tst-pkey.c +@@ -37,7 +37,7 @@ static pthread_barrier_t barrier; + + /* The keys used for testing. These have been allocated with access + rights set based on their array index. */ +-enum { key_count = 4 }; ++enum { key_count = 3 }; + static int keys[key_count]; + static volatile int *pages[key_count]; + +@@ -111,14 +111,16 @@ check_page_access (int page, bool write) + } + + static volatile sig_atomic_t sigusr1_handler_ran; +- +-/* Used to check that access is revoked in signal handlers. */ ++/* Used to check the behavior in signal handlers. In x86 all access are ++ revoked during signal handling. In PowerPC the key permissions are ++ inherited by the interrupted thread. This test accept both approaches. */ + static void + sigusr1_handler (int signum) + { + TEST_COMPARE (signum, SIGUSR1); + for (int i = 0; i < key_count; ++i) +- TEST_COMPARE (pkey_get (keys[i]), PKEY_DISABLE_ACCESS); ++ TEST_VERIFY (pkey_get (keys[i]) == PKEY_DISABLE_ACCESS ++ || pkey_get (keys[i]) == i); + sigusr1_handler_ran = 1; + } + diff --git a/SOURCES/glibc-rh1642150-3.patch b/SOURCES/glibc-rh1642150-3.patch new file mode 100644 index 0000000..84a2191 --- /dev/null +++ b/SOURCES/glibc-rh1642150-3.patch @@ -0,0 +1,46 @@ +commit 70ba28f7ab2923d4e36ffc9d5d2e32357353b25c +Author: Lucas A. M. Magalhaes +Date: Thu Jan 16 10:39:12 2020 -0300 + + Fix tst-pkey.c pkey_alloc return checks and manual + + This test was failing in some powerpc systems as it was not checking + for ENOSPC return. + + As said on the Linux man-pages and can be observed by the implementation + at mm/mprotect.c in the Linux Kernel source. The syscall pkey_alloc can + return EINVAL or ENOSPC. ENOSPC will indicate either that all keys are + in use or that the kernel does not support pkeys. + + Reviewed-by: Gabriel F. T. Gomes + +diff --git a/manual/memory.texi b/manual/memory.texi +index a1435aad1acd3239..4731a38bcc5701e0 100644 +--- a/manual/memory.texi ++++ b/manual/memory.texi +@@ -3289,6 +3289,10 @@ in which memory protection keys are disabled. + + @item ENOSPC + All available protection keys already have been allocated. ++ ++The system does not implement memory protection keys or runs in a mode ++in which memory protection keys are disabled. ++ + @end table + @end deftypefun + +diff --git a/sysdeps/unix/sysv/linux/tst-pkey.c b/sysdeps/unix/sysv/linux/tst-pkey.c +index 600b6f0098def773..40d7e9f24dec3e57 100644 +--- a/sysdeps/unix/sysv/linux/tst-pkey.c ++++ b/sysdeps/unix/sysv/linux/tst-pkey.c +@@ -199,6 +199,10 @@ do_test (void) + if (errno == EINVAL) + FAIL_UNSUPPORTED + ("CPU does not support memory protection keys: %m"); ++ if (errno == ENOSPC) ++ FAIL_UNSUPPORTED ++ ("no keys available or kernel does not support memory" ++ " protection keys"); + FAIL_EXIT1 ("pkey_alloc: %m"); + } + TEST_COMPARE (pkey_get (keys[0]), 0); diff --git a/SOURCES/glibc-rh1642150-4.patch b/SOURCES/glibc-rh1642150-4.patch new file mode 100644 index 0000000..b4d53e5 --- /dev/null +++ b/SOURCES/glibc-rh1642150-4.patch @@ -0,0 +1,36 @@ +commit e627106266ad8785457fadbf5bf67ed604d2a353 +Author: Florian Weimer +Date: Mon May 11 11:20:02 2020 +0200 + + POWER: Add context-synchronizing instructions to pkey_write [BZ #25954] + + Sandipan Das reported that, + + "The Power ISA mandates that all writes to the Authority + Mask Register (AMR) must always be preceded as well as + succeeded by a context-synchronizing instruction. This + applies to both the privileged and unprivileged variants + of the Move To AMR instruction. + + This [requirement] is from Table 6 of Chapter 11 in page 1134 of Power + ISA 3.0B. The document can be found here: + + " + + See this kernel patch submission: + + + +diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/arch-pkey.h b/sysdeps/unix/sysv/linux/powerpc/powerpc64/arch-pkey.h +index 623b073d5a585d51..25d080c9a6f30942 100644 +--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/arch-pkey.h ++++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/arch-pkey.h +@@ -37,7 +37,7 @@ pkey_read (void) + static inline void + pkey_write (unsigned long int value) + { +- __asm__ volatile ("mtspr 13, %0" : : "r" (value)); ++ __asm__ volatile ("isync; mtspr 13, %0; isync" : : "r" (value)); + } + + /* Number of the largest supported key. This depends on the width of diff --git a/SOURCES/glibc-rh1645593.patch b/SOURCES/glibc-rh1645593.patch new file mode 100644 index 0000000..d2b5cc2 --- /dev/null +++ b/SOURCES/glibc-rh1645593.patch @@ -0,0 +1,34 @@ +commit 28669f86f6780a18daca264f32d66b1428c9c6f1 +Author: Stefan Liebler +Date: Thu Sep 6 14:27:03 2018 +0200 + + Fix segfault in maybe_script_execute. + + If glibc is built with gcc 8 and -march=z900, + the testcase posix/tst-spawn4-compat crashes with a segfault. + + In function maybe_script_execute, the new_argv array is dynamically + initialized on stack with (argc + 1) elements. + The function wants to add _PATH_BSHELL as the first argument + and writes out of bounds of new_argv. + There is an off-by-one because maybe_script_execute fails to count + the terminating NULL when sizing new_argv. + + ChangeLog: + + * sysdeps/unix/sysv/linux/spawni.c (maybe_script_execute): + Increment size of new_argv by one. + +diff --git a/sysdeps/unix/sysv/linux/spawni.c b/sysdeps/unix/sysv/linux/spawni.c +index cf0213ece55c675d..85239cedbf2a5ab5 100644 +--- a/sysdeps/unix/sysv/linux/spawni.c ++++ b/sysdeps/unix/sysv/linux/spawni.c +@@ -101,7 +101,7 @@ maybe_script_execute (struct posix_spawn_args *args) + ptrdiff_t argc = args->argc; + + /* Construct an argument list for the shell. */ +- char *new_argv[argc + 1]; ++ char *new_argv[argc + 2]; + new_argv[0] = (char *) _PATH_BSHELL; + new_argv[1] = (char *) args->file; + if (argc > 1) diff --git a/SOURCES/glibc-rh1645596.patch b/SOURCES/glibc-rh1645596.patch new file mode 100644 index 0000000..36e4b9a --- /dev/null +++ b/SOURCES/glibc-rh1645596.patch @@ -0,0 +1,193 @@ +commit 7a16bdbb9ff4122af0a28dc20996c95352011fdd +Author: Adhemerval Zanella +Date: Wed Aug 29 16:36:44 2018 -0300 + + Fix misreported errno on preadv2/pwritev2 (BZ#23579) + + The fallback code of Linux wrapper for preadv2/pwritev2 executes + regardless of the errno code for preadv2, instead of the case where + the syscall is not supported. + + This fixes it by calling the fallback code iff errno is ENOSYS. The + patch also adds tests for both invalid file descriptor and invalid + iov_len and vector count. + + The only discrepancy between preadv2 and fallback code regarding + error reporting is when an invalid flags are used. The fallback code + bails out earlier with ENOTSUP instead of EINVAL/EBADF when the syscall + is used. + + Checked on x86_64-linux-gnu on a 4.4.0 and 4.15.0 kernel. + + [BZ #23579] + * misc/tst-preadvwritev2-common.c (do_test_with_invalid_fd): New + test. + * misc/tst-preadvwritev2.c, misc/tst-preadvwritev64v2.c (do_test): + Call do_test_with_invalid_fd. + * sysdeps/unix/sysv/linux/preadv2.c (preadv2): Use fallback code iff + errno is ENOSYS. + * sysdeps/unix/sysv/linux/preadv64v2.c (preadv64v2): Likewise. + * sysdeps/unix/sysv/linux/pwritev2.c (pwritev2): Likewise. + * sysdeps/unix/sysv/linux/pwritev64v2.c (pwritev64v2): Likewise. + +diff --git a/misc/tst-preadvwritev2-common.c b/misc/tst-preadvwritev2-common.c +index f889a21544947042..50b9da3fea56d288 100644 +--- a/misc/tst-preadvwritev2-common.c ++++ b/misc/tst-preadvwritev2-common.c +@@ -19,9 +19,6 @@ + #include + #include + +-static void +-do_test_with_invalid_flags (void) +-{ + #ifndef RWF_HIPRI + # define RWF_HIPRI 0 + #endif +@@ -39,6 +36,68 @@ do_test_with_invalid_flags (void) + #endif + #define RWF_SUPPORTED (RWF_HIPRI | RWF_DSYNC | RWF_SYNC | RWF_NOWAIT \ + | RWF_APPEND) ++ ++static void ++do_test_with_invalid_fd (void) ++{ ++ char buf[256]; ++ struct iovec iov = { buf, sizeof buf }; ++ ++ /* Check with flag being 0 to use the fallback code which calls pwritev ++ or writev. */ ++ TEST_VERIFY (preadv2 (-1, &iov, 1, -1, 0) == -1); ++ TEST_COMPARE (errno, EBADF); ++ TEST_VERIFY (pwritev2 (-1, &iov, 1, -1, 0) == -1); ++ TEST_COMPARE (errno, EBADF); ++ ++ /* Same tests as before but with flags being different than 0. Since ++ there is no emulation for any flag value, fallback code returns ++ ENOTSUP. This is different running on a kernel with preadv2/pwritev2 ++ support, where EBADF is returned). */ ++ TEST_VERIFY (preadv2 (-1, &iov, 1, 0, RWF_HIPRI) == -1); ++ TEST_VERIFY (errno == EBADF || errno == ENOTSUP); ++ TEST_VERIFY (pwritev2 (-1, &iov, 1, 0, RWF_HIPRI) == -1); ++ TEST_VERIFY (errno == EBADF || errno == ENOTSUP); ++} ++ ++static void ++do_test_with_invalid_iov (void) ++{ ++ { ++ char buf[256]; ++ struct iovec iov; ++ ++ iov.iov_base = buf; ++ iov.iov_len = (size_t)SSIZE_MAX + 1; ++ ++ TEST_VERIFY (preadv2 (temp_fd, &iov, 1, 0, 0) == -1); ++ TEST_COMPARE (errno, EINVAL); ++ TEST_VERIFY (pwritev2 (temp_fd, &iov, 1, 0, 0) == -1); ++ TEST_COMPARE (errno, EINVAL); ++ ++ /* Same as for invalid file descriptor tests, emulation fallback ++ first checks for flag value and return ENOTSUP. */ ++ TEST_VERIFY (preadv2 (temp_fd, &iov, 1, 0, RWF_HIPRI) == -1); ++ TEST_VERIFY (errno == EINVAL || errno == ENOTSUP); ++ TEST_VERIFY (pwritev2 (temp_fd, &iov, 1, 0, RWF_HIPRI) == -1); ++ TEST_VERIFY (errno == EINVAL || errno == ENOTSUP); ++ } ++ ++ { ++ /* An invalid iovec buffer should trigger an invalid memory access ++ or an error (Linux for instance returns EFAULT). */ ++ struct iovec iov[IOV_MAX+1] = { 0 }; ++ ++ TEST_VERIFY (preadv2 (temp_fd, iov, IOV_MAX + 1, 0, RWF_HIPRI) == -1); ++ TEST_VERIFY (errno == EINVAL || errno == ENOTSUP); ++ TEST_VERIFY (pwritev2 (temp_fd, iov, IOV_MAX + 1, 0, RWF_HIPRI) == -1); ++ TEST_VERIFY (errno == EINVAL || errno == ENOTSUP); ++ } ++} ++ ++static void ++do_test_with_invalid_flags (void) ++{ + /* Set the next bit from the mask of all supported flags. */ + int invalid_flag = RWF_SUPPORTED != 0 ? __builtin_clz (RWF_SUPPORTED) : 2; + invalid_flag = 0x1 << ((sizeof (int) * CHAR_BIT) - invalid_flag); +diff --git a/misc/tst-preadvwritev2.c b/misc/tst-preadvwritev2.c +index be22802dbe00317f..cb58cbe41ecc639d 100644 +--- a/misc/tst-preadvwritev2.c ++++ b/misc/tst-preadvwritev2.c +@@ -30,6 +30,8 @@ do_test (void) + { + do_test_with_invalid_flags (); + do_test_without_offset (); ++ do_test_with_invalid_fd (); ++ do_test_with_invalid_iov (); + + return do_test_with_offset (0); + } +diff --git a/misc/tst-preadvwritev64v2.c b/misc/tst-preadvwritev64v2.c +index 8d3cc32b284dbf4c..6a9de54c786acc53 100644 +--- a/misc/tst-preadvwritev64v2.c ++++ b/misc/tst-preadvwritev64v2.c +@@ -32,6 +32,8 @@ do_test (void) + { + do_test_with_invalid_flags (); + do_test_without_offset (); ++ do_test_with_invalid_fd (); ++ do_test_with_invalid_iov (); + + return do_test_with_offset (0); + } +diff --git a/sysdeps/unix/sysv/linux/preadv2.c b/sysdeps/unix/sysv/linux/preadv2.c +index c8bf0764ef2629fc..bb08cbc5fd96962e 100644 +--- a/sysdeps/unix/sysv/linux/preadv2.c ++++ b/sysdeps/unix/sysv/linux/preadv2.c +@@ -32,7 +32,7 @@ preadv2 (int fd, const struct iovec *vector, int count, off_t offset, + # ifdef __NR_preadv2 + ssize_t result = SYSCALL_CANCEL (preadv2, fd, vector, count, + LO_HI_LONG (offset), flags); +- if (result >= 0) ++ if (result >= 0 || errno != ENOSYS) + return result; + # endif + /* Trying to emulate the preadv2 syscall flags is troublesome: +diff --git a/sysdeps/unix/sysv/linux/preadv64v2.c b/sysdeps/unix/sysv/linux/preadv64v2.c +index d7400a0252a8c6a1..b72a047347b1db0e 100644 +--- a/sysdeps/unix/sysv/linux/preadv64v2.c ++++ b/sysdeps/unix/sysv/linux/preadv64v2.c +@@ -30,7 +30,7 @@ preadv64v2 (int fd, const struct iovec *vector, int count, off64_t offset, + #ifdef __NR_preadv64v2 + ssize_t result = SYSCALL_CANCEL (preadv64v2, fd, vector, count, + LO_HI_LONG (offset), flags); +- if (result >= 0) ++ if (result >= 0 || errno != ENOSYS) + return result; + #endif + /* Trying to emulate the preadv2 syscall flags is troublesome: +diff --git a/sysdeps/unix/sysv/linux/pwritev2.c b/sysdeps/unix/sysv/linux/pwritev2.c +index 29c2264c8f3d949a..26333ebd43c5f0af 100644 +--- a/sysdeps/unix/sysv/linux/pwritev2.c ++++ b/sysdeps/unix/sysv/linux/pwritev2.c +@@ -28,7 +28,7 @@ pwritev2 (int fd, const struct iovec *vector, int count, off_t offset, + # ifdef __NR_pwritev2 + ssize_t result = SYSCALL_CANCEL (pwritev2, fd, vector, count, + LO_HI_LONG (offset), flags); +- if (result >= 0) ++ if (result >= 0 || errno != ENOSYS) + return result; + # endif + /* Trying to emulate the pwritev2 syscall flags is troublesome: +diff --git a/sysdeps/unix/sysv/linux/pwritev64v2.c b/sysdeps/unix/sysv/linux/pwritev64v2.c +index 42da321149bce40d..17ea905aa6a8db94 100644 +--- a/sysdeps/unix/sysv/linux/pwritev64v2.c ++++ b/sysdeps/unix/sysv/linux/pwritev64v2.c +@@ -30,7 +30,7 @@ pwritev64v2 (int fd, const struct iovec *vector, int count, off64_t offset, + #ifdef __NR_pwritev64v2 + ssize_t result = SYSCALL_CANCEL (pwritev64v2, fd, vector, count, + LO_HI_LONG (offset), flags); +- if (result >= 0) ++ if (result >= 0 || errno != ENOSYS) + return result; + #endif + /* Trying to emulate the pwritev2 syscall flags is troublesome: diff --git a/SOURCES/glibc-rh1645597.patch b/SOURCES/glibc-rh1645597.patch new file mode 100644 index 0000000..eee0633 --- /dev/null +++ b/SOURCES/glibc-rh1645597.patch @@ -0,0 +1,33 @@ +commit dae3ed958c3d0090838e49ff4f78c201262b1cf0 +Author: Rafal Luzynski +Date: Tue Oct 2 23:34:18 2018 +0200 + + kl_GL: Fix spelling of Sunday, should be "sapaat" (bug 20209). + + Although CLDR says otherwise, it is confirmed by Oqaasileriffik, the + official Greenlandic language regulator, that this change is correct. + + [BZ #20209] + * localedata/locales/kl_GL: (abday): Fix spelling of Sun (Sunday), + should be "sap" rather than "sab". + (day): Fix spelling of Sunday, should be "sapaat" rather than + "sabaat". + +diff --git a/localedata/locales/kl_GL b/localedata/locales/kl_GL +index 5ab14a31aade8644..5723ce7dcf9c5742 100644 +--- a/localedata/locales/kl_GL ++++ b/localedata/locales/kl_GL +@@ -70,11 +70,11 @@ copy "da_DK" + END LC_NUMERIC + + LC_TIME +-abday "sab";"ata";/ ++abday "sap";"ata";/ + "mar";"pin";/ + "sis";"tal";/ + "arf" +-day "sabaat";/ ++day "sapaat";/ + "ataasinngorneq";/ + "marlunngorneq";/ + "pingasunngorneq";/ diff --git a/SOURCES/glibc-rh1645601.patch b/SOURCES/glibc-rh1645601.patch new file mode 100644 index 0000000..6b1804e --- /dev/null +++ b/SOURCES/glibc-rh1645601.patch @@ -0,0 +1,134 @@ +commit 7b1f9406761331cf35fe521fbdb592beecf68a2c +Author: H.J. Lu +Date: Fri Sep 28 13:31:19 2018 -0700 + + i386: Use _dl_runtime_[resolve|profile]_shstk for SHSTK [BZ #23716] + + When elf_machine_runtime_setup is called to set up resolver, it should + use _dl_runtime_resolve_shstk or _dl_runtime_profile_shstk if SHSTK is + enabled by kernel. + + Tested on i686 with and without --enable-cet as well as on CET emulator + with --enable-cet. + + [BZ #23716] + * sysdeps/i386/dl-cet.c: Removed. + * sysdeps/i386/dl-machine.h (_dl_runtime_resolve_shstk): New + prototype. + (_dl_runtime_profile_shstk): Likewise. + (elf_machine_runtime_setup): Use _dl_runtime_profile_shstk or + _dl_runtime_resolve_shstk if SHSTK is enabled by kernel. + + Signed-off-by: H.J. Lu + +diff --git a/sysdeps/i386/dl-cet.c b/sysdeps/i386/dl-cet.c +deleted file mode 100644 +index 5d9a4e8d5179b572..0000000000000000 +--- a/sysdeps/i386/dl-cet.c ++++ /dev/null +@@ -1,67 +0,0 @@ +-/* Linux/i386 CET initializers function. +- Copyright (C) 2018 Free Software Foundation, Inc. +- +- The GNU C Library is free software; you can redistribute it and/or +- modify it under the terms of the GNU Lesser General Public +- License as published by the Free Software Foundation; either +- version 2.1 of the License, or (at your option) any later version. +- +- The GNU C Library is distributed in the hope that it will be useful, +- but WITHOUT ANY WARRANTY; without even the implied warranty of +- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +- Lesser General Public License for 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 LINKAGE static inline +-#define _dl_cet_check cet_check +-#include +-#undef _dl_cet_check +- +-#ifdef SHARED +-void +-_dl_cet_check (struct link_map *main_map, const char *program) +-{ +- cet_check (main_map, program); +- +- if ((GL(dl_x86_feature_1)[0] & GNU_PROPERTY_X86_FEATURE_1_SHSTK)) +- { +- /* Replace _dl_runtime_resolve and _dl_runtime_profile with +- _dl_runtime_resolve_shstk and _dl_runtime_profile_shstk, +- respectively if SHSTK is enabled. */ +- extern void _dl_runtime_resolve (Elf32_Word) attribute_hidden; +- extern void _dl_runtime_resolve_shstk (Elf32_Word) attribute_hidden; +- extern void _dl_runtime_profile (Elf32_Word) attribute_hidden; +- extern void _dl_runtime_profile_shstk (Elf32_Word) attribute_hidden; +- unsigned int i; +- struct link_map *l; +- Elf32_Addr *got; +- +- if (main_map->l_info[DT_JMPREL]) +- { +- got = (Elf32_Addr *) D_PTR (main_map, l_info[DT_PLTGOT]); +- if (got[2] == (Elf32_Addr) &_dl_runtime_resolve) +- got[2] = (Elf32_Addr) &_dl_runtime_resolve_shstk; +- else if (got[2] == (Elf32_Addr) &_dl_runtime_profile) +- got[2] = (Elf32_Addr) &_dl_runtime_profile_shstk; +- } +- +- i = main_map->l_searchlist.r_nlist; +- while (i-- > 0) +- { +- l = main_map->l_initfini[i]; +- if (l->l_info[DT_JMPREL]) +- { +- got = (Elf32_Addr *) D_PTR (l, l_info[DT_PLTGOT]); +- if (got[2] == (Elf32_Addr) &_dl_runtime_resolve) +- got[2] = (Elf32_Addr) &_dl_runtime_resolve_shstk; +- else if (got[2] == (Elf32_Addr) &_dl_runtime_profile) +- got[2] = (Elf32_Addr) &_dl_runtime_profile_shstk; +- } +- } +- } +-} +-#endif +diff --git a/sysdeps/i386/dl-machine.h b/sysdeps/i386/dl-machine.h +index 1afdcbd9ea2626e4..f6cfb90e21015250 100644 +--- a/sysdeps/i386/dl-machine.h ++++ b/sysdeps/i386/dl-machine.h +@@ -67,6 +67,11 @@ elf_machine_runtime_setup (struct link_map *l, int lazy, int profile) + Elf32_Addr *got; + extern void _dl_runtime_resolve (Elf32_Word) attribute_hidden; + extern void _dl_runtime_profile (Elf32_Word) attribute_hidden; ++ extern void _dl_runtime_resolve_shstk (Elf32_Word) attribute_hidden; ++ extern void _dl_runtime_profile_shstk (Elf32_Word) attribute_hidden; ++ /* Check if SHSTK is enabled by kernel. */ ++ bool shstk_enabled ++ = (GL(dl_x86_feature_1)[0] & GNU_PROPERTY_X86_FEATURE_1_SHSTK) != 0; + + if (l->l_info[DT_JMPREL] && lazy) + { +@@ -93,7 +98,9 @@ elf_machine_runtime_setup (struct link_map *l, int lazy, int profile) + end in this function. */ + if (__glibc_unlikely (profile)) + { +- got[2] = (Elf32_Addr) &_dl_runtime_profile; ++ got[2] = (shstk_enabled ++ ? (Elf32_Addr) &_dl_runtime_profile_shstk ++ : (Elf32_Addr) &_dl_runtime_profile); + + if (GLRO(dl_profile) != NULL + && _dl_name_match_p (GLRO(dl_profile), l)) +@@ -104,7 +111,9 @@ elf_machine_runtime_setup (struct link_map *l, int lazy, int profile) + else + /* This function will get called to fix up the GOT entry indicated by + the offset on the stack, and then jump to the resolved address. */ +- got[2] = (Elf32_Addr) &_dl_runtime_resolve; ++ got[2] = (shstk_enabled ++ ? (Elf32_Addr) &_dl_runtime_resolve_shstk ++ : (Elf32_Addr) &_dl_runtime_resolve); + } + + return lazy; diff --git a/SOURCES/glibc-rh1645604.patch b/SOURCES/glibc-rh1645604.patch new file mode 100644 index 0000000..f5c287b --- /dev/null +++ b/SOURCES/glibc-rh1645604.patch @@ -0,0 +1,738 @@ +commit 403b4feb22dcbc85ace72a361d2a951380372471 +Author: Stefan Liebler +Date: Wed Oct 17 12:23:04 2018 +0200 + + Fix race in pthread_mutex_lock while promoting to PTHREAD_MUTEX_ELISION_NP [BZ #23275] + + The race leads either to pthread_mutex_destroy returning EBUSY + or triggering an assertion (See description in bugzilla). + + This patch is fixing the race by ensuring that the elision path is + used in all cases if elision is enabled by the GLIBC_TUNABLES framework. + + The __kind variable in struct __pthread_mutex_s is accessed concurrently. + Therefore we are now using the atomic macros. + + The new testcase tst-mutex10 is triggering the race on s390x and intel. + Presumably also on power, but I don't have access to a power machine + with lock-elision. At least the code for power is the same as on the other + two architectures. + + ChangeLog: + + [BZ #23275] + * nptl/tst-mutex10.c: New File. + * nptl/Makefile (tests): Add tst-mutex10. + (tst-mutex10-ENV): New variable. + * sysdeps/unix/sysv/linux/s390/force-elision.h: (FORCE_ELISION): + Ensure that elision path is used if elision is available. + * sysdeps/unix/sysv/linux/powerpc/force-elision.h (FORCE_ELISION): + Likewise. + * sysdeps/unix/sysv/linux/x86/force-elision.h: (FORCE_ELISION): + Likewise. + * nptl/pthreadP.h (PTHREAD_MUTEX_TYPE, PTHREAD_MUTEX_TYPE_ELISION) + (PTHREAD_MUTEX_PSHARED): Use atomic_load_relaxed. + * nptl/pthread_mutex_consistent.c (pthread_mutex_consistent): Likewise. + * nptl/pthread_mutex_getprioceiling.c (pthread_mutex_getprioceiling): + Likewise. + * nptl/pthread_mutex_lock.c (__pthread_mutex_lock_full) + (__pthread_mutex_cond_lock_adjust): Likewise. + * nptl/pthread_mutex_setprioceiling.c (pthread_mutex_setprioceiling): + Likewise. + * nptl/pthread_mutex_timedlock.c (__pthread_mutex_timedlock): Likewise. + * nptl/pthread_mutex_trylock.c (__pthread_mutex_trylock): Likewise. + * nptl/pthread_mutex_unlock.c (__pthread_mutex_unlock_full): Likewise. + * sysdeps/nptl/bits/thread-shared-types.h (struct __pthread_mutex_s): + Add comments. + * nptl/pthread_mutex_destroy.c (__pthread_mutex_destroy): + Use atomic_load_relaxed and atomic_store_relaxed. + * nptl/pthread_mutex_init.c (__pthread_mutex_init): + Use atomic_store_relaxed. + +diff --git a/nptl/Makefile b/nptl/Makefile +index be8066524cdc57db..49b6faa330c492e0 100644 +--- a/nptl/Makefile ++++ b/nptl/Makefile +@@ -241,9 +241,9 @@ LDLIBS-tst-minstack-throw = -lstdc++ + + tests = tst-attr1 tst-attr2 tst-attr3 tst-default-attr \ + tst-mutex1 tst-mutex2 tst-mutex3 tst-mutex4 tst-mutex5 tst-mutex6 \ +- tst-mutex7 tst-mutex9 tst-mutex5a tst-mutex7a tst-mutex7robust \ +- tst-mutexpi1 tst-mutexpi2 tst-mutexpi3 tst-mutexpi4 tst-mutexpi5 \ +- tst-mutexpi5a tst-mutexpi6 tst-mutexpi7 tst-mutexpi7a \ ++ tst-mutex7 tst-mutex9 tst-mutex10 tst-mutex5a tst-mutex7a \ ++ tst-mutex7robust tst-mutexpi1 tst-mutexpi2 tst-mutexpi3 tst-mutexpi4 \ ++ tst-mutexpi5 tst-mutexpi5a tst-mutexpi6 tst-mutexpi7 tst-mutexpi7a \ + tst-mutexpi9 \ + tst-spin1 tst-spin2 tst-spin3 tst-spin4 \ + tst-cond1 tst-cond2 tst-cond3 tst-cond4 tst-cond5 tst-cond6 tst-cond7 \ +@@ -709,6 +709,8 @@ endif + + $(objpfx)tst-compat-forwarder: $(objpfx)tst-compat-forwarder-mod.so + ++tst-mutex10-ENV = GLIBC_TUNABLES=glibc.elision.enable=1 ++ + # The tests here better do not run in parallel + ifneq ($(filter %tests,$(MAKECMDGOALS)),) + .NOTPARALLEL: +diff --git a/nptl/pthreadP.h b/nptl/pthreadP.h +index 13bdb11133536195..19efe1e35feed5be 100644 +--- a/nptl/pthreadP.h ++++ b/nptl/pthreadP.h +@@ -110,19 +110,23 @@ enum + }; + #define PTHREAD_MUTEX_PSHARED_BIT 128 + ++/* See concurrency notes regarding __kind in struct __pthread_mutex_s ++ in sysdeps/nptl/bits/thread-shared-types.h. */ + #define PTHREAD_MUTEX_TYPE(m) \ +- ((m)->__data.__kind & 127) ++ (atomic_load_relaxed (&((m)->__data.__kind)) & 127) + /* Don't include NO_ELISION, as that type is always the same + as the underlying lock type. */ + #define PTHREAD_MUTEX_TYPE_ELISION(m) \ +- ((m)->__data.__kind & (127|PTHREAD_MUTEX_ELISION_NP)) ++ (atomic_load_relaxed (&((m)->__data.__kind)) \ ++ & (127 | PTHREAD_MUTEX_ELISION_NP)) + + #if LLL_PRIVATE == 0 && LLL_SHARED == 128 + # define PTHREAD_MUTEX_PSHARED(m) \ +- ((m)->__data.__kind & 128) ++ (atomic_load_relaxed (&((m)->__data.__kind)) & 128) + #else + # define PTHREAD_MUTEX_PSHARED(m) \ +- (((m)->__data.__kind & 128) ? LLL_SHARED : LLL_PRIVATE) ++ ((atomic_load_relaxed (&((m)->__data.__kind)) & 128) \ ++ ? LLL_SHARED : LLL_PRIVATE) + #endif + + /* The kernel when waking robust mutexes on exit never uses +diff --git a/nptl/pthread_mutex_consistent.c b/nptl/pthread_mutex_consistent.c +index 85b8e1a6cb027e9b..4fbd875430439e4d 100644 +--- a/nptl/pthread_mutex_consistent.c ++++ b/nptl/pthread_mutex_consistent.c +@@ -23,8 +23,11 @@ + int + pthread_mutex_consistent (pthread_mutex_t *mutex) + { +- /* Test whether this is a robust mutex with a dead owner. */ +- if ((mutex->__data.__kind & PTHREAD_MUTEX_ROBUST_NORMAL_NP) == 0 ++ /* Test whether this is a robust mutex with a dead owner. ++ See concurrency notes regarding __kind in struct __pthread_mutex_s ++ in sysdeps/nptl/bits/thread-shared-types.h. */ ++ if ((atomic_load_relaxed (&(mutex->__data.__kind)) ++ & PTHREAD_MUTEX_ROBUST_NORMAL_NP) == 0 + || mutex->__data.__owner != PTHREAD_MUTEX_INCONSISTENT) + return EINVAL; + +diff --git a/nptl/pthread_mutex_destroy.c b/nptl/pthread_mutex_destroy.c +index 5a22611541995778..713ea684962fefc1 100644 +--- a/nptl/pthread_mutex_destroy.c ++++ b/nptl/pthread_mutex_destroy.c +@@ -27,12 +27,17 @@ __pthread_mutex_destroy (pthread_mutex_t *mutex) + { + LIBC_PROBE (mutex_destroy, 1, mutex); + +- if ((mutex->__data.__kind & PTHREAD_MUTEX_ROBUST_NORMAL_NP) == 0 ++ /* See concurrency notes regarding __kind in struct __pthread_mutex_s ++ in sysdeps/nptl/bits/thread-shared-types.h. */ ++ if ((atomic_load_relaxed (&(mutex->__data.__kind)) ++ & PTHREAD_MUTEX_ROBUST_NORMAL_NP) == 0 + && mutex->__data.__nusers != 0) + return EBUSY; + +- /* Set to an invalid value. */ +- mutex->__data.__kind = -1; ++ /* Set to an invalid value. Relaxed MO is enough as it is undefined behavior ++ if the mutex is used after it has been destroyed. But you can reinitialize ++ it with pthread_mutex_init. */ ++ atomic_store_relaxed (&(mutex->__data.__kind), -1); + + return 0; + } +diff --git a/nptl/pthread_mutex_getprioceiling.c b/nptl/pthread_mutex_getprioceiling.c +index efa37b0d99201f57..ee85949578475f3a 100644 +--- a/nptl/pthread_mutex_getprioceiling.c ++++ b/nptl/pthread_mutex_getprioceiling.c +@@ -24,7 +24,9 @@ + int + pthread_mutex_getprioceiling (const pthread_mutex_t *mutex, int *prioceiling) + { +- if (__builtin_expect ((mutex->__data.__kind ++ /* See concurrency notes regarding __kind in struct __pthread_mutex_s ++ in sysdeps/nptl/bits/thread-shared-types.h. */ ++ if (__builtin_expect ((atomic_load_relaxed (&(mutex->__data.__kind)) + & PTHREAD_MUTEX_PRIO_PROTECT_NP) == 0, 0)) + return EINVAL; + +diff --git a/nptl/pthread_mutex_init.c b/nptl/pthread_mutex_init.c +index d8fe4737289c0bd7..5cf290c272e27915 100644 +--- a/nptl/pthread_mutex_init.c ++++ b/nptl/pthread_mutex_init.c +@@ -101,7 +101,7 @@ __pthread_mutex_init (pthread_mutex_t *mutex, + memset (mutex, '\0', __SIZEOF_PTHREAD_MUTEX_T); + + /* Copy the values from the attribute. */ +- mutex->__data.__kind = imutexattr->mutexkind & ~PTHREAD_MUTEXATTR_FLAG_BITS; ++ int mutex_kind = imutexattr->mutexkind & ~PTHREAD_MUTEXATTR_FLAG_BITS; + + if ((imutexattr->mutexkind & PTHREAD_MUTEXATTR_FLAG_ROBUST) != 0) + { +@@ -111,17 +111,17 @@ __pthread_mutex_init (pthread_mutex_t *mutex, + return ENOTSUP; + #endif + +- mutex->__data.__kind |= PTHREAD_MUTEX_ROBUST_NORMAL_NP; ++ mutex_kind |= PTHREAD_MUTEX_ROBUST_NORMAL_NP; + } + + switch (imutexattr->mutexkind & PTHREAD_MUTEXATTR_PROTOCOL_MASK) + { + case PTHREAD_PRIO_INHERIT << PTHREAD_MUTEXATTR_PROTOCOL_SHIFT: +- mutex->__data.__kind |= PTHREAD_MUTEX_PRIO_INHERIT_NP; ++ mutex_kind |= PTHREAD_MUTEX_PRIO_INHERIT_NP; + break; + + case PTHREAD_PRIO_PROTECT << PTHREAD_MUTEXATTR_PROTOCOL_SHIFT: +- mutex->__data.__kind |= PTHREAD_MUTEX_PRIO_PROTECT_NP; ++ mutex_kind |= PTHREAD_MUTEX_PRIO_PROTECT_NP; + + int ceiling = (imutexattr->mutexkind + & PTHREAD_MUTEXATTR_PRIO_CEILING_MASK) +@@ -145,7 +145,11 @@ __pthread_mutex_init (pthread_mutex_t *mutex, + FUTEX_PRIVATE_FLAG FUTEX_WAKE. */ + if ((imutexattr->mutexkind & (PTHREAD_MUTEXATTR_FLAG_PSHARED + | PTHREAD_MUTEXATTR_FLAG_ROBUST)) != 0) +- mutex->__data.__kind |= PTHREAD_MUTEX_PSHARED_BIT; ++ mutex_kind |= PTHREAD_MUTEX_PSHARED_BIT; ++ ++ /* See concurrency notes regarding __kind in struct __pthread_mutex_s ++ in sysdeps/nptl/bits/thread-shared-types.h. */ ++ atomic_store_relaxed (&(mutex->__data.__kind), mutex_kind); + + /* Default values: mutex not used yet. */ + // mutex->__count = 0; already done by memset +diff --git a/nptl/pthread_mutex_lock.c b/nptl/pthread_mutex_lock.c +index 1519c142bd6ec5cc..29cc143e6cbf2421 100644 +--- a/nptl/pthread_mutex_lock.c ++++ b/nptl/pthread_mutex_lock.c +@@ -62,6 +62,8 @@ static int __pthread_mutex_lock_full (pthread_mutex_t *mutex) + int + __pthread_mutex_lock (pthread_mutex_t *mutex) + { ++ /* See concurrency notes regarding mutex type which is loaded from __kind ++ in struct __pthread_mutex_s in sysdeps/nptl/bits/thread-shared-types.h. */ + unsigned int type = PTHREAD_MUTEX_TYPE_ELISION (mutex); + + LIBC_PROBE (mutex_entry, 1, mutex); +@@ -350,8 +352,14 @@ __pthread_mutex_lock_full (pthread_mutex_t *mutex) + case PTHREAD_MUTEX_PI_ROBUST_NORMAL_NP: + case PTHREAD_MUTEX_PI_ROBUST_ADAPTIVE_NP: + { +- int kind = mutex->__data.__kind & PTHREAD_MUTEX_KIND_MASK_NP; +- int robust = mutex->__data.__kind & PTHREAD_MUTEX_ROBUST_NORMAL_NP; ++ int kind, robust; ++ { ++ /* See concurrency notes regarding __kind in struct __pthread_mutex_s ++ in sysdeps/nptl/bits/thread-shared-types.h. */ ++ int mutex_kind = atomic_load_relaxed (&(mutex->__data.__kind)); ++ kind = mutex_kind & PTHREAD_MUTEX_KIND_MASK_NP; ++ robust = mutex_kind & PTHREAD_MUTEX_ROBUST_NORMAL_NP; ++ } + + if (robust) + { +@@ -502,7 +510,10 @@ __pthread_mutex_lock_full (pthread_mutex_t *mutex) + case PTHREAD_MUTEX_PP_NORMAL_NP: + case PTHREAD_MUTEX_PP_ADAPTIVE_NP: + { +- int kind = mutex->__data.__kind & PTHREAD_MUTEX_KIND_MASK_NP; ++ /* See concurrency notes regarding __kind in struct __pthread_mutex_s ++ in sysdeps/nptl/bits/thread-shared-types.h. */ ++ int kind = atomic_load_relaxed (&(mutex->__data.__kind)) ++ & PTHREAD_MUTEX_KIND_MASK_NP; + + oldval = mutex->__data.__lock; + +@@ -607,15 +618,18 @@ hidden_def (__pthread_mutex_lock) + void + __pthread_mutex_cond_lock_adjust (pthread_mutex_t *mutex) + { +- assert ((mutex->__data.__kind & PTHREAD_MUTEX_PRIO_INHERIT_NP) != 0); +- assert ((mutex->__data.__kind & PTHREAD_MUTEX_ROBUST_NORMAL_NP) == 0); +- assert ((mutex->__data.__kind & PTHREAD_MUTEX_PSHARED_BIT) == 0); ++ /* See concurrency notes regarding __kind in struct __pthread_mutex_s ++ in sysdeps/nptl/bits/thread-shared-types.h. */ ++ int mutex_kind = atomic_load_relaxed (&(mutex->__data.__kind)); ++ assert ((mutex_kind & PTHREAD_MUTEX_PRIO_INHERIT_NP) != 0); ++ assert ((mutex_kind & PTHREAD_MUTEX_ROBUST_NORMAL_NP) == 0); ++ assert ((mutex_kind & PTHREAD_MUTEX_PSHARED_BIT) == 0); + + /* Record the ownership. */ + pid_t id = THREAD_GETMEM (THREAD_SELF, tid); + mutex->__data.__owner = id; + +- if (mutex->__data.__kind == PTHREAD_MUTEX_PI_RECURSIVE_NP) ++ if (mutex_kind == PTHREAD_MUTEX_PI_RECURSIVE_NP) + ++mutex->__data.__count; + } + #endif +diff --git a/nptl/pthread_mutex_setprioceiling.c b/nptl/pthread_mutex_setprioceiling.c +index 8594874f8588b7a8..8306cabcf4e56174 100644 +--- a/nptl/pthread_mutex_setprioceiling.c ++++ b/nptl/pthread_mutex_setprioceiling.c +@@ -27,9 +27,10 @@ int + pthread_mutex_setprioceiling (pthread_mutex_t *mutex, int prioceiling, + int *old_ceiling) + { +- /* The low bits of __kind aren't ever changed after pthread_mutex_init, +- so we don't need a lock yet. */ +- if ((mutex->__data.__kind & PTHREAD_MUTEX_PRIO_PROTECT_NP) == 0) ++ /* See concurrency notes regarding __kind in struct __pthread_mutex_s ++ in sysdeps/nptl/bits/thread-shared-types.h. */ ++ if ((atomic_load_relaxed (&(mutex->__data.__kind)) ++ & PTHREAD_MUTEX_PRIO_PROTECT_NP) == 0) + return EINVAL; + + /* See __init_sched_fifo_prio. */ +diff --git a/nptl/pthread_mutex_timedlock.c b/nptl/pthread_mutex_timedlock.c +index 28237b0e58cfcaf5..888c12fe28b2ebfd 100644 +--- a/nptl/pthread_mutex_timedlock.c ++++ b/nptl/pthread_mutex_timedlock.c +@@ -53,6 +53,8 @@ __pthread_mutex_timedlock (pthread_mutex_t *mutex, + /* We must not check ABSTIME here. If the thread does not block + abstime must not be checked for a valid value. */ + ++ /* See concurrency notes regarding mutex type which is loaded from __kind ++ in struct __pthread_mutex_s in sysdeps/nptl/bits/thread-shared-types.h. */ + switch (__builtin_expect (PTHREAD_MUTEX_TYPE_ELISION (mutex), + PTHREAD_MUTEX_TIMED_NP)) + { +@@ -338,8 +340,14 @@ __pthread_mutex_timedlock (pthread_mutex_t *mutex, + case PTHREAD_MUTEX_PI_ROBUST_NORMAL_NP: + case PTHREAD_MUTEX_PI_ROBUST_ADAPTIVE_NP: + { +- int kind = mutex->__data.__kind & PTHREAD_MUTEX_KIND_MASK_NP; +- int robust = mutex->__data.__kind & PTHREAD_MUTEX_ROBUST_NORMAL_NP; ++ int kind, robust; ++ { ++ /* See concurrency notes regarding __kind in struct __pthread_mutex_s ++ in sysdeps/nptl/bits/thread-shared-types.h. */ ++ int mutex_kind = atomic_load_relaxed (&(mutex->__data.__kind)); ++ kind = mutex_kind & PTHREAD_MUTEX_KIND_MASK_NP; ++ robust = mutex_kind & PTHREAD_MUTEX_ROBUST_NORMAL_NP; ++ } + + if (robust) + { +@@ -509,7 +517,10 @@ __pthread_mutex_timedlock (pthread_mutex_t *mutex, + case PTHREAD_MUTEX_PP_NORMAL_NP: + case PTHREAD_MUTEX_PP_ADAPTIVE_NP: + { +- int kind = mutex->__data.__kind & PTHREAD_MUTEX_KIND_MASK_NP; ++ /* See concurrency notes regarding __kind in struct __pthread_mutex_s ++ in sysdeps/nptl/bits/thread-shared-types.h. */ ++ int kind = atomic_load_relaxed (&(mutex->__data.__kind)) ++ & PTHREAD_MUTEX_KIND_MASK_NP; + + oldval = mutex->__data.__lock; + +diff --git a/nptl/pthread_mutex_trylock.c b/nptl/pthread_mutex_trylock.c +index 7de61f4f688c1537..fa90c1d1e6f5afc2 100644 +--- a/nptl/pthread_mutex_trylock.c ++++ b/nptl/pthread_mutex_trylock.c +@@ -36,6 +36,8 @@ __pthread_mutex_trylock (pthread_mutex_t *mutex) + int oldval; + pid_t id = THREAD_GETMEM (THREAD_SELF, tid); + ++ /* See concurrency notes regarding mutex type which is loaded from __kind ++ in struct __pthread_mutex_s in sysdeps/nptl/bits/thread-shared-types.h. */ + switch (__builtin_expect (PTHREAD_MUTEX_TYPE_ELISION (mutex), + PTHREAD_MUTEX_TIMED_NP)) + { +@@ -199,8 +201,14 @@ __pthread_mutex_trylock (pthread_mutex_t *mutex) + case PTHREAD_MUTEX_PI_ROBUST_NORMAL_NP: + case PTHREAD_MUTEX_PI_ROBUST_ADAPTIVE_NP: + { +- int kind = mutex->__data.__kind & PTHREAD_MUTEX_KIND_MASK_NP; +- int robust = mutex->__data.__kind & PTHREAD_MUTEX_ROBUST_NORMAL_NP; ++ int kind, robust; ++ { ++ /* See concurrency notes regarding __kind in struct __pthread_mutex_s ++ in sysdeps/nptl/bits/thread-shared-types.h. */ ++ int mutex_kind = atomic_load_relaxed (&(mutex->__data.__kind)); ++ kind = mutex_kind & PTHREAD_MUTEX_KIND_MASK_NP; ++ robust = mutex_kind & PTHREAD_MUTEX_ROBUST_NORMAL_NP; ++ } + + if (robust) + /* Note: robust PI futexes are signaled by setting bit 0. */ +@@ -325,7 +333,10 @@ __pthread_mutex_trylock (pthread_mutex_t *mutex) + case PTHREAD_MUTEX_PP_NORMAL_NP: + case PTHREAD_MUTEX_PP_ADAPTIVE_NP: + { +- int kind = mutex->__data.__kind & PTHREAD_MUTEX_KIND_MASK_NP; ++ /* See concurrency notes regarding __kind in struct __pthread_mutex_s ++ in sysdeps/nptl/bits/thread-shared-types.h. */ ++ int kind = atomic_load_relaxed (&(mutex->__data.__kind)) ++ & PTHREAD_MUTEX_KIND_MASK_NP; + + oldval = mutex->__data.__lock; + +diff --git a/nptl/pthread_mutex_unlock.c b/nptl/pthread_mutex_unlock.c +index 9ea62943b7c6b159..68d04d53955584e5 100644 +--- a/nptl/pthread_mutex_unlock.c ++++ b/nptl/pthread_mutex_unlock.c +@@ -35,6 +35,8 @@ int + attribute_hidden + __pthread_mutex_unlock_usercnt (pthread_mutex_t *mutex, int decr) + { ++ /* See concurrency notes regarding mutex type which is loaded from __kind ++ in struct __pthread_mutex_s in sysdeps/nptl/bits/thread-shared-types.h. */ + int type = PTHREAD_MUTEX_TYPE_ELISION (mutex); + if (__builtin_expect (type & + ~(PTHREAD_MUTEX_KIND_MASK_NP|PTHREAD_MUTEX_ELISION_FLAGS_NP), 0)) +@@ -222,13 +224,19 @@ __pthread_mutex_unlock_full (pthread_mutex_t *mutex, int decr) + /* If the previous owner died and the caller did not succeed in + making the state consistent, mark the mutex as unrecoverable + and make all waiters. */ +- if ((mutex->__data.__kind & PTHREAD_MUTEX_ROBUST_NORMAL_NP) != 0 ++ /* See concurrency notes regarding __kind in struct __pthread_mutex_s ++ in sysdeps/nptl/bits/thread-shared-types.h. */ ++ if ((atomic_load_relaxed (&(mutex->__data.__kind)) ++ & PTHREAD_MUTEX_ROBUST_NORMAL_NP) != 0 + && __builtin_expect (mutex->__data.__owner + == PTHREAD_MUTEX_INCONSISTENT, 0)) + pi_notrecoverable: + newowner = PTHREAD_MUTEX_NOTRECOVERABLE; + +- if ((mutex->__data.__kind & PTHREAD_MUTEX_ROBUST_NORMAL_NP) != 0) ++ /* See concurrency notes regarding __kind in struct __pthread_mutex_s ++ in sysdeps/nptl/bits/thread-shared-types.h. */ ++ if ((atomic_load_relaxed (&(mutex->__data.__kind)) ++ & PTHREAD_MUTEX_ROBUST_NORMAL_NP) != 0) + { + continue_pi_robust: + /* Remove mutex from the list. +@@ -251,7 +259,10 @@ __pthread_mutex_unlock_full (pthread_mutex_t *mutex, int decr) + /* Unlock. Load all necessary mutex data before releasing the mutex + to not violate the mutex destruction requirements (see + lll_unlock). */ +- int robust = mutex->__data.__kind & PTHREAD_MUTEX_ROBUST_NORMAL_NP; ++ /* See concurrency notes regarding __kind in struct __pthread_mutex_s ++ in sysdeps/nptl/bits/thread-shared-types.h. */ ++ int robust = atomic_load_relaxed (&(mutex->__data.__kind)) ++ & PTHREAD_MUTEX_ROBUST_NORMAL_NP; + private = (robust + ? PTHREAD_ROBUST_MUTEX_PSHARED (mutex) + : PTHREAD_MUTEX_PSHARED (mutex)); +diff --git a/nptl/tst-mutex10.c b/nptl/tst-mutex10.c +new file mode 100644 +index 0000000000000000..e1113ca60a7c8db5 +--- /dev/null ++++ b/nptl/tst-mutex10.c +@@ -0,0 +1,109 @@ ++/* Testing race while enabling lock elision. ++ 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 ++#include ++#include ++#include ++#include ++#include ++ ++static pthread_barrier_t barrier; ++static pthread_mutex_t mutex; ++static long long int iteration_count = 1000000; ++static unsigned int thread_count = 3; ++ ++static void * ++thr_func (void *arg) ++{ ++ long long int i; ++ for (i = 0; i < iteration_count; i++) ++ { ++ if ((uintptr_t) arg == 0) ++ { ++ xpthread_mutex_destroy (&mutex); ++ xpthread_mutex_init (&mutex, NULL); ++ } ++ ++ xpthread_barrier_wait (&barrier); ++ ++ /* Test if enabling lock elision works if it is enabled concurrently. ++ There was a race in FORCE_ELISION macro which leads to either ++ pthread_mutex_destroy returning EBUSY as the owner was recorded ++ by pthread_mutex_lock - in "normal mutex" code path - but was not ++ resetted in pthread_mutex_unlock - in "elision" code path. ++ Or it leads to the assertion in nptl/pthread_mutex_lock.c: ++ assert (mutex->__data.__owner == 0); ++ Please ensure that the test is run with lock elision: ++ export GLIBC_TUNABLES=glibc.elision.enable=1 */ ++ xpthread_mutex_lock (&mutex); ++ xpthread_mutex_unlock (&mutex); ++ ++ xpthread_barrier_wait (&barrier); ++ } ++ return NULL; ++} ++ ++static int ++do_test (void) ++{ ++ unsigned int i; ++ printf ("Starting %d threads to run %lld iterations.\n", ++ thread_count, iteration_count); ++ ++ pthread_t *threads = xmalloc (thread_count * sizeof (pthread_t)); ++ xpthread_barrier_init (&barrier, NULL, thread_count); ++ xpthread_mutex_init (&mutex, NULL); ++ ++ for (i = 0; i < thread_count; i++) ++ threads[i] = xpthread_create (NULL, thr_func, (void *) (uintptr_t) i); ++ ++ for (i = 0; i < thread_count; i++) ++ xpthread_join (threads[i]); ++ ++ xpthread_barrier_destroy (&barrier); ++ free (threads); ++ ++ return EXIT_SUCCESS; ++} ++ ++#define OPT_ITERATIONS 10000 ++#define OPT_THREADS 10001 ++#define CMDLINE_OPTIONS \ ++ { "iterations", required_argument, NULL, OPT_ITERATIONS }, \ ++ { "threads", required_argument, NULL, OPT_THREADS }, ++static void ++cmdline_process (int c) ++{ ++ long long int arg = strtoll (optarg, NULL, 0); ++ switch (c) ++ { ++ case OPT_ITERATIONS: ++ if (arg > 0) ++ iteration_count = arg; ++ break; ++ case OPT_THREADS: ++ if (arg > 0 && arg < 100) ++ thread_count = arg; ++ break; ++ } ++} ++#define CMDLINE_PROCESS cmdline_process ++#define TIMEOUT 50 ++#include +diff --git a/sysdeps/nptl/bits/thread-shared-types.h b/sysdeps/nptl/bits/thread-shared-types.h +index 1e2092a05d5610f7..05c94e7a710c0eb9 100644 +--- a/sysdeps/nptl/bits/thread-shared-types.h ++++ b/sysdeps/nptl/bits/thread-shared-types.h +@@ -124,7 +124,27 @@ struct __pthread_mutex_s + unsigned int __nusers; + #endif + /* KIND must stay at this position in the structure to maintain +- binary compatibility with static initializers. */ ++ binary compatibility with static initializers. ++ ++ Concurrency notes: ++ The __kind of a mutex is initialized either by the static ++ PTHREAD_MUTEX_INITIALIZER or by a call to pthread_mutex_init. ++ ++ After a mutex has been initialized, the __kind of a mutex is usually not ++ changed. BUT it can be set to -1 in pthread_mutex_destroy or elision can ++ be enabled. This is done concurrently in the pthread_mutex_*lock functions ++ by using the macro FORCE_ELISION. This macro is only defined for ++ architectures which supports lock elision. ++ ++ For elision, there are the flags PTHREAD_MUTEX_ELISION_NP and ++ PTHREAD_MUTEX_NO_ELISION_NP which can be set in addition to the already set ++ type of a mutex. ++ Before a mutex is initialized, only PTHREAD_MUTEX_NO_ELISION_NP can be set ++ with pthread_mutexattr_settype. ++ After a mutex has been initialized, the functions pthread_mutex_*lock can ++ enable elision - if the mutex-type and the machine supports it - by setting ++ the flag PTHREAD_MUTEX_ELISION_NP. This is done concurrently. Afterwards ++ the lock / unlock functions are using specific elision code-paths. */ + int __kind; + __PTHREAD_COMPAT_PADDING_MID + #if __PTHREAD_MUTEX_NUSERS_AFTER_KIND +diff --git a/sysdeps/unix/sysv/linux/powerpc/force-elision.h b/sysdeps/unix/sysv/linux/powerpc/force-elision.h +index fe5d6ceade2bad36..d8f5a4b1c7713bd4 100644 +--- a/sysdeps/unix/sysv/linux/powerpc/force-elision.h ++++ b/sysdeps/unix/sysv/linux/powerpc/force-elision.h +@@ -18,9 +18,45 @@ + + /* Automatically enable elision for existing user lock kinds. */ + #define FORCE_ELISION(m, s) \ +- if (__pthread_force_elision \ +- && (m->__data.__kind & PTHREAD_MUTEX_ELISION_FLAGS_NP) == 0) \ ++ if (__pthread_force_elision) \ + { \ +- mutex->__data.__kind |= PTHREAD_MUTEX_ELISION_NP; \ +- s; \ ++ /* See concurrency notes regarding __kind in \ ++ struct __pthread_mutex_s in \ ++ sysdeps/nptl/bits/thread-shared-types.h. \ ++ \ ++ There are the following cases for the kind of a mutex \ ++ (The mask PTHREAD_MUTEX_ELISION_FLAGS_NP covers the flags \ ++ PTHREAD_MUTEX_ELISION_NP and PTHREAD_MUTEX_NO_ELISION_NP where \ ++ only one of both flags can be set): \ ++ - both flags are not set: \ ++ This is the first lock operation for this mutex. Enable \ ++ elision as it is not enabled so far. \ ++ Note: It can happen that multiple threads are calling e.g. \ ++ pthread_mutex_lock at the same time as the first lock \ ++ operation for this mutex. Then elision is enabled for this \ ++ mutex by multiple threads. Storing with relaxed MO is enough \ ++ as all threads will store the same new value for the kind of \ ++ the mutex. But we have to ensure that we always use the \ ++ elision path regardless if this thread has enabled elision or \ ++ another one. \ ++ \ ++ - PTHREAD_MUTEX_ELISION_NP flag is set: \ ++ Elision was already enabled for this mutex by a previous lock \ ++ operation. See case above. Just use the elision path. \ ++ \ ++ - PTHREAD_MUTEX_NO_ELISION_NP flag is set: \ ++ Elision was explicitly disabled by pthread_mutexattr_settype. \ ++ Do not use the elision path. \ ++ Note: The flag PTHREAD_MUTEX_NO_ELISION_NP will never be \ ++ changed after mutex initialization. */ \ ++ int mutex_kind = atomic_load_relaxed (&((m)->__data.__kind)); \ ++ if ((mutex_kind & PTHREAD_MUTEX_ELISION_FLAGS_NP) == 0) \ ++ { \ ++ mutex_kind |= PTHREAD_MUTEX_ELISION_NP; \ ++ atomic_store_relaxed (&((m)->__data.__kind), mutex_kind); \ ++ } \ ++ if ((mutex_kind & PTHREAD_MUTEX_ELISION_NP) != 0) \ ++ { \ ++ s; \ ++ } \ + } +diff --git a/sysdeps/unix/sysv/linux/s390/force-elision.h b/sysdeps/unix/sysv/linux/s390/force-elision.h +index d8a1b9972f739cfe..71f32367dd6b6489 100644 +--- a/sysdeps/unix/sysv/linux/s390/force-elision.h ++++ b/sysdeps/unix/sysv/linux/s390/force-elision.h +@@ -18,9 +18,45 @@ + + /* Automatically enable elision for existing user lock kinds. */ + #define FORCE_ELISION(m, s) \ +- if (__pthread_force_elision \ +- && (m->__data.__kind & PTHREAD_MUTEX_ELISION_FLAGS_NP) == 0) \ ++ if (__pthread_force_elision) \ + { \ +- mutex->__data.__kind |= PTHREAD_MUTEX_ELISION_NP; \ +- s; \ ++ /* See concurrency notes regarding __kind in \ ++ struct __pthread_mutex_s in \ ++ sysdeps/nptl/bits/thread-shared-types.h. \ ++ \ ++ There are the following cases for the kind of a mutex \ ++ (The mask PTHREAD_MUTEX_ELISION_FLAGS_NP covers the flags \ ++ PTHREAD_MUTEX_ELISION_NP and PTHREAD_MUTEX_NO_ELISION_NP where \ ++ only one of both flags can be set): \ ++ - both flags are not set: \ ++ This is the first lock operation for this mutex. Enable \ ++ elision as it is not enabled so far. \ ++ Note: It can happen that multiple threads are calling e.g. \ ++ pthread_mutex_lock at the same time as the first lock \ ++ operation for this mutex. Then elision is enabled for this \ ++ mutex by multiple threads. Storing with relaxed MO is enough \ ++ as all threads will store the same new value for the kind of \ ++ the mutex. But we have to ensure that we always use the \ ++ elision path regardless if this thread has enabled elision or \ ++ another one. \ ++ \ ++ - PTHREAD_MUTEX_ELISION_NP flag is set: \ ++ Elision was already enabled for this mutex by a previous lock \ ++ operation. See case above. Just use the elision path. \ ++ \ ++ - PTHREAD_MUTEX_NO_ELISION_NP flag is set: \ ++ Elision was explicitly disabled by pthread_mutexattr_settype. \ ++ Do not use the elision path. \ ++ Note: The flag PTHREAD_MUTEX_NO_ELISION_NP will never be \ ++ changed after mutex initialization. */ \ ++ int mutex_kind = atomic_load_relaxed (&((m)->__data.__kind)); \ ++ if ((mutex_kind & PTHREAD_MUTEX_ELISION_FLAGS_NP) == 0) \ ++ { \ ++ mutex_kind |= PTHREAD_MUTEX_ELISION_NP; \ ++ atomic_store_relaxed (&((m)->__data.__kind), mutex_kind); \ ++ } \ ++ if ((mutex_kind & PTHREAD_MUTEX_ELISION_NP) != 0) \ ++ { \ ++ s; \ ++ } \ + } +diff --git a/sysdeps/unix/sysv/linux/x86/force-elision.h b/sysdeps/unix/sysv/linux/x86/force-elision.h +index dd659c908f3046c1..61282d6678d89787 100644 +--- a/sysdeps/unix/sysv/linux/x86/force-elision.h ++++ b/sysdeps/unix/sysv/linux/x86/force-elision.h +@@ -18,9 +18,45 @@ + + /* Automatically enable elision for existing user lock kinds. */ + #define FORCE_ELISION(m, s) \ +- if (__pthread_force_elision \ +- && (m->__data.__kind & PTHREAD_MUTEX_ELISION_FLAGS_NP) == 0) \ ++ if (__pthread_force_elision) \ + { \ +- mutex->__data.__kind |= PTHREAD_MUTEX_ELISION_NP; \ +- s; \ ++ /* See concurrency notes regarding __kind in \ ++ struct __pthread_mutex_s in \ ++ sysdeps/nptl/bits/thread-shared-types.h. \ ++ \ ++ There are the following cases for the kind of a mutex \ ++ (The mask PTHREAD_MUTEX_ELISION_FLAGS_NP covers the flags \ ++ PTHREAD_MUTEX_ELISION_NP and PTHREAD_MUTEX_NO_ELISION_NP where \ ++ only one of both flags can be set): \ ++ - both flags are not set: \ ++ This is the first lock operation for this mutex. Enable \ ++ elision as it is not enabled so far. \ ++ Note: It can happen that multiple threads are calling e.g. \ ++ pthread_mutex_lock at the same time as the first lock \ ++ operation for this mutex. Then elision is enabled for this \ ++ mutex by multiple threads. Storing with relaxed MO is enough \ ++ as all threads will store the same new value for the kind of \ ++ the mutex. But we have to ensure that we always use the \ ++ elision path regardless if this thread has enabled elision or \ ++ another one. \ ++ \ ++ - PTHREAD_MUTEX_ELISION_NP flag is set: \ ++ Elision was already enabled for this mutex by a previous lock \ ++ operation. See case above. Just use the elision path. \ ++ \ ++ - PTHREAD_MUTEX_NO_ELISION_NP flag is set: \ ++ Elision was explicitly disabled by pthread_mutexattr_settype. \ ++ Do not use the elision path. \ ++ Note: The flag PTHREAD_MUTEX_NO_ELISION_NP will never be \ ++ changed after mutex initialization. */ \ ++ int mutex_kind = atomic_load_relaxed (&((m)->__data.__kind)); \ ++ if ((mutex_kind & PTHREAD_MUTEX_ELISION_FLAGS_NP) == 0) \ ++ { \ ++ mutex_kind |= PTHREAD_MUTEX_ELISION_NP; \ ++ atomic_store_relaxed (&((m)->__data.__kind), mutex_kind); \ ++ } \ ++ if ((mutex_kind & PTHREAD_MUTEX_ELISION_NP) != 0) \ ++ { \ ++ s; \ ++ } \ + } diff --git a/SOURCES/glibc-rh1646379.patch b/SOURCES/glibc-rh1646379.patch new file mode 100644 index 0000000..bc8865a --- /dev/null +++ b/SOURCES/glibc-rh1646379.patch @@ -0,0 +1,24 @@ +commit bd3b0fbae33a9a4cc5e2daf049443d5cf03d4251 +Author: Andreas Schwab +Date: Mon Nov 5 12:47:30 2018 +0100 + + libanl: properly cleanup if first helper thread creation failed (bug 22927) + +diff --git a/resolv/gai_misc.c b/resolv/gai_misc.c +index e7c3b63cc5725b4f..80a2cff8353fcb6c 100644 +--- a/resolv/gai_misc.c ++++ b/resolv/gai_misc.c +@@ -261,8 +261,11 @@ __gai_enqueue_request (struct gaicb *gaicbp) + /* We cannot create a thread in the moment and there is + also no thread running. This is a problem. `errno' is + set to EAGAIN if this is only a temporary problem. */ +- assert (lastp->next == newp); +- lastp->next = NULL; ++ assert (requests == newp || lastp->next == newp); ++ if (lastp != NULL) ++ lastp->next = NULL; ++ else ++ requests = NULL; + requests_tail = lastp; + + newp->next = freelist; diff --git a/SOURCES/glibc-rh1650560-1.patch b/SOURCES/glibc-rh1650560-1.patch new file mode 100644 index 0000000..f6724c2 --- /dev/null +++ b/SOURCES/glibc-rh1650560-1.patch @@ -0,0 +1,48 @@ +commit 17b26500f9bb926d85e86821d014f7c1bb88043c +Author: Joseph Myers +Date: Mon Aug 13 21:35:27 2018 +0000 + + Update syscall-names.list for Linux 4.18. + + This patch updates sysdeps/unix/sysv/linux/syscall-names.list for + Linux 4.18. The io_pgetevents and rseq syscalls are added to the + kernel on various architectures, so need to be mentioned in this file. + + Tested with build-many-glibcs.py. + + * sysdeps/unix/sysv/linux/syscall-names.list: Update kernel + version to 4.18. + (io_pgetevents): New syscall. + (rseq): Likewise. + +diff --git a/sysdeps/unix/sysv/linux/syscall-names.list b/sysdeps/unix/sysv/linux/syscall-names.list +index 5306d538e6448163..9982a6334d46ae62 100644 +--- a/sysdeps/unix/sysv/linux/syscall-names.list ++++ b/sysdeps/unix/sysv/linux/syscall-names.list +@@ -22,8 +22,8 @@ + # names are only used if the installed kernel headers also provide + # them. + +-# The list of system calls is current as of Linux 4.17. +-kernel 4.17 ++# The list of system calls is current as of Linux 4.18. ++kernel 4.18 + + FAST_atomic_update + FAST_cmpxchg +@@ -186,6 +186,7 @@ inotify_rm_watch + io_cancel + io_destroy + io_getevents ++io_pgetevents + io_setup + io_submit + ioctl +@@ -431,6 +432,7 @@ renameat2 + request_key + restart_syscall + rmdir ++rseq + rt_sigaction + rt_sigpending + rt_sigprocmask diff --git a/SOURCES/glibc-rh1650560-2.patch b/SOURCES/glibc-rh1650560-2.patch new file mode 100644 index 0000000..1fe8f3b --- /dev/null +++ b/SOURCES/glibc-rh1650560-2.patch @@ -0,0 +1,30 @@ +commit 029ad711b8ad4cf0e5d98e0c138a35a23a376a74 +Author: Joseph Myers +Date: Mon Oct 22 23:26:37 2018 +0000 + + Update kernel version in syscall-names.list to 4.19. + + Linux 4.19 does not add any new syscalls (some existing ones are added + to more architectures); this patch updates the version number in + syscall-names.list to reflect that it's still current for 4.19. + + Tested with build-many-glibcs.py. + + * sysdeps/unix/sysv/linux/syscall-names.list: Update kernel + version to 4.19. + +diff --git a/sysdeps/unix/sysv/linux/syscall-names.list b/sysdeps/unix/sysv/linux/syscall-names.list +index 9982a6334d46ae62..f88001c9c38d5fc7 100644 +--- a/sysdeps/unix/sysv/linux/syscall-names.list ++++ b/sysdeps/unix/sysv/linux/syscall-names.list +@@ -22,8 +22,8 @@ + # names are only used if the installed kernel headers also provide + # them. + +-# The list of system calls is current as of Linux 4.18. +-kernel 4.18 ++# The list of system calls is current as of Linux 4.19. ++kernel 4.19 + + FAST_atomic_update + FAST_cmpxchg diff --git a/SOURCES/glibc-rh1650563.patch b/SOURCES/glibc-rh1650563.patch new file mode 100644 index 0000000..020bddf --- /dev/null +++ b/SOURCES/glibc-rh1650563.patch @@ -0,0 +1,127 @@ +commit 745664bd798ec8fd50438605948eea594179fba1 +Author: Florian Weimer +Date: Tue Aug 28 13:19:27 2018 +0200 + + nscd: Fix use-after-free in addgetnetgrentX [BZ #23520] + + addinnetgrX may use the heap-allocated buffer, so free the buffer + in this function. + +diff --git a/nscd/netgroupcache.c b/nscd/netgroupcache.c +index 2b35389cc816c3c8..87059fb28042f0a5 100644 +--- a/nscd/netgroupcache.c ++++ b/nscd/netgroupcache.c +@@ -113,7 +113,8 @@ do_notfound (struct database_dyn *db, int fd, request_header *req, + static time_t + addgetnetgrentX (struct database_dyn *db, int fd, request_header *req, + const char *key, uid_t uid, struct hashentry *he, +- struct datahead *dh, struct dataset **resultp) ++ struct datahead *dh, struct dataset **resultp, ++ void **tofreep) + { + if (__glibc_unlikely (debug_level > 0)) + { +@@ -139,6 +140,7 @@ addgetnetgrentX (struct database_dyn *db, int fd, request_header *req, + size_t group_len = strlen (key) + 1; + struct name_list *first_needed + = alloca (sizeof (struct name_list) + group_len); ++ *tofreep = NULL; + + if (netgroup_database == NULL + && __nss_database_lookup ("netgroup", NULL, NULL, &netgroup_database)) +@@ -151,6 +153,7 @@ addgetnetgrentX (struct database_dyn *db, int fd, request_header *req, + + memset (&data, '\0', sizeof (data)); + buffer = xmalloc (buflen); ++ *tofreep = buffer; + first_needed->next = first_needed; + memcpy (first_needed->name, key, group_len); + data.needed_groups = first_needed; +@@ -439,8 +442,6 @@ addgetnetgrentX (struct database_dyn *db, int fd, request_header *req, + } + + out: +- free (buffer); +- + *resultp = dataset; + + return timeout; +@@ -477,8 +478,12 @@ addinnetgrX (struct database_dyn *db, int fd, request_header *req, + group, group_len, + db, uid); + time_t timeout; ++ void *tofree; + if (result != NULL) +- timeout = result->head.timeout; ++ { ++ timeout = result->head.timeout; ++ tofree = NULL; ++ } + else + { + request_header req_get = +@@ -487,7 +492,7 @@ addinnetgrX (struct database_dyn *db, int fd, request_header *req, + .key_len = group_len + }; + timeout = addgetnetgrentX (db, -1, &req_get, group, uid, NULL, NULL, +- &result); ++ &result, &tofree); + } + + struct indataset +@@ -560,7 +565,7 @@ addinnetgrX (struct database_dyn *db, int fd, request_header *req, + ++dh->nreloads; + if (cacheable) + pthread_rwlock_unlock (&db->lock); +- return timeout; ++ goto out; + } + + if (he == NULL) +@@ -596,17 +601,30 @@ addinnetgrX (struct database_dyn *db, int fd, request_header *req, + dh->usable = false; + } + ++ out: ++ free (tofree); + return timeout; + } + + ++static time_t ++addgetnetgrentX_ignore (struct database_dyn *db, int fd, request_header *req, ++ const char *key, uid_t uid, struct hashentry *he, ++ struct datahead *dh) ++{ ++ struct dataset *ignore; ++ void *tofree; ++ time_t timeout = addgetnetgrentX (db, fd, req, key, uid, he, dh, ++ &ignore, &tofree); ++ free (tofree); ++ return timeout; ++} ++ + void + addgetnetgrent (struct database_dyn *db, int fd, request_header *req, + void *key, uid_t uid) + { +- struct dataset *ignore; +- +- addgetnetgrentX (db, fd, req, key, uid, NULL, NULL, &ignore); ++ addgetnetgrentX_ignore (db, fd, req, key, uid, NULL, NULL); + } + + +@@ -619,10 +637,8 @@ readdgetnetgrent (struct database_dyn *db, struct hashentry *he, + .type = GETNETGRENT, + .key_len = he->len + }; +- struct dataset *ignore; +- +- return addgetnetgrentX (db, -1, &req, db->data + he->key, he->owner, he, dh, +- &ignore); ++ return addgetnetgrentX_ignore ++ (db, -1, &req, db->data + he->key, he->owner, he, dh); + } + + diff --git a/SOURCES/glibc-rh1650566.patch b/SOURCES/glibc-rh1650566.patch new file mode 100644 index 0000000..4aef679 --- /dev/null +++ b/SOURCES/glibc-rh1650566.patch @@ -0,0 +1,234 @@ +commit a6e8926f8d49a213a9abb1a61f6af964f612ab7f +Author: Paul Pluzhnikov +Date: Fri Aug 31 18:04:32 2018 -0700 + + [BZ #20271] Add newlines in __libc_fatal calls. + +diff --git a/grp/initgroups.c b/grp/initgroups.c +index f056fbf5aa6aa14c..93e7f5814da6286d 100644 +--- a/grp/initgroups.c ++++ b/grp/initgroups.c +@@ -128,7 +128,7 @@ internal_getgrouplist (const char *user, gid_t group, long int *size, + + /* This is really only for debugging. */ + if (NSS_STATUS_TRYAGAIN > status || status > NSS_STATUS_RETURN) +- __libc_fatal ("illegal status in internal_getgrouplist"); ++ __libc_fatal ("Illegal status in internal_getgrouplist.\n"); + + /* For compatibility reason we will continue to look for more + entries using the next service even though data has already +diff --git a/include/stdio.h b/include/stdio.h +index 9162d4e24717e31a..7a5c09089fc4d348 100644 +--- a/include/stdio.h ++++ b/include/stdio.h +@@ -98,7 +98,8 @@ enum __libc_message_action + do_backtrace = 1 << 1 /* Backtrace. */ + }; + +-/* Print out MESSAGE on the error output and abort. */ ++/* Print out MESSAGE (which should end with a newline) on the error output ++ and abort. */ + extern void __libc_fatal (const char *__message) + __attribute__ ((__noreturn__)); + extern void __libc_message (enum __libc_message_action action, +diff --git a/nptl/pthread_cond_wait.c b/nptl/pthread_cond_wait.c +index 3e1105418210288e..ebf07ca82d87de7d 100644 +--- a/nptl/pthread_cond_wait.c ++++ b/nptl/pthread_cond_wait.c +@@ -516,7 +516,7 @@ __pthread_cond_wait_common (pthread_cond_t *cond, pthread_mutex_t *mutex, + struct timespec rt; + if (__clock_gettime (CLOCK_MONOTONIC, &rt) != 0) + __libc_fatal ("clock_gettime does not support " +- "CLOCK_MONOTONIC"); ++ "CLOCK_MONOTONIC\n"); + /* Convert the absolute timeout value to a relative + timeout. */ + rt.tv_sec = abstime->tv_sec - rt.tv_sec; +diff --git a/nscd/initgrcache.c b/nscd/initgrcache.c +index 2c74951f579f4afd..4764f14a45f68e0a 100644 +--- a/nscd/initgrcache.c ++++ b/nscd/initgrcache.c +@@ -159,7 +159,7 @@ addinitgroupsX (struct database_dyn *db, int fd, request_header *req, + + /* This is really only for debugging. */ + if (NSS_STATUS_TRYAGAIN > status || status > NSS_STATUS_RETURN) +- __libc_fatal ("illegal status in internal_getgrouplist"); ++ __libc_fatal ("Illegal status in internal_getgrouplist.\n"); + + any_success |= status == NSS_STATUS_SUCCESS; + +diff --git a/nss/nsswitch.c b/nss/nsswitch.c +index ee46f24424bc1ca2..3c48b4b85e881cdb 100644 +--- a/nss/nsswitch.c ++++ b/nss/nsswitch.c +@@ -235,7 +235,7 @@ __nss_next2 (service_user **ni, const char *fct_name, const char *fct2_name, + /* This is really only for debugging. */ + if (__builtin_expect (NSS_STATUS_TRYAGAIN > status + || status > NSS_STATUS_RETURN, 0)) +- __libc_fatal ("illegal status in __nss_next"); ++ __libc_fatal ("Illegal status in __nss_next.\n"); + + if (nss_next_action (*ni, status) == NSS_ACTION_RETURN) + return 1; +diff --git a/sysdeps/aarch64/dl-irel.h b/sysdeps/aarch64/dl-irel.h +index 5889ee187b7a1eaf..bef71ed0f31a6387 100644 +--- a/sysdeps/aarch64/dl-irel.h ++++ b/sysdeps/aarch64/dl-irel.h +@@ -47,7 +47,7 @@ elf_irela (const ElfW(Rela) *reloc) + *reloc_addr = value; + } + else +- __libc_fatal ("unexpected reloc type in static binary"); ++ __libc_fatal ("Unexpected reloc type in static binary.\n"); + } + + #endif +diff --git a/sysdeps/arm/dl-irel.h b/sysdeps/arm/dl-irel.h +index a7b6456075659baf..be6eb7743eb5f08d 100644 +--- a/sysdeps/arm/dl-irel.h ++++ b/sysdeps/arm/dl-irel.h +@@ -46,7 +46,7 @@ elf_irel (const Elf32_Rel *reloc) + *reloc_addr = value; + } + else +- __libc_fatal ("unexpected reloc type in static binary"); ++ __libc_fatal ("Unexpected reloc type in static binary.\n"); + } + + #endif /* dl-irel.h */ +diff --git a/sysdeps/generic/unwind-dw2.c b/sysdeps/generic/unwind-dw2.c +index 082609b34a3f773b..724c16a7f0bf465b 100644 +--- a/sysdeps/generic/unwind-dw2.c ++++ b/sysdeps/generic/unwind-dw2.c +@@ -843,7 +843,7 @@ execute_cfa_program (const unsigned char *insn_ptr, + struct frame_state_reg_info *old_rs = fs->regs.prev; + #ifdef _LIBC + if (old_rs == NULL) +- __libc_fatal ("invalid DWARF unwind data"); ++ __libc_fatal ("Invalid DWARF unwind data.\n"); + else + #endif + { +diff --git a/sysdeps/i386/dl-irel.h b/sysdeps/i386/dl-irel.h +index 55303180c7aca495..bcaf0668acf8e2f2 100644 +--- a/sysdeps/i386/dl-irel.h ++++ b/sysdeps/i386/dl-irel.h +@@ -45,7 +45,7 @@ elf_irel (const Elf32_Rel *reloc) + *reloc_addr = value; + } + else +- __libc_fatal ("unexpected reloc type in static binary"); ++ __libc_fatal ("Unexpected reloc type in static binary.\n"); + } + + #endif /* dl-irel.h */ +diff --git a/sysdeps/nptl/futex-internal.h b/sysdeps/nptl/futex-internal.h +index 1a5624789d4ab117..6fd27f0df6c27b69 100644 +--- a/sysdeps/nptl/futex-internal.h ++++ b/sysdeps/nptl/futex-internal.h +@@ -197,7 +197,7 @@ futex_wake (unsigned int* futex_word, int processes_to_wake, int private); + static __always_inline __attribute__ ((__noreturn__)) void + futex_fatal_error (void) + { +- __libc_fatal ("The futex facility returned an unexpected error code."); ++ __libc_fatal ("The futex facility returned an unexpected error code.\n"); + } + + #endif /* futex-internal.h */ +diff --git a/sysdeps/powerpc/powerpc32/dl-irel.h b/sysdeps/powerpc/powerpc32/dl-irel.h +index a7368b25829618cb..61d0e4cf61ec45d3 100644 +--- a/sysdeps/powerpc/powerpc32/dl-irel.h ++++ b/sysdeps/powerpc/powerpc32/dl-irel.h +@@ -46,7 +46,7 @@ elf_irela (const Elf32_Rela *reloc) + *reloc_addr = value; + } + else +- __libc_fatal ("unexpected reloc type in static binary"); ++ __libc_fatal ("Unexpected reloc type in static binary.\n"); + } + + #endif /* dl-irel.h */ +diff --git a/sysdeps/powerpc/powerpc64/dl-irel.h b/sysdeps/powerpc/powerpc64/dl-irel.h +index ab13c04358868270..2fd0ee8a86e85ba0 100644 +--- a/sysdeps/powerpc/powerpc64/dl-irel.h ++++ b/sysdeps/powerpc/powerpc64/dl-irel.h +@@ -57,7 +57,7 @@ elf_irela (const Elf64_Rela *reloc) + #endif + } + else +- __libc_fatal ("unexpected reloc type in static binary"); ++ __libc_fatal ("Unexpected reloc type in static binary.\n"); + } + + #endif /* dl-irel.h */ +diff --git a/sysdeps/s390/dl-irel.h b/sysdeps/s390/dl-irel.h +index d8ba7ba42709f45c..ecb24f0a9be0daa7 100644 +--- a/sysdeps/s390/dl-irel.h ++++ b/sysdeps/s390/dl-irel.h +@@ -46,7 +46,7 @@ elf_irela (const ElfW(Rela) *reloc) + *reloc_addr = value; + } + else +- __libc_fatal ("unexpected reloc type in static binary"); ++ __libc_fatal ("Unexpected reloc type in static binary.\n"); + } + + #endif /* dl-irel.h */ +diff --git a/sysdeps/sparc/sparc32/dl-irel.h b/sysdeps/sparc/sparc32/dl-irel.h +index ffca36864f24d1fb..cf47cda8345b1a39 100644 +--- a/sysdeps/sparc/sparc32/dl-irel.h ++++ b/sysdeps/sparc/sparc32/dl-irel.h +@@ -56,7 +56,7 @@ elf_irela (const Elf32_Rela *reloc) + else if (r_type == R_SPARC_NONE) + ; + else +- __libc_fatal ("unexpected reloc type in static binary"); ++ __libc_fatal ("Unexpected reloc type in static binary.\n"); + } + + #endif /* dl-irel.h */ +diff --git a/sysdeps/sparc/sparc64/dl-irel.h b/sysdeps/sparc/sparc64/dl-irel.h +index c5cd3057aca1baf6..446fed18365cfd13 100644 +--- a/sysdeps/sparc/sparc64/dl-irel.h ++++ b/sysdeps/sparc/sparc64/dl-irel.h +@@ -59,7 +59,7 @@ elf_irela (const Elf64_Rela *reloc) + else if (r_type == R_SPARC_NONE) + ; + else +- __libc_fatal ("unexpected reloc type in static binary"); ++ __libc_fatal ("Unexpected reloc type in static binary.\n"); + } + + #endif /* dl-irel.h */ +diff --git a/sysdeps/unix/sysv/linux/netlink_assert_response.c b/sysdeps/unix/sysv/linux/netlink_assert_response.c +index f31ccb52ffa56436..6afc3a17ced18e1c 100644 +--- a/sysdeps/unix/sysv/linux/netlink_assert_response.c ++++ b/sysdeps/unix/sysv/linux/netlink_assert_response.c +@@ -72,12 +72,12 @@ __netlink_assert_response (int fd, ssize_t result) + char message[200]; + if (family < 0) + __snprintf (message, sizeof (message), +- "Unexpected error %d on netlink descriptor %d", ++ "Unexpected error %d on netlink descriptor %d.\n", + error_code, fd); + else + __snprintf (message, sizeof (message), + "Unexpected error %d on netlink descriptor %d" +- " (address family %d)", ++ " (address family %d).\n", + error_code, fd, family); + __libc_fatal (message); + } +diff --git a/sysdeps/x86_64/dl-irel.h b/sysdeps/x86_64/dl-irel.h +index 6ecc50fb42333c19..33f100d8b1781ea7 100644 +--- a/sysdeps/x86_64/dl-irel.h ++++ b/sysdeps/x86_64/dl-irel.h +@@ -45,7 +45,7 @@ elf_irela (const ElfW(Rela) *reloc) + *reloc_addr = value; + } + else +- __libc_fatal ("unexpected reloc type in static binary"); ++ __libc_fatal ("Unexpected reloc type in static binary.\n"); + } + + #endif /* dl-irel.h */ diff --git a/SOURCES/glibc-rh1650571.patch b/SOURCES/glibc-rh1650571.patch new file mode 100644 index 0000000..927e0dc --- /dev/null +++ b/SOURCES/glibc-rh1650571.patch @@ -0,0 +1,24 @@ +commit e4e4fde51a309801af5eed72d3494cbf4b7737aa +Author: Paul Eggert +Date: Tue Sep 18 15:02:10 2018 -0700 + + Fix tzfile low-memory assertion failure + + [BZ #21716] + * time/tzfile.c (__tzfile_read): Check for memory exhaustion + when registering time zone abbreviations. + +diff --git a/time/tzfile.c b/time/tzfile.c +index 2a385b92bcdefec0..ea6e94030392fc75 100644 +--- a/time/tzfile.c ++++ b/time/tzfile.c +@@ -410,7 +410,8 @@ __tzfile_read (const char *file, size_t extra, char **extrap) + + /* First "register" all timezone names. */ + for (i = 0; i < num_types; ++i) +- (void) __tzstring (&zone_names[types[i].idx]); ++ if (__tzstring (&zone_names[types[i].idx]) == NULL) ++ goto ret_free_transitions; + + /* Find the standard and daylight time offsets used by the rule file. + We choose the offsets in the types of each flavor that are diff --git a/SOURCES/glibc-rh1651274.patch b/SOURCES/glibc-rh1651274.patch new file mode 100644 index 0000000..d65cb0a --- /dev/null +++ b/SOURCES/glibc-rh1651274.patch @@ -0,0 +1,70 @@ +commit 35e3fbc4512c880fccb35b8e3abd132d4be18480 +Author: Florian Weimer +Date: Mon Nov 19 15:35:03 2018 +0100 + + support: Print timestamps in timeout handler + + This is sometimes useful to determine if a test truly got stuck, or if + it was making progress (logging information to standard output) and + was merely slow to finish. + +diff --git a/support/support_test_main.c b/support/support_test_main.c +index 23429779aca85613..fa3c2e06dee5ae0f 100644 +--- a/support/support_test_main.c ++++ b/support/support_test_main.c +@@ -30,6 +30,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -86,6 +87,19 @@ static pid_t test_pid; + /* The cleanup handler passed to test_main. */ + static void (*cleanup_function) (void); + ++static void ++print_timestamp (const char *what, struct timeval tv) ++{ ++ struct tm tm; ++ if (gmtime_r (&tv.tv_sec, &tm) == NULL) ++ printf ("%s: %lld.%06d\n", ++ what, (long long int) tv.tv_sec, (int) tv.tv_usec); ++ else ++ printf ("%s: %04d-%02d-%02dT%02d:%02d:%02d.%06d\n", ++ what, 1900 + tm.tm_year, tm.tm_mon + 1, tm.tm_mday, ++ tm.tm_hour, tm.tm_min, tm.tm_sec, (int) tv.tv_usec); ++} ++ + /* Timeout handler. We kill the child and exit with an error. */ + static void + __attribute__ ((noreturn)) +@@ -94,6 +108,13 @@ signal_handler (int sig) + int killed; + int status; + ++ /* Do this first to avoid further interference from the ++ subprocess. */ ++ struct timeval now; ++ bool now_available = gettimeofday (&now, NULL) == 0; ++ struct stat64 st; ++ bool st_available = fstat64 (STDOUT_FILENO, &st) == 0 && st.st_mtime != 0; ++ + assert (test_pid > 1); + /* Kill the whole process group. */ + kill (-test_pid, SIGKILL); +@@ -144,6 +165,13 @@ signal_handler (int sig) + printf ("Timed out: killed the child process but it exited %d\n", + WEXITSTATUS (status)); + ++ if (now_available) ++ print_timestamp ("Termination time", now); ++ if (st_available) ++ print_timestamp ("Last write to standard output", ++ (struct timeval) { st.st_mtim.tv_sec, ++ st.st_mtim.tv_nsec / 1000 }); ++ + /* Exit with an error. */ + exit (1); + } diff --git a/SOURCES/glibc-rh1651283-1.patch b/SOURCES/glibc-rh1651283-1.patch new file mode 100644 index 0000000..cd7e903 --- /dev/null +++ b/SOURCES/glibc-rh1651283-1.patch @@ -0,0 +1,31 @@ +commit d6db68e66dff25d12c3bc5641b60cbd7fb6ab44f +Author: Moritz Eckert +Date: Thu Aug 16 21:08:36 2018 -0400 + + malloc: Mitigate null-byte overflow attacks + + * malloc/malloc.c (_int_free): Check for corrupt prev_size vs size. + (malloc_consolidate): Likewise. + +diff --git a/malloc/malloc.c b/malloc/malloc.c +index 13c52f376859562d..e450597e2e527fb7 100644 +--- a/malloc/malloc.c ++++ b/malloc/malloc.c +@@ -4306,6 +4306,8 @@ _int_free (mstate av, mchunkptr p, int have_lock) + prevsize = prev_size (p); + size += prevsize; + p = chunk_at_offset(p, -((long) prevsize)); ++ if (__glibc_unlikely (chunksize(p) != prevsize)) ++ malloc_printerr ("corrupted size vs. prev_size while consolidating"); + unlink(av, p, bck, fwd); + } + +@@ -4467,6 +4469,8 @@ static void malloc_consolidate(mstate av) + prevsize = prev_size (p); + size += prevsize; + p = chunk_at_offset(p, -((long) prevsize)); ++ if (__glibc_unlikely (chunksize(p) != prevsize)) ++ malloc_printerr ("corrupted size vs. prev_size in fastbins"); + unlink(av, p, bck, fwd); + } + diff --git a/SOURCES/glibc-rh1651283-2.patch b/SOURCES/glibc-rh1651283-2.patch new file mode 100644 index 0000000..ad64396 --- /dev/null +++ b/SOURCES/glibc-rh1651283-2.patch @@ -0,0 +1,30 @@ +commit 30a17d8c95fbfb15c52d1115803b63aaa73a285c +Author: Pochang Chen +Date: Thu Aug 16 15:24:24 2018 -0400 + + malloc: Verify size of top chunk. + + The House of Force is a well-known technique to exploit heap + overflow. In essence, this exploit takes three steps: + 1. Overwrite the size of top chunk with very large value (e.g. -1). + 2. Request x bytes from top chunk. As the size of top chunk + is corrupted, x can be arbitrarily large and top chunk will + still be offset by x. + 3. The next allocation from top chunk will thus be controllable. + + If we verify the size of top chunk at step 2, we can stop such attack. + +diff --git a/malloc/malloc.c b/malloc/malloc.c +index e450597e2e527fb7..d8d4581a9dcea80a 100644 +--- a/malloc/malloc.c ++++ b/malloc/malloc.c +@@ -4084,6 +4084,9 @@ _int_malloc (mstate av, size_t bytes) + victim = av->top; + size = chunksize (victim); + ++ if (__glibc_unlikely (size > av->system_mem)) ++ malloc_printerr ("malloc(): corrupted top size"); ++ + if ((unsigned long) (size) >= (unsigned long) (nb + MINSIZE)) + { + remainder_size = size - nb; diff --git a/SOURCES/glibc-rh1651283-3.patch b/SOURCES/glibc-rh1651283-3.patch new file mode 100644 index 0000000..65a07db --- /dev/null +++ b/SOURCES/glibc-rh1651283-3.patch @@ -0,0 +1,122 @@ +commit b90ddd08f6dd688e651df9ee89ca3a69ff88cd0c +Author: Istvan Kurucsai +Date: Tue Jan 16 14:54:32 2018 +0100 + + malloc: Additional checks for unsorted bin integrity I. + + On Thu, Jan 11, 2018 at 3:50 PM, Florian Weimer wrote: + > On 11/07/2017 04:27 PM, Istvan Kurucsai wrote: + >> + >> + next = chunk_at_offset (victim, size); + > + > + > For new code, we prefer declarations with initializers. + + Noted. + + >> + if (__glibc_unlikely (chunksize_nomask (victim) <= 2 * SIZE_SZ) + >> + || __glibc_unlikely (chunksize_nomask (victim) > + >> av->system_mem)) + >> + malloc_printerr("malloc(): invalid size (unsorted)"); + >> + if (__glibc_unlikely (chunksize_nomask (next) < 2 * SIZE_SZ) + >> + || __glibc_unlikely (chunksize_nomask (next) > + >> av->system_mem)) + >> + malloc_printerr("malloc(): invalid next size (unsorted)"); + >> + if (__glibc_unlikely ((prev_size (next) & ~(SIZE_BITS)) != + >> size)) + >> + malloc_printerr("malloc(): mismatching next->prev_size + >> (unsorted)"); + > + > + > I think this check is redundant because prev_size (next) and chunksize + > (victim) are loaded from the same memory location. + + I'm fairly certain that it compares mchunk_size of victim against + mchunk_prev_size of the next chunk, i.e. the size of victim in its + header and footer. + + >> + if (__glibc_unlikely (bck->fd != victim) + >> + || __glibc_unlikely (victim->fd != unsorted_chunks (av))) + >> + malloc_printerr("malloc(): unsorted double linked list + >> corrupted"); + >> + if (__glibc_unlikely (prev_inuse(next))) + >> + malloc_printerr("malloc(): invalid next->prev_inuse + >> (unsorted)"); + > + > + > There's a missing space after malloc_printerr. + + Noted. + + > Why do you keep using chunksize_nomask? We never investigated why the + > original code uses it. It may have been an accident. + + You are right, I don't think it makes a difference in these checks. So + the size local can be reused for the checks against victim. For next, + leaving it as such avoids the masking operation. + + > Again, for non-main arenas, the checks against av->system_mem could be made + > tighter (against the heap size). Maybe you could put the condition into a + > separate inline function? + + We could also do a chunk boundary check similar to what I proposed in + the thread for the first patch in the series to be even more strict. + I'll gladly try to implement either but believe that refining these + checks would bring less benefits than in the case of the top chunk. + Intra-arena or intra-heap overlaps would still be doable here with + unsorted chunks and I don't see any way to counter that besides more + generic measures like randomizing allocations and your metadata + encoding patches. + + I've attached a revised version with the above comments incorporated + but without the refined checks. + + Thanks, + Istvan + + From a12d5d40fd7aed5fa10fc444dcb819947b72b315 Mon Sep 17 00:00:00 2001 + From: Istvan Kurucsai + Date: Tue, 16 Jan 2018 14:48:16 +0100 + Subject: [PATCH v2 1/1] malloc: Additional checks for unsorted bin integrity + I. + + Ensure the following properties of chunks encountered during binning: + - victim chunk has reasonable size + - next chunk has reasonable size + - next->prev_size == victim->size + - valid double linked list + - PREV_INUSE of next chunk is unset + + * malloc/malloc.c (_int_malloc): Additional binning code checks. + +diff --git a/malloc/malloc.c b/malloc/malloc.c +index d8d4581a9dcea80a..dad0e73735789530 100644 +--- a/malloc/malloc.c ++++ b/malloc/malloc.c +@@ -3724,11 +3724,22 @@ _int_malloc (mstate av, size_t bytes) + while ((victim = unsorted_chunks (av)->bk) != unsorted_chunks (av)) + { + bck = victim->bk; +- if (__builtin_expect (chunksize_nomask (victim) <= 2 * SIZE_SZ, 0) +- || __builtin_expect (chunksize_nomask (victim) +- > av->system_mem, 0)) +- malloc_printerr ("malloc(): memory corruption"); + size = chunksize (victim); ++ mchunkptr next = chunk_at_offset (victim, size); ++ ++ if (__glibc_unlikely (size <= 2 * SIZE_SZ) ++ || __glibc_unlikely (size > av->system_mem)) ++ malloc_printerr ("malloc(): invalid size (unsorted)"); ++ if (__glibc_unlikely (chunksize_nomask (next) < 2 * SIZE_SZ) ++ || __glibc_unlikely (chunksize_nomask (next) > av->system_mem)) ++ malloc_printerr ("malloc(): invalid next size (unsorted)"); ++ if (__glibc_unlikely ((prev_size (next) & ~(SIZE_BITS)) != size)) ++ malloc_printerr ("malloc(): mismatching next->prev_size (unsorted)"); ++ if (__glibc_unlikely (bck->fd != victim) ++ || __glibc_unlikely (victim->fd != unsorted_chunks (av))) ++ malloc_printerr ("malloc(): unsorted double linked list corrupted"); ++ if (__glibc_unlikely (prev_inuse(next))) ++ malloc_printerr ("malloc(): invalid next->prev_inuse (unsorted)"); + + /* + If a small request, try to use last remainder if it is the diff --git a/SOURCES/glibc-rh1651283-4.patch b/SOURCES/glibc-rh1651283-4.patch new file mode 100644 index 0000000..fcec8ee --- /dev/null +++ b/SOURCES/glibc-rh1651283-4.patch @@ -0,0 +1,26 @@ +The below commit contains only a whitespace change and was backported in +order to avoid future conflicts. + +commit 35cfefd96062145eeb8aee6bd72d07e0909a6b2e +Author: Florian Weimer +Date: Mon Aug 20 14:57:13 2018 +0200 + + malloc: Add ChangeLog for accidentally committed change + + Commit b90ddd08f6dd688e651df9ee89ca3a69ff88cd0c ("malloc: Additional + checks for unsorted bin integrity I.") was committed without a + whitespace fix, so it is adjusted here as well. + +diff --git a/malloc/malloc.c b/malloc/malloc.c +index c07463001a65af90..eb6a8ff33c0c313b 100644 +--- a/malloc/malloc.c ++++ b/malloc/malloc.c +@@ -3745,7 +3745,7 @@ _int_malloc (mstate av, size_t bytes) + if (__glibc_unlikely (bck->fd != victim) + || __glibc_unlikely (victim->fd != unsorted_chunks (av))) + malloc_printerr ("malloc(): unsorted double linked list corrupted"); +- if (__glibc_unlikely (prev_inuse(next))) ++ if (__glibc_unlikely (prev_inuse (next))) + malloc_printerr ("malloc(): invalid next->prev_inuse (unsorted)"); + + /* diff --git a/SOURCES/glibc-rh1651283-5.patch b/SOURCES/glibc-rh1651283-5.patch new file mode 100644 index 0000000..e18b513 --- /dev/null +++ b/SOURCES/glibc-rh1651283-5.patch @@ -0,0 +1,38 @@ +commit ebe544bf6e8eec35e754fd49efb027c6f161b6cb +Author: Istvan Kurucsai +Date: Thu Dec 20 23:30:07 2018 -0500 + + malloc: Add more integrity checks to mremap_chunk. + + * malloc/malloc.c (mremap_chunk): Additional checks. + +diff --git a/malloc/malloc.c b/malloc/malloc.c +index eb6a8ff33c0c313b..4df5cb4862a7b854 100644 +--- a/malloc/malloc.c ++++ b/malloc/malloc.c +@@ -2856,16 +2856,22 @@ mremap_chunk (mchunkptr p, size_t new_size) + char *cp; + + assert (chunk_is_mmapped (p)); +- assert (((size + offset) & (GLRO (dl_pagesize) - 1)) == 0); ++ ++ uintptr_t block = (uintptr_t) p - offset; ++ uintptr_t mem = (uintptr_t) chunk2mem(p); ++ size_t total_size = offset + size; ++ if (__glibc_unlikely ((block | total_size) & (pagesize - 1)) != 0 ++ || __glibc_unlikely (!powerof2 (mem & (pagesize - 1)))) ++ malloc_printerr("mremap_chunk(): invalid pointer"); + + /* Note the extra SIZE_SZ overhead as in mmap_chunk(). */ + new_size = ALIGN_UP (new_size + offset + SIZE_SZ, pagesize); + + /* No need to remap if the number of pages does not change. */ +- if (size + offset == new_size) ++ if (total_size == new_size) + return p; + +- cp = (char *) __mremap ((char *) p - offset, size + offset, new_size, ++ cp = (char *) __mremap ((char *) block, total_size, new_size, + MREMAP_MAYMOVE); + + if (cp == MAP_FAILED) diff --git a/SOURCES/glibc-rh1651283-6.patch b/SOURCES/glibc-rh1651283-6.patch new file mode 100644 index 0000000..c578d11 --- /dev/null +++ b/SOURCES/glibc-rh1651283-6.patch @@ -0,0 +1,38 @@ +commit c0e82f117357a941e4d40fcc08babbd6a3c3a1b5 +Author: Istvan Kurucsai +Date: Fri Dec 21 00:13:01 2018 -0500 + + malloc: Check the alignment of mmapped chunks before unmapping. + + * malloc/malloc.c (munmap_chunk): Verify chunk alignment. + +diff --git a/malloc/malloc.c b/malloc/malloc.c +index 4df5cb4862a7b854..4412a4ffc83b013b 100644 +--- a/malloc/malloc.c ++++ b/malloc/malloc.c +@@ -2817,6 +2817,7 @@ systrim (size_t pad, mstate av) + static void + munmap_chunk (mchunkptr p) + { ++ size_t pagesize = GLRO (dl_pagesize); + INTERNAL_SIZE_T size = chunksize (p); + + assert (chunk_is_mmapped (p)); +@@ -2826,6 +2827,7 @@ munmap_chunk (mchunkptr p) + if (DUMPED_MAIN_ARENA_CHUNK (p)) + return; + ++ uintptr_t mem = (uintptr_t) chunk2mem (p); + uintptr_t block = (uintptr_t) p - prev_size (p); + size_t total_size = prev_size (p) + size; + /* Unfortunately we have to do the compilers job by hand here. Normally +@@ -2833,7 +2835,8 @@ munmap_chunk (mchunkptr p) + page size. But gcc does not recognize the optimization possibility + (in the moment at least) so we combine the two values into one before + the bit test. */ +- if (__builtin_expect (((block | total_size) & (GLRO (dl_pagesize) - 1)) != 0, 0)) ++ if (__glibc_unlikely ((block | total_size) & (pagesize - 1)) != 0 ++ || __glibc_unlikely (!powerof2 (mem & (pagesize - 1)))) + malloc_printerr ("munmap_chunk(): invalid pointer"); + + atomic_decrement (&mp_.n_mmaps); diff --git a/SOURCES/glibc-rh1651283-7.patch b/SOURCES/glibc-rh1651283-7.patch new file mode 100644 index 0000000..af0f92b --- /dev/null +++ b/SOURCES/glibc-rh1651283-7.patch @@ -0,0 +1,31 @@ +commit 5b06f538c5aee0389ed034f60d90a8884d6d54de +Author: Adam Maris +Date: Thu Mar 14 16:51:16 2019 -0400 + + malloc: Check for large bin list corruption when inserting unsorted chunk + + Fixes bug 24216. This patch adds security checks for bk and bk_nextsize pointers + of chunks in large bin when inserting chunk from unsorted bin. It was possible + to write the pointer to victim (newly inserted chunk) to arbitrary memory + locations if bk or bk_nextsize pointers of the next large bin chunk + got corrupted. + +diff --git a/malloc/malloc.c b/malloc/malloc.c +index 4412a4ffc83b013b..723d393f529bdb4c 100644 +--- a/malloc/malloc.c ++++ b/malloc/malloc.c +@@ -3876,10 +3876,14 @@ _int_malloc (mstate av, size_t bytes) + { + victim->fd_nextsize = fwd; + victim->bk_nextsize = fwd->bk_nextsize; ++ if (__glibc_unlikely (fwd->bk_nextsize->fd_nextsize != fwd)) ++ malloc_printerr ("malloc(): largebin double linked list corrupted (nextsize)"); + fwd->bk_nextsize = victim; + victim->bk_nextsize->fd_nextsize = victim; + } + bck = fwd->bk; ++ if (bck->fd != fwd) ++ malloc_printerr ("malloc(): largebin double linked list corrupted (bk)"); + } + } + else diff --git a/SOURCES/glibc-rh1651742.patch b/SOURCES/glibc-rh1651742.patch new file mode 100644 index 0000000..1851691 --- /dev/null +++ b/SOURCES/glibc-rh1651742.patch @@ -0,0 +1,307 @@ +commit f0458cf4f9ff3d870c43b624e6dccaaf657d5e83 +Author: Adhemerval Zanella +Date: Mon Aug 27 09:42:50 2018 -0300 + + powerpc: Only enable TLE with PPC_FEATURE2_HTM_NOSC + + Linux from 3.9 through 4.2 does not abort HTM transaction on syscalls, + instead it suspend and resume it when leaving the kernel. The + side-effects of the syscall will always remain visible, even if the + transaction is aborted. This is an issue when transaction is used along + with futex syscall, on pthread_cond_wait for instance, where the futex + call might succeed but the transaction is rolled back leading the + pthread_cond object in an inconsistent state. + + Glibc used to prevent it by always aborting a transaction before issuing + a syscall. Linux 4.2 also decided to abort active transaction in + syscalls which makes the glibc workaround superfluous. Worse, glibc + transaction abortion leads to a performance issue on recent kernels + where the HTM state is saved/restore lazily (v4.9). By aborting a + transaction on every syscalls, regardless whether a transaction has being + initiated before, GLIBS makes the kernel always save/restore HTM state + (it can not even lazily disable it after a certain number of syscall + iterations). + + Because of this shortcoming, Transactional Lock Elision is just enabled + when it has been explicitly set (either by tunables of by a configure + switch) and if kernel aborts HTM transactions on syscalls + (PPC_FEATURE2_HTM_NOSC). It is reported that using simple benchmark [1], + the context-switch is about 5% faster by not issuing a tabort in every + syscall in newer kernels. + + Checked on powerpc64le-linux-gnu with 4.4.0 kernel (Ubuntu 16.04). + + * NEWS: Add note about new TLE support on powerpc64le. + * sysdeps/powerpc/nptl/tcb-offsets.sym (TM_CAPABLE): Remove. + * sysdeps/powerpc/nptl/tls.h (tcbhead_t): Rename tm_capable to + __ununsed1. + (TLS_INIT_TP, TLS_DEFINE_INIT_TP): Remove tm_capable setup. + (THREAD_GET_TM_CAPABLE, THREAD_SET_TM_CAPABLE): Remove macros. + * sysdeps/powerpc/powerpc32/sysdep.h, + sysdeps/powerpc/powerpc64/sysdep.h (ABORT_TRANSACTION_IMPL, + ABORT_TRANSACTION): Remove macros. + * sysdeps/powerpc/sysdep.h (ABORT_TRANSACTION): Likewise. + * sysdeps/unix/sysv/linux/powerpc/elision-conf.c (elision_init): Set + __pthread_force_elision iff PPC_FEATURE2_HTM_NOSC is set. + * sysdeps/unix/sysv/linux/powerpc/powerpc32/sysdep.h, + sysdeps/unix/sysv/linux/powerpc/powerpc64/sysdep.h + sysdeps/unix/sysv/linux/powerpc/syscall.S (ABORT_TRANSACTION): Remove + usage. + * sysdeps/unix/sysv/linux/powerpc/not-errno.h: Remove file. + + Reported-by: Breno Leitão + +diff --git a/sysdeps/powerpc/nptl/tcb-offsets.sym b/sysdeps/powerpc/nptl/tcb-offsets.sym +index e5bb2b3..4c01615 100644 +--- a/sysdeps/powerpc/nptl/tcb-offsets.sym ++++ b/sysdeps/powerpc/nptl/tcb-offsets.sym +@@ -21,7 +21,6 @@ DSO_SLOT2 (offsetof (tcbhead_t, dso_slot2) - TLS_TCB_OFFSET - sizeof (tcbhead_ + #ifdef __powerpc64__ + TCB_AT_PLATFORM (offsetof (tcbhead_t, at_platform) - TLS_TCB_OFFSET - sizeof(tcbhead_t)) + #endif +-TM_CAPABLE (offsetof (tcbhead_t, tm_capable) - TLS_TCB_OFFSET - sizeof (tcbhead_t)) + #ifndef __powerpc64__ + TCB_AT_PLATFORM (offsetof (tcbhead_t, at_platform) - TLS_TCB_OFFSET - sizeof(tcbhead_t)) + PADDING (offsetof (tcbhead_t, padding) - TLS_TCB_OFFSET - sizeof(tcbhead_t)) +diff --git a/sysdeps/powerpc/nptl/tls.h b/sysdeps/powerpc/nptl/tls.h +index f88fed5..8317ca7 100644 +--- a/sysdeps/powerpc/nptl/tls.h ++++ b/sysdeps/powerpc/nptl/tls.h +@@ -67,8 +67,7 @@ typedef struct + uint32_t padding; + uint32_t at_platform; + #endif +- /* Indicate if HTM capable (ISA 2.07). */ +- uint32_t tm_capable; ++ uint32_t __unused; + /* Reservation for AT_PLATFORM data - powerpc64. */ + #ifdef __powerpc64__ + uint32_t at_platform; +@@ -142,7 +141,6 @@ register void *__thread_register __asm__ ("r13"); + # define TLS_INIT_TP(tcbp) \ + ({ \ + __thread_register = (void *) (tcbp) + TLS_TCB_OFFSET; \ +- THREAD_SET_TM_CAPABLE (__tcb_hwcap & PPC_FEATURE2_HAS_HTM ? 1 : 0); \ + THREAD_SET_HWCAP (__tcb_hwcap); \ + THREAD_SET_AT_PLATFORM (__tcb_platform); \ + NULL; \ +@@ -151,8 +149,6 @@ register void *__thread_register __asm__ ("r13"); + /* 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; \ +- (((tcbhead_t *) ((char *) tp - TLS_TCB_OFFSET))[-1].tm_capable) = \ +- THREAD_GET_TM_CAPABLE (); \ + (((tcbhead_t *) ((char *) tp - TLS_TCB_OFFSET))[-1].hwcap) = \ + THREAD_GET_HWCAP (); \ + (((tcbhead_t *) ((char *) tp - TLS_TCB_OFFSET))[-1].at_platform) = \ +@@ -210,13 +206,6 @@ register void *__thread_register __asm__ ("r13"); + + TLS_PRE_TCB_SIZE))[-1].pointer_guard \ + = THREAD_GET_POINTER_GUARD()) + +-/* tm_capable field in TCB head. */ +-# define THREAD_GET_TM_CAPABLE() \ +- (((tcbhead_t *) ((char *) __thread_register \ +- - TLS_TCB_OFFSET))[-1].tm_capable) +-# define THREAD_SET_TM_CAPABLE(value) \ +- (THREAD_GET_TM_CAPABLE () = (value)) +- + /* hwcap field in TCB head. */ + # define THREAD_GET_HWCAP() \ + (((tcbhead_t *) ((char *) __thread_register \ +diff --git a/sysdeps/powerpc/powerpc32/sysdep.h b/sysdeps/powerpc/powerpc32/sysdep.h +index 5f1294e..93097c5 100644 +--- a/sysdeps/powerpc/powerpc32/sysdep.h ++++ b/sysdeps/powerpc/powerpc32/sysdep.h +@@ -90,24 +90,7 @@ GOT_LABEL: ; \ + cfi_endproc; \ + ASM_SIZE_DIRECTIVE(name) + +-#if !IS_IN(rtld) && !defined(__SPE__) +-# define ABORT_TRANSACTION_IMPL \ +- cmpwi 2,0; \ +- beq 1f; \ +- lwz 0,TM_CAPABLE(2); \ +- cmpwi 0,0; \ +- beq 1f; \ +- li 11,_ABORT_SYSCALL; \ +- tabort. 11; \ +- .align 4; \ +-1: +-#else +-# define ABORT_TRANSACTION_IMPL +-#endif +-#define ABORT_TRANSACTION ABORT_TRANSACTION_IMPL +- + #define DO_CALL(syscall) \ +- ABORT_TRANSACTION \ + li 0,syscall; \ + sc + +diff --git a/sysdeps/powerpc/powerpc64/sysdep.h b/sysdeps/powerpc/powerpc64/sysdep.h +index 2df1d9b..50e64f9 100644 +--- a/sysdeps/powerpc/powerpc64/sysdep.h ++++ b/sysdeps/powerpc/powerpc64/sysdep.h +@@ -263,24 +263,7 @@ LT_LABELSUFFIX(name,_name_end): ; \ + TRACEBACK_MASK(name,mask); \ + END_2(name) + +-#if !IS_IN(rtld) +-# define ABORT_TRANSACTION_IMPL \ +- cmpdi 13,0; \ +- beq 1f; \ +- lwz 0,TM_CAPABLE(13); \ +- cmpwi 0,0; \ +- beq 1f; \ +- li 11,_ABORT_SYSCALL; \ +- tabort. 11; \ +- .p2align 4; \ +-1: +-#else +-# define ABORT_TRANSACTION_IMPL +-#endif +-#define ABORT_TRANSACTION ABORT_TRANSACTION_IMPL +- + #define DO_CALL(syscall) \ +- ABORT_TRANSACTION \ + li 0,syscall; \ + sc + +diff --git a/sysdeps/powerpc/sysdep.h b/sysdeps/powerpc/sysdep.h +index 8a6d236..c8bf25e 100644 +--- a/sysdeps/powerpc/sysdep.h ++++ b/sysdeps/powerpc/sysdep.h +@@ -21,8 +21,6 @@ + */ + #define _SYSDEPS_SYSDEP_H 1 + #include +-#include +-#include + + #define PPC_FEATURE_970 (PPC_FEATURE_POWER4 + PPC_FEATURE_HAS_ALTIVEC) + +@@ -166,22 +164,4 @@ + #define ALIGNARG(log2) log2 + #define ASM_SIZE_DIRECTIVE(name) .size name,.-name + +-#else +- +-/* Linux kernel powerpc documentation [1] states issuing a syscall inside a +- transaction is not recommended and may lead to undefined behavior. It +- also states syscalls do not abort transactions. To avoid such traps, +- we abort transaction just before syscalls. +- +- [1] Documentation/powerpc/transactional_memory.txt [Syscalls] */ +-#if !IS_IN(rtld) && !defined(__SPE__) +-# define ABORT_TRANSACTION \ +- ({ \ +- if (THREAD_GET_TM_CAPABLE ()) \ +- __libc_tabort (_ABORT_SYSCALL); \ +- }) +-#else +-# define ABORT_TRANSACTION +-#endif +- + #endif /* __ASSEMBLER__ */ +diff --git a/sysdeps/unix/sysv/linux/powerpc/elision-conf.c b/sysdeps/unix/sysv/linux/powerpc/elision-conf.c +index 906882a..fc82bd1 100644 +--- a/sysdeps/unix/sysv/linux/powerpc/elision-conf.c ++++ b/sysdeps/unix/sysv/linux/powerpc/elision-conf.c +@@ -127,6 +127,26 @@ elision_init (int argc __attribute__ ((unused)), + TUNABLE_CALLBACK (set_elision_skip_trylock_internal_abort)); + #endif + ++ /* Linux from 3.9 through 4.2 do not abort HTM transaction on syscalls, ++ instead it suspends the transaction and resumes it when returning to ++ usercode. The side-effects of the syscall will always remain visible, ++ even if the transaction is aborted. This is an issue when a transaction ++ is used along with futex syscall, on pthread_cond_wait for instance, ++ where futex might succeed but the transaction is rolled back leading ++ the condition variable object in an inconsistent state. ++ ++ Glibc used to prevent it by always aborting a transaction before issuing ++ a syscall. Linux 4.2 also decided to abort active transaction in ++ syscalls which makes the glibc workaround superflours. Worse, glibc ++ transaction abortions leads to a performance issues on recent kernels. ++ ++ So Lock Elision is just enabled when it has been explict set (either ++ by tunables of by a configure switch) and if kernel aborts HTM ++ transactions on syscalls (PPC_FEATURE2_HTM_NOSC) */ ++ ++ __pthread_force_elision = (__pthread_force_elision ++ && GLRO (dl_hwcap2) & PPC_FEATURE2_HTM_NOSC); ++ + if (!__pthread_force_elision) + __elision_aconf.try_tbegin = 0; /* Disable elision on rwlocks. */ + } +diff --git a/sysdeps/unix/sysv/linux/powerpc/not-errno.h b/sysdeps/unix/sysv/linux/powerpc/not-errno.h +deleted file mode 100644 +index 27da21b..0000000 +--- a/sysdeps/unix/sysv/linux/powerpc/not-errno.h ++++ /dev/null +@@ -1,30 +0,0 @@ +-/* Syscall wrapper that do not set errno. Linux powerpc version. +- 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 +- . */ +- +-/* __access_noerrno is used during process initialization in elf/dl-tunables.c +- before the TCB is initialized, prohibiting the usage of +- ABORT_TRANSACTION. */ +-#undef ABORT_TRANSACTION +-#define ABORT_TRANSACTION +- +-#include "sysdeps/unix/sysv/linux/not-errno.h" +- +-/* Recover ABORT_TRANSACTION's previous value, in order to not affect +- other syscalls. */ +-#undef ABORT_TRANSACTION +-#define ABORT_TRANSACTION ABORT_TRANSACTION_IMPL +diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/sysdep.h b/sysdeps/unix/sysv/linux/powerpc/powerpc32/sysdep.h +index f7277d5..ec5c525 100644 +--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/sysdep.h ++++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/sysdep.h +@@ -109,7 +109,6 @@ + register long int r11 __asm__ ("r11"); \ + register long int r12 __asm__ ("r12"); \ + LOADARGS_##nr(name, args); \ +- ABORT_TRANSACTION; \ + __asm__ __volatile__ \ + ("sc \n\t" \ + "mfcr %0" \ +diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/sysdep.h b/sysdeps/unix/sysv/linux/powerpc/powerpc64/sysdep.h +index 0956cf0..1f17f7b 100644 +--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/sysdep.h ++++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/sysdep.h +@@ -131,7 +131,6 @@ + register long int r7 __asm__ ("r7"); \ + register long int r8 __asm__ ("r8"); \ + LOADARGS_##nr (name, ##args); \ +- ABORT_TRANSACTION; \ + __asm__ __volatile__ \ + ("sc\n\t" \ + "mfcr %0\n\t" \ +diff --git a/sysdeps/unix/sysv/linux/powerpc/syscall.S b/sysdeps/unix/sysv/linux/powerpc/syscall.S +index 2da9172..bbab613 100644 +--- a/sysdeps/unix/sysv/linux/powerpc/syscall.S ++++ b/sysdeps/unix/sysv/linux/powerpc/syscall.S +@@ -18,7 +18,6 @@ + #include + + ENTRY (syscall) +- ABORT_TRANSACTION + mr r0,r3 + mr r3,r4 + mr r4,r5 diff --git a/SOURCES/glibc-rh1654010-1.patch b/SOURCES/glibc-rh1654010-1.patch new file mode 100644 index 0000000..b32ce03 --- /dev/null +++ b/SOURCES/glibc-rh1654010-1.patch @@ -0,0 +1,35 @@ +commit d527c860f5a3f0ed687bd03f0cb464612dc23408 +Author: Florian Weimer +Date: Tue Nov 27 16:12:43 2018 +0100 + + CVE-2018-19591: if_nametoindex: Fix descriptor for overlong name [BZ #23927] + +diff --git a/sysdeps/unix/sysv/linux/if_index.c b/sysdeps/unix/sysv/linux/if_index.c +index e3d08982d9931108..782fc5e1750e9ead 100644 +--- a/sysdeps/unix/sysv/linux/if_index.c ++++ b/sysdeps/unix/sysv/linux/if_index.c +@@ -38,11 +38,6 @@ __if_nametoindex (const char *ifname) + return 0; + #else + struct ifreq ifr; +- int fd = __opensock (); +- +- if (fd < 0) +- return 0; +- + if (strlen (ifname) >= IFNAMSIZ) + { + __set_errno (ENODEV); +@@ -50,6 +45,12 @@ __if_nametoindex (const char *ifname) + } + + strncpy (ifr.ifr_name, ifname, sizeof (ifr.ifr_name)); ++ ++ int fd = __opensock (); ++ ++ if (fd < 0) ++ return 0; ++ + if (__ioctl (fd, SIOCGIFINDEX, &ifr) < 0) + { + int saved_errno = errno; diff --git a/SOURCES/glibc-rh1654010-2.patch b/SOURCES/glibc-rh1654010-2.patch new file mode 100644 index 0000000..5e8faa2 --- /dev/null +++ b/SOURCES/glibc-rh1654010-2.patch @@ -0,0 +1,142 @@ +commit c74a91deaa5de416237c02bbb3e41bda76ca4c7b +Author: Florian Weimer +Date: Tue Nov 27 21:35:56 2018 +0100 + + support: Implement support_quote_string + + Reviewed-by: Jonathan Nieder + +diff --git a/support/Makefile b/support/Makefile +index 2b663fbbfa334ea2..a2536980d1d5a89b 100644 +--- a/support/Makefile ++++ b/support/Makefile +@@ -58,6 +58,7 @@ libsupport-routines = \ + support_openpty \ + support_paths \ + support_quote_blob \ ++ support_quote_string \ + support_record_failure \ + support_run_diff \ + support_shared_allocate \ +@@ -196,6 +197,7 @@ tests = \ + tst-support_capture_subprocess \ + tst-support_format_dns_packet \ + tst-support_quote_blob \ ++ tst-support_quote_string \ + tst-support_record_failure \ + tst-test_compare \ + tst-test_compare_blob \ +diff --git a/support/support.h b/support/support.h +index 9418cd11ef6e684d..835e7173eb566355 100644 +--- a/support/support.h ++++ b/support/support.h +@@ -69,6 +69,11 @@ void support_write_file_string (const char *path, const char *contents); + the result). */ + char *support_quote_blob (const void *blob, size_t length); + ++/* Quote the contents of the at STR, in such a way that the result ++ string can be included in a C literal (in single/double quotes, ++ without putting the quotes into the result). */ ++char *support_quote_string (const char *str); ++ + /* Returns non-zero if the file descriptor is a regular file on a file + system which supports holes (that is, seeking and writing does not + allocate storage for the range of zeros). FD must refer to a +diff --git a/support/support_quote_string.c b/support/support_quote_string.c +new file mode 100644 +index 0000000000000000..d324371b133a4d66 +--- /dev/null ++++ b/support/support_quote_string.c +@@ -0,0 +1,26 @@ ++/* Quote a string so that it can be used in C literals. ++ 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 ++ ++char * ++support_quote_string (const char *str) ++{ ++ return support_quote_blob (str, strlen (str)); ++} +diff --git a/support/tst-support_quote_string.c b/support/tst-support_quote_string.c +new file mode 100644 +index 0000000000000000..3c004759b76e21d7 +--- /dev/null ++++ b/support/tst-support_quote_string.c +@@ -0,0 +1,60 @@ ++/* Test the support_quote_string function. ++ 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 ++#include ++ ++static int ++do_test (void) ++{ ++ char *p = support_quote_string (""); ++ TEST_COMPARE (strlen (p), 0); ++ free (p); ++ p = support_quote_string ("X"); ++ TEST_COMPARE (strlen (p), 1); ++ TEST_COMPARE (p[0], 'X'); ++ free (p); ++ ++ /* Check escaping of backslash-escaped characters, and lack of ++ escaping for other shell meta-characters. */ ++ p = support_quote_string ("$()*?`@[]{}~\'\"X"); ++ TEST_COMPARE (strcmp (p, "$()*?`@[]{}~\\'\\\"X"), 0); ++ free (p); ++ ++ /* Check lack of escaping for letters and digits. */ ++#define LETTERS_AND_DIGTS \ ++ "abcdefghijklmnopqrstuvwxyz" \ ++ "ABCDEFGHIJKLMNOPQRSTUVWXYZ" \ ++ "0123456789" ++ p = support_quote_string (LETTERS_AND_DIGTS "@"); ++ TEST_COMPARE (strcmp (p, LETTERS_AND_DIGTS "@"), 0); ++ free (p); ++ ++ /* Check escaping of control characters and other non-printable ++ characters. */ ++ p = support_quote_string ("\r\n\t\a\b\f\v\1\177\200\377@"); ++ TEST_COMPARE (strcmp (p, "\\r\\n\\t\\a\\b\\f\\v\\001" ++ "\\177\\200\\377@"), 0); ++ free (p); ++ ++ return 0; ++} ++ ++#include diff --git a/SOURCES/glibc-rh1654010-3.patch b/SOURCES/glibc-rh1654010-3.patch new file mode 100644 index 0000000..d28ea27 --- /dev/null +++ b/SOURCES/glibc-rh1654010-3.patch @@ -0,0 +1,26 @@ +commit 47d8d9a2172f827a8dde7695f415aa6f78a82d0e +Author: Florian Weimer +Date: Wed Nov 28 07:00:48 2018 +0100 + + support_quote_string: Do not use str parameter name + + This avoids a build failure if this identifier is used as a macro + in a test. + +diff --git a/support/support.h b/support/support.h +index 835e7173eb566355..c3ad76901e352ee7 100644 +--- a/support/support.h ++++ b/support/support.h +@@ -69,10 +69,10 @@ void support_write_file_string (const char *path, const char *contents); + the result). */ + char *support_quote_blob (const void *blob, size_t length); + +-/* Quote the contents of the at STR, in such a way that the result ++/* Quote the contents of the string, in such a way that the result + string can be included in a C literal (in single/double quotes, + without putting the quotes into the result). */ +-char *support_quote_string (const char *str); ++char *support_quote_string (const char *); + + /* Returns non-zero if the file descriptor is a regular file on a file + system which supports holes (that is, seeking and writing does not diff --git a/SOURCES/glibc-rh1654010-4.patch b/SOURCES/glibc-rh1654010-4.patch new file mode 100644 index 0000000..709bb84 --- /dev/null +++ b/SOURCES/glibc-rh1654010-4.patch @@ -0,0 +1,32 @@ +commit 02cd5c1a8d033d7f91fea12a66bb44d1bbf85f76 +Author: Florian Weimer +Date: Sat Dec 1 21:43:36 2018 +0100 + + support: Close original descriptors in support_capture_subprocess + +diff --git a/support/support_capture_subprocess.c b/support/support_capture_subprocess.c +index 6d2029e13bd6ae73..93f6ea310290000a 100644 +--- a/support/support_capture_subprocess.c ++++ b/support/support_capture_subprocess.c +@@ -59,8 +59,12 @@ support_capture_subprocess (void (*callback) (void *), void *closure) + + int stdout_pipe[2]; + xpipe (stdout_pipe); ++ TEST_VERIFY (stdout_pipe[0] > STDERR_FILENO); ++ TEST_VERIFY (stdout_pipe[1] > STDERR_FILENO); + int stderr_pipe[2]; + xpipe (stderr_pipe); ++ TEST_VERIFY (stderr_pipe[0] > STDERR_FILENO); ++ TEST_VERIFY (stderr_pipe[1] > STDERR_FILENO); + + TEST_VERIFY (fflush (stdout) == 0); + TEST_VERIFY (fflush (stderr) == 0); +@@ -72,6 +76,8 @@ support_capture_subprocess (void (*callback) (void *), void *closure) + xclose (stderr_pipe[0]); + xdup2 (stdout_pipe[1], STDOUT_FILENO); + xdup2 (stderr_pipe[1], STDERR_FILENO); ++ xclose (stdout_pipe[1]); ++ xclose (stderr_pipe[1]); + callback (closure); + _exit (0); + } diff --git a/SOURCES/glibc-rh1654010-5.patch b/SOURCES/glibc-rh1654010-5.patch new file mode 100644 index 0000000..9dbfb9d --- /dev/null +++ b/SOURCES/glibc-rh1654010-5.patch @@ -0,0 +1,594 @@ +commit f255336a9301619519045548acb2e1027065a837 +Author: Florian Weimer +Date: Thu Dec 6 15:39:42 2018 +0100 + + support: Implement to track file descriptors + +diff --git a/support/Makefile b/support/Makefile +index a2536980d1d5a89b..93a514301654132e 100644 +--- a/support/Makefile ++++ b/support/Makefile +@@ -46,6 +46,7 @@ libsupport-routines = \ + support_chroot \ + support_copy_file_range \ + support_descriptor_supports_holes \ ++ support_descriptors \ + support_enter_mount_namespace \ + support_enter_network_namespace \ + support_format_address_family \ +@@ -195,6 +196,7 @@ tests = \ + tst-support-namespace \ + tst-support_blob_repeat \ + tst-support_capture_subprocess \ ++ tst-support_descriptors \ + tst-support_format_dns_packet \ + tst-support_quote_blob \ + tst-support_quote_string \ +diff --git a/support/check.h b/support/check.h +index e6765289f2492501..7ea9a86a9c7ed055 100644 +--- a/support/check.h ++++ b/support/check.h +@@ -183,6 +183,10 @@ int support_report_failure (int status) + /* Internal function used to test the failure recording framework. */ + void support_record_failure_reset (void); + ++/* Returns true or false depending on whether there have been test ++ failures or not. */ ++int support_record_failure_is_failed (void); ++ + __END_DECLS + + #endif /* SUPPORT_CHECK_H */ +diff --git a/support/descriptors.h b/support/descriptors.h +new file mode 100644 +index 0000000000000000..8ec4cbbdfb8f1770 +--- /dev/null ++++ b/support/descriptors.h +@@ -0,0 +1,47 @@ ++/* Monitoring file descriptor usage. ++ 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 SUPPORT_DESCRIPTORS_H ++#define SUPPORT_DESCRIPTORS_H ++ ++#include ++ ++/* Opaque pointer, for capturing file descriptor lists. */ ++struct support_descriptors; ++ ++/* Record the currently open file descriptors and store them in the ++ returned list. Terminate the process if the listing operation ++ fails. */ ++struct support_descriptors *support_descriptors_list (void); ++ ++/* Deallocate the list of descriptors. */ ++void support_descriptors_free (struct support_descriptors *); ++ ++/* Write the list of descriptors to STREAM, adding PREFIX to each ++ line. */ ++void support_descriptors_dump (struct support_descriptors *, ++ const char *prefix, FILE *stream); ++ ++/* Check for file descriptor leaks and other file descriptor changes: ++ Compare the current list of descriptors with the passed list. ++ Record a test failure if there are additional open descriptors, ++ descriptors have been closed, or if a change in file descriptor can ++ be detected. */ ++void support_descriptors_check (struct support_descriptors *); ++ ++#endif /* SUPPORT_DESCRIPTORS_H */ +diff --git a/support/support_descriptors.c b/support/support_descriptors.c +new file mode 100644 +index 0000000000000000..d66cf550800201c5 +--- /dev/null ++++ b/support/support_descriptors.c +@@ -0,0 +1,274 @@ ++/* Monitoring file descriptor usage. ++ 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 ++#include ++#include ++#include ++#include ++#include ++#include ++ ++struct procfs_descriptor ++{ ++ int fd; ++ char *link_target; ++ dev_t dev; ++ ino64_t ino; ++}; ++ ++/* Used with qsort. */ ++static int ++descriptor_compare (const void *l, const void *r) ++{ ++ const struct procfs_descriptor *left = l; ++ const struct procfs_descriptor *right = r; ++ /* Cannot overflow due to limited file descriptor range. */ ++ return left->fd - right->fd; ++} ++ ++#define DYNARRAY_STRUCT descriptor_list ++#define DYNARRAY_ELEMENT struct procfs_descriptor ++#define DYNARRAY_PREFIX descriptor_list_ ++#define DYNARRAY_ELEMENT_FREE(e) free ((e)->link_target) ++#define DYNARRAY_INITIAL_SIZE 0 ++#include ++ ++struct support_descriptors ++{ ++ struct descriptor_list list; ++}; ++ ++struct support_descriptors * ++support_descriptors_list (void) ++{ ++ struct support_descriptors *result = xmalloc (sizeof (*result)); ++ descriptor_list_init (&result->list); ++ ++ DIR *fds = opendir ("/proc/self/fd"); ++ if (fds == NULL) ++ FAIL_EXIT1 ("opendir (\"/proc/self/fd\"): %m"); ++ ++ while (true) ++ { ++ errno = 0; ++ struct dirent64 *e = readdir64 (fds); ++ if (e == NULL) ++ { ++ if (errno != 0) ++ FAIL_EXIT1 ("readdir: %m"); ++ break; ++ } ++ ++ if (e->d_name[0] == '.') ++ continue; ++ ++ char *endptr; ++ long int fd = strtol (e->d_name, &endptr, 10); ++ if (*endptr != '\0' || fd < 0 || fd > INT_MAX) ++ FAIL_EXIT1 ("readdir: invalid file descriptor name: /proc/self/fd/%s", ++ e->d_name); ++ ++ /* Skip the descriptor which is used to enumerate the ++ descriptors. */ ++ if (fd == dirfd (fds)) ++ continue; ++ ++ char *target; ++ { ++ char *path = xasprintf ("/proc/self/fd/%ld", fd); ++ target = xreadlink (path); ++ free (path); ++ } ++ struct stat64 st; ++ if (fstat64 (fd, &st) != 0) ++ FAIL_EXIT1 ("readdir: fstat64 (%ld) failed: %m", fd); ++ ++ struct procfs_descriptor *item = descriptor_list_emplace (&result->list); ++ if (item == NULL) ++ FAIL_EXIT1 ("descriptor_list_emplace: %m"); ++ item->fd = fd; ++ item->link_target = target; ++ item->dev = st.st_dev; ++ item->ino = st.st_ino; ++ } ++ ++ closedir (fds); ++ ++ /* Perform a merge join between descrs and current. This assumes ++ that the arrays are sorted by file descriptor. */ ++ ++ qsort (descriptor_list_begin (&result->list), ++ descriptor_list_size (&result->list), ++ sizeof (struct procfs_descriptor), descriptor_compare); ++ ++ return result; ++} ++ ++void ++support_descriptors_free (struct support_descriptors *descrs) ++{ ++ descriptor_list_free (&descrs->list); ++ free (descrs); ++} ++ ++void ++support_descriptors_dump (struct support_descriptors *descrs, ++ const char *prefix, FILE *fp) ++{ ++ struct procfs_descriptor *end = descriptor_list_end (&descrs->list); ++ for (struct procfs_descriptor *d = descriptor_list_begin (&descrs->list); ++ d != end; ++d) ++ { ++ char *quoted = support_quote_string (d->link_target); ++ fprintf (fp, "%s%d: target=\"%s\" major=%lld minor=%lld ino=%lld\n", ++ prefix, d->fd, quoted, ++ (long long int) major (d->dev), ++ (long long int) minor (d->dev), ++ (long long int) d->ino); ++ free (quoted); ++ } ++} ++ ++static void ++dump_mismatch (bool *first, ++ struct support_descriptors *descrs, ++ struct support_descriptors *current) ++{ ++ if (*first) ++ *first = false; ++ else ++ return; ++ ++ puts ("error: Differences found in descriptor set"); ++ puts ("Reference descriptor set:"); ++ support_descriptors_dump (descrs, " ", stdout); ++ puts ("Current descriptor set:"); ++ support_descriptors_dump (current, " ", stdout); ++ puts ("Differences:"); ++} ++ ++static void ++report_closed_descriptor (bool *first, ++ struct support_descriptors *descrs, ++ struct support_descriptors *current, ++ struct procfs_descriptor *left) ++{ ++ support_record_failure (); ++ dump_mismatch (first, descrs, current); ++ printf ("error: descriptor %d was closed\n", left->fd); ++} ++ ++static void ++report_opened_descriptor (bool *first, ++ struct support_descriptors *descrs, ++ struct support_descriptors *current, ++ struct procfs_descriptor *right) ++{ ++ support_record_failure (); ++ dump_mismatch (first, descrs, current); ++ char *quoted = support_quote_string (right->link_target); ++ printf ("error: descriptor %d was opened (\"%s\")\n", right->fd, quoted); ++ free (quoted); ++} ++ ++void ++support_descriptors_check (struct support_descriptors *descrs) ++{ ++ struct support_descriptors *current = support_descriptors_list (); ++ ++ /* Perform a merge join between descrs and current. This assumes ++ that the arrays are sorted by file descriptor. */ ++ ++ struct procfs_descriptor *left = descriptor_list_begin (&descrs->list); ++ struct procfs_descriptor *left_end = descriptor_list_end (&descrs->list); ++ struct procfs_descriptor *right = descriptor_list_begin (¤t->list); ++ struct procfs_descriptor *right_end = descriptor_list_end (¤t->list); ++ ++ bool first = true; ++ while (left != left_end && right != right_end) ++ { ++ if (left->fd == right->fd) ++ { ++ if (strcmp (left->link_target, right->link_target) != 0) ++ { ++ support_record_failure (); ++ char *left_quoted = support_quote_string (left->link_target); ++ char *right_quoted = support_quote_string (right->link_target); ++ dump_mismatch (&first, descrs, current); ++ printf ("error: descriptor %d changed from \"%s\" to \"%s\"\n", ++ left->fd, left_quoted, right_quoted); ++ free (left_quoted); ++ free (right_quoted); ++ } ++ if (left->dev != right->dev) ++ { ++ support_record_failure (); ++ dump_mismatch (&first, descrs, current); ++ printf ("error: descriptor %d changed device" ++ " from %lld:%lld to %lld:%lld\n", ++ left->fd, ++ (long long int) major (left->dev), ++ (long long int) minor (left->dev), ++ (long long int) major (right->dev), ++ (long long int) minor (right->dev)); ++ } ++ if (left->ino != right->ino) ++ { ++ support_record_failure (); ++ dump_mismatch (&first, descrs, current); ++ printf ("error: descriptor %d changed ino from %lld to %lld\n", ++ left->fd, ++ (long long int) left->ino, (long long int) right->ino); ++ } ++ ++left; ++ ++right; ++ } ++ else if (left->fd < right->fd) ++ { ++ /* Gap on the right. */ ++ report_closed_descriptor (&first, descrs, current, left); ++ ++left; ++ } ++ else ++ { ++ /* Gap on the left. */ ++ TEST_VERIFY_EXIT (left->fd > right->fd); ++ report_opened_descriptor (&first, descrs, current, right); ++ ++right; ++ } ++ } ++ ++ while (left != left_end) ++ { ++ /* Closed descriptors (more descriptors on the left). */ ++ report_closed_descriptor (&first, descrs, current, left); ++ ++left; ++ } ++ ++ while (right != right_end) ++ { ++ /* Opened descriptors (more descriptors on the right). */ ++ report_opened_descriptor (&first, descrs, current, right); ++ ++right; ++ } ++ ++ support_descriptors_free (current); ++} +diff --git a/support/support_record_failure.c b/support/support_record_failure.c +index 356798f55608ca71..17ab1d80ef2bbdea 100644 +--- a/support/support_record_failure.c ++++ b/support/support_record_failure.c +@@ -104,3 +104,11 @@ support_record_failure_reset (void) + __atomic_store_n (&state->failed, 0, __ATOMIC_RELAXED); + __atomic_add_fetch (&state->counter, 0, __ATOMIC_RELAXED); + } ++ ++int ++support_record_failure_is_failed (void) ++{ ++ /* Relaxed MO is sufficient because we need (blocking) external ++ synchronization for reliable test error reporting anyway. */ ++ return __atomic_load_n (&state->failed, __ATOMIC_RELAXED); ++} +diff --git a/support/tst-support_descriptors.c b/support/tst-support_descriptors.c +new file mode 100644 +index 0000000000000000..5e9e824bc3820499 +--- /dev/null ++++ b/support/tst-support_descriptors.c +@@ -0,0 +1,198 @@ ++/* Tests for monitoring file descriptor usage. ++ 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 ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* This is the next free descriptor that the subprocess will pick. */ ++static int free_descriptor; ++ ++static void ++subprocess_no_change (void *closure) ++{ ++ struct support_descriptors *descrs = support_descriptors_list (); ++ int fd = xopen ("/dev/null", O_WRONLY, 0); ++ TEST_COMPARE (fd, free_descriptor); ++ xclose (fd); ++ support_descriptors_free (descrs); ++} ++ ++static void ++subprocess_closed_descriptor (void *closure) ++{ ++ int fd = xopen ("/dev/null", O_WRONLY, 0); ++ TEST_COMPARE (fd, free_descriptor); ++ struct support_descriptors *descrs = support_descriptors_list (); ++ xclose (fd); ++ support_descriptors_check (descrs); /* Will report failure. */ ++ puts ("EOT"); ++ support_descriptors_free (descrs); ++} ++ ++static void ++subprocess_opened_descriptor (void *closure) ++{ ++ struct support_descriptors *descrs = support_descriptors_list (); ++ int fd = xopen ("/dev/null", O_WRONLY, 0); ++ TEST_COMPARE (fd, free_descriptor); ++ support_descriptors_check (descrs); /* Will report failure. */ ++ puts ("EOT"); ++ support_descriptors_free (descrs); ++} ++ ++static void ++subprocess_changed_descriptor (void *closure) ++{ ++ int fd = xopen ("/dev/null", O_WRONLY, 0); ++ TEST_COMPARE (fd, free_descriptor); ++ struct support_descriptors *descrs = support_descriptors_list (); ++ xclose (fd); ++ TEST_COMPARE (xopen ("/dev", O_DIRECTORY | O_RDONLY, 0), fd); ++ support_descriptors_check (descrs); /* Will report failure. */ ++ puts ("EOT"); ++ support_descriptors_free (descrs); ++} ++ ++static void ++report_subprocess_output (const char *name, ++ struct support_capture_subprocess *proc) ++{ ++ printf ("info: BEGIN %s output\n" ++ "%s" ++ "info: END %s output\n", ++ name, proc->out.buffer, name); ++} ++ ++/* Use an explicit flag to preserve failure status across ++ support_record_failure_reset calls. */ ++static bool good = true; ++ ++static void ++test_run (void) ++{ ++ struct support_capture_subprocess proc = support_capture_subprocess ++ (&subprocess_no_change, NULL); ++ support_capture_subprocess_check (&proc, "subprocess_no_change", ++ 0, sc_allow_none); ++ support_capture_subprocess_free (&proc); ++ ++ char *expected = xasprintf ("\nDifferences:\n" ++ "error: descriptor %d was closed\n" ++ "EOT\n", ++ free_descriptor); ++ good = good && !support_record_failure_is_failed (); ++ proc = support_capture_subprocess (&subprocess_closed_descriptor, NULL); ++ good = good && support_record_failure_is_failed (); ++ support_record_failure_reset (); /* Discard the reported error. */ ++ report_subprocess_output ("subprocess_closed_descriptor", &proc); ++ TEST_VERIFY (strstr (proc.out.buffer, expected) != NULL); ++ support_capture_subprocess_check (&proc, "subprocess_closed_descriptor", ++ 0, sc_allow_stdout); ++ support_capture_subprocess_free (&proc); ++ free (expected); ++ ++ expected = xasprintf ("\nDifferences:\n" ++ "error: descriptor %d was opened (\"/dev/null\")\n" ++ "EOT\n", ++ free_descriptor); ++ good = good && !support_record_failure_is_failed (); ++ proc = support_capture_subprocess (&subprocess_opened_descriptor, NULL); ++ good = good && support_record_failure_is_failed (); ++ support_record_failure_reset (); /* Discard the reported error. */ ++ report_subprocess_output ("subprocess_opened_descriptor", &proc); ++ TEST_VERIFY (strstr (proc.out.buffer, expected) != NULL); ++ support_capture_subprocess_check (&proc, "subprocess_opened_descriptor", ++ 0, sc_allow_stdout); ++ support_capture_subprocess_free (&proc); ++ free (expected); ++ ++ expected = xasprintf ("\nDifferences:\n" ++ "error: descriptor %d changed from \"/dev/null\"" ++ " to \"/dev\"\n" ++ "error: descriptor %d changed ino ", ++ free_descriptor, free_descriptor); ++ good = good && !support_record_failure_is_failed (); ++ proc = support_capture_subprocess (&subprocess_changed_descriptor, NULL); ++ good = good && support_record_failure_is_failed (); ++ support_record_failure_reset (); /* Discard the reported error. */ ++ report_subprocess_output ("subprocess_changed_descriptor", &proc); ++ TEST_VERIFY (strstr (proc.out.buffer, expected) != NULL); ++ support_capture_subprocess_check (&proc, "subprocess_changed_descriptor", ++ 0, sc_allow_stdout); ++ support_capture_subprocess_free (&proc); ++ free (expected); ++} ++ ++static int ++do_test (void) ++{ ++ puts ("info: initial descriptor set"); ++ { ++ struct support_descriptors *descrs = support_descriptors_list (); ++ support_descriptors_dump (descrs, "info: ", stdout); ++ support_descriptors_free (descrs); ++ } ++ ++ free_descriptor = xopen ("/dev/null", O_WRONLY, 0); ++ puts ("info: descriptor set with additional free descriptor"); ++ { ++ struct support_descriptors *descrs = support_descriptors_list (); ++ support_descriptors_dump (descrs, "info: ", stdout); ++ support_descriptors_free (descrs); ++ } ++ TEST_VERIFY (free_descriptor >= 3); ++ xclose (free_descriptor); ++ ++ /* Initial test run without a sentinel descriptor. The presence of ++ such a descriptor exercises different conditions in the list ++ comparison in support_descriptors_check. */ ++ test_run (); ++ ++ /* Allocate a sentinel descriptor at the end of the descriptor list, ++ after free_descriptor. */ ++ int sentinel_fd; ++ { ++ int fd = xopen ("/dev/full", O_WRONLY, 0); ++ TEST_COMPARE (fd, free_descriptor); ++ sentinel_fd = dup (fd); ++ TEST_VERIFY_EXIT (sentinel_fd > fd); ++ xclose (fd); ++ } ++ puts ("info: descriptor set with sentinel descriptor"); ++ { ++ struct support_descriptors *descrs = support_descriptors_list (); ++ support_descriptors_dump (descrs, "info: ", stdout); ++ support_descriptors_free (descrs); ++ } ++ ++ /* Second test run with sentinel descriptor. */ ++ test_run (); ++ ++ xclose (sentinel_fd); ++ ++ return !good; ++} ++ ++#include diff --git a/SOURCES/glibc-rh1654010-6.patch b/SOURCES/glibc-rh1654010-6.patch new file mode 100644 index 0000000..bf6a137 --- /dev/null +++ b/SOURCES/glibc-rh1654010-6.patch @@ -0,0 +1,86 @@ +commit 899478c2bfa00c5df8d8bedb52effbb065700278 +Author: Florian Weimer +Date: Thu Dec 6 15:39:50 2018 +0100 + + inet/tst-if_index-long: New test case for CVE-2018-19591 [BZ #23927] + +diff --git a/inet/Makefile b/inet/Makefile +index 09f5ba78fc5f3120..7782913b4c06f057 100644 +--- a/inet/Makefile ++++ b/inet/Makefile +@@ -52,7 +52,7 @@ aux := check_pf check_native ifreq + tests := htontest test_ifindex tst-ntoa tst-ether_aton tst-network \ + tst-gethnm test-ifaddrs bug-if1 test-inet6_opt tst-ether_line \ + tst-getni1 tst-getni2 tst-inet6_rth tst-checks tst-checks-posix \ +- tst-sockaddr test-hnto-types ++ tst-sockaddr test-hnto-types tst-if_index-long + + # tst-deadline must be linked statically so that we can access + # internal functions. +diff --git a/inet/tst-if_index-long.c b/inet/tst-if_index-long.c +new file mode 100644 +index 0000000000000000..3dc74874e5310945 +--- /dev/null ++++ b/inet/tst-if_index-long.c +@@ -0,0 +1,61 @@ ++/* Check for descriptor leak in if_nametoindex with a long interface name. ++ 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 ++ . */ ++ ++/* This test checks for a descriptor leak in case of a long interface ++ name (CVE-2018-19591, bug 23927). */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++static int ++do_test (void) ++{ ++ struct support_descriptors *descrs = support_descriptors_list (); ++ ++ /* Prepare a name which is just as long as required for trigging the ++ bug. */ ++ char name[IFNAMSIZ + 1]; ++ memset (name, 'A', IFNAMSIZ); ++ name[IFNAMSIZ] = '\0'; ++ TEST_COMPARE (strlen (name), IFNAMSIZ); ++ struct ifreq ifr; ++ TEST_COMPARE (strlen (name), sizeof (ifr.ifr_name)); ++ ++ /* Test directly via if_nametoindex. */ ++ TEST_COMPARE (if_nametoindex (name), 0); ++ TEST_COMPARE (errno, ENODEV); ++ support_descriptors_check (descrs); ++ ++ /* Same test via getaddrinfo. */ ++ char *host = xasprintf ("fea0::%%%s", name); ++ struct addrinfo hints = { .ai_flags = AI_NUMERICHOST, }; ++ struct addrinfo *ai; ++ TEST_COMPARE (getaddrinfo (host, NULL, &hints, &ai), EAI_NONAME); ++ support_descriptors_check (descrs); ++ ++ support_descriptors_free (descrs); ++ ++ return 0; ++} ++ ++#include diff --git a/SOURCES/glibc-rh1654872-1.patch b/SOURCES/glibc-rh1654872-1.patch new file mode 100644 index 0000000..38b6412 --- /dev/null +++ b/SOURCES/glibc-rh1654872-1.patch @@ -0,0 +1,446 @@ +commit 3d265911c2aac65d978f679101594f9071024874 +Author: Andreas Schwab +Date: Mon Nov 12 11:11:40 2018 +0100 + + Reindent nptl/pthread_rwlock_common.c + +diff --git a/nptl/pthread_rwlock_common.c b/nptl/pthread_rwlock_common.c +index a290d08332b802a5..5dd534271aed6b41 100644 +--- a/nptl/pthread_rwlock_common.c ++++ b/nptl/pthread_rwlock_common.c +@@ -34,7 +34,7 @@ + + A thread is allowed to acquire a read lock recursively (i.e., have rdlock + critical sections that overlap in sequenced-before) unless the kind of the +- rwlock is set to PTHREAD_RWLOCK_PREFER_WRITERS_NONRECURSIVE_NP. ++ rwlock is set to PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP. + + This lock is built so that workloads of mostly readers can be executed with + low runtime overheads. This matches that the default kind of the lock is +@@ -46,7 +46,7 @@ + An uncontended write lock acquisition is as fast as for a normal + exclusive mutex but writer contention is somewhat more costly due to + keeping track of the exact number of writers. If the rwlock kind requests +- writers to be preferred (i.e., PTHREAD_RWLOCK_PREFER_WRITERS_NP or the ++ writers to be preferred (i.e., PTHREAD_RWLOCK_PREFER_WRITER_NP or the + no-recursive-readers variant of it), then writer--to--writer lock ownership + hand-over is fairly fast and bypasses lock acquisition attempts by readers. + The costs of lock ownership transfer between readers and writers vary. If +@@ -251,7 +251,7 @@ __pthread_rwlock_rdunlock (pthread_rwlock_t *rwlock) + the first reader's store to __wrphase_futex (or a later value) if + the writer observes that a write phase has been started. */ + if (atomic_compare_exchange_weak_release (&rwlock->__data.__readers, +- &r, rnew)) ++ &r, rnew)) + break; + /* TODO Back-off. */ + } +@@ -285,7 +285,7 @@ __pthread_rwlock_rdlock_full (pthread_rwlock_t *rwlock, + /* Make sure we are not holding the rwlock as a writer. This is a deadlock + situation we recognize and report. */ + if (__glibc_unlikely (atomic_load_relaxed (&rwlock->__data.__cur_writer) +- == THREAD_GETMEM (THREAD_SELF, tid))) ++ == THREAD_GETMEM (THREAD_SELF, tid))) + return EDEADLK; + + /* If we prefer writers, recursive rdlock is disallowed, we are in a read +@@ -299,9 +299,9 @@ __pthread_rwlock_rdlock_full (pthread_rwlock_t *rwlock, + if (rwlock->__data.__flags == PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP) + { + r = atomic_load_relaxed (&rwlock->__data.__readers); +- while (((r & PTHREAD_RWLOCK_WRPHASE) == 0) +- && ((r & PTHREAD_RWLOCK_WRLOCKED) != 0) +- && ((r >> PTHREAD_RWLOCK_READER_SHIFT) > 0)) ++ while ((r & PTHREAD_RWLOCK_WRPHASE) == 0 ++ && (r & PTHREAD_RWLOCK_WRLOCKED) != 0 ++ && (r >> PTHREAD_RWLOCK_READER_SHIFT) > 0) + { + /* TODO Spin first. */ + /* Try setting the flag signaling that we are waiting without having +@@ -315,11 +315,11 @@ __pthread_rwlock_rdlock_full (pthread_rwlock_t *rwlock, + __readers, and all threads set the flag under the same + conditions. */ + while ((atomic_load_relaxed (&rwlock->__data.__readers) +- & PTHREAD_RWLOCK_RWAITING) != 0) ++ & PTHREAD_RWLOCK_RWAITING) != 0) + { + int private = __pthread_rwlock_get_private (rwlock); + int err = futex_abstimed_wait (&rwlock->__data.__readers, +- r, abstime, private); ++ r, abstime, private); + /* We ignore EAGAIN and EINTR. On time-outs, we can just + return because we don't need to clean up anything. */ + if (err == ETIMEDOUT) +@@ -338,8 +338,9 @@ __pthread_rwlock_rdlock_full (pthread_rwlock_t *rwlock, + expected value for future operations. Acquire MO so we synchronize with + prior writers as well as the last reader of the previous read phase (see + below). */ +- r = atomic_fetch_add_acquire (&rwlock->__data.__readers, +- (1 << PTHREAD_RWLOCK_READER_SHIFT)) + (1 << PTHREAD_RWLOCK_READER_SHIFT); ++ r = (atomic_fetch_add_acquire (&rwlock->__data.__readers, ++ (1 << PTHREAD_RWLOCK_READER_SHIFT)) ++ + (1 << PTHREAD_RWLOCK_READER_SHIFT)); + + /* Check whether there is an overflow in the number of readers. We assume + that the total number of threads is less than half the maximum number +@@ -359,8 +360,9 @@ __pthread_rwlock_rdlock_full (pthread_rwlock_t *rwlock, + /* Relaxed MO is okay because we just want to undo our registration and + cannot have changed the rwlock state substantially if the CAS + succeeds. */ +- if (atomic_compare_exchange_weak_relaxed (&rwlock->__data.__readers, &r, +- r - (1 << PTHREAD_RWLOCK_READER_SHIFT))) ++ if (atomic_compare_exchange_weak_relaxed ++ (&rwlock->__data.__readers, ++ &r, r - (1 << PTHREAD_RWLOCK_READER_SHIFT))) + return EAGAIN; + } + +@@ -378,15 +380,15 @@ __pthread_rwlock_rdlock_full (pthread_rwlock_t *rwlock, + /* Otherwise, if we were in a write phase (states #6 or #8), we must wait + for explicit hand-over of the read phase; the only exception is if we + can start a read phase if there is no primary writer currently. */ +- while (((r & PTHREAD_RWLOCK_WRPHASE) != 0) +- && ((r & PTHREAD_RWLOCK_WRLOCKED) == 0)) ++ while ((r & PTHREAD_RWLOCK_WRPHASE) != 0 ++ && (r & PTHREAD_RWLOCK_WRLOCKED) == 0) + { +- /* Try to enter a read phase: If the CAS below succeeds, we have ++ /* Try to enter a read phase: If the CAS below succeeds, we have + ownership; if it fails, we will simply retry and reassess the + situation. + Acquire MO so we synchronize with prior writers. */ + if (atomic_compare_exchange_weak_acquire (&rwlock->__data.__readers, &r, +- r ^ PTHREAD_RWLOCK_WRPHASE)) ++ r ^ PTHREAD_RWLOCK_WRPHASE)) + { + /* We started the read phase, so we are also responsible for + updating the write-phase futex. Relaxed MO is sufficient. +@@ -397,7 +399,7 @@ __pthread_rwlock_rdlock_full (pthread_rwlock_t *rwlock, + (but we can pretend to do the setting and unsetting of WRLOCKED + atomically, and thus can skip this step). */ + if ((atomic_exchange_relaxed (&rwlock->__data.__wrphase_futex, 0) +- & PTHREAD_RWLOCK_FUTEX_USED) != 0) ++ & PTHREAD_RWLOCK_FUTEX_USED) != 0) + { + int private = __pthread_rwlock_get_private (rwlock); + futex_wake (&rwlock->__data.__wrphase_futex, INT_MAX, private); +@@ -435,16 +437,17 @@ __pthread_rwlock_rdlock_full (pthread_rwlock_t *rwlock, + for (;;) + { + while (((wpf = atomic_load_relaxed (&rwlock->__data.__wrphase_futex)) +- | PTHREAD_RWLOCK_FUTEX_USED) == (1 | PTHREAD_RWLOCK_FUTEX_USED)) ++ | PTHREAD_RWLOCK_FUTEX_USED) == (1 | PTHREAD_RWLOCK_FUTEX_USED)) + { + int private = __pthread_rwlock_get_private (rwlock); + if (((wpf & PTHREAD_RWLOCK_FUTEX_USED) == 0) +- && !atomic_compare_exchange_weak_relaxed ++ && (!atomic_compare_exchange_weak_relaxed + (&rwlock->__data.__wrphase_futex, +- &wpf, wpf | PTHREAD_RWLOCK_FUTEX_USED)) ++ &wpf, wpf | PTHREAD_RWLOCK_FUTEX_USED))) + continue; + int err = futex_abstimed_wait (&rwlock->__data.__wrphase_futex, +- 1 | PTHREAD_RWLOCK_FUTEX_USED, abstime, private); ++ 1 | PTHREAD_RWLOCK_FUTEX_USED, ++ abstime, private); + if (err == ETIMEDOUT) + { + /* If we timed out, we need to unregister. If no read phase +@@ -477,8 +480,8 @@ __pthread_rwlock_rdlock_full (pthread_rwlock_t *rwlock, + in this case and thus make the spin-waiting we need + unnecessarily expensive. */ + while ((atomic_load_relaxed (&rwlock->__data.__wrphase_futex) +- | PTHREAD_RWLOCK_FUTEX_USED) +- == (1 | PTHREAD_RWLOCK_FUTEX_USED)) ++ | PTHREAD_RWLOCK_FUTEX_USED) ++ == (1 | PTHREAD_RWLOCK_FUTEX_USED)) + { + /* TODO Back-off? */ + } +@@ -495,7 +498,7 @@ __pthread_rwlock_rdlock_full (pthread_rwlock_t *rwlock, + release of the writer, and so that we observe a recent value of + __wrphase_futex (see below). */ + if ((atomic_load_acquire (&rwlock->__data.__readers) +- & PTHREAD_RWLOCK_WRPHASE) == 0) ++ & PTHREAD_RWLOCK_WRPHASE) == 0) + /* We are in a read phase now, so the least recent modification of + __wrphase_futex we can read from is the store by the writer + with value 1. Thus, only now we can assume that if we observe +@@ -516,8 +519,9 @@ __pthread_rwlock_wrunlock (pthread_rwlock_t *rwlock) + atomic_store_relaxed (&rwlock->__data.__cur_writer, 0); + /* Disable waiting by writers. We will wake up after we decided how to + proceed. */ +- bool wake_writers = ((atomic_exchange_relaxed +- (&rwlock->__data.__writers_futex, 0) & PTHREAD_RWLOCK_FUTEX_USED) != 0); ++ bool wake_writers ++ = ((atomic_exchange_relaxed (&rwlock->__data.__writers_futex, 0) ++ & PTHREAD_RWLOCK_FUTEX_USED) != 0); + + if (rwlock->__data.__flags != PTHREAD_RWLOCK_PREFER_READER_NP) + { +@@ -529,8 +533,8 @@ __pthread_rwlock_wrunlock (pthread_rwlock_t *rwlock) + synchronize with us and thus can take over our view of + __readers (including, for example, whether we are in a write + phase or not). */ +- if (atomic_compare_exchange_weak_release (&rwlock->__data.__writers, +- &w, w | PTHREAD_RWLOCK_WRHANDOVER)) ++ if (atomic_compare_exchange_weak_release ++ (&rwlock->__data.__writers, &w, w | PTHREAD_RWLOCK_WRHANDOVER)) + /* Another writer will take over. */ + goto done; + /* TODO Back-off. */ +@@ -543,9 +547,10 @@ __pthread_rwlock_wrunlock (pthread_rwlock_t *rwlock) + unsigned int r = atomic_load_relaxed (&rwlock->__data.__readers); + /* Release MO so that subsequent readers or writers synchronize with us. */ + while (!atomic_compare_exchange_weak_release +- (&rwlock->__data.__readers, &r, (r ^ PTHREAD_RWLOCK_WRLOCKED) +- ^ ((r >> PTHREAD_RWLOCK_READER_SHIFT) == 0 ? 0 +- : PTHREAD_RWLOCK_WRPHASE))) ++ (&rwlock->__data.__readers, &r, ++ ((r ^ PTHREAD_RWLOCK_WRLOCKED) ++ ^ ((r >> PTHREAD_RWLOCK_READER_SHIFT) == 0 ? 0 ++ : PTHREAD_RWLOCK_WRPHASE)))) + { + /* TODO Back-off. */ + } +@@ -574,7 +579,7 @@ __pthread_rwlock_wrlock_full (pthread_rwlock_t *rwlock, + /* Make sure we are not holding the rwlock as a writer. This is a deadlock + situation we recognize and report. */ + if (__glibc_unlikely (atomic_load_relaxed (&rwlock->__data.__cur_writer) +- == THREAD_GETMEM (THREAD_SELF, tid))) ++ == THREAD_GETMEM (THREAD_SELF, tid))) + return EDEADLK; + + /* First we try to acquire the role of primary writer by setting WRLOCKED; +@@ -593,12 +598,12 @@ __pthread_rwlock_wrlock_full (pthread_rwlock_t *rwlock, + this could be less scalable if readers arrive and leave frequently. */ + bool may_share_futex_used_flag = false; + unsigned int r = atomic_fetch_or_acquire (&rwlock->__data.__readers, +- PTHREAD_RWLOCK_WRLOCKED); ++ PTHREAD_RWLOCK_WRLOCKED); + if (__glibc_unlikely ((r & PTHREAD_RWLOCK_WRLOCKED) != 0)) + { + /* There is another primary writer. */ +- bool prefer_writer = +- (rwlock->__data.__flags != PTHREAD_RWLOCK_PREFER_READER_NP); ++ bool prefer_writer ++ = (rwlock->__data.__flags != PTHREAD_RWLOCK_PREFER_READER_NP); + if (prefer_writer) + { + /* We register as a waiting writer, so that we can make use of +@@ -617,8 +622,7 @@ __pthread_rwlock_wrlock_full (pthread_rwlock_t *rwlock, + /* Try to become the primary writer or retry. Acquire MO as in + the fetch_or above. */ + if (atomic_compare_exchange_weak_acquire +- (&rwlock->__data.__readers, &r, +- r | PTHREAD_RWLOCK_WRLOCKED)) ++ (&rwlock->__data.__readers, &r, r | PTHREAD_RWLOCK_WRLOCKED)) + { + if (prefer_writer) + { +@@ -633,8 +637,7 @@ __pthread_rwlock_wrlock_full (pthread_rwlock_t *rwlock, + __writers). + ??? Perhaps this is not strictly necessary for + reasons we do not yet know of. */ +- atomic_fetch_add_relaxed (&rwlock->__data.__writers, +- -1); ++ atomic_fetch_add_relaxed (&rwlock->__data.__writers, -1); + } + break; + } +@@ -646,8 +649,7 @@ __pthread_rwlock_wrlock_full (pthread_rwlock_t *rwlock, + succeed, we own WRLOCKED. */ + if (prefer_writer) + { +- unsigned int w = atomic_load_relaxed +- (&rwlock->__data.__writers); ++ unsigned int w = atomic_load_relaxed (&rwlock->__data.__writers); + if ((w & PTHREAD_RWLOCK_WRHANDOVER) != 0) + { + /* Acquire MO is required here so that we synchronize with +@@ -677,13 +679,13 @@ __pthread_rwlock_wrlock_full (pthread_rwlock_t *rwlock, + /* We did not acquire WRLOCKED nor were able to use writer--writer + hand-over, so we block on __writers_futex. */ + int private = __pthread_rwlock_get_private (rwlock); +- unsigned int wf = atomic_load_relaxed +- (&rwlock->__data.__writers_futex); ++ unsigned int wf ++ = atomic_load_relaxed (&rwlock->__data.__writers_futex); + if (((wf & ~(unsigned int) PTHREAD_RWLOCK_FUTEX_USED) != 1) + || ((wf != (1 | PTHREAD_RWLOCK_FUTEX_USED)) +- && !atomic_compare_exchange_weak_relaxed ++ && (!atomic_compare_exchange_weak_relaxed + (&rwlock->__data.__writers_futex, &wf, +- 1 | PTHREAD_RWLOCK_FUTEX_USED))) ++ 1 | PTHREAD_RWLOCK_FUTEX_USED)))) + { + /* If we cannot block on __writers_futex because there is no + primary writer, or we cannot set PTHREAD_RWLOCK_FUTEX_USED, +@@ -704,7 +706,8 @@ __pthread_rwlock_wrlock_full (pthread_rwlock_t *rwlock, + in this group. */ + may_share_futex_used_flag = true; + int err = futex_abstimed_wait (&rwlock->__data.__writers_futex, +- 1 | PTHREAD_RWLOCK_FUTEX_USED, abstime, private); ++ 1 | PTHREAD_RWLOCK_FUTEX_USED, ++ abstime, private); + if (err == ETIMEDOUT) + { + if (prefer_writer) +@@ -716,10 +719,10 @@ __pthread_rwlock_wrlock_full (pthread_rwlock_t *rwlock, + that this happened before the timeout; see + pthread_rwlock_rdlock_full for the full reasoning.) + Also see the similar code above. */ +- unsigned int w = atomic_load_relaxed +- (&rwlock->__data.__writers); ++ unsigned int w ++ = atomic_load_relaxed (&rwlock->__data.__writers); + while (!atomic_compare_exchange_weak_acquire +- (&rwlock->__data.__writers, &w, ++ (&rwlock->__data.__writers, &w, + (w == PTHREAD_RWLOCK_WRHANDOVER + 1 ? 0 : w - 1))) + { + /* TODO Back-off. */ +@@ -751,7 +754,8 @@ __pthread_rwlock_wrlock_full (pthread_rwlock_t *rwlock, + modifications of __readers ensures that this store happens after the + store of value 0 by the previous primary writer. */ + atomic_store_relaxed (&rwlock->__data.__writers_futex, +- 1 | (may_share_futex_used_flag ? PTHREAD_RWLOCK_FUTEX_USED : 0)); ++ 1 | (may_share_futex_used_flag ++ ? PTHREAD_RWLOCK_FUTEX_USED : 0)); + + /* If we are in a write phase, we have acquired the lock. */ + if ((r & PTHREAD_RWLOCK_WRPHASE) != 0) +@@ -759,15 +763,15 @@ __pthread_rwlock_wrlock_full (pthread_rwlock_t *rwlock, + + /* If we are in a read phase and there are no readers, try to start a write + phase. */ +- while (((r & PTHREAD_RWLOCK_WRPHASE) == 0) +- && ((r >> PTHREAD_RWLOCK_READER_SHIFT) == 0)) ++ while ((r & PTHREAD_RWLOCK_WRPHASE) == 0 ++ && (r >> PTHREAD_RWLOCK_READER_SHIFT) == 0) + { + /* Acquire MO so that we synchronize with prior writers and do + not interfere with their updates to __writers_futex, as well + as regarding prior readers and their updates to __wrphase_futex, + respectively. */ + if (atomic_compare_exchange_weak_acquire (&rwlock->__data.__readers, +- &r, r | PTHREAD_RWLOCK_WRPHASE)) ++ &r, r | PTHREAD_RWLOCK_WRPHASE)) + { + /* We have started a write phase, so need to enable readers to wait. + See the similar case in __pthread_rwlock_rdlock_full. Unlike in +@@ -792,24 +796,24 @@ __pthread_rwlock_wrlock_full (pthread_rwlock_t *rwlock, + for (;;) + { + while (((wpf = atomic_load_relaxed (&rwlock->__data.__wrphase_futex)) +- | PTHREAD_RWLOCK_FUTEX_USED) == PTHREAD_RWLOCK_FUTEX_USED) ++ | PTHREAD_RWLOCK_FUTEX_USED) == PTHREAD_RWLOCK_FUTEX_USED) + { + int private = __pthread_rwlock_get_private (rwlock); +- if (((wpf & PTHREAD_RWLOCK_FUTEX_USED) == 0) +- && !atomic_compare_exchange_weak_relaxed ++ if ((wpf & PTHREAD_RWLOCK_FUTEX_USED) == 0 ++ && (!atomic_compare_exchange_weak_relaxed + (&rwlock->__data.__wrphase_futex, &wpf, +- PTHREAD_RWLOCK_FUTEX_USED)) ++ PTHREAD_RWLOCK_FUTEX_USED))) + continue; + int err = futex_abstimed_wait (&rwlock->__data.__wrphase_futex, +- PTHREAD_RWLOCK_FUTEX_USED, abstime, private); ++ PTHREAD_RWLOCK_FUTEX_USED, ++ abstime, private); + if (err == ETIMEDOUT) + { +- if (rwlock->__data.__flags +- != PTHREAD_RWLOCK_PREFER_READER_NP) ++ if (rwlock->__data.__flags != PTHREAD_RWLOCK_PREFER_READER_NP) + { + /* We try writer--writer hand-over. */ +- unsigned int w = atomic_load_relaxed +- (&rwlock->__data.__writers); ++ unsigned int w ++ = atomic_load_relaxed (&rwlock->__data.__writers); + if (w != 0) + { + /* We are about to hand over WRLOCKED, so we must +@@ -823,13 +827,13 @@ __pthread_rwlock_wrlock_full (pthread_rwlock_t *rwlock, + Release MO so that another writer that gets + WRLOCKED from us can take over our view of + __readers. */ +- unsigned int wf = atomic_exchange_relaxed +- (&rwlock->__data.__writers_futex, 0); ++ unsigned int wf ++ = atomic_exchange_relaxed (&rwlock->__data.__writers_futex, 0); + while (w != 0) + { + if (atomic_compare_exchange_weak_release + (&rwlock->__data.__writers, &w, +- w | PTHREAD_RWLOCK_WRHANDOVER)) ++ w | PTHREAD_RWLOCK_WRHANDOVER)) + { + /* Wake other writers. */ + if ((wf & PTHREAD_RWLOCK_FUTEX_USED) != 0) +@@ -844,8 +848,7 @@ __pthread_rwlock_wrlock_full (pthread_rwlock_t *rwlock, + again. Make sure we don't loose the flag that + signals whether there are threads waiting on + this futex. */ +- atomic_store_relaxed +- (&rwlock->__data.__writers_futex, wf); ++ atomic_store_relaxed (&rwlock->__data.__writers_futex, wf); + } + } + /* If we timed out and we are not in a write phase, we can +@@ -857,8 +860,8 @@ __pthread_rwlock_wrlock_full (pthread_rwlock_t *rwlock, + /* We are about to release WRLOCKED, so we must release + __writers_futex too; see the handling of + writer--writer hand-over above. */ +- unsigned int wf = atomic_exchange_relaxed +- (&rwlock->__data.__writers_futex, 0); ++ unsigned int wf ++ = atomic_exchange_relaxed (&rwlock->__data.__writers_futex, 0); + while ((r & PTHREAD_RWLOCK_WRPHASE) == 0) + { + /* While we don't need to make anything from a +@@ -877,11 +880,11 @@ __pthread_rwlock_wrlock_full (pthread_rwlock_t *rwlock, + /* Wake other writers. */ + if ((wf & PTHREAD_RWLOCK_FUTEX_USED) != 0) + futex_wake (&rwlock->__data.__writers_futex, +- 1, private); ++ 1, private); + /* Wake waiting readers. */ + if ((r & PTHREAD_RWLOCK_RWAITING) != 0) + futex_wake (&rwlock->__data.__readers, +- INT_MAX, private); ++ INT_MAX, private); + return ETIMEDOUT; + } + } +@@ -898,10 +901,9 @@ __pthread_rwlock_wrlock_full (pthread_rwlock_t *rwlock, + atomic_thread_fence_acquire (); + /* We still need to wait for explicit hand-over, but we must + not use futex_wait anymore. */ +- while ((atomic_load_relaxed +- (&rwlock->__data.__wrphase_futex) +- | PTHREAD_RWLOCK_FUTEX_USED) +- == PTHREAD_RWLOCK_FUTEX_USED) ++ while ((atomic_load_relaxed (&rwlock->__data.__wrphase_futex) ++ | PTHREAD_RWLOCK_FUTEX_USED) ++ == PTHREAD_RWLOCK_FUTEX_USED) + { + /* TODO Back-off. */ + } +@@ -915,12 +917,12 @@ __pthread_rwlock_wrlock_full (pthread_rwlock_t *rwlock, + if (ready) + break; + if ((atomic_load_acquire (&rwlock->__data.__readers) +- & PTHREAD_RWLOCK_WRPHASE) != 0) ++ & PTHREAD_RWLOCK_WRPHASE) != 0) + ready = true; + } + + done: + atomic_store_relaxed (&rwlock->__data.__cur_writer, +- THREAD_GETMEM (THREAD_SELF, tid)); ++ THREAD_GETMEM (THREAD_SELF, tid)); + return 0; + } diff --git a/SOURCES/glibc-rh1654872-2.patch b/SOURCES/glibc-rh1654872-2.patch new file mode 100644 index 0000000..04c40ee --- /dev/null +++ b/SOURCES/glibc-rh1654872-2.patch @@ -0,0 +1,134 @@ +commit f21e8f8ca466320fed38bdb71526c574dae98026 +Author: Andreas Schwab +Date: Thu Nov 8 14:28:22 2018 +0100 + + Fix rwlock stall with PREFER_WRITER_NONRECURSIVE_NP (bug 23861) + + In the read lock function (__pthread_rwlock_rdlock_full) there was a + code path which would fail to reload __readers while waiting for + PTHREAD_RWLOCK_RWAITING to change. This failure to reload __readers + into a local value meant that various conditionals used the old value + of __readers and with only two threads left it could result in an + indefinite stall of one of the readers (waiting for PTHREAD_RWLOCK_RWAITING + to go to zero, but it never would). + +diff --git a/nptl/Makefile b/nptl/Makefile +index ee720960d18f33d1..2d2db648f730db61 100644 +--- a/nptl/Makefile ++++ b/nptl/Makefile +@@ -318,7 +318,8 @@ tests = tst-attr1 tst-attr2 tst-attr3 tst-default-attr \ + tst-minstack-throw \ + tst-cnd-basic tst-mtx-trylock tst-cnd-broadcast \ + tst-cnd-timedwait tst-thrd-detach tst-mtx-basic tst-thrd-sleep \ +- tst-mtx-recursive tst-tss-basic tst-call-once tst-mtx-timedlock ++ tst-mtx-recursive tst-tss-basic tst-call-once tst-mtx-timedlock \ ++ tst-rwlock-pwn + + tests-internal := tst-rwlock19 tst-rwlock20 \ + tst-sem11 tst-sem12 tst-sem13 \ +diff --git a/nptl/pthread_rwlock_common.c b/nptl/pthread_rwlock_common.c +index 5dd534271aed6b41..85fc1bcfc7f5e60d 100644 +--- a/nptl/pthread_rwlock_common.c ++++ b/nptl/pthread_rwlock_common.c +@@ -314,7 +314,7 @@ __pthread_rwlock_rdlock_full (pthread_rwlock_t *rwlock, + harmless because the flag is just about the state of + __readers, and all threads set the flag under the same + conditions. */ +- while ((atomic_load_relaxed (&rwlock->__data.__readers) ++ while (((r = atomic_load_relaxed (&rwlock->__data.__readers)) + & PTHREAD_RWLOCK_RWAITING) != 0) + { + int private = __pthread_rwlock_get_private (rwlock); +diff --git a/nptl/tst-rwlock-pwn.c b/nptl/tst-rwlock-pwn.c +new file mode 100644 +index 0000000000000000..c39dd70973f1a76e +--- /dev/null ++++ b/nptl/tst-rwlock-pwn.c +@@ -0,0 +1,87 @@ ++/* Test rwlock with PREFER_WRITER_NONRECURSIVE_NP (bug 23861). ++ 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 ++#include ++#include ++ ++/* We choose 10 iterations because this happens to be able to trigger the ++ stall on contemporary hardware. */ ++#define LOOPS 10 ++/* We need 3 threads to trigger bug 23861. One thread as a writer, and ++ two reader threads. The test verifies that the second-to-last reader ++ is able to notify the *last* reader that it should be done waiting. ++ If the second-to-last reader fails to notify the last reader or does ++ so incorrectly then the last reader may stall indefinitely. */ ++#define NTHREADS 3 ++ ++_Atomic int do_exit; ++pthread_rwlockattr_t mylock_attr; ++pthread_rwlock_t mylock; ++ ++void * ++run_loop (void *a) ++{ ++ while (!do_exit) ++ { ++ if (random () & 1) ++ { ++ xpthread_rwlock_wrlock (&mylock); ++ xpthread_rwlock_unlock (&mylock); ++ } ++ else ++ { ++ xpthread_rwlock_rdlock (&mylock); ++ xpthread_rwlock_unlock (&mylock); ++ } ++ } ++ return NULL; ++} ++ ++int ++do_test (void) ++{ ++ xpthread_rwlockattr_init (&mylock_attr); ++ xpthread_rwlockattr_setkind_np (&mylock_attr, ++ PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP); ++ xpthread_rwlock_init (&mylock, &mylock_attr); ++ ++ for (int n = 0; n < LOOPS; n++) ++ { ++ pthread_t tids[NTHREADS]; ++ do_exit = 0; ++ for (int i = 0; i < NTHREADS; i++) ++ tids[i] = xpthread_create (NULL, run_loop, NULL); ++ /* Let the threads run for some time. */ ++ sleep (1); ++ printf ("Exiting..."); ++ fflush (stdout); ++ do_exit = 1; ++ for (int i = 0; i < NTHREADS; i++) ++ xpthread_join (tids[i]); ++ printf ("done.\n"); ++ } ++ pthread_rwlock_destroy (&mylock); ++ pthread_rwlockattr_destroy (&mylock_attr); ++ return 0; ++} ++ ++#define TIMEOUT (DEFAULT_TIMEOUT + 3 * LOOPS) ++#include diff --git a/SOURCES/glibc-rh1658901.patch b/SOURCES/glibc-rh1658901.patch new file mode 100644 index 0000000..59d7cab --- /dev/null +++ b/SOURCES/glibc-rh1658901.patch @@ -0,0 +1,140 @@ +Upstream commit 1d880d4a9bf7608c2cd33bbe954ce6995f79121a + +From: Tulio Magno Quites Machado Filho +Date: Wed, 12 Dec 2018 12:41:52 +0000 (-0200) +Subject: powerpc: Add missing CFI register information (bug #23614) +X-Git-Tag: glibc-2.29~210 +X-Git-Url: https://sourceware.org/git/?p=glibc.git;a=commitdiff_plain;h=1d880d4a9bf7608c2cd33bbe954ce6995f79121a + +powerpc: Add missing CFI register information (bug #23614) + +Add CFI information about the offset of registers stored in the stack +frame. + + [BZ #23614] + * sysdeps/powerpc/powerpc64/addmul_1.S (FUNC): Add CFI offset for + registers saved in the stack frame. + * sysdeps/powerpc/powerpc64/lshift.S (__mpn_lshift): Likewise. + * sysdeps/powerpc/powerpc64/mul_1.S (__mpn_mul_1): Likewise. + +Signed-off-by: Tulio Magno Quites Machado Filho +Reviewed-by: Gabriel F. T. Gomes +--- + +diff --git a/sysdeps/powerpc/powerpc64/addmul_1.S b/sysdeps/powerpc/powerpc64/addmul_1.S +index 48e3b1b..e450d6a 100644 +--- a/sysdeps/powerpc/powerpc64/addmul_1.S ++++ b/sysdeps/powerpc/powerpc64/addmul_1.S +@@ -34,16 +34,27 @@ + #define N r5 + #define VL r6 + ++#define R27SAVE (-40) ++#define R28SAVE (-32) ++#define R29SAVE (-24) ++#define R30SAVE (-16) ++#define R31SAVE (-8) ++ + ENTRY_TOCLESS (FUNC, 5) +- std r31, -8(r1) ++ std r31, R31SAVE(r1) + rldicl. r0, N, 0, 62 +- std r30, -16(r1) ++ std r30, R30SAVE(r1) + cmpdi VL, r0, 2 +- std r29, -24(r1) ++ std r29, R29SAVE(r1) + addi N, N, 3 +- std r28, -32(r1) ++ std r28, R28SAVE(r1) + srdi N, N, 2 +- std r27, -40(r1) ++ std r27, R27SAVE(r1) ++ cfi_offset(r31, R31SAVE) ++ cfi_offset(r30, R30SAVE) ++ cfi_offset(r29, R29SAVE) ++ cfi_offset(r28, R28SAVE) ++ cfi_offset(r27, R27SAVE) + mtctr N + beq cr0, L(b00) + blt cr6, L(b01) +@@ -199,10 +210,10 @@ L(end): mulld r0, r9, VL + addic r11, r11, 1 + #endif + addze RP, r8 +- ld r31, -8(r1) +- ld r30, -16(r1) +- ld r29, -24(r1) +- ld r28, -32(r1) +- ld r27, -40(r1) ++ ld r31, R31SAVE(r1) ++ ld r30, R30SAVE(r1) ++ ld r29, R29SAVE(r1) ++ ld r28, R28SAVE(r1) ++ ld r27, R27SAVE(r1) + blr + END(FUNC) +diff --git a/sysdeps/powerpc/powerpc64/lshift.S b/sysdeps/powerpc/powerpc64/lshift.S +index 8b6396e..855d6f2 100644 +--- a/sysdeps/powerpc/powerpc64/lshift.S ++++ b/sysdeps/powerpc/powerpc64/lshift.S +@@ -26,11 +26,15 @@ + #define TNC r0 + #define U0 r30 + #define U1 r31 ++#define U0SAVE (-16) ++#define U1SAVE (-8) + #define RETVAL r5 + + ENTRY_TOCLESS (__mpn_lshift, 5) +- std U1, -8(r1) +- std U0, -16(r1) ++ std U1, U1SAVE(r1) ++ std U0, U0SAVE(r1) ++ cfi_offset(U1, U1SAVE) ++ cfi_offset(U0, U0SAVE) + subfic TNC, CNT, 64 + sldi r7, N, RP + add UP, UP, r7 +@@ -170,8 +174,8 @@ L(cj3): or r10, r12, r7 + L(cj2): std r10, -32(RP) + std r8, -40(RP) + +-L(ret): ld U1, -8(r1) +- ld U0, -16(r1) ++L(ret): ld U1, U1SAVE(r1) ++ ld U0, U0SAVE(r1) + mr RP, RETVAL + blr + END(__mpn_lshift) +diff --git a/sysdeps/powerpc/powerpc64/mul_1.S b/sysdeps/powerpc/powerpc64/mul_1.S +index 953ded8..cade365 100644 +--- a/sysdeps/powerpc/powerpc64/mul_1.S ++++ b/sysdeps/powerpc/powerpc64/mul_1.S +@@ -24,9 +24,14 @@ + #define N r5 + #define VL r6 + ++#define R26SAVE (-48) ++#define R27SAVE (-40) ++ + ENTRY_TOCLESS (__mpn_mul_1, 5) +- std r27, -40(r1) +- std r26, -48(r1) ++ std r27, R27SAVE(r1) ++ std r26, R26SAVE(r1) ++ cfi_offset(r27, R27SAVE) ++ cfi_offset(r26, R26SAVE) + li r12, 0 + ld r26, 0(UP) + +@@ -129,7 +134,7 @@ L(end): mulld r0, r26, VL + std r0, 0(RP) + std r7, 8(RP) + L(ret): addze RP, r8 +- ld r27, -40(r1) +- ld r26, -48(r1) ++ ld r27, R27SAVE(r1) ++ ld r26, R26SAVE(r1) + blr + END(__mpn_mul_1) diff --git a/SOURCES/glibc-rh1659293-1.patch b/SOURCES/glibc-rh1659293-1.patch new file mode 100644 index 0000000..cf8ca21 --- /dev/null +++ b/SOURCES/glibc-rh1659293-1.patch @@ -0,0 +1,663 @@ +nptl: Fix pthread_rwlock_try*lock stalls (Bug 23844) + +For a full analysis of both the pthread_rwlock_tryrdlock() stall +and the pthread_rwlock_trywrlock() stall see: +https://sourceware.org/bugzilla/show_bug.cgi?id=23844#c14 + +In the pthread_rwlock_trydlock() function we fail to inspect for +PTHREAD_RWLOCK_FUTEX_USED in __wrphase_futex and wake the waiting +readers. + +In the pthread_rwlock_trywrlock() function we write 1 to +__wrphase_futex and loose the setting of the PTHREAD_RWLOCK_FUTEX_USED +bit, again failing to wake waiting readers during unlock. + +The fix in the case of pthread_rwlock_trydlock() is to check for +PTHREAD_RWLOCK_FUTEX_USED and wake the readers. + +The fix in the case of pthread_rwlock_trywrlock() is to only write +1 to __wrphase_futex if we installed the write phase, since all other +readers would be spinning waiting for this step. + +We add two new tests, one exercises the stall for +pthread_rwlock_trywrlock() which is easy to exercise, and one exercises +the stall for pthread_rwlock_trydlock() which is harder to exercise. + +The pthread_rwlock_trywrlock() test fails consistently without the fix, +and passes after. The pthread_rwlock_tryrdlock() test fails roughly +5-10% of the time without the fix, and passes all the time after. + +Signed-off-by: Carlos O'Donell +Signed-off-by: Torvald Riegel +Signed-off-by: Rik Prohaska +Co-authored-by: Torvald Riegel +Co-authored-by: Rik Prohaska +(cherry picked from commit 5fc9ed4c4058bfbdf51ad6e7aac7d209b580e8c4) + +diff --git a/ChangeLog b/ChangeLog +index 08b42bd2f56471e3..ed1a2ffe8356fd96 100644 +--- a/ChangeLog ++++ b/ChangeLog +@@ -1,3 +1,20 @@ ++2019-01-31 Carlos O'Donell ++ Torvald Riegel ++ Rik Prohaska ++ ++ [BZ# 23844] ++ * nptl/Makefile (tests): Add tst-rwlock-tryrdlock-stall, and ++ tst-rwlock-trywrlock-stall. ++ * nptl/pthread_rwlock_tryrdlock.c (__pthread_rwlock_tryrdlock): ++ Wake waiters if PTHREAD_RWLOCK_FUTEX_USED is set. ++ * nptl/pthread_rwlock_trywrlock.c (__pthread_rwlock_trywrlock): ++ Set __wrphase_fute to 1 only if we started the write phase. ++ * nptl/tst-rwlock-tryrdlock-stall.c: New file. ++ * nptl/tst-rwlock-trywrlock-stall.c: New file. ++ * support/Makefile (libsupport-routines): Add xpthread_rwlock_destroy. ++ * support/xpthread_rwlock_destroy.c: New file. ++ * support/xthread.h: Declare xpthread_rwlock_destroy. ++ + 2018-08-01 Carlos O'Donel + + * version.h (RELEASE): Set to "stable". +diff --git a/nptl/Makefile b/nptl/Makefile +index 2d2db648f730db61..b1003cf56b31ddfa 100644 +--- a/nptl/Makefile ++++ b/nptl/Makefile +@@ -319,7 +319,8 @@ tests = tst-attr1 tst-attr2 tst-attr3 tst-default-attr \ + tst-cnd-basic tst-mtx-trylock tst-cnd-broadcast \ + tst-cnd-timedwait tst-thrd-detach tst-mtx-basic tst-thrd-sleep \ + tst-mtx-recursive tst-tss-basic tst-call-once tst-mtx-timedlock \ +- tst-rwlock-pwn ++ tst-rwlock-pwn \ ++ tst-rwlock-tryrdlock-stall tst-rwlock-trywrlock-stall + + tests-internal := tst-rwlock19 tst-rwlock20 \ + tst-sem11 tst-sem12 tst-sem13 \ +diff --git a/nptl/pthread_rwlock_tryrdlock.c b/nptl/pthread_rwlock_tryrdlock.c +index 4aec1fc15acb2448..31a88d33a6e8f256 100644 +--- a/nptl/pthread_rwlock_tryrdlock.c ++++ b/nptl/pthread_rwlock_tryrdlock.c +@@ -94,15 +94,22 @@ __pthread_rwlock_tryrdlock (pthread_rwlock_t *rwlock) + /* Same as in __pthread_rwlock_rdlock_full: + We started the read phase, so we are also responsible for + updating the write-phase futex. Relaxed MO is sufficient. +- Note that there can be no other reader that we have to wake +- because all other readers will see the read phase started by us +- (or they will try to start it themselves); if a writer started +- the read phase, we cannot have started it. Furthermore, we +- cannot discard a PTHREAD_RWLOCK_FUTEX_USED flag because we will +- overwrite the value set by the most recent writer (or the readers +- before it in case of explicit hand-over) and we know that there +- are no waiting readers. */ +- atomic_store_relaxed (&rwlock->__data.__wrphase_futex, 0); ++ We have to do the same steps as a writer would when handing over the ++ read phase to use because other readers cannot distinguish between ++ us and the writer. ++ Note that __pthread_rwlock_tryrdlock callers will not have to be ++ woken up because they will either see the read phase started by us ++ or they will try to start it themselves; however, callers of ++ __pthread_rwlock_rdlock_full just increase the reader count and then ++ check what state the lock is in, so they cannot distinguish between ++ us and a writer that acquired and released the lock in the ++ meantime. */ ++ if ((atomic_exchange_relaxed (&rwlock->__data.__wrphase_futex, 0) ++ & PTHREAD_RWLOCK_FUTEX_USED) != 0) ++ { ++ int private = __pthread_rwlock_get_private (rwlock); ++ futex_wake (&rwlock->__data.__wrphase_futex, INT_MAX, private); ++ } + } + + return 0; +diff --git a/nptl/pthread_rwlock_trywrlock.c b/nptl/pthread_rwlock_trywrlock.c +index 5a73eba756077297..f2e3443466a2554f 100644 +--- a/nptl/pthread_rwlock_trywrlock.c ++++ b/nptl/pthread_rwlock_trywrlock.c +@@ -46,8 +46,15 @@ __pthread_rwlock_trywrlock (pthread_rwlock_t *rwlock) + &rwlock->__data.__readers, &r, + r | PTHREAD_RWLOCK_WRPHASE | PTHREAD_RWLOCK_WRLOCKED)) + { ++ /* We have become the primary writer and we cannot have shared ++ the PTHREAD_RWLOCK_FUTEX_USED flag with someone else, so we ++ can simply enable blocking (see full wrlock code). */ + atomic_store_relaxed (&rwlock->__data.__writers_futex, 1); +- atomic_store_relaxed (&rwlock->__data.__wrphase_futex, 1); ++ /* If we started a write phase, we need to enable readers to ++ wait. If we did not, we must not change it because other threads ++ may have set the PTHREAD_RWLOCK_FUTEX_USED in the meantime. */ ++ if ((r & PTHREAD_RWLOCK_WRPHASE) == 0) ++ atomic_store_relaxed (&rwlock->__data.__wrphase_futex, 1); + atomic_store_relaxed (&rwlock->__data.__cur_writer, + THREAD_GETMEM (THREAD_SELF, tid)); + return 0; +diff --git a/nptl/tst-rwlock-tryrdlock-stall.c b/nptl/tst-rwlock-tryrdlock-stall.c +new file mode 100644 +index 0000000000000000..5e476da2b8d00c6a +--- /dev/null ++++ b/nptl/tst-rwlock-tryrdlock-stall.c +@@ -0,0 +1,355 @@ ++/* Bug 23844: Test for pthread_rwlock_tryrdlock stalls. ++ 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, see ++ . */ ++ ++/* For a full analysis see comment: ++ https://sourceware.org/bugzilla/show_bug.cgi?id=23844#c14 ++ ++ Provided here for reference: ++ ++ --- Analysis of pthread_rwlock_tryrdlock() stall --- ++ A read lock begins to execute. ++ ++ In __pthread_rwlock_rdlock_full: ++ ++ We can attempt a read lock, but find that the lock is ++ in a write phase (PTHREAD_RWLOCK_WRPHASE, or WP-bit ++ is set), and the lock is held by a primary writer ++ (PTHREAD_RWLOCK_WRLOCKED is set). In this case we must ++ wait for explicit hand over from the writer to us or ++ one of the other waiters. The read lock threads are ++ about to execute: ++ ++ 341 r = (atomic_fetch_add_acquire (&rwlock->__data.__readers, ++ 342 (1 << PTHREAD_RWLOCK_READER_SHIFT)) ++ 343 + (1 << PTHREAD_RWLOCK_READER_SHIFT)); ++ ++ An unlock beings to execute. ++ ++ Then in __pthread_rwlock_wrunlock: ++ ++ 547 unsigned int r = atomic_load_relaxed (&rwlock->__data.__readers); ++ ... ++ 549 while (!atomic_compare_exchange_weak_release ++ 550 (&rwlock->__data.__readers, &r, ++ 551 ((r ^ PTHREAD_RWLOCK_WRLOCKED) ++ 552 ^ ((r >> PTHREAD_RWLOCK_READER_SHIFT) == 0 ? 0 ++ 553 : PTHREAD_RWLOCK_WRPHASE)))) ++ 554 { ++ ... ++ 556 } ++ ++ We clear PTHREAD_RWLOCK_WRLOCKED, and if there are ++ no readers so we leave the lock in PTHRAD_RWLOCK_WRPHASE. ++ ++ Back in the read lock. ++ ++ The read lock adjusts __readres as above. ++ ++ 383 while ((r & PTHREAD_RWLOCK_WRPHASE) != 0 ++ 384 && (r & PTHREAD_RWLOCK_WRLOCKED) == 0) ++ 385 { ++ ... ++ 390 if (atomic_compare_exchange_weak_acquire (&rwlock->__data.__readers, &r, ++ 391 r ^ PTHREAD_RWLOCK_WRPHASE)) ++ 392 { ++ ++ And then attemps to start the read phase. ++ ++ Assume there happens to be a tryrdlock at this point, noting ++ that PTHREAD_RWLOCK_WRLOCKED is clear, and PTHREAD_RWLOCK_WRPHASE ++ is 1. So the try lock attemps to start the read phase. ++ ++ In __pthread_rwlock_tryrdlock: ++ ++ 44 if ((r & PTHREAD_RWLOCK_WRPHASE) == 0) ++ 45 { ++ ... ++ 49 if (((r & PTHREAD_RWLOCK_WRLOCKED) != 0) ++ 50 && (rwlock->__data.__flags ++ 51 == PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP)) ++ 52 return EBUSY; ++ 53 rnew = r + (1 << PTHREAD_RWLOCK_READER_SHIFT); ++ 54 } ++ ... ++ 89 while (!atomic_compare_exchange_weak_acquire (&rwlock->__data.__readers, ++ 90 &r, rnew)); ++ ++ And succeeds. ++ ++ Back in the write unlock: ++ ++ 557 if ((r >> PTHREAD_RWLOCK_READER_SHIFT) != 0) ++ 558 { ++ ... ++ 563 if ((atomic_exchange_relaxed (&rwlock->__data.__wrphase_futex, 0) ++ 564 & PTHREAD_RWLOCK_FUTEX_USED) != 0) ++ 565 futex_wake (&rwlock->__data.__wrphase_futex, INT_MAX, private); ++ 566 } ++ ++ We note that PTHREAD_RWLOCK_FUTEX_USED is non-zero ++ and don't wake anyone. This is OK because we handed ++ over to the trylock. It will be the trylock's responsibility ++ to wake any waiters. ++ ++ Back in the read lock: ++ ++ The read lock fails to install PTHRAD_REWLOCK_WRPHASE as 0 because ++ the __readers value was adjusted by the trylock, and so it falls through ++ to waiting on the lock for explicit handover from either a new writer ++ or a new reader. ++ ++ 448 int err = futex_abstimed_wait (&rwlock->__data.__wrphase_futex, ++ 449 1 | PTHREAD_RWLOCK_FUTEX_USED, ++ 450 abstime, private); ++ ++ We use PTHREAD_RWLOCK_FUTEX_USED to indicate the futex ++ is in use. ++ ++ At this point we have readers waiting on the read lock ++ to unlock. The wrlock is done. The trylock is finishing ++ the installation of the read phase. ++ ++ 92 if ((r & PTHREAD_RWLOCK_WRPHASE) != 0) ++ 93 { ++ ... ++ 105 atomic_store_relaxed (&rwlock->__data.__wrphase_futex, 0); ++ 106 } ++ ++ The trylock does note that we were the one that ++ installed the read phase, but the comments are not ++ correct, the execution ordering above shows that ++ readers might indeed be waiting, and they are. ++ ++ The atomic_store_relaxed throws away PTHREAD_RWLOCK_FUTEX_USED, ++ and the waiting reader is never worken becuase as noted ++ above it is conditional on the futex being used. ++ ++ The solution is for the trylock thread to inspect ++ PTHREAD_RWLOCK_FUTEX_USED and wake the waiting readers. ++ ++ --- Analysis of pthread_rwlock_trywrlock() stall --- ++ ++ A write lock begins to execute, takes the write lock, ++ and then releases the lock... ++ ++ In pthread_rwlock_wrunlock(): ++ ++ 547 unsigned int r = atomic_load_relaxed (&rwlock->__data.__readers); ++ ... ++ 549 while (!atomic_compare_exchange_weak_release ++ 550 (&rwlock->__data.__readers, &r, ++ 551 ((r ^ PTHREAD_RWLOCK_WRLOCKED) ++ 552 ^ ((r >> PTHREAD_RWLOCK_READER_SHIFT) == 0 ? 0 ++ 553 : PTHREAD_RWLOCK_WRPHASE)))) ++ 554 { ++ ... ++ 556 } ++ ++ ... leaving it in the write phase with zero readers ++ (the case where we leave the write phase in place ++ during a write unlock). ++ ++ A write trylock begins to execute. ++ ++ In __pthread_rwlock_trywrlock: ++ ++ 40 while (((r & PTHREAD_RWLOCK_WRLOCKED) == 0) ++ 41 && (((r >> PTHREAD_RWLOCK_READER_SHIFT) == 0) ++ 42 || (prefer_writer && ((r & PTHREAD_RWLOCK_WRPHASE) != 0)))) ++ 43 { ++ ++ The lock is not locked. ++ ++ There are no readers. ++ ++ 45 if (atomic_compare_exchange_weak_acquire ( ++ 46 &rwlock->__data.__readers, &r, ++ 47 r | PTHREAD_RWLOCK_WRPHASE | PTHREAD_RWLOCK_WRLOCKED)) ++ ++ We atomically install the write phase and we take the ++ exclusive write lock. ++ ++ 48 { ++ 49 atomic_store_relaxed (&rwlock->__data.__writers_futex, 1); ++ ++ We get this far. ++ ++ A reader lock begins to execute. ++ ++ In pthread_rwlock_rdlock: ++ ++ 437 for (;;) ++ 438 { ++ 439 while (((wpf = atomic_load_relaxed (&rwlock->__data.__wrphase_futex)) ++ 440 | PTHREAD_RWLOCK_FUTEX_USED) == (1 | PTHREAD_RWLOCK_FUTEX_USED)) ++ 441 { ++ 442 int private = __pthread_rwlock_get_private (rwlock); ++ 443 if (((wpf & PTHREAD_RWLOCK_FUTEX_USED) == 0) ++ 444 && (!atomic_compare_exchange_weak_relaxed ++ 445 (&rwlock->__data.__wrphase_futex, ++ 446 &wpf, wpf | PTHREAD_RWLOCK_FUTEX_USED))) ++ 447 continue; ++ 448 int err = futex_abstimed_wait (&rwlock->__data.__wrphase_futex, ++ 449 1 | PTHREAD_RWLOCK_FUTEX_USED, ++ 450 abstime, private); ++ ++ We are in a write phase, so the while() on line 439 is true. ++ ++ The value of wpf does not have PTHREAD_RWLOCK_FUTEX_USED set ++ since this is the first reader to lock. ++ ++ The atomic operation sets wpf with PTHREAD_RELOCK_FUTEX_USED ++ on the expectation that this reader will be woken during ++ the handoff. ++ ++ Back in pthread_rwlock_trywrlock: ++ ++ 50 atomic_store_relaxed (&rwlock->__data.__wrphase_futex, 1); ++ 51 atomic_store_relaxed (&rwlock->__data.__cur_writer, ++ 52 THREAD_GETMEM (THREAD_SELF, tid)); ++ 53 return 0; ++ 54 } ++ ... ++ 57 } ++ ++ We write 1 to __wrphase_futex discarding PTHREAD_RWLOCK_FUTEX_USED, ++ and so in the unlock we will not awaken the waiting reader. ++ ++ The solution to this is to realize that if we did not start the write ++ phase we need not write 1 or any other value to __wrphase_futex. ++ This ensures that any readers (which saw __wrphase_futex != 0) can ++ set PTHREAD_RWLOCK_FUTEX_USED and this can be used at unlock to ++ wake them. ++ ++ If we installed the write phase then all other readers are looping ++ here: ++ ++ In __pthread_rwlock_rdlock_full: ++ ++ 437 for (;;) ++ 438 { ++ 439 while (((wpf = atomic_load_relaxed (&rwlock->__data.__wrphase_futex)) ++ 440 | PTHREAD_RWLOCK_FUTEX_USED) == (1 | PTHREAD_RWLOCK_FUTEX_USED)) ++ 441 { ++ ... ++ 508 } ++ ++ waiting for the write phase to be installed or removed before they ++ can begin waiting on __wrphase_futex (part of the algorithm), or ++ taking a concurrent read lock, and thus we can safely write 1 to ++ __wrphase_futex. ++ ++ If we did not install the write phase then the readers may already ++ be waiting on the futex, the original writer wrote 1 to __wrphase_futex ++ as part of starting the write phase, and we cannot also write 1 ++ without loosing the PTHREAD_RWLOCK_FUTEX_USED bit. ++ ++ --- ++ ++ Summary for the pthread_rwlock_tryrdlock() stall: ++ ++ The stall is caused by pthread_rwlock_tryrdlock failing to check ++ that PTHREAD_RWLOCK_FUTEX_USED is set in the __wrphase_futex futex ++ and then waking the futex. ++ ++ The fix for bug 23844 ensures that waiters on __wrphase_futex are ++ correctly woken. Before the fix the test stalls as readers can ++ wait forever on __wrphase_futex. */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* We need only one lock to reproduce the issue. We will need multiple ++ threads to get the exact case where we have a read, try, and unlock ++ all interleaving to produce the case where the readers are waiting ++ and the try fails to wake them. */ ++pthread_rwlock_t onelock; ++ ++/* The number of threads is arbitrary but empirically chosen to have ++ enough threads that we see the condition where waiting readers are ++ not woken by a successful tryrdlock. */ ++#define NTHREADS 32 ++ ++_Atomic int do_exit; ++ ++void * ++run_loop (void *arg) ++{ ++ int i = 0, ret; ++ while (!do_exit) ++ { ++ /* Arbitrarily choose if we are the writer or reader. Choose a ++ high enough ratio of readers to writers to make it likely ++ that readers block (and eventually are susceptable to ++ stalling). ++ ++ If we are a writer, take the write lock, and then unlock. ++ If we are a reader, try the lock, then lock, then unlock. */ ++ if ((i % 8) != 0) ++ xpthread_rwlock_wrlock (&onelock); ++ else ++ { ++ if ((ret = pthread_rwlock_tryrdlock (&onelock)) != 0) ++ { ++ if (ret == EBUSY) ++ xpthread_rwlock_rdlock (&onelock); ++ else ++ exit (EXIT_FAILURE); ++ } ++ } ++ /* Thread does some work and then unlocks. */ ++ xpthread_rwlock_unlock (&onelock); ++ i++; ++ } ++ return NULL; ++} ++ ++int ++do_test (void) ++{ ++ int i; ++ pthread_t tids[NTHREADS]; ++ xpthread_rwlock_init (&onelock, NULL); ++ for (i = 0; i < NTHREADS; i++) ++ tids[i] = xpthread_create (NULL, run_loop, NULL); ++ /* Run for some amount of time. Empirically speaking exercising ++ the stall via pthread_rwlock_tryrdlock is much harder, and on ++ a 3.5GHz 4 core x86_64 VM system it takes somewhere around ++ 20-200s to stall, approaching 100% stall past 200s. We can't ++ wait that long for a regression test so we just test for 20s, ++ and expect the stall to happen with a 5-10% chance (enough for ++ developers to see). */ ++ sleep (20); ++ /* Then exit. */ ++ printf ("INFO: Exiting...\n"); ++ do_exit = 1; ++ /* If any readers stalled then we will timeout waiting for them. */ ++ for (i = 0; i < NTHREADS; i++) ++ xpthread_join (tids[i]); ++ printf ("INFO: Done.\n"); ++ xpthread_rwlock_destroy (&onelock); ++ printf ("PASS: No pthread_rwlock_tryrdlock stalls detected.\n"); ++ return 0; ++} ++ ++#define TIMEOUT 30 ++#include +diff --git a/nptl/tst-rwlock-trywrlock-stall.c b/nptl/tst-rwlock-trywrlock-stall.c +new file mode 100644 +index 0000000000000000..14d27cbcbc882cb1 +--- /dev/null ++++ b/nptl/tst-rwlock-trywrlock-stall.c +@@ -0,0 +1,108 @@ ++/* Bug 23844: Test for pthread_rwlock_trywrlock stalls. ++ 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, see ++ . */ ++ ++/* For a full analysis see comments in tst-rwlock-tryrdlock-stall.c. ++ ++ Summary for the pthread_rwlock_trywrlock() stall: ++ ++ The stall is caused by pthread_rwlock_trywrlock setting ++ __wrphase_futex futex to 1 and loosing the ++ PTHREAD_RWLOCK_FUTEX_USED bit. ++ ++ The fix for bug 23844 ensures that waiters on __wrphase_futex are ++ correctly woken. Before the fix the test stalls as readers can ++ wait forever on __wrphase_futex. */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* We need only one lock to reproduce the issue. We will need multiple ++ threads to get the exact case where we have a read, try, and unlock ++ all interleaving to produce the case where the readers are waiting ++ and the try clears the PTHREAD_RWLOCK_FUTEX_USED bit and a ++ subsequent unlock fails to wake them. */ ++pthread_rwlock_t onelock; ++ ++/* The number of threads is arbitrary but empirically chosen to have ++ enough threads that we see the condition where waiting readers are ++ not woken by a successful unlock. */ ++#define NTHREADS 32 ++ ++_Atomic int do_exit; ++ ++void * ++run_loop (void *arg) ++{ ++ int i = 0, ret; ++ while (!do_exit) ++ { ++ /* Arbitrarily choose if we are the writer or reader. Choose a ++ high enough ratio of readers to writers to make it likely ++ that readers block (and eventually are susceptable to ++ stalling). ++ ++ If we are a writer, take the write lock, and then unlock. ++ If we are a reader, try the lock, then lock, then unlock. */ ++ if ((i % 8) != 0) ++ { ++ if ((ret = pthread_rwlock_trywrlock (&onelock)) != 0) ++ { ++ if (ret == EBUSY) ++ xpthread_rwlock_wrlock (&onelock); ++ else ++ exit (EXIT_FAILURE); ++ } ++ } ++ else ++ xpthread_rwlock_rdlock (&onelock); ++ /* Thread does some work and then unlocks. */ ++ xpthread_rwlock_unlock (&onelock); ++ i++; ++ } ++ return NULL; ++} ++ ++int ++do_test (void) ++{ ++ int i; ++ pthread_t tids[NTHREADS]; ++ xpthread_rwlock_init (&onelock, NULL); ++ for (i = 0; i < NTHREADS; i++) ++ tids[i] = xpthread_create (NULL, run_loop, NULL); ++ /* Run for some amount of time. The pthread_rwlock_tryrwlock stall ++ is very easy to trigger and happens in seconds under the test ++ conditions. */ ++ sleep (10); ++ /* Then exit. */ ++ printf ("INFO: Exiting...\n"); ++ do_exit = 1; ++ /* If any readers stalled then we will timeout waiting for them. */ ++ for (i = 0; i < NTHREADS; i++) ++ xpthread_join (tids[i]); ++ printf ("INFO: Done.\n"); ++ xpthread_rwlock_destroy (&onelock); ++ printf ("PASS: No pthread_rwlock_tryrwlock stalls detected.\n"); ++ return 0; ++} ++ ++#include +diff --git a/support/Makefile b/support/Makefile +index 93a514301654132e..41da4abaaa5a645a 100644 +--- a/support/Makefile ++++ b/support/Makefile +@@ -129,6 +129,7 @@ libsupport-routines = \ + xpthread_mutexattr_settype \ + xpthread_once \ + xpthread_rwlock_init \ ++ xpthread_rwlock_destroy \ + xpthread_rwlock_rdlock \ + xpthread_rwlock_unlock \ + xpthread_rwlock_wrlock \ +diff --git a/support/xpthread_rwlock_destroy.c b/support/xpthread_rwlock_destroy.c +new file mode 100644 +index 0000000000000000..6d6e95356963b47f +--- /dev/null ++++ b/support/xpthread_rwlock_destroy.c +@@ -0,0 +1,26 @@ ++/* pthread_rwlock_destroy with error checking. ++ 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, see ++ . */ ++ ++#include ++ ++void ++xpthread_rwlock_destroy (pthread_rwlock_t *rwlock) ++{ ++ xpthread_check_return ("pthread_rwlock_destroy", ++ pthread_rwlock_destroy (rwlock)); ++} +diff --git a/support/xthread.h b/support/xthread.h +index 623f5ad0acb895ef..1af77280871464c2 100644 +--- a/support/xthread.h ++++ b/support/xthread.h +@@ -84,6 +84,7 @@ void xpthread_rwlockattr_setkind_np (pthread_rwlockattr_t *attr, int pref); + void xpthread_rwlock_wrlock (pthread_rwlock_t *rwlock); + void xpthread_rwlock_rdlock (pthread_rwlock_t *rwlock); + void xpthread_rwlock_unlock (pthread_rwlock_t *rwlock); ++void xpthread_rwlock_destroy (pthread_rwlock_t *rwlock); + + __END_DECLS + diff --git a/SOURCES/glibc-rh1659293-2.patch b/SOURCES/glibc-rh1659293-2.patch new file mode 100644 index 0000000..eca43d2 --- /dev/null +++ b/SOURCES/glibc-rh1659293-2.patch @@ -0,0 +1,61 @@ +nptl/tst-rwlock14: Test pthread_rwlock_timedwrlock correctly + +(cherry picked from commit 82849fde3b8cb9b9396fa8cadf842dc2b1d2cced) + +diff --git a/ChangeLog b/ChangeLog +index ed1a2ffe8356fd96..74e634670c62d5c2 100644 +--- a/ChangeLog ++++ b/ChangeLog +@@ -1,3 +1,10 @@ ++2019-03-25 Mike Crowe ++ ++ * nptl/tst-rwlock14.c (do_test): Replace duplicate calls to ++ pthread_rwlock_timedrdlock with calls to ++ pthread_rwlock_timedwrlock to ensure that the latter is tested ++ too. Use new function name in diagnostic messages too. ++ + 2019-01-31 Carlos O'Donell + Torvald Riegel + Rik Prohaska +diff --git a/nptl/tst-rwlock14.c b/nptl/tst-rwlock14.c +index d6fda87c61e9aed4..073e6c98d2f5cc12 100644 +--- a/nptl/tst-rwlock14.c ++++ b/nptl/tst-rwlock14.c +@@ -117,15 +117,15 @@ do_test (void) + result = 1; + } + +- e = pthread_rwlock_timedrdlock (&r, &ts); ++ e = pthread_rwlock_timedwrlock (&r, &ts); + if (e == 0) + { +- puts ("second rwlock_timedrdlock did not fail"); ++ puts ("second rwlock_timedwrlock did not fail"); + result = 1; + } + else if (e != EINVAL) + { +- puts ("second rwlock_timedrdlock did not return EINVAL"); ++ puts ("second rwlock_timedwrlock did not return EINVAL"); + result = 1; + } + +@@ -145,15 +145,15 @@ do_test (void) + result = 1; + } + +- e = pthread_rwlock_timedrdlock (&r, &ts); ++ e = pthread_rwlock_timedwrlock (&r, &ts); + if (e == 0) + { +- puts ("third rwlock_timedrdlock did not fail"); ++ puts ("third rwlock_timedwrlock did not fail"); + result = 1; + } + else if (e != EINVAL) + { +- puts ("third rwlock_timedrdlock did not return EINVAL"); ++ puts ("third rwlock_timedwrlock did not return EINVAL"); + result = 1; + } + diff --git a/SOURCES/glibc-rh1659438-1.patch b/SOURCES/glibc-rh1659438-1.patch new file mode 100644 index 0000000..6e22946 --- /dev/null +++ b/SOURCES/glibc-rh1659438-1.patch @@ -0,0 +1,118 @@ +commit b8686c0d7098168481a246f8199ab2d865f52d3d +Author: Stefan Liebler +Date: Tue Dec 18 13:57:03 2018 +0100 + + S390: Add configure check to detect z10 as mininum architecture level set. + + Add a configure check for z10 in the same way as done for z196. + + ChangeLog: + + * config.h.in (HAVE_S390_MIN_Z10_ZARCH_ASM_SUPPORT): New undefine. + * sysdeps/s390/configure.ac: Add check for z10 support. + * sysdeps/s390/configure: Regenerated. + +diff --git a/config.h.in b/config.h.in +index 141db213a9046eb4..beecc39d5b8c3f4a 100644 +--- a/config.h.in ++++ b/config.h.in +@@ -62,6 +62,9 @@ + /* Define if assembler supports AVX512DQ. */ + #undef HAVE_AVX512DQ_ASM_SUPPORT + ++/* Define if assembler supports z10 zarch instructions as default on S390. */ ++#undef HAVE_S390_MIN_Z10_ZARCH_ASM_SUPPORT ++ + /* Define if assembler supports z196 zarch instructions as default on S390. */ + #undef HAVE_S390_MIN_Z196_ZARCH_ASM_SUPPORT + +diff --git a/sysdeps/s390/configure b/sysdeps/s390/configure +index 74b415f2ab0fa982..f30f8644361f474a 100644 +--- a/sysdeps/s390/configure ++++ b/sysdeps/s390/configure +@@ -112,6 +112,45 @@ then + + fi + ++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for S390 z10 zarch instruction support as default" >&5 ++$as_echo_n "checking for S390 z10 zarch instruction support as default... " >&6; } ++if ${libc_cv_asm_s390_min_z10_zarch+:} false; then : ++ $as_echo_n "(cached) " >&6 ++else ++ cat > conftest.c <<\EOF ++void testinsn (void *a, void *b, int n) ++{ ++ __asm__ ("exrl %2,1f \n\t" ++ "j 2f \n\t" ++ "1: mvc 0(1,%0),0(%1) \n\t" ++ "2:" ++ : : "a" (a), "a" (b), "d" (n) ++ : "memory", "cc"); ++} ++EOF ++if { ac_try='${CC-cc} $CFLAGS $CPPFLAGS $LDFLAGS --shared conftest.c ++ -o conftest.o &> /dev/null' ++ { { 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; }; } ; ++then ++ libc_cv_asm_s390_min_z10_zarch=yes ++else ++ libc_cv_asm_s390_min_z10_zarch=no ++fi ++rm -f conftest* ++fi ++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libc_cv_asm_s390_min_z10_zarch" >&5 ++$as_echo "$libc_cv_asm_s390_min_z10_zarch" >&6; } ++ ++if test "$libc_cv_asm_s390_min_z10_zarch" = yes ; ++then ++ $as_echo "#define HAVE_S390_MIN_Z10_ZARCH_ASM_SUPPORT 1" >>confdefs.h ++ ++fi ++ + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for S390 z196 zarch instruction support as default" >&5 + $as_echo_n "checking for S390 z196 zarch instruction support as default... " >&6; } + if ${libc_cv_asm_s390_min_z196_zarch+:} false; then : +diff --git a/sysdeps/s390/configure.ac b/sysdeps/s390/configure.ac +index 1cdb0212825a3f18..981f7a79dd7066fc 100644 +--- a/sysdeps/s390/configure.ac ++++ b/sysdeps/s390/configure.ac +@@ -80,6 +80,35 @@ then + AC_DEFINE(HAVE_S390_VX_GCC_SUPPORT) + fi + ++AC_CACHE_CHECK(for S390 z10 zarch instruction support as default, ++ libc_cv_asm_s390_min_z10_zarch, [dnl ++cat > conftest.c <<\EOF ++void testinsn (void *a, void *b, int n) ++{ ++ __asm__ ("exrl %2,1f \n\t" ++ "j 2f \n\t" ++ "1: mvc 0(1,%0),0(%1) \n\t" ++ "2:" ++ : : "a" (a), "a" (b), "d" (n) ++ : "memory", "cc"); ++} ++EOF ++dnl ++dnl test, if assembler supports S390 z10 zarch instructions as default ++if AC_TRY_COMMAND([${CC-cc} $CFLAGS $CPPFLAGS $LDFLAGS --shared conftest.c ++ -o conftest.o &> /dev/null]) ; ++then ++ libc_cv_asm_s390_min_z10_zarch=yes ++else ++ libc_cv_asm_s390_min_z10_zarch=no ++fi ++rm -f conftest* ]) ++ ++if test "$libc_cv_asm_s390_min_z10_zarch" = yes ; ++then ++ AC_DEFINE(HAVE_S390_MIN_Z10_ZARCH_ASM_SUPPORT) ++fi ++ + AC_CACHE_CHECK(for S390 z196 zarch instruction support as default, + libc_cv_asm_s390_min_z196_zarch, [dnl + cat > conftest.c <<\EOF diff --git a/SOURCES/glibc-rh1659438-10.patch b/SOURCES/glibc-rh1659438-10.patch new file mode 100644 index 0000000..729f1b5 --- /dev/null +++ b/SOURCES/glibc-rh1659438-10.patch @@ -0,0 +1,189 @@ +commit e099aab060df178a7fcd5a55282650fe45ccea66 +Author: Stefan Liebler +Date: Tue Dec 18 13:57:07 2018 +0100 + + S390: Remove s390 specific implementation of bcopy. + + Nowadays gcc is automatically replacing a call to bcopy + with a call to memmove. Thus only old binaries will call + the s390 specific bcopy implementation. + + The s390 specific implementation is using an own + implementation for memcpy in the forward case and is + relying on memmove in the backward case. + + After removing the s390 specific bcopy, the common code + bcopy is used. It just performs a tail call to memmove. + + ChangeLog: + * sysdeps/s390/s390-32/bcopy.S: Remove. + * sysdeps/s390/s390-64/bcopy.S: Likewise. + +diff --git a/sysdeps/s390/s390-32/bcopy.S b/sysdeps/s390/s390-32/bcopy.S +deleted file mode 100644 +index 560e04fdee93dafb..0000000000000000 +--- a/sysdeps/s390/s390-32/bcopy.S ++++ /dev/null +@@ -1,85 +0,0 @@ +-/* bcopy -- copy a block from source to destination. S/390 version. +- This file is part of the GNU C Library. +- Copyright (C) 2000-2018 Free Software Foundation, Inc. +- Contributed by Martin Schwidefsky (schwidefsky@de.ibm.com). +- +- The GNU C Library is free software; you can redistribute it and/or +- modify it under the terms of the GNU Lesser General Public +- License as published by the Free Software Foundation; either +- version 2.1 of the License, or (at your option) any later version. +- +- The GNU C Library is distributed in the hope that it will be useful, +- but WITHOUT ANY WARRANTY; without even the implied warranty of +- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +- Lesser General Public License for more details. +- +- You should have received a copy of the GNU Lesser General Public +- License along with the GNU C Library; if not, see +- . */ +- +-/* INPUT PARAMETERS +- %r2 = address of source +- %r3 = address of destination +- %r4 = number of bytes to copy. */ +- +-#include "sysdep.h" +-#include "asm-syntax.h" +- +- .text +-ENTRY(__bcopy) +- ltr %r1,%r4 # zero bcopy ? +- jz .L4 +- clr %r2,%r3 # check against destructive overlap +- jnl .L0 +- alr %r1,%r2 +- clr %r1,%r3 +- jh .L7 +-.L0: ahi %r4,-1 # length - 1 +- lr %r1,%r4 +- srl %r1,8 +- ltr %r1,%r1 # < 256 bytes to move ? +- jz .L2 +- chi %r1,255 # > 1MB to move ? +- jh .L5 +-.L1: mvc 0(256,%r3),0(%r2) # move in 256 byte chunks +- la %r2,256(%r2) +- la %r3,256(%r3) +- brct %r1,.L1 +-.L2: bras %r1,.L3 # setup base pointer for execute +- mvc 0(1,%r3),0(%r2) # instruction for execute +-.L3: ex %r4,0(%r1) # execute mvc with length ((%r4)&255)+1 +-.L4: br %r14 +- +- # data copies > 1MB are faster with mvcle. +-.L5: ahi %r4,1 # length + 1 +- lr %r5,%r4 # source length +- lr %r4,%r2 # source address +- lr %r2,%r3 # set destination +- lr %r3,%r5 # destination length = source length +-.L6: mvcle %r2,%r4,0 # thats it, MVCLE is your friend +- jo .L6 +- br %r14 +-.L7: # destructive overlay, can not use mvcle +- lr %r1,%r2 # bcopy is called with source,dest +- lr %r2,%r3 # memmove with dest,source! Oh, well... +- lr %r3,%r1 +- basr %r1,0 +-.L8: +-#ifdef PIC +- al %r1,.L9-.L8(%r1) # get address of global offset table +- # load address of memmove +- l %r1,memmove@GOT(%r1) +- br %r1 +-.L9: .long _GLOBAL_OFFSET_TABLE_-.L8 +-#else +- al %r1,.L9-.L8(%r1) # load address of memmove +- br %r1 # jump to memmove +-.L9: .long memmove-.L8 +-#endif +- +-END(__bcopy) +- +-#ifndef NO_WEAK_ALIAS +-weak_alias (__bcopy, bcopy) +-#endif +- +diff --git a/sysdeps/s390/s390-64/bcopy.S b/sysdeps/s390/s390-64/bcopy.S +deleted file mode 100644 +index 806dd15d0203d32a..0000000000000000 +--- a/sysdeps/s390/s390-64/bcopy.S ++++ /dev/null +@@ -1,71 +0,0 @@ +-/* bcopy -- copy a block from source to destination. 64 bit S/390 version. +- This file is part of the GNU C Library. +- Copyright (C) 2000-2018 Free Software Foundation, Inc. +- Contributed by Martin Schwidefsky (schwidefsky@de.ibm.com). +- +- The GNU C Library is free software; you can redistribute it and/or +- modify it under the terms of the GNU Lesser General Public +- License as published by the Free Software Foundation; either +- version 2.1 of the License, or (at your option) any later version. +- +- The GNU C Library is distributed in the hope that it will be useful, +- but WITHOUT ANY WARRANTY; without even the implied warranty of +- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +- Lesser General Public License for more details. +- +- You should have received a copy of the GNU Lesser General Public +- License along with the GNU C Library; if not, see +- . */ +- +-/* INPUT PARAMETERS +- %r2 = address of source +- %r3 = address of destination +- %r4 = number of bytes to copy. */ +- +-#include "sysdep.h" +-#include "asm-syntax.h" +- +- .text +-ENTRY(__bcopy) +- ltgr %r1,%r4 # zero bcopy ? +- jz .L4 +- clgr %r2,%r3 # check against destructive overlap +- jnl .L0 +- algr %r1,%r2 +- clgr %r1,%r3 +- jh .L7 +-.L0: aghi %r4,-1 # length - 1 +- srlg %r1,%r4,8 +- ltgr %r1,%r1 # < 256 bytes to move ? +- jz .L2 +- cghi %r1,255 # > 1MB to move ? +- jh .L5 +-.L1: mvc 0(256,%r3),0(%r2) # move in 256 byte chunks +- la %r2,256(%r2) +- la %r3,256(%r3) +- brctg %r1,.L1 +-.L2: bras %r1,.L3 # setup base pointer for execute +- mvc 0(1,%r3),0(%r2) # instruction for execute +-.L3: ex %r4,0(%r1) # execute mvc with length ((%r4)&255)+1 +-.L4: br %r14 +- # data copies > 1MB are faster with mvcle. +-.L5: aghi %r4,1 # length + 1 +- lgr %r5,%r4 # source length +- lgr %r4,%r2 # source address +- lgr %r2,%r3 # set destination +- lgr %r3,%r5 # destination length = source length +-.L6: mvcle %r2,%r4,0 # thats it, MVCLE is your friend +- jo .L6 +- br %r14 +-.L7: # destructive overlay, can not use mvcle +- lgr %r1,%r2 # bcopy is called with source,dest +- lgr %r2,%r3 # memmove with dest,source! Oh, well... +- lgr %r3,%r1 +- jg HIDDEN_BUILTIN_JUMPTARGET(memmove) +- +-END(__bcopy) +- +-#ifndef NO_WEAK_ALIAS +-weak_alias (__bcopy, bcopy) +-#endif +- diff --git a/SOURCES/glibc-rh1659438-11.patch b/SOURCES/glibc-rh1659438-11.patch new file mode 100644 index 0000000..71d20a3 --- /dev/null +++ b/SOURCES/glibc-rh1659438-11.patch @@ -0,0 +1,43 @@ +commit d097d97626e44bc6e76d5daf80ce3ff7d147b623 +Author: Stefan Liebler +Date: Tue Dec 18 13:57:07 2018 +0100 + + S390: Use memcpy for forward cases in memmove. + + The s390/s390x memcpy implementations are safe to be + used by memmove. Starting with this commit, memmove is + using memcpy for the forward cases on s390. + + ChangeLog: + + * sysdeps/s390/memcopy.h: New file. + +diff --git a/sysdeps/s390/memcopy.h b/sysdeps/s390/memcopy.h +new file mode 100644 +index 0000000000000000..9a76196502f25bbf +--- /dev/null ++++ b/sysdeps/s390/memcopy.h +@@ -0,0 +1,23 @@ ++/* memcopy.h -- definitions for memory copy functions. ++ 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 ++ ++/* The s390/s390x memcpy implementations are safe to be used by memmove. */ ++#undef MEMCPY_OK_FOR_FWD_MEMMOVE ++#define MEMCPY_OK_FOR_FWD_MEMMOVE 1 diff --git a/SOURCES/glibc-rh1659438-12.patch b/SOURCES/glibc-rh1659438-12.patch new file mode 100644 index 0000000..e257c4e --- /dev/null +++ b/SOURCES/glibc-rh1659438-12.patch @@ -0,0 +1,114 @@ +commit 2ee1bc57ab50737ee2ab88c4d796b90e08b4bf93 +Author: Stefan Liebler +Date: Tue Dec 18 13:57:08 2018 +0100 + + S390: Add configure check to detect z13 as mininum architecture level set. + + Add a configure check for z13 in the same way as done for z196. + + ChangeLog: + + * config.h.in (HAVE_S390_MIN_Z13_ZARCH_ASM_SUPPORT): New undefine. + * sysdeps/s390/configure.ac: Add check for z13 support. + * sysdeps/s390/configure: Regenerated. + +diff --git a/config.h.in b/config.h.in +index beecc39d5b8c3f4a..422a6036ab16e3b6 100644 +--- a/config.h.in ++++ b/config.h.in +@@ -68,6 +68,9 @@ + /* Define if assembler supports z196 zarch instructions as default on S390. */ + #undef HAVE_S390_MIN_Z196_ZARCH_ASM_SUPPORT + ++/* Define if assembler supports z13 zarch instructions as default on S390. */ ++#undef HAVE_S390_MIN_Z13_ZARCH_ASM_SUPPORT ++ + /* Define if assembler supports vector instructions on S390. */ + #undef HAVE_S390_VX_ASM_SUPPORT + +diff --git a/sysdeps/s390/configure b/sysdeps/s390/configure +index f30f8644361f474a..4a44775e3083d8c3 100644 +--- a/sysdeps/s390/configure ++++ b/sysdeps/s390/configure +@@ -187,5 +187,43 @@ then + + fi + ++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for S390 z13 zarch instruction support as default" >&5 ++$as_echo_n "checking for S390 z13 zarch instruction support as default... " >&6; } ++if ${libc_cv_asm_s390_min_z13_zarch+:} false; then : ++ $as_echo_n "(cached) " >&6 ++else ++ cat > conftest.c <<\EOF ++int testinsn (void) ++{ ++ int i; ++ __asm__ ("vl %%v16,0(%%r15)\n\t" ++ "vlgvf %0,%%v16,0" ++ : "=d" (i) : : "memory", "v16"); ++ return i; ++} ++EOF ++if { ac_try='${CC-cc} $CFLAGS $CPPFLAGS $LDFLAGS --shared conftest.c ++ -o conftest.o &> /dev/null' ++ { { 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; }; } ; ++then ++ libc_cv_asm_s390_min_z13_zarch=yes ++else ++ libc_cv_asm_s390_min_z13_zarch=no ++fi ++rm -f conftest* ++fi ++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libc_cv_asm_s390_min_z13_zarch" >&5 ++$as_echo "$libc_cv_asm_s390_min_z13_zarch" >&6; } ++ ++if test "$libc_cv_asm_s390_min_z13_zarch" = yes ; ++then ++ $as_echo "#define HAVE_S390_MIN_Z13_ZARCH_ASM_SUPPORT 1" >>confdefs.h ++ ++fi ++ + test -n "$critic_missing" && as_fn_error $? " + *** $critic_missing" "$LINENO" 5 +diff --git a/sysdeps/s390/configure.ac b/sysdeps/s390/configure.ac +index 981f7a79dd7066fc..4dfb5574b49d5949 100644 +--- a/sysdeps/s390/configure.ac ++++ b/sysdeps/s390/configure.ac +@@ -135,5 +135,33 @@ then + AC_DEFINE(HAVE_S390_MIN_Z196_ZARCH_ASM_SUPPORT) + fi + ++AC_CACHE_CHECK(for S390 z13 zarch instruction support as default, ++ libc_cv_asm_s390_min_z13_zarch, [dnl ++cat > conftest.c <<\EOF ++int testinsn (void) ++{ ++ int i; ++ __asm__ ("vl %%v16,0(%%r15)\n\t" ++ "vlgvf %0,%%v16,0" ++ : "=d" (i) : : "memory", "v16"); ++ return i; ++} ++EOF ++dnl ++dnl test, if assembler supports S390 z13 zarch instructions as default ++if AC_TRY_COMMAND([${CC-cc} $CFLAGS $CPPFLAGS $LDFLAGS --shared conftest.c ++ -o conftest.o &> /dev/null]) ; ++then ++ libc_cv_asm_s390_min_z13_zarch=yes ++else ++ libc_cv_asm_s390_min_z13_zarch=no ++fi ++rm -f conftest* ]) ++ ++if test "$libc_cv_asm_s390_min_z13_zarch" = yes ; ++then ++ AC_DEFINE(HAVE_S390_MIN_Z13_ZARCH_ASM_SUPPORT) ++fi ++ + test -n "$critic_missing" && AC_MSG_ERROR([ + *** $critic_missing]) diff --git a/SOURCES/glibc-rh1659438-13.patch b/SOURCES/glibc-rh1659438-13.patch new file mode 100644 index 0000000..4f8aa88 --- /dev/null +++ b/SOURCES/glibc-rh1659438-13.patch @@ -0,0 +1,327 @@ +commit cdd927d98cc38acf55e1c6594b5c9451df8f239f +Author: Stefan Liebler +Date: Tue Dec 18 13:57:08 2018 +0100 + + S390: Add z13 memmove ifunc variant. + + This patch introduces a z13 specific ifunc variant for memmove. + As the common code implementation, it checks if we can copy from + the beginning to the end - with z196 memcpy implementation - or + if we have to copy from the end to the beginning. + The latter case is done by using vector load/store instructions. + + If vector instructions are not available, the common-code is + used as fallback. Therefore it is implemented in memmove-c with + a different name. + Furthermore the ifunc logic decides if we need the common-code + implementation at all. If vector instructions are supported + due to the minimum architecture level set we can skip the + common-code ifunc variant. + + ChangeLog: + + * sysdeps/s390/Makefile (sysdep_routines): Add memmove-c. + * sysdeps/s390/ifunc-memcpy.h (HAVE_MEMMOVE_IFUNC, + HAVE_MEMMOVE_IFUNC_AND_VX_SUPPORT, MEMMOVE_DEFAULT, + HAVE_MEMMOVE_C, MEMMOVE_C, HAVE_MEMMOVE_Z13, MEMMOVE_Z13): + New defines. + * sysdeps/s390/memcpy-z900.S: Add z13 memmove implementation. + * sysdeps/s390/memmove-c.c: New file. + * sysdeps/s390/memmove.c: Likewise. + * sysdeps/s390/multiarch/ifunc-impl-list.c + (__libc_ifunc_impl_list): Add ifunc variants for memmove. + +diff --git a/sysdeps/s390/Makefile b/sysdeps/s390/Makefile +index 838950a5ab958e31..3a7cccdf8f147398 100644 +--- a/sysdeps/s390/Makefile ++++ b/sysdeps/s390/Makefile +@@ -33,5 +33,6 @@ endif + ifeq ($(subdir),string) + sysdep_routines += bzero memset memset-z900 \ + memcmp memcmp-z900 \ +- mempcpy memcpy memcpy-z900 ++ mempcpy memcpy memcpy-z900 \ ++ memmove memmove-c + endif +diff --git a/sysdeps/s390/ifunc-memcpy.h b/sysdeps/s390/ifunc-memcpy.h +index 51c71baa2c0b0452..0e701968c8f39014 100644 +--- a/sysdeps/s390/ifunc-memcpy.h ++++ b/sysdeps/s390/ifunc-memcpy.h +@@ -43,6 +43,29 @@ + # define HAVE_MEMCPY_Z196 HAVE_MEMCPY_IFUNC + #endif + ++#if defined SHARED && defined USE_MULTIARCH && IS_IN (libc) \ ++ && ! defined HAVE_S390_MIN_Z13_ZARCH_ASM_SUPPORT ++# define HAVE_MEMMOVE_IFUNC 1 ++#else ++# define HAVE_MEMMOVE_IFUNC 0 ++#endif ++ ++#ifdef HAVE_S390_VX_ASM_SUPPORT ++# define HAVE_MEMMOVE_IFUNC_AND_VX_SUPPORT HAVE_MEMMOVE_IFUNC ++#else ++# define HAVE_MEMMOVE_IFUNC_AND_VX_SUPPORT 0 ++#endif ++ ++#if defined HAVE_S390_MIN_Z13_ZARCH_ASM_SUPPORT ++# define MEMMOVE_DEFAULT MEMMOVE_Z13 ++# define HAVE_MEMMOVE_C 0 ++# define HAVE_MEMMOVE_Z13 1 ++#else ++# define MEMMOVE_DEFAULT MEMMOVE_C ++# define HAVE_MEMMOVE_C 1 ++# define HAVE_MEMMOVE_Z13 HAVE_MEMMOVE_IFUNC_AND_VX_SUPPORT ++#endif ++ + #if HAVE_MEMCPY_Z900_G5 + # define MEMCPY_Z900_G5 __memcpy_default + # define MEMPCPY_Z900_G5 __mempcpy_default +@@ -66,3 +89,15 @@ + # define MEMCPY_Z196 NULL + # define MEMPCPY_Z196 NULL + #endif ++ ++#if HAVE_MEMMOVE_C ++# define MEMMOVE_C __memmove_c ++#else ++# define MEMMOVE_C NULL ++#endif ++ ++#if HAVE_MEMMOVE_Z13 ++# define MEMMOVE_Z13 __memmove_z13 ++#else ++# define MEMMOVE_Z13 NULL ++#endif +diff --git a/sysdeps/s390/memcpy-z900.S b/sysdeps/s390/memcpy-z900.S +index 3a50cf44d85d2417..bd3b1950ee442c0c 100644 +--- a/sysdeps/s390/memcpy-z900.S ++++ b/sysdeps/s390/memcpy-z900.S +@@ -182,6 +182,7 @@ ENTRY(MEMCPY_Z196) + # endif /* !defined __s390x__ */ + ltgr %r4,%r4 + je .L_Z196_4 ++.L_Z196_start2: + aghi %r4,-1 + srlg %r5,%r4,8 + ltgr %r5,%r5 +@@ -207,6 +208,75 @@ ENTRY(MEMCPY_Z196) + END(MEMCPY_Z196) + #endif /* HAVE_MEMCPY_Z196 */ + ++#if HAVE_MEMMOVE_Z13 ++ENTRY(MEMMOVE_Z13) ++ .machine "z13" ++ .machinemode "zarch_nohighgprs" ++# if !defined __s390x__ ++ /* Note: The 31bit dst and src pointers are prefixed with zeroes. */ ++ llgfr %r4,%r4 ++ llgfr %r3,%r3 ++ llgfr %r2,%r2 ++# endif /* !defined __s390x__ */ ++ sgrk %r0,%r2,%r3 ++ clgijh %r4,16,.L_MEMMOVE_Z13_LARGE ++ aghik %r5,%r4,-1 ++.L_MEMMOVE_Z13_SMALL: ++ jl .L_MEMMOVE_Z13_END /* Jump away if len was zero. */ ++ /* Store up to 16 bytes with vll/vstl which needs the index ++ instead of lengths. */ ++ vll %v16,%r5,0(%r3) ++ vstl %v16,%r5,0(%r2) ++.L_MEMMOVE_Z13_END: ++ br %r14 ++.L_MEMMOVE_Z13_LARGE: ++ lgr %r1,%r2 /* For memcpy: r1: Use as dest ; ++ r2: Return dest */ ++ /* The unsigned comparison (dst - src >= len) determines if we can ++ execute the forward case with memcpy. */ ++#if ! HAVE_MEMCPY_Z196 ++# error The z13 variant of memmove needs the z196 variant of memcpy! ++#endif ++ clgrjhe %r0,%r4,.L_Z196_start2 ++ risbgn %r5,%r4,4,128+63,60 /* r5 = r4 / 16 */ ++ aghi %r4,-16 ++ clgijhe %r5,8,.L_MEMMOVE_Z13_LARGE_64B ++.L_MEMMOVE_Z13_LARGE_16B_LOOP: ++ /* Store at least 16 bytes with vl/vst. The number of 16byte blocks ++ is stored in r5. */ ++ vl %v16,0(%r4,%r3) ++ vst %v16,0(%r4,%r2) ++ aghi %r4,-16 ++ brctg %r5,.L_MEMMOVE_Z13_LARGE_16B_LOOP ++ aghik %r5,%r4,15 ++ j .L_MEMMOVE_Z13_SMALL ++.L_MEMMOVE_Z13_LARGE_64B: ++ /* Store at least 128 bytes with 4x vl/vst. The number of 64byte blocks ++ will be stored in r0. */ ++ aghi %r4,-48 ++ srlg %r0,%r5,2 /* r5 = %r0 / 4 ++ => Number of 64byte blocks. */ ++.L_MEMMOVE_Z13_LARGE_64B_LOOP: ++ vl %v20,48(%r4,%r3) ++ vl %v19,32(%r4,%r3) ++ vl %v18,16(%r4,%r3) ++ vl %v17,0(%r4,%r3) ++ vst %v20,48(%r4,%r2) ++ vst %v19,32(%r4,%r2) ++ vst %v18,16(%r4,%r2) ++ vst %v17,0(%r4,%r2) ++ aghi %r4,-64 ++ brctg %r0,.L_MEMMOVE_Z13_LARGE_64B_LOOP ++ aghi %r4,48 ++ /* Recalculate the number of 16byte blocks. */ ++ risbg %r5,%r5,62,128+63,0 /* r5 = r5 & 3 ++ => Remaining 16byte blocks. */ ++ jne .L_MEMMOVE_Z13_LARGE_16B_LOOP ++ aghik %r5,%r4,15 ++ j .L_MEMMOVE_Z13_SMALL ++END(MEMMOVE_Z13) ++#endif /* HAVE_MEMMOVE_Z13 */ ++ + #if ! HAVE_MEMCPY_IFUNC + /* If we don't use ifunc, define an alias for mem[p]cpy here. + Otherwise see sysdeps/s390/mem[p]cpy.c. */ +@@ -215,10 +285,27 @@ strong_alias (MEMPCPY_DEFAULT, __mempcpy) + weak_alias (__mempcpy, mempcpy) + #endif + ++#if ! HAVE_MEMMOVE_IFUNC ++/* If we don't use ifunc, define an alias for memmove here. ++ Otherwise see sysdeps/s390/memmove.c. */ ++# if ! HAVE_MEMMOVE_C ++/* If the c variant is needed, then sysdeps/s390/memmove-c.c ++ defines memmove. ++ Otherwise MEMMOVE_DEFAULT is implemented here and we have to define it. */ ++strong_alias (MEMMOVE_DEFAULT, memmove) ++# endif ++#endif ++ + #if defined SHARED && IS_IN (libc) + /* Defines the internal symbols. + Compare to libc_hidden_[builtin_]def (mem[p]cpy) in string/mem[p]cpy.c. */ + strong_alias (MEMCPY_DEFAULT, __GI_memcpy) + strong_alias (MEMPCPY_DEFAULT, __GI_mempcpy) + strong_alias (MEMPCPY_DEFAULT, __GI___mempcpy) ++# if ! HAVE_MEMMOVE_C ++/* If the c variant is needed, then sysdeps/s390/memmove-c.c ++ defines the internal symbol. ++ Otherwise MEMMOVE_DEFAULT is implemented here and we have to define it. */ ++strong_alias (MEMMOVE_DEFAULT, __GI_memmove) ++# endif + #endif +diff --git a/sysdeps/s390/memmove-c.c b/sysdeps/s390/memmove-c.c +new file mode 100644 +index 0000000000000000..be571093e019a38d +--- /dev/null ++++ b/sysdeps/s390/memmove-c.c +@@ -0,0 +1,37 @@ ++/* Fallback C version of memmove. ++ 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 ++ ++#if HAVE_MEMMOVE_C ++# if HAVE_MEMMOVE_IFUNC ++/* If we use ifunc, then the memmove symbol is defined ++ in sysdeps/s390/memmove.c and we use a different name here. ++ Otherwise, we have to define memmove here or in ++ sysdeps/s390/memcpy.S depending on the used default implementation. */ ++# define MEMMOVE MEMMOVE_C ++# if defined SHARED && IS_IN (libc) ++/* Define the internal symbol. */ ++# undef libc_hidden_builtin_def ++# define libc_hidden_builtin_def(name) \ ++ __hidden_ver1 (__memmove_c, __GI_memmove, __memmove_c); ++# endif ++# endif ++ ++# include ++#endif +diff --git a/sysdeps/s390/memmove.c b/sysdeps/s390/memmove.c +new file mode 100644 +index 0000000000000000..ac34edf80f2678cd +--- /dev/null ++++ b/sysdeps/s390/memmove.c +@@ -0,0 +1,44 @@ ++/* Multiple versions of memmove. ++ 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 ++ ++#if HAVE_MEMMOVE_IFUNC ++/* If we don't use ifunc, an alias is defined for memmove ++ in sysdeps/s390/memmove-c.c or sysdeps/s390/memcpy.S ++ depending on the used default implementation. */ ++# undef memmove ++# define memmove __redirect_memmove ++# include ++# include ++# undef memmove ++ ++# if HAVE_MEMMOVE_C ++extern __typeof (__redirect_memmove) MEMMOVE_C attribute_hidden; ++# endif ++ ++# if HAVE_MEMMOVE_Z13 ++extern __typeof (__redirect_memmove) MEMMOVE_Z13 attribute_hidden; ++# endif ++ ++s390_libc_ifunc_expr (__redirect_memmove, memmove, ++ (HAVE_MEMMOVE_Z13 && (hwcap & HWCAP_S390_VX)) ++ ? MEMMOVE_Z13 ++ : MEMMOVE_DEFAULT ++ ) ++#endif +diff --git a/sysdeps/s390/multiarch/ifunc-impl-list.c b/sysdeps/s390/multiarch/ifunc-impl-list.c +index 6969c480cc40e0e2..c05c63e00608dcd7 100644 +--- a/sysdeps/s390/multiarch/ifunc-impl-list.c ++++ b/sysdeps/s390/multiarch/ifunc-impl-list.c +@@ -126,6 +126,18 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + ) + #endif /* HAVE_MEMCPY_IFUNC */ + ++#if HAVE_MEMMOVE_IFUNC ++ IFUNC_IMPL (i, name, memmove, ++# if HAVE_MEMMOVE_Z13 ++ IFUNC_IMPL_ADD (array, i, memmove, ++ dl_hwcap & HWCAP_S390_VX, MEMMOVE_Z13) ++# endif ++# if HAVE_MEMMOVE_C ++ IFUNC_IMPL_ADD (array, i, memmove, 1, MEMMOVE_C) ++# endif ++ ) ++#endif /* HAVE_MEMMOVE_IFUNC */ ++ + #ifdef HAVE_S390_VX_ASM_SUPPORT + + # define IFUNC_VX_IMPL(FUNC) \ diff --git a/SOURCES/glibc-rh1659438-14.patch b/SOURCES/glibc-rh1659438-14.patch new file mode 100644 index 0000000..7209f89 --- /dev/null +++ b/SOURCES/glibc-rh1659438-14.patch @@ -0,0 +1,263 @@ +commit 8c25dddd2e32bce47dfe01ca51c8aab535dbe23d +Author: Stefan Liebler +Date: Tue Dec 18 13:57:09 2018 +0100 + + S390: Add z13 strstr ifunc variant. + + The new vector variant of strstr is using the common code + implementation, but instead of calling the default + str* / mem* functions, the vector variants are called. + + ChangeLog: + + * sysdeps/s390/Makefile (sysdep_routines): Add strstr variants. + * sysdeps/s390/multiarch/ifunc-impl-list.c + (__libc_ifunc_impl_list): Add ifunc variants for strstr. + * sysdeps/s390/ifunc-strstr.h: New file. + * sysdeps/s390/strstr.c: Likewise. + * sysdeps/s390/strstr-c.c: Likewise. + * sysdeps/s390/strstr-vx.c: Likewise. + +diff --git a/sysdeps/s390/Makefile b/sysdeps/s390/Makefile +index 3a7cccdf8f147398..4441e7a5cf6fa167 100644 +--- a/sysdeps/s390/Makefile ++++ b/sysdeps/s390/Makefile +@@ -34,5 +34,6 @@ ifeq ($(subdir),string) + sysdep_routines += bzero memset memset-z900 \ + memcmp memcmp-z900 \ + mempcpy memcpy memcpy-z900 \ +- memmove memmove-c ++ memmove memmove-c \ ++ strstr strstr-vx strstr-c + endif +diff --git a/sysdeps/s390/ifunc-strstr.h b/sysdeps/s390/ifunc-strstr.h +new file mode 100644 +index 0000000000000000..e6ccfd4e44a1a790 +--- /dev/null ++++ b/sysdeps/s390/ifunc-strstr.h +@@ -0,0 +1,52 @@ ++/* strstr variant information on S/390 version. ++ 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 ++ . */ ++ ++#if defined USE_MULTIARCH && IS_IN (libc) \ ++ && ! defined HAVE_S390_MIN_Z13_ZARCH_ASM_SUPPORT ++# define HAVE_STRSTR_IFUNC 1 ++#else ++# define HAVE_STRSTR_IFUNC 0 ++#endif ++ ++#ifdef HAVE_S390_VX_ASM_SUPPORT ++# define HAVE_STRSTR_IFUNC_AND_VX_SUPPORT HAVE_STRSTR_IFUNC ++#else ++# define HAVE_STRSTR_IFUNC_AND_VX_SUPPORT 0 ++#endif ++ ++#if defined HAVE_S390_MIN_Z13_ZARCH_ASM_SUPPORT ++# define STRSTR_DEFAULT STRSTR_Z13 ++# define HAVE_STRSTR_C 0 ++# define HAVE_STRSTR_Z13 1 ++#else ++# define STRSTR_DEFAULT STRSTR_C ++# define HAVE_STRSTR_C 1 ++# define HAVE_STRSTR_Z13 HAVE_STRSTR_IFUNC_AND_VX_SUPPORT ++#endif ++ ++#if HAVE_STRSTR_C ++# define STRSTR_C __strstr_c ++#else ++# define STRSTR_C NULL ++#endif ++ ++#if HAVE_STRSTR_Z13 ++# define STRSTR_Z13 __strstr_vx ++#else ++# define STRSTR_Z13 NULL ++#endif +diff --git a/sysdeps/s390/multiarch/ifunc-impl-list.c b/sysdeps/s390/multiarch/ifunc-impl-list.c +index c05c63e00608dcd7..14727f8fef5431dd 100644 +--- a/sysdeps/s390/multiarch/ifunc-impl-list.c ++++ b/sysdeps/s390/multiarch/ifunc-impl-list.c +@@ -24,6 +24,7 @@ + #include + #include + #include ++#include + + /* Maximum number of IFUNC implementations. */ + #define MAX_IFUNC 3 +@@ -138,6 +139,18 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + ) + #endif /* HAVE_MEMMOVE_IFUNC */ + ++#if HAVE_STRSTR_IFUNC ++ IFUNC_IMPL (i, name, strstr, ++# if HAVE_STRSTR_Z13 ++ IFUNC_IMPL_ADD (array, i, strstr, ++ dl_hwcap & HWCAP_S390_VX, STRSTR_Z13) ++# endif ++# if HAVE_STRSTR_C ++ IFUNC_IMPL_ADD (array, i, strstr, 1, STRSTR_C) ++# endif ++ ) ++#endif /* HAVE_STRSTR_IFUNC */ ++ + #ifdef HAVE_S390_VX_ASM_SUPPORT + + # define IFUNC_VX_IMPL(FUNC) \ +diff --git a/sysdeps/s390/strstr-c.c b/sysdeps/s390/strstr-c.c +new file mode 100644 +index 0000000000000000..53717bfb276fed3d +--- /dev/null ++++ b/sysdeps/s390/strstr-c.c +@@ -0,0 +1,32 @@ ++/* Default strstr implementation for S/390. ++ 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 ++ ++#if HAVE_STRSTR_C ++# if HAVE_STRSTR_IFUNC ++# define STRSTR STRSTR_C ++# if defined SHARED && IS_IN (libc) ++# undef libc_hidden_builtin_def ++# define libc_hidden_builtin_def(name) \ ++ __hidden_ver1 (__strstr_c, __GI_strstr, __strstr_c); ++# endif ++# endif ++ ++# include ++#endif +diff --git a/sysdeps/s390/strstr-vx.c b/sysdeps/s390/strstr-vx.c +new file mode 100644 +index 0000000000000000..effae9d5eb7d2fb1 +--- /dev/null ++++ b/sysdeps/s390/strstr-vx.c +@@ -0,0 +1,52 @@ ++/* Default strstr implementation with vector string functions for S/390. ++ 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 ++ ++#if HAVE_STRSTR_Z13 ++# if HAVE_STRSTR_IFUNC ++# define STRSTR STRSTR_Z13 ++# if defined SHARED && IS_IN (libc) ++# undef libc_hidden_builtin_def ++# if HAVE_STRSTR_C ++# define libc_hidden_builtin_def(name) ++# else ++# define libc_hidden_builtin_def(name) \ ++ __hidden_ver1 (__strstr_vx, __GI_strstr, __strstr_vx); ++# endif ++# endif ++# endif ++ ++# include ++ ++# ifdef USE_MULTIARCH ++extern __typeof (strchr) __strchr_vx attribute_hidden; ++# define strchr __strchr_vx ++ ++extern __typeof (strlen) __strlen_vx attribute_hidden; ++# define strlen __strlen_vx ++ ++extern __typeof (__strnlen) __strnlen_vx attribute_hidden; ++# define __strnlen __strnlen_vx ++ ++extern __typeof (memcmp) __memcmp_z196 attribute_hidden; ++# define memcmp __memcmp_z196 ++# endif ++ ++# include ++#endif +diff --git a/sysdeps/s390/strstr.c b/sysdeps/s390/strstr.c +new file mode 100644 +index 0000000000000000..f8432349a7254cc6 +--- /dev/null ++++ b/sysdeps/s390/strstr.c +@@ -0,0 +1,40 @@ ++/* Multiple versions of strstr. ++ 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 ++ ++#if HAVE_STRSTR_IFUNC ++# define strstr __redirect_strstr ++# include ++# include ++# undef strstr ++ ++# if HAVE_STRSTR_C ++extern __typeof (__redirect_strstr) STRSTR_C attribute_hidden; ++# endif ++ ++# if HAVE_STRSTR_Z13 ++extern __typeof (__redirect_strstr) STRSTR_Z13 attribute_hidden; ++# endif ++ ++s390_libc_ifunc_expr (__redirect_strstr, strstr, ++ (HAVE_STRSTR_Z13 && (hwcap & HWCAP_S390_VX)) ++ ? STRSTR_Z13 ++ : STRSTR_DEFAULT ++ ) ++#endif diff --git a/SOURCES/glibc-rh1659438-15.patch b/SOURCES/glibc-rh1659438-15.patch new file mode 100644 index 0000000..0cb1dbe --- /dev/null +++ b/SOURCES/glibc-rh1659438-15.patch @@ -0,0 +1,290 @@ +commit d2c4c403feddd6f0b9dbf31ca7541b37f90ee30a +Author: Stefan Liebler +Date: Tue Dec 18 13:57:09 2018 +0100 + + S390: Add z13 memmem ifunc variant. + + The new vector variant of memmem is using the common code + implementation, but instead of calling the default + mem* functions, the vector variants are called. + + ChangeLog: + + * sysdeps/s390/Makefile (sysdep_routines): Add memmem variants. + * sysdeps/s390/multiarch/ifunc-impl-list.c + (__libc_ifunc_impl_list): Add ifunc variants for memmem. + * sysdeps/s390/ifunc-memmem.h: New file. + * sysdeps/s390/memmem.c: Likewise. + * sysdeps/s390/memmem-c.c: Likewise. + * sysdeps/s390/memmem-vx.c: Likewise. + +diff --git a/sysdeps/s390/Makefile b/sysdeps/s390/Makefile +index 4441e7a5cf6fa167..47d606d3d5d99274 100644 +--- a/sysdeps/s390/Makefile ++++ b/sysdeps/s390/Makefile +@@ -35,5 +35,6 @@ sysdep_routines += bzero memset memset-z900 \ + memcmp memcmp-z900 \ + mempcpy memcpy memcpy-z900 \ + memmove memmove-c \ +- strstr strstr-vx strstr-c ++ strstr strstr-vx strstr-c \ ++ memmem memmem-vx memmem-c + endif +diff --git a/sysdeps/s390/ifunc-memmem.h b/sysdeps/s390/ifunc-memmem.h +new file mode 100644 +index 0000000000000000..0f860d8d40080acf +--- /dev/null ++++ b/sysdeps/s390/ifunc-memmem.h +@@ -0,0 +1,52 @@ ++/* memmem variant information on S/390 version. ++ 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 ++ . */ ++ ++#if defined USE_MULTIARCH && IS_IN (libc) \ ++ && ! defined HAVE_S390_MIN_Z13_ZARCH_ASM_SUPPORT ++# define HAVE_MEMMEM_IFUNC 1 ++#else ++# define HAVE_MEMMEM_IFUNC 0 ++#endif ++ ++#ifdef HAVE_S390_VX_ASM_SUPPORT ++# define HAVE_MEMMEM_IFUNC_AND_VX_SUPPORT HAVE_MEMMEM_IFUNC ++#else ++# define HAVE_MEMMEM_IFUNC_AND_VX_SUPPORT 0 ++#endif ++ ++#if defined HAVE_S390_MIN_Z13_ZARCH_ASM_SUPPORT ++# define MEMMEM_DEFAULT MEMMEM_Z13 ++# define HAVE_MEMMEM_C 0 ++# define HAVE_MEMMEM_Z13 1 ++#else ++# define MEMMEM_DEFAULT MEMMEM_C ++# define HAVE_MEMMEM_C 1 ++# define HAVE_MEMMEM_Z13 HAVE_MEMMEM_IFUNC_AND_VX_SUPPORT ++#endif ++ ++#if HAVE_MEMMEM_C ++# define MEMMEM_C __memmem_c ++#else ++# define MEMMEM_C NULL ++#endif ++ ++#if HAVE_MEMMEM_Z13 ++# define MEMMEM_Z13 __memmem_vx ++#else ++# define MEMMEM_Z13 NULL ++#endif +diff --git a/sysdeps/s390/memmem-c.c b/sysdeps/s390/memmem-c.c +new file mode 100644 +index 0000000000000000..1d8ffefcb840b8d2 +--- /dev/null ++++ b/sysdeps/s390/memmem-c.c +@@ -0,0 +1,47 @@ ++/* Default memmem implementation for S/390. ++ 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 ++ ++#if HAVE_MEMMEM_C ++# if HAVE_MEMMEM_IFUNC ++# include ++ ++# ifndef _LIBC ++# define memmem MEMMEM_C ++# else ++# define __memmem MEMMEM_C ++# endif ++ ++# if defined SHARED && IS_IN (libc) ++# undef libc_hidden_def ++# define libc_hidden_def(name) \ ++ strong_alias (__memmem_c, __memmem_c_1); \ ++ __hidden_ver1 (__memmem_c, __GI___memmem, __memmem_c); ++ ++# undef libc_hidden_weak ++# define libc_hidden_weak(name) \ ++ __hidden_ver1 (__memmem_c_1, __GI_memmem, __memmem_c_1) __attribute__((weak)); ++# endif ++ ++# undef weak_alias ++# define weak_alias(a, b) ++# endif ++ ++# include ++#endif +diff --git a/sysdeps/s390/memmem-vx.c b/sysdeps/s390/memmem-vx.c +new file mode 100644 +index 0000000000000000..af6e200e4e0af1a5 +--- /dev/null ++++ b/sysdeps/s390/memmem-vx.c +@@ -0,0 +1,61 @@ ++/* Default memmem implementation with vector string functions for S/390. ++ 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 ++ ++#if HAVE_MEMMEM_Z13 ++# include ++# if HAVE_MEMMEM_IFUNC ++ ++# ifndef _LIBC ++# define memmem MEMMEM_Z13 ++# else ++# define __memmem MEMMEM_Z13 ++# endif ++ ++# if defined SHARED && IS_IN (libc) ++# undef libc_hidden_def ++# undef libc_hidden_weak ++ ++# if HAVE_MEMMEM_C ++# define libc_hidden_def(name) ++# define libc_hidden_weak(name) ++# else ++# define libc_hidden_def(name) \ ++ strong_alias (__memmem_vx, __memmem_vx_1); \ ++ __hidden_ver1 (__memmem_vx, __GI___memmem, __memmem_vx); ++ ++# define libc_hidden_weak(name) \ ++ __hidden_ver1 (__memmem_vx_1, __GI_memmem, __memmem_vx_1) __attribute__((weak)); ++# endif ++# endif ++ ++# undef weak_alias ++# define weak_alias(a, b) ++# endif ++ ++# ifdef USE_MULTIARCH ++extern __typeof (memchr) __memchr_vx attribute_hidden; ++# define memchr __memchr_vx ++ ++extern __typeof (memcmp) __memcmp_z196 attribute_hidden; ++# define memcmp __memcmp_z196 ++# endif ++ ++# include ++#endif +diff --git a/sysdeps/s390/memmem.c b/sysdeps/s390/memmem.c +new file mode 100644 +index 0000000000000000..8c50b3f403eb8d1f +--- /dev/null ++++ b/sysdeps/s390/memmem.c +@@ -0,0 +1,43 @@ ++/* Multiple versions of memmem. ++ 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 ++ ++#if HAVE_MEMMEM_IFUNC ++# define memmem __redirect_memmem ++# define __memmem __redirect___memmem ++# include ++# include ++# undef memmem ++# undef __memmem ++ ++# if HAVE_MEMMEM_C ++extern __typeof (__redirect_memmem) MEMMEM_C attribute_hidden; ++# endif ++ ++# if HAVE_MEMMEM_Z13 ++extern __typeof (__redirect_memmem) MEMMEM_Z13 attribute_hidden; ++# endif ++ ++s390_libc_ifunc_expr (__redirect_memmem, __memmem, ++ (HAVE_MEMMEM_Z13 && (hwcap & HWCAP_S390_VX)) ++ ? MEMMEM_Z13 ++ : MEMMEM_DEFAULT ++ ) ++weak_alias (__memmem, memmem) ++#endif +diff --git a/sysdeps/s390/multiarch/ifunc-impl-list.c b/sysdeps/s390/multiarch/ifunc-impl-list.c +index 14727f8fef5431dd..da8696d917abf51c 100644 +--- a/sysdeps/s390/multiarch/ifunc-impl-list.c ++++ b/sysdeps/s390/multiarch/ifunc-impl-list.c +@@ -25,6 +25,7 @@ + #include + #include + #include ++#include + + /* Maximum number of IFUNC implementations. */ + #define MAX_IFUNC 3 +@@ -151,6 +152,18 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + ) + #endif /* HAVE_STRSTR_IFUNC */ + ++#if HAVE_MEMMEM_IFUNC ++ IFUNC_IMPL (i, name, memmem, ++# if HAVE_MEMMEM_Z13 ++ IFUNC_IMPL_ADD (array, i, memmem, ++ dl_hwcap & HWCAP_S390_VX, MEMMEM_Z13) ++# endif ++# if HAVE_MEMMEM_C ++ IFUNC_IMPL_ADD (array, i, memmem, 1, MEMMEM_C) ++# endif ++ ) ++#endif /* HAVE_MEMMEM_IFUNC */ ++ + #ifdef HAVE_S390_VX_ASM_SUPPORT + + # define IFUNC_VX_IMPL(FUNC) \ diff --git a/SOURCES/glibc-rh1659438-16.patch b/SOURCES/glibc-rh1659438-16.patch new file mode 100644 index 0000000..b55bebc --- /dev/null +++ b/SOURCES/glibc-rh1659438-16.patch @@ -0,0 +1,259 @@ +commit ff3ca3743a00af749258cc242457b648d65a1537 +Author: Stefan Liebler +Date: Tue Dec 18 13:57:10 2018 +0100 + + S390: Refactor strlen ifunc handling. + + The ifunc handling for strlen is adjusted in order to omit ifunc + variants if those will never be used as the minimum architecture level + already supports newer CPUs by default. + Glibc internal calls will then also use the "newer" ifunc variant. + + ChangeLog: + + * sysdeps/s390/multiarch/Makefile + (sysdep_routines): Remove strlen variants. + * sysdeps/s390/Makefile (sysdep_routines): Add strlen variants. + * sysdeps/s390/multiarch/ifunc-impl-list.c + (__libc_ifunc_impl_list): Refactor ifunc handling for strlen. + * sysdeps/s390/multiarch/strlen-c.c: Move to ... + * sysdeps/s390/strlen-c.c: ... here and adjust ifunc handling. + * sysdeps/s390/multiarch/strlen-vx.S: Move to ... + * sysdeps/s390/strlen-vx.S: ... here and adjust ifunc handling. + * sysdeps/s390/multiarch/strlen.c: Move to ... + * sysdeps/s390/strlen.c: ... here and adjust ifunc handling. + * sysdeps/s390/ifunc-strlen.h: New file. + +diff --git a/sysdeps/s390/Makefile b/sysdeps/s390/Makefile +index 47d606d3d5d99274..600d8e629df7090e 100644 +--- a/sysdeps/s390/Makefile ++++ b/sysdeps/s390/Makefile +@@ -36,5 +36,6 @@ sysdep_routines += bzero memset memset-z900 \ + mempcpy memcpy memcpy-z900 \ + memmove memmove-c \ + strstr strstr-vx strstr-c \ +- memmem memmem-vx memmem-c ++ memmem memmem-vx memmem-c \ ++ strlen strlen-vx strlen-c + endif +diff --git a/sysdeps/s390/ifunc-strlen.h b/sysdeps/s390/ifunc-strlen.h +new file mode 100644 +index 0000000000000000..f2070596636f29a9 +--- /dev/null ++++ b/sysdeps/s390/ifunc-strlen.h +@@ -0,0 +1,52 @@ ++/* strlen variant information on S/390 version. ++ 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 ++ . */ ++ ++#if defined USE_MULTIARCH && IS_IN (libc) \ ++ && ! defined HAVE_S390_MIN_Z13_ZARCH_ASM_SUPPORT ++# define HAVE_STRLEN_IFUNC 1 ++#else ++# define HAVE_STRLEN_IFUNC 0 ++#endif ++ ++#ifdef HAVE_S390_VX_ASM_SUPPORT ++# define HAVE_STRLEN_IFUNC_AND_VX_SUPPORT HAVE_STRLEN_IFUNC ++#else ++# define HAVE_STRLEN_IFUNC_AND_VX_SUPPORT 0 ++#endif ++ ++#if defined HAVE_S390_MIN_Z13_ZARCH_ASM_SUPPORT ++# define STRLEN_DEFAULT STRLEN_Z13 ++# define HAVE_STRLEN_C 0 ++# define HAVE_STRLEN_Z13 1 ++#else ++# define STRLEN_DEFAULT STRLEN_C ++# define HAVE_STRLEN_C 1 ++# define HAVE_STRLEN_Z13 HAVE_STRLEN_IFUNC_AND_VX_SUPPORT ++#endif ++ ++#if HAVE_STRLEN_C ++# define STRLEN_C __strlen_c ++#else ++# define STRLEN_C NULL ++#endif ++ ++#if HAVE_STRLEN_Z13 ++# define STRLEN_Z13 __strlen_vx ++#else ++# define STRLEN_Z13 NULL ++#endif +diff --git a/sysdeps/s390/multiarch/Makefile b/sysdeps/s390/multiarch/Makefile +index 24949cd3a88b8015..601523919c235f76 100644 +--- a/sysdeps/s390/multiarch/Makefile ++++ b/sysdeps/s390/multiarch/Makefile +@@ -1,6 +1,5 @@ + ifeq ($(subdir),string) +-sysdep_routines += strlen strlen-vx strlen-c \ +- strnlen strnlen-vx strnlen-c \ ++sysdep_routines += strnlen strnlen-vx strnlen-c \ + strcpy strcpy-vx \ + stpcpy stpcpy-vx stpcpy-c \ + strncpy strncpy-vx \ +diff --git a/sysdeps/s390/multiarch/ifunc-impl-list.c b/sysdeps/s390/multiarch/ifunc-impl-list.c +index da8696d917abf51c..c531be4bc7eb3f55 100644 +--- a/sysdeps/s390/multiarch/ifunc-impl-list.c ++++ b/sysdeps/s390/multiarch/ifunc-impl-list.c +@@ -26,6 +26,7 @@ + #include + #include + #include ++#include + + /* Maximum number of IFUNC implementations. */ + #define MAX_IFUNC 3 +@@ -164,6 +165,18 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + ) + #endif /* HAVE_MEMMEM_IFUNC */ + ++#if HAVE_STRLEN_IFUNC ++ IFUNC_IMPL (i, name, strlen, ++# if HAVE_STRLEN_Z13 ++ IFUNC_IMPL_ADD (array, i, strlen, ++ dl_hwcap & HWCAP_S390_VX, STRLEN_Z13) ++# endif ++# if HAVE_STRLEN_C ++ IFUNC_IMPL_ADD (array, i, strlen, 1, STRLEN_C) ++# endif ++ ) ++#endif /* HAVE_STRLEN_IFUNC */ ++ + #ifdef HAVE_S390_VX_ASM_SUPPORT + + # define IFUNC_VX_IMPL(FUNC) \ +@@ -172,7 +185,6 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + __##FUNC##_vx) \ + IFUNC_IMPL_ADD (array, i, FUNC, 1, __##FUNC##_c)) + +- IFUNC_VX_IMPL (strlen); + IFUNC_VX_IMPL (wcslen); + + IFUNC_VX_IMPL (strnlen); +diff --git a/sysdeps/s390/multiarch/strlen-c.c b/sysdeps/s390/strlen-c.c +similarity index 78% +rename from sysdeps/s390/multiarch/strlen-c.c +rename to sysdeps/s390/strlen-c.c +index a2c8e43624a9bc91..b4569701af96f4a9 100644 +--- a/sysdeps/s390/multiarch/strlen-c.c ++++ b/sysdeps/s390/strlen-c.c +@@ -16,13 +16,17 @@ + License along with the GNU C Library; if not, see + . */ + +-#if defined HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc) +-# define STRLEN __strlen_c +-# ifdef SHARED +-# undef libc_hidden_builtin_def +-# define libc_hidden_builtin_def(name) \ ++#include ++ ++#if HAVE_STRLEN_C ++# if HAVE_STRLEN_IFUNC ++# define STRLEN STRLEN_C ++# if defined SHARED && IS_IN (libc) ++# undef libc_hidden_builtin_def ++# define libc_hidden_builtin_def(name) \ + __hidden_ver1 (__strlen_c, __GI_strlen, __strlen_c); +-# endif /* SHARED */ ++# endif ++# endif + + # include +-#endif /* HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc) */ ++#endif +diff --git a/sysdeps/s390/multiarch/strlen-vx.S b/sysdeps/s390/strlen-vx.S +similarity index 90% +rename from sysdeps/s390/multiarch/strlen-vx.S +rename to sysdeps/s390/strlen-vx.S +index 9308b332371dcdaa..39ef43107d11ec73 100644 +--- a/sysdeps/s390/multiarch/strlen-vx.S ++++ b/sysdeps/s390/strlen-vx.S +@@ -16,7 +16,8 @@ + License along with the GNU C Library; if not, see + . */ + +-#if defined HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc) ++#include ++#if HAVE_STRLEN_Z13 + + # include "sysdep.h" + # include "asm-syntax.h" +@@ -34,7 +35,7 @@ + -r5=current_len and return_value + -v16=part of s + */ +-ENTRY(__strlen_vx) ++ENTRY(STRLEN_Z13) + .machine "z13" + .machinemode "zarch_nohighgprs" + +@@ -80,5 +81,13 @@ ENTRY(__strlen_vx) + vlgvb %r2,%v16,7 /* Load byte index of zero. */ + algr %r2,%r5 + br %r14 +-END(__strlen_vx) +-#endif /* HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc) */ ++END(STRLEN_Z13) ++ ++# if ! HAVE_STRLEN_IFUNC ++strong_alias (STRLEN_Z13, strlen) ++# endif ++ ++# if ! HAVE_STRLEN_C && defined SHARED && IS_IN (libc) ++strong_alias (STRLEN_Z13, __GI_strlen) ++# endif ++#endif +diff --git a/sysdeps/s390/multiarch/strlen.c b/sysdeps/s390/strlen.c +similarity index 69% +rename from sysdeps/s390/multiarch/strlen.c +rename to sysdeps/s390/strlen.c +index 0edf8b7d0231cf31..6ba0fe86fe9789f0 100644 +--- a/sysdeps/s390/multiarch/strlen.c ++++ b/sysdeps/s390/strlen.c +@@ -16,14 +16,25 @@ + License along with the GNU C Library; if not, see + . */ + +-#if defined HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc) ++#include ++ ++#if HAVE_STRLEN_IFUNC + # define strlen __redirect_strlen + # include + # include + # undef strlen + +-s390_vx_libc_ifunc2_redirected (__redirect_strlen, __strlen, strlen) ++# if HAVE_STRLEN_C ++extern __typeof (__redirect_strlen) STRLEN_C attribute_hidden; ++# endif ++ ++# if HAVE_STRLEN_Z13 ++extern __typeof (__redirect_strlen) STRLEN_Z13 attribute_hidden; ++# endif + +-#else +-# include +-#endif /* !(defined HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc)) */ ++s390_libc_ifunc_expr (__redirect_strlen, strlen, ++ (HAVE_STRLEN_Z13 && (hwcap & HWCAP_S390_VX)) ++ ? STRLEN_Z13 ++ : STRLEN_DEFAULT ++ ) ++#endif diff --git a/SOURCES/glibc-rh1659438-17.patch b/SOURCES/glibc-rh1659438-17.patch new file mode 100644 index 0000000..da43ae2 --- /dev/null +++ b/SOURCES/glibc-rh1659438-17.patch @@ -0,0 +1,269 @@ +commit de10e44dda686e3ed6a7a1463869df846ea39825 +Author: Stefan Liebler +Date: Tue Dec 18 13:57:10 2018 +0100 + + S390: Refactor strnlen ifunc handling. + + The ifunc handling for strnlen is adjusted in order to omit ifunc + variants if those will never be used as the minimum architecture level + already supports newer CPUs by default. + Glibc internal calls will then also use the "newer" ifunc variant. + + ChangeLog: + + * sysdeps/s390/multiarch/Makefile + (sysdep_routines): Remove strnlen variants. + * sysdeps/s390/Makefile (sysdep_routines): Add strnlen variants. + * sysdeps/s390/multiarch/ifunc-impl-list.c + (__libc_ifunc_impl_list): Refactor ifunc handling for strnlen. + * sysdeps/s390/multiarch/strnlen-c.c: Move to ... + * sysdeps/s390/strnlen-c.c: ... here and adjust ifunc handling. + * sysdeps/s390/multiarch/strnlen-vx.S: Move to ... + * sysdeps/s390/strnlen-vx.S: ... here and adjust ifunc handling. + * sysdeps/s390/multiarch/strnlen.c: Move to ... + * sysdeps/s390/strnlen.c: ... here and adjust ifunc handling. + * sysdeps/s390/ifunc-strnlen.h: New file. + +diff --git a/sysdeps/s390/Makefile b/sysdeps/s390/Makefile +index 600d8e629df7090e..f092355743e3908f 100644 +--- a/sysdeps/s390/Makefile ++++ b/sysdeps/s390/Makefile +@@ -37,5 +37,6 @@ sysdep_routines += bzero memset memset-z900 \ + memmove memmove-c \ + strstr strstr-vx strstr-c \ + memmem memmem-vx memmem-c \ +- strlen strlen-vx strlen-c ++ strlen strlen-vx strlen-c \ ++ strnlen strnlen-vx strnlen-c + endif +diff --git a/sysdeps/s390/ifunc-strnlen.h b/sysdeps/s390/ifunc-strnlen.h +new file mode 100644 +index 0000000000000000..e92329888773304d +--- /dev/null ++++ b/sysdeps/s390/ifunc-strnlen.h +@@ -0,0 +1,52 @@ ++/* strnlen variant information on S/390 version. ++ 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 ++ . */ ++ ++#if defined USE_MULTIARCH && IS_IN (libc) \ ++ && ! defined HAVE_S390_MIN_Z13_ZARCH_ASM_SUPPORT ++# define HAVE_STRNLEN_IFUNC 1 ++#else ++# define HAVE_STRNLEN_IFUNC 0 ++#endif ++ ++#ifdef HAVE_S390_VX_ASM_SUPPORT ++# define HAVE_STRNLEN_IFUNC_AND_VX_SUPPORT HAVE_STRNLEN_IFUNC ++#else ++# define HAVE_STRNLEN_IFUNC_AND_VX_SUPPORT 0 ++#endif ++ ++#if defined HAVE_S390_MIN_Z13_ZARCH_ASM_SUPPORT ++# define STRNLEN_DEFAULT STRNLEN_Z13 ++# define HAVE_STRNLEN_C 0 ++# define HAVE_STRNLEN_Z13 1 ++#else ++# define STRNLEN_DEFAULT STRNLEN_C ++# define HAVE_STRNLEN_C 1 ++# define HAVE_STRNLEN_Z13 HAVE_STRNLEN_IFUNC_AND_VX_SUPPORT ++#endif ++ ++#if HAVE_STRNLEN_C ++# define STRNLEN_C __strnlen_c ++#else ++# define STRNLEN_C NULL ++#endif ++ ++#if HAVE_STRNLEN_Z13 ++# define STRNLEN_Z13 __strnlen_vx ++#else ++# define STRNLEN_Z13 NULL ++#endif +diff --git a/sysdeps/s390/multiarch/Makefile b/sysdeps/s390/multiarch/Makefile +index 601523919c235f76..35ba223c5d4fb52f 100644 +--- a/sysdeps/s390/multiarch/Makefile ++++ b/sysdeps/s390/multiarch/Makefile +@@ -1,6 +1,5 @@ + ifeq ($(subdir),string) +-sysdep_routines += strnlen strnlen-vx strnlen-c \ +- strcpy strcpy-vx \ ++sysdep_routines += strcpy strcpy-vx \ + stpcpy stpcpy-vx stpcpy-c \ + strncpy strncpy-vx \ + stpncpy stpncpy-vx stpncpy-c \ +diff --git a/sysdeps/s390/multiarch/ifunc-impl-list.c b/sysdeps/s390/multiarch/ifunc-impl-list.c +index c531be4bc7eb3f55..680e5b738bfb7f32 100644 +--- a/sysdeps/s390/multiarch/ifunc-impl-list.c ++++ b/sysdeps/s390/multiarch/ifunc-impl-list.c +@@ -27,6 +27,7 @@ + #include + #include + #include ++#include + + /* Maximum number of IFUNC implementations. */ + #define MAX_IFUNC 3 +@@ -177,6 +178,18 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + ) + #endif /* HAVE_STRLEN_IFUNC */ + ++#if HAVE_STRNLEN_IFUNC ++ IFUNC_IMPL (i, name, strnlen, ++# if HAVE_STRNLEN_Z13 ++ IFUNC_IMPL_ADD (array, i, strnlen, ++ dl_hwcap & HWCAP_S390_VX, STRNLEN_Z13) ++# endif ++# if HAVE_STRNLEN_C ++ IFUNC_IMPL_ADD (array, i, strnlen, 1, STRNLEN_C) ++# endif ++ ) ++#endif /* HAVE_STRNLEN_IFUNC */ ++ + #ifdef HAVE_S390_VX_ASM_SUPPORT + + # define IFUNC_VX_IMPL(FUNC) \ +@@ -187,7 +200,6 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + + IFUNC_VX_IMPL (wcslen); + +- IFUNC_VX_IMPL (strnlen); + IFUNC_VX_IMPL (wcsnlen); + + IFUNC_VX_IMPL (strcpy); +diff --git a/sysdeps/s390/multiarch/strnlen-c.c b/sysdeps/s390/strnlen-c.c +similarity index 81% +rename from sysdeps/s390/multiarch/strnlen-c.c +rename to sysdeps/s390/strnlen-c.c +index 353e83ed356ca080..c2d887f1e4f504e8 100644 +--- a/sysdeps/s390/multiarch/strnlen-c.c ++++ b/sysdeps/s390/strnlen-c.c +@@ -16,15 +16,19 @@ + License along with the GNU C Library; if not, see + . */ + +-#if defined HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc) +-# define STRNLEN __strnlen_c +-# ifdef SHARED +-# undef libc_hidden_def +-# define libc_hidden_def(name) \ ++#include ++ ++#if HAVE_STRNLEN_C ++# if HAVE_STRNLEN_IFUNC ++# define STRNLEN STRNLEN_C ++# if defined SHARED && IS_IN (libc) ++# undef libc_hidden_def ++# define libc_hidden_def(name) \ + __hidden_ver1 (__strnlen_c, __GI_strnlen, __strnlen_c); \ + strong_alias (__strnlen_c, __strnlen_c_1); \ + __hidden_ver1 (__strnlen_c_1, __GI___strnlen, __strnlen_c_1); +-# endif /* SHARED */ ++# endif ++# endif + + # include +-#endif /* HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc) */ ++#endif +diff --git a/sysdeps/s390/multiarch/strnlen-vx.S b/sysdeps/s390/strnlen-vx.S +similarity index 90% +rename from sysdeps/s390/multiarch/strnlen-vx.S +rename to sysdeps/s390/strnlen-vx.S +index fc659a956cfc1fa1..0b8fe3da342f6803 100644 +--- a/sysdeps/s390/multiarch/strnlen-vx.S ++++ b/sysdeps/s390/strnlen-vx.S +@@ -16,7 +16,9 @@ + License along with the GNU C Library; if not, see + . */ + +-#if defined HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc) ++#include ++ ++#if HAVE_STRNLEN_Z13 + + # include "sysdep.h" + # include "asm-syntax.h" +@@ -34,7 +36,7 @@ + -r5=current_len and return_value + -v16=part of s + */ +-ENTRY(__strnlen_vx) ++ENTRY(STRNLEN_Z13) + .machine "z13" + .machinemode "zarch_nohighgprs" + +@@ -130,5 +132,16 @@ ENTRY(__strnlen_vx) + clgrjl %r1,%r3,.Lloop64 + + j .Llt64 +-END(__strnlen_vx) +-#endif /* HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc) */ ++END(STRNLEN_Z13) ++ ++# if ! HAVE_STRNLEN_IFUNC ++strong_alias (STRNLEN_Z13, __strnlen) ++weak_alias (__strnlen, strnlen) ++# endif ++ ++# if ! HAVE_STRNLEN_C && defined SHARED && IS_IN (libc) ++strong_alias (STRNLEN_Z13, __GI_strnlen) ++strong_alias (STRNLEN_Z13, __GI___strnlen) ++# endif ++ ++#endif /* HAVE_STRNLEN_Z13 */ +diff --git a/sysdeps/s390/multiarch/strnlen.c b/sysdeps/s390/strnlen.c +similarity index 69% +rename from sysdeps/s390/multiarch/strnlen.c +rename to sysdeps/s390/strnlen.c +index 0f9cff5d69b017ae..aa4953d5035bc2fc 100644 +--- a/sysdeps/s390/multiarch/strnlen.c ++++ b/sysdeps/s390/strnlen.c +@@ -16,7 +16,9 @@ + License along with the GNU C Library; if not, see + . */ + +-#if defined HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc) ++#include ++ ++#if HAVE_STRNLEN_IFUNC + # define strnlen __redirect_strnlen + # define __strnlen __redirect___strnlen + # include +@@ -24,9 +26,18 @@ + # undef __strnlen + # include + +-s390_vx_libc_ifunc_redirected (__redirect___strnlen, __strnlen) +-weak_alias (__strnlen, strnlen) ++# if HAVE_STRNLEN_C ++extern __typeof (__redirect_strnlen) STRNLEN_C attribute_hidden; ++# endif + +-#else +-# include +-#endif /* !(defined HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc)) */ ++# if HAVE_STRNLEN_Z13 ++extern __typeof (__redirect_strnlen) STRNLEN_Z13 attribute_hidden; ++# endif ++ ++s390_libc_ifunc_expr (__redirect___strnlen, __strnlen, ++ (HAVE_STRNLEN_Z13 && (hwcap & HWCAP_S390_VX)) ++ ? STRNLEN_Z13 ++ : STRNLEN_DEFAULT ++ ) ++weak_alias (__strnlen, strnlen) ++#endif /* HAVE_STRNLEN_IFUNC */ diff --git a/SOURCES/glibc-rh1659438-18.patch b/SOURCES/glibc-rh1659438-18.patch new file mode 100644 index 0000000..bcd7958 --- /dev/null +++ b/SOURCES/glibc-rh1659438-18.patch @@ -0,0 +1,398 @@ +commit 914a4e05572e108201d71dcd3e47da8aeeecd70d +Author: Stefan Liebler +Date: Tue Dec 18 13:57:10 2018 +0100 + + S390: Refactor strcpy ifunc handling. + + The ifunc handling for strcpy is adjusted in order to omit ifunc + variants if those will never be used as the minimum architecture level + already supports newer CPUs by default. + Glibc internal calls will then also use the "newer" ifunc variant. + + Note: The fallback s390-32/s390-64 ifunc variants with mvst instruction + are now moved to the unified strcpy-z900.S file which can be used for + 31/64bit. The s390-32/s390-64 files multiarch/strcpy.c and strcpy.S + are deleted. + + ChangeLog: + + * sysdeps/s390/multiarch/Makefile + (sysdep_routines): Remove strcpy variants. + * sysdeps/s390/Makefile (sysdep_routines): Add strcpy variants. + * sysdeps/s390/multiarch/ifunc-impl-list.c + (__libc_ifunc_impl_list): Refactor ifunc handling for strcpy. + * sysdeps/s390/multiarch/strcpy-vx.S: Move to ... + * sysdeps/s390/strcpy-vx.S: ... here and adjust ifunc handling. + * sysdeps/s390/multiarch/strcpy.c: Move to ... + * sysdeps/s390/strcpy.c: ... here and adjust ifunc handling. + * sysdeps/s390/ifunc-strcpy.h: New file. + * sysdeps/s390/s390-64/strcpy.S: Move to ... + * sysdeps/s390/strcpy-z900.S: ... here and adjust to be usable + for 31/64bit and ifunc handling. + * sysdeps/s390/s390-32/multiarch/strcpy.c: Delete file. + * sysdeps/s390/s390-64/multiarch/strcpy.c: Likewise. + * sysdeps/s390/s390-32/strcpy.S: Likewise. + +diff --git a/sysdeps/s390/Makefile b/sysdeps/s390/Makefile +index f092355743e3908f..e4191319531ecb01 100644 +--- a/sysdeps/s390/Makefile ++++ b/sysdeps/s390/Makefile +@@ -38,5 +38,6 @@ sysdep_routines += bzero memset memset-z900 \ + strstr strstr-vx strstr-c \ + memmem memmem-vx memmem-c \ + strlen strlen-vx strlen-c \ +- strnlen strnlen-vx strnlen-c ++ strnlen strnlen-vx strnlen-c \ ++ strcpy strcpy-vx strcpy-z900 + endif +diff --git a/sysdeps/s390/ifunc-strcpy.h b/sysdeps/s390/ifunc-strcpy.h +new file mode 100644 +index 0000000000000000..85e45556e6a61dd5 +--- /dev/null ++++ b/sysdeps/s390/ifunc-strcpy.h +@@ -0,0 +1,52 @@ ++/* strcpy variant information on S/390 version. ++ 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 ++ . */ ++ ++#if defined USE_MULTIARCH && IS_IN (libc) \ ++ && ! defined HAVE_S390_MIN_Z13_ZARCH_ASM_SUPPORT ++# define HAVE_STRCPY_IFUNC 1 ++#else ++# define HAVE_STRCPY_IFUNC 0 ++#endif ++ ++#ifdef HAVE_S390_VX_ASM_SUPPORT ++# define HAVE_STRCPY_IFUNC_AND_VX_SUPPORT HAVE_STRCPY_IFUNC ++#else ++# define HAVE_STRCPY_IFUNC_AND_VX_SUPPORT 0 ++#endif ++ ++#if defined HAVE_S390_MIN_Z13_ZARCH_ASM_SUPPORT ++# define STRCPY_DEFAULT STRCPY_Z13 ++# define HAVE_STRCPY_Z900_G5 0 ++# define HAVE_STRCPY_Z13 1 ++#else ++# define STRCPY_DEFAULT STRCPY_Z900_G5 ++# define HAVE_STRCPY_Z900_G5 1 ++# define HAVE_STRCPY_Z13 HAVE_STRCPY_IFUNC_AND_VX_SUPPORT ++#endif ++ ++#if HAVE_STRCPY_Z900_G5 ++# define STRCPY_Z900_G5 __strcpy_default ++#else ++# define STRCPY_Z900_G5 NULL ++#endif ++ ++#if HAVE_STRCPY_Z13 ++# define STRCPY_Z13 __strcpy_vx ++#else ++# define STRCPY_Z13 NULL ++#endif +diff --git a/sysdeps/s390/multiarch/Makefile b/sysdeps/s390/multiarch/Makefile +index 35ba223c5d4fb52f..50f7f0b78df723bb 100644 +--- a/sysdeps/s390/multiarch/Makefile ++++ b/sysdeps/s390/multiarch/Makefile +@@ -1,6 +1,5 @@ + ifeq ($(subdir),string) +-sysdep_routines += strcpy strcpy-vx \ +- stpcpy stpcpy-vx stpcpy-c \ ++sysdep_routines += stpcpy stpcpy-vx stpcpy-c \ + strncpy strncpy-vx \ + stpncpy stpncpy-vx stpncpy-c \ + strcat strcat-vx strcat-c \ +diff --git a/sysdeps/s390/multiarch/ifunc-impl-list.c b/sysdeps/s390/multiarch/ifunc-impl-list.c +index 680e5b738bfb7f32..1784372db9828463 100644 +--- a/sysdeps/s390/multiarch/ifunc-impl-list.c ++++ b/sysdeps/s390/multiarch/ifunc-impl-list.c +@@ -28,6 +28,7 @@ + #include + #include + #include ++#include + + /* Maximum number of IFUNC implementations. */ + #define MAX_IFUNC 3 +@@ -190,6 +191,18 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + ) + #endif /* HAVE_STRNLEN_IFUNC */ + ++#if HAVE_STRCPY_IFUNC ++ IFUNC_IMPL (i, name, strcpy, ++# if HAVE_STRCPY_Z13 ++ IFUNC_IMPL_ADD (array, i, strcpy, ++ dl_hwcap & HWCAP_S390_VX, STRCPY_Z13) ++# endif ++# if HAVE_STRCPY_Z900_G5 ++ IFUNC_IMPL_ADD (array, i, strcpy, 1, STRCPY_Z900_G5) ++# endif ++ ) ++#endif /* HAVE_STRCPY_IFUNC */ ++ + #ifdef HAVE_S390_VX_ASM_SUPPORT + + # define IFUNC_VX_IMPL(FUNC) \ +@@ -202,7 +215,6 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + + IFUNC_VX_IMPL (wcsnlen); + +- IFUNC_VX_IMPL (strcpy); + IFUNC_VX_IMPL (wcscpy); + + IFUNC_VX_IMPL (stpcpy); +diff --git a/sysdeps/s390/s390-32/multiarch/strcpy.c b/sysdeps/s390/s390-32/multiarch/strcpy.c +deleted file mode 100644 +index 6a22e31a03c8c1c4..0000000000000000 +--- a/sysdeps/s390/s390-32/multiarch/strcpy.c ++++ /dev/null +@@ -1,21 +0,0 @@ +-/* Multiple versions of strcpy. +- 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 +- . */ +- +-/* This wrapper-file is needed, because otherwise file +- sysdeps/s390/s390-[32|64]/strcpy.S will be used. */ +-#include +diff --git a/sysdeps/s390/s390-32/strcpy.S b/sysdeps/s390/s390-32/strcpy.S +deleted file mode 100644 +index d49136ee92b83378..0000000000000000 +--- a/sysdeps/s390/s390-32/strcpy.S ++++ /dev/null +@@ -1,36 +0,0 @@ +-/* strcpy - copy a string from source to destination. For IBM S390 +- This file is part of the GNU C Library. +- Copyright (C) 2000-2018 Free Software Foundation, Inc. +- Contributed by Martin Schwidefsky (schwidefsky@de.ibm.com). +- +- The GNU C Library is free software; you can redistribute it and/or +- modify it under the terms of the GNU Lesser General Public +- License as published by the Free Software Foundation; either +- version 2.1 of the License, or (at your option) any later version. +- +- The GNU C Library is distributed in the hope that it will be useful, +- but WITHOUT ANY WARRANTY; without even the implied warranty of +- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +- Lesser General Public License for more details. +- +- You should have received a copy of the GNU Lesser General Public +- License along with the GNU C Library; if not, see +- . */ +- +-/* +- * R2 = address of destination +- * R3 = address of source +- */ +- +-#include "sysdep.h" +-#include "asm-syntax.h" +- +- .text +-ENTRY(strcpy) +- slr %r0,%r0 +- lr %r1,%r2 +-0: mvst %r1,%r3 +- jo 0b +- br %r14 +-END(strcpy) +-libc_hidden_builtin_def (strcpy) +diff --git a/sysdeps/s390/s390-64/multiarch/strcpy.c b/sysdeps/s390/s390-64/multiarch/strcpy.c +deleted file mode 100644 +index 6a22e31a03c8c1c4..0000000000000000 +--- a/sysdeps/s390/s390-64/multiarch/strcpy.c ++++ /dev/null +@@ -1,21 +0,0 @@ +-/* Multiple versions of strcpy. +- 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 +- . */ +- +-/* This wrapper-file is needed, because otherwise file +- sysdeps/s390/s390-[32|64]/strcpy.S will be used. */ +-#include +diff --git a/sysdeps/s390/multiarch/strcpy-vx.S b/sysdeps/s390/strcpy-vx.S +similarity index 85% +rename from sysdeps/s390/multiarch/strcpy-vx.S +rename to sysdeps/s390/strcpy-vx.S +index 52197f57f7b5d5cf..844d23e4fee32c9b 100644 +--- a/sysdeps/s390/multiarch/strcpy-vx.S ++++ b/sysdeps/s390/strcpy-vx.S +@@ -16,13 +16,13 @@ + License along with the GNU C Library; if not, see + . */ + +-#if defined HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc) +- +-# include "sysdep.h" +-# include "asm-syntax.h" ++#include ++#include "sysdep.h" ++#include "asm-syntax.h" + + .text + ++#if HAVE_STRCPY_Z13 + /* char * strcpy (const char *dest, const char *src) + Copy string src to dest. + +@@ -36,7 +36,7 @@ + -v17=index of zero + -v18=part of src + */ +-ENTRY(__strcpy_vx) ++ENTRY(STRCPY_Z13) + .machine "z13" + .machinemode "zarch_nohighgprs" + +@@ -97,13 +97,13 @@ ENTRY(__strcpy_vx) + .Lfound_align: + vstl %v16,%r5,0(%r2) /* Copy characters including zero. */ + br %r14 +-END(__strcpy_vx) ++END(STRCPY_Z13) + +-/* Use mvst-strcpy-implementation as default implementation. */ +-# define strcpy __strcpy_c +-# undef libc_hidden_builtin_def +-# define libc_hidden_builtin_def(name) strong_alias(__strcpy_c, __GI_strcpy) +-#endif /* HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc) */ ++# if ! HAVE_STRCPY_IFUNC ++strong_alias (STRCPY_Z13, strcpy) ++# endif + +-/* Include mvst-strcpy-implementation in s390-32/s390-64 subdirectory. */ +-#include ++# if ! HAVE_STRCPY_Z900_G5 && defined SHARED && IS_IN (libc) ++strong_alias (STRCPY_Z13, __GI_strcpy) ++# endif ++#endif +diff --git a/sysdeps/s390/s390-64/strcpy.S b/sysdeps/s390/strcpy-z900.S +similarity index 66% +rename from sysdeps/s390/s390-64/strcpy.S +rename to sysdeps/s390/strcpy-z900.S +index 203c73c905d0d86c..42798b1fd5c51187 100644 +--- a/sysdeps/s390/s390-64/strcpy.S ++++ b/sysdeps/s390/strcpy-z900.S +@@ -1,4 +1,4 @@ +-/* strcpy - copy a string from source to destination. 64 bit S/390 version. ++/* strcpy - copy a string from source to destination. 64/31 bit S/390 version. + Copyright (C) 2001-2018 Free Software Foundation, Inc. + Contributed by Martin Schwidefsky (schwidefsky@de.ibm.com). + This file is part of the GNU C Library. +@@ -21,15 +21,36 @@ + %r2 = address of destination + %r3 = address of source. */ + ++#include + #include "sysdep.h" + #include "asm-syntax.h" + ++#if HAVE_STRCPY_Z900_G5 ++# if defined __s390x__ ++# define SLGR slgr ++# define LGR lgr ++# else ++# define SLGR slr ++# define LGR lr ++# endif /* ! defined __s390x__ */ ++ + .text +-ENTRY(strcpy) +- slgr %r0,%r0 +- lgr %r1,%r2 ++ENTRY(STRCPY_Z900_G5) ++ SLGR %r0,%r0 ++ LGR %r1,%r2 + 0: mvst %r1,%r3 + jo 0b + br %r14 +-END(strcpy) +-libc_hidden_builtin_def (strcpy) ++END(STRCPY_Z900_G5) ++ ++# undef SLGR ++# undef LGR ++ ++# if ! HAVE_STRCPY_IFUNC ++strong_alias (STRCPY_Z900_G5, strcpy) ++# endif ++ ++# if defined SHARED && IS_IN (libc) ++strong_alias (STRCPY_Z900_G5, __GI_strcpy) ++# endif ++#endif +diff --git a/sysdeps/s390/multiarch/strcpy.c b/sysdeps/s390/strcpy.c +similarity index 69% +rename from sysdeps/s390/multiarch/strcpy.c +rename to sysdeps/s390/strcpy.c +index 8f32a13f6730c427..f4e28e24c85b7162 100644 +--- a/sysdeps/s390/multiarch/strcpy.c ++++ b/sysdeps/s390/strcpy.c +@@ -16,12 +16,25 @@ + License along with the GNU C Library; if not, see + . */ + +-#if defined HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc) ++#include ++ ++#if HAVE_STRCPY_IFUNC + # define strcpy __redirect_strcpy + # include + # undef strcpy + # include + +-s390_vx_libc_ifunc2_redirected (__redirect_strcpy, __strcpy, strcpy) ++# if HAVE_STRCPY_Z900_G5 ++extern __typeof (__redirect_strcpy) STRCPY_Z900_G5 attribute_hidden; ++# endif ++ ++# if HAVE_STRCPY_Z13 ++extern __typeof (__redirect_strcpy) STRCPY_Z13 attribute_hidden; ++# endif + ++s390_libc_ifunc_expr (__redirect_strcpy, strcpy, ++ (HAVE_STRCPY_Z13 && (hwcap & HWCAP_S390_VX)) ++ ? STRCPY_Z13 ++ : STRCPY_DEFAULT ++ ) + #endif diff --git a/SOURCES/glibc-rh1659438-19.patch b/SOURCES/glibc-rh1659438-19.patch new file mode 100644 index 0000000..b80b640 --- /dev/null +++ b/SOURCES/glibc-rh1659438-19.patch @@ -0,0 +1,279 @@ +commit 970449311ded3cacb6058c96143dd4c057900589 +Author: Stefan Liebler +Date: Tue Dec 18 13:57:11 2018 +0100 + + S390: Refactor stpcpy ifunc handling. + + The ifunc handling for stpcpy is adjusted in order to omit ifunc + variants if those will never be used as the minimum architecture level + already supports newer CPUs by default. + Glibc internal calls will then also use the "newer" ifunc variant. + + ChangeLog: + + * sysdeps/s390/multiarch/Makefile + (sysdep_routines): Remove stpcpy variants. + * sysdeps/s390/Makefile (sysdep_routines): Add stpcpy variants. + * sysdeps/s390/multiarch/ifunc-impl-list.c + (__libc_ifunc_impl_list): Refactor ifunc handling for stpcpy. + * sysdeps/s390/multiarch/stpcpy-c.c: Move to ... + * sysdeps/s390/stpcpy-c.c: ... here and adjust ifunc handling. + * sysdeps/s390/multiarch/stpcpy-vx.S: Move to ... + * sysdeps/s390/stpcpy-vx.S: ... here and adjust ifunc handling. + * sysdeps/s390/multiarch/stpcpy.c: Move to ... + * sysdeps/s390/stpcpy.c: ... here and adjust ifunc handling. + * sysdeps/s390/ifunc-stpcpy.h: New file. + +diff --git a/sysdeps/s390/Makefile b/sysdeps/s390/Makefile +index e4191319531ecb01..b7e1bc8aecf2f8c9 100644 +--- a/sysdeps/s390/Makefile ++++ b/sysdeps/s390/Makefile +@@ -39,5 +39,6 @@ sysdep_routines += bzero memset memset-z900 \ + memmem memmem-vx memmem-c \ + strlen strlen-vx strlen-c \ + strnlen strnlen-vx strnlen-c \ +- strcpy strcpy-vx strcpy-z900 ++ strcpy strcpy-vx strcpy-z900 \ ++ stpcpy stpcpy-vx stpcpy-c + endif +diff --git a/sysdeps/s390/ifunc-stpcpy.h b/sysdeps/s390/ifunc-stpcpy.h +new file mode 100644 +index 0000000000000000..9a70cd7c8c4f4582 +--- /dev/null ++++ b/sysdeps/s390/ifunc-stpcpy.h +@@ -0,0 +1,52 @@ ++/* stpcpy variant information on S/390 version. ++ 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 ++ . */ ++ ++#if defined USE_MULTIARCH && IS_IN (libc) \ ++ && ! defined HAVE_S390_MIN_Z13_ZARCH_ASM_SUPPORT ++# define HAVE_STPCPY_IFUNC 1 ++#else ++# define HAVE_STPCPY_IFUNC 0 ++#endif ++ ++#ifdef HAVE_S390_VX_ASM_SUPPORT ++# define HAVE_STPCPY_IFUNC_AND_VX_SUPPORT HAVE_STPCPY_IFUNC ++#else ++# define HAVE_STPCPY_IFUNC_AND_VX_SUPPORT 0 ++#endif ++ ++#if defined HAVE_S390_MIN_Z13_ZARCH_ASM_SUPPORT ++# define STPCPY_DEFAULT STPCPY_Z13 ++# define HAVE_STPCPY_C 0 ++# define HAVE_STPCPY_Z13 1 ++#else ++# define STPCPY_DEFAULT STPCPY_C ++# define HAVE_STPCPY_C 1 ++# define HAVE_STPCPY_Z13 HAVE_STPCPY_IFUNC_AND_VX_SUPPORT ++#endif ++ ++#if HAVE_STPCPY_C ++# define STPCPY_C __stpcpy_c ++#else ++# define STPCPY_C NULL ++#endif ++ ++#if HAVE_STPCPY_Z13 ++# define STPCPY_Z13 __stpcpy_vx ++#else ++# define STPCPY_Z13 NULL ++#endif +diff --git a/sysdeps/s390/multiarch/Makefile b/sysdeps/s390/multiarch/Makefile +index 50f7f0b78df723bb..9517417dcbe1c701 100644 +--- a/sysdeps/s390/multiarch/Makefile ++++ b/sysdeps/s390/multiarch/Makefile +@@ -1,6 +1,5 @@ + ifeq ($(subdir),string) +-sysdep_routines += stpcpy stpcpy-vx stpcpy-c \ +- strncpy strncpy-vx \ ++sysdep_routines += strncpy strncpy-vx \ + stpncpy stpncpy-vx stpncpy-c \ + strcat strcat-vx strcat-c \ + strncat strncat-vx strncat-c \ +diff --git a/sysdeps/s390/multiarch/ifunc-impl-list.c b/sysdeps/s390/multiarch/ifunc-impl-list.c +index 1784372db9828463..678ed13833332f11 100644 +--- a/sysdeps/s390/multiarch/ifunc-impl-list.c ++++ b/sysdeps/s390/multiarch/ifunc-impl-list.c +@@ -29,6 +29,7 @@ + #include + #include + #include ++#include + + /* Maximum number of IFUNC implementations. */ + #define MAX_IFUNC 3 +@@ -203,6 +204,18 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + ) + #endif /* HAVE_STRCPY_IFUNC */ + ++#if HAVE_STPCPY_IFUNC ++ IFUNC_IMPL (i, name, stpcpy, ++# if HAVE_STPCPY_Z13 ++ IFUNC_IMPL_ADD (array, i, stpcpy, ++ dl_hwcap & HWCAP_S390_VX, STPCPY_Z13) ++# endif ++# if HAVE_STPCPY_C ++ IFUNC_IMPL_ADD (array, i, stpcpy, 1, STPCPY_C) ++# endif ++ ) ++#endif /* HAVE_STPCPY_IFUNC */ ++ + #ifdef HAVE_S390_VX_ASM_SUPPORT + + # define IFUNC_VX_IMPL(FUNC) \ +@@ -217,7 +230,6 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + + IFUNC_VX_IMPL (wcscpy); + +- IFUNC_VX_IMPL (stpcpy); + IFUNC_VX_IMPL (wcpcpy); + + IFUNC_VX_IMPL (strncpy); +diff --git a/sysdeps/s390/multiarch/stpcpy-c.c b/sysdeps/s390/stpcpy-c.c +similarity index 74% +rename from sysdeps/s390/multiarch/stpcpy-c.c +rename to sysdeps/s390/stpcpy-c.c +index 4a1c3e5832c9b544..76ec88462717799c 100644 +--- a/sysdeps/s390/multiarch/stpcpy-c.c ++++ b/sysdeps/s390/stpcpy-c.c +@@ -16,20 +16,25 @@ + License along with the GNU C Library; if not, see + . */ + +-#if defined HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc) +-# define STPCPY __stpcpy_c +-# undef weak_alias +-# define weak_alias(a, b) +-# ifdef SHARED +-# undef libc_hidden_def +-# define libc_hidden_def(name) \ ++#include ++ ++#if HAVE_STPCPY_C ++# if HAVE_STPCPY_IFUNC ++# define STPCPY STPCPY_C ++ ++# undef weak_alias ++# define weak_alias(a, b) ++ ++# if defined SHARED && IS_IN (libc) ++# undef libc_hidden_def ++# define libc_hidden_def(name) \ + __hidden_ver1 (__stpcpy_c, __GI___stpcpy, __stpcpy_c); +-# undef libc_hidden_builtin_def +-# define libc_hidden_builtin_def(name) \ ++# undef libc_hidden_builtin_def ++# define libc_hidden_builtin_def(name) \ + strong_alias (__stpcpy_c, __stpcpy_c_1); \ + __hidden_ver1 (__stpcpy_c_1, __GI_stpcpy, __stpcpy_c_1); +-# endif /* SHARED */ +- ++# endif ++# endif + + # include +-#endif /* HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc) */ ++#endif +diff --git a/sysdeps/s390/multiarch/stpcpy-vx.S b/sysdeps/s390/stpcpy-vx.S +similarity index 90% +rename from sysdeps/s390/multiarch/stpcpy-vx.S +rename to sysdeps/s390/stpcpy-vx.S +index 6c17def0fc35d60d..d2db02d0cd714d27 100644 +--- a/sysdeps/s390/multiarch/stpcpy-vx.S ++++ b/sysdeps/s390/stpcpy-vx.S +@@ -16,7 +16,9 @@ + License along with the GNU C Library; if not, see + . */ + +-#if defined HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc) ++#include ++ ++#if HAVE_STPCPY_Z13 + + # include "sysdep.h" + # include "asm-syntax.h" +@@ -36,7 +38,7 @@ + -v17=index of zero + -v18=part of src + */ +-ENTRY(__stpcpy_vx) ++ENTRY(STPCPY_Z13) + .machine "z13" + .machinemode "zarch_nohighgprs" + +@@ -100,5 +102,15 @@ ENTRY(__stpcpy_vx) + vstl %v16,%r5,0(%r2) /* Copy characters including zero. */ + la %r2,0(%r5,%r2) /* Return pointer to zero. */ + br %r14 +-END(__stpcpy_vx) +-#endif /* HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc) */ ++END(STPCPY_Z13) ++ ++# if ! HAVE_STPCPY_IFUNC ++strong_alias (STPCPY_Z13, __stpcpy) ++weak_alias (__stpcpy, stpcpy) ++# endif ++ ++# if ! HAVE_STPCPY_C && defined SHARED && IS_IN (libc) ++strong_alias (STPCPY_Z13, __GI_stpcpy) ++strong_alias (STPCPY_Z13, __GI___stpcpy) ++# endif ++#endif +diff --git a/sysdeps/s390/multiarch/stpcpy.c b/sysdeps/s390/stpcpy.c +similarity index 74% +rename from sysdeps/s390/multiarch/stpcpy.c +rename to sysdeps/s390/stpcpy.c +index 654f9dfbef512e34..670604e2de3806b7 100644 +--- a/sysdeps/s390/multiarch/stpcpy.c ++++ b/sysdeps/s390/stpcpy.c +@@ -16,7 +16,9 @@ + License along with the GNU C Library; if not, see + . */ + +-#if defined HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc) ++#include ++ ++#if HAVE_STPCPY_IFUNC + # define stpcpy __redirect_stpcpy + # define __stpcpy __redirect___stpcpy + /* Omit the stpcpy inline definitions because it would redefine stpcpy. */ +@@ -27,9 +29,18 @@ + # undef __stpcpy + # include + +-s390_vx_libc_ifunc_redirected (__redirect___stpcpy, __stpcpy); +-weak_alias (__stpcpy, stpcpy) ++# if HAVE_STPCPY_C ++extern __typeof (__redirect_stpcpy) STPCPY_C attribute_hidden; ++# endif + +-#else +-# include +-#endif /* !(defined HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc)) */ ++# if HAVE_STPCPY_Z13 ++extern __typeof (__redirect_stpcpy) STPCPY_Z13 attribute_hidden; ++# endif ++ ++s390_libc_ifunc_expr (__redirect___stpcpy, __stpcpy, ++ (HAVE_STPCPY_Z13 && (hwcap & HWCAP_S390_VX)) ++ ? STPCPY_Z13 ++ : STPCPY_DEFAULT ++ ) ++weak_alias (__stpcpy, stpcpy) ++#endif diff --git a/SOURCES/glibc-rh1659438-2.patch b/SOURCES/glibc-rh1659438-2.patch new file mode 100644 index 0000000..855686c --- /dev/null +++ b/SOURCES/glibc-rh1659438-2.patch @@ -0,0 +1,58 @@ +commit e8023f2685c9f97e72bbe9d2a9c968e0d8438371 +Author: Stefan Liebler +Date: Tue Dec 18 13:57:03 2018 +0100 + + S390: Use hwcap instead of dl_hwcap in ifunc-resolvers. + + The renaming of hwcap arguments in ifunc-resolvers is needed + in order to prepare for further commits which refactors + ifunc handling for memset, memcmp, and memcpy. Now you are able + to use s390_libc_ifunc_init which stores the stfle bits + within the expression for an ifunc-resolver generated by + s390_libc_ifunc_expr. + + ChangeLog: + + * sysdeps/s390/multiarch/ifunc-resolve.h + (s390_libc_ifunc_init, s390_libc_ifunc, + s390_vx_libc_ifunc2_redirected): Use hwcap instead of dl_hwcap. + +diff --git a/sysdeps/s390/multiarch/ifunc-resolve.h b/sysdeps/s390/multiarch/ifunc-resolve.h +index b42ed922fd27834b..b7e20abc59638251 100644 +--- a/sysdeps/s390/multiarch/ifunc-resolve.h ++++ b/sysdeps/s390/multiarch/ifunc-resolve.h +@@ -42,9 +42,9 @@ + : : "cc"); + #define s390_libc_ifunc_init() \ + unsigned long long stfle_bits = 0ULL; \ +- if (__glibc_likely((dl_hwcap & HWCAP_S390_STFLE) \ +- && (dl_hwcap & HWCAP_S390_ZARCH) \ +- && (dl_hwcap & HWCAP_S390_HIGH_GPRS))) \ ++ if (__glibc_likely ((hwcap & HWCAP_S390_STFLE) \ ++ && (hwcap & HWCAP_S390_ZARCH) \ ++ && (hwcap & HWCAP_S390_HIGH_GPRS))) \ + { \ + S390_STORE_STFLE (stfle_bits); \ + } +@@ -61,7 +61,7 @@ + : __glibc_likely (S390_IS_Z10 (stfle_bits)) \ + ? RESOLVERFUNC##_z10 \ + : RESOLVERFUNC##_default, \ +- unsigned long int dl_hwcap, s390_libc_ifunc_init); ++ unsigned long int hwcap, s390_libc_ifunc_init); + + #define s390_vx_libc_ifunc(FUNC) \ + s390_vx_libc_ifunc2_redirected(FUNC, FUNC, FUNC) +@@ -79,10 +79,10 @@ + extern __typeof (TYPE_FUNC) RESOLVERFUNC##_vx attribute_hidden; \ + extern __typeof (TYPE_FUNC) RESOLVERFUNC##_c attribute_hidden; \ + __ifunc (TYPE_FUNC, FUNC, \ +- (dl_hwcap & HWCAP_S390_VX) \ ++ (hwcap & HWCAP_S390_VX) \ + ? RESOLVERFUNC##_vx \ + : RESOLVERFUNC##_c, \ +- unsigned long int dl_hwcap, s390_vx_libc_ifunc_init); ++ unsigned long int hwcap, s390_vx_libc_ifunc_init); + + #define s390_libc_ifunc_expr_init() + #define s390_libc_ifunc_expr(TYPE_FUNC, FUNC, EXPR) \ diff --git a/SOURCES/glibc-rh1659438-20.patch b/SOURCES/glibc-rh1659438-20.patch new file mode 100644 index 0000000..855354d --- /dev/null +++ b/SOURCES/glibc-rh1659438-20.patch @@ -0,0 +1,378 @@ +commit d1bdbf380908c34f31ba145ec9afebade3f1418f +Author: Stefan Liebler +Date: Tue Dec 18 13:57:11 2018 +0100 + + S390: Refactor strncpy ifunc handling. + + The ifunc handling for strncpy is adjusted in order to omit ifunc + variants if those will never be used as the minimum architecture level + already supports newer CPUs by default. + Glibc internal calls will then also use the "newer" ifunc variant. + + Note: The fallback s390-32/s390-64 ifunc variants are now moved to + the strncpy-z900.S files. The s390-32/s390-64 files multiarch/strncpy.c + and strncpy.S are deleted. + + ChangeLog: + + * sysdeps/s390/multiarch/Makefile + (sysdep_routines): Remove strncpy variants. + * sysdeps/s390/Makefile (sysdep_routines): Add strncpy variants. + * sysdeps/s390/multiarch/ifunc-impl-list.c + (__libc_ifunc_impl_list): Refactor ifunc handling for strncpy. + * sysdeps/s390/multiarch/strncpy-vx.S: Move to ... + * sysdeps/s390/strncpy-vx.S: ... here and adjust ifunc handling. + * sysdeps/s390/multiarch/strncpy.c: Move to ... + * sysdeps/s390/strncpy.c: ... here and adjust ifunc handling. + * sysdeps/s390/ifunc-strncpy.h: New file. + * sysdeps/s390/s390-64/strncpy.S: Move to ... + * sysdeps/s390/s390-64/strncpy-z900.S: ... here + and adjust ifunc handling. + * sysdeps/s390/s390-32/strncpy.S: Move to ... + * sysdeps/s390/s390-32/strncpy-z900.S: ... here + and adjust ifunc handling. + * sysdeps/s390/s390-32/multiarch/strncpy.c: Delete file. + * sysdeps/s390/s390-64/multiarch/strncpy.c: Likewise. + +diff --git a/sysdeps/s390/Makefile b/sysdeps/s390/Makefile +index b7e1bc8aecf2f8c9..db060c81aade84ca 100644 +--- a/sysdeps/s390/Makefile ++++ b/sysdeps/s390/Makefile +@@ -40,5 +40,6 @@ sysdep_routines += bzero memset memset-z900 \ + strlen strlen-vx strlen-c \ + strnlen strnlen-vx strnlen-c \ + strcpy strcpy-vx strcpy-z900 \ +- stpcpy stpcpy-vx stpcpy-c ++ stpcpy stpcpy-vx stpcpy-c \ ++ strncpy strncpy-vx strncpy-z900 + endif +diff --git a/sysdeps/s390/ifunc-strncpy.h b/sysdeps/s390/ifunc-strncpy.h +new file mode 100644 +index 0000000000000000..31e87e93c529c443 +--- /dev/null ++++ b/sysdeps/s390/ifunc-strncpy.h +@@ -0,0 +1,52 @@ ++/* strncpy variant information on S/390 version. ++ 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 ++ . */ ++ ++#if defined USE_MULTIARCH && IS_IN (libc) \ ++ && ! defined HAVE_S390_MIN_Z13_ZARCH_ASM_SUPPORT ++# define HAVE_STRNCPY_IFUNC 1 ++#else ++# define HAVE_STRNCPY_IFUNC 0 ++#endif ++ ++#ifdef HAVE_S390_VX_ASM_SUPPORT ++# define HAVE_STRNCPY_IFUNC_AND_VX_SUPPORT HAVE_STRNCPY_IFUNC ++#else ++# define HAVE_STRNCPY_IFUNC_AND_VX_SUPPORT 0 ++#endif ++ ++#if defined HAVE_S390_MIN_Z13_ZARCH_ASM_SUPPORT ++# define STRNCPY_DEFAULT STRNCPY_Z13 ++# define HAVE_STRNCPY_Z900_G5 0 ++# define HAVE_STRNCPY_Z13 1 ++#else ++# define STRNCPY_DEFAULT STRNCPY_Z900_G5 ++# define HAVE_STRNCPY_Z900_G5 1 ++# define HAVE_STRNCPY_Z13 HAVE_STRNCPY_IFUNC_AND_VX_SUPPORT ++#endif ++ ++#if HAVE_STRNCPY_Z900_G5 ++# define STRNCPY_Z900_G5 __strncpy_default ++#else ++# define STRNCPY_Z900_G5 NULL ++#endif ++ ++#if HAVE_STRNCPY_Z13 ++# define STRNCPY_Z13 __strncpy_vx ++#else ++# define STRNCPY_Z13 NULL ++#endif +diff --git a/sysdeps/s390/multiarch/Makefile b/sysdeps/s390/multiarch/Makefile +index 9517417dcbe1c701..c5189b556cf3762d 100644 +--- a/sysdeps/s390/multiarch/Makefile ++++ b/sysdeps/s390/multiarch/Makefile +@@ -1,6 +1,5 @@ + ifeq ($(subdir),string) +-sysdep_routines += strncpy strncpy-vx \ +- stpncpy stpncpy-vx stpncpy-c \ ++sysdep_routines += stpncpy stpncpy-vx stpncpy-c \ + strcat strcat-vx strcat-c \ + strncat strncat-vx strncat-c \ + strcmp strcmp-vx \ +diff --git a/sysdeps/s390/multiarch/ifunc-impl-list.c b/sysdeps/s390/multiarch/ifunc-impl-list.c +index 678ed13833332f11..d598fc5c22050da2 100644 +--- a/sysdeps/s390/multiarch/ifunc-impl-list.c ++++ b/sysdeps/s390/multiarch/ifunc-impl-list.c +@@ -30,6 +30,7 @@ + #include + #include + #include ++#include + + /* Maximum number of IFUNC implementations. */ + #define MAX_IFUNC 3 +@@ -216,6 +217,19 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + ) + #endif /* HAVE_STPCPY_IFUNC */ + ++#if HAVE_STRNCPY_IFUNC ++ IFUNC_IMPL (i, name, strncpy, ++# if HAVE_STRNCPY_Z13 ++ IFUNC_IMPL_ADD (array, i, strncpy, ++ dl_hwcap & HWCAP_S390_VX, STRNCPY_Z13) ++# endif ++# if HAVE_STRNCPY_Z900_G5 ++ IFUNC_IMPL_ADD (array, i, strncpy, 1, STRNCPY_Z900_G5) ++# endif ++ ) ++#endif /* HAVE_STRNCPY_IFUNC */ ++ ++ + #ifdef HAVE_S390_VX_ASM_SUPPORT + + # define IFUNC_VX_IMPL(FUNC) \ +@@ -232,7 +246,6 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + + IFUNC_VX_IMPL (wcpcpy); + +- IFUNC_VX_IMPL (strncpy); + IFUNC_VX_IMPL (wcsncpy); + + IFUNC_VX_IMPL (stpncpy); +diff --git a/sysdeps/s390/s390-32/multiarch/strncpy.c b/sysdeps/s390/s390-32/multiarch/strncpy.c +deleted file mode 100644 +index 57f9df18d12c1959..0000000000000000 +--- a/sysdeps/s390/s390-32/multiarch/strncpy.c ++++ /dev/null +@@ -1,21 +0,0 @@ +-/* Multiple versions of strncpy. +- 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 +- . */ +- +-/* This wrapper-file is needed, because otherwise file +- sysdeps/s390/s390-[32|64]/strncpy.S will be used. */ +-#include +diff --git a/sysdeps/s390/s390-32/strncpy.S b/sysdeps/s390/s390-32/strncpy-z900.S +similarity index 89% +rename from sysdeps/s390/s390-32/strncpy.S +rename to sysdeps/s390/s390-32/strncpy-z900.S +index 9086eb1c707bdfb3..ebdaba015214bc59 100644 +--- a/sysdeps/s390/s390-32/strncpy.S ++++ b/sysdeps/s390/s390-32/strncpy-z900.S +@@ -24,10 +24,12 @@ + * R4 = max of bytes to copy + */ + ++#include + #include "sysdep.h" + #include "asm-syntax.h" + +-ENTRY(strncpy) ++#if HAVE_STRNCPY_Z900_G5 ++ENTRY(STRNCPY_Z900_G5) + .text + st %r2,24(%r15) # save dst pointer + slr %r2,%r3 # %r3 points to src, %r2+%r3 to dst +@@ -75,5 +77,13 @@ ENTRY(strncpy) + jo .L9 + .Lexit: l %r2,24(%r15) # return dst pointer + br %r14 +-END(strncpy) +-libc_hidden_builtin_def (strncpy) ++END(STRNCPY_Z900_G5) ++ ++# if ! HAVE_STRNCPY_IFUNC ++strong_alias (STRNCPY_Z900_G5, strncpy) ++# endif ++ ++# if defined SHARED && IS_IN (libc) ++strong_alias (STRNCPY_Z900_G5, __GI_strncpy) ++# endif ++#endif +diff --git a/sysdeps/s390/s390-64/multiarch/strncpy.c b/sysdeps/s390/s390-64/multiarch/strncpy.c +deleted file mode 100644 +index 57f9df18d12c1959..0000000000000000 +--- a/sysdeps/s390/s390-64/multiarch/strncpy.c ++++ /dev/null +@@ -1,21 +0,0 @@ +-/* Multiple versions of strncpy. +- 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 +- . */ +- +-/* This wrapper-file is needed, because otherwise file +- sysdeps/s390/s390-[32|64]/strncpy.S will be used. */ +-#include +diff --git a/sysdeps/s390/s390-64/strncpy.S b/sysdeps/s390/s390-64/strncpy-z900.S +similarity index 90% +rename from sysdeps/s390/s390-64/strncpy.S +rename to sysdeps/s390/s390-64/strncpy-z900.S +index be40aa32d5d9a2df..5732e6d83b5e8f30 100644 +--- a/sysdeps/s390/s390-64/strncpy.S ++++ b/sysdeps/s390/s390-64/strncpy-z900.S +@@ -23,10 +23,12 @@ + %r3 = address of source (src) + %r4 = max of bytes to copy. */ + ++#include + #include "sysdep.h" + #include "asm-syntax.h" + +-ENTRY(strncpy) ++#if HAVE_STRNCPY_Z900_G5 ++ENTRY(STRNCPY_Z900_G5) + .text + stg %r2,48(%r15) # save dst pointer + slgr %r2,%r3 # %r3 points to src, %r2+%r3 to dst +@@ -86,5 +88,13 @@ ENTRY(strncpy) + jo .L13 + .Lexit: lg %r2,48(%r15) # return dst pointer + br %r14 +-END(strncpy) +-libc_hidden_builtin_def (strncpy) ++END(STRNCPY_Z900_G5) ++ ++# if ! HAVE_STRNCPY_IFUNC ++strong_alias (STRNCPY_Z900_G5, strncpy) ++# endif ++ ++# if defined SHARED && IS_IN (libc) ++strong_alias (STRNCPY_Z900_G5, __GI_strncpy) ++# endif ++#endif +diff --git a/sysdeps/s390/multiarch/strncpy-vx.S b/sysdeps/s390/strncpy-vx.S +similarity index 93% +rename from sysdeps/s390/multiarch/strncpy-vx.S +rename to sysdeps/s390/strncpy-vx.S +index 2a37b7b84e0a2514..be09ddf092388c72 100644 +--- a/sysdeps/s390/multiarch/strncpy-vx.S ++++ b/sysdeps/s390/strncpy-vx.S +@@ -16,13 +16,13 @@ + License along with the GNU C Library; if not, see + . */ + +-#if defined HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc) +- +-# include "sysdep.h" +-# include "asm-syntax.h" ++#include ++#include "sysdep.h" ++#include "asm-syntax.h" + + .text + ++#if HAVE_STRNCPY_Z13 + /* char * strncpy (const char *dest, const char *src, size_t n) + Copy at most n characters of string src to dest. + +@@ -40,7 +40,7 @@ + -v18=part of src + -v31=register save area for r6, r7 + */ +-ENTRY(__strncpy_vx) ++ENTRY(STRNCPY_Z13) + .machine "z13" + .machinemode "zarch_nohighgprs" + +@@ -196,12 +196,13 @@ ENTRY(__strncpy_vx) + + vl %v16,0(%r5,%r3) /* Load s. */ + j .Llt64 +-END(__strncpy_vx) ++END(STRNCPY_Z13) + +-# define strncpy __strncpy_c +-# undef libc_hidden_builtin_def +-# define libc_hidden_builtin_def(name) strong_alias(__strncpy_c, __GI_strncpy) +-#endif /* HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc) */ ++# if ! HAVE_STRNCPY_IFUNC ++strong_alias (STRNCPY_Z13, strncpy) ++# endif + +-/* Include strncpy-implementation in s390-32/s390-64 subdirectory. */ +-#include ++# if ! HAVE_STRNCPY_Z900_G5 && defined SHARED && IS_IN (libc) ++strong_alias (STRNCPY_Z13, __GI_strncpy) ++# endif ++#endif +diff --git a/sysdeps/s390/multiarch/strncpy.c b/sysdeps/s390/strncpy.c +similarity index 71% +rename from sysdeps/s390/multiarch/strncpy.c +rename to sysdeps/s390/strncpy.c +index 2d4c456d96dad0d6..ec8a26471b6536e8 100644 +--- a/sysdeps/s390/multiarch/strncpy.c ++++ b/sysdeps/s390/strncpy.c +@@ -16,7 +16,9 @@ + License along with the GNU C Library; if not, see + . */ + +-#if defined HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc) ++#include ++ ++#if HAVE_STRNCPY_IFUNC + # define strncpy __redirect_strncpy + /* Omit the strncpy inline definitions because it would redefine strncpy. */ + # define __NO_STRING_INLINES +@@ -24,6 +26,17 @@ + # undef strncpy + # include + +-s390_vx_libc_ifunc2_redirected (__redirect_strncpy, __strncpy, strncpy); ++# if HAVE_STRNCPY_Z900_G5 ++extern __typeof (__redirect_strncpy) STRNCPY_Z900_G5 attribute_hidden; ++# endif ++ ++# if HAVE_STRNCPY_Z13 ++extern __typeof (__redirect_strncpy) STRNCPY_Z13 attribute_hidden; ++# endif + ++s390_libc_ifunc_expr (__redirect_strncpy, strncpy, ++ (HAVE_STRNCPY_Z13 && (hwcap & HWCAP_S390_VX)) ++ ? STRNCPY_Z13 ++ : STRNCPY_DEFAULT ++ ) + #endif diff --git a/SOURCES/glibc-rh1659438-21.patch b/SOURCES/glibc-rh1659438-21.patch new file mode 100644 index 0000000..91393ae --- /dev/null +++ b/SOURCES/glibc-rh1659438-21.patch @@ -0,0 +1,267 @@ +commit 25218822bdbfb49b8ea0f419e8a20d2b9bd47cd0 +Author: Stefan Liebler +Date: Tue Dec 18 13:57:11 2018 +0100 + + S390: Refactor stpncpy ifunc handling. + + The ifunc handling for stpncpy is adjusted in order to omit ifunc + variants if those will never be used as the minimum architecture level + already supports newer CPUs by default. + Glibc internal calls will then also use the "newer" ifunc variant. + + ChangeLog: + + * sysdeps/s390/multiarch/Makefile + (sysdep_routines): Remove stpncpy variants. + * sysdeps/s390/Makefile (sysdep_routines): Add stpncpy variants. + * sysdeps/s390/multiarch/ifunc-impl-list.c + (__libc_ifunc_impl_list): Refactor ifunc handling for stpncpy. + * sysdeps/s390/multiarch/stpncpy-c.c: Move to ... + * sysdeps/s390/stpncpy-c.c: ... here and adjust ifunc handling. + * sysdeps/s390/multiarch/stpncpy-vx.S: Move to ... + * sysdeps/s390/stpncpy-vx.S: ... here and adjust ifunc handling. + * sysdeps/s390/multiarch/stpncpy.c: Move to ... + * sysdeps/s390/stpncpy.c: ... here and adjust ifunc handling. + * sysdeps/s390/ifunc-stpncpy.h: New file. + +diff --git a/sysdeps/s390/Makefile b/sysdeps/s390/Makefile +index db060c81aade84ca..a9882b3996c30322 100644 +--- a/sysdeps/s390/Makefile ++++ b/sysdeps/s390/Makefile +@@ -41,5 +41,6 @@ sysdep_routines += bzero memset memset-z900 \ + strnlen strnlen-vx strnlen-c \ + strcpy strcpy-vx strcpy-z900 \ + stpcpy stpcpy-vx stpcpy-c \ +- strncpy strncpy-vx strncpy-z900 ++ strncpy strncpy-vx strncpy-z900 \ ++ stpncpy stpncpy-vx stpncpy-c + endif +diff --git a/sysdeps/s390/ifunc-stpncpy.h b/sysdeps/s390/ifunc-stpncpy.h +new file mode 100644 +index 0000000000000000..46e57334e8439c1c +--- /dev/null ++++ b/sysdeps/s390/ifunc-stpncpy.h +@@ -0,0 +1,52 @@ ++/* stpncpy variant information on S/390 version. ++ 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 ++ . */ ++ ++#if defined USE_MULTIARCH && IS_IN (libc) \ ++ && ! defined HAVE_S390_MIN_Z13_ZARCH_ASM_SUPPORT ++# define HAVE_STPNCPY_IFUNC 1 ++#else ++# define HAVE_STPNCPY_IFUNC 0 ++#endif ++ ++#ifdef HAVE_S390_VX_ASM_SUPPORT ++# define HAVE_STPNCPY_IFUNC_AND_VX_SUPPORT HAVE_STPNCPY_IFUNC ++#else ++# define HAVE_STPNCPY_IFUNC_AND_VX_SUPPORT 0 ++#endif ++ ++#if defined HAVE_S390_MIN_Z13_ZARCH_ASM_SUPPORT ++# define STPNCPY_DEFAULT STPNCPY_Z13 ++# define HAVE_STPNCPY_C 0 ++# define HAVE_STPNCPY_Z13 1 ++#else ++# define STPNCPY_DEFAULT STPNCPY_C ++# define HAVE_STPNCPY_C 1 ++# define HAVE_STPNCPY_Z13 HAVE_STPNCPY_IFUNC_AND_VX_SUPPORT ++#endif ++ ++#if HAVE_STPNCPY_C ++# define STPNCPY_C __stpncpy_c ++#else ++# define STPNCPY_C NULL ++#endif ++ ++#if HAVE_STPNCPY_Z13 ++# define STPNCPY_Z13 __stpncpy_vx ++#else ++# define STPNCPY_Z13 NULL ++#endif +diff --git a/sysdeps/s390/multiarch/Makefile b/sysdeps/s390/multiarch/Makefile +index c5189b556cf3762d..3d97d21da1fc852b 100644 +--- a/sysdeps/s390/multiarch/Makefile ++++ b/sysdeps/s390/multiarch/Makefile +@@ -1,6 +1,5 @@ + ifeq ($(subdir),string) +-sysdep_routines += stpncpy stpncpy-vx stpncpy-c \ +- strcat strcat-vx strcat-c \ ++sysdep_routines += strcat strcat-vx strcat-c \ + strncat strncat-vx strncat-c \ + strcmp strcmp-vx \ + strncmp strncmp-vx strncmp-c \ +diff --git a/sysdeps/s390/multiarch/ifunc-impl-list.c b/sysdeps/s390/multiarch/ifunc-impl-list.c +index d598fc5c22050da2..021e9f247fff44df 100644 +--- a/sysdeps/s390/multiarch/ifunc-impl-list.c ++++ b/sysdeps/s390/multiarch/ifunc-impl-list.c +@@ -31,6 +31,7 @@ + #include + #include + #include ++#include + + /* Maximum number of IFUNC implementations. */ + #define MAX_IFUNC 3 +@@ -229,6 +230,18 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + ) + #endif /* HAVE_STRNCPY_IFUNC */ + ++#if HAVE_STPNCPY_IFUNC ++ IFUNC_IMPL (i, name, stpncpy, ++# if HAVE_STPNCPY_Z13 ++ IFUNC_IMPL_ADD (array, i, stpncpy, ++ dl_hwcap & HWCAP_S390_VX, STPNCPY_Z13) ++# endif ++# if HAVE_STPNCPY_C ++ IFUNC_IMPL_ADD (array, i, stpncpy, 1, STPNCPY_C) ++# endif ++ ) ++#endif /* HAVE_STPNCPY_IFUNC */ ++ + + #ifdef HAVE_S390_VX_ASM_SUPPORT + +@@ -248,7 +261,6 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + + IFUNC_VX_IMPL (wcsncpy); + +- IFUNC_VX_IMPL (stpncpy); + IFUNC_VX_IMPL (wcpncpy); + + IFUNC_VX_IMPL (strcat); +diff --git a/sysdeps/s390/multiarch/stpncpy-c.c b/sysdeps/s390/stpncpy-c.c +similarity index 74% +rename from sysdeps/s390/multiarch/stpncpy-c.c +rename to sysdeps/s390/stpncpy-c.c +index 45e50aa9e7df0b5e..e5d1ae867562da6c 100644 +--- a/sysdeps/s390/multiarch/stpncpy-c.c ++++ b/sysdeps/s390/stpncpy-c.c +@@ -16,13 +16,18 @@ + License along with the GNU C Library; if not, see + . */ + +-#if defined HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc) +-# define STPNCPY __stpncpy_c +-# ifdef SHARED +-# undef libc_hidden_def +-# define libc_hidden_def(name) \ +- __hidden_ver1 (__stpncpy_c, __GI___stpncpy, __stpncpy_c); +-# endif /* SHARED */ ++#include ++ ++#if HAVE_STPNCPY_C ++# if HAVE_STPNCPY_IFUNC ++# define STPNCPY STPNCPY_C ++ ++# if defined SHARED && IS_IN (libc) ++# undef libc_hidden_def ++# define libc_hidden_def(name) \ ++ __hidden_ver1 (__stpncpy_c, __GI___stpncpy, __stpncpy_c); ++# endif ++# endif + + # include +-#endif /* HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc) */ ++#endif +diff --git a/sysdeps/s390/multiarch/stpncpy-vx.S b/sysdeps/s390/stpncpy-vx.S +similarity index 95% +rename from sysdeps/s390/multiarch/stpncpy-vx.S +rename to sysdeps/s390/stpncpy-vx.S +index 922bd7a355a2d8a0..3dccc10be3b58d8d 100644 +--- a/sysdeps/s390/multiarch/stpncpy-vx.S ++++ b/sysdeps/s390/stpncpy-vx.S +@@ -16,7 +16,9 @@ + License along with the GNU C Library; if not, see + . */ + +-#if defined HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc) ++#include ++ ++#if HAVE_STPNCPY_Z13 + + # include "sysdep.h" + # include "asm-syntax.h" +@@ -38,7 +40,7 @@ + -%r6 = loaded bytes + -%r7 = border, tmp + */ +-ENTRY(__stpncpy_vx) ++ENTRY(STPNCPY_Z13) + .machine "z13" + .machinemode "zarch_nohighgprs" + +@@ -196,5 +198,14 @@ ENTRY(__stpncpy_vx) + + vl %v16,0(%r5,%r3) /* Load s. */ + j .Llt64 +-END(__stpncpy_vx) +-#endif /* HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc) */ ++END(STPNCPY_Z13) ++ ++# if ! HAVE_STPNCPY_IFUNC ++strong_alias (STPNCPY_Z13, __stpncpy) ++weak_alias (__stpncpy, stpncpy) ++# endif ++ ++# if ! HAVE_STPNCPY_C && defined SHARED && IS_IN (libc) ++strong_alias (STPNCPY_Z13, __GI___stpncpy) ++# endif ++#endif +diff --git a/sysdeps/s390/multiarch/stpncpy.c b/sysdeps/s390/stpncpy.c +similarity index 70% +rename from sysdeps/s390/multiarch/stpncpy.c +rename to sysdeps/s390/stpncpy.c +index f7f9d51a50db47d7..250dc68ed19bf6d9 100644 +--- a/sysdeps/s390/multiarch/stpncpy.c ++++ b/sysdeps/s390/stpncpy.c +@@ -16,7 +16,9 @@ + License along with the GNU C Library; if not, see + . */ + +-#if defined HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc) ++#include ++ ++#if HAVE_STPNCPY_IFUNC + # define stpncpy __redirect_stpncpy + # define __stpncpy __redirect___stpncpy + # include +@@ -24,9 +26,18 @@ + # undef __stpncpy + # include + +-s390_vx_libc_ifunc_redirected (__redirect___stpncpy, __stpncpy) +-weak_alias (__stpncpy, stpncpy) ++# if HAVE_STPNCPY_C ++extern __typeof (__redirect_stpncpy) STPNCPY_C attribute_hidden; ++# endif + +-#else +-# include +-#endif /* !(defined HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc)) */ ++# if HAVE_STPNCPY_Z13 ++extern __typeof (__redirect_stpncpy) STPNCPY_Z13 attribute_hidden; ++# endif ++ ++s390_libc_ifunc_expr (__redirect___stpncpy, __stpncpy, ++ (HAVE_STPNCPY_Z13 && (hwcap & HWCAP_S390_VX)) ++ ? STPNCPY_Z13 ++ : STPNCPY_DEFAULT ++ ) ++weak_alias (__stpncpy, stpncpy) ++#endif diff --git a/SOURCES/glibc-rh1659438-22.patch b/SOURCES/glibc-rh1659438-22.patch new file mode 100644 index 0000000..3e74480 --- /dev/null +++ b/SOURCES/glibc-rh1659438-22.patch @@ -0,0 +1,259 @@ +commit 8e5a0afbbf0a96fb873e27aa064c9bacc9cfd9c6 +Author: Stefan Liebler +Date: Tue Dec 18 13:57:12 2018 +0100 + + S390: Refactor strcat ifunc handling. + + The ifunc handling for strcat is adjusted in order to omit ifunc + variants if those will never be used as the minimum architecture level + already supports newer CPUs by default. + Glibc internal calls will then also use the "newer" ifunc variant. + + ChangeLog: + + * sysdeps/s390/multiarch/Makefile + (sysdep_routines): Remove strcat variants. + * sysdeps/s390/Makefile (sysdep_routines): Add strcat variants. + * sysdeps/s390/multiarch/ifunc-impl-list.c + (__libc_ifunc_impl_list): Refactor ifunc handling for strcat. + * sysdeps/s390/multiarch/strcat-c.c: Move to ... + * sysdeps/s390/strcat-c.c: ... here and adjust ifunc handling. + * sysdeps/s390/multiarch/strcat-vx.S: Move to ... + * sysdeps/s390/strcat-vx.S: ... here and adjust ifunc handling. + * sysdeps/s390/multiarch/strcat.c: Move to ... + * sysdeps/s390/strcat.c: ... here and adjust ifunc handling. + * sysdeps/s390/ifunc-strcat.h: New file. + +diff --git a/sysdeps/s390/Makefile b/sysdeps/s390/Makefile +index a9882b3996c30322..de2d5e5652dde412 100644 +--- a/sysdeps/s390/Makefile ++++ b/sysdeps/s390/Makefile +@@ -42,5 +42,6 @@ sysdep_routines += bzero memset memset-z900 \ + strcpy strcpy-vx strcpy-z900 \ + stpcpy stpcpy-vx stpcpy-c \ + strncpy strncpy-vx strncpy-z900 \ +- stpncpy stpncpy-vx stpncpy-c ++ stpncpy stpncpy-vx stpncpy-c \ ++ strcat strcat-vx strcat-c + endif +diff --git a/sysdeps/s390/ifunc-strcat.h b/sysdeps/s390/ifunc-strcat.h +new file mode 100644 +index 0000000000000000..6fd2f7dd31fff64f +--- /dev/null ++++ b/sysdeps/s390/ifunc-strcat.h +@@ -0,0 +1,52 @@ ++/* strcat variant information on S/390 version. ++ 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 ++ . */ ++ ++#if defined USE_MULTIARCH && IS_IN (libc) \ ++ && ! defined HAVE_S390_MIN_Z13_ZARCH_ASM_SUPPORT ++# define HAVE_STRCAT_IFUNC 1 ++#else ++# define HAVE_STRCAT_IFUNC 0 ++#endif ++ ++#ifdef HAVE_S390_VX_ASM_SUPPORT ++# define HAVE_STRCAT_IFUNC_AND_VX_SUPPORT HAVE_STRCAT_IFUNC ++#else ++# define HAVE_STRCAT_IFUNC_AND_VX_SUPPORT 0 ++#endif ++ ++#if defined HAVE_S390_MIN_Z13_ZARCH_ASM_SUPPORT ++# define STRCAT_DEFAULT STRCAT_Z13 ++# define HAVE_STRCAT_C 0 ++# define HAVE_STRCAT_Z13 1 ++#else ++# define STRCAT_DEFAULT STRCAT_C ++# define HAVE_STRCAT_C 1 ++# define HAVE_STRCAT_Z13 HAVE_STRCAT_IFUNC_AND_VX_SUPPORT ++#endif ++ ++#if HAVE_STRCAT_C ++# define STRCAT_C __strcat_c ++#else ++# define STRCAT_C NULL ++#endif ++ ++#if HAVE_STRCAT_Z13 ++# define STRCAT_Z13 __strcat_vx ++#else ++# define STRCAT_Z13 NULL ++#endif +diff --git a/sysdeps/s390/multiarch/Makefile b/sysdeps/s390/multiarch/Makefile +index 3d97d21da1fc852b..9b66237aaf9eb47e 100644 +--- a/sysdeps/s390/multiarch/Makefile ++++ b/sysdeps/s390/multiarch/Makefile +@@ -1,6 +1,5 @@ + ifeq ($(subdir),string) +-sysdep_routines += strcat strcat-vx strcat-c \ +- strncat strncat-vx strncat-c \ ++sysdep_routines += strncat strncat-vx strncat-c \ + strcmp strcmp-vx \ + strncmp strncmp-vx strncmp-c \ + strchr strchr-vx strchr-c \ +diff --git a/sysdeps/s390/multiarch/ifunc-impl-list.c b/sysdeps/s390/multiarch/ifunc-impl-list.c +index 021e9f247fff44df..1b7f3df3a3cfe561 100644 +--- a/sysdeps/s390/multiarch/ifunc-impl-list.c ++++ b/sysdeps/s390/multiarch/ifunc-impl-list.c +@@ -32,6 +32,7 @@ + #include + #include + #include ++#include + + /* Maximum number of IFUNC implementations. */ + #define MAX_IFUNC 3 +@@ -242,6 +243,17 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + ) + #endif /* HAVE_STPNCPY_IFUNC */ + ++#if HAVE_STRCAT_IFUNC ++ IFUNC_IMPL (i, name, strcat, ++# if HAVE_STRCAT_Z13 ++ IFUNC_IMPL_ADD (array, i, strcat, ++ dl_hwcap & HWCAP_S390_VX, STRCAT_Z13) ++# endif ++# if HAVE_STRCAT_C ++ IFUNC_IMPL_ADD (array, i, strcat, 1, STRCAT_C) ++# endif ++ ) ++#endif /* HAVE_STRCAT_IFUNC */ + + #ifdef HAVE_S390_VX_ASM_SUPPORT + +@@ -263,7 +275,6 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + + IFUNC_VX_IMPL (wcpncpy); + +- IFUNC_VX_IMPL (strcat); + IFUNC_VX_IMPL (wcscat); + + IFUNC_VX_IMPL (strncat); +diff --git a/sysdeps/s390/multiarch/strcat-c.c b/sysdeps/s390/strcat-c.c +similarity index 73% +rename from sysdeps/s390/multiarch/strcat-c.c +rename to sysdeps/s390/strcat-c.c +index f871faa7b563e74b..7accc6c7ef80ecf2 100644 +--- a/sysdeps/s390/multiarch/strcat-c.c ++++ b/sysdeps/s390/strcat-c.c +@@ -16,13 +16,17 @@ + License along with the GNU C Library; if not, see + . */ + +-#if defined HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc) +-# define STRCAT __strcat_c +-# ifdef SHARED +-# undef libc_hidden_builtin_def +-# define libc_hidden_builtin_def(name) \ +- __hidden_ver1 (__strcat_c, __GI_strcat, __strcat_c); +-# endif /* SHARED */ ++#include ++ ++#if HAVE_STRCAT_C ++# if HAVE_STRCAT_IFUNC ++# define STRCAT STRCAT_C ++# if defined SHARED && IS_IN (libc) ++# undef libc_hidden_builtin_def ++# define libc_hidden_builtin_def(name) \ ++ __hidden_ver1 (__strcat_c, __GI_strcat, __strcat_c); ++# endif ++# endif + + # include +-#endif /* HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc) */ ++#endif +diff --git a/sysdeps/s390/multiarch/strcat-vx.S b/sysdeps/s390/strcat-vx.S +similarity index 94% +rename from sysdeps/s390/multiarch/strcat-vx.S +rename to sysdeps/s390/strcat-vx.S +index 3abbbcccedad0eb4..218e301f10c6abe3 100644 +--- a/sysdeps/s390/multiarch/strcat-vx.S ++++ b/sysdeps/s390/strcat-vx.S +@@ -16,7 +16,8 @@ + License along with the GNU C Library; if not, see + . */ + +-#if defined HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc) ++#include ++#if HAVE_STRCAT_Z13 + + # include "sysdep.h" + # include "asm-syntax.h" +@@ -37,7 +38,7 @@ + -v17=index of zero + -v18=part of src + */ +-ENTRY(__strcat_vx) ++ENTRY(STRCAT_Z13) + .machine "z13" + .machinemode "zarch_nohighgprs" + +@@ -157,5 +158,13 @@ ENTRY(__strcat_vx) + vstl %v16,%r5,0(%r2) /* Copy characters including zero. */ + lgr %r2,%r0 /* Load saved dest-ptr. */ + br %r14 +-END(__strcat_vx) +-#endif /* HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc) */ ++END(STRCAT_Z13) ++ ++# if ! HAVE_STRCAT_IFUNC ++strong_alias (STRCAT_Z13, strcat) ++# endif ++ ++# if ! HAVE_STRCAT_C && defined SHARED && IS_IN (libc) ++strong_alias (STRCAT_Z13, __GI_strcat) ++# endif ++#endif +diff --git a/sysdeps/s390/multiarch/strcat.c b/sysdeps/s390/strcat.c +similarity index 69% +rename from sysdeps/s390/multiarch/strcat.c +rename to sysdeps/s390/strcat.c +index 7d4126b44f23679a..d378519c8af59620 100644 +--- a/sysdeps/s390/multiarch/strcat.c ++++ b/sysdeps/s390/strcat.c +@@ -16,14 +16,25 @@ + License along with the GNU C Library; if not, see + . */ + +-#if defined HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc) ++#include ++ ++#if HAVE_STRCAT_IFUNC + # define strcat __redirect_strcat + # include + # undef strcat + # include + +-s390_vx_libc_ifunc2_redirected (__redirect_strcat, __strcat, strcat) ++# if HAVE_STRCAT_C ++extern __typeof (__redirect_strcat) STRCAT_C attribute_hidden; ++# endif ++ ++# if HAVE_STRCAT_Z13 ++extern __typeof (__redirect_strcat) STRCAT_Z13 attribute_hidden; ++# endif + +-#else +-# include +-#endif /* !(defined HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc)) */ ++s390_libc_ifunc_expr (__redirect_strcat, strcat, ++ (HAVE_STRCAT_Z13 && (hwcap & HWCAP_S390_VX)) ++ ? STRCAT_Z13 ++ : STRCAT_DEFAULT ++ ) ++#endif diff --git a/SOURCES/glibc-rh1659438-23.patch b/SOURCES/glibc-rh1659438-23.patch new file mode 100644 index 0000000..46f3173 --- /dev/null +++ b/SOURCES/glibc-rh1659438-23.patch @@ -0,0 +1,252 @@ +commit b935335155d65971fe2a54e32c0eb74303d4e4fc +Author: Stefan Liebler +Date: Tue Dec 18 13:57:12 2018 +0100 + + S390: Refactor strncat ifunc handling. + + The ifunc handling for strncat is adjusted in order to omit ifunc + variants if those will never be used as the minimum architecture level + already supports newer CPUs by default. + Glibc internal calls will then also use the "newer" ifunc variant. + + ChangeLog: + + * sysdeps/s390/multiarch/Makefile + (sysdep_routines): Remove strncat variants. + * sysdeps/s390/Makefile (sysdep_routines): Add strncat variants. + * sysdeps/s390/multiarch/ifunc-impl-list.c + (__libc_ifunc_impl_list): Refactor ifunc handling for strncat. + * sysdeps/s390/multiarch/strncat-c.c: Move to ... + * sysdeps/s390/strncat-c.c: ... here and adjust ifunc handling. + * sysdeps/s390/multiarch/strncat-vx.S: Move to ... + * sysdeps/s390/strncat-vx.S: ... here and adjust ifunc handling. + * sysdeps/s390/multiarch/strncat.c: Move to ... + * sysdeps/s390/strncat.c: ... here and adjust ifunc handling. + * sysdeps/s390/ifunc-strncat.h: New file. + +diff --git a/sysdeps/s390/Makefile b/sysdeps/s390/Makefile +index de2d5e5652dde412..cb5dc1d4f95fd11c 100644 +--- a/sysdeps/s390/Makefile ++++ b/sysdeps/s390/Makefile +@@ -43,5 +43,6 @@ sysdep_routines += bzero memset memset-z900 \ + stpcpy stpcpy-vx stpcpy-c \ + strncpy strncpy-vx strncpy-z900 \ + stpncpy stpncpy-vx stpncpy-c \ +- strcat strcat-vx strcat-c ++ strcat strcat-vx strcat-c \ ++ strncat strncat-vx strncat-c + endif +diff --git a/sysdeps/s390/ifunc-strncat.h b/sysdeps/s390/ifunc-strncat.h +new file mode 100644 +index 0000000000000000..bb164dcc32905b18 +--- /dev/null ++++ b/sysdeps/s390/ifunc-strncat.h +@@ -0,0 +1,52 @@ ++/* strncat variant information on S/390 version. ++ 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 ++ . */ ++ ++#if defined USE_MULTIARCH && IS_IN (libc) \ ++ && ! defined HAVE_S390_MIN_Z13_ZARCH_ASM_SUPPORT ++# define HAVE_STRNCAT_IFUNC 1 ++#else ++# define HAVE_STRNCAT_IFUNC 0 ++#endif ++ ++#ifdef HAVE_S390_VX_ASM_SUPPORT ++# define HAVE_STRNCAT_IFUNC_AND_VX_SUPPORT HAVE_STRNCAT_IFUNC ++#else ++# define HAVE_STRNCAT_IFUNC_AND_VX_SUPPORT 0 ++#endif ++ ++#if defined HAVE_S390_MIN_Z13_ZARCH_ASM_SUPPORT ++# define STRNCAT_DEFAULT STRNCAT_Z13 ++# define HAVE_STRNCAT_C 0 ++# define HAVE_STRNCAT_Z13 1 ++#else ++# define STRNCAT_DEFAULT STRNCAT_C ++# define HAVE_STRNCAT_C 1 ++# define HAVE_STRNCAT_Z13 HAVE_STRNCAT_IFUNC_AND_VX_SUPPORT ++#endif ++ ++#if HAVE_STRNCAT_C ++# define STRNCAT_C __strncat_c ++#else ++# define STRNCAT_C NULL ++#endif ++ ++#if HAVE_STRNCAT_Z13 ++# define STRNCAT_Z13 __strncat_vx ++#else ++# define STRNCAT_Z13 NULL ++#endif +diff --git a/sysdeps/s390/multiarch/Makefile b/sysdeps/s390/multiarch/Makefile +index 9b66237aaf9eb47e..24be3eac5131fd4a 100644 +--- a/sysdeps/s390/multiarch/Makefile ++++ b/sysdeps/s390/multiarch/Makefile +@@ -1,6 +1,5 @@ + ifeq ($(subdir),string) +-sysdep_routines += strncat strncat-vx strncat-c \ +- strcmp strcmp-vx \ ++sysdep_routines += strcmp strcmp-vx \ + strncmp strncmp-vx strncmp-c \ + strchr strchr-vx strchr-c \ + strchrnul strchrnul-vx strchrnul-c \ +diff --git a/sysdeps/s390/multiarch/ifunc-impl-list.c b/sysdeps/s390/multiarch/ifunc-impl-list.c +index 1b7f3df3a3cfe561..3abcaf08e0ccd385 100644 +--- a/sysdeps/s390/multiarch/ifunc-impl-list.c ++++ b/sysdeps/s390/multiarch/ifunc-impl-list.c +@@ -33,6 +33,7 @@ + #include + #include + #include ++#include + + /* Maximum number of IFUNC implementations. */ + #define MAX_IFUNC 3 +@@ -255,6 +256,18 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + ) + #endif /* HAVE_STRCAT_IFUNC */ + ++#if HAVE_STRNCAT_IFUNC ++ IFUNC_IMPL (i, name, strncat, ++# if HAVE_STRNCAT_Z13 ++ IFUNC_IMPL_ADD (array, i, strncat, ++ dl_hwcap & HWCAP_S390_VX, STRNCAT_Z13) ++# endif ++# if HAVE_STRNCAT_C ++ IFUNC_IMPL_ADD (array, i, strncat, 1, STRNCAT_C) ++# endif ++ ) ++#endif /* HAVE_STRNCAT_IFUNC */ ++ + #ifdef HAVE_S390_VX_ASM_SUPPORT + + # define IFUNC_VX_IMPL(FUNC) \ +@@ -277,7 +290,6 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + + IFUNC_VX_IMPL (wcscat); + +- IFUNC_VX_IMPL (strncat); + IFUNC_VX_IMPL (wcsncat); + + IFUNC_VX_IMPL (strcmp); +diff --git a/sysdeps/s390/multiarch/strncat-c.c b/sysdeps/s390/strncat-c.c +similarity index 86% +rename from sysdeps/s390/multiarch/strncat-c.c +rename to sysdeps/s390/strncat-c.c +index 9e6c245ccbbc2e23..86df89887c7b6293 100644 +--- a/sysdeps/s390/multiarch/strncat-c.c ++++ b/sysdeps/s390/strncat-c.c +@@ -16,8 +16,12 @@ + License along with the GNU C Library; if not, see + . */ + +-#if defined HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc) +-# define STRNCAT __strncat_c +-# define STRNCAT_PRIMARY ++#include ++ ++#if HAVE_STRNCAT_C ++# if HAVE_STRNCAT_IFUNC ++# define STRNCAT STRNCAT_C ++# define STRNCAT_PRIMARY ++# endif + # include + #endif +diff --git a/sysdeps/s390/multiarch/strncat-vx.S b/sysdeps/s390/strncat-vx.S +similarity index 94% +rename from sysdeps/s390/multiarch/strncat-vx.S +rename to sysdeps/s390/strncat-vx.S +index e6584d0f438f0e38..76345e7dd702dd85 100644 +--- a/sysdeps/s390/multiarch/strncat-vx.S ++++ b/sysdeps/s390/strncat-vx.S +@@ -16,7 +16,8 @@ + License along with the GNU C Library; if not, see + . */ + +-#if defined HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc) ++#include ++#if HAVE_STRNCAT_Z13 + + # include "sysdep.h" + # include "asm-syntax.h" +@@ -40,7 +41,7 @@ + -v18=part of src + -v31=register save area for r6, r7 + */ +-ENTRY(__strncat_vx) ++ENTRY(STRNCAT_Z13) + .machine "z13" + .machinemode "zarch_nohighgprs" + +@@ -235,5 +236,17 @@ ENTRY(__strncat_vx) + + vl %v16,0(%r5,%r3) /* Load s. */ + j .Lcpy_lt64 +-END(__strncat_vx) +-#endif /* HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc) */ ++END(STRNCAT_Z13) ++ ++# if ! HAVE_STRNCAT_IFUNC ++strong_alias (STRNCAT_Z13, strncat) ++# endif ++ ++# if ! HAVE_STRNCAT_C ++/* See string/strncat.c and define STRNCAT_PRIMARY. */ ++strong_alias (STRNCAT_Z13, __strncat) ++# if defined SHARED && IS_IN (libc) ++strong_alias (__strncat, __GI___strncat) ++# endif ++# endif ++#endif +diff --git a/sysdeps/s390/multiarch/strncat.c b/sysdeps/s390/strncat.c +similarity index 69% +rename from sysdeps/s390/multiarch/strncat.c +rename to sysdeps/s390/strncat.c +index 94b8dffa85420cfa..b4b3656c5ae9c535 100644 +--- a/sysdeps/s390/multiarch/strncat.c ++++ b/sysdeps/s390/strncat.c +@@ -16,12 +16,23 @@ + License along with the GNU C Library; if not, see + . */ + +-#if defined HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc) ++#include ++ ++#if HAVE_STRNCAT_IFUNC + # include + # include + +-s390_vx_libc_ifunc2 (__strncat, strncat) ++# if HAVE_STRNCAT_C ++extern __typeof (__strncat) STRNCAT_C attribute_hidden; ++# endif ++ ++# if HAVE_STRNCAT_Z13 ++extern __typeof (__strncat) STRNCAT_Z13 attribute_hidden; ++# endif + +-#else +-# include +-#endif /* !(defined HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc)) */ ++s390_libc_ifunc_expr (__strncat, strncat, ++ (HAVE_STRNCAT_Z13 && (hwcap & HWCAP_S390_VX)) ++ ? STRNCAT_Z13 ++ : STRNCAT_DEFAULT ++ ) ++#endif diff --git a/SOURCES/glibc-rh1659438-24.patch b/SOURCES/glibc-rh1659438-24.patch new file mode 100644 index 0000000..b0f4be8 --- /dev/null +++ b/SOURCES/glibc-rh1659438-24.patch @@ -0,0 +1,394 @@ +commit cdab85fe33b0443a645509cbb5b929a0d3307f18 +Author: Stefan Liebler +Date: Tue Dec 18 13:57:13 2018 +0100 + + S390: Refactor strcmp ifunc handling. + + The ifunc handling for strcmp is adjusted in order to omit ifunc + variants if those will never be used as the minimum architecture level + already supports newer CPUs by default. + Glibc internal calls will then also use the "newer" ifunc variant. + + Note: The fallback s390-32/s390-64 ifunc variants with clst instruction + are now moved to the unified strcmp-z900.S file which can be used for + 31/64bit. The s390-32/s390-64 files multiarch/strcmp.c and strcmp.S + are deleted. + + ChangeLog: + + * sysdeps/s390/multiarch/Makefile + (sysdep_routines): Remove strcmp variants. + * sysdeps/s390/Makefile (sysdep_routines): Add strcmp variants. + * sysdeps/s390/multiarch/ifunc-impl-list.c + (__libc_ifunc_impl_list): Refactor ifunc handling for strcmp. + * sysdeps/s390/multiarch/strcmp-vx.S: Move to ... + * sysdeps/s390/strcmp-vx.S: ... here and adjust ifunc handling. + * sysdeps/s390/multiarch/strcmp.c: Move to ... + * sysdeps/s390/strcmp.c: ... here and adjust ifunc handling. + * sysdeps/s390/ifunc-strcmp.h: New file. + * sysdeps/s390/s390-64/strcmp.S: Move to ... + * sysdeps/s390/strcmp-z900.S: ... here and adjust to be usable + for 31/64bit and ifunc handling. + * sysdeps/s390/s390-32/multiarch/strcmp.c: Delete file. + * sysdeps/s390/s390-64/multiarch/strcmp.c: Likewise. + * sysdeps/s390/s390-32/strcmp.S: Likewise. + +diff --git a/sysdeps/s390/Makefile b/sysdeps/s390/Makefile +index cb5dc1d4f95fd11c..71a4658b43aeb745 100644 +--- a/sysdeps/s390/Makefile ++++ b/sysdeps/s390/Makefile +@@ -44,5 +44,6 @@ sysdep_routines += bzero memset memset-z900 \ + strncpy strncpy-vx strncpy-z900 \ + stpncpy stpncpy-vx stpncpy-c \ + strcat strcat-vx strcat-c \ +- strncat strncat-vx strncat-c ++ strncat strncat-vx strncat-c \ ++ strcmp strcmp-vx strcmp-z900 + endif +diff --git a/sysdeps/s390/ifunc-strcmp.h b/sysdeps/s390/ifunc-strcmp.h +new file mode 100644 +index 0000000000000000..86ffe686ade52b64 +--- /dev/null ++++ b/sysdeps/s390/ifunc-strcmp.h +@@ -0,0 +1,52 @@ ++/* strcmp variant information on S/390 version. ++ 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 ++ . */ ++ ++#if defined USE_MULTIARCH && IS_IN (libc) \ ++ && ! defined HAVE_S390_MIN_Z13_ZARCH_ASM_SUPPORT ++# define HAVE_STRCMP_IFUNC 1 ++#else ++# define HAVE_STRCMP_IFUNC 0 ++#endif ++ ++#ifdef HAVE_S390_VX_ASM_SUPPORT ++# define HAVE_STRCMP_IFUNC_AND_VX_SUPPORT HAVE_STRCMP_IFUNC ++#else ++# define HAVE_STRCMP_IFUNC_AND_VX_SUPPORT 0 ++#endif ++ ++#if defined HAVE_S390_MIN_Z13_ZARCH_ASM_SUPPORT ++# define STRCMP_DEFAULT STRCMP_Z13 ++# define HAVE_STRCMP_Z900_G5 0 ++# define HAVE_STRCMP_Z13 1 ++#else ++# define STRCMP_DEFAULT STRCMP_Z900_G5 ++# define HAVE_STRCMP_Z900_G5 1 ++# define HAVE_STRCMP_Z13 HAVE_STRCMP_IFUNC_AND_VX_SUPPORT ++#endif ++ ++#if HAVE_STRCMP_Z900_G5 ++# define STRCMP_Z900_G5 __strcmp_default ++#else ++# define STRCMP_Z900_G5 NULL ++#endif ++ ++#if HAVE_STRCMP_Z13 ++# define STRCMP_Z13 __strcmp_vx ++#else ++# define STRCMP_Z13 NULL ++#endif +diff --git a/sysdeps/s390/multiarch/Makefile b/sysdeps/s390/multiarch/Makefile +index 24be3eac5131fd4a..97421a499625c7f2 100644 +--- a/sysdeps/s390/multiarch/Makefile ++++ b/sysdeps/s390/multiarch/Makefile +@@ -1,6 +1,5 @@ + ifeq ($(subdir),string) +-sysdep_routines += strcmp strcmp-vx \ +- strncmp strncmp-vx strncmp-c \ ++sysdep_routines += strncmp strncmp-vx strncmp-c \ + strchr strchr-vx strchr-c \ + strchrnul strchrnul-vx strchrnul-c \ + strrchr strrchr-vx strrchr-c \ +diff --git a/sysdeps/s390/multiarch/ifunc-impl-list.c b/sysdeps/s390/multiarch/ifunc-impl-list.c +index 3abcaf08e0ccd385..44637c431b144c66 100644 +--- a/sysdeps/s390/multiarch/ifunc-impl-list.c ++++ b/sysdeps/s390/multiarch/ifunc-impl-list.c +@@ -34,6 +34,7 @@ + #include + #include + #include ++#include + + /* Maximum number of IFUNC implementations. */ + #define MAX_IFUNC 3 +@@ -268,6 +269,18 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + ) + #endif /* HAVE_STRNCAT_IFUNC */ + ++#if HAVE_STRCMP_IFUNC ++ IFUNC_IMPL (i, name, strcmp, ++# if HAVE_STRCMP_Z13 ++ IFUNC_IMPL_ADD (array, i, strcmp, ++ dl_hwcap & HWCAP_S390_VX, STRCMP_Z13) ++# endif ++# if HAVE_STRCMP_Z900_G5 ++ IFUNC_IMPL_ADD (array, i, strcmp, 1, STRCMP_Z900_G5) ++# endif ++ ) ++#endif /* HAVE_STRCMP_IFUNC */ ++ + #ifdef HAVE_S390_VX_ASM_SUPPORT + + # define IFUNC_VX_IMPL(FUNC) \ +@@ -292,7 +305,6 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + + IFUNC_VX_IMPL (wcsncat); + +- IFUNC_VX_IMPL (strcmp); + IFUNC_VX_IMPL (wcscmp); + + IFUNC_VX_IMPL (strncmp); +diff --git a/sysdeps/s390/s390-32/multiarch/strcmp.c b/sysdeps/s390/s390-32/multiarch/strcmp.c +deleted file mode 100644 +index d06b0f3436b2abfd..0000000000000000 +--- a/sysdeps/s390/s390-32/multiarch/strcmp.c ++++ /dev/null +@@ -1,21 +0,0 @@ +-/* Multiple versions of strcmp. +- 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 +- . */ +- +-/* This wrapper-file is needed, because otherwise file +- sysdeps/s390/s390-[32|64]/strcmp.S will be used. */ +-#include +diff --git a/sysdeps/s390/s390-32/strcmp.S b/sysdeps/s390/s390-32/strcmp.S +deleted file mode 100644 +index 3cf3f239fddccce8..0000000000000000 +--- a/sysdeps/s390/s390-32/strcmp.S ++++ /dev/null +@@ -1,41 +0,0 @@ +-/* strcmp - compare two string. S/390 version. +- This file is part of the GNU C Library. +- Copyright (C) 2001-2018 Free Software Foundation, Inc. +- Contributed by Martin Schwidefsky (schwidefsky@de.ibm.com). +- +- The GNU C Library is free software; you can redistribute it and/or +- modify it under the terms of the GNU Lesser General Public +- License as published by the Free Software Foundation; either +- version 2.1 of the License, or (at your option) any later version. +- +- The GNU C Library is distributed in the hope that it will be useful, +- but WITHOUT ANY WARRANTY; without even the implied warranty of +- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +- Lesser General Public License for more details. +- +- You should have received a copy of the GNU Lesser General Public +- License along with the GNU C Library; if not, see +- . */ +- +-/* INPUT PARAMETERS +- %r2 = address of string 1 +- %r3 = address of string 2. */ +- +-#include "sysdep.h" +-#include "asm-syntax.h" +- +- .text +-ENTRY(strcmp) +- slr %r0,%r0 +-0: clst %r2,%r3 +- jo 0b +- jp 1f +- jm 2f +- slr %r2,%r2 +- br %r14 +-1: lhi %r2,1 +- br %r14 +-2: lhi %r2,-1 +- br %r14 +-END(strcmp) +-libc_hidden_builtin_def (strcmp) +diff --git a/sysdeps/s390/s390-64/multiarch/strcmp.c b/sysdeps/s390/s390-64/multiarch/strcmp.c +deleted file mode 100644 +index d06b0f3436b2abfd..0000000000000000 +--- a/sysdeps/s390/s390-64/multiarch/strcmp.c ++++ /dev/null +@@ -1,21 +0,0 @@ +-/* Multiple versions of strcmp. +- 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 +- . */ +- +-/* This wrapper-file is needed, because otherwise file +- sysdeps/s390/s390-[32|64]/strcmp.S will be used. */ +-#include +diff --git a/sysdeps/s390/multiarch/strcmp-vx.S b/sysdeps/s390/strcmp-vx.S +similarity index 90% +rename from sysdeps/s390/multiarch/strcmp-vx.S +rename to sysdeps/s390/strcmp-vx.S +index bcaeb564d47c58ff..801ad9d32bbd76c0 100644 +--- a/sysdeps/s390/multiarch/strcmp-vx.S ++++ b/sysdeps/s390/strcmp-vx.S +@@ -16,7 +16,8 @@ + License along with the GNU C Library; if not, see + . */ + +-#if defined HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc) ++#include ++#if HAVE_STRCMP_Z13 + + # include "sysdep.h" + # include "asm-syntax.h" +@@ -36,7 +37,7 @@ + -v17=part of s2 + -v18=index of unequal + */ +-ENTRY(__strcmp_vx) ++ENTRY(STRCMP_Z13) + .machine "z13" + .machinemode "zarch_nohighgprs" + +@@ -106,11 +107,13 @@ ENTRY(__strcmp_vx) + .Lend_equal: + lghi %r2,0 + br %r14 +-END(__strcmp_vx) ++END(STRCMP_Z13) + +-# define strcmp __strcmp_c +-# undef libc_hidden_builtin_def +-# define libc_hidden_builtin_def(name) strong_alias(__strcmp_c, __GI_strcmp) +-#endif /* HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc) */ ++# if ! HAVE_STRCMP_IFUNC ++strong_alias (STRCMP_Z13, strcmp) ++# endif + +-#include ++# if ! HAVE_STRCMP_Z900_G5 && defined SHARED && IS_IN (libc) ++strong_alias (STRCMP_Z13, __GI_strcmp) ++# endif ++#endif +diff --git a/sysdeps/s390/s390-64/strcmp.S b/sysdeps/s390/strcmp-z900.S +similarity index 70% +rename from sysdeps/s390/s390-64/strcmp.S +rename to sysdeps/s390/strcmp-z900.S +index 6cf1addd8bdf1a19..67b3c8b2e5989cd2 100644 +--- a/sysdeps/s390/s390-64/strcmp.S ++++ b/sysdeps/s390/strcmp-z900.S +@@ -21,21 +21,39 @@ + %r2 = address of string 1 + %r3 = address of string 2. */ + ++#include + #include "sysdep.h" + #include "asm-syntax.h" + ++#if HAVE_STRCMP_Z900_G5 ++# if defined __s390x__ ++# define SLGR slgr ++# define LGHI lghi ++# else ++# define SLGR slr ++# define LGHI lhi ++# endif /* ! defined __s390x__ */ ++ + .text +-ENTRY(strcmp) +- slr %r0,%r0 ++ENTRY(STRCMP_Z900_G5) ++ SLGR %r0,%r0 + 0: clst %r2,%r3 + jo 0b + jp 1f + jm 2f +- slgr %r2,%r2 ++ SLGR %r2,%r2 + br %r14 +-1: lghi %r2,1 ++1: LGHI %r2,1 + br %r14 +-2: lghi %r2,-1 ++2: LGHI %r2,-1 + br %r14 +-END(strcmp) +-libc_hidden_builtin_def (strcmp) ++END(STRCMP_Z900_G5) ++ ++# if ! HAVE_STRCMP_IFUNC ++strong_alias (STRCMP_Z900_G5, strcmp) ++# endif ++ ++# if defined SHARED && IS_IN (libc) ++strong_alias (STRCMP_Z900_G5, __GI_strcmp) ++# endif ++#endif +diff --git a/sysdeps/s390/multiarch/strcmp.c b/sysdeps/s390/strcmp.c +similarity index 71% +rename from sysdeps/s390/multiarch/strcmp.c +rename to sysdeps/s390/strcmp.c +index 7c8b17b3041dd549..9efa30acaf21f4e8 100644 +--- a/sysdeps/s390/multiarch/strcmp.c ++++ b/sysdeps/s390/strcmp.c +@@ -16,7 +16,9 @@ + License along with the GNU C Library; if not, see + . */ + +-#if defined HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc) ++#include ++ ++#if HAVE_STRCMP_IFUNC + # define strcmp __redirect_strcmp + /* Omit the strcmp inline definitions because it would redefine strcmp. */ + # define __NO_STRING_INLINES +@@ -24,6 +26,17 @@ + # include + # undef strcmp + +-s390_vx_libc_ifunc2_redirected (__redirect_strcmp, __strcmp, strcmp) ++# if HAVE_STRCMP_Z900_G5 ++extern __typeof (__redirect_strcmp) STRCMP_Z900_G5 attribute_hidden; ++# endif ++ ++# if HAVE_STRCMP_Z13 ++extern __typeof (__redirect_strcmp) STRCMP_Z13 attribute_hidden; ++# endif + ++s390_libc_ifunc_expr (__redirect_strcmp, strcmp, ++ (HAVE_STRCMP_Z13 && (hwcap & HWCAP_S390_VX)) ++ ? STRCMP_Z13 ++ : STRCMP_DEFAULT ++ ) + #endif diff --git a/SOURCES/glibc-rh1659438-25.patch b/SOURCES/glibc-rh1659438-25.patch new file mode 100644 index 0000000..afe7ad0 --- /dev/null +++ b/SOURCES/glibc-rh1659438-25.patch @@ -0,0 +1,263 @@ +commit 316b88421993d540513a6b25b59ec16df267e9b4 +Author: Stefan Liebler +Date: Tue Dec 18 13:57:13 2018 +0100 + + S390: Refactor strncmp ifunc handling. + + The ifunc handling for strncmp is adjusted in order to omit ifunc + variants if those will never be used as the minimum architecture level + already supports newer CPUs by default. + Glibc internal calls will then also use the "newer" ifunc variant. + + ChangeLog: + + * sysdeps/s390/multiarch/Makefile + (sysdep_routines): Remove strncmp variants. + * sysdeps/s390/Makefile (sysdep_routines): Add strncmp variants. + * sysdeps/s390/multiarch/ifunc-impl-list.c + (__libc_ifunc_impl_list): Refactor ifunc handling for strncmp. + * sysdeps/s390/multiarch/strncmp-c.c: Move to ... + * sysdeps/s390/strncmp-c.c: ... here and adjust ifunc handling. + * sysdeps/s390/multiarch/strncmp-vx.S: Move to ... + * sysdeps/s390/strncmp-vx.S: ... here and adjust ifunc handling. + * sysdeps/s390/multiarch/strncmp.c: Move to ... + * sysdeps/s390/strncmp.c: ... here and adjust ifunc handling. + * sysdeps/s390/ifunc-strncmp.h: New file. + +diff --git a/sysdeps/s390/Makefile b/sysdeps/s390/Makefile +index 71a4658b43aeb745..adf3521876725ac8 100644 +--- a/sysdeps/s390/Makefile ++++ b/sysdeps/s390/Makefile +@@ -45,5 +45,6 @@ sysdep_routines += bzero memset memset-z900 \ + stpncpy stpncpy-vx stpncpy-c \ + strcat strcat-vx strcat-c \ + strncat strncat-vx strncat-c \ +- strcmp strcmp-vx strcmp-z900 ++ strcmp strcmp-vx strcmp-z900 \ ++ strncmp strncmp-vx strncmp-c + endif +diff --git a/sysdeps/s390/ifunc-strncmp.h b/sysdeps/s390/ifunc-strncmp.h +new file mode 100644 +index 0000000000000000..511b3e9720520a0c +--- /dev/null ++++ b/sysdeps/s390/ifunc-strncmp.h +@@ -0,0 +1,52 @@ ++/* strncmp variant information on S/390 version. ++ 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 ++ . */ ++ ++#if defined USE_MULTIARCH && IS_IN (libc) \ ++ && ! defined HAVE_S390_MIN_Z13_ZARCH_ASM_SUPPORT ++# define HAVE_STRNCMP_IFUNC 1 ++#else ++# define HAVE_STRNCMP_IFUNC 0 ++#endif ++ ++#ifdef HAVE_S390_VX_ASM_SUPPORT ++# define HAVE_STRNCMP_IFUNC_AND_VX_SUPPORT HAVE_STRNCMP_IFUNC ++#else ++# define HAVE_STRNCMP_IFUNC_AND_VX_SUPPORT 0 ++#endif ++ ++#if defined HAVE_S390_MIN_Z13_ZARCH_ASM_SUPPORT ++# define STRNCMP_DEFAULT STRNCMP_Z13 ++# define HAVE_STRNCMP_C 0 ++# define HAVE_STRNCMP_Z13 1 ++#else ++# define STRNCMP_DEFAULT STRNCMP_C ++# define HAVE_STRNCMP_C 1 ++# define HAVE_STRNCMP_Z13 HAVE_STRNCMP_IFUNC_AND_VX_SUPPORT ++#endif ++ ++#if HAVE_STRNCMP_C ++# define STRNCMP_C __strncmp_c ++#else ++# define STRNCMP_C NULL ++#endif ++ ++#if HAVE_STRNCMP_Z13 ++# define STRNCMP_Z13 __strncmp_vx ++#else ++# define STRNCMP_Z13 NULL ++#endif +diff --git a/sysdeps/s390/multiarch/Makefile b/sysdeps/s390/multiarch/Makefile +index 97421a499625c7f2..381376bf9fcb0f58 100644 +--- a/sysdeps/s390/multiarch/Makefile ++++ b/sysdeps/s390/multiarch/Makefile +@@ -1,6 +1,5 @@ + ifeq ($(subdir),string) +-sysdep_routines += strncmp strncmp-vx strncmp-c \ +- strchr strchr-vx strchr-c \ ++sysdep_routines += strchr strchr-vx strchr-c \ + strchrnul strchrnul-vx strchrnul-c \ + strrchr strrchr-vx strrchr-c \ + strspn strspn-vx strspn-c \ +diff --git a/sysdeps/s390/multiarch/ifunc-impl-list.c b/sysdeps/s390/multiarch/ifunc-impl-list.c +index 44637c431b144c66..d982de5788c0b5d5 100644 +--- a/sysdeps/s390/multiarch/ifunc-impl-list.c ++++ b/sysdeps/s390/multiarch/ifunc-impl-list.c +@@ -35,6 +35,7 @@ + #include + #include + #include ++#include + + /* Maximum number of IFUNC implementations. */ + #define MAX_IFUNC 3 +@@ -281,6 +282,18 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + ) + #endif /* HAVE_STRCMP_IFUNC */ + ++#if HAVE_STRNCMP_IFUNC ++ IFUNC_IMPL (i, name, strncmp, ++# if HAVE_STRNCMP_Z13 ++ IFUNC_IMPL_ADD (array, i, strncmp, ++ dl_hwcap & HWCAP_S390_VX, STRNCMP_Z13) ++# endif ++# if HAVE_STRNCMP_C ++ IFUNC_IMPL_ADD (array, i, strncmp, 1, STRNCMP_C) ++# endif ++ ) ++#endif /* HAVE_STRNCMP_IFUNC */ ++ + #ifdef HAVE_S390_VX_ASM_SUPPORT + + # define IFUNC_VX_IMPL(FUNC) \ +@@ -307,7 +320,6 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + + IFUNC_VX_IMPL (wcscmp); + +- IFUNC_VX_IMPL (strncmp); + IFUNC_VX_IMPL (wcsncmp); + + IFUNC_VX_IMPL (strchr); +diff --git a/sysdeps/s390/multiarch/strncmp-c.c b/sysdeps/s390/strncmp-c.c +similarity index 78% +rename from sysdeps/s390/multiarch/strncmp-c.c +rename to sysdeps/s390/strncmp-c.c +index e54277ec1b10f8d7..c7ffdb03e37dc8d8 100644 +--- a/sysdeps/s390/multiarch/strncmp-c.c ++++ b/sysdeps/s390/strncmp-c.c +@@ -16,13 +16,17 @@ + License along with the GNU C Library; if not, see + . */ + +-#if defined HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc) +-# define STRNCMP __strncmp_c +-# ifdef SHARED +-# undef libc_hidden_builtin_def +-# define libc_hidden_builtin_def(name) \ ++#include ++ ++#if HAVE_STRNCMP_C ++# if HAVE_STRNCMP_IFUNC ++# define STRNCMP STRNCMP_C ++# if defined SHARED && IS_IN (libc) ++# undef libc_hidden_builtin_def ++# define libc_hidden_builtin_def(name) \ + __hidden_ver1 (__strncmp_c, __GI_strncmp, __strncmp_c); +-# endif /* SHARED */ ++# endif ++# endif + + # include +-#endif /* HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc) */ ++#endif +diff --git a/sysdeps/s390/multiarch/strncmp-vx.S b/sysdeps/s390/strncmp-vx.S +similarity index 93% +rename from sysdeps/s390/multiarch/strncmp-vx.S +rename to sysdeps/s390/strncmp-vx.S +index 168fd657da2a1173..f557afb336d418ff 100644 +--- a/sysdeps/s390/multiarch/strncmp-vx.S ++++ b/sysdeps/s390/strncmp-vx.S +@@ -16,7 +16,9 @@ + License along with the GNU C Library; if not, see + . */ + +-#if defined HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc) ++#include ++ ++#if HAVE_STRNCMP_Z13 + + # include "sysdep.h" + # include "asm-syntax.h" +@@ -37,7 +39,7 @@ + -v17=part of s2 + -v18=index of unequal + */ +-ENTRY(__strncmp_vx) ++ENTRY(STRNCMP_Z13) + .machine "z13" + .machinemode "zarch_nohighgprs" + +@@ -133,5 +135,14 @@ ENTRY(__strncmp_vx) + .Lend_equal: + lghi %r2,0 + br %r14 +-END(__strncmp_vx) +-#endif /* HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc) */ ++END(STRNCMP_Z13) ++ ++# if ! HAVE_STRNCMP_IFUNC ++strong_alias (STRNCMP_Z13, strncmp) ++# endif ++ ++# if ! HAVE_STRNCMP_C && defined SHARED && IS_IN (libc) ++strong_alias (STRNCMP_Z13, __GI_strncmp) ++# endif ++ ++#endif /* HAVE_STRNCMP_Z13 */ +diff --git a/sysdeps/s390/multiarch/strncmp.c b/sysdeps/s390/strncmp.c +similarity index 70% +rename from sysdeps/s390/multiarch/strncmp.c +rename to sysdeps/s390/strncmp.c +index 0ec472c3b03419a3..71351273c4058129 100644 +--- a/sysdeps/s390/multiarch/strncmp.c ++++ b/sysdeps/s390/strncmp.c +@@ -16,7 +16,9 @@ + License along with the GNU C Library; if not, see + . */ + +-#if defined HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc) ++#include ++ ++#if HAVE_STRNCMP_IFUNC + # define strncmp __redirect_strncmp + /* Omit the strncmp inline definitions because it would redefine strncmp. */ + # define __NO_STRING_INLINES +@@ -24,8 +26,17 @@ + # undef strncmp + # include + +-s390_vx_libc_ifunc2_redirected (__redirect_strncmp, __strncmp, strncmp) ++# if HAVE_STRNCMP_C ++extern __typeof (__redirect_strncmp) STRNCMP_C attribute_hidden; ++# endif ++ ++# if HAVE_STRNCMP_Z13 ++extern __typeof (__redirect_strncmp) STRNCMP_Z13 attribute_hidden; ++# endif + +-#else +-# include +-#endif /* !(defined HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc)) */ ++s390_libc_ifunc_expr (__redirect_strncmp, strncmp, ++ (HAVE_STRNCMP_Z13 && (hwcap & HWCAP_S390_VX)) ++ ? STRNCMP_Z13 ++ : STRNCMP_DEFAULT ++ ) ++#endif /* HAVE_STRNCMP_IFUNC */ diff --git a/SOURCES/glibc-rh1659438-26.patch b/SOURCES/glibc-rh1659438-26.patch new file mode 100644 index 0000000..65995ca --- /dev/null +++ b/SOURCES/glibc-rh1659438-26.patch @@ -0,0 +1,268 @@ +commit 32f12653d4ea2fbff409351bf8067f9a0b4a3963 +Author: Stefan Liebler +Date: Tue Dec 18 13:57:14 2018 +0100 + + S390: Refactor strchr ifunc handling. + + The ifunc handling for strchr is adjusted in order to omit ifunc + variants if those will never be used as the minimum architecture level + already supports newer CPUs by default. + Glibc internal calls will then also use the "newer" ifunc variant. + + ChangeLog: + + * sysdeps/s390/multiarch/Makefile + (sysdep_routines): Remove strchr variants. + * sysdeps/s390/Makefile (sysdep_routines): Add strchr variants. + * sysdeps/s390/multiarch/ifunc-impl-list.c + (__libc_ifunc_impl_list): Refactor ifunc handling for strchr. + * sysdeps/s390/multiarch/strchr-c.c: Move to ... + * sysdeps/s390/strchr-c.c: ... here and adjust ifunc handling. + * sysdeps/s390/multiarch/strchr-vx.S: Move to ... + * sysdeps/s390/strchr-vx.S: ... here and adjust ifunc handling. + * sysdeps/s390/multiarch/strchr.c: Move to ... + * sysdeps/s390/strchr.c: ... here and adjust ifunc handling. + * sysdeps/s390/ifunc-strchr.h: New file. + +diff --git a/sysdeps/s390/Makefile b/sysdeps/s390/Makefile +index adf3521876725ac8..8bb396f498e0b0b0 100644 +--- a/sysdeps/s390/Makefile ++++ b/sysdeps/s390/Makefile +@@ -46,5 +46,6 @@ sysdep_routines += bzero memset memset-z900 \ + strcat strcat-vx strcat-c \ + strncat strncat-vx strncat-c \ + strcmp strcmp-vx strcmp-z900 \ +- strncmp strncmp-vx strncmp-c ++ strncmp strncmp-vx strncmp-c \ ++ strchr strchr-vx strchr-c + endif +diff --git a/sysdeps/s390/ifunc-strchr.h b/sysdeps/s390/ifunc-strchr.h +new file mode 100644 +index 0000000000000000..cfeb00eeda890512 +--- /dev/null ++++ b/sysdeps/s390/ifunc-strchr.h +@@ -0,0 +1,52 @@ ++/* strchr variant information on S/390 version. ++ 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 ++ . */ ++ ++#if defined USE_MULTIARCH && IS_IN (libc) \ ++ && ! defined HAVE_S390_MIN_Z13_ZARCH_ASM_SUPPORT ++# define HAVE_STRCHR_IFUNC 1 ++#else ++# define HAVE_STRCHR_IFUNC 0 ++#endif ++ ++#ifdef HAVE_S390_VX_ASM_SUPPORT ++# define HAVE_STRCHR_IFUNC_AND_VX_SUPPORT HAVE_STRCHR_IFUNC ++#else ++# define HAVE_STRCHR_IFUNC_AND_VX_SUPPORT 0 ++#endif ++ ++#if defined HAVE_S390_MIN_Z13_ZARCH_ASM_SUPPORT ++# define STRCHR_DEFAULT STRCHR_Z13 ++# define HAVE_STRCHR_C 0 ++# define HAVE_STRCHR_Z13 1 ++#else ++# define STRCHR_DEFAULT STRCHR_C ++# define HAVE_STRCHR_C 1 ++# define HAVE_STRCHR_Z13 HAVE_STRCHR_IFUNC_AND_VX_SUPPORT ++#endif ++ ++#if HAVE_STRCHR_C ++# define STRCHR_C __strchr_c ++#else ++# define STRCHR_C NULL ++#endif ++ ++#if HAVE_STRCHR_Z13 ++# define STRCHR_Z13 __strchr_vx ++#else ++# define STRCHR_Z13 NULL ++#endif +diff --git a/sysdeps/s390/multiarch/Makefile b/sysdeps/s390/multiarch/Makefile +index 381376bf9fcb0f58..a8e9d0acd9ebf986 100644 +--- a/sysdeps/s390/multiarch/Makefile ++++ b/sysdeps/s390/multiarch/Makefile +@@ -1,6 +1,5 @@ + ifeq ($(subdir),string) +-sysdep_routines += strchr strchr-vx strchr-c \ +- strchrnul strchrnul-vx strchrnul-c \ ++sysdep_routines += strchrnul strchrnul-vx strchrnul-c \ + strrchr strrchr-vx strrchr-c \ + strspn strspn-vx strspn-c \ + strpbrk strpbrk-vx strpbrk-c \ +diff --git a/sysdeps/s390/multiarch/ifunc-impl-list.c b/sysdeps/s390/multiarch/ifunc-impl-list.c +index d982de5788c0b5d5..e809ca3bacb18aa9 100644 +--- a/sysdeps/s390/multiarch/ifunc-impl-list.c ++++ b/sysdeps/s390/multiarch/ifunc-impl-list.c +@@ -36,6 +36,7 @@ + #include + #include + #include ++#include + + /* Maximum number of IFUNC implementations. */ + #define MAX_IFUNC 3 +@@ -294,6 +295,18 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + ) + #endif /* HAVE_STRNCMP_IFUNC */ + ++#if HAVE_STRCHR_IFUNC ++ IFUNC_IMPL (i, name, strchr, ++# if HAVE_STRCHR_Z13 ++ IFUNC_IMPL_ADD (array, i, strchr, ++ dl_hwcap & HWCAP_S390_VX, STRCHR_Z13) ++# endif ++# if HAVE_STRCHR_C ++ IFUNC_IMPL_ADD (array, i, strchr, 1, STRCHR_C) ++# endif ++ ) ++#endif /* HAVE_STRCHR_IFUNC */ ++ + #ifdef HAVE_S390_VX_ASM_SUPPORT + + # define IFUNC_VX_IMPL(FUNC) \ +@@ -322,7 +335,6 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + + IFUNC_VX_IMPL (wcsncmp); + +- IFUNC_VX_IMPL (strchr); + IFUNC_VX_IMPL (wcschr); + + IFUNC_VX_IMPL (strchrnul); +diff --git a/sysdeps/s390/multiarch/strchr-c.c b/sysdeps/s390/strchr-c.c +similarity index 77% +rename from sysdeps/s390/multiarch/strchr-c.c +rename to sysdeps/s390/strchr-c.c +index 606cb56788966153..3d3579a1d3bc06d0 100644 +--- a/sysdeps/s390/multiarch/strchr-c.c ++++ b/sysdeps/s390/strchr-c.c +@@ -16,14 +16,18 @@ + License along with the GNU C Library; if not, see + . */ + +-#if defined HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc) +-# define STRCHR __strchr_c +-# undef weak_alias +-# ifdef SHARED +-# undef libc_hidden_builtin_def +-# define libc_hidden_builtin_def(name) \ ++#include ++ ++#if HAVE_STRCHR_C ++# if HAVE_STRCHR_IFUNC ++# define STRCHR STRCHR_C ++# undef weak_alias ++# if defined SHARED && IS_IN (libc) ++# undef libc_hidden_builtin_def ++# define libc_hidden_builtin_def(name) \ + __hidden_ver1 (__strchr_c, __GI_strchr, __strchr_c); +-# endif /* SHARED */ ++# endif ++# endif + + # include +-#endif /* HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc) */ ++#endif +diff --git a/sysdeps/s390/multiarch/strchr-vx.S b/sysdeps/s390/strchr-vx.S +similarity index 90% +rename from sysdeps/s390/multiarch/strchr-vx.S +rename to sysdeps/s390/strchr-vx.S +index 6e744fb82f3249a6..6ffa06f78c14c8da 100644 +--- a/sysdeps/s390/multiarch/strchr-vx.S ++++ b/sysdeps/s390/strchr-vx.S +@@ -16,7 +16,9 @@ + License along with the GNU C Library; if not, see + . */ + +-#if defined HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc) ++#include ++ ++#if HAVE_STRCHR_Z13 + + # include "sysdep.h" + # include "asm-syntax.h" +@@ -36,7 +38,7 @@ + -v17=index of unequal + -v18=replicated c + */ +-ENTRY(__strchr_vx) ++ENTRY(STRCHR_Z13) + .machine "z13" + .machinemode "zarch_nohighgprs" + +@@ -96,5 +98,15 @@ ENTRY(__strchr_vx) + clije %r3,0,.Lcharacter /* Found zero and c is zero. */ + lghi %r2,0 /* Return null if character not found. */ + br %r14 +-END(__strchr_vx) +-#endif /* HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc) */ ++END(STRCHR_Z13) ++ ++# if ! HAVE_STRCHR_IFUNC ++strong_alias (STRCHR_Z13, strchr) ++weak_alias (strchr, index) ++# endif ++ ++# if ! HAVE_STRCHR_C && defined SHARED && IS_IN (libc) ++strong_alias (STRCHR_Z13, __GI_strchr) ++# endif ++ ++#endif /* HAVE_STRCHR_Z13 */ +diff --git a/sysdeps/s390/multiarch/strchr.c b/sysdeps/s390/strchr.c +similarity index 71% +rename from sysdeps/s390/multiarch/strchr.c +rename to sysdeps/s390/strchr.c +index 8aa33a51cc7e91de..a106c6106dcd5307 100644 +--- a/sysdeps/s390/multiarch/strchr.c ++++ b/sysdeps/s390/strchr.c +@@ -16,7 +16,9 @@ + License along with the GNU C Library; if not, see + . */ + +-#if defined HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc) ++#include ++ ++#if HAVE_STRCHR_IFUNC + # define strchr __redirect_strchr + /* Omit the strchr inline definitions because it would redefine strchr. */ + # define __NO_STRING_INLINES +@@ -24,9 +26,18 @@ + # undef strchr + # include + +-s390_vx_libc_ifunc2_redirected (__redirect_strchr, __strchr, strchr) +-weak_alias (strchr, index) ++# if HAVE_STRCHR_C ++extern __typeof (__redirect_strchr) STRCHR_C attribute_hidden; ++# endif + +-#else +-# include +-#endif /* !(defined HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc)) */ ++# if HAVE_STRCHR_Z13 ++extern __typeof (__redirect_strchr) STRCHR_Z13 attribute_hidden; ++# endif ++ ++s390_libc_ifunc_expr (__redirect_strchr, strchr, ++ (HAVE_STRCHR_Z13 && (hwcap & HWCAP_S390_VX)) ++ ? STRCHR_Z13 ++ : STRCHR_DEFAULT ++ ) ++weak_alias (strchr, index) ++#endif /* HAVE_STRCHR_IFUNC */ diff --git a/SOURCES/glibc-rh1659438-27.patch b/SOURCES/glibc-rh1659438-27.patch new file mode 100644 index 0000000..9fb75a4 --- /dev/null +++ b/SOURCES/glibc-rh1659438-27.patch @@ -0,0 +1,253 @@ +commit a1361e65617c660a3ba7d561e081dcd18762a688 +Author: Stefan Liebler +Date: Tue Dec 18 13:57:14 2018 +0100 + + S390: Refactor strchrnul ifunc handling. + + The ifunc handling for strchrnul is adjusted in order to omit ifunc + variants if those will never be used as the minimum architecture level + already supports newer CPUs by default. + + ChangeLog: + + * sysdeps/s390/multiarch/Makefile + (sysdep_routines): Remove strchrnul variants. + * sysdeps/s390/Makefile (sysdep_routines): Add strchrnul variants. + * sysdeps/s390/multiarch/ifunc-impl-list.c + (__libc_ifunc_impl_list): Refactor ifunc handling for strchrnul. + * sysdeps/s390/multiarch/strchrnul-c.c: Move to ... + * sysdeps/s390/strchrnul-c.c: ... here and adjust ifunc handling. + * sysdeps/s390/multiarch/strchrnul-vx.S: Move to ... + * sysdeps/s390/strchrnul-vx.S: ... here and adjust ifunc handling. + * sysdeps/s390/multiarch/strchrnul.c: Move to ... + * sysdeps/s390/strchrnul.c: ... here and adjust ifunc handling. + * sysdeps/s390/ifunc-strchrnul.h: New file. + +diff --git a/sysdeps/s390/Makefile b/sysdeps/s390/Makefile +index 8bb396f498e0b0b0..c54bb82f4d4f8a67 100644 +--- a/sysdeps/s390/Makefile ++++ b/sysdeps/s390/Makefile +@@ -47,5 +47,6 @@ sysdep_routines += bzero memset memset-z900 \ + strncat strncat-vx strncat-c \ + strcmp strcmp-vx strcmp-z900 \ + strncmp strncmp-vx strncmp-c \ +- strchr strchr-vx strchr-c ++ strchr strchr-vx strchr-c \ ++ strchrnul strchrnul-vx strchrnul-c + endif +diff --git a/sysdeps/s390/ifunc-strchrnul.h b/sysdeps/s390/ifunc-strchrnul.h +new file mode 100644 +index 0000000000000000..cac817e6f0a9406d +--- /dev/null ++++ b/sysdeps/s390/ifunc-strchrnul.h +@@ -0,0 +1,52 @@ ++/* strchrnul variant information on S/390 version. ++ 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 ++ . */ ++ ++#if defined USE_MULTIARCH && IS_IN (libc) \ ++ && ! defined HAVE_S390_MIN_Z13_ZARCH_ASM_SUPPORT ++# define HAVE_STRCHRNUL_IFUNC 1 ++#else ++# define HAVE_STRCHRNUL_IFUNC 0 ++#endif ++ ++#ifdef HAVE_S390_VX_ASM_SUPPORT ++# define HAVE_STRCHRNUL_IFUNC_AND_VX_SUPPORT HAVE_STRCHRNUL_IFUNC ++#else ++# define HAVE_STRCHRNUL_IFUNC_AND_VX_SUPPORT 0 ++#endif ++ ++#if defined HAVE_S390_MIN_Z13_ZARCH_ASM_SUPPORT ++# define STRCHRNUL_DEFAULT STRCHRNUL_Z13 ++# define HAVE_STRCHRNUL_C 0 ++# define HAVE_STRCHRNUL_Z13 1 ++#else ++# define STRCHRNUL_DEFAULT STRCHRNUL_C ++# define HAVE_STRCHRNUL_C 1 ++# define HAVE_STRCHRNUL_Z13 HAVE_STRCHRNUL_IFUNC_AND_VX_SUPPORT ++#endif ++ ++#if HAVE_STRCHRNUL_C ++# define STRCHRNUL_C __strchrnul_c ++#else ++# define STRCHRNUL_C NULL ++#endif ++ ++#if HAVE_STRCHRNUL_Z13 ++# define STRCHRNUL_Z13 __strchrnul_vx ++#else ++# define STRCHRNUL_Z13 NULL ++#endif +diff --git a/sysdeps/s390/multiarch/Makefile b/sysdeps/s390/multiarch/Makefile +index a8e9d0acd9ebf986..999a979fee1417b2 100644 +--- a/sysdeps/s390/multiarch/Makefile ++++ b/sysdeps/s390/multiarch/Makefile +@@ -1,6 +1,5 @@ + ifeq ($(subdir),string) +-sysdep_routines += strchrnul strchrnul-vx strchrnul-c \ +- strrchr strrchr-vx strrchr-c \ ++sysdep_routines += strrchr strrchr-vx strrchr-c \ + strspn strspn-vx strspn-c \ + strpbrk strpbrk-vx strpbrk-c \ + strcspn strcspn-vx strcspn-c \ +diff --git a/sysdeps/s390/multiarch/ifunc-impl-list.c b/sysdeps/s390/multiarch/ifunc-impl-list.c +index e809ca3bacb18aa9..0a47ffeac3492b3e 100644 +--- a/sysdeps/s390/multiarch/ifunc-impl-list.c ++++ b/sysdeps/s390/multiarch/ifunc-impl-list.c +@@ -37,6 +37,7 @@ + #include + #include + #include ++#include + + /* Maximum number of IFUNC implementations. */ + #define MAX_IFUNC 3 +@@ -307,6 +308,18 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + ) + #endif /* HAVE_STRCHR_IFUNC */ + ++#if HAVE_STRCHRNUL_IFUNC ++ IFUNC_IMPL (i, name, strchrnul, ++# if HAVE_STRCHRNUL_Z13 ++ IFUNC_IMPL_ADD (array, i, strchrnul, ++ dl_hwcap & HWCAP_S390_VX, STRCHRNUL_Z13) ++# endif ++# if HAVE_STRCHRNUL_C ++ IFUNC_IMPL_ADD (array, i, strchrnul, 1, STRCHRNUL_C) ++# endif ++ ) ++#endif /* HAVE_STRCHRNUL_IFUNC */ ++ + #ifdef HAVE_S390_VX_ASM_SUPPORT + + # define IFUNC_VX_IMPL(FUNC) \ +@@ -337,7 +350,6 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + + IFUNC_VX_IMPL (wcschr); + +- IFUNC_VX_IMPL (strchrnul); + IFUNC_VX_IMPL (wcschrnul); + + IFUNC_VX_IMPL (strrchr); +diff --git a/sysdeps/s390/multiarch/strchrnul-c.c b/sysdeps/s390/strchrnul-c.c +similarity index 81% +rename from sysdeps/s390/multiarch/strchrnul-c.c +rename to sysdeps/s390/strchrnul-c.c +index 020cebcf3e275b07..585273f5de8b82bc 100644 +--- a/sysdeps/s390/multiarch/strchrnul-c.c ++++ b/sysdeps/s390/strchrnul-c.c +@@ -16,11 +16,15 @@ + License along with the GNU C Library; if not, see + . */ + +-#if defined HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc) +-# define STRCHRNUL __strchrnul_c +-# define __strchrnul STRCHRNUL +-# undef weak_alias +-# define weak_alias(name, alias) ++#include ++ ++#if HAVE_STRCHRNUL_C ++# if HAVE_STRCHRNUL_IFUNC ++# define STRCHRNUL STRCHRNUL_C ++# define __strchrnul STRCHRNUL ++# undef weak_alias ++# define weak_alias(name, alias) ++# endif + + # include + #endif +diff --git a/sysdeps/s390/multiarch/strchrnul-vx.S b/sysdeps/s390/strchrnul-vx.S +similarity index 91% +rename from sysdeps/s390/multiarch/strchrnul-vx.S +rename to sysdeps/s390/strchrnul-vx.S +index d561825e0432458c..0cd587bc32cf811f 100644 +--- a/sysdeps/s390/multiarch/strchrnul-vx.S ++++ b/sysdeps/s390/strchrnul-vx.S +@@ -16,7 +16,9 @@ + License along with the GNU C Library; if not, see + . */ + +-#if defined HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc) ++#include ++ ++#if HAVE_STRCHRNUL_Z13 + + # include "sysdep.h" + # include "asm-syntax.h" +@@ -35,7 +37,7 @@ + -v16=part of s + -v18=vector with c replicated in every byte + */ +-ENTRY(__strchrnul_vx) ++ENTRY(STRCHRNUL_Z13) + .machine "z13" + .machinemode "zarch_nohighgprs" + +@@ -89,5 +91,11 @@ ENTRY(__strchrnul_vx) + + .Lend: + br %r14 +-END(__strchrnul_vx) +-#endif /* HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc) */ ++END(STRCHRNUL_Z13) ++ ++# if ! HAVE_STRCHRNUL_IFUNC ++strong_alias (STRCHRNUL_Z13, __strchrnul) ++weak_alias (__strchrnul, strchrnul) ++# endif ++ ++#endif /* HAVE_STRCHRNUL_Z13 */ +diff --git a/sysdeps/s390/multiarch/strchrnul.c b/sysdeps/s390/strchrnul.c +similarity index 67% +rename from sysdeps/s390/multiarch/strchrnul.c +rename to sysdeps/s390/strchrnul.c +index 62dfc6bd90638b60..e9fefe1bdc77f038 100644 +--- a/sysdeps/s390/multiarch/strchrnul.c ++++ b/sysdeps/s390/strchrnul.c +@@ -16,13 +16,24 @@ + License along with the GNU C Library; if not, see + . */ + +-#if defined HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc) ++#include ++ ++#if HAVE_STRCHRNUL_IFUNC + # include + # include + +-s390_vx_libc_ifunc (__strchrnul) +-weak_alias (__strchrnul, strchrnul) ++# if HAVE_STRCHRNUL_C ++extern __typeof (__strchrnul) STRCHRNUL_C attribute_hidden; ++# endif + +-#else +-# include +-#endif /* !(defined HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc)) */ ++# if HAVE_STRCHRNUL_Z13 ++extern __typeof (__strchrnul) STRCHRNUL_Z13 attribute_hidden; ++# endif ++ ++s390_libc_ifunc_expr (__strchrnul, __strchrnul, ++ (HAVE_STRCHRNUL_Z13 && (hwcap & HWCAP_S390_VX)) ++ ? STRCHRNUL_Z13 ++ : STRCHRNUL_DEFAULT ++ ) ++weak_alias (__strchrnul, strchrnul) ++#endif /* HAVE_STRCHRNUL_IFUNC */ diff --git a/SOURCES/glibc-rh1659438-28.patch b/SOURCES/glibc-rh1659438-28.patch new file mode 100644 index 0000000..2e29a54 --- /dev/null +++ b/SOURCES/glibc-rh1659438-28.patch @@ -0,0 +1,266 @@ +commit 26ea8760877cf03272e98c21eb1a7745ceca76c4 +Author: Stefan Liebler +Date: Tue Dec 18 13:57:14 2018 +0100 + + S390: Refactor strrchr ifunc handling. + + The ifunc handling for strrchr is adjusted in order to omit ifunc + variants if those will never be used as the minimum architecture level + already supports newer CPUs by default. + Glibc internal calls will then also use the "newer" ifunc variant. + + ChangeLog: + + * sysdeps/s390/multiarch/Makefile + (sysdep_routines): Remove strrchr variants. + * sysdeps/s390/Makefile (sysdep_routines): Add strrchr variants. + * sysdeps/s390/multiarch/ifunc-impl-list.c + (__libc_ifunc_impl_list): Refactor ifunc handling for strrchr. + * sysdeps/s390/multiarch/strrchr-c.c: Move to ... + * sysdeps/s390/strrchr-c.c: ... here and adjust ifunc handling. + * sysdeps/s390/multiarch/strrchr-vx.S: Move to ... + * sysdeps/s390/strrchr-vx.S: ... here and adjust ifunc handling. + * sysdeps/s390/multiarch/strrchr.c: Move to ... + * sysdeps/s390/strrchr.c: ... here and adjust ifunc handling. + * sysdeps/s390/ifunc-strrchr.h: New file. + +diff --git a/sysdeps/s390/Makefile b/sysdeps/s390/Makefile +index c54bb82f4d4f8a67..3ad44c997e9f1f6b 100644 +--- a/sysdeps/s390/Makefile ++++ b/sysdeps/s390/Makefile +@@ -48,5 +48,6 @@ sysdep_routines += bzero memset memset-z900 \ + strcmp strcmp-vx strcmp-z900 \ + strncmp strncmp-vx strncmp-c \ + strchr strchr-vx strchr-c \ +- strchrnul strchrnul-vx strchrnul-c ++ strchrnul strchrnul-vx strchrnul-c \ ++ strrchr strrchr-vx strrchr-c + endif +diff --git a/sysdeps/s390/ifunc-strrchr.h b/sysdeps/s390/ifunc-strrchr.h +new file mode 100644 +index 0000000000000000..7185fc32601f7388 +--- /dev/null ++++ b/sysdeps/s390/ifunc-strrchr.h +@@ -0,0 +1,52 @@ ++/* strrchr variant information on S/390 version. ++ 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 ++ . */ ++ ++#if defined USE_MULTIARCH && IS_IN (libc) \ ++ && ! defined HAVE_S390_MIN_Z13_ZARCH_ASM_SUPPORT ++# define HAVE_STRRCHR_IFUNC 1 ++#else ++# define HAVE_STRRCHR_IFUNC 0 ++#endif ++ ++#ifdef HAVE_S390_VX_ASM_SUPPORT ++# define HAVE_STRRCHR_IFUNC_AND_VX_SUPPORT HAVE_STRRCHR_IFUNC ++#else ++# define HAVE_STRRCHR_IFUNC_AND_VX_SUPPORT 0 ++#endif ++ ++#if defined HAVE_S390_MIN_Z13_ZARCH_ASM_SUPPORT ++# define STRRCHR_DEFAULT STRRCHR_Z13 ++# define HAVE_STRRCHR_C 0 ++# define HAVE_STRRCHR_Z13 1 ++#else ++# define STRRCHR_DEFAULT STRRCHR_C ++# define HAVE_STRRCHR_C 1 ++# define HAVE_STRRCHR_Z13 HAVE_STRRCHR_IFUNC_AND_VX_SUPPORT ++#endif ++ ++#if HAVE_STRRCHR_C ++# define STRRCHR_C __strrchr_c ++#else ++# define STRRCHR_C NULL ++#endif ++ ++#if HAVE_STRRCHR_Z13 ++# define STRRCHR_Z13 __strrchr_vx ++#else ++# define STRRCHR_Z13 NULL ++#endif +diff --git a/sysdeps/s390/multiarch/Makefile b/sysdeps/s390/multiarch/Makefile +index 999a979fee1417b2..c8267555585b617e 100644 +--- a/sysdeps/s390/multiarch/Makefile ++++ b/sysdeps/s390/multiarch/Makefile +@@ -1,6 +1,5 @@ + ifeq ($(subdir),string) +-sysdep_routines += strrchr strrchr-vx strrchr-c \ +- strspn strspn-vx strspn-c \ ++sysdep_routines += strspn strspn-vx strspn-c \ + strpbrk strpbrk-vx strpbrk-c \ + strcspn strcspn-vx strcspn-c \ + memchr memchr-vx \ +diff --git a/sysdeps/s390/multiarch/ifunc-impl-list.c b/sysdeps/s390/multiarch/ifunc-impl-list.c +index 0a47ffeac3492b3e..60cd705ffa4e2c35 100644 +--- a/sysdeps/s390/multiarch/ifunc-impl-list.c ++++ b/sysdeps/s390/multiarch/ifunc-impl-list.c +@@ -38,6 +38,7 @@ + #include + #include + #include ++#include + + /* Maximum number of IFUNC implementations. */ + #define MAX_IFUNC 3 +@@ -320,6 +321,18 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + ) + #endif /* HAVE_STRCHRNUL_IFUNC */ + ++#if HAVE_STRRCHR_IFUNC ++ IFUNC_IMPL (i, name, strrchr, ++# if HAVE_STRRCHR_Z13 ++ IFUNC_IMPL_ADD (array, i, strrchr, ++ dl_hwcap & HWCAP_S390_VX, STRRCHR_Z13) ++# endif ++# if HAVE_STRRCHR_C ++ IFUNC_IMPL_ADD (array, i, strrchr, 1, STRRCHR_C) ++# endif ++ ) ++#endif /* HAVE_STRRCHR_IFUNC */ ++ + #ifdef HAVE_S390_VX_ASM_SUPPORT + + # define IFUNC_VX_IMPL(FUNC) \ +@@ -352,7 +365,6 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + + IFUNC_VX_IMPL (wcschrnul); + +- IFUNC_VX_IMPL (strrchr); + IFUNC_VX_IMPL (wcsrchr); + + IFUNC_VX_IMPL (strspn); +diff --git a/sysdeps/s390/multiarch/strrchr-c.c b/sysdeps/s390/strrchr-c.c +similarity index 77% +rename from sysdeps/s390/multiarch/strrchr-c.c +rename to sysdeps/s390/strrchr-c.c +index 53ceb8086f0711c8..615f16da7d9db5ef 100644 +--- a/sysdeps/s390/multiarch/strrchr-c.c ++++ b/sysdeps/s390/strrchr-c.c +@@ -16,14 +16,18 @@ + License along with the GNU C Library; if not, see + . */ + +-#if defined HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc) +-# define STRRCHR __strrchr_c +-# undef weak_alias +-# ifdef SHARED +-# undef libc_hidden_builtin_def +-# define libc_hidden_builtin_def(name) \ ++#include ++ ++#if HAVE_STRRCHR_C ++# if HAVE_STRRCHR_IFUNC ++# define STRRCHR STRRCHR_C ++# undef weak_alias ++# if defined SHARED && IS_IN (libc) ++# undef libc_hidden_builtin_def ++# define libc_hidden_builtin_def(name) \ + __hidden_ver1 (__strrchr_c, __GI_strrchr, __strrchr_c); +-# endif /* SHARED */ ++# endif ++# endif + + # include +-#endif /* HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc) */ ++#endif +diff --git a/sysdeps/s390/multiarch/strrchr-vx.S b/sysdeps/s390/strrchr-vx.S +similarity index 94% +rename from sysdeps/s390/multiarch/strrchr-vx.S +rename to sysdeps/s390/strrchr-vx.S +index 8b3b989631f23de5..5f4ac14ee338c790 100644 +--- a/sysdeps/s390/multiarch/strrchr-vx.S ++++ b/sysdeps/s390/strrchr-vx.S +@@ -16,7 +16,9 @@ + License along with the GNU C Library; if not, see + . */ + +-#if defined HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc) ++#include ++ ++#if HAVE_STRRCHR_Z13 + + # include "sysdep.h" + # include "asm-syntax.h" +@@ -39,7 +41,7 @@ + -v19=part of s with last occurence of c. + -v20=permute pattern + */ +-ENTRY(__strrchr_vx) ++ENTRY(STRRCHR_Z13) + .machine "z13" + .machinemode "zarch_nohighgprs" + +@@ -176,5 +178,15 @@ ENTRY(__strrchr_vx) + .Lpermute_mask: + .byte 0x0F,0x0E,0x0D,0x0C,0x0B,0x0A,0x09,0x08 + .byte 0x07,0x06,0x05,0x04,0x03,0x02,0x01,0x00 +-END(__strrchr_vx) +-#endif /* HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc) */ ++END(STRRCHR_Z13) ++ ++# if ! HAVE_STRRCHR_IFUNC ++strong_alias (STRRCHR_Z13, strrchr) ++weak_alias (strrchr, rindex) ++# endif ++ ++# if ! HAVE_STRRCHR_C && defined SHARED && IS_IN (libc) ++strong_alias (STRRCHR_Z13, __GI_strrchr) ++# endif ++ ++#endif /* HAVE_STRRCHR_Z13 */ +diff --git a/sysdeps/s390/multiarch/strrchr.c b/sysdeps/s390/strrchr.c +similarity index 66% +rename from sysdeps/s390/multiarch/strrchr.c +rename to sysdeps/s390/strrchr.c +index e00e25a3a4f51b1e..9a8cecff0b29c057 100644 +--- a/sysdeps/s390/multiarch/strrchr.c ++++ b/sysdeps/s390/strrchr.c +@@ -16,15 +16,26 @@ + License along with the GNU C Library; if not, see + . */ + +-#if defined HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc) ++#include ++ ++#if HAVE_STRRCHR_IFUNC + # define strrchr __redirect_strrchr + # include + # undef strrchr + # include + +-s390_vx_libc_ifunc2_redirected (__redirect_strrchr, __strrchr, strrchr) +-weak_alias (strrchr, rindex); ++# if HAVE_STRRCHR_C ++extern __typeof (__redirect_strrchr) STRRCHR_C attribute_hidden; ++# endif ++ ++# if HAVE_STRRCHR_Z13 ++extern __typeof (__redirect_strrchr) STRRCHR_Z13 attribute_hidden; ++# endif + +-#else +-# include +-#endif /* !(defined HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc)) */ ++s390_libc_ifunc_expr (__redirect_strrchr, strrchr, ++ (HAVE_STRRCHR_Z13 && (hwcap & HWCAP_S390_VX)) ++ ? STRRCHR_Z13 ++ : STRRCHR_DEFAULT ++ ) ++weak_alias (strrchr, rindex) ++#endif /* HAVE_STRRCHR_IFUNC */ diff --git a/SOURCES/glibc-rh1659438-29.patch b/SOURCES/glibc-rh1659438-29.patch new file mode 100644 index 0000000..edb4940 --- /dev/null +++ b/SOURCES/glibc-rh1659438-29.patch @@ -0,0 +1,263 @@ +commit 483fc56978d11c7118326f92ea678bea2f092300 +Author: Stefan Liebler +Date: Tue Dec 18 13:57:15 2018 +0100 + + S390: Refactor strspn ifunc handling. + + The ifunc handling for strspn is adjusted in order to omit ifunc + variants if those will never be used as the minimum architecture level + already supports newer CPUs by default. + Glibc internal calls will then also use the "newer" ifunc variant. + + ChangeLog: + + * sysdeps/s390/multiarch/Makefile + (sysdep_routines): Remove strspn variants. + * sysdeps/s390/Makefile (sysdep_routines): Add strspn variants. + * sysdeps/s390/multiarch/ifunc-impl-list.c + (__libc_ifunc_impl_list): Refactor ifunc handling for strspn. + * sysdeps/s390/multiarch/strspn-c.c: Move to ... + * sysdeps/s390/strspn-c.c: ... here and adjust ifunc handling. + * sysdeps/s390/multiarch/strspn-vx.S: Move to ... + * sysdeps/s390/strspn-vx.S: ... here and adjust ifunc handling. + * sysdeps/s390/multiarch/strspn.c: Move to ... + * sysdeps/s390/strspn.c: ... here and adjust ifunc handling. + * sysdeps/s390/ifunc-strspn.h: New file. + +diff --git a/sysdeps/s390/Makefile b/sysdeps/s390/Makefile +index 3ad44c997e9f1f6b..c0a402117197b87f 100644 +--- a/sysdeps/s390/Makefile ++++ b/sysdeps/s390/Makefile +@@ -49,5 +49,6 @@ sysdep_routines += bzero memset memset-z900 \ + strncmp strncmp-vx strncmp-c \ + strchr strchr-vx strchr-c \ + strchrnul strchrnul-vx strchrnul-c \ +- strrchr strrchr-vx strrchr-c ++ strrchr strrchr-vx strrchr-c \ ++ strspn strspn-vx strspn-c + endif +diff --git a/sysdeps/s390/ifunc-strspn.h b/sysdeps/s390/ifunc-strspn.h +new file mode 100644 +index 0000000000000000..1152ba1f3d3b9b62 +--- /dev/null ++++ b/sysdeps/s390/ifunc-strspn.h +@@ -0,0 +1,52 @@ ++/* strspn variant information on S/390 version. ++ 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 ++ . */ ++ ++#if defined USE_MULTIARCH && IS_IN (libc) \ ++ && ! defined HAVE_S390_MIN_Z13_ZARCH_ASM_SUPPORT ++# define HAVE_STRSPN_IFUNC 1 ++#else ++# define HAVE_STRSPN_IFUNC 0 ++#endif ++ ++#ifdef HAVE_S390_VX_ASM_SUPPORT ++# define HAVE_STRSPN_IFUNC_AND_VX_SUPPORT HAVE_STRSPN_IFUNC ++#else ++# define HAVE_STRSPN_IFUNC_AND_VX_SUPPORT 0 ++#endif ++ ++#if defined HAVE_S390_MIN_Z13_ZARCH_ASM_SUPPORT ++# define STRSPN_DEFAULT STRSPN_Z13 ++# define HAVE_STRSPN_C 0 ++# define HAVE_STRSPN_Z13 1 ++#else ++# define STRSPN_DEFAULT STRSPN_C ++# define HAVE_STRSPN_C 1 ++# define HAVE_STRSPN_Z13 HAVE_STRSPN_IFUNC_AND_VX_SUPPORT ++#endif ++ ++#if HAVE_STRSPN_C ++# define STRSPN_C __strspn_c ++#else ++# define STRSPN_C NULL ++#endif ++ ++#if HAVE_STRSPN_Z13 ++# define STRSPN_Z13 __strspn_vx ++#else ++# define STRSPN_Z13 NULL ++#endif +diff --git a/sysdeps/s390/multiarch/Makefile b/sysdeps/s390/multiarch/Makefile +index c8267555585b617e..9b141e338ca551ec 100644 +--- a/sysdeps/s390/multiarch/Makefile ++++ b/sysdeps/s390/multiarch/Makefile +@@ -1,6 +1,5 @@ + ifeq ($(subdir),string) +-sysdep_routines += strspn strspn-vx strspn-c \ +- strpbrk strpbrk-vx strpbrk-c \ ++sysdep_routines += strpbrk strpbrk-vx strpbrk-c \ + strcspn strcspn-vx strcspn-c \ + memchr memchr-vx \ + rawmemchr rawmemchr-vx rawmemchr-c \ +diff --git a/sysdeps/s390/multiarch/ifunc-impl-list.c b/sysdeps/s390/multiarch/ifunc-impl-list.c +index 60cd705ffa4e2c35..c39e1f793aad530c 100644 +--- a/sysdeps/s390/multiarch/ifunc-impl-list.c ++++ b/sysdeps/s390/multiarch/ifunc-impl-list.c +@@ -39,6 +39,7 @@ + #include + #include + #include ++#include + + /* Maximum number of IFUNC implementations. */ + #define MAX_IFUNC 3 +@@ -333,6 +334,18 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + ) + #endif /* HAVE_STRRCHR_IFUNC */ + ++#if HAVE_STRSPN_IFUNC ++ IFUNC_IMPL (i, name, strspn, ++# if HAVE_STRSPN_Z13 ++ IFUNC_IMPL_ADD (array, i, strspn, ++ dl_hwcap & HWCAP_S390_VX, STRSPN_Z13) ++# endif ++# if HAVE_STRSPN_C ++ IFUNC_IMPL_ADD (array, i, strspn, 1, STRSPN_C) ++# endif ++ ) ++#endif /* HAVE_STRSPN_IFUNC */ ++ + #ifdef HAVE_S390_VX_ASM_SUPPORT + + # define IFUNC_VX_IMPL(FUNC) \ +@@ -367,7 +380,6 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + + IFUNC_VX_IMPL (wcsrchr); + +- IFUNC_VX_IMPL (strspn); + IFUNC_VX_IMPL (wcsspn); + + IFUNC_VX_IMPL (strpbrk); +diff --git a/sysdeps/s390/multiarch/strspn-c.c b/sysdeps/s390/strspn-c.c +similarity index 78% +rename from sysdeps/s390/multiarch/strspn-c.c +rename to sysdeps/s390/strspn-c.c +index 0efe61bfb2f89caf..506f6683212f03ab 100644 +--- a/sysdeps/s390/multiarch/strspn-c.c ++++ b/sysdeps/s390/strspn-c.c +@@ -16,13 +16,17 @@ + License along with the GNU C Library; if not, see + . */ + +-#if defined HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc) +-# define STRSPN __strspn_c +-# ifdef SHARED +-# undef libc_hidden_builtin_def +-# define libc_hidden_builtin_def(name) \ ++#include ++ ++#if HAVE_STRSPN_C ++# if HAVE_STRSPN_IFUNC ++# define STRSPN STRSPN_C ++# if defined SHARED && IS_IN (libc) ++# undef libc_hidden_builtin_def ++# define libc_hidden_builtin_def(name) \ + __hidden_ver1 (__strspn_c, __GI_strspn, __strspn_c); +-# endif /* SHARED */ ++# endif ++# endif + + # include +-#endif /* HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc) */ ++#endif +diff --git a/sysdeps/s390/multiarch/strspn-vx.S b/sysdeps/s390/strspn-vx.S +similarity index 97% +rename from sysdeps/s390/multiarch/strspn-vx.S +rename to sysdeps/s390/strspn-vx.S +index 6aa823e63b1189c3..ae5529b567ee7435 100644 +--- a/sysdeps/s390/multiarch/strspn-vx.S ++++ b/sysdeps/s390/strspn-vx.S +@@ -16,7 +16,9 @@ + License along with the GNU C Library; if not, see + . */ + +-#if defined HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc) ++#include ++ ++#if HAVE_STRSPN_Z13 + + # include "sysdep.h" + # include "asm-syntax.h" +@@ -57,7 +59,7 @@ + otherwise =0; + r9: loaded byte count of vlbb accept-string + */ +-ENTRY(__strspn_vx) ++ENTRY(STRSPN_Z13) + .machine "z13" + .machinemode "zarch_nohighgprs" + +@@ -252,5 +254,14 @@ ENTRY(__strspn_vx) + Check for zero is in jump-target. */ + j .Lslow_next_acc_notonbb /* ... and search for zero in + fully loaded vreg again. */ +-END(__strspn_vx) +-#endif /* HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc) */ ++END(STRSPN_Z13) ++ ++# if ! HAVE_STRSPN_IFUNC ++strong_alias (STRSPN_Z13, strspn) ++# endif ++ ++# if ! HAVE_STRSPN_C && defined SHARED && IS_IN (libc) ++strong_alias (STRSPN_Z13, __GI_strspn) ++# endif ++ ++#endif /* HAVE_STRSPN_Z13 */ +diff --git a/sysdeps/s390/multiarch/strspn.c b/sysdeps/s390/strspn.c +similarity index 70% +rename from sysdeps/s390/multiarch/strspn.c +rename to sysdeps/s390/strspn.c +index bedbe98cfc4ab14d..91401fdaf89ed8a2 100644 +--- a/sysdeps/s390/multiarch/strspn.c ++++ b/sysdeps/s390/strspn.c +@@ -16,7 +16,9 @@ + License along with the GNU C Library; if not, see + . */ + +-#if defined HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc) ++#include ++ ++#if HAVE_STRSPN_IFUNC + # define strspn __redirect_strspn + /* Omit the strspn inline definitions because it would redefine strspn. */ + # define __NO_STRING_INLINES +@@ -24,8 +26,17 @@ + # undef strspn + # include + +-s390_vx_libc_ifunc2_redirected (__redirect_strspn, __strspn, strspn) ++# if HAVE_STRSPN_C ++extern __typeof (__redirect_strspn) STRSPN_C attribute_hidden; ++# endif ++ ++# if HAVE_STRSPN_Z13 ++extern __typeof (__redirect_strspn) STRSPN_Z13 attribute_hidden; ++# endif + +-#else +-# include +-#endif /* !(defined HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc)) */ ++s390_libc_ifunc_expr (__redirect_strspn, strspn, ++ (HAVE_STRSPN_Z13 && (hwcap & HWCAP_S390_VX)) ++ ? STRSPN_Z13 ++ : STRSPN_DEFAULT ++ ) ++#endif /* HAVE_STRSPN_IFUNC */ diff --git a/SOURCES/glibc-rh1659438-3.patch b/SOURCES/glibc-rh1659438-3.patch new file mode 100644 index 0000000..161448c --- /dev/null +++ b/SOURCES/glibc-rh1659438-3.patch @@ -0,0 +1,440 @@ +commit 5f1743d118047ff1fbefe713f2397090e0418deb +Author: Stefan Liebler +Date: Tue Dec 18 13:57:04 2018 +0100 + + S390: Unify 31/64bit memset. + + The implementation of memset for s390-32 (31bit) and + s390-64 (64bit) is nearly the same. + This patch unifies it for maintability reasons. + + __memset_z10 and __memset_z196 differs between 31 and 64bit: + -31bit needs .machinemode "zarch_nohighgprs" and llgfr %r4,%r4 + -lr vs lgr and some other instructions: + But lgr and co can be also used on 31bit as this ifunc variant + is only called if we are on a zarch machine. + + __memset_default differs between 31 and 64bit: + -Some 31bit vs 64bit instructions (e.g. ltr vs ltgr. + Solved with 31/64 specific instruction macros). + -The address of mvc instruction is setup in different ways + (larl vs bras). Solved with #if defined __s390x__. + + Otherwise 31/64bit implementation has the same structure of the code. + + ChangeLog: + + * sysdeps/s390/s390-64/memset.S: Move to ... + * sysdeps/s390/memset.S: ... here. + Adjust to be usable for 31/64bit. + * sysdeps/s390/s390-32/memset.S: Delete File. + * sysdeps/s390/multiarch/Makefile (sysdep_routines): Add memset. + * sysdeps/s390/s390-32/multiarch/Makefile (sysdep_routines): + Remove memset. + * sysdeps/s390/s390-64/multiarch/Makefile: Likewise. + * sysdeps/s390/s390-64/multiarch/memset-s390x.S: Move to ... + * sysdeps/s390/multiarch/memset-s390x.S: ... here. + Adjust to be usable for 31/64bit. + * sysdeps/s390/s390-32/multiarch/memset-s390.S: Delete File. + * sysdeps/s390/s390-64/multiarch/memset.c: Move to ... + * sysdeps/s390/multiarch/memset.c: ... here. + * sysdeps/s390/s390-32/multiarch/memset.c: Delete File. + +diff --git a/sysdeps/s390/s390-64/memset.S b/sysdeps/s390/memset.S +similarity index 58% +rename from sysdeps/s390/s390-64/memset.S +rename to sysdeps/s390/memset.S +index 8799c6592ce2dacf..72e7c5a42efbaf6c 100644 +--- a/sysdeps/s390/s390-64/memset.S ++++ b/sysdeps/s390/memset.S +@@ -1,4 +1,4 @@ +-/* Set a block of memory to some byte value. 64 bit S/390 version. ++/* Set a block of memory to some byte value. 31/64 bit S/390 version. + Copyright (C) 2001-2018 Free Software Foundation, Inc. + Contributed by Martin Schwidefsky (schwidefsky@de.ibm.com). + This file is part of the GNU C Library. +@@ -28,33 +28,60 @@ + + .text + ++#if defined __s390x__ ++# define LTGR ltgr ++# define CGHI cghi ++# define LGR lgr ++# define AGHI aghi ++# define BRCTG brctg ++#else ++# define LTGR ltr ++# define CGHI chi ++# define LGR lr ++# define AGHI ahi ++# define BRCTG brct ++#endif /* ! defined __s390x__ */ ++ + #ifdef USE_MULTIARCH + ENTRY(__memset_default) + #else + ENTRY(memset) + #endif ++#if defined __s390x__ + .machine "z900" +- ltgr %r4,%r4 +- je .L_Z900_4 ++#else ++ .machine "g5" ++#endif /* ! defined __s390x__ */ ++ LTGR %r4,%r4 ++ je .L_Z900_G5_4 + stc %r3,0(%r2) +- cghi %r4,1 +- lgr %r1,%r2 +- je .L_Z900_4 +- aghi %r4,-2 ++ CGHI %r4,1 ++ LGR %r1,%r2 ++ je .L_Z900_G5_4 ++ AGHI %r4,-2 ++#if defined __s390x__ ++ larl %r5,.L_Z900_G5_18 + srlg %r3,%r4,8 +- ltgr %r3,%r3 +- jne .L_Z900_14 +-.L_Z900_3: +- larl %r3,.L_Z900_18 +- ex %r4,0(%r3) +-.L_Z900_4: ++# define Z900_G5_EX_D 0 ++#else ++ basr %r5,0 ++.L_Z900_G5_19: ++# define Z900_G5_EX_D .L_Z900_G5_18-.L_Z900_G5_19 ++ lr %r3,%r4 ++ srl %r3,8 ++#endif /* ! defined __s390x__ */ ++ LTGR %r3,%r3 ++ jne .L_Z900_G5_14 ++.L_Z900_G5_3: ++ ex %r4,Z900_G5_EX_D(%r5) ++.L_Z900_G5_4: + br %r14 +-.L_Z900_14: ++.L_Z900_G5_14: + mvc 1(256,%r1),0(%r1) + la %r1,256(%r1) +- brctg %r3,.L_Z900_14 +- j .L_Z900_3 +-.L_Z900_18: ++ BRCTG %r3,.L_Z900_G5_14 ++ j .L_Z900_G5_3 ++.L_Z900_G5_18: + mvc 1(1,%r1),0(%r1) + #ifdef USE_MULTIARCH + END(__memset_default) +@@ -62,3 +89,9 @@ END(__memset_default) + END(memset) + libc_hidden_builtin_def (memset) + #endif ++ ++#undef LTGR ++#undef CGHI ++#undef LGR ++#undef AGHI ++#undef BRCTG +diff --git a/sysdeps/s390/multiarch/Makefile b/sysdeps/s390/multiarch/Makefile +index c893ebc5659fd4ae..93ad21bfa2686ee5 100644 +--- a/sysdeps/s390/multiarch/Makefile ++++ b/sysdeps/s390/multiarch/Makefile +@@ -19,7 +19,8 @@ sysdep_routines += strlen strlen-vx strlen-c \ + rawmemchr rawmemchr-vx rawmemchr-c \ + memccpy memccpy-vx memccpy-c \ + memrchr memrchr-vx memrchr-c \ +- mempcpy ++ mempcpy \ ++ memset memset-s390x + endif + + ifeq ($(subdir),wcsmbs) +diff --git a/sysdeps/s390/s390-64/multiarch/memset-s390x.S b/sysdeps/s390/multiarch/memset-s390x.S +similarity index 90% +rename from sysdeps/s390/s390-64/multiarch/memset-s390x.S +rename to sysdeps/s390/multiarch/memset-s390x.S +index 0c5aaef34fdf47e6..aca3ac3fda1dd228 100644 +--- a/sysdeps/s390/s390-64/multiarch/memset-s390x.S ++++ b/sysdeps/s390/multiarch/memset-s390x.S +@@ -1,4 +1,4 @@ +-/* Set a block of memory to some byte value. 64 bit S/390 version. ++/* Set a block of memory to some byte value. 31/64 bit S/390 version. + Copyright (C) 2012-2018 Free Software Foundation, Inc. + This file is part of the GNU C Library. + +@@ -31,6 +31,10 @@ + + ENTRY(__memset_z196) + .machine "z196" ++ .machinemode "zarch_nohighgprs" ++# if !defined __s390x__ ++ llgfr %r4,%r4 ++# endif /* !defined __s390x__ */ + ltgr %r4,%r4 + je .L_Z196_4 + stc %r3,0(%r2) +@@ -61,6 +65,10 @@ END(__memset_z196) + + ENTRY(__memset_z10) + .machine "z10" ++ .machinemode "zarch_nohighgprs" ++# if !defined __s390x__ ++ llgfr %r4,%r4 ++# endif /* !defined __s390x__ */ + cgije %r4,0,.L_Z10_4 + stc %r3,0(%r2) + lgr %r1,%r2 +diff --git a/sysdeps/s390/s390-32/multiarch/memset.c b/sysdeps/s390/multiarch/memset.c +similarity index 100% +rename from sysdeps/s390/s390-32/multiarch/memset.c +rename to sysdeps/s390/multiarch/memset.c +diff --git a/sysdeps/s390/s390-32/memset.S b/sysdeps/s390/s390-32/memset.S +deleted file mode 100644 +index 57f08e1cae1abd01..0000000000000000 +--- a/sysdeps/s390/s390-32/memset.S ++++ /dev/null +@@ -1,65 +0,0 @@ +-/* Set a block of memory to some byte value. For IBM S390 +- Copyright (C) 2012-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 "sysdep.h" +-#include "asm-syntax.h" +- +-/* INPUT PARAMETERS +- %r2 = address to memory area +- %r3 = byte to fill memory with +- %r4 = number of bytes to fill. */ +- +- .text +- +-#ifdef USE_MULTIARCH +-ENTRY(__memset_default) +-#else +-ENTRY(memset) +-#endif +- .machine "g5" +- basr %r5,0 +-.L_G5_19: +- ltr %r4,%r4 +- je .L_G5_4 +- stc %r3,0(%r2) +- chi %r4,1 +- lr %r1,%r2 +- je .L_G5_4 +- ahi %r4,-2 +- lr %r3,%r4 +- srl %r3,8 +- ltr %r3,%r3 +- jne .L_G5_14 +- ex %r4,.L_G5_20-.L_G5_19(%r5) +-.L_G5_4: +- br %r14 +-.L_G5_14: +- mvc 1(256,%r1),0(%r1) +- la %r1,256(%r1) +- brct %r3,.L_G5_14 +- ex %r4,.L_G5_20-.L_G5_19(%r5) +- j .L_G5_4 +-.L_G5_20: +- mvc 1(1,%r1),0(%r1) +-#ifdef USE_MULTIARCH +-END(__memset_default) +-#else +-END(memset) +-libc_hidden_builtin_def (memset) +-#endif +diff --git a/sysdeps/s390/s390-32/multiarch/Makefile b/sysdeps/s390/s390-32/multiarch/Makefile +index f8aee14bbd4736ad..4b11e28656ac19ab 100644 +--- a/sysdeps/s390/s390-32/multiarch/Makefile ++++ b/sysdeps/s390/s390-32/multiarch/Makefile +@@ -1,4 +1,3 @@ + ifeq ($(subdir),string) +-sysdep_routines += memset memset-s390 memcpy memcpy-s390 \ +- memcmp memcmp-s390 ++sysdep_routines += memcpy memcpy-s390 memcmp memcmp-s390 + endif +diff --git a/sysdeps/s390/s390-32/multiarch/memset-s390.S b/sysdeps/s390/s390-32/multiarch/memset-s390.S +deleted file mode 100644 +index b092073d6bef6b56..0000000000000000 +--- a/sysdeps/s390/s390-32/multiarch/memset-s390.S ++++ /dev/null +@@ -1,116 +0,0 @@ +-/* Set a block of memory to some byte value. 32 bit S/390 version. +- Copyright (C) 2012-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 "sysdep.h" +-#include "asm-syntax.h" +- +-/* INPUT PARAMETERS +- %r2 = address of memory area +- %r3 = byte to fill memory with +- %r4 = number of bytes to fill. */ +- +- .text +- +-#if IS_IN (libc) +- +-ENTRY(__memset_z196) +- .machine "z196" +- .machinemode "zarch_nohighgprs" +- llgfr %r4,%r4 +- ltgr %r4,%r4 +- je .L_Z196_4 +- stc %r3,0(%r2) +- lr %r1,%r2 +- cghi %r4,1 +- je .L_Z196_4 +- aghi %r4,-2 +- srlg %r5,%r4,8 +- ltgr %r5,%r5 +- jne .L_Z196_1 +-.L_Z196_3: +- exrl %r4,.L_Z196_17 +-.L_Z196_4: +- br %r14 +-.L_Z196_1: +- cgfi %r5,1048576 +- jh __memset_mvcle # Switch to mvcle for >256MB +-.L_Z196_2: +- pfd 2,1024(%r1) +- mvc 1(256,%r1),0(%r1) +- aghi %r5,-1 +- la %r1,256(%r1) +- jne .L_Z196_2 +- j .L_Z196_3 +-.L_Z196_17: +- mvc 1(1,%r1),0(%r1) +-END(__memset_z196) +- +-ENTRY(__memset_z10) +- .machine "z10" +- .machinemode "zarch_nohighgprs" +- llgfr %r4,%r4 +- cgije %r4,0,.L_Z10_4 +- stc %r3,0(%r2) +- lr %r1,%r2 +- cgije %r4,1,.L_Z10_4 +- aghi %r4,-2 +- srlg %r5,%r4,8 +- cgijlh %r5,0,.L_Z10_15 +-.L_Z10_3: +- exrl %r4,.L_Z10_18 +-.L_Z10_4: +- br %r14 +-.L_Z10_15: +- cgfi %r5,163840 # Switch to mvcle for >40MB +- jh __memset_mvcle +-.L_Z10_14: +- pfd 2,1024(%r1) +- mvc 1(256,%r1),0(%r1) +- la %r1,256(%r1) +- brctg %r5,.L_Z10_14 +- j .L_Z10_3 +-.L_Z10_18: +- mvc 1(1,%r1),0(%r1) +-END(__memset_z10) +- +-ENTRY(__memset_mvcle) +- ahi %r4,2 # take back the change done by the caller +- lr %r0,%r2 # save source address +- lr %r1,%r3 # move pad byte to R1 +- lr %r3,%r4 +- sr %r4,%r4 # no source for MVCLE, only a pad byte +- sr %r5,%r5 +-.L0: mvcle %r2,%r4,0(%r1) # thats it, MVCLE is your friend +- jo .L0 +- lr %r2,%r0 # return value is source address +-.L1: +- br %r14 +-END(__memset_mvcle) +- +-#endif /* IS_IN (libc) */ +- +-#include "../memset.S" +- +-#if !IS_IN (libc) +-.globl memset +-.set memset,__memset_default +-#elif defined SHARED && IS_IN (libc) +-.globl __GI_memset +-.set __GI_memset,__memset_default +-#endif +diff --git a/sysdeps/s390/s390-64/multiarch/Makefile b/sysdeps/s390/s390-64/multiarch/Makefile +index 91053b536420aabb..e4870c7ee177ad0d 100644 +--- a/sysdeps/s390/s390-64/multiarch/Makefile ++++ b/sysdeps/s390/s390-64/multiarch/Makefile +@@ -1,4 +1,3 @@ + ifeq ($(subdir),string) +-sysdep_routines += memset memset-s390x memcpy memcpy-s390x \ +- memcmp memcmp-s390x ++sysdep_routines += memcpy memcpy-s390x memcmp memcmp-s390x + endif +diff --git a/sysdeps/s390/s390-64/multiarch/memset.c b/sysdeps/s390/s390-64/multiarch/memset.c +deleted file mode 100644 +index 760b3e9df201b8b4..0000000000000000 +--- a/sysdeps/s390/s390-64/multiarch/memset.c ++++ /dev/null +@@ -1,26 +0,0 @@ +-/* Multiple versions of memset. +- 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 +- . */ +- +-#if IS_IN (libc) +-# define memset __redirect_memset +-# include +-# undef memset +-# include +- +-s390_libc_ifunc (__redirect_memset, __memset, memset) +-#endif diff --git a/SOURCES/glibc-rh1659438-30.patch b/SOURCES/glibc-rh1659438-30.patch new file mode 100644 index 0000000..9e7db8e --- /dev/null +++ b/SOURCES/glibc-rh1659438-30.patch @@ -0,0 +1,264 @@ +commit 572cca93fafa59d641c11372a9556722d95b038c +Author: Stefan Liebler +Date: Tue Dec 18 13:57:15 2018 +0100 + + S390: Refactor strpbrk ifunc handling. + + The ifunc handling for strpbrk is adjusted in order to omit ifunc + variants if those will never be used as the minimum architecture level + already supports newer CPUs by default. + Glibc internal calls will then also use the "newer" ifunc variant. + + ChangeLog: + + * sysdeps/s390/multiarch/Makefile + (sysdep_routines): Remove strpbrk variants. + * sysdeps/s390/Makefile (sysdep_routines): Add strpbrk variants. + * sysdeps/s390/multiarch/ifunc-impl-list.c + (__libc_ifunc_impl_list): Refactor ifunc handling for strpbrk. + * sysdeps/s390/multiarch/strpbrk-c.c: Move to ... + * sysdeps/s390/strpbrk-c.c: ... here and adjust ifunc handling. + * sysdeps/s390/multiarch/strpbrk-vx.S: Move to ... + * sysdeps/s390/strpbrk-vx.S: ... here and adjust ifunc handling. + * sysdeps/s390/multiarch/strpbrk.c: Move to ... + * sysdeps/s390/strpbrk.c: ... here and adjust ifunc handling. + * sysdeps/s390/ifunc-strpbrk.h: New file. + +diff --git a/sysdeps/s390/Makefile b/sysdeps/s390/Makefile +index c0a402117197b87f..a21fa7507b1d64a1 100644 +--- a/sysdeps/s390/Makefile ++++ b/sysdeps/s390/Makefile +@@ -50,5 +50,6 @@ sysdep_routines += bzero memset memset-z900 \ + strchr strchr-vx strchr-c \ + strchrnul strchrnul-vx strchrnul-c \ + strrchr strrchr-vx strrchr-c \ +- strspn strspn-vx strspn-c ++ strspn strspn-vx strspn-c \ ++ strpbrk strpbrk-vx strpbrk-c + endif +diff --git a/sysdeps/s390/ifunc-strpbrk.h b/sysdeps/s390/ifunc-strpbrk.h +new file mode 100644 +index 0000000000000000..4a3138c6bf377286 +--- /dev/null ++++ b/sysdeps/s390/ifunc-strpbrk.h +@@ -0,0 +1,52 @@ ++/* strpbrk variant information on S/390 version. ++ 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 ++ . */ ++ ++#if defined USE_MULTIARCH && IS_IN (libc) \ ++ && ! defined HAVE_S390_MIN_Z13_ZARCH_ASM_SUPPORT ++# define HAVE_STRPBRK_IFUNC 1 ++#else ++# define HAVE_STRPBRK_IFUNC 0 ++#endif ++ ++#ifdef HAVE_S390_VX_ASM_SUPPORT ++# define HAVE_STRPBRK_IFUNC_AND_VX_SUPPORT HAVE_STRPBRK_IFUNC ++#else ++# define HAVE_STRPBRK_IFUNC_AND_VX_SUPPORT 0 ++#endif ++ ++#if defined HAVE_S390_MIN_Z13_ZARCH_ASM_SUPPORT ++# define STRPBRK_DEFAULT STRPBRK_Z13 ++# define HAVE_STRPBRK_C 0 ++# define HAVE_STRPBRK_Z13 1 ++#else ++# define STRPBRK_DEFAULT STRPBRK_C ++# define HAVE_STRPBRK_C 1 ++# define HAVE_STRPBRK_Z13 HAVE_STRPBRK_IFUNC_AND_VX_SUPPORT ++#endif ++ ++#if HAVE_STRPBRK_C ++# define STRPBRK_C __strpbrk_c ++#else ++# define STRPBRK_C NULL ++#endif ++ ++#if HAVE_STRPBRK_Z13 ++# define STRPBRK_Z13 __strpbrk_vx ++#else ++# define STRPBRK_Z13 NULL ++#endif +diff --git a/sysdeps/s390/multiarch/Makefile b/sysdeps/s390/multiarch/Makefile +index 9b141e338ca551ec..1a3fed9fc88012d1 100644 +--- a/sysdeps/s390/multiarch/Makefile ++++ b/sysdeps/s390/multiarch/Makefile +@@ -1,6 +1,5 @@ + ifeq ($(subdir),string) +-sysdep_routines += strpbrk strpbrk-vx strpbrk-c \ +- strcspn strcspn-vx strcspn-c \ ++sysdep_routines += strcspn strcspn-vx strcspn-c \ + memchr memchr-vx \ + rawmemchr rawmemchr-vx rawmemchr-c \ + memccpy memccpy-vx memccpy-c \ +diff --git a/sysdeps/s390/multiarch/ifunc-impl-list.c b/sysdeps/s390/multiarch/ifunc-impl-list.c +index c39e1f793aad530c..8e23416730f8a8d5 100644 +--- a/sysdeps/s390/multiarch/ifunc-impl-list.c ++++ b/sysdeps/s390/multiarch/ifunc-impl-list.c +@@ -40,6 +40,7 @@ + #include + #include + #include ++#include + + /* Maximum number of IFUNC implementations. */ + #define MAX_IFUNC 3 +@@ -346,6 +347,18 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + ) + #endif /* HAVE_STRSPN_IFUNC */ + ++#if HAVE_STRPBRK_IFUNC ++ IFUNC_IMPL (i, name, strpbrk, ++# if HAVE_STRPBRK_Z13 ++ IFUNC_IMPL_ADD (array, i, strpbrk, ++ dl_hwcap & HWCAP_S390_VX, STRPBRK_Z13) ++# endif ++# if HAVE_STRPBRK_C ++ IFUNC_IMPL_ADD (array, i, strpbrk, 1, STRPBRK_C) ++# endif ++ ) ++#endif /* HAVE_STRPBRK_IFUNC */ ++ + #ifdef HAVE_S390_VX_ASM_SUPPORT + + # define IFUNC_VX_IMPL(FUNC) \ +@@ -382,7 +395,6 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + + IFUNC_VX_IMPL (wcsspn); + +- IFUNC_VX_IMPL (strpbrk); + IFUNC_VX_IMPL (wcspbrk); + + IFUNC_VX_IMPL (strcspn); +diff --git a/sysdeps/s390/multiarch/strpbrk-c.c b/sysdeps/s390/strpbrk-c.c +similarity index 73% +rename from sysdeps/s390/multiarch/strpbrk-c.c +rename to sysdeps/s390/strpbrk-c.c +index 2c0517aeb52985b3..70cc5db672adb6c9 100644 +--- a/sysdeps/s390/multiarch/strpbrk-c.c ++++ b/sysdeps/s390/strpbrk-c.c +@@ -16,13 +16,17 @@ + License along with the GNU C Library; if not, see + . */ + +-#if defined HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc) +-# define STRPBRK __strpbrk_c +-# ifdef SHARED +-# undef libc_hidden_builtin_def +-# define libc_hidden_builtin_def(name) \ +- __hidden_ver1 (__strpbrk_c, __GI_strpbrk, __strpbrk_c); +-# endif /* SHARED */ ++#include ++ ++#if HAVE_STRPBRK_C ++# if HAVE_STRPBRK_IFUNC ++# define STRPBRK STRPBRK_C ++# if defined SHARED && IS_IN (libc) ++# undef libc_hidden_builtin_def ++# define libc_hidden_builtin_def(name) \ ++ __hidden_ver1 (__strpbrk_c, __GI_strpbrk, __strpbrk_c); ++# endif ++# endif + + # include +-#endif /* HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc) */ ++#endif +diff --git a/sysdeps/s390/multiarch/strpbrk-vx.S b/sysdeps/s390/strpbrk-vx.S +similarity index 97% +rename from sysdeps/s390/multiarch/strpbrk-vx.S +rename to sysdeps/s390/strpbrk-vx.S +index e19c550ed404a9a8..0fc7dc143337779f 100644 +--- a/sysdeps/s390/multiarch/strpbrk-vx.S ++++ b/sysdeps/s390/strpbrk-vx.S +@@ -16,7 +16,9 @@ + License along with the GNU C Library; if not, see + . */ + +-#if defined HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc) ++#include ++ ++#if HAVE_STRPBRK_Z13 + + # include "sysdep.h" + # include "asm-syntax.h" +@@ -59,7 +61,7 @@ + otherwise =0; + r9: loaded byte count of vlbb accept-string + */ +-ENTRY(__strpbrk_vx) ++ENTRY(STRPBRK_Z13) + .machine "z13" + .machinemode "zarch_nohighgprs" + +@@ -298,5 +300,14 @@ ENTRY(__strpbrk_vx) + vlgvg %r9,%v31,1 + lgr %r2,%r1 + br %r14 +-END(__strpbrk_vx) +-#endif /* HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc) */ ++END(STRPBRK_Z13) ++ ++# if ! HAVE_STRPBRK_IFUNC ++strong_alias (STRPBRK_Z13, strpbrk) ++# endif ++ ++# if ! HAVE_STRPBRK_C && defined SHARED && IS_IN (libc) ++strong_alias (STRPBRK_Z13, __GI_strpbrk) ++# endif ++ ++#endif /* HAVE_STRPBRK_Z13 */ +diff --git a/sysdeps/s390/multiarch/strpbrk.c b/sysdeps/s390/strpbrk.c +similarity index 70% +rename from sysdeps/s390/multiarch/strpbrk.c +rename to sysdeps/s390/strpbrk.c +index 11afc268f702ce09..41ce00a1aedf0020 100644 +--- a/sysdeps/s390/multiarch/strpbrk.c ++++ b/sysdeps/s390/strpbrk.c +@@ -16,7 +16,9 @@ + License along with the GNU C Library; if not, see + . */ + +-#if defined HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc) ++#include ++ ++#if HAVE_STRPBRK_IFUNC + # define strpbrk __redirect_strpbrk + /* Omit the strpbrk inline definitions because it would redefine strpbrk. */ + # define __NO_STRING_INLINES +@@ -24,8 +26,17 @@ + # undef strpbrk + # include + +-s390_vx_libc_ifunc2_redirected (__redirect_strpbrk, __strpbrk, strpbrk) ++# if HAVE_STRPBRK_C ++extern __typeof (__redirect_strpbrk) STRPBRK_C attribute_hidden; ++# endif ++ ++# if HAVE_STRPBRK_Z13 ++extern __typeof (__redirect_strpbrk) STRPBRK_Z13 attribute_hidden; ++# endif + +-#else +-# include +-#endif /* !(defined HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc)) */ ++s390_libc_ifunc_expr (__redirect_strpbrk, strpbrk, ++ (HAVE_STRPBRK_Z13 && (hwcap & HWCAP_S390_VX)) ++ ? STRPBRK_Z13 ++ : STRPBRK_DEFAULT ++ ) ++#endif /* HAVE_STRPBRK_IFUNC */ diff --git a/SOURCES/glibc-rh1659438-31.patch b/SOURCES/glibc-rh1659438-31.patch new file mode 100644 index 0000000..e448fc9 --- /dev/null +++ b/SOURCES/glibc-rh1659438-31.patch @@ -0,0 +1,264 @@ +commit 5d2ec20a997b87c1667e0e71b3ff1e9df96eac15 +Author: Stefan Liebler +Date: Tue Dec 18 13:57:15 2018 +0100 + + S390: Refactor strcspn ifunc handling. + + The ifunc handling for strcspn is adjusted in order to omit ifunc + variants if those will never be used as the minimum architecture level + already supports newer CPUs by default. + Glibc internal calls will then also use the "newer" ifunc variant. + + ChangeLog: + + * sysdeps/s390/multiarch/Makefile + (sysdep_routines): Remove strcspn variants. + * sysdeps/s390/Makefile (sysdep_routines): Add strcspn variants. + * sysdeps/s390/multiarch/ifunc-impl-list.c + (__libc_ifunc_impl_list): Refactor ifunc handling for strcspn. + * sysdeps/s390/multiarch/strcspn-c.c: Move to ... + * sysdeps/s390/strcspn-c.c: ... here and adjust ifunc handling. + * sysdeps/s390/multiarch/strcspn-vx.S: Move to ... + * sysdeps/s390/strcspn-vx.S: ... here and adjust ifunc handling. + * sysdeps/s390/multiarch/strcspn.c: Move to ... + * sysdeps/s390/strcspn.c: ... here and adjust ifunc handling. + * sysdeps/s390/ifunc-strcspn.h: New file. + +diff --git a/sysdeps/s390/Makefile b/sysdeps/s390/Makefile +index a21fa7507b1d64a1..092d55826fbd15a5 100644 +--- a/sysdeps/s390/Makefile ++++ b/sysdeps/s390/Makefile +@@ -51,5 +51,6 @@ sysdep_routines += bzero memset memset-z900 \ + strchrnul strchrnul-vx strchrnul-c \ + strrchr strrchr-vx strrchr-c \ + strspn strspn-vx strspn-c \ +- strpbrk strpbrk-vx strpbrk-c ++ strpbrk strpbrk-vx strpbrk-c \ ++ strcspn strcspn-vx strcspn-c + endif +diff --git a/sysdeps/s390/ifunc-strcspn.h b/sysdeps/s390/ifunc-strcspn.h +new file mode 100644 +index 0000000000000000..9b7032509a2fb9a8 +--- /dev/null ++++ b/sysdeps/s390/ifunc-strcspn.h +@@ -0,0 +1,52 @@ ++/* strcspn variant information on S/390 version. ++ 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 ++ . */ ++ ++#if defined USE_MULTIARCH && IS_IN (libc) \ ++ && ! defined HAVE_S390_MIN_Z13_ZARCH_ASM_SUPPORT ++# define HAVE_STRCSPN_IFUNC 1 ++#else ++# define HAVE_STRCSPN_IFUNC 0 ++#endif ++ ++#ifdef HAVE_S390_VX_ASM_SUPPORT ++# define HAVE_STRCSPN_IFUNC_AND_VX_SUPPORT HAVE_STRCSPN_IFUNC ++#else ++# define HAVE_STRCSPN_IFUNC_AND_VX_SUPPORT 0 ++#endif ++ ++#if defined HAVE_S390_MIN_Z13_ZARCH_ASM_SUPPORT ++# define STRCSPN_DEFAULT STRCSPN_Z13 ++# define HAVE_STRCSPN_C 0 ++# define HAVE_STRCSPN_Z13 1 ++#else ++# define STRCSPN_DEFAULT STRCSPN_C ++# define HAVE_STRCSPN_C 1 ++# define HAVE_STRCSPN_Z13 HAVE_STRCSPN_IFUNC_AND_VX_SUPPORT ++#endif ++ ++#if HAVE_STRCSPN_C ++# define STRCSPN_C __strcspn_c ++#else ++# define STRCSPN_C NULL ++#endif ++ ++#if HAVE_STRCSPN_Z13 ++# define STRCSPN_Z13 __strcspn_vx ++#else ++# define STRCSPN_Z13 NULL ++#endif +diff --git a/sysdeps/s390/multiarch/Makefile b/sysdeps/s390/multiarch/Makefile +index 1a3fed9fc88012d1..1578f21af4a1bd06 100644 +--- a/sysdeps/s390/multiarch/Makefile ++++ b/sysdeps/s390/multiarch/Makefile +@@ -1,6 +1,5 @@ + ifeq ($(subdir),string) +-sysdep_routines += strcspn strcspn-vx strcspn-c \ +- memchr memchr-vx \ ++sysdep_routines += memchr memchr-vx \ + rawmemchr rawmemchr-vx rawmemchr-c \ + memccpy memccpy-vx memccpy-c \ + memrchr memrchr-vx memrchr-c +diff --git a/sysdeps/s390/multiarch/ifunc-impl-list.c b/sysdeps/s390/multiarch/ifunc-impl-list.c +index 8e23416730f8a8d5..2d48c99c8d5663fe 100644 +--- a/sysdeps/s390/multiarch/ifunc-impl-list.c ++++ b/sysdeps/s390/multiarch/ifunc-impl-list.c +@@ -41,6 +41,7 @@ + #include + #include + #include ++#include + + /* Maximum number of IFUNC implementations. */ + #define MAX_IFUNC 3 +@@ -359,6 +360,18 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + ) + #endif /* HAVE_STRPBRK_IFUNC */ + ++#if HAVE_STRCSPN_IFUNC ++ IFUNC_IMPL (i, name, strcspn, ++# if HAVE_STRCSPN_Z13 ++ IFUNC_IMPL_ADD (array, i, strcspn, ++ dl_hwcap & HWCAP_S390_VX, STRCSPN_Z13) ++# endif ++# if HAVE_STRCSPN_C ++ IFUNC_IMPL_ADD (array, i, strcspn, 1, STRCSPN_C) ++# endif ++ ) ++#endif /* HAVE_STRCSPN_IFUNC */ ++ + #ifdef HAVE_S390_VX_ASM_SUPPORT + + # define IFUNC_VX_IMPL(FUNC) \ +@@ -397,7 +410,6 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + + IFUNC_VX_IMPL (wcspbrk); + +- IFUNC_VX_IMPL (strcspn); + IFUNC_VX_IMPL (wcscspn); + + IFUNC_VX_IMPL (memchr); +diff --git a/sysdeps/s390/multiarch/strcspn-c.c b/sysdeps/s390/strcspn-c.c +similarity index 73% +rename from sysdeps/s390/multiarch/strcspn-c.c +rename to sysdeps/s390/strcspn-c.c +index 7b454f5b56077abc..9f51f92bdbd49a67 100644 +--- a/sysdeps/s390/multiarch/strcspn-c.c ++++ b/sysdeps/s390/strcspn-c.c +@@ -16,13 +16,17 @@ + License along with the GNU C Library; if not, see + . */ + +-#if defined HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc) +-# define STRCSPN __strcspn_c +-# ifdef SHARED +-# undef libc_hidden_builtin_def +-# define libc_hidden_builtin_def(name) \ +- __hidden_ver1 (__strcspn_c, __GI_strcspn, __strcspn_c); +-# endif /* SHARED */ ++#include ++ ++#if HAVE_STRCSPN_C ++# if HAVE_STRCSPN_IFUNC ++# define STRCSPN STRCSPN_C ++# if defined SHARED && IS_IN (libc) ++# undef libc_hidden_builtin_def ++# define libc_hidden_builtin_def(name) \ ++ __hidden_ver1 (__strcspn_c, __GI_strcspn, __strcspn_c); ++# endif ++# endif + + # include +-#endif /* HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc) */ ++#endif +diff --git a/sysdeps/s390/multiarch/strcspn-vx.S b/sysdeps/s390/strcspn-vx.S +similarity index 97% +rename from sysdeps/s390/multiarch/strcspn-vx.S +rename to sysdeps/s390/strcspn-vx.S +index ea1668742bd1c7ff..ff5b1be549e6e210 100644 +--- a/sysdeps/s390/multiarch/strcspn-vx.S ++++ b/sysdeps/s390/strcspn-vx.S +@@ -16,7 +16,9 @@ + License along with the GNU C Library; if not, see + . */ + +-#if defined HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc) ++#include ++ ++#if HAVE_STRCSPN_Z13 + + # include "sysdep.h" + # include "asm-syntax.h" +@@ -58,7 +60,7 @@ + otherwise =0; + r9: loaded byte count of vlbb reject-string + */ +-ENTRY(__strcspn_vx) ++ENTRY(STRCSPN_Z13) + .machine "z13" + .machinemode "zarch_nohighgprs" + +@@ -277,5 +279,14 @@ ENTRY(__strcspn_vx) + vlgvg %r8,%v31,0 + vlgvg %r9,%v31,1 + br %r14 +-END(__strcspn_vx) +-#endif /* HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc) */ ++END(STRCSPN_Z13) ++ ++# if ! HAVE_STRCSPN_IFUNC ++strong_alias (STRCSPN_Z13, strcspn) ++# endif ++ ++# if ! HAVE_STRCSPN_C && defined SHARED && IS_IN (libc) ++strong_alias (STRCSPN_Z13, __GI_strcspn) ++# endif ++ ++#endif /* HAVE_STRCSPN_Z13 */ +diff --git a/sysdeps/s390/multiarch/strcspn.c b/sysdeps/s390/strcspn.c +similarity index 70% +rename from sysdeps/s390/multiarch/strcspn.c +rename to sysdeps/s390/strcspn.c +index 418ffcdded76fe50..a3f35d39c50dd5e5 100644 +--- a/sysdeps/s390/multiarch/strcspn.c ++++ b/sysdeps/s390/strcspn.c +@@ -16,7 +16,9 @@ + License along with the GNU C Library; if not, see + . */ + +-#if defined HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc) ++#include ++ ++#if HAVE_STRCSPN_IFUNC + # define strcspn __redirect_strcspn + /* Omit the strcspn inline definitions because it would redefine strcspn. */ + # define __NO_STRING_INLINES +@@ -24,8 +26,17 @@ + # undef strcspn + # include + +-s390_vx_libc_ifunc2_redirected (__redirect_strcspn, __strcspn, strcspn) ++# if HAVE_STRCSPN_C ++extern __typeof (__redirect_strcspn) STRCSPN_C attribute_hidden; ++# endif ++ ++# if HAVE_STRCSPN_Z13 ++extern __typeof (__redirect_strcspn) STRCSPN_Z13 attribute_hidden; ++# endif + +-#else +-# include +-#endif /* !(defined HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc)) */ ++s390_libc_ifunc_expr (__redirect_strcspn, strcspn, ++ (HAVE_STRCSPN_Z13 && (hwcap & HWCAP_S390_VX)) ++ ? STRCSPN_Z13 ++ : STRCSPN_DEFAULT ++ ) ++#endif /* HAVE_STRCSPN_IFUNC */ diff --git a/SOURCES/glibc-rh1659438-32.patch b/SOURCES/glibc-rh1659438-32.patch new file mode 100644 index 0000000..85327b9 --- /dev/null +++ b/SOURCES/glibc-rh1659438-32.patch @@ -0,0 +1,403 @@ +commit 581a051c2e09a847332d4750f6132de0f0ad15b6 +Author: Stefan Liebler +Date: Tue Dec 18 13:57:16 2018 +0100 + + S390: Refactor memchr ifunc handling. + + The ifunc handling for memchr is adjusted in order to omit ifunc + variants if those will never be used as the minimum architecture level + already supports newer CPUs by default. + Glibc internal calls will then also use the "newer" ifunc variant. + + Note: The fallback s390-32/s390-64 ifunc variants with srst instruction + are now moved to the unified memchr-z900.S file which can be used for + 31/64bit. The s390-32/s390-64 files multiarch/memchr.c and memchr.S + are deleted. + + ChangeLog: + + * sysdeps/s390/multiarch/Makefile + (sysdep_routines): Remove memchr variants. + * sysdeps/s390/Makefile (sysdep_routines): Add memchr variants. + * sysdeps/s390/multiarch/ifunc-impl-list.c + (__libc_ifunc_impl_list): Refactor ifunc handling for memchr. + * sysdeps/s390/multiarch/memchr-vx.S: Move to ... + * sysdeps/s390/memchr-vx.S: ... here and adjust ifunc handling. + * sysdeps/s390/multiarch/memchr.c: Move to ... + * sysdeps/s390/memchr.c: ... here and adjust ifunc handling. + * sysdeps/s390/ifunc-memchr.h: New file. + * sysdeps/s390/s390-64/memchr.S: Move to ... + * sysdeps/s390/memchr-z900.S: ... here and adjust to be usable + for 31/64bit and ifunc handling. + * sysdeps/s390/s390-32/multiarch/memchr.c: Delete file. + * sysdeps/s390/s390-64/multiarch/memchr.c: Likewise. + * sysdeps/s390/s390-32/memchr.S: Likewise. + +diff --git a/sysdeps/s390/Makefile b/sysdeps/s390/Makefile +index 092d55826fbd15a5..816b2fccdc75e4cf 100644 +--- a/sysdeps/s390/Makefile ++++ b/sysdeps/s390/Makefile +@@ -52,5 +52,6 @@ sysdep_routines += bzero memset memset-z900 \ + strrchr strrchr-vx strrchr-c \ + strspn strspn-vx strspn-c \ + strpbrk strpbrk-vx strpbrk-c \ +- strcspn strcspn-vx strcspn-c ++ strcspn strcspn-vx strcspn-c \ ++ memchr memchr-vx memchr-z900 + endif +diff --git a/sysdeps/s390/ifunc-memchr.h b/sysdeps/s390/ifunc-memchr.h +new file mode 100644 +index 0000000000000000..5d1327b45353322b +--- /dev/null ++++ b/sysdeps/s390/ifunc-memchr.h +@@ -0,0 +1,52 @@ ++/* memchr variant information on S/390 version. ++ 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 ++ . */ ++ ++#if defined USE_MULTIARCH && IS_IN (libc) \ ++ && ! defined HAVE_S390_MIN_Z13_ZARCH_ASM_SUPPORT ++# define HAVE_MEMCHR_IFUNC 1 ++#else ++# define HAVE_MEMCHR_IFUNC 0 ++#endif ++ ++#ifdef HAVE_S390_VX_ASM_SUPPORT ++# define HAVE_MEMCHR_IFUNC_AND_VX_SUPPORT HAVE_MEMCHR_IFUNC ++#else ++# define HAVE_MEMCHR_IFUNC_AND_VX_SUPPORT 0 ++#endif ++ ++#if defined HAVE_S390_MIN_Z13_ZARCH_ASM_SUPPORT ++# define MEMCHR_DEFAULT MEMCHR_Z13 ++# define HAVE_MEMCHR_Z900_G5 0 ++# define HAVE_MEMCHR_Z13 1 ++#else ++# define MEMCHR_DEFAULT MEMCHR_Z900_G5 ++# define HAVE_MEMCHR_Z900_G5 1 ++# define HAVE_MEMCHR_Z13 HAVE_MEMCHR_IFUNC_AND_VX_SUPPORT ++#endif ++ ++#if HAVE_MEMCHR_Z900_G5 ++# define MEMCHR_Z900_G5 __memchr_default ++#else ++# define MEMCHR_Z900_G5 NULL ++#endif ++ ++#if HAVE_MEMCHR_Z13 ++# define MEMCHR_Z13 __memchr_vx ++#else ++# define MEMCHR_Z13 NULL ++#endif +diff --git a/sysdeps/s390/multiarch/memchr-vx.S b/sysdeps/s390/memchr-vx.S +similarity index 92% +rename from sysdeps/s390/multiarch/memchr-vx.S +rename to sysdeps/s390/memchr-vx.S +index 77d31e0036915665..274e7971ca7e9413 100644 +--- a/sysdeps/s390/multiarch/memchr-vx.S ++++ b/sysdeps/s390/memchr-vx.S +@@ -16,7 +16,8 @@ + License along with the GNU C Library; if not, see + . */ + +-#if defined HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc) ++#include ++#if HAVE_MEMCHR_Z13 + + # include "sysdep.h" + # include "asm-syntax.h" +@@ -38,7 +39,7 @@ + -v17=index of found c + -v18=c replicated + */ +-ENTRY(__memchr_vx) ++ENTRY(MEMCHR_Z13) + + .machine "z13" + .machinemode "zarch_nohighgprs" +@@ -149,11 +150,14 @@ ENTRY(__memchr_vx) + clgrjl %r0,%r4,.Lloop64 + + j .Llt64 +-END(__memchr_vx) ++END(MEMCHR_Z13) + +-# define memchr __memchr_c +-# undef libc_hidden_builtin_def +-# define libc_hidden_builtin_def(name) strong_alias(__memchr_c, __GI_memchr) +-#endif /* HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc) */ ++# if ! HAVE_MEMCHR_IFUNC ++strong_alias (MEMCHR_Z13, __memchr) ++weak_alias (__memchr, memchr) ++# endif + +-#include ++# if ! HAVE_MEMCHR_Z900_G5 && defined SHARED && IS_IN (libc) ++strong_alias (MEMCHR_Z13, __GI_memchr) ++# endif ++#endif +diff --git a/sysdeps/s390/s390-64/memchr.S b/sysdeps/s390/memchr-z900.S +similarity index 63% +rename from sysdeps/s390/s390-64/memchr.S +rename to sysdeps/s390/memchr-z900.S +index a19fcafa147dc338..c016bc41c61be2dc 100644 +--- a/sysdeps/s390/s390-64/memchr.S ++++ b/sysdeps/s390/memchr-z900.S +@@ -1,4 +1,4 @@ +-/* Search a character in a block of memory. 64 bit S/390 version. ++/* Search a character in a block of memory. 31/64 bit S/390 version. + Copyright (C) 2001-2018 Free Software Foundation, Inc. + Contributed by Martin Schwidefsky (schwidefsky@de.ibm.com). + This file is part of the GNU C Library. +@@ -22,19 +22,42 @@ + %r3 = character to find + %r4 = number of bytes to search. */ + ++#include + #include "sysdep.h" + #include "asm-syntax.h" + ++#if HAVE_MEMCHR_Z900_G5 ++# if defined __s390x__ ++# define SLGR slgr ++# define LGHI lghi ++# define NGR ngr ++# define LGR lgr ++# else ++# define SLGR slr ++# define LGHI lhi ++# define NGR nr ++# define LGR lr ++# endif /* ! defined __s390x__ */ ++ + .text +-ENTRY(memchr) +- lghi %r0,0xff +- ngr %r0,%r3 +- lgr %r1,%r2 ++ENTRY(MEMCHR_Z900_G5) ++ LGHI %r0,0xff ++ NGR %r0,%r3 ++ LGR %r1,%r2 + la %r2,0(%r4,%r1) + 0: srst %r2,%r1 + jo 0b + brc 13,1f +- slgr %r2,%r2 ++ SLGR %r2,%r2 + 1: br %r14 +-END(memchr) +-libc_hidden_builtin_def (memchr) ++END(MEMCHR_Z900_G5) ++ ++# if ! HAVE_MEMCHR_IFUNC ++strong_alias (MEMCHR_Z900_G5, __memchr) ++weak_alias (__memchr, memchr) ++# endif ++ ++# if defined SHARED && IS_IN (libc) ++strong_alias (MEMCHR_Z900_G5, __GI_memchr) ++# endif ++#endif +diff --git a/sysdeps/s390/multiarch/memchr.c b/sysdeps/s390/memchr.c +similarity index 68% +rename from sysdeps/s390/multiarch/memchr.c +rename to sysdeps/s390/memchr.c +index 3885ebaa4d90ed1a..490f1b66002aae05 100644 +--- a/sysdeps/s390/multiarch/memchr.c ++++ b/sysdeps/s390/memchr.c +@@ -16,12 +16,26 @@ + License along with the GNU C Library; if not, see + . */ + +-#if defined HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc) ++#include ++ ++#if HAVE_MEMCHR_IFUNC + # define memchr __redirect_memchr + # include + # undef memchr + # include + +-s390_vx_libc_ifunc2_redirected (__redirect_memchr, __memchr, memchr) ++# if HAVE_MEMCHR_Z900_G5 ++extern __typeof (__redirect_memchr) MEMCHR_Z900_G5 attribute_hidden; ++# endif ++ ++# if HAVE_MEMCHR_Z13 ++extern __typeof (__redirect_memchr) MEMCHR_Z13 attribute_hidden; ++# endif + ++s390_libc_ifunc_expr (__redirect_memchr, __memchr, ++ (HAVE_MEMCHR_Z13 && (hwcap & HWCAP_S390_VX)) ++ ? MEMCHR_Z13 ++ : MEMCHR_DEFAULT ++ ) ++weak_alias (__memchr, memchr) + #endif +diff --git a/sysdeps/s390/multiarch/Makefile b/sysdeps/s390/multiarch/Makefile +index 1578f21af4a1bd06..fa1f7b81db912be0 100644 +--- a/sysdeps/s390/multiarch/Makefile ++++ b/sysdeps/s390/multiarch/Makefile +@@ -1,6 +1,5 @@ + ifeq ($(subdir),string) +-sysdep_routines += memchr memchr-vx \ +- rawmemchr rawmemchr-vx rawmemchr-c \ ++sysdep_routines += rawmemchr rawmemchr-vx rawmemchr-c \ + memccpy memccpy-vx memccpy-c \ + memrchr memrchr-vx memrchr-c + endif +diff --git a/sysdeps/s390/multiarch/ifunc-impl-list.c b/sysdeps/s390/multiarch/ifunc-impl-list.c +index 2d48c99c8d5663fe..b4be0140424aed69 100644 +--- a/sysdeps/s390/multiarch/ifunc-impl-list.c ++++ b/sysdeps/s390/multiarch/ifunc-impl-list.c +@@ -42,6 +42,7 @@ + #include + #include + #include ++#include + + /* Maximum number of IFUNC implementations. */ + #define MAX_IFUNC 3 +@@ -372,6 +373,18 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + ) + #endif /* HAVE_STRCSPN_IFUNC */ + ++#if HAVE_MEMCHR_IFUNC ++ IFUNC_IMPL (i, name, memchr, ++# if HAVE_MEMCHR_Z13 ++ IFUNC_IMPL_ADD (array, i, memchr, ++ dl_hwcap & HWCAP_S390_VX, MEMCHR_Z13) ++# endif ++# if HAVE_MEMCHR_Z900_G5 ++ IFUNC_IMPL_ADD (array, i, memchr, 1, MEMCHR_Z900_G5) ++# endif ++ ) ++#endif /* HAVE_MEMCHR_IFUNC */ ++ + #ifdef HAVE_S390_VX_ASM_SUPPORT + + # define IFUNC_VX_IMPL(FUNC) \ +@@ -412,7 +425,6 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + + IFUNC_VX_IMPL (wcscspn); + +- IFUNC_VX_IMPL (memchr); + IFUNC_VX_IMPL (wmemchr); + IFUNC_VX_IMPL (rawmemchr); + +diff --git a/sysdeps/s390/s390-32/memchr.S b/sysdeps/s390/s390-32/memchr.S +deleted file mode 100644 +index 54f9b85f578fa1c7..0000000000000000 +--- a/sysdeps/s390/s390-32/memchr.S ++++ /dev/null +@@ -1,41 +0,0 @@ +-/* Search a character in a block of memory. For IBM S390 +- Copyright (C) 2000-2018 Free Software Foundation, Inc. +- This file is part of the GNU C Library. +- Contributed by Martin Schwidefsky (schwidefsky@de.ibm.com). +- +- The GNU C Library is free software; you can redistribute it and/or +- modify it under the terms of the GNU Lesser General Public +- License as published by the Free Software Foundation; either +- version 2.1 of the License, or (at your option) any later version. +- +- The GNU C Library is distributed in the hope that it will be useful, +- but WITHOUT ANY WARRANTY; without even the implied warranty of +- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +- Lesser General Public License for more details. +- +- You should have received a copy of the GNU Lesser General Public +- License along with the GNU C Library; if not, see +- . */ +- +-/* +- * R2 = address to memory area +- * R3 = character to find +- * R4 = number of bytes to search +- */ +- +-#include "sysdep.h" +-#include "asm-syntax.h" +- +- .text +-ENTRY(memchr) +- lhi %r0,0xff +- nr %r0,%r3 +- lr %r1,%r2 +- la %r2,0(%r4,%r1) +-0: srst %r2,%r1 +- jo 0b +- brc 13,1f +- slr %r2,%r2 +-1: br %r14 +-END(memchr) +-libc_hidden_builtin_def (memchr) +diff --git a/sysdeps/s390/s390-32/multiarch/memchr.c b/sysdeps/s390/s390-32/multiarch/memchr.c +deleted file mode 100644 +index 5e1610afa43ee549..0000000000000000 +--- a/sysdeps/s390/s390-32/multiarch/memchr.c ++++ /dev/null +@@ -1,21 +0,0 @@ +-/* Multiple versions of memchr. +- 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 +- . */ +- +-/* This wrapper-file is needed, because otherwise file +- sysdeps/s390/s390-[32|64]/memchr.S will be used. */ +-#include +diff --git a/sysdeps/s390/s390-64/multiarch/memchr.c b/sysdeps/s390/s390-64/multiarch/memchr.c +deleted file mode 100644 +index 5e1610afa43ee549..0000000000000000 +--- a/sysdeps/s390/s390-64/multiarch/memchr.c ++++ /dev/null +@@ -1,21 +0,0 @@ +-/* Multiple versions of memchr. +- 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 +- . */ +- +-/* This wrapper-file is needed, because otherwise file +- sysdeps/s390/s390-[32|64]/memchr.S will be used. */ +-#include diff --git a/SOURCES/glibc-rh1659438-33.patch b/SOURCES/glibc-rh1659438-33.patch new file mode 100644 index 0000000..b2b59ee --- /dev/null +++ b/SOURCES/glibc-rh1659438-33.patch @@ -0,0 +1,287 @@ +commit 4c7b3cec113d9bb7dfc004e22c7a98e310ab9bcc +Author: Stefan Liebler +Date: Tue Dec 18 13:57:16 2018 +0100 + + S390: Refactor rawmemchr ifunc handling. + + The ifunc handling for rawmemchr is adjusted in order to omit ifunc + variants if those will never be used as the minimum architecture level + already supports newer CPUs by default. + Glibc internal calls will then also use the "newer" ifunc variant. + + ChangeLog: + + * sysdeps/s390/multiarch/Makefile + (sysdep_routines): Remove rawmemchr variants. + * sysdeps/s390/Makefile (sysdep_routines): Add rawmemchr variants. + * sysdeps/s390/multiarch/ifunc-impl-list.c + (__libc_ifunc_impl_list): Refactor ifunc handling for rawmemchr. + * sysdeps/s390/multiarch/rawmemchr-c.c: Move to ... + * sysdeps/s390/rawmemchr-c.c: ... here and adjust ifunc handling. + * sysdeps/s390/multiarch/rawmemchr-vx.S: Move to ... + * sysdeps/s390/rawmemchr-vx.S: ... here and adjust ifunc handling. + * sysdeps/s390/multiarch/rawmemchr.c: Move to ... + * sysdeps/s390/rawmemchr.c: ... here and adjust ifunc handling. + * sysdeps/s390/ifunc-rawmemchr.h: New file. + +diff --git a/sysdeps/s390/Makefile b/sysdeps/s390/Makefile +index 816b2fccdc75e4cf..9b38b461b34176b0 100644 +--- a/sysdeps/s390/Makefile ++++ b/sysdeps/s390/Makefile +@@ -53,5 +53,6 @@ sysdep_routines += bzero memset memset-z900 \ + strspn strspn-vx strspn-c \ + strpbrk strpbrk-vx strpbrk-c \ + strcspn strcspn-vx strcspn-c \ +- memchr memchr-vx memchr-z900 ++ memchr memchr-vx memchr-z900 \ ++ rawmemchr rawmemchr-vx rawmemchr-c + endif +diff --git a/sysdeps/s390/ifunc-rawmemchr.h b/sysdeps/s390/ifunc-rawmemchr.h +new file mode 100644 +index 0000000000000000..bfcbeae802fb372e +--- /dev/null ++++ b/sysdeps/s390/ifunc-rawmemchr.h +@@ -0,0 +1,52 @@ ++/* rawmemchr variant information on S/390 version. ++ 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 ++ . */ ++ ++#if defined USE_MULTIARCH && IS_IN (libc) \ ++ && ! defined HAVE_S390_MIN_Z13_ZARCH_ASM_SUPPORT ++# define HAVE_RAWMEMCHR_IFUNC 1 ++#else ++# define HAVE_RAWMEMCHR_IFUNC 0 ++#endif ++ ++#ifdef HAVE_S390_VX_ASM_SUPPORT ++# define HAVE_RAWMEMCHR_IFUNC_AND_VX_SUPPORT HAVE_RAWMEMCHR_IFUNC ++#else ++# define HAVE_RAWMEMCHR_IFUNC_AND_VX_SUPPORT 0 ++#endif ++ ++#if defined HAVE_S390_MIN_Z13_ZARCH_ASM_SUPPORT ++# define RAWMEMCHR_DEFAULT RAWMEMCHR_Z13 ++# define HAVE_RAWMEMCHR_C 0 ++# define HAVE_RAWMEMCHR_Z13 1 ++#else ++# define RAWMEMCHR_DEFAULT RAWMEMCHR_C ++# define HAVE_RAWMEMCHR_C 1 ++# define HAVE_RAWMEMCHR_Z13 HAVE_RAWMEMCHR_IFUNC_AND_VX_SUPPORT ++#endif ++ ++#if HAVE_RAWMEMCHR_C ++# define RAWMEMCHR_C __rawmemchr_c ++#else ++# define RAWMEMCHR_C NULL ++#endif ++ ++#if HAVE_RAWMEMCHR_Z13 ++# define RAWMEMCHR_Z13 __rawmemchr_vx ++#else ++# define RAWMEMCHR_Z13 NULL ++#endif +diff --git a/sysdeps/s390/multiarch/Makefile b/sysdeps/s390/multiarch/Makefile +index fa1f7b81db912be0..ac6cfcf9c7dbbc3a 100644 +--- a/sysdeps/s390/multiarch/Makefile ++++ b/sysdeps/s390/multiarch/Makefile +@@ -1,6 +1,5 @@ + ifeq ($(subdir),string) +-sysdep_routines += rawmemchr rawmemchr-vx rawmemchr-c \ +- memccpy memccpy-vx memccpy-c \ ++sysdep_routines += memccpy memccpy-vx memccpy-c \ + memrchr memrchr-vx memrchr-c + endif + +diff --git a/sysdeps/s390/multiarch/ifunc-impl-list.c b/sysdeps/s390/multiarch/ifunc-impl-list.c +index b4be0140424aed69..bf3b40e111a6bd31 100644 +--- a/sysdeps/s390/multiarch/ifunc-impl-list.c ++++ b/sysdeps/s390/multiarch/ifunc-impl-list.c +@@ -43,6 +43,7 @@ + #include + #include + #include ++#include + + /* Maximum number of IFUNC implementations. */ + #define MAX_IFUNC 3 +@@ -385,6 +386,18 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + ) + #endif /* HAVE_MEMCHR_IFUNC */ + ++#if HAVE_RAWMEMCHR_IFUNC ++ IFUNC_IMPL (i, name, rawmemchr, ++# if HAVE_RAWMEMCHR_Z13 ++ IFUNC_IMPL_ADD (array, i, rawmemchr, ++ dl_hwcap & HWCAP_S390_VX, RAWMEMCHR_Z13) ++# endif ++# if HAVE_RAWMEMCHR_C ++ IFUNC_IMPL_ADD (array, i, rawmemchr, 1, RAWMEMCHR_C) ++# endif ++ ) ++#endif /* HAVE_RAWMEMCHR_IFUNC */ ++ + #ifdef HAVE_S390_VX_ASM_SUPPORT + + # define IFUNC_VX_IMPL(FUNC) \ +@@ -426,7 +439,6 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + IFUNC_VX_IMPL (wcscspn); + + IFUNC_VX_IMPL (wmemchr); +- IFUNC_VX_IMPL (rawmemchr); + + IFUNC_VX_IMPL (memccpy); + +diff --git a/sysdeps/s390/multiarch/rawmemchr.c b/sysdeps/s390/rawmemchr-c.c +similarity index 67% +rename from sysdeps/s390/multiarch/rawmemchr.c +rename to sysdeps/s390/rawmemchr-c.c +index 5fdb2252df7f8fa1..8b8208e542092383 100644 +--- a/sysdeps/s390/multiarch/rawmemchr.c ++++ b/sysdeps/s390/rawmemchr-c.c +@@ -1,4 +1,4 @@ +-/* Multiple versions of rawmemchr. ++/* Default rawmemchr implementation for S/390. + Copyright (C) 2015-2018 Free Software Foundation, Inc. + This file is part of the GNU C Library. + +@@ -16,16 +16,19 @@ + License along with the GNU C Library; if not, see + . */ + +-#if defined HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc) +-# define __rawmemchr __redirect___rawmemchr +-# include +-# undef __rawmemchr +-# include ++#include + +-s390_vx_libc_ifunc2_redirected (__redirect___rawmemchr, __rawmemchr +- , __rawmemchr) +-weak_alias (__rawmemchr, rawmemchr) ++#if HAVE_RAWMEMCHR_C ++# if HAVE_RAWMEMCHR_IFUNC ++# define RAWMEMCHR RAWMEMCHR_C ++# undef weak_alias ++# define weak_alias(a, b) ++# if defined SHARED && IS_IN (libc) ++# undef libc_hidden_def ++# define libc_hidden_def(name) \ ++ __hidden_ver1 (__rawmemchr_c, __GI___rawmemchr, __rawmemchr_c); ++# endif ++# endif + +-#else + # include +-#endif /* !(defined HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc)) */ ++#endif +diff --git a/sysdeps/s390/multiarch/rawmemchr-vx.S b/sysdeps/s390/rawmemchr-vx.S +similarity index 87% +rename from sysdeps/s390/multiarch/rawmemchr-vx.S +rename to sysdeps/s390/rawmemchr-vx.S +index d5778be068394394..f04c0e8b616a76ea 100644 +--- a/sysdeps/s390/multiarch/rawmemchr-vx.S ++++ b/sysdeps/s390/rawmemchr-vx.S +@@ -16,7 +16,9 @@ + License along with the GNU C Library; if not, see + . */ + +-#if defined HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc) ++#include ++ ++#if HAVE_RAWMEMCHR_Z13 + + # include "sysdep.h" + # include "asm-syntax.h" +@@ -37,7 +39,7 @@ + -v17=index of unequal + -v18=c replicated + */ +-ENTRY(__rawmemchr_vx) ++ENTRY(RAWMEMCHR_Z13) + .machine "z13" + .machinemode "zarch_nohighgprs" + +@@ -88,5 +90,15 @@ ENTRY(__rawmemchr_vx) + .Lend_found: + la %r2,0(%r5,%r2) /* Return pointer to character. */ + br %r14 +-END(__rawmemchr_vx) +-#endif /* HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc) */ ++END(RAWMEMCHR_Z13) ++ ++# if ! HAVE_RAWMEMCHR_IFUNC ++strong_alias (RAWMEMCHR_Z13, __rawmemchr) ++weak_alias (__rawmemchr, rawmemchr) ++# endif ++ ++# if ! HAVE_RAWMEMCHR_C && defined SHARED && IS_IN (libc) ++strong_alias (RAWMEMCHR_Z13, __GI___rawmemchr) ++# endif ++ ++#endif /* HAVE_RAWMEMCHR_Z13 */ +diff --git a/sysdeps/s390/multiarch/rawmemchr-c.c b/sysdeps/s390/rawmemchr.c +similarity index 56% +rename from sysdeps/s390/multiarch/rawmemchr-c.c +rename to sysdeps/s390/rawmemchr.c +index f43c883a76e52480..d9263ce208ea6361 100644 +--- a/sysdeps/s390/multiarch/rawmemchr-c.c ++++ b/sysdeps/s390/rawmemchr.c +@@ -1,4 +1,4 @@ +-/* Default rawmemchr implementation for S/390. ++/* Multiple versions of rawmemchr. + Copyright (C) 2015-2018 Free Software Foundation, Inc. + This file is part of the GNU C Library. + +@@ -16,19 +16,26 @@ + License along with the GNU C Library; if not, see + . */ + +-#if defined HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc) ++#include ++ ++#if HAVE_RAWMEMCHR_IFUNC ++# define __rawmemchr __redirect___rawmemchr + # include ++# undef __rawmemchr ++# include + +-# define RAWMEMCHR __rawmemchr_c +-# undef weak_alias +-# define weak_alias(a, b) +-# ifdef SHARED +-# undef libc_hidden_def +-# define libc_hidden_def(name) \ +- __hidden_ver1 (__rawmemchr_c, __GI___rawmemchr, __rawmemchr_c); +-# endif /* SHARED */ ++# if HAVE_RAWMEMCHR_C ++extern __typeof (__redirect___rawmemchr) RAWMEMCHR_C attribute_hidden; ++# endif + +-extern __typeof (rawmemchr) __rawmemchr_c attribute_hidden; ++# if HAVE_RAWMEMCHR_Z13 ++extern __typeof (__redirect___rawmemchr) RAWMEMCHR_Z13 attribute_hidden; ++# endif + +-# include +-#endif /* !(defined HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc)) */ ++s390_libc_ifunc_expr (__redirect___rawmemchr, __rawmemchr, ++ (HAVE_RAWMEMCHR_Z13 && (hwcap & HWCAP_S390_VX)) ++ ? RAWMEMCHR_Z13 ++ : RAWMEMCHR_DEFAULT ++ ) ++weak_alias (__rawmemchr, rawmemchr) ++#endif /* HAVE_RAWMEMCHR_IFUNC */ diff --git a/SOURCES/glibc-rh1659438-34.patch b/SOURCES/glibc-rh1659438-34.patch new file mode 100644 index 0000000..f2fbe7f --- /dev/null +++ b/SOURCES/glibc-rh1659438-34.patch @@ -0,0 +1,252 @@ +commit 196655ba54ebdcdcc0468bcb6e136757b013d350 +Author: Stefan Liebler +Date: Tue Dec 18 13:57:16 2018 +0100 + + S390: Refactor memccpy ifunc handling. + + The ifunc handling for memccpy is adjusted in order to omit ifunc + variants if those will never be used as the minimum architecture level + already supports newer CPUs by default. + + ChangeLog: + + * sysdeps/s390/multiarch/Makefile + (sysdep_routines): Remove memccpy variants. + * sysdeps/s390/Makefile (sysdep_routines): Add memccpy variants. + * sysdeps/s390/multiarch/ifunc-impl-list.c + (__libc_ifunc_impl_list): Refactor ifunc handling for memccpy. + * sysdeps/s390/multiarch/memccpy-c.c: Move to ... + * sysdeps/s390/memccpy-c.c: ... here and adjust ifunc handling. + * sysdeps/s390/multiarch/memccpy-vx.S: Move to ... + * sysdeps/s390/memccpy-vx.S: ... here and adjust ifunc handling. + * sysdeps/s390/multiarch/memccpy.c: Move to ... + * sysdeps/s390/memccpy.c: ... here and adjust ifunc handling. + * sysdeps/s390/ifunc-memccpy.h: New file. + +diff --git a/sysdeps/s390/Makefile b/sysdeps/s390/Makefile +index 9b38b461b34176b0..239426dbc1ce9d09 100644 +--- a/sysdeps/s390/Makefile ++++ b/sysdeps/s390/Makefile +@@ -54,5 +54,6 @@ sysdep_routines += bzero memset memset-z900 \ + strpbrk strpbrk-vx strpbrk-c \ + strcspn strcspn-vx strcspn-c \ + memchr memchr-vx memchr-z900 \ +- rawmemchr rawmemchr-vx rawmemchr-c ++ rawmemchr rawmemchr-vx rawmemchr-c \ ++ memccpy memccpy-vx memccpy-c + endif +diff --git a/sysdeps/s390/ifunc-memccpy.h b/sysdeps/s390/ifunc-memccpy.h +new file mode 100644 +index 0000000000000000..8f7a1d0f9fffe106 +--- /dev/null ++++ b/sysdeps/s390/ifunc-memccpy.h +@@ -0,0 +1,52 @@ ++/* memccpy variant information on S/390 version. ++ 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 ++ . */ ++ ++#if defined USE_MULTIARCH && IS_IN (libc) \ ++ && ! defined HAVE_S390_MIN_Z13_ZARCH_ASM_SUPPORT ++# define HAVE_MEMCCPY_IFUNC 1 ++#else ++# define HAVE_MEMCCPY_IFUNC 0 ++#endif ++ ++#ifdef HAVE_S390_VX_ASM_SUPPORT ++# define HAVE_MEMCCPY_IFUNC_AND_VX_SUPPORT HAVE_MEMCCPY_IFUNC ++#else ++# define HAVE_MEMCCPY_IFUNC_AND_VX_SUPPORT 0 ++#endif ++ ++#if defined HAVE_S390_MIN_Z13_ZARCH_ASM_SUPPORT ++# define MEMCCPY_DEFAULT MEMCCPY_Z13 ++# define HAVE_MEMCCPY_C 0 ++# define HAVE_MEMCCPY_Z13 1 ++#else ++# define MEMCCPY_DEFAULT MEMCCPY_C ++# define HAVE_MEMCCPY_C 1 ++# define HAVE_MEMCCPY_Z13 HAVE_MEMCCPY_IFUNC_AND_VX_SUPPORT ++#endif ++ ++#if HAVE_MEMCCPY_C ++# define MEMCCPY_C __memccpy_c ++#else ++# define MEMCCPY_C NULL ++#endif ++ ++#if HAVE_MEMCCPY_Z13 ++# define MEMCCPY_Z13 __memccpy_vx ++#else ++# define MEMCCPY_Z13 NULL ++#endif +diff --git a/sysdeps/s390/multiarch/memccpy-c.c b/sysdeps/s390/memccpy-c.c +similarity index 85% +rename from sysdeps/s390/multiarch/memccpy-c.c +rename to sysdeps/s390/memccpy-c.c +index 1f4c5481991fcb70..2b2f81eb9cfe9369 100644 +--- a/sysdeps/s390/multiarch/memccpy-c.c ++++ b/sysdeps/s390/memccpy-c.c +@@ -16,10 +16,14 @@ + License along with the GNU C Library; if not, see + . */ + +-#if defined HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc) +-# define MEMCCPY __memccpy_c ++#include ++ ++#if HAVE_MEMCCPY_C ++# if HAVE_MEMCCPY_IFUNC ++# define MEMCCPY MEMCCPY_C ++# undef weak_alias ++# define weak_alias(a, b) ++#endif + +-# include +-extern __typeof (__memccpy) __memccpy_c; + # include + #endif +diff --git a/sysdeps/s390/multiarch/memccpy-vx.S b/sysdeps/s390/memccpy-vx.S +similarity index 95% +rename from sysdeps/s390/multiarch/memccpy-vx.S +rename to sysdeps/s390/memccpy-vx.S +index 150aa0e4a48ca181..44f7bc582410ba22 100644 +--- a/sysdeps/s390/multiarch/memccpy-vx.S ++++ b/sysdeps/s390/memccpy-vx.S +@@ -16,7 +16,9 @@ + License along with the GNU C Library; if not, see + . */ + +-#if defined HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc) ++#include ++ ++#if HAVE_MEMCCPY_Z13 + + # include "sysdep.h" + # include "asm-syntax.h" +@@ -42,7 +44,7 @@ + -v19=part #2 of s + -v31=save area for r6 + */ +-ENTRY(__memccpy_vx) ++ENTRY(MEMCCPY_Z13) + .machine "z13" + .machinemode "zarch_nohighgprs" + +@@ -152,5 +154,11 @@ ENTRY(__memccpy_vx) + vlgvg %r7,%v31,1 + lghi %r2,0 /* Return null. */ + br %r14 +-END(__memccpy_vx) +-#endif /* HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc) */ ++END(MEMCCPY_Z13) ++ ++# if ! HAVE_MEMCCPY_IFUNC ++strong_alias (MEMCCPY_Z13, __memccpy) ++weak_alias (__memccpy, memccpy) ++# endif ++ ++#endif /* HAVE_MEMCCPY_Z13 */ +diff --git a/sysdeps/s390/multiarch/memccpy.c b/sysdeps/s390/memccpy.c +similarity index 68% +rename from sysdeps/s390/multiarch/memccpy.c +rename to sysdeps/s390/memccpy.c +index 30aae82321048b7d..bcfeb31e86c56115 100644 +--- a/sysdeps/s390/multiarch/memccpy.c ++++ b/sysdeps/s390/memccpy.c +@@ -16,13 +16,24 @@ + License along with the GNU C Library; if not, see + . */ + +-#if defined HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc) ++#include ++ ++#if HAVE_MEMCCPY_IFUNC + # include + # include + +-s390_vx_libc_ifunc (__memccpy) +-weak_alias (__memccpy, memccpy) ++# if HAVE_MEMCCPY_C ++extern __typeof (__memccpy) MEMCCPY_C attribute_hidden; ++# endif + +-#else +-# include +-#endif /* !(defined HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc)) */ ++# if HAVE_MEMCCPY_Z13 ++extern __typeof (__memccpy) MEMCCPY_Z13 attribute_hidden; ++# endif ++ ++s390_libc_ifunc_expr (__memccpy, __memccpy, ++ (HAVE_MEMCCPY_Z13 && (hwcap & HWCAP_S390_VX)) ++ ? MEMCCPY_Z13 ++ : MEMCCPY_DEFAULT ++ ) ++weak_alias (__memccpy, memccpy) ++#endif /* HAVE_MEMCCPY_IFUNC */ +diff --git a/sysdeps/s390/multiarch/Makefile b/sysdeps/s390/multiarch/Makefile +index ac6cfcf9c7dbbc3a..d5a32fc309ba4b3c 100644 +--- a/sysdeps/s390/multiarch/Makefile ++++ b/sysdeps/s390/multiarch/Makefile +@@ -1,6 +1,5 @@ + ifeq ($(subdir),string) +-sysdep_routines += memccpy memccpy-vx memccpy-c \ +- memrchr memrchr-vx memrchr-c ++sysdep_routines += memrchr memrchr-vx memrchr-c + endif + + ifeq ($(subdir),wcsmbs) +diff --git a/sysdeps/s390/multiarch/ifunc-impl-list.c b/sysdeps/s390/multiarch/ifunc-impl-list.c +index bf3b40e111a6bd31..b8917747f0f23cd9 100644 +--- a/sysdeps/s390/multiarch/ifunc-impl-list.c ++++ b/sysdeps/s390/multiarch/ifunc-impl-list.c +@@ -44,6 +44,7 @@ + #include + #include + #include ++#include + + /* Maximum number of IFUNC implementations. */ + #define MAX_IFUNC 3 +@@ -398,6 +399,18 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + ) + #endif /* HAVE_RAWMEMCHR_IFUNC */ + ++#if HAVE_MEMCCPY_IFUNC ++ IFUNC_IMPL (i, name, memccpy, ++# if HAVE_MEMCCPY_Z13 ++ IFUNC_IMPL_ADD (array, i, memccpy, ++ dl_hwcap & HWCAP_S390_VX, MEMCCPY_Z13) ++# endif ++# if HAVE_MEMCCPY_C ++ IFUNC_IMPL_ADD (array, i, memccpy, 1, MEMCCPY_C) ++# endif ++ ) ++#endif /* HAVE_MEMCCPY_IFUNC */ ++ + #ifdef HAVE_S390_VX_ASM_SUPPORT + + # define IFUNC_VX_IMPL(FUNC) \ +@@ -440,8 +453,6 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + + IFUNC_VX_IMPL (wmemchr); + +- IFUNC_VX_IMPL (memccpy); +- + IFUNC_VX_IMPL (wmemset); + + IFUNC_VX_IMPL (wmemcmp); diff --git a/SOURCES/glibc-rh1659438-35.patch b/SOURCES/glibc-rh1659438-35.patch new file mode 100644 index 0000000..53091b6 --- /dev/null +++ b/SOURCES/glibc-rh1659438-35.patch @@ -0,0 +1,250 @@ +commit 89bfcbdf9d3d36eff0d544f655991149a7ae680b +Author: Stefan Liebler +Date: Tue Dec 18 13:57:17 2018 +0100 + + S390: Refactor memrchr ifunc handling. + + The ifunc handling for memrchr is adjusted in order to omit ifunc + variants if those will never be used as the minimum architecture level + already supports newer CPUs by default. + + ChangeLog: + + * sysdeps/s390/multiarch/Makefile + (sysdep_routines): Remove memrchr variants. + * sysdeps/s390/Makefile (sysdep_routines): Add memrchr variants. + * sysdeps/s390/multiarch/ifunc-impl-list.c + (__libc_ifunc_impl_list): Refactor ifunc handling for memrchr. + * sysdeps/s390/multiarch/memrchr-c.c: Move to ... + * sysdeps/s390/memrchr-c.c: ... here and adjust ifunc handling. + * sysdeps/s390/multiarch/memrchr-vx.S: Move to ... + * sysdeps/s390/memrchr-vx.S: ... here and adjust ifunc handling. + * sysdeps/s390/multiarch/memrchr.c: Move to ... + * sysdeps/s390/memrchr.c: ... here and adjust ifunc handling. + * sysdeps/s390/ifunc-memrchr.h: New file. + +diff --git a/sysdeps/s390/Makefile b/sysdeps/s390/Makefile +index 239426dbc1ce9d09..9a16ce1692e51607 100644 +--- a/sysdeps/s390/Makefile ++++ b/sysdeps/s390/Makefile +@@ -55,5 +55,6 @@ sysdep_routines += bzero memset memset-z900 \ + strcspn strcspn-vx strcspn-c \ + memchr memchr-vx memchr-z900 \ + rawmemchr rawmemchr-vx rawmemchr-c \ +- memccpy memccpy-vx memccpy-c ++ memccpy memccpy-vx memccpy-c \ ++ memrchr memrchr-vx memrchr-c + endif +diff --git a/sysdeps/s390/ifunc-memrchr.h b/sysdeps/s390/ifunc-memrchr.h +new file mode 100644 +index 0000000000000000..9d80d5528dc92dab +--- /dev/null ++++ b/sysdeps/s390/ifunc-memrchr.h +@@ -0,0 +1,52 @@ ++/* memrchr variant information on S/390 version. ++ 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 ++ . */ ++ ++#if defined USE_MULTIARCH && IS_IN (libc) \ ++ && ! defined HAVE_S390_MIN_Z13_ZARCH_ASM_SUPPORT ++# define HAVE_MEMRCHR_IFUNC 1 ++#else ++# define HAVE_MEMRCHR_IFUNC 0 ++#endif ++ ++#ifdef HAVE_S390_VX_ASM_SUPPORT ++# define HAVE_MEMRCHR_IFUNC_AND_VX_SUPPORT HAVE_MEMRCHR_IFUNC ++#else ++# define HAVE_MEMRCHR_IFUNC_AND_VX_SUPPORT 0 ++#endif ++ ++#if defined HAVE_S390_MIN_Z13_ZARCH_ASM_SUPPORT ++# define MEMRCHR_DEFAULT MEMRCHR_Z13 ++# define HAVE_MEMRCHR_C 0 ++# define HAVE_MEMRCHR_Z13 1 ++#else ++# define MEMRCHR_DEFAULT MEMRCHR_C ++# define HAVE_MEMRCHR_C 1 ++# define HAVE_MEMRCHR_Z13 HAVE_MEMRCHR_IFUNC_AND_VX_SUPPORT ++#endif ++ ++#if HAVE_MEMRCHR_C ++# define MEMRCHR_C __memrchr_c ++#else ++# define MEMRCHR_C NULL ++#endif ++ ++#if HAVE_MEMRCHR_Z13 ++# define MEMRCHR_Z13 __memrchr_vx ++#else ++# define MEMRCHR_Z13 NULL ++#endif +diff --git a/sysdeps/s390/multiarch/memrchr-c.c b/sysdeps/s390/memrchr-c.c +similarity index 85% +rename from sysdeps/s390/multiarch/memrchr-c.c +rename to sysdeps/s390/memrchr-c.c +index 1e3c914a5d61dbc5..333c0fc8d1855323 100644 +--- a/sysdeps/s390/multiarch/memrchr-c.c ++++ b/sysdeps/s390/memrchr-c.c +@@ -16,10 +16,12 @@ + License along with the GNU C Library; if not, see + . */ + +-#if defined HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc) +-# define MEMRCHR __memrchr_c ++#include ++ ++#if HAVE_MEMRCHR_C ++# if HAVE_MEMRCHR_IFUNC ++# define MEMRCHR MEMRCHR_C ++# endif + +-# include +-extern __typeof (__memrchr) __memrchr_c; + # include + #endif +diff --git a/sysdeps/s390/multiarch/memrchr-vx.S b/sysdeps/s390/memrchr-vx.S +similarity index 94% +rename from sysdeps/s390/multiarch/memrchr-vx.S +rename to sysdeps/s390/memrchr-vx.S +index 8e81f5ed7519c2cc..ba832f1b21ad5a4c 100644 +--- a/sysdeps/s390/multiarch/memrchr-vx.S ++++ b/sysdeps/s390/memrchr-vx.S +@@ -16,7 +16,9 @@ + License along with the GNU C Library; if not, see + . */ + +-#if defined HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc) ++#include ++ ++#if HAVE_MEMRCHR_Z13 + + # include "sysdep.h" + # include "asm-syntax.h" +@@ -40,7 +42,7 @@ + -v18=c replicated + -v20=permute pattern + */ +-ENTRY(__memrchr_vx) ++ENTRY(MEMRCHR_Z13) + .machine "z13" + .machinemode "zarch_nohighgprs" + +@@ -156,5 +158,11 @@ ENTRY(__memrchr_vx) + + clgijhe %r4,64,.Lloop64 /* If n >= 64 -> loop64. */ + j .Llt64 +-END(__memrchr_vx) +-#endif /* HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc) */ ++END(MEMRCHR_Z13) ++ ++# if ! HAVE_MEMRCHR_IFUNC ++strong_alias (MEMRCHR_Z13, __memrchr) ++weak_alias (__memrchr, memrchr) ++# endif ++ ++#endif /* HAVE_MEMRCHR_Z13 */ +diff --git a/sysdeps/s390/multiarch/memrchr.c b/sysdeps/s390/memrchr.c +similarity index 68% +rename from sysdeps/s390/multiarch/memrchr.c +rename to sysdeps/s390/memrchr.c +index 43a44abcf6cc3bdc..d995e9961c1cc9eb 100644 +--- a/sysdeps/s390/multiarch/memrchr.c ++++ b/sysdeps/s390/memrchr.c +@@ -16,13 +16,24 @@ + License along with the GNU C Library; if not, see + . */ + +-#if defined HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc) ++#include ++ ++#if HAVE_MEMRCHR_IFUNC + # include + # include + +-s390_vx_libc_ifunc (__memrchr) +-weak_alias (__memrchr, memrchr) ++# if HAVE_MEMRCHR_C ++extern __typeof (__memrchr) MEMRCHR_C attribute_hidden; ++# endif + +-#else +-# include +-#endif /* !(defined HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc)) */ ++# if HAVE_MEMRCHR_Z13 ++extern __typeof (__memrchr) MEMRCHR_Z13 attribute_hidden; ++# endif ++ ++s390_libc_ifunc_expr (__memrchr, __memrchr, ++ (HAVE_MEMRCHR_Z13 && (hwcap & HWCAP_S390_VX)) ++ ? MEMRCHR_Z13 ++ : MEMRCHR_DEFAULT ++ ) ++weak_alias (__memrchr, memrchr) ++#endif /* HAVE_MEMRCHR_IFUNC */ +diff --git a/sysdeps/s390/multiarch/Makefile b/sysdeps/s390/multiarch/Makefile +index d5a32fc309ba4b3c..260b514936b93306 100644 +--- a/sysdeps/s390/multiarch/Makefile ++++ b/sysdeps/s390/multiarch/Makefile +@@ -1,7 +1,3 @@ +-ifeq ($(subdir),string) +-sysdep_routines += memrchr memrchr-vx memrchr-c +-endif +- + ifeq ($(subdir),wcsmbs) + sysdep_routines += wcslen wcslen-vx wcslen-c \ + wcsnlen wcsnlen-vx wcsnlen-c \ +diff --git a/sysdeps/s390/multiarch/ifunc-impl-list.c b/sysdeps/s390/multiarch/ifunc-impl-list.c +index b8917747f0f23cd9..0f01b99691002be0 100644 +--- a/sysdeps/s390/multiarch/ifunc-impl-list.c ++++ b/sysdeps/s390/multiarch/ifunc-impl-list.c +@@ -45,6 +45,7 @@ + #include + #include + #include ++#include + + /* Maximum number of IFUNC implementations. */ + #define MAX_IFUNC 3 +@@ -411,6 +412,18 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + ) + #endif /* HAVE_MEMCCPY_IFUNC */ + ++#if HAVE_MEMRCHR_IFUNC ++ IFUNC_IMPL (i, name, memrchr, ++# if HAVE_MEMRCHR_Z13 ++ IFUNC_IMPL_ADD (array, i, memrchr, ++ dl_hwcap & HWCAP_S390_VX, MEMRCHR_Z13) ++# endif ++# if HAVE_MEMRCHR_C ++ IFUNC_IMPL_ADD (array, i, memrchr, 1, MEMRCHR_C) ++# endif ++ ) ++#endif /* HAVE_MEMRCHR_IFUNC */ ++ + #ifdef HAVE_S390_VX_ASM_SUPPORT + + # define IFUNC_VX_IMPL(FUNC) \ +@@ -457,8 +470,6 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + + IFUNC_VX_IMPL (wmemcmp); + +- IFUNC_VX_IMPL (memrchr); +- + #endif /* HAVE_S390_VX_ASM_SUPPORT */ + + return i; diff --git a/SOURCES/glibc-rh1659438-36.patch b/SOURCES/glibc-rh1659438-36.patch new file mode 100644 index 0000000..146d137 --- /dev/null +++ b/SOURCES/glibc-rh1659438-36.patch @@ -0,0 +1,252 @@ +commit 2e02d0b7a9bf3421638d2d0f2526275a1df5c0da +Author: Stefan Liebler +Date: Tue Dec 18 13:57:17 2018 +0100 + + S390: Refactor wcslen ifunc handling. + + The ifunc handling for wcslen is adjusted in order to omit ifunc + if the minimum architecture level already supports newer CPUs by default. + Unfortunately the c ifunc variant can't be omitted at all as it is used + by the z13 ifunc variant as fallback if the pointers are not 4-byte aligned. + + ChangeLog: + + * sysdeps/s390/multiarch/Makefile + (sysdep_routines): Remove wcslen variants. + * sysdeps/s390/Makefile (sysdep_routines): Add wcslen variants. + * sysdeps/s390/multiarch/ifunc-impl-list.c + (__libc_ifunc_impl_list): Refactor ifunc handling for wcslen. + * sysdeps/s390/multiarch/wcslen-c.c: Move to ... + * sysdeps/s390/wcslen-c.c: ... here and adjust ifunc handling. + * sysdeps/s390/multiarch/wcslen-vx.S: Move to ... + * sysdeps/s390/wcslen-vx.S: ... here and adjust ifunc handling. + * sysdeps/s390/multiarch/wcslen.c: Move to ... + * sysdeps/s390/wcslen.c: ... here and adjust ifunc handling. + * sysdeps/s390/ifunc-wcslen.h: New file. + +diff --git a/sysdeps/s390/Makefile b/sysdeps/s390/Makefile +index 9a16ce1692e51607..65e89118936bb668 100644 +--- a/sysdeps/s390/Makefile ++++ b/sysdeps/s390/Makefile +@@ -58,3 +58,7 @@ sysdep_routines += bzero memset memset-z900 \ + memccpy memccpy-vx memccpy-c \ + memrchr memrchr-vx memrchr-c + endif ++ ++ifeq ($(subdir),wcsmbs) ++sysdep_routines += wcslen wcslen-vx wcslen-c ++endif +diff --git a/sysdeps/s390/ifunc-wcslen.h b/sysdeps/s390/ifunc-wcslen.h +new file mode 100644 +index 0000000000000000..50d879caf2b8186b +--- /dev/null ++++ b/sysdeps/s390/ifunc-wcslen.h +@@ -0,0 +1,53 @@ ++/* wcslen variant information on S/390 version. ++ 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 ++ . */ ++ ++#if defined USE_MULTIARCH && IS_IN (libc) \ ++ && ! defined HAVE_S390_MIN_Z13_ZARCH_ASM_SUPPORT ++# define HAVE_WCSLEN_IFUNC 1 ++#else ++# define HAVE_WCSLEN_IFUNC 0 ++#endif ++ ++#ifdef HAVE_S390_VX_ASM_SUPPORT ++# define HAVE_WCSLEN_IFUNC_AND_VX_SUPPORT HAVE_WCSLEN_IFUNC ++#else ++# define HAVE_WCSLEN_IFUNC_AND_VX_SUPPORT 0 ++#endif ++ ++#if defined HAVE_S390_MIN_Z13_ZARCH_ASM_SUPPORT ++# define WCSLEN_DEFAULT WCSLEN_Z13 ++/* The z13 ifunc variant is using the common code variant as fallback! */ ++# define HAVE_WCSLEN_C 1 ++# define HAVE_WCSLEN_Z13 1 ++#else ++# define WCSLEN_DEFAULT WCSLEN_C ++# define HAVE_WCSLEN_C 1 ++# define HAVE_WCSLEN_Z13 HAVE_WCSLEN_IFUNC_AND_VX_SUPPORT ++#endif ++ ++#if HAVE_WCSLEN_C ++# define WCSLEN_C __wcslen_c ++#else ++# define WCSLEN_C NULL ++#endif ++ ++#if HAVE_WCSLEN_Z13 ++# define WCSLEN_Z13 __wcslen_vx ++#else ++# define WCSLEN_Z13 NULL ++#endif +diff --git a/sysdeps/s390/multiarch/Makefile b/sysdeps/s390/multiarch/Makefile +index 260b514936b93306..421d40d020b81560 100644 +--- a/sysdeps/s390/multiarch/Makefile ++++ b/sysdeps/s390/multiarch/Makefile +@@ -1,6 +1,5 @@ + ifeq ($(subdir),wcsmbs) +-sysdep_routines += wcslen wcslen-vx wcslen-c \ +- wcsnlen wcsnlen-vx wcsnlen-c \ ++sysdep_routines += wcsnlen wcsnlen-vx wcsnlen-c \ + wcscpy wcscpy-vx wcscpy-c \ + wcpcpy wcpcpy-vx wcpcpy-c \ + wcsncpy wcsncpy-vx wcsncpy-c \ +diff --git a/sysdeps/s390/multiarch/ifunc-impl-list.c b/sysdeps/s390/multiarch/ifunc-impl-list.c +index 0f01b99691002be0..7bf5f14c015b54fe 100644 +--- a/sysdeps/s390/multiarch/ifunc-impl-list.c ++++ b/sysdeps/s390/multiarch/ifunc-impl-list.c +@@ -46,6 +46,7 @@ + #include + #include + #include ++#include + + /* Maximum number of IFUNC implementations. */ + #define MAX_IFUNC 3 +@@ -424,6 +425,18 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + ) + #endif /* HAVE_MEMRCHR_IFUNC */ + ++#if HAVE_WCSLEN_IFUNC ++ IFUNC_IMPL (i, name, wcslen, ++# if HAVE_WCSLEN_Z13 ++ IFUNC_IMPL_ADD (array, i, wcslen, ++ dl_hwcap & HWCAP_S390_VX, WCSLEN_Z13) ++# endif ++# if HAVE_WCSLEN_C ++ IFUNC_IMPL_ADD (array, i, wcslen, 1, WCSLEN_C) ++# endif ++ ) ++#endif /* HAVE_WCSLEN_IFUNC */ ++ + #ifdef HAVE_S390_VX_ASM_SUPPORT + + # define IFUNC_VX_IMPL(FUNC) \ +@@ -432,8 +445,6 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + __##FUNC##_vx) \ + IFUNC_IMPL_ADD (array, i, FUNC, 1, __##FUNC##_c)) + +- IFUNC_VX_IMPL (wcslen); +- + IFUNC_VX_IMPL (wcsnlen); + + IFUNC_VX_IMPL (wcscpy); +diff --git a/sysdeps/s390/multiarch/wcslen-c.c b/sysdeps/s390/wcslen-c.c +similarity index 86% +rename from sysdeps/s390/multiarch/wcslen-c.c +rename to sysdeps/s390/wcslen-c.c +index 32a23e206d2e9cf9..45399cff3a127b5e 100644 +--- a/sysdeps/s390/multiarch/wcslen-c.c ++++ b/sysdeps/s390/wcslen-c.c +@@ -16,10 +16,12 @@ + License along with the GNU C Library; if not, see + . */ + +-#if defined HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc) +-# define WCSLEN __wcslen_c ++#include ++ ++#if HAVE_WCSLEN_C ++# if HAVE_WCSLEN_IFUNC || HAVE_WCSLEN_Z13 ++# define WCSLEN WCSLEN_C ++# endif + +-# include +-extern __typeof (__wcslen) __wcslen_c; + # include + #endif +diff --git a/sysdeps/s390/multiarch/wcslen-vx.S b/sysdeps/s390/wcslen-vx.S +similarity index 92% +rename from sysdeps/s390/multiarch/wcslen-vx.S +rename to sysdeps/s390/wcslen-vx.S +index 337cbed6ec21db76..114f7ef743b10c63 100644 +--- a/sysdeps/s390/multiarch/wcslen-vx.S ++++ b/sysdeps/s390/wcslen-vx.S +@@ -16,7 +16,8 @@ + License along with the GNU C Library; if not, see + . */ + +-#if defined HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc) ++#include ++#if HAVE_WCSLEN_Z13 + + # include "sysdep.h" + # include "asm-syntax.h" +@@ -34,7 +35,7 @@ + -r5=current_len and return_value + -v16=part of s + */ +-ENTRY(__wcslen_vx) ++ENTRY(WCSLEN_Z13) + .machine "z13" + .machinemode "zarch_nohighgprs" + +@@ -86,6 +87,11 @@ ENTRY(__wcslen_vx) + srlg %r2,%r2,2 /* Convert byte-count to character-count. */ + br %r14 + .Lfallback: +- jg __wcslen_c +-END(__wcslen_vx) +-#endif /* HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc) */ ++ jg WCSLEN_C ++END(WCSLEN_Z13) ++ ++# if ! HAVE_WCSLEN_IFUNC ++strong_alias (WCSLEN_Z13, __wcslen) ++weak_alias (__wcslen, wcslen) ++# endif ++#endif +diff --git a/sysdeps/s390/multiarch/wcslen.c b/sysdeps/s390/wcslen.c +similarity index 70% +rename from sysdeps/s390/multiarch/wcslen.c +rename to sysdeps/s390/wcslen.c +index 3a1d1a32c9a99749..a5eee83f6cae7166 100644 +--- a/sysdeps/s390/multiarch/wcslen.c ++++ b/sysdeps/s390/wcslen.c +@@ -16,13 +16,24 @@ + License along with the GNU C Library; if not, see + . */ + +-#if defined HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc) ++#include ++ ++#if HAVE_WCSLEN_IFUNC + # include + # include + +-s390_vx_libc_ifunc (__wcslen) +-weak_alias (__wcslen, wcslen) ++# if HAVE_WCSLEN_C ++extern __typeof (__wcslen) WCSLEN_C attribute_hidden; ++# endif + +-#else +-# include +-#endif /* !(defined HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc)) */ ++# if HAVE_WCSLEN_Z13 ++extern __typeof (__wcslen) WCSLEN_Z13 attribute_hidden; ++# endif ++ ++s390_libc_ifunc_expr (__wcslen, __wcslen, ++ (HAVE_WCSLEN_Z13 && (hwcap & HWCAP_S390_VX)) ++ ? WCSLEN_Z13 ++ : WCSLEN_DEFAULT ++ ) ++weak_alias (__wcslen, wcslen) ++#endif diff --git a/SOURCES/glibc-rh1659438-37.patch b/SOURCES/glibc-rh1659438-37.patch new file mode 100644 index 0000000..827d82d --- /dev/null +++ b/SOURCES/glibc-rh1659438-37.patch @@ -0,0 +1,253 @@ +commit c7e7cd266ed123b6dfb722f599934ca5dcfd3e93 +Author: Stefan Liebler +Date: Tue Dec 18 13:57:18 2018 +0100 + + S390: Refactor wcsnlen ifunc handling. + + The ifunc handling for wcsnlen is adjusted in order to omit ifunc + if the minimum architecture level already supports newer CPUs by default. + Unfortunately the c ifunc variant can't be omitted at all as it is used + by the z13 ifunc variant as fallback if the pointers are not 4-byte aligned. + Glibc internal calls will use the "newer" ifunc variant. + + ChangeLog: + + * sysdeps/s390/multiarch/Makefile + (sysdep_routines): Remove wcsnlen variants. + * sysdeps/s390/Makefile (sysdep_routines): Add wcsnlen variants. + * sysdeps/s390/multiarch/ifunc-impl-list.c + (__libc_ifunc_impl_list): Refactor ifunc handling for wcsnlen. + * sysdeps/s390/multiarch/wcsnlen-c.c: Move to ... + * sysdeps/s390/wcsnlen-c.c: ... here and adjust ifunc handling. + * sysdeps/s390/multiarch/wcsnlen-vx.S: Move to ... + * sysdeps/s390/wcsnlen-vx.S: ... here and adjust ifunc handling. + * sysdeps/s390/multiarch/wcsnlen.c: Move to ... + * sysdeps/s390/wcsnlen.c: ... here and adjust ifunc handling. + * sysdeps/s390/ifunc-wcsnlen.h: New file. + +diff --git a/sysdeps/s390/Makefile b/sysdeps/s390/Makefile +index 65e89118936bb668..f5983815479a76da 100644 +--- a/sysdeps/s390/Makefile ++++ b/sysdeps/s390/Makefile +@@ -60,5 +60,6 @@ sysdep_routines += bzero memset memset-z900 \ + endif + + ifeq ($(subdir),wcsmbs) +-sysdep_routines += wcslen wcslen-vx wcslen-c ++sysdep_routines += wcslen wcslen-vx wcslen-c \ ++ wcsnlen wcsnlen-vx wcsnlen-c + endif +diff --git a/sysdeps/s390/ifunc-wcsnlen.h b/sysdeps/s390/ifunc-wcsnlen.h +new file mode 100644 +index 0000000000000000..b5b21da2f17d9cd9 +--- /dev/null ++++ b/sysdeps/s390/ifunc-wcsnlen.h +@@ -0,0 +1,53 @@ ++/* wcsnlen variant information on S/390 version. ++ 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 ++ . */ ++ ++#if defined USE_MULTIARCH && IS_IN (libc) \ ++ && ! defined HAVE_S390_MIN_Z13_ZARCH_ASM_SUPPORT ++# define HAVE_WCSNLEN_IFUNC 1 ++#else ++# define HAVE_WCSNLEN_IFUNC 0 ++#endif ++ ++#ifdef HAVE_S390_VX_ASM_SUPPORT ++# define HAVE_WCSNLEN_IFUNC_AND_VX_SUPPORT HAVE_WCSNLEN_IFUNC ++#else ++# define HAVE_WCSNLEN_IFUNC_AND_VX_SUPPORT 0 ++#endif ++ ++#if defined HAVE_S390_MIN_Z13_ZARCH_ASM_SUPPORT ++# define WCSNLEN_DEFAULT WCSNLEN_Z13 ++/* The z13 ifunc variant is using the common code variant as fallback! */ ++# define HAVE_WCSNLEN_C 1 ++# define HAVE_WCSNLEN_Z13 1 ++#else ++# define WCSNLEN_DEFAULT WCSNLEN_C ++# define HAVE_WCSNLEN_C 1 ++# define HAVE_WCSNLEN_Z13 HAVE_WCSNLEN_IFUNC_AND_VX_SUPPORT ++#endif ++ ++#if HAVE_WCSNLEN_C ++# define WCSNLEN_C __wcsnlen_c ++#else ++# define WCSNLEN_C NULL ++#endif ++ ++#if HAVE_WCSNLEN_Z13 ++# define WCSNLEN_Z13 __wcsnlen_vx ++#else ++# define WCSNLEN_Z13 NULL ++#endif +diff --git a/sysdeps/s390/multiarch/Makefile b/sysdeps/s390/multiarch/Makefile +index 421d40d020b81560..ce2e7ce5f4eef0fa 100644 +--- a/sysdeps/s390/multiarch/Makefile ++++ b/sysdeps/s390/multiarch/Makefile +@@ -1,6 +1,5 @@ + ifeq ($(subdir),wcsmbs) +-sysdep_routines += wcsnlen wcsnlen-vx wcsnlen-c \ +- wcscpy wcscpy-vx wcscpy-c \ ++sysdep_routines += wcscpy wcscpy-vx wcscpy-c \ + wcpcpy wcpcpy-vx wcpcpy-c \ + wcsncpy wcsncpy-vx wcsncpy-c \ + wcpncpy wcpncpy-vx wcpncpy-c \ +diff --git a/sysdeps/s390/multiarch/ifunc-impl-list.c b/sysdeps/s390/multiarch/ifunc-impl-list.c +index 7bf5f14c015b54fe..c199fd0e0b43e4b4 100644 +--- a/sysdeps/s390/multiarch/ifunc-impl-list.c ++++ b/sysdeps/s390/multiarch/ifunc-impl-list.c +@@ -47,6 +47,7 @@ + #include + #include + #include ++#include + + /* Maximum number of IFUNC implementations. */ + #define MAX_IFUNC 3 +@@ -437,6 +438,18 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + ) + #endif /* HAVE_WCSLEN_IFUNC */ + ++#if HAVE_WCSNLEN_IFUNC ++ IFUNC_IMPL (i, name, wcsnlen, ++# if HAVE_WCSNLEN_Z13 ++ IFUNC_IMPL_ADD (array, i, wcsnlen, ++ dl_hwcap & HWCAP_S390_VX, WCSNLEN_Z13) ++# endif ++# if HAVE_WCSNLEN_C ++ IFUNC_IMPL_ADD (array, i, wcsnlen, 1, WCSNLEN_C) ++# endif ++ ) ++#endif /* HAVE_WCSNLEN_IFUNC */ ++ + #ifdef HAVE_S390_VX_ASM_SUPPORT + + # define IFUNC_VX_IMPL(FUNC) \ +@@ -445,8 +458,6 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + __##FUNC##_vx) \ + IFUNC_IMPL_ADD (array, i, FUNC, 1, __##FUNC##_c)) + +- IFUNC_VX_IMPL (wcsnlen); +- + IFUNC_VX_IMPL (wcscpy); + + IFUNC_VX_IMPL (wcpcpy); +diff --git a/sysdeps/s390/multiarch/wcsnlen-c.c b/sysdeps/s390/wcsnlen-c.c +similarity index 85% +rename from sysdeps/s390/multiarch/wcsnlen-c.c +rename to sysdeps/s390/wcsnlen-c.c +index 8f43f5104f2eab3f..7495a6f97cfeca62 100644 +--- a/sysdeps/s390/multiarch/wcsnlen-c.c ++++ b/sysdeps/s390/wcsnlen-c.c +@@ -16,10 +16,12 @@ + License along with the GNU C Library; if not, see + . */ + +-#if defined HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc) +-# define WCSNLEN __wcsnlen_c ++#include ++ ++#if HAVE_WCSNLEN_C ++# if HAVE_WCSNLEN_IFUNC || HAVE_WCSNLEN_Z13 ++# define WCSNLEN WCSNLEN_C ++# endif + +-# include +-extern __typeof (__wcsnlen) __wcsnlen_c; + # include + #endif +diff --git a/sysdeps/s390/multiarch/wcsnlen-vx.S b/sysdeps/s390/wcsnlen-vx.S +similarity index 95% +rename from sysdeps/s390/multiarch/wcsnlen-vx.S +rename to sysdeps/s390/wcsnlen-vx.S +index 420f29fbc0d2965a..47f4ca82840538d9 100644 +--- a/sysdeps/s390/multiarch/wcsnlen-vx.S ++++ b/sysdeps/s390/wcsnlen-vx.S +@@ -16,7 +16,8 @@ + License along with the GNU C Library; if not, see + . */ + +-#if defined HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc) ++#include ++#if HAVE_WCSNLEN_Z13 + + # include "sysdep.h" + # include "asm-syntax.h" +@@ -34,7 +35,7 @@ + -r5=current_len and return_value + -v16=part of s + */ +-ENTRY(__wcsnlen_vx) ++ENTRY(WCSNLEN_Z13) + + .machine "z13" + .machinemode "zarch_nohighgprs" +@@ -146,6 +147,11 @@ ENTRY(__wcsnlen_vx) + j .Llt64 + + .Lfallback: +- jg __wcsnlen_c +-END(__wcsnlen_vx) +-#endif /* HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc) */ ++ jg WCSNLEN_C ++END(WCSNLEN_Z13) ++ ++# if ! HAVE_WCSNLEN_IFUNC ++strong_alias (WCSNLEN_Z13, __wcsnlen) ++weak_alias (__wcsnlen, wcsnlen) ++# endif ++#endif +diff --git a/sysdeps/s390/multiarch/wcsnlen.c b/sysdeps/s390/wcsnlen.c +similarity index 70% +rename from sysdeps/s390/multiarch/wcsnlen.c +rename to sysdeps/s390/wcsnlen.c +index 5234074b1fce8ca1..b5c8ad9fde5a9752 100644 +--- a/sysdeps/s390/multiarch/wcsnlen.c ++++ b/sysdeps/s390/wcsnlen.c +@@ -16,13 +16,24 @@ + License along with the GNU C Library; if not, see + . */ + +-#if defined HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc) ++#include ++ ++#if HAVE_WCSNLEN_IFUNC + # include + # include + +-s390_vx_libc_ifunc (__wcsnlen) +-weak_alias (__wcsnlen, wcsnlen) ++# if HAVE_WCSNLEN_C ++extern __typeof (__wcsnlen) WCSNLEN_C attribute_hidden; ++# endif + +-#else +-# include +-#endif /* !(defined HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc)) */ ++# if HAVE_WCSNLEN_Z13 ++extern __typeof (__wcsnlen) WCSNLEN_Z13 attribute_hidden; ++# endif ++ ++s390_libc_ifunc_expr (__wcsnlen, __wcsnlen, ++ (HAVE_WCSNLEN_Z13 && (hwcap & HWCAP_S390_VX)) ++ ? WCSNLEN_Z13 ++ : WCSNLEN_DEFAULT ++ ) ++weak_alias (__wcsnlen, wcsnlen) ++#endif diff --git a/SOURCES/glibc-rh1659438-38.patch b/SOURCES/glibc-rh1659438-38.patch new file mode 100644 index 0000000..7549d69 --- /dev/null +++ b/SOURCES/glibc-rh1659438-38.patch @@ -0,0 +1,249 @@ +commit 804f2e5c73b1363836ce5db29a0abb3d36e1286a +Author: Stefan Liebler +Date: Tue Dec 18 13:57:18 2018 +0100 + + S390: Refactor wcscpy ifunc handling. + + The ifunc handling for wcscpy is adjusted in order to omit ifunc + if the minimum architecture level already supports newer CPUs by default. + Unfortunately the c ifunc variant can't be omitted at all as it is used + by the z13 ifunc variant as fallback if the pointers are not 4-byte aligned. + + ChangeLog: + + * sysdeps/s390/multiarch/Makefile + (sysdep_routines): Remove wcscpy variants. + * sysdeps/s390/Makefile (sysdep_routines): Add wcscpy variants. + * sysdeps/s390/multiarch/ifunc-impl-list.c + (__libc_ifunc_impl_list): Refactor ifunc handling for wcscpy. + * sysdeps/s390/multiarch/wcscpy-c.c: Move to ... + * sysdeps/s390/wcscpy-c.c: ... here and adjust ifunc handling. + * sysdeps/s390/multiarch/wcscpy-vx.S: Move to ... + * sysdeps/s390/wcscpy-vx.S: ... here and adjust ifunc handling. + * sysdeps/s390/multiarch/wcscpy.c: Move to ... + * sysdeps/s390/wcscpy.c: ... here and adjust ifunc handling. + * sysdeps/s390/ifunc-wcscpy.h: New file. + +diff --git a/sysdeps/s390/Makefile b/sysdeps/s390/Makefile +index f5983815479a76da..8bdbd1b5d8e9df01 100644 +--- a/sysdeps/s390/Makefile ++++ b/sysdeps/s390/Makefile +@@ -61,5 +61,6 @@ endif + + ifeq ($(subdir),wcsmbs) + sysdep_routines += wcslen wcslen-vx wcslen-c \ +- wcsnlen wcsnlen-vx wcsnlen-c ++ wcsnlen wcsnlen-vx wcsnlen-c \ ++ wcscpy wcscpy-vx wcscpy-c + endif +diff --git a/sysdeps/s390/ifunc-wcscpy.h b/sysdeps/s390/ifunc-wcscpy.h +new file mode 100644 +index 0000000000000000..fba7c9c7a7c354d1 +--- /dev/null ++++ b/sysdeps/s390/ifunc-wcscpy.h +@@ -0,0 +1,53 @@ ++/* wcscpy variant information on S/390 version. ++ 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 ++ . */ ++ ++#if defined USE_MULTIARCH && IS_IN (libc) \ ++ && ! defined HAVE_S390_MIN_Z13_ZARCH_ASM_SUPPORT ++# define HAVE_WCSCPY_IFUNC 1 ++#else ++# define HAVE_WCSCPY_IFUNC 0 ++#endif ++ ++#ifdef HAVE_S390_VX_ASM_SUPPORT ++# define HAVE_WCSCPY_IFUNC_AND_VX_SUPPORT HAVE_WCSCPY_IFUNC ++#else ++# define HAVE_WCSCPY_IFUNC_AND_VX_SUPPORT 0 ++#endif ++ ++#if defined HAVE_S390_MIN_Z13_ZARCH_ASM_SUPPORT ++# define WCSCPY_DEFAULT WCSCPY_Z13 ++/* The z13 ifunc variant is using the common code variant as fallback! */ ++# define HAVE_WCSCPY_C 1 ++# define HAVE_WCSCPY_Z13 1 ++#else ++# define WCSCPY_DEFAULT WCSCPY_C ++# define HAVE_WCSCPY_C 1 ++# define HAVE_WCSCPY_Z13 HAVE_WCSCPY_IFUNC_AND_VX_SUPPORT ++#endif ++ ++#if HAVE_WCSCPY_C ++# define WCSCPY_C __wcscpy_c ++#else ++# define WCSCPY_C NULL ++#endif ++ ++#if HAVE_WCSCPY_Z13 ++# define WCSCPY_Z13 __wcscpy_vx ++#else ++# define WCSCPY_Z13 NULL ++#endif +diff --git a/sysdeps/s390/multiarch/Makefile b/sysdeps/s390/multiarch/Makefile +index ce2e7ce5f4eef0fa..8828897a59ae580c 100644 +--- a/sysdeps/s390/multiarch/Makefile ++++ b/sysdeps/s390/multiarch/Makefile +@@ -1,6 +1,5 @@ + ifeq ($(subdir),wcsmbs) +-sysdep_routines += wcscpy wcscpy-vx wcscpy-c \ +- wcpcpy wcpcpy-vx wcpcpy-c \ ++sysdep_routines += wcpcpy wcpcpy-vx wcpcpy-c \ + wcsncpy wcsncpy-vx wcsncpy-c \ + wcpncpy wcpncpy-vx wcpncpy-c \ + wcscat wcscat-vx wcscat-c \ +diff --git a/sysdeps/s390/multiarch/ifunc-impl-list.c b/sysdeps/s390/multiarch/ifunc-impl-list.c +index c199fd0e0b43e4b4..aac8f4ea4671d0cf 100644 +--- a/sysdeps/s390/multiarch/ifunc-impl-list.c ++++ b/sysdeps/s390/multiarch/ifunc-impl-list.c +@@ -48,6 +48,7 @@ + #include + #include + #include ++#include + + /* Maximum number of IFUNC implementations. */ + #define MAX_IFUNC 3 +@@ -450,6 +451,18 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + ) + #endif /* HAVE_WCSNLEN_IFUNC */ + ++#if HAVE_WCSCPY_IFUNC ++ IFUNC_IMPL (i, name, wcscpy, ++# if HAVE_WCSCPY_Z13 ++ IFUNC_IMPL_ADD (array, i, wcscpy, ++ dl_hwcap & HWCAP_S390_VX, WCSCPY_Z13) ++# endif ++# if HAVE_WCSCPY_C ++ IFUNC_IMPL_ADD (array, i, wcscpy, 1, WCSCPY_C) ++# endif ++ ) ++#endif /* HAVE_WCSCPY_IFUNC */ ++ + #ifdef HAVE_S390_VX_ASM_SUPPORT + + # define IFUNC_VX_IMPL(FUNC) \ +@@ -458,8 +471,6 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + __##FUNC##_vx) \ + IFUNC_IMPL_ADD (array, i, FUNC, 1, __##FUNC##_c)) + +- IFUNC_VX_IMPL (wcscpy); +- + IFUNC_VX_IMPL (wcpcpy); + + IFUNC_VX_IMPL (wcsncpy); +diff --git a/sysdeps/s390/multiarch/wcscpy-c.c b/sysdeps/s390/wcscpy-c.c +similarity index 86% +rename from sysdeps/s390/multiarch/wcscpy-c.c +rename to sysdeps/s390/wcscpy-c.c +index 4a510f466be80679..db2967f47d7bc3cc 100644 +--- a/sysdeps/s390/multiarch/wcscpy-c.c ++++ b/sysdeps/s390/wcscpy-c.c +@@ -16,10 +16,12 @@ + License along with the GNU C Library; if not, see + . */ + +-#if defined HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc) +-# define WCSCPY __wcscpy_c ++#include ++ ++#if HAVE_WCSCPY_C ++# if HAVE_WCSCPY_IFUNC || HAVE_WCSCPY_Z13 ++# define WCSCPY WCSCPY_C ++# endif + +-# include +-extern __typeof (wcscpy) __wcscpy_c; + # include + #endif +diff --git a/sysdeps/s390/multiarch/wcscpy-vx.S b/sysdeps/s390/wcscpy-vx.S +similarity index 95% +rename from sysdeps/s390/multiarch/wcscpy-vx.S +rename to sysdeps/s390/wcscpy-vx.S +index c2e81055be958907..8fe12f4d8b3e66a8 100644 +--- a/sysdeps/s390/multiarch/wcscpy-vx.S ++++ b/sysdeps/s390/wcscpy-vx.S +@@ -16,7 +16,8 @@ + License along with the GNU C Library; if not, see + . */ + +-#if defined HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc) ++#include ++#if HAVE_WCSCPY_Z13 + + # include "sysdep.h" + # include "asm-syntax.h" +@@ -37,7 +38,7 @@ + -v17=index of zero + -v18=part of src + */ +-ENTRY(__wcscpy_vx) ++ENTRY(WCSCPY_Z13) + .machine "z13" + .machinemode "zarch_nohighgprs" + +@@ -106,6 +107,10 @@ ENTRY(__wcscpy_vx) + br %r14 + + .Lfallback: +- jg __wcscpy_c +-END(__wcscpy_vx) +-#endif /* HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc) */ ++ jg WCSCPY_C ++END(WCSCPY_Z13) ++ ++# if ! HAVE_WCSCPY_IFUNC ++strong_alias (WCSCPY_Z13, wcscpy) ++# endif ++#endif +diff --git a/sysdeps/s390/multiarch/wcscpy.c b/sysdeps/s390/wcscpy.c +similarity index 70% +rename from sysdeps/s390/multiarch/wcscpy.c +rename to sysdeps/s390/wcscpy.c +index e69baa6c59906df3..51f07327da1bec74 100644 +--- a/sysdeps/s390/multiarch/wcscpy.c ++++ b/sysdeps/s390/wcscpy.c +@@ -16,12 +16,23 @@ + License along with the GNU C Library; if not, see + . */ + +-#if defined HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc) ++#include ++ ++#if HAVE_WCSCPY_IFUNC + # include + # include + +-s390_vx_libc_ifunc2 (__wcscpy, wcscpy) ++# if HAVE_WCSCPY_C ++extern __typeof (wcscpy) WCSCPY_C attribute_hidden; ++# endif ++ ++# if HAVE_WCSCPY_Z13 ++extern __typeof (wcscpy) WCSCPY_Z13 attribute_hidden; ++# endif + +-#else +-# include +-#endif /* !(defined HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc)) */ ++s390_libc_ifunc_expr (wcscpy, wcscpy, ++ (HAVE_WCSCPY_Z13 && (hwcap & HWCAP_S390_VX)) ++ ? WCSCPY_Z13 ++ : WCSCPY_DEFAULT ++ ) ++#endif diff --git a/SOURCES/glibc-rh1659438-39.patch b/SOURCES/glibc-rh1659438-39.patch new file mode 100644 index 0000000..8fe2754 --- /dev/null +++ b/SOURCES/glibc-rh1659438-39.patch @@ -0,0 +1,252 @@ +commit 0582e4284529b4ea0fcd1a8973ccab7d95ec0e87 +Author: Stefan Liebler +Date: Tue Dec 18 13:57:19 2018 +0100 + + S390: Refactor wcpcpy ifunc handling. + + The ifunc handling for wcpcpy is adjusted in order to omit ifunc + if the minimum architecture level already supports newer CPUs by default. + Unfortunately the c ifunc variant can't be omitted at all as it is used + by the z13 ifunc variant as fallback if the pointers are not 4-byte aligned. + + ChangeLog: + + * sysdeps/s390/multiarch/Makefile + (sysdep_routines): Remove wcpcpy variants. + * sysdeps/s390/Makefile (sysdep_routines): Add wcpcpy variants. + * sysdeps/s390/multiarch/ifunc-impl-list.c + (__libc_ifunc_impl_list): Refactor ifunc handling for wcpcpy. + * sysdeps/s390/multiarch/wcpcpy-c.c: Move to ... + * sysdeps/s390/wcpcpy-c.c: ... here and adjust ifunc handling. + * sysdeps/s390/multiarch/wcpcpy-vx.S: Move to ... + * sysdeps/s390/wcpcpy-vx.S: ... here and adjust ifunc handling. + * sysdeps/s390/multiarch/wcpcpy.c: Move to ... + * sysdeps/s390/wcpcpy.c: ... here and adjust ifunc handling. + * sysdeps/s390/ifunc-wcpcpy.h: New file. + +diff --git a/sysdeps/s390/Makefile b/sysdeps/s390/Makefile +index 8bdbd1b5d8e9df01..5b6446f55299af03 100644 +--- a/sysdeps/s390/Makefile ++++ b/sysdeps/s390/Makefile +@@ -62,5 +62,6 @@ endif + ifeq ($(subdir),wcsmbs) + sysdep_routines += wcslen wcslen-vx wcslen-c \ + wcsnlen wcsnlen-vx wcsnlen-c \ +- wcscpy wcscpy-vx wcscpy-c ++ wcscpy wcscpy-vx wcscpy-c \ ++ wcpcpy wcpcpy-vx wcpcpy-c + endif +diff --git a/sysdeps/s390/ifunc-wcpcpy.h b/sysdeps/s390/ifunc-wcpcpy.h +new file mode 100644 +index 0000000000000000..0d5e2ba1a0b09905 +--- /dev/null ++++ b/sysdeps/s390/ifunc-wcpcpy.h +@@ -0,0 +1,53 @@ ++/* wcpcpy variant information on S/390 version. ++ 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 ++ . */ ++ ++#if defined USE_MULTIARCH && IS_IN (libc) \ ++ && ! defined HAVE_S390_MIN_Z13_ZARCH_ASM_SUPPORT ++# define HAVE_WCPCPY_IFUNC 1 ++#else ++# define HAVE_WCPCPY_IFUNC 0 ++#endif ++ ++#ifdef HAVE_S390_VX_ASM_SUPPORT ++# define HAVE_WCPCPY_IFUNC_AND_VX_SUPPORT HAVE_WCPCPY_IFUNC ++#else ++# define HAVE_WCPCPY_IFUNC_AND_VX_SUPPORT 0 ++#endif ++ ++#if defined HAVE_S390_MIN_Z13_ZARCH_ASM_SUPPORT ++# define WCPCPY_DEFAULT WCPCPY_Z13 ++/* The z13 ifunc variant is using the common code variant as fallback! */ ++# define HAVE_WCPCPY_C 1 ++# define HAVE_WCPCPY_Z13 1 ++#else ++# define WCPCPY_DEFAULT WCPCPY_C ++# define HAVE_WCPCPY_C 1 ++# define HAVE_WCPCPY_Z13 HAVE_WCPCPY_IFUNC_AND_VX_SUPPORT ++#endif ++ ++#if HAVE_WCPCPY_C ++# define WCPCPY_C __wcpcpy_c ++#else ++# define WCPCPY_C NULL ++#endif ++ ++#if HAVE_WCPCPY_Z13 ++# define WCPCPY_Z13 __wcpcpy_vx ++#else ++# define WCPCPY_Z13 NULL ++#endif +diff --git a/sysdeps/s390/multiarch/Makefile b/sysdeps/s390/multiarch/Makefile +index 8828897a59ae580c..7d7b05dcf21cff7d 100644 +--- a/sysdeps/s390/multiarch/Makefile ++++ b/sysdeps/s390/multiarch/Makefile +@@ -1,6 +1,5 @@ + ifeq ($(subdir),wcsmbs) +-sysdep_routines += wcpcpy wcpcpy-vx wcpcpy-c \ +- wcsncpy wcsncpy-vx wcsncpy-c \ ++sysdep_routines += wcsncpy wcsncpy-vx wcsncpy-c \ + wcpncpy wcpncpy-vx wcpncpy-c \ + wcscat wcscat-vx wcscat-c \ + wcsncat wcsncat-vx wcsncat-c \ +diff --git a/sysdeps/s390/multiarch/ifunc-impl-list.c b/sysdeps/s390/multiarch/ifunc-impl-list.c +index aac8f4ea4671d0cf..656ab59db66dbb48 100644 +--- a/sysdeps/s390/multiarch/ifunc-impl-list.c ++++ b/sysdeps/s390/multiarch/ifunc-impl-list.c +@@ -49,6 +49,7 @@ + #include + #include + #include ++#include + + /* Maximum number of IFUNC implementations. */ + #define MAX_IFUNC 3 +@@ -463,6 +464,18 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + ) + #endif /* HAVE_WCSCPY_IFUNC */ + ++#if HAVE_WCPCPY_IFUNC ++ IFUNC_IMPL (i, name, wcpcpy, ++# if HAVE_WCPCPY_Z13 ++ IFUNC_IMPL_ADD (array, i, wcpcpy, ++ dl_hwcap & HWCAP_S390_VX, WCPCPY_Z13) ++# endif ++# if HAVE_WCPCPY_C ++ IFUNC_IMPL_ADD (array, i, wcpcpy, 1, WCPCPY_C) ++# endif ++ ) ++#endif /* HAVE_WCPCPY_IFUNC */ ++ + #ifdef HAVE_S390_VX_ASM_SUPPORT + + # define IFUNC_VX_IMPL(FUNC) \ +@@ -471,8 +484,6 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + __##FUNC##_vx) \ + IFUNC_IMPL_ADD (array, i, FUNC, 1, __##FUNC##_c)) + +- IFUNC_VX_IMPL (wcpcpy); +- + IFUNC_VX_IMPL (wcsncpy); + + IFUNC_VX_IMPL (wcpncpy); +diff --git a/sysdeps/s390/multiarch/wcpcpy-c.c b/sysdeps/s390/wcpcpy-c.c +similarity index 86% +rename from sysdeps/s390/multiarch/wcpcpy-c.c +rename to sysdeps/s390/wcpcpy-c.c +index e3282fde19c5262a..ed1539cde2f6f858 100644 +--- a/sysdeps/s390/multiarch/wcpcpy-c.c ++++ b/sysdeps/s390/wcpcpy-c.c +@@ -16,10 +16,12 @@ + License along with the GNU C Library; if not, see + . */ + +-#if defined HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc) +-# define WCPCPY __wcpcpy_c ++#include ++ ++#if HAVE_WCPCPY_C ++# if HAVE_WCPCPY_IFUNC || HAVE_WCPCPY_Z13 ++# define WCPCPY WCPCPY_C ++# endif + +-# include +-extern __typeof (__wcpcpy) __wcpcpy_c; + # include + #endif +diff --git a/sysdeps/s390/multiarch/wcpcpy-vx.S b/sysdeps/s390/wcpcpy-vx.S +similarity index 94% +rename from sysdeps/s390/multiarch/wcpcpy-vx.S +rename to sysdeps/s390/wcpcpy-vx.S +index bff6e8562884066c..5154ad44610c1ed1 100644 +--- a/sysdeps/s390/multiarch/wcpcpy-vx.S ++++ b/sysdeps/s390/wcpcpy-vx.S +@@ -16,7 +16,8 @@ + License along with the GNU C Library; if not, see + . */ + +-#if defined HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc) ++#include ++#if HAVE_WCPCPY_Z13 + + # include "sysdep.h" + # include "asm-syntax.h" +@@ -37,7 +38,7 @@ + -v17=index of zero + -v18=part of src + */ +-ENTRY(__wcpcpy_vx) ++ENTRY(WCPCPY_Z13) + .machine "z13" + .machinemode "zarch_nohighgprs" + +@@ -109,6 +110,11 @@ ENTRY(__wcpcpy_vx) + br %r14 + + .Lfallback: +- jg __wcpcpy_c +-END(__wcpcpy_vx) +-#endif /* HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc) */ ++ jg WCPCPY_C ++END(WCPCPY_Z13) ++ ++# if ! HAVE_WCPCPY_IFUNC ++strong_alias (WCPCPY_Z13, __wcpcpy) ++weak_alias (__wcpcpy, wcpcpy) ++# endif ++#endif +diff --git a/sysdeps/s390/multiarch/wcpcpy.c b/sysdeps/s390/wcpcpy.c +similarity index 70% +rename from sysdeps/s390/multiarch/wcpcpy.c +rename to sysdeps/s390/wcpcpy.c +index f19d376d8530d0a4..34ac68b31fedcb09 100644 +--- a/sysdeps/s390/multiarch/wcpcpy.c ++++ b/sysdeps/s390/wcpcpy.c +@@ -16,13 +16,24 @@ + License along with the GNU C Library; if not, see + . */ + +-#if defined HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc) ++#include ++ ++#if HAVE_WCPCPY_IFUNC + # include + # include + +-s390_vx_libc_ifunc (__wcpcpy) +-weak_alias (__wcpcpy, wcpcpy) ++# if HAVE_WCPCPY_C ++extern __typeof (__wcpcpy) WCPCPY_C attribute_hidden; ++# endif + +-#else +-# include +-#endif /* !(defined HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc)) */ ++# if HAVE_WCPCPY_Z13 ++extern __typeof (__wcpcpy) WCPCPY_Z13 attribute_hidden; ++# endif ++ ++s390_libc_ifunc_expr (__wcpcpy, __wcpcpy, ++ (HAVE_WCPCPY_Z13 && (hwcap & HWCAP_S390_VX)) ++ ? WCPCPY_Z13 ++ : WCPCPY_DEFAULT ++ ) ++weak_alias (__wcpcpy, wcpcpy) ++#endif diff --git a/SOURCES/glibc-rh1659438-4.patch b/SOURCES/glibc-rh1659438-4.patch new file mode 100644 index 0000000..38bf785 --- /dev/null +++ b/SOURCES/glibc-rh1659438-4.patch @@ -0,0 +1,521 @@ +commit 712a254a97ade7f48fb7a434339faa05c048ce1f +Author: Stefan Liebler +Date: Tue Dec 18 13:57:04 2018 +0100 + + S390: Refactor memset ifunc handling. + + This patch moves all ifunc variants for memset + to sysdeps/s390/memset-z900.S. The configure-check/preprocessor logic + in sysdeps/s390/ifunc-memset.h decides if ifunc is needed at all + and which ifunc variants should be available. + E.g. if the compiler/assembler already supports z196 by default, + the older ifunc variants are not included. + If we only need the newest ifunc variant, + then we can skip ifunc at all. + + Therefore the ifunc-resolvers and __libc_ifunc_impl_list are adjusted + in order to handle only the available ifunc variants. + + ChangeLog: + + * sysdeps/s390/ifunc-memset.h: New File. + * sysdeps/s390/memset.S: Move to ... + * sysdeps/s390/memset-z900.S ... here. + Move implementations from memset-s390x.s to here. + * sysdeps/s390/multiarch/memset-s390x.S: Delete File. + * sysdeps/s390/multiarch/Makefile (sysdep_routines): + Remove memset variants. + * sysdeps/s390/Makefile (sysdep_routines): + Add memset variants. + * sysdeps/s390/multiarch/ifunc-impl-list.c + (__libc_ifunc_impl_list): Adjust ifunc variants for + memset. + * sysdeps/s390/multiarch/memset.c: Move ifunc resolver + to ... + * sysdeps/s390/memset.c: ... here. + Adjust ifunc variants for memset. + +Conflicts: + sysdeps/s390/Makefile + Missing backport of commit 69e2444ab1444ab8210598abbcb4822701d368b9 + ("S390: Test that lazy binding does not clobber R0"). + +diff --git a/sysdeps/s390/Makefile b/sysdeps/s390/Makefile +index 8a54f88cd7ac880e..360838e172f4ca37 100644 +--- a/sysdeps/s390/Makefile ++++ b/sysdeps/s390/Makefile +@@ -29,3 +29,7 @@ $(inst_gconvdir)/%.so: $(objpfx)%.so $(+force) + + sysdeps-gconv-modules = ../sysdeps/s390/gconv-modules + endif ++ ++ifeq ($(subdir),string) ++sysdep_routines += memset memset-z900 ++endif +diff --git a/sysdeps/s390/ifunc-memset.h b/sysdeps/s390/ifunc-memset.h +new file mode 100644 +index 0000000000000000..9a13b1001fed9979 +--- /dev/null ++++ b/sysdeps/s390/ifunc-memset.h +@@ -0,0 +1,65 @@ ++/* memset variant information on S/390 version. ++ 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 ++ . */ ++ ++#if defined USE_MULTIARCH && IS_IN (libc) \ ++ && ! defined HAVE_S390_MIN_Z196_ZARCH_ASM_SUPPORT ++# define HAVE_MEMSET_IFUNC 1 ++#else ++# define HAVE_MEMSET_IFUNC 0 ++#endif ++ ++#if defined HAVE_S390_MIN_Z196_ZARCH_ASM_SUPPORT ++# define MEMSET_DEFAULT MEMSET_Z196 ++# define HAVE_MEMSET_Z900_G5 0 ++# define HAVE_MEMSET_Z10 0 ++# define HAVE_MEMSET_Z196 1 ++#elif defined HAVE_S390_MIN_Z10_ZARCH_ASM_SUPPORT ++# define MEMSET_DEFAULT MEMSET_Z10 ++# define HAVE_MEMSET_Z900_G5 0 ++# define HAVE_MEMSET_Z10 1 ++# define HAVE_MEMSET_Z196 HAVE_MEMSET_IFUNC ++#else ++# define MEMSET_DEFAULT MEMSET_Z900_G5 ++# define HAVE_MEMSET_Z900_G5 1 ++# define HAVE_MEMSET_Z10 HAVE_MEMSET_IFUNC ++# define HAVE_MEMSET_Z196 HAVE_MEMSET_IFUNC ++#endif ++ ++#if HAVE_MEMSET_Z10 || HAVE_MEMSET_Z196 ++# define HAVE_MEMSET_MVCLE 1 ++#else ++# define HAVE_MEMSET_MVCLE 0 ++#endif ++ ++#if HAVE_MEMSET_Z900_G5 ++# define MEMSET_Z900_G5 __memset_default ++#else ++# define MEMSET_Z900_G5 NULL ++#endif ++ ++#if HAVE_MEMSET_Z10 ++# define MEMSET_Z10 __memset_z10 ++#else ++# define MEMSET_Z10 NULL ++#endif ++ ++#if HAVE_MEMSET_Z196 ++# define MEMSET_Z196 __memset_z196 ++#else ++# define MEMSET_Z196 NULL ++#endif +diff --git a/sysdeps/s390/multiarch/memset-s390x.S b/sysdeps/s390/memset-z900.S +similarity index 57% +rename from sysdeps/s390/multiarch/memset-s390x.S +rename to sysdeps/s390/memset-z900.S +index aca3ac3fda1dd228..eaf13402bd3e251d 100644 +--- a/sysdeps/s390/multiarch/memset-s390x.S ++++ b/sysdeps/s390/memset-z900.S +@@ -1,5 +1,6 @@ + /* Set a block of memory to some byte value. 31/64 bit S/390 version. +- Copyright (C) 2012-2018 Free Software Foundation, Inc. ++ Copyright (C) 2001-2018 Free Software Foundation, Inc. ++ Contributed by Martin Schwidefsky (schwidefsky@de.ibm.com). + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or +@@ -17,8 +18,9 @@ + . */ + + +-#include "sysdep.h" ++#include + #include "asm-syntax.h" ++#include + + /* INPUT PARAMETERS + %r2 = address of memory area +@@ -27,43 +29,68 @@ + + .text + +-#if IS_IN (libc) ++#if HAVE_MEMSET_Z900_G5 ++# if defined __s390x__ ++# define LTGR ltgr ++# define CGHI cghi ++# define LGR lgr ++# define AGHI aghi ++# define BRCTG brctg ++# else ++# define LTGR ltr ++# define CGHI chi ++# define LGR lr ++# define AGHI ahi ++# define BRCTG brct ++# endif /* ! defined __s390x__ */ + +-ENTRY(__memset_z196) +- .machine "z196" +- .machinemode "zarch_nohighgprs" +-# if !defined __s390x__ +- llgfr %r4,%r4 +-# endif /* !defined __s390x__ */ +- ltgr %r4,%r4 +- je .L_Z196_4 ++ENTRY(MEMSET_Z900_G5) ++#if defined __s390x__ ++ .machine "z900" ++#else ++ .machine "g5" ++#endif /* ! defined __s390x__ */ ++ LTGR %r4,%r4 ++ je .L_Z900_G5_4 + stc %r3,0(%r2) +- lgr %r1,%r2 +- cghi %r4,1 +- je .L_Z196_4 +- aghi %r4,-2 +- srlg %r5,%r4,8 +- ltgr %r5,%r5 +- jne .L_Z196_1 +-.L_Z196_3: +- exrl %r4,.L_Z196_17 +-.L_Z196_4: ++ CGHI %r4,1 ++ LGR %r1,%r2 ++ je .L_Z900_G5_4 ++ AGHI %r4,-2 ++#if defined __s390x__ ++ larl %r5,.L_Z900_G5_18 ++ srlg %r3,%r4,8 ++# define Z900_G5_EX_D 0 ++#else ++ basr %r5,0 ++.L_Z900_G5_19: ++# define Z900_G5_EX_D .L_Z900_G5_18-.L_Z900_G5_19 ++ lr %r3,%r4 ++ srl %r3,8 ++#endif /* ! defined __s390x__ */ ++ LTGR %r3,%r3 ++ jne .L_Z900_G5_14 ++.L_Z900_G5_3: ++ ex %r4,Z900_G5_EX_D(%r5) ++.L_Z900_G5_4: + br %r14 +-.L_Z196_1: +- cgfi %r5,1048576 +- jh __memset_mvcle # Switch to mvcle for >256MB +-.L_Z196_2: +- pfd 2,1024(%r1) ++.L_Z900_G5_14: + mvc 1(256,%r1),0(%r1) +- aghi %r5,-1 + la %r1,256(%r1) +- jne .L_Z196_2 +- j .L_Z196_3 +-.L_Z196_17: ++ BRCTG %r3,.L_Z900_G5_14 ++ j .L_Z900_G5_3 ++.L_Z900_G5_18: + mvc 1(1,%r1),0(%r1) +-END(__memset_z196) ++END(MEMSET_Z900_G5) ++# undef LTGR ++# undef CGHI ++# undef LGR ++# undef AGHI ++# undef BRCTG ++#endif /* HAVE_MEMSET_Z900_G5 */ + +-ENTRY(__memset_z10) ++#if HAVE_MEMSET_Z10 ++ENTRY(MEMSET_Z10) + .machine "z10" + .machinemode "zarch_nohighgprs" + # if !defined __s390x__ +@@ -91,8 +118,46 @@ ENTRY(__memset_z10) + j .L_Z10_3 + .L_Z10_18: + mvc 1(1,%r1),0(%r1) +-END(__memset_z10) ++END(MEMSET_Z10) ++#endif /* HAVE_MEMSET_Z10 */ ++ ++#if HAVE_MEMSET_Z196 ++ENTRY(MEMSET_Z196) ++ .machine "z196" ++ .machinemode "zarch_nohighgprs" ++# if !defined __s390x__ ++ llgfr %r4,%r4 ++# endif /* !defined __s390x__ */ ++ ltgr %r4,%r4 ++ je .L_Z196_4 ++ stc %r3,0(%r2) ++ lgr %r1,%r2 ++ cghi %r4,1 ++ je .L_Z196_4 ++ aghi %r4,-2 ++ srlg %r5,%r4,8 ++ ltgr %r5,%r5 ++ jne .L_Z196_1 ++.L_Z196_3: ++ exrl %r4,.L_Z196_17 ++.L_Z196_4: ++ br %r14 ++.L_Z196_1: ++ cgfi %r5,1048576 ++ jh __memset_mvcle # Switch to mvcle for >256MB ++.L_Z196_2: ++ pfd 2,1024(%r1) ++ mvc 1(256,%r1),0(%r1) ++ aghi %r5,-1 ++ la %r1,256(%r1) ++ jne .L_Z196_2 ++ j .L_Z196_3 ++.L_Z196_17: ++ mvc 1(1,%r1),0(%r1) ++END(MEMSET_Z196) ++#endif /* HAVE_MEMSET_Z196 */ + ++#if HAVE_MEMSET_MVCLE + ENTRY(__memset_mvcle) + aghi %r4,2 # take back the change done by the caller + lgr %r0,%r2 # save source address +@@ -106,15 +171,16 @@ ENTRY(__memset_mvcle) + .L1: + br %r14 + END(__memset_mvcle) ++#endif /* HAVE_MEMSET_MVCLE */ + +-#endif /* IS_IN (libc) */ +- +-#include "../memset.S" ++#if ! HAVE_MEMSET_IFUNC ++/* If we don't use ifunc, define an alias for memset here. ++ Otherwise see sysdeps/s390/memset.c. */ ++strong_alias (MEMSET_DEFAULT, memset) ++#endif + +-#if !IS_IN (libc) +-.globl memset +-.set memset,__memset_default +-#elif defined SHARED && IS_IN (libc) +-.globl __GI_memset +-.set __GI_memset,__memset_default ++#if defined SHARED && IS_IN (libc) ++/* Defines the internal symbol. ++ Compare to libc_hidden_builtin_def (memset) in string/memset.c. */ ++strong_alias (MEMSET_DEFAULT, __GI_memset) + #endif +diff --git a/sysdeps/s390/memset.S b/sysdeps/s390/memset.S +deleted file mode 100644 +index 72e7c5a42efbaf6c..0000000000000000 +--- a/sysdeps/s390/memset.S ++++ /dev/null +@@ -1,97 +0,0 @@ +-/* Set a block of memory to some byte value. 31/64 bit S/390 version. +- Copyright (C) 2001-2018 Free Software Foundation, Inc. +- Contributed by Martin Schwidefsky (schwidefsky@de.ibm.com). +- This file is part of the GNU C Library. +- +- The GNU C Library is free software; you can redistribute it and/or +- modify it under the terms of the GNU Lesser General Public +- License as published by the Free Software Foundation; either +- version 2.1 of the License, or (at your option) any later version. +- +- The GNU C Library is distributed in the hope that it will be useful, +- but WITHOUT ANY WARRANTY; without even the implied warranty of +- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +- Lesser General Public License for 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 "asm-syntax.h" +- +-/* INPUT PARAMETERS +- %r2 = address of memory area +- %r3 = byte to fill memory with +- %r4 = number of bytes to fill. */ +- +- .text +- +-#if defined __s390x__ +-# define LTGR ltgr +-# define CGHI cghi +-# define LGR lgr +-# define AGHI aghi +-# define BRCTG brctg +-#else +-# define LTGR ltr +-# define CGHI chi +-# define LGR lr +-# define AGHI ahi +-# define BRCTG brct +-#endif /* ! defined __s390x__ */ +- +-#ifdef USE_MULTIARCH +-ENTRY(__memset_default) +-#else +-ENTRY(memset) +-#endif +-#if defined __s390x__ +- .machine "z900" +-#else +- .machine "g5" +-#endif /* ! defined __s390x__ */ +- LTGR %r4,%r4 +- je .L_Z900_G5_4 +- stc %r3,0(%r2) +- CGHI %r4,1 +- LGR %r1,%r2 +- je .L_Z900_G5_4 +- AGHI %r4,-2 +-#if defined __s390x__ +- larl %r5,.L_Z900_G5_18 +- srlg %r3,%r4,8 +-# define Z900_G5_EX_D 0 +-#else +- basr %r5,0 +-.L_Z900_G5_19: +-# define Z900_G5_EX_D .L_Z900_G5_18-.L_Z900_G5_19 +- lr %r3,%r4 +- srl %r3,8 +-#endif /* ! defined __s390x__ */ +- LTGR %r3,%r3 +- jne .L_Z900_G5_14 +-.L_Z900_G5_3: +- ex %r4,Z900_G5_EX_D(%r5) +-.L_Z900_G5_4: +- br %r14 +-.L_Z900_G5_14: +- mvc 1(256,%r1),0(%r1) +- la %r1,256(%r1) +- BRCTG %r3,.L_Z900_G5_14 +- j .L_Z900_G5_3 +-.L_Z900_G5_18: +- mvc 1(1,%r1),0(%r1) +-#ifdef USE_MULTIARCH +-END(__memset_default) +-#else +-END(memset) +-libc_hidden_builtin_def (memset) +-#endif +- +-#undef LTGR +-#undef CGHI +-#undef LGR +-#undef AGHI +-#undef BRCTG +diff --git a/sysdeps/s390/multiarch/memset.c b/sysdeps/s390/memset.c +similarity index 60% +rename from sysdeps/s390/multiarch/memset.c +rename to sysdeps/s390/memset.c +index 760b3e9df201b8b4..57a35aebc7d3c794 100644 +--- a/sysdeps/s390/multiarch/memset.c ++++ b/sysdeps/s390/memset.c +@@ -16,11 +16,33 @@ + License along with the GNU C Library; if not, see + . */ + +-#if IS_IN (libc) ++#include ++#if HAVE_MEMSET_IFUNC + # define memset __redirect_memset + # include + # undef memset + # include + +-s390_libc_ifunc (__redirect_memset, __memset, memset) ++# if HAVE_MEMSET_Z900_G5 ++extern __typeof (__redirect_memset) MEMSET_Z900_G5 attribute_hidden; ++# endif ++ ++# if HAVE_MEMSET_Z10 ++extern __typeof (__redirect_memset) MEMSET_Z10 attribute_hidden; ++# endif ++ ++# if HAVE_MEMSET_Z196 ++extern __typeof (__redirect_memset) MEMSET_Z196 attribute_hidden; ++# endif ++ ++s390_libc_ifunc_expr (__redirect_memset, memset, ++ ({ ++ s390_libc_ifunc_init (); ++ (HAVE_MEMSET_Z196 && S390_IS_Z196 (stfle_bits)) ++ ? MEMSET_Z196 ++ : (HAVE_MEMSET_Z10 && S390_IS_Z10 (stfle_bits)) ++ ? MEMSET_Z10 ++ : MEMSET_DEFAULT; ++ }) ++ ) + #endif +diff --git a/sysdeps/s390/multiarch/Makefile b/sysdeps/s390/multiarch/Makefile +index 93ad21bfa2686ee5..c893ebc5659fd4ae 100644 +--- a/sysdeps/s390/multiarch/Makefile ++++ b/sysdeps/s390/multiarch/Makefile +@@ -19,8 +19,7 @@ sysdep_routines += strlen strlen-vx strlen-c \ + rawmemchr rawmemchr-vx rawmemchr-c \ + memccpy memccpy-vx memccpy-c \ + memrchr memrchr-vx memrchr-c \ +- mempcpy \ +- memset memset-s390x ++ mempcpy + endif + + ifeq ($(subdir),wcsmbs) +diff --git a/sysdeps/s390/multiarch/ifunc-impl-list.c b/sysdeps/s390/multiarch/ifunc-impl-list.c +index ec3373ae2653d66e..2f671eac1f4f1ffd 100644 +--- a/sysdeps/s390/multiarch/ifunc-impl-list.c ++++ b/sysdeps/s390/multiarch/ifunc-impl-list.c +@@ -21,6 +21,7 @@ + #include + #include + #include ++#include + + /* Maximum number of IFUNC implementations. */ + #define MAX_IFUNC 3 +@@ -46,12 +47,21 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + S390_STORE_STFLE (stfle_bits); + } + ++#if HAVE_MEMSET_IFUNC + IFUNC_IMPL (i, name, memset, ++# if HAVE_MEMSET_Z196 + IFUNC_IMPL_ADD (array, i, memset, +- S390_IS_Z196 (stfle_bits), __memset_z196) ++ S390_IS_Z196 (stfle_bits), MEMSET_Z196) ++# endif ++# if HAVE_MEMSET_Z10 + IFUNC_IMPL_ADD (array, i, memset, +- S390_IS_Z10 (stfle_bits), __memset_z10) +- IFUNC_IMPL_ADD (array, i, memset, 1, __memset_default)) ++ S390_IS_Z10 (stfle_bits), MEMSET_Z10) ++# endif ++# if HAVE_MEMSET_Z900_G5 ++ IFUNC_IMPL_ADD (array, i, memset, 1, MEMSET_Z900_G5) ++# endif ++ ) ++#endif /* HAVE_MEMSET_IFUNC */ + + IFUNC_IMPL (i, name, memcmp, + IFUNC_IMPL_ADD (array, i, memcmp, diff --git a/SOURCES/glibc-rh1659438-40.patch b/SOURCES/glibc-rh1659438-40.patch new file mode 100644 index 0000000..3eddef4 --- /dev/null +++ b/SOURCES/glibc-rh1659438-40.patch @@ -0,0 +1,253 @@ +commit 0966dd86896d7cd6c107c751ba7d3b69542ca11d +Author: Stefan Liebler +Date: Tue Dec 18 13:57:19 2018 +0100 + + S390: Refactor wcsncpy ifunc handling. + + The ifunc handling for wcsncpy is adjusted in order to omit ifunc + if the minimum architecture level already supports newer CPUs by default. + Unfortunately the c ifunc variant can't be omitted at all as it is used + by the z13 ifunc variant as fallback if the pointers are not 4-byte aligned. + + ChangeLog: + + * sysdeps/s390/multiarch/Makefile + (sysdep_routines): Remove wcsncpy variants. + * sysdeps/s390/Makefile (sysdep_routines): Add wcsncpy variants. + * sysdeps/s390/multiarch/ifunc-impl-list.c + (__libc_ifunc_impl_list): Refactor ifunc handling for wcsncpy. + * sysdeps/s390/multiarch/wcsncpy-c.c: Move to ... + * sysdeps/s390/wcsncpy-c.c: ... here and adjust ifunc handling. + * sysdeps/s390/multiarch/wcsncpy-vx.S: Move to ... + * sysdeps/s390/wcsncpy-vx.S: ... here and adjust ifunc handling. + * sysdeps/s390/multiarch/wcsncpy.c: Move to ... + * sysdeps/s390/wcsncpy.c: ... here and adjust ifunc handling. + * sysdeps/s390/ifunc-wcsncpy.h: New file. + +diff --git a/sysdeps/s390/Makefile b/sysdeps/s390/Makefile +index 5b6446f55299af03..cc8357361e1f2574 100644 +--- a/sysdeps/s390/Makefile ++++ b/sysdeps/s390/Makefile +@@ -63,5 +63,6 @@ ifeq ($(subdir),wcsmbs) + sysdep_routines += wcslen wcslen-vx wcslen-c \ + wcsnlen wcsnlen-vx wcsnlen-c \ + wcscpy wcscpy-vx wcscpy-c \ +- wcpcpy wcpcpy-vx wcpcpy-c ++ wcpcpy wcpcpy-vx wcpcpy-c \ ++ wcsncpy wcsncpy-vx wcsncpy-c + endif +diff --git a/sysdeps/s390/ifunc-wcsncpy.h b/sysdeps/s390/ifunc-wcsncpy.h +new file mode 100644 +index 0000000000000000..d7beca128aaaebc8 +--- /dev/null ++++ b/sysdeps/s390/ifunc-wcsncpy.h +@@ -0,0 +1,53 @@ ++/* wcsncpy variant information on S/390 version. ++ 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 ++ . */ ++ ++#if defined USE_MULTIARCH && IS_IN (libc) \ ++ && ! defined HAVE_S390_MIN_Z13_ZARCH_ASM_SUPPORT ++# define HAVE_WCSNCPY_IFUNC 1 ++#else ++# define HAVE_WCSNCPY_IFUNC 0 ++#endif ++ ++#ifdef HAVE_S390_VX_ASM_SUPPORT ++# define HAVE_WCSNCPY_IFUNC_AND_VX_SUPPORT HAVE_WCSNCPY_IFUNC ++#else ++# define HAVE_WCSNCPY_IFUNC_AND_VX_SUPPORT 0 ++#endif ++ ++#if defined HAVE_S390_MIN_Z13_ZARCH_ASM_SUPPORT ++# define WCSNCPY_DEFAULT WCSNCPY_Z13 ++/* The z13 ifunc variant is using the common code variant as fallback! */ ++# define HAVE_WCSNCPY_C 1 ++# define HAVE_WCSNCPY_Z13 1 ++#else ++# define WCSNCPY_DEFAULT WCSNCPY_C ++# define HAVE_WCSNCPY_C 1 ++# define HAVE_WCSNCPY_Z13 HAVE_WCSNCPY_IFUNC_AND_VX_SUPPORT ++#endif ++ ++#if HAVE_WCSNCPY_C ++# define WCSNCPY_C __wcsncpy_c ++#else ++# define WCSNCPY_C NULL ++#endif ++ ++#if HAVE_WCSNCPY_Z13 ++# define WCSNCPY_Z13 __wcsncpy_vx ++#else ++# define WCSNCPY_Z13 NULL ++#endif +diff --git a/sysdeps/s390/multiarch/Makefile b/sysdeps/s390/multiarch/Makefile +index 7d7b05dcf21cff7d..6631fd14d32fde72 100644 +--- a/sysdeps/s390/multiarch/Makefile ++++ b/sysdeps/s390/multiarch/Makefile +@@ -1,6 +1,5 @@ + ifeq ($(subdir),wcsmbs) +-sysdep_routines += wcsncpy wcsncpy-vx wcsncpy-c \ +- wcpncpy wcpncpy-vx wcpncpy-c \ ++sysdep_routines += wcpncpy wcpncpy-vx wcpncpy-c \ + wcscat wcscat-vx wcscat-c \ + wcsncat wcsncat-vx wcsncat-c \ + wcscmp wcscmp-vx wcscmp-c \ +diff --git a/sysdeps/s390/multiarch/ifunc-impl-list.c b/sysdeps/s390/multiarch/ifunc-impl-list.c +index 656ab59db66dbb48..9ebaf4de6f2eb841 100644 +--- a/sysdeps/s390/multiarch/ifunc-impl-list.c ++++ b/sysdeps/s390/multiarch/ifunc-impl-list.c +@@ -50,6 +50,7 @@ + #include + #include + #include ++#include + + /* Maximum number of IFUNC implementations. */ + #define MAX_IFUNC 3 +@@ -476,6 +477,18 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + ) + #endif /* HAVE_WCPCPY_IFUNC */ + ++#if HAVE_WCSNCPY_IFUNC ++ IFUNC_IMPL (i, name, wcsncpy, ++# if HAVE_WCSNCPY_Z13 ++ IFUNC_IMPL_ADD (array, i, wcsncpy, ++ dl_hwcap & HWCAP_S390_VX, WCSNCPY_Z13) ++# endif ++# if HAVE_WCSNCPY_C ++ IFUNC_IMPL_ADD (array, i, wcsncpy, 1, WCSNCPY_C) ++# endif ++ ) ++#endif /* HAVE_WCSNCPY_IFUNC */ ++ + #ifdef HAVE_S390_VX_ASM_SUPPORT + + # define IFUNC_VX_IMPL(FUNC) \ +@@ -484,8 +497,6 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + __##FUNC##_vx) \ + IFUNC_IMPL_ADD (array, i, FUNC, 1, __##FUNC##_c)) + +- IFUNC_VX_IMPL (wcsncpy); +- + IFUNC_VX_IMPL (wcpncpy); + + IFUNC_VX_IMPL (wcscat); +diff --git a/sysdeps/s390/multiarch/wcsncpy-c.c b/sysdeps/s390/wcsncpy-c.c +similarity index 85% +rename from sysdeps/s390/multiarch/wcsncpy-c.c +rename to sysdeps/s390/wcsncpy-c.c +index 6b89b8c14bf58198..4d0ddb09ecb1c849 100644 +--- a/sysdeps/s390/multiarch/wcsncpy-c.c ++++ b/sysdeps/s390/wcsncpy-c.c +@@ -16,10 +16,12 @@ + License along with the GNU C Library; if not, see + . */ + +-#if defined HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc) +-# define WCSNCPY __wcsncpy_c ++#include ++ ++#if HAVE_WCSNCPY_C ++# if HAVE_WCSNCPY_IFUNC || HAVE_WCSNCPY_Z13 ++# define WCSNCPY WCSNCPY_C ++# endif + +-# include +-extern __typeof (__wcsncpy) __wcsncpy_c; + # include + #endif +diff --git a/sysdeps/s390/multiarch/wcsncpy-vx.S b/sysdeps/s390/wcsncpy-vx.S +similarity index 97% +rename from sysdeps/s390/multiarch/wcsncpy-vx.S +rename to sysdeps/s390/wcsncpy-vx.S +index b3400d50d9ab3324..9bcbdbf3229033da 100644 +--- a/sysdeps/s390/multiarch/wcsncpy-vx.S ++++ b/sysdeps/s390/wcsncpy-vx.S +@@ -16,7 +16,8 @@ + License along with the GNU C Library; if not, see + . */ + +-#if defined HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc) ++#include ++#if HAVE_WCSNCPY_Z13 + + # include "sysdep.h" + # include "asm-syntax.h" +@@ -40,7 +41,7 @@ + -v18=part of src + -v31=register save area for r6, r7 + */ +-ENTRY(__wcsncpy_vx) ++ENTRY(WCSNCPY_Z13) + .machine "z13" + .machinemode "zarch_nohighgprs" + +@@ -217,7 +218,11 @@ ENTRY(__wcsncpy_vx) + j .Llt64 + + .Lfallback: +- jg __wcsncpy_c +-END(__wcsncpy_vx) +- +-#endif /* HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc) */ ++ jg WCSNCPY_C ++END(WCSNCPY_Z13) ++ ++# if ! HAVE_WCSNCPY_IFUNC ++strong_alias (WCSNCPY_Z13, __wcsncpy) ++weak_alias (__wcsncpy, wcsncpy) ++# endif ++#endif +diff --git a/sysdeps/s390/multiarch/wcsncpy.c b/sysdeps/s390/wcsncpy.c +similarity index 70% +rename from sysdeps/s390/multiarch/wcsncpy.c +rename to sysdeps/s390/wcsncpy.c +index 7209c7d4310d6013..e011de7ee7652bec 100644 +--- a/sysdeps/s390/multiarch/wcsncpy.c ++++ b/sysdeps/s390/wcsncpy.c +@@ -16,13 +16,24 @@ + License along with the GNU C Library; if not, see + . */ + +-#if defined HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc) ++#include ++ ++#if HAVE_WCSNCPY_IFUNC + # include + # include + +-s390_vx_libc_ifunc (__wcsncpy) +-weak_alias (__wcsncpy, wcsncpy) ++# if HAVE_WCSNCPY_C ++extern __typeof (__wcsncpy) WCSNCPY_C attribute_hidden; ++# endif + +-#else +-# include +-#endif /* !(defined HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc)) */ ++# if HAVE_WCSNCPY_Z13 ++extern __typeof (__wcsncpy) WCSNCPY_Z13 attribute_hidden; ++# endif ++ ++s390_libc_ifunc_expr (__wcsncpy, __wcsncpy, ++ (HAVE_WCSNCPY_Z13 && (hwcap & HWCAP_S390_VX)) ++ ? WCSNCPY_Z13 ++ : WCSNCPY_DEFAULT ++ ) ++weak_alias (__wcsncpy, wcsncpy) ++#endif diff --git a/SOURCES/glibc-rh1659438-41.patch b/SOURCES/glibc-rh1659438-41.patch new file mode 100644 index 0000000..ee4a97f --- /dev/null +++ b/SOURCES/glibc-rh1659438-41.patch @@ -0,0 +1,252 @@ +commit c3081bcbd91a619115f047c2ceea90a9090d5216 +Author: Stefan Liebler +Date: Tue Dec 18 13:57:19 2018 +0100 + + S390: Refactor wcpncpy ifunc handling. + + The ifunc handling for wcpncpy is adjusted in order to omit ifunc + if the minimum architecture level already supports newer CPUs by default. + Unfortunately the c ifunc variant can't be omitted at all as it is used + by the z13 ifunc variant as fallback if the pointers are not 4-byte aligned. + + ChangeLog: + + * sysdeps/s390/multiarch/Makefile + (sysdep_routines): Remove wcpncpy variants. + * sysdeps/s390/Makefile (sysdep_routines): Add wcpncpy variants. + * sysdeps/s390/multiarch/ifunc-impl-list.c + (__libc_ifunc_impl_list): Refactor ifunc handling for wcpncpy. + * sysdeps/s390/multiarch/wcpncpy-c.c: Move to ... + * sysdeps/s390/wcpncpy-c.c: ... here and adjust ifunc handling. + * sysdeps/s390/multiarch/wcpncpy-vx.S: Move to ... + * sysdeps/s390/wcpncpy-vx.S: ... here and adjust ifunc handling. + * sysdeps/s390/multiarch/wcpncpy.c: Move to ... + * sysdeps/s390/wcpncpy.c: ... here and adjust ifunc handling. + * sysdeps/s390/ifunc-wcpncpy.h: New file. + +diff --git a/sysdeps/s390/Makefile b/sysdeps/s390/Makefile +index cc8357361e1f2574..640177370382235f 100644 +--- a/sysdeps/s390/Makefile ++++ b/sysdeps/s390/Makefile +@@ -64,5 +64,6 @@ sysdep_routines += wcslen wcslen-vx wcslen-c \ + wcsnlen wcsnlen-vx wcsnlen-c \ + wcscpy wcscpy-vx wcscpy-c \ + wcpcpy wcpcpy-vx wcpcpy-c \ +- wcsncpy wcsncpy-vx wcsncpy-c ++ wcsncpy wcsncpy-vx wcsncpy-c \ ++ wcpncpy wcpncpy-vx wcpncpy-c + endif +diff --git a/sysdeps/s390/ifunc-wcpncpy.h b/sysdeps/s390/ifunc-wcpncpy.h +new file mode 100644 +index 0000000000000000..0dd5633aa9cd780b +--- /dev/null ++++ b/sysdeps/s390/ifunc-wcpncpy.h +@@ -0,0 +1,53 @@ ++/* wcpncpy variant information on S/390 version. ++ 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 ++ . */ ++ ++#if defined USE_MULTIARCH && IS_IN (libc) \ ++ && ! defined HAVE_S390_MIN_Z13_ZARCH_ASM_SUPPORT ++# define HAVE_WCPNCPY_IFUNC 1 ++#else ++# define HAVE_WCPNCPY_IFUNC 0 ++#endif ++ ++#ifdef HAVE_S390_VX_ASM_SUPPORT ++# define HAVE_WCPNCPY_IFUNC_AND_VX_SUPPORT HAVE_WCPNCPY_IFUNC ++#else ++# define HAVE_WCPNCPY_IFUNC_AND_VX_SUPPORT 0 ++#endif ++ ++#if defined HAVE_S390_MIN_Z13_ZARCH_ASM_SUPPORT ++# define WCPNCPY_DEFAULT WCPNCPY_Z13 ++/* The z13 ifunc variant is using the common code variant as fallback! */ ++# define HAVE_WCPNCPY_C 1 ++# define HAVE_WCPNCPY_Z13 1 ++#else ++# define WCPNCPY_DEFAULT WCPNCPY_C ++# define HAVE_WCPNCPY_C 1 ++# define HAVE_WCPNCPY_Z13 HAVE_WCPNCPY_IFUNC_AND_VX_SUPPORT ++#endif ++ ++#if HAVE_WCPNCPY_C ++# define WCPNCPY_C __wcpncpy_c ++#else ++# define WCPNCPY_C NULL ++#endif ++ ++#if HAVE_WCPNCPY_Z13 ++# define WCPNCPY_Z13 __wcpncpy_vx ++#else ++# define WCPNCPY_Z13 NULL ++#endif +diff --git a/sysdeps/s390/multiarch/Makefile b/sysdeps/s390/multiarch/Makefile +index 6631fd14d32fde72..158fb495523438b4 100644 +--- a/sysdeps/s390/multiarch/Makefile ++++ b/sysdeps/s390/multiarch/Makefile +@@ -1,6 +1,5 @@ + ifeq ($(subdir),wcsmbs) +-sysdep_routines += wcpncpy wcpncpy-vx wcpncpy-c \ +- wcscat wcscat-vx wcscat-c \ ++sysdep_routines += wcscat wcscat-vx wcscat-c \ + wcsncat wcsncat-vx wcsncat-c \ + wcscmp wcscmp-vx wcscmp-c \ + wcsncmp wcsncmp-vx wcsncmp-c \ +diff --git a/sysdeps/s390/multiarch/ifunc-impl-list.c b/sysdeps/s390/multiarch/ifunc-impl-list.c +index 9ebaf4de6f2eb841..e60238fcde4dcd4f 100644 +--- a/sysdeps/s390/multiarch/ifunc-impl-list.c ++++ b/sysdeps/s390/multiarch/ifunc-impl-list.c +@@ -51,6 +51,7 @@ + #include + #include + #include ++#include + + /* Maximum number of IFUNC implementations. */ + #define MAX_IFUNC 3 +@@ -489,6 +490,18 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + ) + #endif /* HAVE_WCSNCPY_IFUNC */ + ++#if HAVE_WCPNCPY_IFUNC ++ IFUNC_IMPL (i, name, wcpncpy, ++# if HAVE_WCPNCPY_Z13 ++ IFUNC_IMPL_ADD (array, i, wcpncpy, ++ dl_hwcap & HWCAP_S390_VX, WCPNCPY_Z13) ++# endif ++# if HAVE_WCPNCPY_C ++ IFUNC_IMPL_ADD (array, i, wcpncpy, 1, WCPNCPY_C) ++# endif ++ ) ++#endif /* HAVE_WCPNCPY_IFUNC */ ++ + #ifdef HAVE_S390_VX_ASM_SUPPORT + + # define IFUNC_VX_IMPL(FUNC) \ +@@ -497,8 +510,6 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + __##FUNC##_vx) \ + IFUNC_IMPL_ADD (array, i, FUNC, 1, __##FUNC##_c)) + +- IFUNC_VX_IMPL (wcpncpy); +- + IFUNC_VX_IMPL (wcscat); + + IFUNC_VX_IMPL (wcsncat); +diff --git a/sysdeps/s390/multiarch/wcpncpy-c.c b/sysdeps/s390/wcpncpy-c.c +similarity index 85% +rename from sysdeps/s390/multiarch/wcpncpy-c.c +rename to sysdeps/s390/wcpncpy-c.c +index 1f44bacea9b65d44..d03359217e98a1f3 100644 +--- a/sysdeps/s390/multiarch/wcpncpy-c.c ++++ b/sysdeps/s390/wcpncpy-c.c +@@ -16,10 +16,12 @@ + License along with the GNU C Library; if not, see + . */ + +-#if defined HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc) +-# define WCPNCPY __wcpncpy_c ++#include ++ ++#if HAVE_WCPNCPY_C ++# if HAVE_WCPNCPY_IFUNC || HAVE_WCPNCPY_Z13 ++# define WCPNCPY WCPNCPY_C ++# endif + +-# include +-extern __typeof (__wcpncpy) __wcpncpy_c; + # include + #endif +diff --git a/sysdeps/s390/multiarch/wcpncpy-vx.S b/sysdeps/s390/wcpncpy-vx.S +similarity index 97% +rename from sysdeps/s390/multiarch/wcpncpy-vx.S +rename to sysdeps/s390/wcpncpy-vx.S +index 004f512e1f1a7982..7b5e4ad32d42d44b 100644 +--- a/sysdeps/s390/multiarch/wcpncpy-vx.S ++++ b/sysdeps/s390/wcpncpy-vx.S +@@ -16,7 +16,8 @@ + License along with the GNU C Library; if not, see + . */ + +-#if defined HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc) ++#include ++#if HAVE_WCPNCPY_Z13 + + # include "sysdep.h" + # include "asm-syntax.h" +@@ -38,7 +39,7 @@ + -%r6 = loaded bytes + -%r7 = border, tmp + */ +-ENTRY(__wcpncpy_vx) ++ENTRY(WCPNCPY_Z13) + .machine "z13" + .machinemode "zarch_nohighgprs" + +@@ -217,6 +218,11 @@ ENTRY(__wcpncpy_vx) + j .Llt64 + + .Lfallback: +- jg __wcpncpy_c +-END(__wcpncpy_vx) +-#endif /* HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc) */ ++ jg WCPNCPY_C ++END(WCPNCPY_Z13) ++ ++# if ! HAVE_WCPNCPY_IFUNC ++strong_alias (WCPNCPY_Z13, __wcpncpy) ++weak_alias (__wcpncpy, wcpncpy) ++# endif ++#endif +diff --git a/sysdeps/s390/multiarch/wcpncpy.c b/sysdeps/s390/wcpncpy.c +similarity index 70% +rename from sysdeps/s390/multiarch/wcpncpy.c +rename to sysdeps/s390/wcpncpy.c +index b72265fbe9df65d0..08d097dd2cb6dfd7 100644 +--- a/sysdeps/s390/multiarch/wcpncpy.c ++++ b/sysdeps/s390/wcpncpy.c +@@ -16,13 +16,24 @@ + License along with the GNU C Library; if not, see + . */ + +-#if defined HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc) ++#include ++ ++#if HAVE_WCPNCPY_IFUNC + # include + # include + +-s390_vx_libc_ifunc (__wcpncpy) +-weak_alias (__wcpncpy, wcpncpy) ++# if HAVE_WCPNCPY_C ++extern __typeof (__wcpncpy) WCPNCPY_C attribute_hidden; ++# endif + +-#else +-# include +-#endif /* !(defined HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc)) */ ++# if HAVE_WCPNCPY_Z13 ++extern __typeof (__wcpncpy) WCPNCPY_Z13 attribute_hidden; ++# endif ++ ++s390_libc_ifunc_expr (__wcpncpy, __wcpncpy, ++ (HAVE_WCPNCPY_Z13 && (hwcap & HWCAP_S390_VX)) ++ ? WCPNCPY_Z13 ++ : WCPNCPY_DEFAULT ++ ) ++weak_alias (__wcpncpy, wcpncpy) ++#endif diff --git a/SOURCES/glibc-rh1659438-42.patch b/SOURCES/glibc-rh1659438-42.patch new file mode 100644 index 0000000..49b154b --- /dev/null +++ b/SOURCES/glibc-rh1659438-42.patch @@ -0,0 +1,252 @@ +commit 3389cae427b4032c3a991cb32b5178a85a652d84 +Author: Stefan Liebler +Date: Tue Dec 18 13:57:20 2018 +0100 + + S390: Refactor wcscat ifunc handling. + + The ifunc handling for wcscat is adjusted in order to omit ifunc + if the minimum architecture level already supports newer CPUs by default. + Unfortunately the c ifunc variant can't be omitted at all as it is used + by the z13 ifunc variant as fallback if the pointers are not 4-byte aligned. + + ChangeLog: + + * sysdeps/s390/multiarch/Makefile + (sysdep_routines): Remove wcscat variants. + * sysdeps/s390/Makefile (sysdep_routines): Add wcscat variants. + * sysdeps/s390/multiarch/ifunc-impl-list.c + (__libc_ifunc_impl_list): Refactor ifunc handling for wcscat. + * sysdeps/s390/multiarch/wcscat-c.c: Move to ... + * sysdeps/s390/wcscat-c.c: ... here and adjust ifunc handling. + * sysdeps/s390/multiarch/wcscat-vx.S: Move to ... + * sysdeps/s390/wcscat-vx.S: ... here and adjust ifunc handling. + * sysdeps/s390/multiarch/wcscat.c: Move to ... + * sysdeps/s390/wcscat.c: ... here and adjust ifunc handling. + * sysdeps/s390/ifunc-wcscat.h: New file. + +diff --git a/sysdeps/s390/Makefile b/sysdeps/s390/Makefile +index 640177370382235f..5fd00ad4a8661c4c 100644 +--- a/sysdeps/s390/Makefile ++++ b/sysdeps/s390/Makefile +@@ -65,5 +65,6 @@ sysdep_routines += wcslen wcslen-vx wcslen-c \ + wcscpy wcscpy-vx wcscpy-c \ + wcpcpy wcpcpy-vx wcpcpy-c \ + wcsncpy wcsncpy-vx wcsncpy-c \ +- wcpncpy wcpncpy-vx wcpncpy-c ++ wcpncpy wcpncpy-vx wcpncpy-c \ ++ wcscat wcscat-vx wcscat-c + endif +diff --git a/sysdeps/s390/ifunc-wcscat.h b/sysdeps/s390/ifunc-wcscat.h +new file mode 100644 +index 0000000000000000..fecae21403e4c664 +--- /dev/null ++++ b/sysdeps/s390/ifunc-wcscat.h +@@ -0,0 +1,53 @@ ++/* wcscat variant information on S/390 version. ++ 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 ++ . */ ++ ++#if defined USE_MULTIARCH && IS_IN (libc) \ ++ && ! defined HAVE_S390_MIN_Z13_ZARCH_ASM_SUPPORT ++# define HAVE_WCSCAT_IFUNC 1 ++#else ++# define HAVE_WCSCAT_IFUNC 0 ++#endif ++ ++#ifdef HAVE_S390_VX_ASM_SUPPORT ++# define HAVE_WCSCAT_IFUNC_AND_VX_SUPPORT HAVE_WCSCAT_IFUNC ++#else ++# define HAVE_WCSCAT_IFUNC_AND_VX_SUPPORT 0 ++#endif ++ ++#if defined HAVE_S390_MIN_Z13_ZARCH_ASM_SUPPORT ++# define WCSCAT_DEFAULT WCSCAT_Z13 ++/* The z13 ifunc variant is using the common code variant as fallback! */ ++# define HAVE_WCSCAT_C 1 ++# define HAVE_WCSCAT_Z13 1 ++#else ++# define WCSCAT_DEFAULT WCSCAT_C ++# define HAVE_WCSCAT_C 1 ++# define HAVE_WCSCAT_Z13 HAVE_WCSCAT_IFUNC_AND_VX_SUPPORT ++#endif ++ ++#if HAVE_WCSCAT_C ++# define WCSCAT_C __wcscat_c ++#else ++# define WCSCAT_C NULL ++#endif ++ ++#if HAVE_WCSCAT_Z13 ++# define WCSCAT_Z13 __wcscat_vx ++#else ++# define WCSCAT_Z13 NULL ++#endif +diff --git a/sysdeps/s390/multiarch/Makefile b/sysdeps/s390/multiarch/Makefile +index 158fb495523438b4..617017496c79e2ca 100644 +--- a/sysdeps/s390/multiarch/Makefile ++++ b/sysdeps/s390/multiarch/Makefile +@@ -1,6 +1,5 @@ + ifeq ($(subdir),wcsmbs) +-sysdep_routines += wcscat wcscat-vx wcscat-c \ +- wcsncat wcsncat-vx wcsncat-c \ ++sysdep_routines += wcsncat wcsncat-vx wcsncat-c \ + wcscmp wcscmp-vx wcscmp-c \ + wcsncmp wcsncmp-vx wcsncmp-c \ + wcschr wcschr-vx wcschr-c \ +diff --git a/sysdeps/s390/multiarch/ifunc-impl-list.c b/sysdeps/s390/multiarch/ifunc-impl-list.c +index e60238fcde4dcd4f..b05bd35fd898d0a6 100644 +--- a/sysdeps/s390/multiarch/ifunc-impl-list.c ++++ b/sysdeps/s390/multiarch/ifunc-impl-list.c +@@ -52,6 +52,7 @@ + #include + #include + #include ++#include + + /* Maximum number of IFUNC implementations. */ + #define MAX_IFUNC 3 +@@ -502,6 +503,18 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + ) + #endif /* HAVE_WCPNCPY_IFUNC */ + ++#if HAVE_WCSCAT_IFUNC ++ IFUNC_IMPL (i, name, wcscat, ++# if HAVE_WCSCAT_Z13 ++ IFUNC_IMPL_ADD (array, i, wcscat, ++ dl_hwcap & HWCAP_S390_VX, WCSCAT_Z13) ++# endif ++# if HAVE_WCSCAT_C ++ IFUNC_IMPL_ADD (array, i, wcscat, 1, WCSCAT_C) ++# endif ++ ) ++#endif /* HAVE_WCSCAT_IFUNC */ ++ + #ifdef HAVE_S390_VX_ASM_SUPPORT + + # define IFUNC_VX_IMPL(FUNC) \ +@@ -510,8 +523,6 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + __##FUNC##_vx) \ + IFUNC_IMPL_ADD (array, i, FUNC, 1, __##FUNC##_c)) + +- IFUNC_VX_IMPL (wcscat); +- + IFUNC_VX_IMPL (wcsncat); + + IFUNC_VX_IMPL (wcscmp); +diff --git a/sysdeps/s390/multiarch/wcscat-c.c b/sysdeps/s390/wcscat-c.c +similarity index 86% +rename from sysdeps/s390/multiarch/wcscat-c.c +rename to sysdeps/s390/wcscat-c.c +index 9a31c65a0ba668e5..bc1a50b1a52da259 100644 +--- a/sysdeps/s390/multiarch/wcscat-c.c ++++ b/sysdeps/s390/wcscat-c.c +@@ -16,10 +16,12 @@ + License along with the GNU C Library; if not, see + . */ + +-#if defined HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc) +-# define WCSCAT __wcscat_c ++#include ++ ++#if HAVE_WCSCAT_C ++# if HAVE_WCSCAT_IFUNC || HAVE_WCSCAT_Z13 ++# define WCSCAT WCSCAT_C ++# endif + +-# include +-extern __typeof (__wcscat) __wcscat_c; + # include + #endif +diff --git a/sysdeps/s390/multiarch/wcscat-vx.S b/sysdeps/s390/wcscat-vx.S +similarity index 96% +rename from sysdeps/s390/multiarch/wcscat-vx.S +rename to sysdeps/s390/wcscat-vx.S +index 2164a8da411eadaa..4e40d69e8417d6d1 100644 +--- a/sysdeps/s390/multiarch/wcscat-vx.S ++++ b/sysdeps/s390/wcscat-vx.S +@@ -16,7 +16,8 @@ + License along with the GNU C Library; if not, see + . */ + +-#if defined HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc) ++#include ++#if HAVE_WCSCAT_Z13 + + # include "sysdep.h" + # include "asm-syntax.h" +@@ -37,7 +38,7 @@ + -v17=index of zero + -v18=part of src + */ +-ENTRY(__wcscat_vx) ++ENTRY(WCSCAT_Z13) + .machine "z13" + .machinemode "zarch_nohighgprs" + +@@ -170,6 +171,11 @@ ENTRY(__wcscat_vx) + lgr %r2,%r0 /* Load saved dest-ptr. */ + br %r14 + .Lfallback: +- jg __wcscat_c +-END(__wcscat_vx) +-#endif /* HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc) */ ++ jg WCSCAT_C ++END(WCSCAT_Z13) ++ ++# if ! HAVE_WCSCAT_IFUNC ++strong_alias (WCSCAT_Z13, __wcscat) ++weak_alias (__wcscat, wcscat) ++# endif ++#endif +diff --git a/sysdeps/s390/multiarch/wcscat.c b/sysdeps/s390/wcscat.c +similarity index 70% +rename from sysdeps/s390/multiarch/wcscat.c +rename to sysdeps/s390/wcscat.c +index 33e4f6da3ff8eea7..3741210a177f8029 100644 +--- a/sysdeps/s390/multiarch/wcscat.c ++++ b/sysdeps/s390/wcscat.c +@@ -16,13 +16,24 @@ + License along with the GNU C Library; if not, see + . */ + +-#if defined HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc) ++#include ++ ++#if HAVE_WCSCAT_IFUNC + # include + # include + +-s390_vx_libc_ifunc (__wcscat) +-weak_alias (__wcscat, wcscat) ++# if HAVE_WCSCAT_C ++extern __typeof (__wcscat) WCSCAT_C attribute_hidden; ++# endif + +-#else +-# include +-#endif /* !(defined HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc)) */ ++# if HAVE_WCSCAT_Z13 ++extern __typeof (__wcscat) WCSCAT_Z13 attribute_hidden; ++# endif ++ ++s390_libc_ifunc_expr (__wcscat, __wcscat, ++ (HAVE_WCSCAT_Z13 && (hwcap & HWCAP_S390_VX)) ++ ? WCSCAT_Z13 ++ : WCSCAT_DEFAULT ++ ) ++weak_alias (__wcscat, wcscat) ++#endif diff --git a/SOURCES/glibc-rh1659438-43.patch b/SOURCES/glibc-rh1659438-43.patch new file mode 100644 index 0000000..df2053a --- /dev/null +++ b/SOURCES/glibc-rh1659438-43.patch @@ -0,0 +1,249 @@ +commit 814a76e1bcc59e6c4899279ede887bf9fecf5a40 +Author: Stefan Liebler +Date: Tue Dec 18 13:57:20 2018 +0100 + + S390: Refactor wcsncat ifunc handling. + + The ifunc handling for wcsncat is adjusted in order to omit ifunc + if the minimum architecture level already supports newer CPUs by default. + Unfortunately the c ifunc variant can't be omitted at all as it is used + by the z13 ifunc variant as fallback if the pointers are not 4-byte aligned. + + ChangeLog: + + * sysdeps/s390/multiarch/Makefile + (sysdep_routines): Remove wcsncat variants. + * sysdeps/s390/Makefile (sysdep_routines): Add wcsncat variants. + * sysdeps/s390/multiarch/ifunc-impl-list.c + (__libc_ifunc_impl_list): Refactor ifunc handling for wcsncat. + * sysdeps/s390/multiarch/wcsncat-c.c: Move to ... + * sysdeps/s390/wcsncat-c.c: ... here and adjust ifunc handling. + * sysdeps/s390/multiarch/wcsncat-vx.S: Move to ... + * sysdeps/s390/wcsncat-vx.S: ... here and adjust ifunc handling. + * sysdeps/s390/multiarch/wcsncat.c: Move to ... + * sysdeps/s390/wcsncat.c: ... here and adjust ifunc handling. + * sysdeps/s390/ifunc-wcsncat.h: New file. + +diff --git a/sysdeps/s390/Makefile b/sysdeps/s390/Makefile +index 5fd00ad4a8661c4c..cafabe62165f0213 100644 +--- a/sysdeps/s390/Makefile ++++ b/sysdeps/s390/Makefile +@@ -66,5 +66,6 @@ sysdep_routines += wcslen wcslen-vx wcslen-c \ + wcpcpy wcpcpy-vx wcpcpy-c \ + wcsncpy wcsncpy-vx wcsncpy-c \ + wcpncpy wcpncpy-vx wcpncpy-c \ +- wcscat wcscat-vx wcscat-c ++ wcscat wcscat-vx wcscat-c \ ++ wcsncat wcsncat-vx wcsncat-c + endif +diff --git a/sysdeps/s390/ifunc-wcsncat.h b/sysdeps/s390/ifunc-wcsncat.h +new file mode 100644 +index 0000000000000000..99495e0e640611ca +--- /dev/null ++++ b/sysdeps/s390/ifunc-wcsncat.h +@@ -0,0 +1,53 @@ ++/* wcsncat variant information on S/390 version. ++ 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 ++ . */ ++ ++#if defined USE_MULTIARCH && IS_IN (libc) \ ++ && ! defined HAVE_S390_MIN_Z13_ZARCH_ASM_SUPPORT ++# define HAVE_WCSNCAT_IFUNC 1 ++#else ++# define HAVE_WCSNCAT_IFUNC 0 ++#endif ++ ++#ifdef HAVE_S390_VX_ASM_SUPPORT ++# define HAVE_WCSNCAT_IFUNC_AND_VX_SUPPORT HAVE_WCSNCAT_IFUNC ++#else ++# define HAVE_WCSNCAT_IFUNC_AND_VX_SUPPORT 0 ++#endif ++ ++#if defined HAVE_S390_MIN_Z13_ZARCH_ASM_SUPPORT ++# define WCSNCAT_DEFAULT WCSNCAT_Z13 ++/* The z13 ifunc variant is using the common code variant as fallback! */ ++# define HAVE_WCSNCAT_C 1 ++# define HAVE_WCSNCAT_Z13 1 ++#else ++# define WCSNCAT_DEFAULT WCSNCAT_C ++# define HAVE_WCSNCAT_C 1 ++# define HAVE_WCSNCAT_Z13 HAVE_WCSNCAT_IFUNC_AND_VX_SUPPORT ++#endif ++ ++#if HAVE_WCSNCAT_C ++# define WCSNCAT_C __wcsncat_c ++#else ++# define WCSNCAT_C NULL ++#endif ++ ++#if HAVE_WCSNCAT_Z13 ++# define WCSNCAT_Z13 __wcsncat_vx ++#else ++# define WCSNCAT_Z13 NULL ++#endif +diff --git a/sysdeps/s390/multiarch/Makefile b/sysdeps/s390/multiarch/Makefile +index 617017496c79e2ca..6cb75950c2c453f6 100644 +--- a/sysdeps/s390/multiarch/Makefile ++++ b/sysdeps/s390/multiarch/Makefile +@@ -1,6 +1,5 @@ + ifeq ($(subdir),wcsmbs) +-sysdep_routines += wcsncat wcsncat-vx wcsncat-c \ +- wcscmp wcscmp-vx wcscmp-c \ ++sysdep_routines += wcscmp wcscmp-vx wcscmp-c \ + wcsncmp wcsncmp-vx wcsncmp-c \ + wcschr wcschr-vx wcschr-c \ + wcschrnul wcschrnul-vx wcschrnul-c \ +diff --git a/sysdeps/s390/multiarch/ifunc-impl-list.c b/sysdeps/s390/multiarch/ifunc-impl-list.c +index b05bd35fd898d0a6..7b7b1e7497ec1a4f 100644 +--- a/sysdeps/s390/multiarch/ifunc-impl-list.c ++++ b/sysdeps/s390/multiarch/ifunc-impl-list.c +@@ -53,6 +53,7 @@ + #include + #include + #include ++#include + + /* Maximum number of IFUNC implementations. */ + #define MAX_IFUNC 3 +@@ -515,6 +516,18 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + ) + #endif /* HAVE_WCSCAT_IFUNC */ + ++#if HAVE_WCSNCAT_IFUNC ++ IFUNC_IMPL (i, name, wcsncat, ++# if HAVE_WCSNCAT_Z13 ++ IFUNC_IMPL_ADD (array, i, wcsncat, ++ dl_hwcap & HWCAP_S390_VX, WCSNCAT_Z13) ++# endif ++# if HAVE_WCSNCAT_C ++ IFUNC_IMPL_ADD (array, i, wcsncat, 1, WCSNCAT_C) ++# endif ++ ) ++#endif /* HAVE_WCSNCAT_IFUNC */ ++ + #ifdef HAVE_S390_VX_ASM_SUPPORT + + # define IFUNC_VX_IMPL(FUNC) \ +@@ -523,8 +536,6 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + __##FUNC##_vx) \ + IFUNC_IMPL_ADD (array, i, FUNC, 1, __##FUNC##_c)) + +- IFUNC_VX_IMPL (wcsncat); +- + IFUNC_VX_IMPL (wcscmp); + + IFUNC_VX_IMPL (wcsncmp); +diff --git a/sysdeps/s390/multiarch/wcsncat-c.c b/sysdeps/s390/wcsncat-c.c +similarity index 85% +rename from sysdeps/s390/multiarch/wcsncat-c.c +rename to sysdeps/s390/wcsncat-c.c +index 2cf1a76385932c64..5782d5cb28c9e7f6 100644 +--- a/sysdeps/s390/multiarch/wcsncat-c.c ++++ b/sysdeps/s390/wcsncat-c.c +@@ -16,10 +16,12 @@ + License along with the GNU C Library; if not, see + . */ + +-#if defined HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc) +-# define WCSNCAT __wcsncat_c ++#include ++ ++#if HAVE_WCSNCAT_C ++# if HAVE_WCSNCAT_IFUNC || HAVE_WCSNCAT_Z13 ++# define WCSNCAT WCSNCAT_C ++# endif + +-# include +-extern __typeof (wcsncat) __wcsncat_c; + # include + #endif +diff --git a/sysdeps/s390/multiarch/wcsncat-vx.S b/sysdeps/s390/wcsncat-vx.S +similarity index 97% +rename from sysdeps/s390/multiarch/wcsncat-vx.S +rename to sysdeps/s390/wcsncat-vx.S +index 1d3935690d9f91a3..7c89d3d856faee24 100644 +--- a/sysdeps/s390/multiarch/wcsncat-vx.S ++++ b/sysdeps/s390/wcsncat-vx.S +@@ -16,7 +16,8 @@ + License along with the GNU C Library; if not, see + . */ + +-#if defined HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc) ++#include ++#if HAVE_WCSNCAT_Z13 + + # include "sysdep.h" + # include "asm-syntax.h" +@@ -40,7 +41,7 @@ + -v18=part of src + -v31=register save area for r6, r7 + */ +-ENTRY(__wcsncat_vx) ++ENTRY(WCSNCAT_Z13) + .machine "z13" + .machinemode "zarch_nohighgprs" + +@@ -260,6 +261,10 @@ ENTRY(__wcsncat_vx) + j .Lcpy_lt64 + + .Lfallback: +- jg __wcsncat_c +-END(__wcsncat_vx) +-#endif /* HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc) */ ++ jg WCSNCAT_C ++END(WCSNCAT_Z13) ++ ++# if ! HAVE_WCSNCAT_IFUNC ++strong_alias (WCSNCAT_Z13, wcsncat) ++# endif ++#endif +diff --git a/sysdeps/s390/multiarch/wcsncat.c b/sysdeps/s390/wcsncat.c +similarity index 69% +rename from sysdeps/s390/multiarch/wcsncat.c +rename to sysdeps/s390/wcsncat.c +index c49b8ff78671cb99..722429fd5b5b4d9d 100644 +--- a/sysdeps/s390/multiarch/wcsncat.c ++++ b/sysdeps/s390/wcsncat.c +@@ -16,12 +16,23 @@ + License along with the GNU C Library; if not, see + . */ + +-#if defined HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc) ++#include ++ ++#if HAVE_WCSNCAT_IFUNC + # include + # include + +-s390_vx_libc_ifunc2 (__wcsncat, wcsncat) ++# if HAVE_WCSNCAT_C ++extern __typeof (wcsncat) WCSNCAT_C attribute_hidden; ++# endif ++ ++# if HAVE_WCSNCAT_Z13 ++extern __typeof (wcsncat) WCSNCAT_Z13 attribute_hidden; ++# endif + +-#else +-# include +-#endif /* !(defined HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc)) */ ++s390_libc_ifunc_expr (wcsncat, wcsncat, ++ (HAVE_WCSNCAT_Z13 && (hwcap & HWCAP_S390_VX)) ++ ? WCSNCAT_Z13 ++ : WCSNCAT_DEFAULT ++ ) ++#endif diff --git a/SOURCES/glibc-rh1659438-44.patch b/SOURCES/glibc-rh1659438-44.patch new file mode 100644 index 0000000..c49fa9a --- /dev/null +++ b/SOURCES/glibc-rh1659438-44.patch @@ -0,0 +1,269 @@ +commit 3459e23dd4ae4aa8999df7111d833a0bb9add7cd +Author: Stefan Liebler +Date: Tue Dec 18 13:57:21 2018 +0100 + + S390: Refactor wcscmp ifunc handling. + + The ifunc handling for wcscmp is adjusted in order to omit ifunc + variants if those will never be used as the minimum architecture level + already supports newer CPUs by default. + Glibc internal calls will then also use the "newer" ifunc variant. + + ChangeLog: + + * sysdeps/s390/multiarch/Makefile + (sysdep_routines): Remove wcscmp variants. + * sysdeps/s390/Makefile (sysdep_routines): Add wcscmp variants. + * sysdeps/s390/multiarch/ifunc-impl-list.c + (__libc_ifunc_impl_list): Refactor ifunc handling for wcscmp. + * sysdeps/s390/multiarch/wcscmp-c.c: Move to ... + * sysdeps/s390/wcscmp-c.c: ... here and adjust ifunc handling. + * sysdeps/s390/multiarch/wcscmp-vx.S: Move to ... + * sysdeps/s390/wcscmp-vx.S: ... here and adjust ifunc handling. + * sysdeps/s390/multiarch/wcscmp.c: Move to ... + * sysdeps/s390/wcscmp.c: ... here and adjust ifunc handling. + * sysdeps/s390/ifunc-wcscmp.h: New file. + +diff --git a/sysdeps/s390/Makefile b/sysdeps/s390/Makefile +index cafabe62165f0213..fb104af231c48d3a 100644 +--- a/sysdeps/s390/Makefile ++++ b/sysdeps/s390/Makefile +@@ -67,5 +67,6 @@ sysdep_routines += wcslen wcslen-vx wcslen-c \ + wcsncpy wcsncpy-vx wcsncpy-c \ + wcpncpy wcpncpy-vx wcpncpy-c \ + wcscat wcscat-vx wcscat-c \ +- wcsncat wcsncat-vx wcsncat-c ++ wcsncat wcsncat-vx wcsncat-c \ ++ wcscmp wcscmp-vx wcscmp-c + endif +diff --git a/sysdeps/s390/ifunc-wcscmp.h b/sysdeps/s390/ifunc-wcscmp.h +new file mode 100644 +index 0000000000000000..99fe0213021458ae +--- /dev/null ++++ b/sysdeps/s390/ifunc-wcscmp.h +@@ -0,0 +1,52 @@ ++/* wcscmp variant information on S/390 version. ++ 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 ++ . */ ++ ++#if defined USE_MULTIARCH && IS_IN (libc) \ ++ && ! defined HAVE_S390_MIN_Z13_ZARCH_ASM_SUPPORT ++# define HAVE_WCSCMP_IFUNC 1 ++#else ++# define HAVE_WCSCMP_IFUNC 0 ++#endif ++ ++#ifdef HAVE_S390_VX_ASM_SUPPORT ++# define HAVE_WCSCMP_IFUNC_AND_VX_SUPPORT HAVE_WCSCMP_IFUNC ++#else ++# define HAVE_WCSCMP_IFUNC_AND_VX_SUPPORT 0 ++#endif ++ ++#if defined HAVE_S390_MIN_Z13_ZARCH_ASM_SUPPORT ++# define WCSCMP_DEFAULT WCSCMP_Z13 ++# define HAVE_WCSCMP_C 0 ++# define HAVE_WCSCMP_Z13 1 ++#else ++# define WCSCMP_DEFAULT WCSCMP_C ++# define HAVE_WCSCMP_C 1 ++# define HAVE_WCSCMP_Z13 HAVE_WCSCMP_IFUNC_AND_VX_SUPPORT ++#endif ++ ++#if HAVE_WCSCMP_C ++# define WCSCMP_C __wcscmp_c ++#else ++# define WCSCMP_C NULL ++#endif ++ ++#if HAVE_WCSCMP_Z13 ++# define WCSCMP_Z13 __wcscmp_vx ++#else ++# define WCSCMP_Z13 NULL ++#endif +diff --git a/sysdeps/s390/multiarch/Makefile b/sysdeps/s390/multiarch/Makefile +index 6cb75950c2c453f6..70162d0eaa6a0dee 100644 +--- a/sysdeps/s390/multiarch/Makefile ++++ b/sysdeps/s390/multiarch/Makefile +@@ -1,6 +1,5 @@ + ifeq ($(subdir),wcsmbs) +-sysdep_routines += wcscmp wcscmp-vx wcscmp-c \ +- wcsncmp wcsncmp-vx wcsncmp-c \ ++sysdep_routines += wcsncmp wcsncmp-vx wcsncmp-c \ + wcschr wcschr-vx wcschr-c \ + wcschrnul wcschrnul-vx wcschrnul-c \ + wcsrchr wcsrchr-vx wcsrchr-c \ +diff --git a/sysdeps/s390/multiarch/ifunc-impl-list.c b/sysdeps/s390/multiarch/ifunc-impl-list.c +index 7b7b1e7497ec1a4f..f461063c80b364fb 100644 +--- a/sysdeps/s390/multiarch/ifunc-impl-list.c ++++ b/sysdeps/s390/multiarch/ifunc-impl-list.c +@@ -54,6 +54,7 @@ + #include + #include + #include ++#include + + /* Maximum number of IFUNC implementations. */ + #define MAX_IFUNC 3 +@@ -528,6 +529,18 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + ) + #endif /* HAVE_WCSNCAT_IFUNC */ + ++#if HAVE_WCSCMP_IFUNC ++ IFUNC_IMPL (i, name, wcscmp, ++# if HAVE_WCSCMP_Z13 ++ IFUNC_IMPL_ADD (array, i, wcscmp, ++ dl_hwcap & HWCAP_S390_VX, WCSCMP_Z13) ++# endif ++# if HAVE_WCSCMP_C ++ IFUNC_IMPL_ADD (array, i, wcscmp, 1, WCSCMP_C) ++# endif ++ ) ++#endif /* HAVE_WCSCMP_IFUNC */ ++ + #ifdef HAVE_S390_VX_ASM_SUPPORT + + # define IFUNC_VX_IMPL(FUNC) \ +@@ -536,8 +549,6 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + __##FUNC##_vx) \ + IFUNC_IMPL_ADD (array, i, FUNC, 1, __##FUNC##_c)) + +- IFUNC_VX_IMPL (wcscmp); +- + IFUNC_VX_IMPL (wcsncmp); + + IFUNC_VX_IMPL (wcschr); +diff --git a/sysdeps/s390/multiarch/wcscmp-c.c b/sysdeps/s390/wcscmp-c.c +similarity index 72% +rename from sysdeps/s390/multiarch/wcscmp-c.c +rename to sysdeps/s390/wcscmp-c.c +index ce0817ae97deab77..643ba7a682469e73 100644 +--- a/sysdeps/s390/multiarch/wcscmp-c.c ++++ b/sysdeps/s390/wcscmp-c.c +@@ -16,17 +16,19 @@ + License along with the GNU C Library; if not, see + . */ + +-#if defined HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc) +-# define WCSCMP __wcscmp_c ++#include + +-# include +-extern __typeof (wcscmp) __wcscmp_c; +-# undef weak_alias +-# define weak_alias(name, alias) +-# ifdef SHARED +-# undef libc_hidden_def +-# define libc_hidden_def(name) \ ++#if HAVE_WCSCMP_C ++# if HAVE_WCSCMP_IFUNC ++# define WCSCMP WCSCMP_C ++# undef weak_alias ++# define weak_alias(name, alias) ++# if defined SHARED && IS_IN (libc) ++# undef libc_hidden_def ++# define libc_hidden_def(name) \ + __hidden_ver1 (__wcscmp_c, __GI___wcscmp, __wcscmp_c); +-# endif /* SHARED */ ++# endif ++# endif ++ + # include +-#endif /* HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc) */ ++#endif +diff --git a/sysdeps/s390/multiarch/wcscmp-vx.S b/sysdeps/s390/wcscmp-vx.S +similarity index 92% +rename from sysdeps/s390/multiarch/wcscmp-vx.S +rename to sysdeps/s390/wcscmp-vx.S +index 14267dbfc7d9b936..a2789d8a693802cc 100644 +--- a/sysdeps/s390/multiarch/wcscmp-vx.S ++++ b/sysdeps/s390/wcscmp-vx.S +@@ -16,7 +16,8 @@ + License along with the GNU C Library; if not, see + . */ + +-#if defined HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc) ++#include ++#if HAVE_WCSCMP_Z13 + + # include "sysdep.h" + # include "asm-syntax.h" +@@ -36,7 +37,7 @@ + -v17=part of s2 + -v18=index of unequal + */ +-ENTRY(__wcscmp_vx) ++ENTRY(WCSCMP_Z13) + .machine "z13" + .machinemode "zarch_nohighgprs" + +@@ -127,5 +128,14 @@ ENTRY(__wcscmp_vx) + .Lend_equal: + lghi %r2,0 + br %r14 +-END(__wcscmp_vx) +-#endif /* HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc) */ ++END(WCSCMP_Z13) ++ ++# if ! HAVE_WCSCMP_IFUNC ++strong_alias (WCSCMP_Z13, __wcscmp) ++weak_alias (__wcscmp, wcscmp) ++# endif ++ ++# if ! HAVE_WCSCMP_C && defined SHARED && IS_IN (libc) ++strong_alias (WCSCMP_Z13, __GI___wcscmp) ++# endif ++#endif +diff --git a/sysdeps/s390/multiarch/wcscmp.c b/sysdeps/s390/wcscmp.c +similarity index 70% +rename from sysdeps/s390/multiarch/wcscmp.c +rename to sysdeps/s390/wcscmp.c +index 5ee0fd4d881db9cb..769c73506e40c3a0 100644 +--- a/sysdeps/s390/multiarch/wcscmp.c ++++ b/sysdeps/s390/wcscmp.c +@@ -16,15 +16,26 @@ + License along with the GNU C Library; if not, see + . */ + +-#if defined HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc) ++#include ++ ++#if HAVE_WCSCMP_IFUNC + # define __wcscmp __redirect___wcscmp + # include + # undef __wcscmp + # include + +-s390_vx_libc_ifunc_redirected (__redirect___wcscmp, __wcscmp) +-weak_alias (__wcscmp, wcscmp) ++# if HAVE_WCSCMP_C ++extern __typeof (__redirect___wcscmp) WCSCMP_C attribute_hidden; ++# endif + +-#else +-# include +-#endif /* !(defined HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc)) */ ++# if HAVE_WCSCMP_Z13 ++extern __typeof (__redirect___wcscmp) WCSCMP_Z13 attribute_hidden; ++# endif ++ ++s390_libc_ifunc_expr (__redirect___wcscmp, __wcscmp, ++ (HAVE_WCSCMP_Z13 && (hwcap & HWCAP_S390_VX)) ++ ? WCSCMP_Z13 ++ : WCSCMP_DEFAULT ++ ) ++weak_alias (__wcscmp, wcscmp) ++#endif diff --git a/SOURCES/glibc-rh1659438-45.patch b/SOURCES/glibc-rh1659438-45.patch new file mode 100644 index 0000000..a4233ac --- /dev/null +++ b/SOURCES/glibc-rh1659438-45.patch @@ -0,0 +1,245 @@ +commit e9873e1d47c870d707117ada91c9be21e3bf1537 +Author: Stefan Liebler +Date: Tue Dec 18 13:57:21 2018 +0100 + + S390: Refactor wcsncmp ifunc handling. + + The ifunc handling for wcsncmp is adjusted in order to omit ifunc + variants if those will never be used as the minimum architecture level + already supports newer CPUs by default. + + ChangeLog: + + * sysdeps/s390/multiarch/Makefile + (sysdep_routines): Remove wcsncmp variants. + * sysdeps/s390/Makefile (sysdep_routines): Add wcsncmp variants. + * sysdeps/s390/multiarch/ifunc-impl-list.c + (__libc_ifunc_impl_list): Refactor ifunc handling for wcsncmp. + * sysdeps/s390/multiarch/wcsncmp-c.c: Move to ... + * sysdeps/s390/wcsncmp-c.c: ... here and adjust ifunc handling. + * sysdeps/s390/multiarch/wcsncmp-vx.S: Move to ... + * sysdeps/s390/wcsncmp-vx.S: ... here and adjust ifunc handling. + * sysdeps/s390/multiarch/wcsncmp.c: Move to ... + * sysdeps/s390/wcsncmp.c: ... here and adjust ifunc handling. + * sysdeps/s390/ifunc-wcsncmp.h: New file. + +diff --git a/sysdeps/s390/Makefile b/sysdeps/s390/Makefile +index fb104af231c48d3a..9146b32a939fd5bd 100644 +--- a/sysdeps/s390/Makefile ++++ b/sysdeps/s390/Makefile +@@ -68,5 +68,6 @@ sysdep_routines += wcslen wcslen-vx wcslen-c \ + wcpncpy wcpncpy-vx wcpncpy-c \ + wcscat wcscat-vx wcscat-c \ + wcsncat wcsncat-vx wcsncat-c \ +- wcscmp wcscmp-vx wcscmp-c ++ wcscmp wcscmp-vx wcscmp-c \ ++ wcsncmp wcsncmp-vx wcsncmp-c + endif +diff --git a/sysdeps/s390/ifunc-wcsncmp.h b/sysdeps/s390/ifunc-wcsncmp.h +new file mode 100644 +index 0000000000000000..3a22bc9c126107ad +--- /dev/null ++++ b/sysdeps/s390/ifunc-wcsncmp.h +@@ -0,0 +1,52 @@ ++/* wcsncmp variant information on S/390 version. ++ 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 ++ . */ ++ ++#if defined USE_MULTIARCH && IS_IN (libc) \ ++ && ! defined HAVE_S390_MIN_Z13_ZARCH_ASM_SUPPORT ++# define HAVE_WCSNCMP_IFUNC 1 ++#else ++# define HAVE_WCSNCMP_IFUNC 0 ++#endif ++ ++#ifdef HAVE_S390_VX_ASM_SUPPORT ++# define HAVE_WCSNCMP_IFUNC_AND_VX_SUPPORT HAVE_WCSNCMP_IFUNC ++#else ++# define HAVE_WCSNCMP_IFUNC_AND_VX_SUPPORT 0 ++#endif ++ ++#if defined HAVE_S390_MIN_Z13_ZARCH_ASM_SUPPORT ++# define WCSNCMP_DEFAULT WCSNCMP_Z13 ++# define HAVE_WCSNCMP_C 0 ++# define HAVE_WCSNCMP_Z13 1 ++#else ++# define WCSNCMP_DEFAULT WCSNCMP_C ++# define HAVE_WCSNCMP_C 1 ++# define HAVE_WCSNCMP_Z13 HAVE_WCSNCMP_IFUNC_AND_VX_SUPPORT ++#endif ++ ++#if HAVE_WCSNCMP_C ++# define WCSNCMP_C __wcsncmp_c ++#else ++# define WCSNCMP_C NULL ++#endif ++ ++#if HAVE_WCSNCMP_Z13 ++# define WCSNCMP_Z13 __wcsncmp_vx ++#else ++# define WCSNCMP_Z13 NULL ++#endif +diff --git a/sysdeps/s390/multiarch/Makefile b/sysdeps/s390/multiarch/Makefile +index 70162d0eaa6a0dee..d1740fa8e4f5faa8 100644 +--- a/sysdeps/s390/multiarch/Makefile ++++ b/sysdeps/s390/multiarch/Makefile +@@ -1,6 +1,5 @@ + ifeq ($(subdir),wcsmbs) +-sysdep_routines += wcsncmp wcsncmp-vx wcsncmp-c \ +- wcschr wcschr-vx wcschr-c \ ++sysdep_routines += wcschr wcschr-vx wcschr-c \ + wcschrnul wcschrnul-vx wcschrnul-c \ + wcsrchr wcsrchr-vx wcsrchr-c \ + wcsspn wcsspn-vx wcsspn-c \ +diff --git a/sysdeps/s390/multiarch/ifunc-impl-list.c b/sysdeps/s390/multiarch/ifunc-impl-list.c +index f461063c80b364fb..8c9e788ae5962e2a 100644 +--- a/sysdeps/s390/multiarch/ifunc-impl-list.c ++++ b/sysdeps/s390/multiarch/ifunc-impl-list.c +@@ -55,6 +55,7 @@ + #include + #include + #include ++#include + + /* Maximum number of IFUNC implementations. */ + #define MAX_IFUNC 3 +@@ -541,6 +542,18 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + ) + #endif /* HAVE_WCSCMP_IFUNC */ + ++#if HAVE_WCSNCMP_IFUNC ++ IFUNC_IMPL (i, name, wcsncmp, ++# if HAVE_WCSNCMP_Z13 ++ IFUNC_IMPL_ADD (array, i, wcsncmp, ++ dl_hwcap & HWCAP_S390_VX, WCSNCMP_Z13) ++# endif ++# if HAVE_WCSNCMP_C ++ IFUNC_IMPL_ADD (array, i, wcsncmp, 1, WCSNCMP_C) ++# endif ++ ) ++#endif /* HAVE_WCSNCMP_IFUNC */ ++ + #ifdef HAVE_S390_VX_ASM_SUPPORT + + # define IFUNC_VX_IMPL(FUNC) \ +@@ -549,8 +562,6 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + __##FUNC##_vx) \ + IFUNC_IMPL_ADD (array, i, FUNC, 1, __##FUNC##_c)) + +- IFUNC_VX_IMPL (wcsncmp); +- + IFUNC_VX_IMPL (wcschr); + + IFUNC_VX_IMPL (wcschrnul); +diff --git a/sysdeps/s390/multiarch/wcsncmp-c.c b/sysdeps/s390/wcsncmp-c.c +similarity index 85% +rename from sysdeps/s390/multiarch/wcsncmp-c.c +rename to sysdeps/s390/wcsncmp-c.c +index 92ab5e8b50bd93d0..a9ccb8de8276e97c 100644 +--- a/sysdeps/s390/multiarch/wcsncmp-c.c ++++ b/sysdeps/s390/wcsncmp-c.c +@@ -16,10 +16,12 @@ + License along with the GNU C Library; if not, see + . */ + +-#if defined HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc) +-# define WCSNCMP __wcsncmp_c ++#include ++ ++#if HAVE_WCSNCMP_C ++# if HAVE_WCSNCMP_IFUNC ++# define WCSNCMP WCSNCMP_C ++# endif + +-# include +-extern __typeof (wcsncmp) __wcsncmp_c; + # include + #endif +diff --git a/sysdeps/s390/multiarch/wcsncmp-vx.S b/sysdeps/s390/wcsncmp-vx.S +similarity index 97% +rename from sysdeps/s390/multiarch/wcsncmp-vx.S +rename to sysdeps/s390/wcsncmp-vx.S +index 34c203bc90b2b012..9bdd21acefc2d44d 100644 +--- a/sysdeps/s390/multiarch/wcsncmp-vx.S ++++ b/sysdeps/s390/wcsncmp-vx.S +@@ -16,7 +16,8 @@ + License along with the GNU C Library; if not, see + . */ + +-#if defined HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc) ++#include ++#if HAVE_WCSNCMP_Z13 + + # include "sysdep.h" + # include "asm-syntax.h" +@@ -37,7 +38,7 @@ + -v17=part of s2 + -v18=index of unequal + */ +-ENTRY(__wcsncmp_vx) ++ENTRY(WCSNCMP_Z13) + .machine "z13" + .machinemode "zarch_nohighgprs" + +@@ -173,5 +174,9 @@ ENTRY(__wcsncmp_vx) + lghi %r1,-1 + locgrl %r2,%r1 + br %r14 +-END(__wcsncmp_vx) +-#endif /* HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc) */ ++END(WCSNCMP_Z13) ++ ++# if ! HAVE_WCSNCMP_IFUNC ++strong_alias (WCSNCMP_Z13, wcsncmp) ++# endif ++#endif +diff --git a/sysdeps/s390/multiarch/wcsncmp.c b/sysdeps/s390/wcsncmp.c +similarity index 69% +rename from sysdeps/s390/multiarch/wcsncmp.c +rename to sysdeps/s390/wcsncmp.c +index ee5f08c1e4106495..101db445918b0f7d 100644 +--- a/sysdeps/s390/multiarch/wcsncmp.c ++++ b/sysdeps/s390/wcsncmp.c +@@ -16,12 +16,23 @@ + License along with the GNU C Library; if not, see + . */ + +-#if defined HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc) ++#include ++ ++#if HAVE_WCSNCMP_IFUNC + # include + # include + +-s390_vx_libc_ifunc2 (__wcsncmp, wcsncmp) ++# if HAVE_WCSNCMP_C ++extern __typeof (wcsncmp) WCSNCMP_C attribute_hidden; ++# endif ++ ++# if HAVE_WCSNCMP_Z13 ++extern __typeof (wcsncmp) WCSNCMP_Z13 attribute_hidden; ++# endif + +-#else +-# include +-#endif /* !(defined HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc)) */ ++s390_libc_ifunc_expr (wcsncmp, wcsncmp, ++ (HAVE_WCSNCMP_Z13 && (hwcap & HWCAP_S390_VX)) ++ ? WCSNCMP_Z13 ++ : WCSNCMP_DEFAULT ++ ) ++#endif diff --git a/SOURCES/glibc-rh1659438-46.patch b/SOURCES/glibc-rh1659438-46.patch new file mode 100644 index 0000000..a4a0eb0 --- /dev/null +++ b/SOURCES/glibc-rh1659438-46.patch @@ -0,0 +1,292 @@ +commit cf3ccc31a3d76a9b4db410d3087055c3aff2b71b +Author: Stefan Liebler +Date: Tue Dec 18 13:57:22 2018 +0100 + + S390: Refactor wcschr ifunc handling. + + The ifunc handling for wcschr is adjusted in order to omit ifunc + if the minimum architecture level already supports newer CPUs by default. + Unfortunately the c ifunc variant can't be omitted at all as it is used + by the z13 ifunc variant as fallback if the pointers are not 4-byte aligned. + Glibc internal calls will use the "newer" ifunc variant. + + ChangeLog: + + * sysdeps/s390/multiarch/Makefile + (sysdep_routines): Remove wcschr variants. + * sysdeps/s390/Makefile (sysdep_routines): Add wcschr variants. + * sysdeps/s390/multiarch/ifunc-impl-list.c + (__libc_ifunc_impl_list): Refactor ifunc handling for wcschr. + * sysdeps/s390/multiarch/wcschr-c.c: Move to ... + * sysdeps/s390/wcschr-c.c: ... here and adjust ifunc handling. + * sysdeps/s390/multiarch/wcschr-vx.S: Move to ... + * sysdeps/s390/wcschr-vx.S: ... here and adjust ifunc handling. + * sysdeps/s390/multiarch/wcschr.c: Move to ... + * sysdeps/s390/wcschr.c: ... here and adjust ifunc handling. + * sysdeps/s390/ifunc-wcschr.h: New file. + +diff --git a/sysdeps/s390/Makefile b/sysdeps/s390/Makefile +index 9146b32a939fd5bd..91ee84a54b713e4a 100644 +--- a/sysdeps/s390/Makefile ++++ b/sysdeps/s390/Makefile +@@ -69,5 +69,6 @@ sysdep_routines += wcslen wcslen-vx wcslen-c \ + wcscat wcscat-vx wcscat-c \ + wcsncat wcsncat-vx wcsncat-c \ + wcscmp wcscmp-vx wcscmp-c \ +- wcsncmp wcsncmp-vx wcsncmp-c ++ wcsncmp wcsncmp-vx wcsncmp-c \ ++ wcschr wcschr-vx wcschr-c + endif +diff --git a/sysdeps/s390/ifunc-wcschr.h b/sysdeps/s390/ifunc-wcschr.h +new file mode 100644 +index 0000000000000000..2fe9110f7c9564d2 +--- /dev/null ++++ b/sysdeps/s390/ifunc-wcschr.h +@@ -0,0 +1,53 @@ ++/* wcschr variant information on S/390 version. ++ 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 ++ . */ ++ ++#if defined USE_MULTIARCH && IS_IN (libc) \ ++ && ! defined HAVE_S390_MIN_Z13_ZARCH_ASM_SUPPORT ++# define HAVE_WCSCHR_IFUNC 1 ++#else ++# define HAVE_WCSCHR_IFUNC 0 ++#endif ++ ++#ifdef HAVE_S390_VX_ASM_SUPPORT ++# define HAVE_WCSCHR_IFUNC_AND_VX_SUPPORT HAVE_WCSCHR_IFUNC ++#else ++# define HAVE_WCSCHR_IFUNC_AND_VX_SUPPORT 0 ++#endif ++ ++#if defined HAVE_S390_MIN_Z13_ZARCH_ASM_SUPPORT ++# define WCSCHR_DEFAULT WCSCHR_Z13 ++/* The z13 ifunc variant is using the common code variant as fallback! */ ++# define HAVE_WCSCHR_C 1 ++# define HAVE_WCSCHR_Z13 1 ++#else ++# define WCSCHR_DEFAULT WCSCHR_C ++# define HAVE_WCSCHR_C 1 ++# define HAVE_WCSCHR_Z13 HAVE_WCSCHR_IFUNC_AND_VX_SUPPORT ++#endif ++ ++#if HAVE_WCSCHR_C ++# define WCSCHR_C __wcschr_c ++#else ++# define WCSCHR_C NULL ++#endif ++ ++#if HAVE_WCSCHR_Z13 ++# define WCSCHR_Z13 __wcschr_vx ++#else ++# define WCSCHR_Z13 NULL ++#endif +diff --git a/sysdeps/s390/multiarch/Makefile b/sysdeps/s390/multiarch/Makefile +index d1740fa8e4f5faa8..b282613b4705bb14 100644 +--- a/sysdeps/s390/multiarch/Makefile ++++ b/sysdeps/s390/multiarch/Makefile +@@ -1,6 +1,5 @@ + ifeq ($(subdir),wcsmbs) +-sysdep_routines += wcschr wcschr-vx wcschr-c \ +- wcschrnul wcschrnul-vx wcschrnul-c \ ++sysdep_routines += wcschrnul wcschrnul-vx wcschrnul-c \ + wcsrchr wcsrchr-vx wcsrchr-c \ + wcsspn wcsspn-vx wcsspn-c \ + wcspbrk wcspbrk-vx wcspbrk-c \ +diff --git a/sysdeps/s390/multiarch/ifunc-impl-list.c b/sysdeps/s390/multiarch/ifunc-impl-list.c +index 8c9e788ae5962e2a..c69165465dc97111 100644 +--- a/sysdeps/s390/multiarch/ifunc-impl-list.c ++++ b/sysdeps/s390/multiarch/ifunc-impl-list.c +@@ -56,6 +56,7 @@ + #include + #include + #include ++#include + + /* Maximum number of IFUNC implementations. */ + #define MAX_IFUNC 3 +@@ -554,6 +555,18 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + ) + #endif /* HAVE_WCSNCMP_IFUNC */ + ++#if HAVE_WCSCHR_IFUNC ++ IFUNC_IMPL (i, name, wcschr, ++# if HAVE_WCSCHR_Z13 ++ IFUNC_IMPL_ADD (array, i, wcschr, ++ dl_hwcap & HWCAP_S390_VX, WCSCHR_Z13) ++# endif ++# if HAVE_WCSCHR_C ++ IFUNC_IMPL_ADD (array, i, wcschr, 1, WCSCHR_C) ++# endif ++ ) ++#endif /* HAVE_WCSCHR_IFUNC */ ++ + #ifdef HAVE_S390_VX_ASM_SUPPORT + + # define IFUNC_VX_IMPL(FUNC) \ +@@ -562,8 +575,6 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + __##FUNC##_vx) \ + IFUNC_IMPL_ADD (array, i, FUNC, 1, __##FUNC##_c)) + +- IFUNC_VX_IMPL (wcschr); +- + IFUNC_VX_IMPL (wcschrnul); + + IFUNC_VX_IMPL (wcsrchr); +diff --git a/sysdeps/s390/multiarch/wcschr-c.c b/sysdeps/s390/wcschr-c.c +similarity index 61% +rename from sysdeps/s390/multiarch/wcschr-c.c +rename to sysdeps/s390/wcschr-c.c +index 8d6679c7f2f89864..4908492a0a72ed28 100644 +--- a/sysdeps/s390/multiarch/wcschr-c.c ++++ b/sysdeps/s390/wcschr-c.c +@@ -16,22 +16,29 @@ + License along with the GNU C Library; if not, see + . */ + +-#if defined HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc) +-# define WCSCHR __wcschr_c +- +-# include +-extern __typeof (__wcschr) __wcschr_c; +-# undef weak_alias +-# define weak_alias(name, alias) +-# ifdef SHARED +-# undef libc_hidden_def +-# define libc_hidden_def(name) \ +- __hidden_ver1 (__wcschr_c, __GI_wcschr, __wcschr_c); \ +- strong_alias (__wcschr_c, __wcschr_c_1); \ ++#include ++ ++#if HAVE_WCSCHR_C ++# if HAVE_WCSCHR_IFUNC || HAVE_WCSCHR_Z13 ++# define WCSCHR WCSCHR_C ++ ++# undef weak_alias ++# define weak_alias(name, alias) ++ ++# if defined SHARED && IS_IN (libc) ++# undef libc_hidden_weak ++# define libc_hidden_weak(name) ++# undef libc_hidden_def ++# if ! defined HAVE_S390_MIN_Z13_ZARCH_ASM_SUPPORT ++# define libc_hidden_def(name) \ ++ __hidden_ver1 (__wcschr_c, __GI_wcschr, __wcschr_c) __attribute__((weak)); \ ++ strong_alias (__wcschr_c, __wcschr_c_1); \ + __hidden_ver1 (__wcschr_c_1, __GI___wcschr, __wcschr_c_1); +-# undef libc_hidden_weak +-# define libc_hidden_weak(name) +-# endif /* SHARED */ ++# else ++# define libc_hidden_def(name) ++# endif ++# endif ++# endif + + # include +-#endif /* HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc) */ ++#endif +diff --git a/sysdeps/s390/multiarch/wcschr-vx.S b/sysdeps/s390/wcschr-vx.S +similarity index 88% +rename from sysdeps/s390/multiarch/wcschr-vx.S +rename to sysdeps/s390/wcschr-vx.S +index 94e5df7f365aa361..dd24998390c7e2e6 100644 +--- a/sysdeps/s390/multiarch/wcschr-vx.S ++++ b/sysdeps/s390/wcschr-vx.S +@@ -16,7 +16,8 @@ + License along with the GNU C Library; if not, see + . */ + +-#if defined HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc) ++#include ++#if HAVE_WCSCHR_Z13 + + # include "sysdep.h" + # include "asm-syntax.h" +@@ -36,7 +37,7 @@ + -v17=index of unequal + -v18=replicated c + */ +-ENTRY(__wcschr_vx) ++ENTRY(WCSCHR_Z13) + .machine "z13" + .machinemode "zarch_nohighgprs" + +@@ -98,6 +99,17 @@ ENTRY(__wcschr_vx) + lghi %r2,0 /* Return null if character not found. */ + br %r14 + .Lfallback: +- jg __wcschr_c +-END(__wcschr_vx) +-#endif /* HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc) */ ++ jg WCSCHR_C ++END(WCSCHR_Z13) ++ ++# if ! HAVE_WCSCHR_IFUNC ++strong_alias (WCSCHR_Z13, __wcschr) ++weak_alias (__wcschr, wcschr) ++# endif ++ ++# if defined HAVE_S390_MIN_Z13_ZARCH_ASM_SUPPORT \ ++ && defined SHARED && IS_IN (libc) ++strong_alias (WCSCHR_Z13, __GI___wcschr) ++weak_alias (WCSCHR_Z13, __GI_wcschr) ++# endif ++#endif +diff --git a/sysdeps/s390/multiarch/wcschr.c b/sysdeps/s390/wcschr.c +similarity index 71% +rename from sysdeps/s390/multiarch/wcschr.c +rename to sysdeps/s390/wcschr.c +index f44138f771f9f9cb..9923864ff8f5ef1f 100644 +--- a/sysdeps/s390/multiarch/wcschr.c ++++ b/sysdeps/s390/wcschr.c +@@ -16,7 +16,9 @@ + License along with the GNU C Library; if not, see + . */ + +-#if defined HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc) ++#include ++ ++#if HAVE_WCSCHR_IFUNC + # define wcschr __redirect_wcschr + # define __wcschr __redirect___wcschr + # include +@@ -24,9 +26,18 @@ + # undef __wcschr + # include + +-s390_vx_libc_ifunc_redirected (__redirect___wcschr, __wcschr) +-weak_alias (__wcschr, wcschr) ++# if HAVE_WCSCHR_C ++extern __typeof (__redirect___wcschr) WCSCHR_C attribute_hidden; ++# endif + +-#else +-# include +-#endif /* !(defined HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc)) */ ++# if HAVE_WCSCHR_Z13 ++extern __typeof (__redirect___wcschr) WCSCHR_Z13 attribute_hidden; ++# endif ++ ++s390_libc_ifunc_expr (__redirect___wcschr, __wcschr, ++ (HAVE_WCSCHR_Z13 && (hwcap & HWCAP_S390_VX)) ++ ? WCSCHR_Z13 ++ : WCSCHR_DEFAULT ++ ) ++weak_alias (__wcschr, wcschr) ++#endif diff --git a/SOURCES/glibc-rh1659438-47.patch b/SOURCES/glibc-rh1659438-47.patch new file mode 100644 index 0000000..d79d982 --- /dev/null +++ b/SOURCES/glibc-rh1659438-47.patch @@ -0,0 +1,252 @@ +commit c09c1b6f014a45f6c4ba189f5ae94b1fb1a2982a +Author: Stefan Liebler +Date: Tue Dec 18 13:57:22 2018 +0100 + + S390: Refactor wcschrnul ifunc handling. + + The ifunc handling for wcschrnul is adjusted in order to omit ifunc + if the minimum architecture level already supports newer CPUs by default. + Unfortunately the c ifunc variant can't be omitted at all as it is used + by the z13 ifunc variant as fallback if the pointers are not 4-byte aligned. + + ChangeLog: + + * sysdeps/s390/multiarch/Makefile + (sysdep_routines): Remove wcschrnul variants. + * sysdeps/s390/Makefile (sysdep_routines): Add wcschrnul variants. + * sysdeps/s390/multiarch/ifunc-impl-list.c + (__libc_ifunc_impl_list): Refactor ifunc handling for wcschrnul. + * sysdeps/s390/multiarch/wcschrnul-c.c: Move to ... + * sysdeps/s390/wcschrnul-c.c: ... here and adjust ifunc handling. + * sysdeps/s390/multiarch/wcschrnul-vx.S: Move to ... + * sysdeps/s390/wcschrnul-vx.S: ... here and adjust ifunc handling. + * sysdeps/s390/multiarch/wcschrnul.c: Move to ... + * sysdeps/s390/wcschrnul.c: ... here and adjust ifunc handling. + * sysdeps/s390/ifunc-wcschrnul.h: New file. + +diff --git a/sysdeps/s390/Makefile b/sysdeps/s390/Makefile +index 91ee84a54b713e4a..a6ebf11ad1913cc4 100644 +--- a/sysdeps/s390/Makefile ++++ b/sysdeps/s390/Makefile +@@ -70,5 +70,6 @@ sysdep_routines += wcslen wcslen-vx wcslen-c \ + wcsncat wcsncat-vx wcsncat-c \ + wcscmp wcscmp-vx wcscmp-c \ + wcsncmp wcsncmp-vx wcsncmp-c \ +- wcschr wcschr-vx wcschr-c ++ wcschr wcschr-vx wcschr-c \ ++ wcschrnul wcschrnul-vx wcschrnul-c + endif +diff --git a/sysdeps/s390/ifunc-wcschrnul.h b/sysdeps/s390/ifunc-wcschrnul.h +new file mode 100644 +index 0000000000000000..39d4120eb3cfafdf +--- /dev/null ++++ b/sysdeps/s390/ifunc-wcschrnul.h +@@ -0,0 +1,53 @@ ++/* wcschrnul variant information on S/390 version. ++ 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 ++ . */ ++ ++#if defined USE_MULTIARCH && IS_IN (libc) \ ++ && ! defined HAVE_S390_MIN_Z13_ZARCH_ASM_SUPPORT ++# define HAVE_WCSCHRNUL_IFUNC 1 ++#else ++# define HAVE_WCSCHRNUL_IFUNC 0 ++#endif ++ ++#ifdef HAVE_S390_VX_ASM_SUPPORT ++# define HAVE_WCSCHRNUL_IFUNC_AND_VX_SUPPORT HAVE_WCSCHRNUL_IFUNC ++#else ++# define HAVE_WCSCHRNUL_IFUNC_AND_VX_SUPPORT 0 ++#endif ++ ++#if defined HAVE_S390_MIN_Z13_ZARCH_ASM_SUPPORT ++# define WCSCHRNUL_DEFAULT WCSCHRNUL_Z13 ++/* The z13 ifunc variant is using the common code variant as fallback! */ ++# define HAVE_WCSCHRNUL_C 1 ++# define HAVE_WCSCHRNUL_Z13 1 ++#else ++# define WCSCHRNUL_DEFAULT WCSCHRNUL_C ++# define HAVE_WCSCHRNUL_C 1 ++# define HAVE_WCSCHRNUL_Z13 HAVE_WCSCHRNUL_IFUNC_AND_VX_SUPPORT ++#endif ++ ++#if HAVE_WCSCHRNUL_C ++# define WCSCHRNUL_C __wcschrnul_c ++#else ++# define WCSCHRNUL_C NULL ++#endif ++ ++#if HAVE_WCSCHRNUL_Z13 ++# define WCSCHRNUL_Z13 __wcschrnul_vx ++#else ++# define WCSCHRNUL_Z13 NULL ++#endif +diff --git a/sysdeps/s390/multiarch/Makefile b/sysdeps/s390/multiarch/Makefile +index b282613b4705bb14..0eb01d5d84c60408 100644 +--- a/sysdeps/s390/multiarch/Makefile ++++ b/sysdeps/s390/multiarch/Makefile +@@ -1,6 +1,5 @@ + ifeq ($(subdir),wcsmbs) +-sysdep_routines += wcschrnul wcschrnul-vx wcschrnul-c \ +- wcsrchr wcsrchr-vx wcsrchr-c \ ++sysdep_routines += wcsrchr wcsrchr-vx wcsrchr-c \ + wcsspn wcsspn-vx wcsspn-c \ + wcspbrk wcspbrk-vx wcspbrk-c \ + wcscspn wcscspn-vx wcscspn-c \ +diff --git a/sysdeps/s390/multiarch/ifunc-impl-list.c b/sysdeps/s390/multiarch/ifunc-impl-list.c +index c69165465dc97111..553a76c39ecc87ae 100644 +--- a/sysdeps/s390/multiarch/ifunc-impl-list.c ++++ b/sysdeps/s390/multiarch/ifunc-impl-list.c +@@ -57,6 +57,7 @@ + #include + #include + #include ++#include + + /* Maximum number of IFUNC implementations. */ + #define MAX_IFUNC 3 +@@ -567,6 +568,18 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + ) + #endif /* HAVE_WCSCHR_IFUNC */ + ++#if HAVE_WCSCHRNUL_IFUNC ++ IFUNC_IMPL (i, name, wcschrnul, ++# if HAVE_WCSCHRNUL_Z13 ++ IFUNC_IMPL_ADD (array, i, wcschrnul, ++ dl_hwcap & HWCAP_S390_VX, WCSCHRNUL_Z13) ++# endif ++# if HAVE_WCSCHRNUL_C ++ IFUNC_IMPL_ADD (array, i, wcschrnul, 1, WCSCHRNUL_C) ++# endif ++ ) ++#endif /* HAVE_WCSCHRNUL_IFUNC */ ++ + #ifdef HAVE_S390_VX_ASM_SUPPORT + + # define IFUNC_VX_IMPL(FUNC) \ +@@ -575,8 +588,6 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + __##FUNC##_vx) \ + IFUNC_IMPL_ADD (array, i, FUNC, 1, __##FUNC##_c)) + +- IFUNC_VX_IMPL (wcschrnul); +- + IFUNC_VX_IMPL (wcsrchr); + + IFUNC_VX_IMPL (wcsspn); +diff --git a/sysdeps/s390/multiarch/wcschrnul-c.c b/sysdeps/s390/wcschrnul-c.c +similarity index 85% +rename from sysdeps/s390/multiarch/wcschrnul-c.c +rename to sysdeps/s390/wcschrnul-c.c +index 00e776a3adc11e67..410cee1399a67914 100644 +--- a/sysdeps/s390/multiarch/wcschrnul-c.c ++++ b/sysdeps/s390/wcschrnul-c.c +@@ -16,10 +16,12 @@ + License along with the GNU C Library; if not, see + . */ + +-#if defined HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc) +-# define WCSCHRNUL __wcschrnul_c ++#include ++ ++#if HAVE_WCSCHRNUL_C ++# if HAVE_WCSCHRNUL_IFUNC || HAVE_WCSCHRNUL_Z13 ++# define WCSCHRNUL WCSCHRNUL_C ++# endif + +-# include +-extern __typeof (__wcschrnul) __wcschrnul_c; + # include + #endif +diff --git a/sysdeps/s390/multiarch/wcschrnul-vx.S b/sysdeps/s390/wcschrnul-vx.S +similarity index 92% +rename from sysdeps/s390/multiarch/wcschrnul-vx.S +rename to sysdeps/s390/wcschrnul-vx.S +index ebcd32b8703608d6..4ffb937c6bbd7008 100644 +--- a/sysdeps/s390/multiarch/wcschrnul-vx.S ++++ b/sysdeps/s390/wcschrnul-vx.S +@@ -16,7 +16,8 @@ + License along with the GNU C Library; if not, see + . */ + +-#if defined HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc) ++#include ++#if HAVE_WCSCHRNUL_Z13 + + # include "sysdep.h" + # include "asm-syntax.h" +@@ -35,7 +36,7 @@ + -v16=part of s + -v18=vector with c replicated in every byte + */ +-ENTRY(__wcschrnul_vx) ++ENTRY(WCSCHRNUL_Z13) + .machine "z13" + .machinemode "zarch_nohighgprs" + +@@ -92,6 +93,11 @@ ENTRY(__wcschrnul_vx) + .Lend: + br %r14 + .Lfallback: +- jg __wcschrnul_c +-END(__wcschrnul_vx) +-#endif /* HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc) */ ++ jg WCSCHRNUL_C ++END(WCSCHRNUL_Z13) ++ ++# if ! HAVE_WCSCHRNUL_IFUNC ++strong_alias (WCSCHRNUL_Z13, __wcschrnul) ++weak_alias (__wcschrnul, wcschrnul) ++# endif ++#endif +diff --git a/sysdeps/s390/multiarch/wcschrnul.c b/sysdeps/s390/wcschrnul.c +similarity index 68% +rename from sysdeps/s390/multiarch/wcschrnul.c +rename to sysdeps/s390/wcschrnul.c +index 807d7ee08963a601..ab5aaf04020bb571 100644 +--- a/sysdeps/s390/multiarch/wcschrnul.c ++++ b/sysdeps/s390/wcschrnul.c +@@ -16,13 +16,24 @@ + License along with the GNU C Library; if not, see + . */ + +-#if defined HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc) ++#include ++ ++#if HAVE_WCSCHRNUL_IFUNC + # include + # include + +-s390_vx_libc_ifunc (__wcschrnul) +-weak_alias (__wcschrnul, wcschrnul) ++# if HAVE_WCSCHRNUL_C ++extern __typeof (__wcschrnul) WCSCHRNUL_C attribute_hidden; ++# endif + +-#else +-# include +-#endif /* !(defined HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc)) */ ++# if HAVE_WCSCHRNUL_Z13 ++extern __typeof (__wcschrnul) WCSCHRNUL_Z13 attribute_hidden; ++# endif ++ ++s390_libc_ifunc_expr (__wcschrnul, __wcschrnul, ++ (HAVE_WCSCHRNUL_Z13 && (hwcap & HWCAP_S390_VX)) ++ ? WCSCHRNUL_Z13 ++ : WCSCHRNUL_DEFAULT ++ ) ++weak_alias (__wcschrnul, wcschrnul) ++#endif diff --git a/SOURCES/glibc-rh1659438-48.patch b/SOURCES/glibc-rh1659438-48.patch new file mode 100644 index 0000000..f786c3b --- /dev/null +++ b/SOURCES/glibc-rh1659438-48.patch @@ -0,0 +1,249 @@ +commit 4753713aaed400d88cfc598e25d504478120b065 +Author: Stefan Liebler +Date: Tue Dec 18 13:57:22 2018 +0100 + + S390: Refactor wcsrchr ifunc handling. + + The ifunc handling for wcsrchr is adjusted in order to omit ifunc + if the minimum architecture level already supports newer CPUs by default. + Unfortunately the c ifunc variant can't be omitted at all as it is used + by the z13 ifunc variant as fallback if the pointers are not 4-byte aligned. + + ChangeLog: + + * sysdeps/s390/multiarch/Makefile + (sysdep_routines): Remove wcsrchr variants. + * sysdeps/s390/Makefile (sysdep_routines): Add wcsrchr variants. + * sysdeps/s390/multiarch/ifunc-impl-list.c + (__libc_ifunc_impl_list): Refactor ifunc handling for wcsrchr. + * sysdeps/s390/multiarch/wcsrchr-c.c: Move to ... + * sysdeps/s390/wcsrchr-c.c: ... here and adjust ifunc handling. + * sysdeps/s390/multiarch/wcsrchr-vx.S: Move to ... + * sysdeps/s390/wcsrchr-vx.S: ... here and adjust ifunc handling. + * sysdeps/s390/multiarch/wcsrchr.c: Move to ... + * sysdeps/s390/wcsrchr.c: ... here and adjust ifunc handling. + * sysdeps/s390/ifunc-wcsrchr.h: New file. + +diff --git a/sysdeps/s390/Makefile b/sysdeps/s390/Makefile +index a6ebf11ad1913cc4..19a556eccf285e2f 100644 +--- a/sysdeps/s390/Makefile ++++ b/sysdeps/s390/Makefile +@@ -71,5 +71,6 @@ sysdep_routines += wcslen wcslen-vx wcslen-c \ + wcscmp wcscmp-vx wcscmp-c \ + wcsncmp wcsncmp-vx wcsncmp-c \ + wcschr wcschr-vx wcschr-c \ +- wcschrnul wcschrnul-vx wcschrnul-c ++ wcschrnul wcschrnul-vx wcschrnul-c \ ++ wcsrchr wcsrchr-vx wcsrchr-c + endif +diff --git a/sysdeps/s390/ifunc-wcsrchr.h b/sysdeps/s390/ifunc-wcsrchr.h +new file mode 100644 +index 0000000000000000..4eec0c17074c99fc +--- /dev/null ++++ b/sysdeps/s390/ifunc-wcsrchr.h +@@ -0,0 +1,53 @@ ++/* wcsrchr variant information on S/390 version. ++ 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 ++ . */ ++ ++#if defined USE_MULTIARCH && IS_IN (libc) \ ++ && ! defined HAVE_S390_MIN_Z13_ZARCH_ASM_SUPPORT ++# define HAVE_WCSRCHR_IFUNC 1 ++#else ++# define HAVE_WCSRCHR_IFUNC 0 ++#endif ++ ++#ifdef HAVE_S390_VX_ASM_SUPPORT ++# define HAVE_WCSRCHR_IFUNC_AND_VX_SUPPORT HAVE_WCSRCHR_IFUNC ++#else ++# define HAVE_WCSRCHR_IFUNC_AND_VX_SUPPORT 0 ++#endif ++ ++#if defined HAVE_S390_MIN_Z13_ZARCH_ASM_SUPPORT ++# define WCSRCHR_DEFAULT WCSRCHR_Z13 ++/* The z13 ifunc variant is using the common code variant as fallback! */ ++# define HAVE_WCSRCHR_C 1 ++# define HAVE_WCSRCHR_Z13 1 ++#else ++# define WCSRCHR_DEFAULT WCSRCHR_C ++# define HAVE_WCSRCHR_C 1 ++# define HAVE_WCSRCHR_Z13 HAVE_WCSRCHR_IFUNC_AND_VX_SUPPORT ++#endif ++ ++#if HAVE_WCSRCHR_C ++# define WCSRCHR_C __wcsrchr_c ++#else ++# define WCSRCHR_C NULL ++#endif ++ ++#if HAVE_WCSRCHR_Z13 ++# define WCSRCHR_Z13 __wcsrchr_vx ++#else ++# define WCSRCHR_Z13 NULL ++#endif +diff --git a/sysdeps/s390/multiarch/Makefile b/sysdeps/s390/multiarch/Makefile +index 0eb01d5d84c60408..3d72cbb5f32e68f3 100644 +--- a/sysdeps/s390/multiarch/Makefile ++++ b/sysdeps/s390/multiarch/Makefile +@@ -1,6 +1,5 @@ + ifeq ($(subdir),wcsmbs) +-sysdep_routines += wcsrchr wcsrchr-vx wcsrchr-c \ +- wcsspn wcsspn-vx wcsspn-c \ ++sysdep_routines += wcsspn wcsspn-vx wcsspn-c \ + wcspbrk wcspbrk-vx wcspbrk-c \ + wcscspn wcscspn-vx wcscspn-c \ + wmemchr wmemchr-vx wmemchr-c \ +diff --git a/sysdeps/s390/multiarch/ifunc-impl-list.c b/sysdeps/s390/multiarch/ifunc-impl-list.c +index 553a76c39ecc87ae..ffb4d5b6872ef9db 100644 +--- a/sysdeps/s390/multiarch/ifunc-impl-list.c ++++ b/sysdeps/s390/multiarch/ifunc-impl-list.c +@@ -58,6 +58,7 @@ + #include + #include + #include ++#include + + /* Maximum number of IFUNC implementations. */ + #define MAX_IFUNC 3 +@@ -580,6 +581,18 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + ) + #endif /* HAVE_WCSCHRNUL_IFUNC */ + ++#if HAVE_WCSRCHR_IFUNC ++ IFUNC_IMPL (i, name, wcsrchr, ++# if HAVE_WCSRCHR_Z13 ++ IFUNC_IMPL_ADD (array, i, wcsrchr, ++ dl_hwcap & HWCAP_S390_VX, WCSRCHR_Z13) ++# endif ++# if HAVE_WCSRCHR_C ++ IFUNC_IMPL_ADD (array, i, wcsrchr, 1, WCSRCHR_C) ++# endif ++ ) ++#endif /* HAVE_WCSRCHR_IFUNC */ ++ + #ifdef HAVE_S390_VX_ASM_SUPPORT + + # define IFUNC_VX_IMPL(FUNC) \ +@@ -588,8 +601,6 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + __##FUNC##_vx) \ + IFUNC_IMPL_ADD (array, i, FUNC, 1, __##FUNC##_c)) + +- IFUNC_VX_IMPL (wcsrchr); +- + IFUNC_VX_IMPL (wcsspn); + + IFUNC_VX_IMPL (wcspbrk); +diff --git a/sysdeps/s390/multiarch/wcsrchr-c.c b/sysdeps/s390/wcsrchr-c.c +similarity index 85% +rename from sysdeps/s390/multiarch/wcsrchr-c.c +rename to sysdeps/s390/wcsrchr-c.c +index 615250358ba9c00a..65164a897fb773f7 100644 +--- a/sysdeps/s390/multiarch/wcsrchr-c.c ++++ b/sysdeps/s390/wcsrchr-c.c +@@ -16,10 +16,12 @@ + License along with the GNU C Library; if not, see + . */ + +-#if defined HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc) +-# define WCSRCHR __wcsrchr_c ++#include ++ ++#if HAVE_WCSRCHR_C ++# if HAVE_WCSRCHR_IFUNC || HAVE_WCSRCHR_Z13 ++# define WCSRCHR WCSRCHR_C ++# endif + +-# include +-extern __typeof (wcsrchr) __wcsrchr_c; + # include + #endif +diff --git a/sysdeps/s390/multiarch/wcsrchr-vx.S b/sysdeps/s390/wcsrchr-vx.S +similarity index 97% +rename from sysdeps/s390/multiarch/wcsrchr-vx.S +rename to sysdeps/s390/wcsrchr-vx.S +index e40a554e5d9a216d..c7b6585beaeaef53 100644 +--- a/sysdeps/s390/multiarch/wcsrchr-vx.S ++++ b/sysdeps/s390/wcsrchr-vx.S +@@ -16,7 +16,8 @@ + License along with the GNU C Library; if not, see + . */ + +-#if defined HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc) ++#include ++#if HAVE_WCSRCHR_Z13 + + # include "sysdep.h" + # include "asm-syntax.h" +@@ -39,7 +40,7 @@ + -v19=part of s with last occurence of c. + -v20=permute pattern + */ +-ENTRY(__wcsrchr_vx) ++ENTRY(WCSRCHR_Z13) + .machine "z13" + .machinemode "zarch_nohighgprs" + +@@ -185,6 +186,10 @@ ENTRY(__wcsrchr_vx) + .byte 0x0C,0x0D,0x0E,0x0F,0x08,0x09,0x0A,0x0B + .byte 0x04,0x05,0x06,0x07,0x00,0x01,0x02,0x03 + .Lfallback: +- jg __wcsrchr_c +-END(__wcsrchr_vx) +-#endif /* HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc) */ ++ jg WCSRCHR_C ++END(WCSRCHR_Z13) ++ ++# if ! HAVE_WCSRCHR_IFUNC ++strong_alias (WCSRCHR_Z13, wcsrchr) ++# endif ++#endif +diff --git a/sysdeps/s390/multiarch/wcsrchr.c b/sysdeps/s390/wcsrchr.c +similarity index 69% +rename from sysdeps/s390/multiarch/wcsrchr.c +rename to sysdeps/s390/wcsrchr.c +index aa0b8a8f82545f64..eb70f270383880f2 100644 +--- a/sysdeps/s390/multiarch/wcsrchr.c ++++ b/sysdeps/s390/wcsrchr.c +@@ -16,12 +16,23 @@ + License along with the GNU C Library; if not, see + . */ + +-#if defined HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc) ++#include ++ ++#if HAVE_WCSRCHR_IFUNC + # include + # include + +-s390_vx_libc_ifunc2 (__wcsrchr, wcsrchr) ++# if HAVE_WCSRCHR_C ++extern __typeof (wcsrchr) WCSRCHR_C attribute_hidden; ++# endif ++ ++# if HAVE_WCSRCHR_Z13 ++extern __typeof (wcsrchr) WCSRCHR_Z13 attribute_hidden; ++# endif + +-#else +-# include +-#endif /* !(defined HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc)) */ ++s390_libc_ifunc_expr (wcsrchr, wcsrchr, ++ (HAVE_WCSRCHR_Z13 && (hwcap & HWCAP_S390_VX)) ++ ? WCSRCHR_Z13 ++ : WCSRCHR_DEFAULT ++ ) ++#endif diff --git a/SOURCES/glibc-rh1659438-49.patch b/SOURCES/glibc-rh1659438-49.patch new file mode 100644 index 0000000..3508d5e --- /dev/null +++ b/SOURCES/glibc-rh1659438-49.patch @@ -0,0 +1,271 @@ +commit 8507e831907ff46d06382fe453c6832db2594e0b +Author: Stefan Liebler +Date: Tue Dec 18 13:57:23 2018 +0100 + + S390: Refactor wcsspn ifunc handling. + + The ifunc handling for wcsspn is adjusted in order to omit ifunc + if the minimum architecture level already supports newer CPUs by default. + Unfortunately the c ifunc variant can't be omitted at all as it is used + by the z13 ifunc variant as fallback if the pointers are not 4-byte aligned. + Glibc internal calls will use the "newer" ifunc variant. + + ChangeLog: + + * sysdeps/s390/multiarch/Makefile + (sysdep_routines): Remove wcsspn variants. + * sysdeps/s390/Makefile (sysdep_routines): Add wcsspn variants. + * sysdeps/s390/multiarch/ifunc-impl-list.c + (__libc_ifunc_impl_list): Refactor ifunc handling for wcsspn. + * sysdeps/s390/multiarch/wcsspn-c.c: Move to ... + * sysdeps/s390/wcsspn-c.c: ... here and adjust ifunc handling. + * sysdeps/s390/multiarch/wcsspn-vx.S: Move to ... + * sysdeps/s390/wcsspn-vx.S: ... here and adjust ifunc handling. + * sysdeps/s390/multiarch/wcsspn.c: Move to ... + * sysdeps/s390/wcsspn.c: ... here and adjust ifunc handling. + * sysdeps/s390/ifunc-wcsspn.h: New file. + +diff --git a/sysdeps/s390/Makefile b/sysdeps/s390/Makefile +index 19a556eccf285e2f..38dbba8ccfd3cd66 100644 +--- a/sysdeps/s390/Makefile ++++ b/sysdeps/s390/Makefile +@@ -72,5 +72,6 @@ sysdep_routines += wcslen wcslen-vx wcslen-c \ + wcsncmp wcsncmp-vx wcsncmp-c \ + wcschr wcschr-vx wcschr-c \ + wcschrnul wcschrnul-vx wcschrnul-c \ +- wcsrchr wcsrchr-vx wcsrchr-c ++ wcsrchr wcsrchr-vx wcsrchr-c \ ++ wcsspn wcsspn-vx wcsspn-c + endif +diff --git a/sysdeps/s390/ifunc-wcsspn.h b/sysdeps/s390/ifunc-wcsspn.h +new file mode 100644 +index 0000000000000000..1189c6b93ff9fbec +--- /dev/null ++++ b/sysdeps/s390/ifunc-wcsspn.h +@@ -0,0 +1,53 @@ ++/* wcsspn variant information on S/390 version. ++ 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 ++ . */ ++ ++#if defined USE_MULTIARCH && IS_IN (libc) \ ++ && ! defined HAVE_S390_MIN_Z13_ZARCH_ASM_SUPPORT ++# define HAVE_WCSSPN_IFUNC 1 ++#else ++# define HAVE_WCSSPN_IFUNC 0 ++#endif ++ ++#ifdef HAVE_S390_VX_ASM_SUPPORT ++# define HAVE_WCSSPN_IFUNC_AND_VX_SUPPORT HAVE_WCSSPN_IFUNC ++#else ++# define HAVE_WCSSPN_IFUNC_AND_VX_SUPPORT 0 ++#endif ++ ++#if defined HAVE_S390_MIN_Z13_ZARCH_ASM_SUPPORT ++# define WCSSPN_DEFAULT WCSSPN_Z13 ++/* The z13 ifunc variant is using the common code variant as fallback! */ ++# define HAVE_WCSSPN_C 1 ++# define HAVE_WCSSPN_Z13 1 ++#else ++# define WCSSPN_DEFAULT WCSSPN_C ++# define HAVE_WCSSPN_C 1 ++# define HAVE_WCSSPN_Z13 HAVE_WCSSPN_IFUNC_AND_VX_SUPPORT ++#endif ++ ++#if HAVE_WCSSPN_C ++# define WCSSPN_C __wcsspn_c ++#else ++# define WCSSPN_C NULL ++#endif ++ ++#if HAVE_WCSSPN_Z13 ++# define WCSSPN_Z13 __wcsspn_vx ++#else ++# define WCSSPN_Z13 NULL ++#endif +diff --git a/sysdeps/s390/multiarch/Makefile b/sysdeps/s390/multiarch/Makefile +index 3d72cbb5f32e68f3..091f5150847a404a 100644 +--- a/sysdeps/s390/multiarch/Makefile ++++ b/sysdeps/s390/multiarch/Makefile +@@ -1,6 +1,5 @@ + ifeq ($(subdir),wcsmbs) +-sysdep_routines += wcsspn wcsspn-vx wcsspn-c \ +- wcspbrk wcspbrk-vx wcspbrk-c \ ++sysdep_routines += wcspbrk wcspbrk-vx wcspbrk-c \ + wcscspn wcscspn-vx wcscspn-c \ + wmemchr wmemchr-vx wmemchr-c \ + wmemset wmemset-vx wmemset-c \ +diff --git a/sysdeps/s390/multiarch/ifunc-impl-list.c b/sysdeps/s390/multiarch/ifunc-impl-list.c +index ffb4d5b6872ef9db..6f4de2845ba0a378 100644 +--- a/sysdeps/s390/multiarch/ifunc-impl-list.c ++++ b/sysdeps/s390/multiarch/ifunc-impl-list.c +@@ -59,6 +59,7 @@ + #include + #include + #include ++#include + + /* Maximum number of IFUNC implementations. */ + #define MAX_IFUNC 3 +@@ -593,6 +594,18 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + ) + #endif /* HAVE_WCSRCHR_IFUNC */ + ++#if HAVE_WCSSPN_IFUNC ++ IFUNC_IMPL (i, name, wcsspn, ++# if HAVE_WCSSPN_Z13 ++ IFUNC_IMPL_ADD (array, i, wcsspn, ++ dl_hwcap & HWCAP_S390_VX, WCSSPN_Z13) ++# endif ++# if HAVE_WCSSPN_C ++ IFUNC_IMPL_ADD (array, i, wcsspn, 1, WCSSPN_C) ++# endif ++ ) ++#endif /* HAVE_WCSSPN_IFUNC */ ++ + #ifdef HAVE_S390_VX_ASM_SUPPORT + + # define IFUNC_VX_IMPL(FUNC) \ +@@ -601,8 +614,6 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + __##FUNC##_vx) \ + IFUNC_IMPL_ADD (array, i, FUNC, 1, __##FUNC##_c)) + +- IFUNC_VX_IMPL (wcsspn); +- + IFUNC_VX_IMPL (wcspbrk); + + IFUNC_VX_IMPL (wcscspn); +diff --git a/sysdeps/s390/multiarch/wcsspn-c.c b/sysdeps/s390/wcsspn-c.c +similarity index 72% +rename from sysdeps/s390/multiarch/wcsspn-c.c +rename to sysdeps/s390/wcsspn-c.c +index 2c0bd0f4e69516de..db3bdb9b9f09e500 100644 +--- a/sysdeps/s390/multiarch/wcsspn-c.c ++++ b/sysdeps/s390/wcsspn-c.c +@@ -16,16 +16,22 @@ + License along with the GNU C Library; if not, see + . */ + +-#if defined HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc) +-# define WCSSPN __wcsspn_c ++#include + +-# include +-extern __typeof (wcsspn) __wcsspn_c; +-# ifdef SHARED +-# undef libc_hidden_def +-# define libc_hidden_def(name) \ ++#if HAVE_WCSSPN_C ++# if HAVE_WCSSPN_IFUNC || HAVE_WCSSPN_Z13 ++# define WCSSPN WCSSPN_C ++ ++# if defined SHARED && IS_IN (libc) ++# undef libc_hidden_def ++# if ! defined HAVE_S390_MIN_Z13_ZARCH_ASM_SUPPORT ++# define libc_hidden_def(name) \ + __hidden_ver1 (__wcsspn_c, __GI_wcsspn, __wcsspn_c); +-# endif /* SHARED */ ++# else ++# define libc_hidden_def(name) ++# endif ++# endif ++# endif + + # include +-#endif /* HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc) */ ++#endif +diff --git a/sysdeps/s390/multiarch/wcsspn-vx.S b/sysdeps/s390/wcsspn-vx.S +similarity index 97% +rename from sysdeps/s390/multiarch/wcsspn-vx.S +rename to sysdeps/s390/wcsspn-vx.S +index 548f2ad1644c8e88..61f7d6d0902125b7 100644 +--- a/sysdeps/s390/multiarch/wcsspn-vx.S ++++ b/sysdeps/s390/wcsspn-vx.S +@@ -16,7 +16,8 @@ + License along with the GNU C Library; if not, see + . */ + +-#if defined HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc) ++#include ++#if HAVE_WCSSPN_Z13 + + # include "sysdep.h" + # include "asm-syntax.h" +@@ -57,7 +58,7 @@ + otherwise =0; + r9: loaded byte count of vlbb accept-string + */ +-ENTRY(__wcsspn_vx) ++ENTRY(WCSSPN_Z13) + .machine "z13" + .machinemode "zarch_nohighgprs" + +@@ -265,6 +266,15 @@ ENTRY(__wcsspn_vx) + j .Lslow_next_acc_notonbb /* ... and search for zero in + fully loaded vreg again. */ + .Lfallback: +- jg __wcsspn_c +-END(__wcsspn_vx) +-#endif /* HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc) */ ++ jg WCSSPN_C ++END(WCSSPN_Z13) ++ ++# if ! HAVE_WCSSPN_IFUNC ++strong_alias (WCSSPN_Z13, wcsspn) ++# endif ++ ++# if defined HAVE_S390_MIN_Z13_ZARCH_ASM_SUPPORT \ ++ && defined SHARED && IS_IN (libc) ++strong_alias (WCSSPN_Z13, __GI_wcsspn) ++# endif ++#endif +diff --git a/sysdeps/s390/multiarch/wcsspn.c b/sysdeps/s390/wcsspn.c +similarity index 69% +rename from sysdeps/s390/multiarch/wcsspn.c +rename to sysdeps/s390/wcsspn.c +index 7743144a8ca7c2ee..e916b1e4414e774d 100644 +--- a/sysdeps/s390/multiarch/wcsspn.c ++++ b/sysdeps/s390/wcsspn.c +@@ -16,14 +16,24 @@ + License along with the GNU C Library; if not, see + . */ + +-#if defined HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc) ++#include ++ ++#if HAVE_WCSSPN_IFUNC + # define wcsspn __redirect_wcsspn + # include + # undef wcsspn + # include ++# if HAVE_WCSSPN_C ++extern __typeof (__redirect_wcsspn) WCSSPN_C attribute_hidden; ++# endif + +-s390_vx_libc_ifunc2_redirected (__redirect_wcsspn, __wcsspn, wcsspn) ++# if HAVE_WCSSPN_Z13 ++extern __typeof (__redirect_wcsspn) WCSSPN_Z13 attribute_hidden; ++# endif + +-#else +-# include +-#endif /* !(defined HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc)) */ ++s390_libc_ifunc_expr (__redirect_wcsspn, wcsspn, ++ (HAVE_WCSSPN_Z13 && (hwcap & HWCAP_S390_VX)) ++ ? WCSSPN_Z13 ++ : WCSSPN_DEFAULT ++ ) ++#endif diff --git a/SOURCES/glibc-rh1659438-5.patch b/SOURCES/glibc-rh1659438-5.patch new file mode 100644 index 0000000..440659f --- /dev/null +++ b/SOURCES/glibc-rh1659438-5.patch @@ -0,0 +1,306 @@ +commit 07be392807ac78330da90f01408aa7e042a97a88 +Author: Stefan Liebler +Date: Tue Dec 18 13:57:05 2018 +0100 + + S390: Implement bzero with memset. + + This patch removes the bzero s390 implementation with mvcle and + adds entry points for bzero in memset ifunc variants. + Therefore an ifunc resolver is implemented for bzero, too. + + ChangeLog: + + * sysdeps/s390/s390-32/bzero.S: Delete file. + * sysdeps/s390/s390-64/bzero.S: Likewise. + * sysdeps/s390/Makefile (sysdep_routines): Add bzero. + * sysdeps/s390/bzero.c: New file. + * sysdeps/s390/memset-z900.S: Add bzero entry points. + * sysdeps/s390/ifunc-memset.h: Add bzero function macros. + * sysdeps/s390/multiarch/ifunc-impl-list.c + (__libc_ifunc_impl_list): Add bzero ifunc variants. + +diff --git a/sysdeps/s390/Makefile b/sysdeps/s390/Makefile +index 360838e172f4ca37..e40e5bd982e54d89 100644 +--- a/sysdeps/s390/Makefile ++++ b/sysdeps/s390/Makefile +@@ -31,5 +31,5 @@ sysdeps-gconv-modules = ../sysdeps/s390/gconv-modules + endif + + ifeq ($(subdir),string) +-sysdep_routines += memset memset-z900 ++sysdep_routines += bzero memset memset-z900 + endif +diff --git a/sysdeps/s390/s390-32/bzero.S b/sysdeps/s390/bzero.c +similarity index 52% +rename from sysdeps/s390/s390-32/bzero.S +rename to sysdeps/s390/bzero.c +index 897aa2154a861b7f..9f8d95781bf2fb68 100644 +--- a/sysdeps/s390/s390-32/bzero.S ++++ b/sysdeps/s390/bzero.c +@@ -1,7 +1,6 @@ +-/* bzero -- set a block of memory to zero. IBM S390 version ++/* Multiple versions of bzero. ++ Copyright (C) 2018 Free Software Foundation, Inc. + This file is part of the GNU C Library. +- Copyright (C) 2000-2018 Free Software Foundation, Inc. +- Contributed by Martin Schwidefsky (schwidefsky@de.ibm.com). + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public +@@ -17,26 +16,32 @@ + License along with the GNU C Library; if not, see + . */ + +-/* +- * R2 = address to memory area +- * R3 = number of bytes to fill +- */ +- +-#include "sysdep.h" +-#include "asm-syntax.h" +- +- .text +-ENTRY(__bzero) +- ltr %r3,%r3 +- jz .L1 +- sr %r1,%r1 # set pad byte to zero +- sr %r4,%r4 # no source for MVCLE, only a pad byte +- sr %r5,%r5 +-.L0: mvcle %r2,%r4,0(%r1) # thats it, MVCLE is your friend +- jo .L0 +-.L1: br %r14 +-END(__bzero) +- +-#ifndef NO_WEAK_ALIAS ++#include ++#if HAVE_MEMSET_IFUNC ++# include ++# include ++ ++# if HAVE_MEMSET_Z900_G5 ++extern __typeof (__bzero) BZERO_Z900_G5 attribute_hidden; ++# endif ++ ++# if HAVE_MEMSET_Z10 ++extern __typeof (__bzero) BZERO_Z10 attribute_hidden; ++# endif ++ ++# if HAVE_MEMSET_Z196 ++extern __typeof (__bzero) BZERO_Z196 attribute_hidden; ++# endif ++ ++s390_libc_ifunc_expr (__bzero, __bzero, ++ ({ ++ s390_libc_ifunc_init (); ++ (HAVE_MEMSET_Z196 && S390_IS_Z196 (stfle_bits)) ++ ? BZERO_Z196 ++ : (HAVE_MEMSET_Z10 && S390_IS_Z10 (stfle_bits)) ++ ? BZERO_Z10 ++ : BZERO_DEFAULT; ++ }) ++ ) + weak_alias (__bzero, bzero) + #endif +diff --git a/sysdeps/s390/ifunc-memset.h b/sysdeps/s390/ifunc-memset.h +index 9a13b1001fed9979..32bc155f7e79fa26 100644 +--- a/sysdeps/s390/ifunc-memset.h ++++ b/sysdeps/s390/ifunc-memset.h +@@ -25,16 +25,19 @@ + + #if defined HAVE_S390_MIN_Z196_ZARCH_ASM_SUPPORT + # define MEMSET_DEFAULT MEMSET_Z196 ++# define BZERO_DEFAULT BZERO_Z196 + # define HAVE_MEMSET_Z900_G5 0 + # define HAVE_MEMSET_Z10 0 + # define HAVE_MEMSET_Z196 1 + #elif defined HAVE_S390_MIN_Z10_ZARCH_ASM_SUPPORT + # define MEMSET_DEFAULT MEMSET_Z10 ++# define BZERO_DEFAULT BZERO_Z10 + # define HAVE_MEMSET_Z900_G5 0 + # define HAVE_MEMSET_Z10 1 + # define HAVE_MEMSET_Z196 HAVE_MEMSET_IFUNC + #else + # define MEMSET_DEFAULT MEMSET_Z900_G5 ++# define BZERO_DEFAULT BZERO_Z900_G5 + # define HAVE_MEMSET_Z900_G5 1 + # define HAVE_MEMSET_Z10 HAVE_MEMSET_IFUNC + # define HAVE_MEMSET_Z196 HAVE_MEMSET_IFUNC +@@ -48,18 +51,24 @@ + + #if HAVE_MEMSET_Z900_G5 + # define MEMSET_Z900_G5 __memset_default ++# define BZERO_Z900_G5 __bzero_default + #else + # define MEMSET_Z900_G5 NULL ++# define BZERO_Z900_G5 NULL + #endif + + #if HAVE_MEMSET_Z10 + # define MEMSET_Z10 __memset_z10 ++# define BZERO_Z10 __bzero_z10 + #else + # define MEMSET_Z10 NULL ++# define BZERO_Z10 NULL + #endif + + #if HAVE_MEMSET_Z196 + # define MEMSET_Z196 __memset_z196 ++# define BZERO_Z196 __bzero_z196 + #else + # define MEMSET_Z196 NULL ++# define BZERO_Z196 NULL + #endif +diff --git a/sysdeps/s390/memset-z900.S b/sysdeps/s390/memset-z900.S +index eaf13402bd3e251d..bfc659ae0b029eb4 100644 +--- a/sysdeps/s390/memset-z900.S ++++ b/sysdeps/s390/memset-z900.S +@@ -22,10 +22,14 @@ + #include "asm-syntax.h" + #include + +-/* INPUT PARAMETERS ++/* INPUT PARAMETERS - MEMSET + %r2 = address of memory area + %r3 = byte to fill memory with +- %r4 = number of bytes to fill. */ ++ %r4 = number of bytes to fill. ++ ++ INPUT PARAMETERS - BZERO ++ %r2 = address of memory area ++ %r3 = number of bytes to fill. */ + + .text + +@@ -44,7 +48,14 @@ + # define BRCTG brct + # endif /* ! defined __s390x__ */ + ++ENTRY(BZERO_Z900_G5) ++ LGR %r4,%r3 ++ xr %r3,%r3 ++ j .L_Z900_G5_start ++END(BZERO_Z900_G5) ++ + ENTRY(MEMSET_Z900_G5) ++.L_Z900_G5_start: + #if defined __s390x__ + .machine "z900" + #else +@@ -90,7 +101,16 @@ END(MEMSET_Z900_G5) + #endif /* HAVE_MEMSET_Z900_G5 */ + + #if HAVE_MEMSET_Z10 ++ENTRY(BZERO_Z10) ++ .machine "z10" ++ .machinemode "zarch_nohighgprs" ++ lgr %r4,%r3 ++ xr %r3,%r3 ++ j .L_Z10_start ++END(BZERO_Z10) ++ + ENTRY(MEMSET_Z10) ++.L_Z10_start: + .machine "z10" + .machinemode "zarch_nohighgprs" + # if !defined __s390x__ +@@ -122,7 +142,16 @@ END(MEMSET_Z10) + #endif /* HAVE_MEMSET_Z10 */ + + #if HAVE_MEMSET_Z196 ++ENTRY(BZERO_Z196) ++ .machine "z196" ++ .machinemode "zarch_nohighgprs" ++ lgr %r4,%r3 ++ xr %r3,%r3 ++ j .L_Z196_start ++END(BZERO_Z196) ++ + ENTRY(MEMSET_Z196) ++.L_Z196_start: + .machine "z196" + .machinemode "zarch_nohighgprs" + # if !defined __s390x__ +@@ -177,6 +206,10 @@ END(__memset_mvcle) + /* If we don't use ifunc, define an alias for memset here. + Otherwise see sysdeps/s390/memset.c. */ + strong_alias (MEMSET_DEFAULT, memset) ++/* Same for bzero. If ifunc is used, see ++ sysdeps/s390/bzero.c. */ ++strong_alias (BZERO_DEFAULT, __bzero) ++weak_alias (__bzero, bzero) + #endif + + #if defined SHARED && IS_IN (libc) +diff --git a/sysdeps/s390/multiarch/ifunc-impl-list.c b/sysdeps/s390/multiarch/ifunc-impl-list.c +index 2f671eac1f4f1ffd..253f36045b57cc3c 100644 +--- a/sysdeps/s390/multiarch/ifunc-impl-list.c ++++ b/sysdeps/s390/multiarch/ifunc-impl-list.c +@@ -59,6 +59,21 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + # endif + # if HAVE_MEMSET_Z900_G5 + IFUNC_IMPL_ADD (array, i, memset, 1, MEMSET_Z900_G5) ++# endif ++ ) ++ ++ /* Note: bzero is implemented in memset. */ ++ IFUNC_IMPL (i, name, bzero, ++# if HAVE_MEMSET_Z196 ++ IFUNC_IMPL_ADD (array, i, bzero, ++ S390_IS_Z196 (stfle_bits), BZERO_Z196) ++# endif ++# if HAVE_MEMSET_Z10 ++ IFUNC_IMPL_ADD (array, i, bzero, ++ S390_IS_Z10 (stfle_bits), BZERO_Z10) ++# endif ++# if HAVE_MEMSET_Z900_G5 ++ IFUNC_IMPL_ADD (array, i, bzero, 1, BZERO_Z900_G5) + # endif + ) + #endif /* HAVE_MEMSET_IFUNC */ +diff --git a/sysdeps/s390/s390-64/bzero.S b/sysdeps/s390/s390-64/bzero.S +deleted file mode 100644 +index b3216652985cc239..0000000000000000 +--- a/sysdeps/s390/s390-64/bzero.S ++++ /dev/null +@@ -1,41 +0,0 @@ +-/* bzero -- set a block of memory to zero. 64 bit S/390 version. +- This file is part of the GNU C Library. +- Copyright (C) 2001-2018 Free Software Foundation, Inc. +- Contributed by Martin Schwidefsky (schwidefsky@de.ibm.com). +- +- The GNU C Library is free software; you can redistribute it and/or +- modify it under the terms of the GNU Lesser General Public +- License as published by the Free Software Foundation; either +- version 2.1 of the License, or (at your option) any later version. +- +- The GNU C Library is distributed in the hope that it will be useful, +- but WITHOUT ANY WARRANTY; without even the implied warranty of +- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +- Lesser General Public License for more details. +- +- You should have received a copy of the GNU Lesser General Public +- License along with the GNU C Library; if not, see +- . */ +- +-/* INPUT PARAMETERS +- %r2 = address of memory area +- %r3 = number of bytes to fill. */ +- +-#include "sysdep.h" +-#include "asm-syntax.h" +- +- .text +-ENTRY(__bzero) +- ltgr %r3,%r3 +- jz .L1 +- sgr %r1,%r1 # set pad byte to zero +- sgr %r4,%r4 # no source for MVCLE, only a pad byte +- sgr %r5,%r5 +-.L0: mvcle %r2,%r4,0(%r1) # thats it, MVCLE is your friend +- jo .L0 +-.L1: br %r14 +-END(__bzero) +- +-#ifndef NO_WEAK_ALIAS +-weak_alias (__bzero, bzero) +-#endif diff --git a/SOURCES/glibc-rh1659438-50.patch b/SOURCES/glibc-rh1659438-50.patch new file mode 100644 index 0000000..41d29db --- /dev/null +++ b/SOURCES/glibc-rh1659438-50.patch @@ -0,0 +1,271 @@ +commit 8e87c1f6d45a63dc2175825c2dc5d66192a13aab +Author: Stefan Liebler +Date: Tue Dec 18 13:57:23 2018 +0100 + + S390: Refactor wcspbrk ifunc handling. + + The ifunc handling for wcspbrk is adjusted in order to omit ifunc + if the minimum architecture level already supports newer CPUs by default. + Unfortunately the c ifunc variant can't be omitted at all as it is used + by the z13 ifunc variant as fallback if the pointers are not 4-byte aligned. + Glibc internal calls will use the "newer" ifunc variant. + + ChangeLog: + + * sysdeps/s390/multiarch/Makefile + (sysdep_routines): Remove wcspbrk variants. + * sysdeps/s390/Makefile (sysdep_routines): Add wcspbrk variants. + * sysdeps/s390/multiarch/ifunc-impl-list.c + (__libc_ifunc_impl_list): Refactor ifunc handling for wcspbrk. + * sysdeps/s390/multiarch/wcspbrk-c.c: Move to ... + * sysdeps/s390/wcspbrk-c.c: ... here and adjust ifunc handling. + * sysdeps/s390/multiarch/wcspbrk-vx.S: Move to ... + * sysdeps/s390/wcspbrk-vx.S: ... here and adjust ifunc handling. + * sysdeps/s390/multiarch/wcspbrk.c: Move to ... + * sysdeps/s390/wcspbrk.c: ... here and adjust ifunc handling. + * sysdeps/s390/ifunc-wcspbrk.h: New file. + +diff --git a/sysdeps/s390/Makefile b/sysdeps/s390/Makefile +index 38dbba8ccfd3cd66..af595050d43c63ed 100644 +--- a/sysdeps/s390/Makefile ++++ b/sysdeps/s390/Makefile +@@ -73,5 +73,6 @@ sysdep_routines += wcslen wcslen-vx wcslen-c \ + wcschr wcschr-vx wcschr-c \ + wcschrnul wcschrnul-vx wcschrnul-c \ + wcsrchr wcsrchr-vx wcsrchr-c \ +- wcsspn wcsspn-vx wcsspn-c ++ wcsspn wcsspn-vx wcsspn-c \ ++ wcspbrk wcspbrk-vx wcspbrk-c + endif +diff --git a/sysdeps/s390/ifunc-wcspbrk.h b/sysdeps/s390/ifunc-wcspbrk.h +new file mode 100644 +index 0000000000000000..d3b9b7363a73fab0 +--- /dev/null ++++ b/sysdeps/s390/ifunc-wcspbrk.h +@@ -0,0 +1,53 @@ ++/* wcspbrk variant information on S/390 version. ++ 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 ++ . */ ++ ++#if defined USE_MULTIARCH && IS_IN (libc) \ ++ && ! defined HAVE_S390_MIN_Z13_ZARCH_ASM_SUPPORT ++# define HAVE_WCSPBRK_IFUNC 1 ++#else ++# define HAVE_WCSPBRK_IFUNC 0 ++#endif ++ ++#ifdef HAVE_S390_VX_ASM_SUPPORT ++# define HAVE_WCSPBRK_IFUNC_AND_VX_SUPPORT HAVE_WCSPBRK_IFUNC ++#else ++# define HAVE_WCSPBRK_IFUNC_AND_VX_SUPPORT 0 ++#endif ++ ++#if defined HAVE_S390_MIN_Z13_ZARCH_ASM_SUPPORT ++# define WCSPBRK_DEFAULT WCSPBRK_Z13 ++/* The z13 ifunc variant is using the common code variant as fallback! */ ++# define HAVE_WCSPBRK_C 1 ++# define HAVE_WCSPBRK_Z13 1 ++#else ++# define WCSPBRK_DEFAULT WCSPBRK_C ++# define HAVE_WCSPBRK_C 1 ++# define HAVE_WCSPBRK_Z13 HAVE_WCSPBRK_IFUNC_AND_VX_SUPPORT ++#endif ++ ++#if HAVE_WCSPBRK_C ++# define WCSPBRK_C __wcspbrk_c ++#else ++# define WCSPBRK_C NULL ++#endif ++ ++#if HAVE_WCSPBRK_Z13 ++# define WCSPBRK_Z13 __wcspbrk_vx ++#else ++# define WCSPBRK_Z13 NULL ++#endif +diff --git a/sysdeps/s390/multiarch/Makefile b/sysdeps/s390/multiarch/Makefile +index 091f5150847a404a..e1e2d9dc7495ebdc 100644 +--- a/sysdeps/s390/multiarch/Makefile ++++ b/sysdeps/s390/multiarch/Makefile +@@ -1,6 +1,5 @@ + ifeq ($(subdir),wcsmbs) +-sysdep_routines += wcspbrk wcspbrk-vx wcspbrk-c \ +- wcscspn wcscspn-vx wcscspn-c \ ++sysdep_routines += wcscspn wcscspn-vx wcscspn-c \ + wmemchr wmemchr-vx wmemchr-c \ + wmemset wmemset-vx wmemset-c \ + wmemcmp wmemcmp-vx wmemcmp-c +diff --git a/sysdeps/s390/multiarch/ifunc-impl-list.c b/sysdeps/s390/multiarch/ifunc-impl-list.c +index 6f4de2845ba0a378..89d6e8ad7e323fec 100644 +--- a/sysdeps/s390/multiarch/ifunc-impl-list.c ++++ b/sysdeps/s390/multiarch/ifunc-impl-list.c +@@ -60,6 +60,7 @@ + #include + #include + #include ++#include + + /* Maximum number of IFUNC implementations. */ + #define MAX_IFUNC 3 +@@ -606,6 +607,18 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + ) + #endif /* HAVE_WCSSPN_IFUNC */ + ++#if HAVE_WCSPBRK_IFUNC ++ IFUNC_IMPL (i, name, wcspbrk, ++# if HAVE_WCSPBRK_Z13 ++ IFUNC_IMPL_ADD (array, i, wcspbrk, ++ dl_hwcap & HWCAP_S390_VX, WCSPBRK_Z13) ++# endif ++# if HAVE_WCSPBRK_C ++ IFUNC_IMPL_ADD (array, i, wcspbrk, 1, WCSPBRK_C) ++# endif ++ ) ++#endif /* HAVE_WCSPBRK_IFUNC */ ++ + #ifdef HAVE_S390_VX_ASM_SUPPORT + + # define IFUNC_VX_IMPL(FUNC) \ +@@ -614,8 +627,6 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + __##FUNC##_vx) \ + IFUNC_IMPL_ADD (array, i, FUNC, 1, __##FUNC##_c)) + +- IFUNC_VX_IMPL (wcspbrk); +- + IFUNC_VX_IMPL (wcscspn); + + IFUNC_VX_IMPL (wmemchr); +diff --git a/sysdeps/s390/multiarch/wcspbrk-c.c b/sysdeps/s390/wcspbrk-c.c +similarity index 72% +rename from sysdeps/s390/multiarch/wcspbrk-c.c +rename to sysdeps/s390/wcspbrk-c.c +index 6b6e7aade46942ed..e79c6a85503dc32b 100644 +--- a/sysdeps/s390/multiarch/wcspbrk-c.c ++++ b/sysdeps/s390/wcspbrk-c.c +@@ -16,16 +16,22 @@ + License along with the GNU C Library; if not, see + . */ + +-#if defined HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc) +-# define WCSPBRK __wcspbrk_c ++#include + +-# include +-extern __typeof (wcspbrk) __wcspbrk_c; +-# ifdef SHARED +-# undef libc_hidden_def +-# define libc_hidden_def(name) \ ++#if HAVE_WCSPBRK_C ++# if HAVE_WCSPBRK_IFUNC || HAVE_WCSPBRK_Z13 ++# define WCSPBRK WCSPBRK_C ++ ++# if defined SHARED && IS_IN (libc) ++# undef libc_hidden_def ++# if ! defined HAVE_S390_MIN_Z13_ZARCH_ASM_SUPPORT ++# define libc_hidden_def(name) \ + __hidden_ver1 (__wcspbrk_c, __GI_wcspbrk, __wcspbrk_c); +-# endif /* SHARED */ ++# else ++# define libc_hidden_def(name) ++# endif ++# endif ++# endif + + # include +-#endif /* HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc) */ ++#endif +diff --git a/sysdeps/s390/multiarch/wcspbrk-vx.S b/sysdeps/s390/wcspbrk-vx.S +similarity index 97% +rename from sysdeps/s390/multiarch/wcspbrk-vx.S +rename to sysdeps/s390/wcspbrk-vx.S +index 5c89ec5d336c1acd..5870c4684d140ab0 100644 +--- a/sysdeps/s390/multiarch/wcspbrk-vx.S ++++ b/sysdeps/s390/wcspbrk-vx.S +@@ -16,7 +16,8 @@ + License along with the GNU C Library; if not, see + . */ + +-#if defined HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc) ++#include ++#if HAVE_WCSPBRK_Z13 + + # include "sysdep.h" + # include "asm-syntax.h" +@@ -59,7 +60,7 @@ + otherwise =0; + r9: loaded byte count of vlbb accept-string + */ +-ENTRY(__wcspbrk_vx) ++ENTRY(WCSPBRK_Z13) + .machine "z13" + .machinemode "zarch_nohighgprs" + +@@ -310,6 +311,15 @@ ENTRY(__wcspbrk_vx) + lgr %r2,%r1 + br %r14 + .Lfallback: +- jg __wcspbrk_c +-END(__wcspbrk_vx) +-#endif /* HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc) */ ++ jg WCSPBRK_C ++END(WCSPBRK_Z13) ++ ++# if ! HAVE_WCSPBRK_IFUNC ++strong_alias (WCSPBRK_Z13, wcspbrk) ++# endif ++ ++# if defined HAVE_S390_MIN_Z13_ZARCH_ASM_SUPPORT \ ++ && defined SHARED && IS_IN (libc) ++strong_alias (WCSPBRK_Z13, __GI_wcspbrk) ++# endif ++#endif +diff --git a/sysdeps/s390/multiarch/wcspbrk.c b/sysdeps/s390/wcspbrk.c +similarity index 69% +rename from sysdeps/s390/multiarch/wcspbrk.c +rename to sysdeps/s390/wcspbrk.c +index 97876328b5ad9425..84ab911a24fba3c4 100644 +--- a/sysdeps/s390/multiarch/wcspbrk.c ++++ b/sysdeps/s390/wcspbrk.c +@@ -16,14 +16,24 @@ + License along with the GNU C Library; if not, see + . */ + +-#if defined HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc) ++#include ++ ++#if HAVE_WCSPBRK_IFUNC + # define wcspbrk __redirect_wcspbrk + # include + # undef wcspbrk + # include ++# if HAVE_WCSPBRK_C ++extern __typeof (__redirect_wcspbrk) WCSPBRK_C attribute_hidden; ++# endif + +-s390_vx_libc_ifunc2_redirected (__redirect_wcspbrk, __wcspbrk, wcspbrk) ++# if HAVE_WCSPBRK_Z13 ++extern __typeof (__redirect_wcspbrk) WCSPBRK_Z13 attribute_hidden; ++# endif + +-#else +-# include +-#endif /* !(defined HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc)) */ ++s390_libc_ifunc_expr (__redirect_wcspbrk, wcspbrk, ++ (HAVE_WCSPBRK_Z13 && (hwcap & HWCAP_S390_VX)) ++ ? WCSPBRK_Z13 ++ : WCSPBRK_DEFAULT ++ ) ++#endif diff --git a/SOURCES/glibc-rh1659438-51.patch b/SOURCES/glibc-rh1659438-51.patch new file mode 100644 index 0000000..264a0e1 --- /dev/null +++ b/SOURCES/glibc-rh1659438-51.patch @@ -0,0 +1,249 @@ +commit 79b44cf61115bd48006227bb325b709f294c56f9 +Author: Stefan Liebler +Date: Tue Dec 18 13:57:23 2018 +0100 + + S390: Refactor wcscspn ifunc handling. + + The ifunc handling for wcscspn is adjusted in order to omit ifunc + if the minimum architecture level already supports newer CPUs by default. + Unfortunately the c ifunc variant can't be omitted at all as it is used + by the z13 ifunc variant as fallback if the pointers are not 4-byte aligned. + + ChangeLog: + + * sysdeps/s390/multiarch/Makefile + (sysdep_routines): Remove wcscspn variants. + * sysdeps/s390/Makefile (sysdep_routines): Add wcscspn variants. + * sysdeps/s390/multiarch/ifunc-impl-list.c + (__libc_ifunc_impl_list): Refactor ifunc handling for wcscspn. + * sysdeps/s390/multiarch/wcscspn-c.c: Move to ... + * sysdeps/s390/wcscspn-c.c: ... here and adjust ifunc handling. + * sysdeps/s390/multiarch/wcscspn-vx.S: Move to ... + * sysdeps/s390/wcscspn-vx.S: ... here and adjust ifunc handling. + * sysdeps/s390/multiarch/wcscspn.c: Move to ... + * sysdeps/s390/wcscspn.c: ... here and adjust ifunc handling. + * sysdeps/s390/ifunc-wcscspn.h: New file. + +diff --git a/sysdeps/s390/Makefile b/sysdeps/s390/Makefile +index af595050d43c63ed..da96ac3a36bd7f4e 100644 +--- a/sysdeps/s390/Makefile ++++ b/sysdeps/s390/Makefile +@@ -74,5 +74,6 @@ sysdep_routines += wcslen wcslen-vx wcslen-c \ + wcschrnul wcschrnul-vx wcschrnul-c \ + wcsrchr wcsrchr-vx wcsrchr-c \ + wcsspn wcsspn-vx wcsspn-c \ +- wcspbrk wcspbrk-vx wcspbrk-c ++ wcspbrk wcspbrk-vx wcspbrk-c \ ++ wcscspn wcscspn-vx wcscspn-c + endif +diff --git a/sysdeps/s390/ifunc-wcscspn.h b/sysdeps/s390/ifunc-wcscspn.h +new file mode 100644 +index 0000000000000000..23f3667ba3823e99 +--- /dev/null ++++ b/sysdeps/s390/ifunc-wcscspn.h +@@ -0,0 +1,53 @@ ++/* wcscspn variant information on S/390 version. ++ 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 ++ . */ ++ ++#if defined USE_MULTIARCH && IS_IN (libc) \ ++ && ! defined HAVE_S390_MIN_Z13_ZARCH_ASM_SUPPORT ++# define HAVE_WCSCSPN_IFUNC 1 ++#else ++# define HAVE_WCSCSPN_IFUNC 0 ++#endif ++ ++#ifdef HAVE_S390_VX_ASM_SUPPORT ++# define HAVE_WCSCSPN_IFUNC_AND_VX_SUPPORT HAVE_WCSCSPN_IFUNC ++#else ++# define HAVE_WCSCSPN_IFUNC_AND_VX_SUPPORT 0 ++#endif ++ ++#if defined HAVE_S390_MIN_Z13_ZARCH_ASM_SUPPORT ++# define WCSCSPN_DEFAULT WCSCSPN_Z13 ++/* The z13 ifunc variant is using the common code variant as fallback! */ ++# define HAVE_WCSCSPN_C 1 ++# define HAVE_WCSCSPN_Z13 1 ++#else ++# define WCSCSPN_DEFAULT WCSCSPN_C ++# define HAVE_WCSCSPN_C 1 ++# define HAVE_WCSCSPN_Z13 HAVE_WCSCSPN_IFUNC_AND_VX_SUPPORT ++#endif ++ ++#if HAVE_WCSCSPN_C ++# define WCSCSPN_C __wcscspn_c ++#else ++# define WCSCSPN_C NULL ++#endif ++ ++#if HAVE_WCSCSPN_Z13 ++# define WCSCSPN_Z13 __wcscspn_vx ++#else ++# define WCSCSPN_Z13 NULL ++#endif +diff --git a/sysdeps/s390/multiarch/Makefile b/sysdeps/s390/multiarch/Makefile +index e1e2d9dc7495ebdc..5be635542361b355 100644 +--- a/sysdeps/s390/multiarch/Makefile ++++ b/sysdeps/s390/multiarch/Makefile +@@ -1,6 +1,5 @@ + ifeq ($(subdir),wcsmbs) +-sysdep_routines += wcscspn wcscspn-vx wcscspn-c \ +- wmemchr wmemchr-vx wmemchr-c \ ++sysdep_routines += wmemchr wmemchr-vx wmemchr-c \ + wmemset wmemset-vx wmemset-c \ + wmemcmp wmemcmp-vx wmemcmp-c + endif +diff --git a/sysdeps/s390/multiarch/ifunc-impl-list.c b/sysdeps/s390/multiarch/ifunc-impl-list.c +index 89d6e8ad7e323fec..7d8031a069bd23ba 100644 +--- a/sysdeps/s390/multiarch/ifunc-impl-list.c ++++ b/sysdeps/s390/multiarch/ifunc-impl-list.c +@@ -61,6 +61,7 @@ + #include + #include + #include ++#include + + /* Maximum number of IFUNC implementations. */ + #define MAX_IFUNC 3 +@@ -619,6 +620,18 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + ) + #endif /* HAVE_WCSPBRK_IFUNC */ + ++#if HAVE_WCSCSPN_IFUNC ++ IFUNC_IMPL (i, name, wcscspn, ++# if HAVE_WCSCSPN_Z13 ++ IFUNC_IMPL_ADD (array, i, wcscspn, ++ dl_hwcap & HWCAP_S390_VX, WCSCSPN_Z13) ++# endif ++# if HAVE_WCSCSPN_C ++ IFUNC_IMPL_ADD (array, i, wcscspn, 1, WCSCSPN_C) ++# endif ++ ) ++#endif /* HAVE_WCSCSPN_IFUNC */ ++ + #ifdef HAVE_S390_VX_ASM_SUPPORT + + # define IFUNC_VX_IMPL(FUNC) \ +@@ -627,8 +640,6 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + __##FUNC##_vx) \ + IFUNC_IMPL_ADD (array, i, FUNC, 1, __##FUNC##_c)) + +- IFUNC_VX_IMPL (wcscspn); +- + IFUNC_VX_IMPL (wmemchr); + + IFUNC_VX_IMPL (wmemset); +diff --git a/sysdeps/s390/multiarch/wcscspn-c.c b/sysdeps/s390/wcscspn-c.c +similarity index 86% +rename from sysdeps/s390/multiarch/wcscspn-c.c +rename to sysdeps/s390/wcscspn-c.c +index 161e52e686c73907..d47cb6b75be14e14 100644 +--- a/sysdeps/s390/multiarch/wcscspn-c.c ++++ b/sysdeps/s390/wcscspn-c.c +@@ -16,11 +16,12 @@ + License along with the GNU C Library; if not, see + . */ + +-#if defined HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc) +-# define WCSCSPN __wcscspn_c ++#include + +-# include +-extern __typeof (wcscspn) __wcscspn_c; ++#if HAVE_WCSCSPN_C ++# if HAVE_WCSCSPN_IFUNC || HAVE_WCSCSPN_Z13 ++# define WCSCSPN WCSCSPN_C ++# endif + + # include + #endif +diff --git a/sysdeps/s390/multiarch/wcscspn-vx.S b/sysdeps/s390/wcscspn-vx.S +similarity index 98% +rename from sysdeps/s390/multiarch/wcscspn-vx.S +rename to sysdeps/s390/wcscspn-vx.S +index 06bc4e25d0456aea..882cb93fb807caa1 100644 +--- a/sysdeps/s390/multiarch/wcscspn-vx.S ++++ b/sysdeps/s390/wcscspn-vx.S +@@ -16,7 +16,8 @@ + License along with the GNU C Library; if not, see + . */ + +-#if defined HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc) ++#include ++#if HAVE_WCSCSPN_Z13 + + # include "sysdep.h" + # include "asm-syntax.h" +@@ -57,7 +58,7 @@ + otherwise =0; + r9: loaded byte count of vlbb reject-string + */ +-ENTRY(__wcscspn_vx) ++ENTRY(WCSCSPN_Z13) + .machine "z13" + .machinemode "zarch_nohighgprs" + +@@ -288,6 +289,10 @@ ENTRY(__wcscspn_vx) + vlgvg %r9,%v31,1 + br %r14 + .Lfallback: +- jg __wcscspn_c +-END(__wcscspn_vx) +-#endif /* HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc) */ ++ jg WCSCSPN_C ++END(WCSCSPN_Z13) ++ ++# if ! HAVE_WCSCSPN_IFUNC ++strong_alias (WCSCSPN_Z13, wcscspn) ++# endif ++#endif +diff --git a/sysdeps/s390/multiarch/wcscspn.c b/sysdeps/s390/wcscspn.c +similarity index 69% +rename from sysdeps/s390/multiarch/wcscspn.c +rename to sysdeps/s390/wcscspn.c +index 707327522ad20287..0ce31b8aabf3b429 100644 +--- a/sysdeps/s390/multiarch/wcscspn.c ++++ b/sysdeps/s390/wcscspn.c +@@ -16,12 +16,23 @@ + License along with the GNU C Library; if not, see + . */ + +-#if defined HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc) ++#include ++ ++#if HAVE_WCSCSPN_IFUNC + # include + # include + +-s390_vx_libc_ifunc2 (__wcscspn, wcscspn) ++# if HAVE_WCSCSPN_C ++extern __typeof (wcscspn) WCSCSPN_C attribute_hidden; ++# endif ++ ++# if HAVE_WCSCSPN_Z13 ++extern __typeof (wcscspn) WCSCSPN_Z13 attribute_hidden; ++# endif + +-#else +-# include +-#endif /* !(defined HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc)) */ ++s390_libc_ifunc_expr (wcscspn, wcscspn, ++ (HAVE_WCSCSPN_Z13 && (hwcap & HWCAP_S390_VX)) ++ ? WCSCSPN_Z13 ++ : WCSCSPN_DEFAULT ++ ) ++#endif diff --git a/SOURCES/glibc-rh1659438-52.patch b/SOURCES/glibc-rh1659438-52.patch new file mode 100644 index 0000000..c46c2ec --- /dev/null +++ b/SOURCES/glibc-rh1659438-52.patch @@ -0,0 +1,292 @@ +commit c62534ae524111eae48b2c2adf3f9a2ca90824f5 +Author: Stefan Liebler +Date: Tue Dec 18 13:57:24 2018 +0100 + + S390: Refactor wmemchr ifunc handling. + + The ifunc handling for wmemchr is adjusted in order to omit ifunc + if the minimum architecture level already supports newer CPUs by default. + Unfortunately the c ifunc variant can't be omitted at all as it is used + by the z13 ifunc variant as fallback if the pointers are not 4-byte aligned. + Glibc internal calls will use the "newer" ifunc variant. + + ChangeLog: + + * sysdeps/s390/multiarch/Makefile + (sysdep_routines): Remove wmemchr variants. + * sysdeps/s390/Makefile (sysdep_routines): Add wmemchr variants. + * sysdeps/s390/multiarch/ifunc-impl-list.c + (__libc_ifunc_impl_list): Refactor ifunc handling for wmemchr. + * sysdeps/s390/multiarch/wmemchr-c.c: Move to ... + * sysdeps/s390/wmemchr-c.c: ... here and adjust ifunc handling. + * sysdeps/s390/multiarch/wmemchr-vx.S: Move to ... + * sysdeps/s390/wmemchr-vx.S: ... here and adjust ifunc handling. + * sysdeps/s390/multiarch/wmemchr.c: Move to ... + * sysdeps/s390/wmemchr.c: ... here and adjust ifunc handling. + * sysdeps/s390/ifunc-wmemchr.h: New file. + +diff --git a/sysdeps/s390/Makefile b/sysdeps/s390/Makefile +index da96ac3a36bd7f4e..fdfd1c605c28ddc7 100644 +--- a/sysdeps/s390/Makefile ++++ b/sysdeps/s390/Makefile +@@ -75,5 +75,6 @@ sysdep_routines += wcslen wcslen-vx wcslen-c \ + wcsrchr wcsrchr-vx wcsrchr-c \ + wcsspn wcsspn-vx wcsspn-c \ + wcspbrk wcspbrk-vx wcspbrk-c \ +- wcscspn wcscspn-vx wcscspn-c ++ wcscspn wcscspn-vx wcscspn-c \ ++ wmemchr wmemchr-vx wmemchr-c + endif +diff --git a/sysdeps/s390/ifunc-wmemchr.h b/sysdeps/s390/ifunc-wmemchr.h +new file mode 100644 +index 0000000000000000..0610cfb5d4a7fb18 +--- /dev/null ++++ b/sysdeps/s390/ifunc-wmemchr.h +@@ -0,0 +1,53 @@ ++/* wmemchr variant information on S/390 version. ++ 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 ++ . */ ++ ++#if defined USE_MULTIARCH && IS_IN (libc) \ ++ && ! defined HAVE_S390_MIN_Z13_ZARCH_ASM_SUPPORT ++# define HAVE_WMEMCHR_IFUNC 1 ++#else ++# define HAVE_WMEMCHR_IFUNC 0 ++#endif ++ ++#ifdef HAVE_S390_VX_ASM_SUPPORT ++# define HAVE_WMEMCHR_IFUNC_AND_VX_SUPPORT HAVE_WMEMCHR_IFUNC ++#else ++# define HAVE_WMEMCHR_IFUNC_AND_VX_SUPPORT 0 ++#endif ++ ++#if defined HAVE_S390_MIN_Z13_ZARCH_ASM_SUPPORT ++# define WMEMCHR_DEFAULT WMEMCHR_Z13 ++/* The z13 ifunc variant is using the common code variant as fallback! */ ++# define HAVE_WMEMCHR_C 1 ++# define HAVE_WMEMCHR_Z13 1 ++#else ++# define WMEMCHR_DEFAULT WMEMCHR_C ++# define HAVE_WMEMCHR_C 1 ++# define HAVE_WMEMCHR_Z13 HAVE_WMEMCHR_IFUNC_AND_VX_SUPPORT ++#endif ++ ++#if HAVE_WMEMCHR_C ++# define WMEMCHR_C __wmemchr_c ++#else ++# define WMEMCHR_C NULL ++#endif ++ ++#if HAVE_WMEMCHR_Z13 ++# define WMEMCHR_Z13 __wmemchr_vx ++#else ++# define WMEMCHR_Z13 NULL ++#endif +diff --git a/sysdeps/s390/multiarch/Makefile b/sysdeps/s390/multiarch/Makefile +index 5be635542361b355..92e28dc45ddbae37 100644 +--- a/sysdeps/s390/multiarch/Makefile ++++ b/sysdeps/s390/multiarch/Makefile +@@ -1,6 +1,5 @@ + ifeq ($(subdir),wcsmbs) +-sysdep_routines += wmemchr wmemchr-vx wmemchr-c \ +- wmemset wmemset-vx wmemset-c \ ++sysdep_routines += wmemset wmemset-vx wmemset-c \ + wmemcmp wmemcmp-vx wmemcmp-c + endif + +diff --git a/sysdeps/s390/multiarch/ifunc-impl-list.c b/sysdeps/s390/multiarch/ifunc-impl-list.c +index 7d8031a069bd23ba..b5f55deb7faae9c4 100644 +--- a/sysdeps/s390/multiarch/ifunc-impl-list.c ++++ b/sysdeps/s390/multiarch/ifunc-impl-list.c +@@ -62,6 +62,7 @@ + #include + #include + #include ++#include + + /* Maximum number of IFUNC implementations. */ + #define MAX_IFUNC 3 +@@ -632,6 +633,18 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + ) + #endif /* HAVE_WCSCSPN_IFUNC */ + ++#if HAVE_WMEMCHR_IFUNC ++ IFUNC_IMPL (i, name, wmemchr, ++# if HAVE_WMEMCHR_Z13 ++ IFUNC_IMPL_ADD (array, i, wmemchr, ++ dl_hwcap & HWCAP_S390_VX, WMEMCHR_Z13) ++# endif ++# if HAVE_WMEMCHR_C ++ IFUNC_IMPL_ADD (array, i, wmemchr, 1, WMEMCHR_C) ++# endif ++ ) ++#endif /* HAVE_WMEMCHR_IFUNC */ ++ + #ifdef HAVE_S390_VX_ASM_SUPPORT + + # define IFUNC_VX_IMPL(FUNC) \ +@@ -640,8 +653,6 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + __##FUNC##_vx) \ + IFUNC_IMPL_ADD (array, i, FUNC, 1, __##FUNC##_c)) + +- IFUNC_VX_IMPL (wmemchr); +- + IFUNC_VX_IMPL (wmemset); + + IFUNC_VX_IMPL (wmemcmp); +diff --git a/sysdeps/s390/multiarch/wmemchr-c.c b/sysdeps/s390/wmemchr-c.c +similarity index 59% +rename from sysdeps/s390/multiarch/wmemchr-c.c +rename to sysdeps/s390/wmemchr-c.c +index 089392b512d29187..bb2526e76c41d0c7 100644 +--- a/sysdeps/s390/multiarch/wmemchr-c.c ++++ b/sysdeps/s390/wmemchr-c.c +@@ -16,22 +16,29 @@ + License along with the GNU C Library; if not, see + . */ + +-#if defined HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc) +-# define WMEMCHR __wmemchr_c +- +-# include +-extern __typeof (wmemchr) __wmemchr_c; +-# undef weak_alias +-# define weak_alias(name, alias) +-# ifdef SHARED +-# undef libc_hidden_def +-# define libc_hidden_def(name) \ +- __hidden_ver1 (__wmemchr_c, __GI___wmemchr, __wmemchr_c); +-# undef libc_hidden_weak +-# define libc_hidden_weak(name) \ ++#include ++ ++#if HAVE_WMEMCHR_C ++# if HAVE_WMEMCHR_IFUNC || HAVE_WMEMCHR_Z13 ++# define WMEMCHR WMEMCHR_C ++ ++# undef weak_alias ++# define weak_alias(name, alias) ++ ++# if defined SHARED && IS_IN (libc) ++# undef libc_hidden_weak ++# define libc_hidden_weak(name) ++# undef libc_hidden_def ++# if ! defined HAVE_S390_MIN_Z13_ZARCH_ASM_SUPPORT ++# define libc_hidden_def(name) \ ++ __hidden_ver1 (__wmemchr_c, __GI_wmemchr, __wmemchr_c) __attribute__((weak)); \ + strong_alias (__wmemchr_c, __wmemchr_c_1); \ +- __hidden_ver1 (__wmemchr_c_1, __GI_wmemchr, __wmemchr_c_1); +-# endif /* SHARED */ ++ __hidden_ver1 (__wmemchr_c_1, __GI___wmemchr, __wmemchr_c_1); ++# else ++# define libc_hidden_def(name) ++# endif ++# endif ++# endif + + # include +-#endif /* HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc) */ ++#endif +diff --git a/sysdeps/s390/multiarch/wmemchr-vx.S b/sysdeps/s390/wmemchr-vx.S +similarity index 92% +rename from sysdeps/s390/multiarch/wmemchr-vx.S +rename to sysdeps/s390/wmemchr-vx.S +index db057b579a7230f0..72e9ef59af77b8f7 100644 +--- a/sysdeps/s390/multiarch/wmemchr-vx.S ++++ b/sysdeps/s390/wmemchr-vx.S +@@ -16,7 +16,8 @@ + License along with the GNU C Library; if not, see + . */ + +-#if defined HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc) ++#include ++#if HAVE_WMEMCHR_Z13 + + # include "sysdep.h" + # include "asm-syntax.h" +@@ -38,7 +39,7 @@ + -v17=index of found c + -v18=c replicated + */ +-ENTRY(__wmemchr_vx) ++ENTRY(WMEMCHR_Z13) + .machine "z13" + .machinemode "zarch_nohighgprs" + +@@ -161,6 +162,17 @@ ENTRY(__wmemchr_vx) + + j .Llt64 + .Lfallback: +- jg __wmemchr_c +-END(__wmemchr_vx) +-#endif /* HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc) */ ++ jg WMEMCHR_C ++END(WMEMCHR_Z13) ++ ++# if ! HAVE_WMEMCHR_IFUNC ++strong_alias (WMEMCHR_Z13, __wmemchr) ++weak_alias (__wmemchr, wmemchr) ++# endif ++ ++# if defined HAVE_S390_MIN_Z13_ZARCH_ASM_SUPPORT \ ++ && defined SHARED && IS_IN (libc) ++strong_alias (WMEMCHR_Z13, __GI___wmemchr) ++weak_alias (WMEMCHR_Z13, __GI_wmemchr) ++# endif ++#endif +diff --git a/sysdeps/s390/multiarch/wmemchr.c b/sysdeps/s390/wmemchr.c +similarity index 70% +rename from sysdeps/s390/multiarch/wmemchr.c +rename to sysdeps/s390/wmemchr.c +index 6b55c1d7fa10afb9..0d2fbb22c6d65a97 100644 +--- a/sysdeps/s390/multiarch/wmemchr.c ++++ b/sysdeps/s390/wmemchr.c +@@ -16,7 +16,9 @@ + License along with the GNU C Library; if not, see + . */ + +-#if defined HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc) ++#include ++ ++#if HAVE_WMEMCHR_IFUNC + # define wmemchr __redirect_wmemchr + # define __wmemchr __redirect___wmemchr + # include +@@ -24,9 +26,18 @@ + # undef __wmemchr + # include + +-s390_vx_libc_ifunc_redirected (__redirect___wmemchr, __wmemchr) +-weak_alias (__wmemchr, wmemchr) ++# if HAVE_WMEMCHR_C ++extern __typeof (__redirect___wmemchr) WMEMCHR_C attribute_hidden; ++# endif + +-#else +-# include +-#endif /* !(defined HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc)) */ ++# if HAVE_WMEMCHR_Z13 ++extern __typeof (__redirect___wmemchr) WMEMCHR_Z13 attribute_hidden; ++# endif ++ ++s390_libc_ifunc_expr (__redirect___wmemchr, __wmemchr, ++ (HAVE_WMEMCHR_Z13 && (hwcap & HWCAP_S390_VX)) ++ ? WMEMCHR_Z13 ++ : WMEMCHR_DEFAULT ++ ) ++weak_alias (__wmemchr, wmemchr) ++#endif diff --git a/SOURCES/glibc-rh1659438-53.patch b/SOURCES/glibc-rh1659438-53.patch new file mode 100644 index 0000000..7d8150d --- /dev/null +++ b/SOURCES/glibc-rh1659438-53.patch @@ -0,0 +1,292 @@ +commit d2a7436c1c6144bbba2eb2a7b25db9b90515f0e6 +Author: Stefan Liebler +Date: Tue Dec 18 13:57:24 2018 +0100 + + S390: Refactor wmemset ifunc handling. + + The ifunc handling for wmemset is adjusted in order to omit ifunc + if the minimum architecture level already supports newer CPUs by default. + Unfortunately the c ifunc variant can't be omitted at all as it is used + by the z13 ifunc variant as fallback if the pointers are not 4-byte aligned. + Glibc internal calls will use the "newer" ifunc variant. + + ChangeLog: + + * sysdeps/s390/multiarch/Makefile + (sysdep_routines): Remove wmemset variants. + * sysdeps/s390/Makefile (sysdep_routines): Add wmemset variants. + * sysdeps/s390/multiarch/ifunc-impl-list.c + (__libc_ifunc_impl_list): Refactor ifunc handling for wmemset. + * sysdeps/s390/multiarch/wmemset-c.c: Move to ... + * sysdeps/s390/wmemset-c.c: ... here and adjust ifunc handling. + * sysdeps/s390/multiarch/wmemset-vx.S: Move to ... + * sysdeps/s390/wmemset-vx.S: ... here and adjust ifunc handling. + * sysdeps/s390/multiarch/wmemset.c: Move to ... + * sysdeps/s390/wmemset.c: ... here and adjust ifunc handling. + * sysdeps/s390/ifunc-wmemset.h: New file. + +diff --git a/sysdeps/s390/Makefile b/sysdeps/s390/Makefile +index fdfd1c605c28ddc7..f9a71276331b396a 100644 +--- a/sysdeps/s390/Makefile ++++ b/sysdeps/s390/Makefile +@@ -76,5 +76,6 @@ sysdep_routines += wcslen wcslen-vx wcslen-c \ + wcsspn wcsspn-vx wcsspn-c \ + wcspbrk wcspbrk-vx wcspbrk-c \ + wcscspn wcscspn-vx wcscspn-c \ +- wmemchr wmemchr-vx wmemchr-c ++ wmemchr wmemchr-vx wmemchr-c \ ++ wmemset wmemset-vx wmemset-c + endif +diff --git a/sysdeps/s390/ifunc-wmemset.h b/sysdeps/s390/ifunc-wmemset.h +new file mode 100644 +index 0000000000000000..c9d1d17c3bfc7e9e +--- /dev/null ++++ b/sysdeps/s390/ifunc-wmemset.h +@@ -0,0 +1,53 @@ ++/* wmemset variant information on S/390 version. ++ 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 ++ . */ ++ ++#if defined USE_MULTIARCH && IS_IN (libc) \ ++ && ! defined HAVE_S390_MIN_Z13_ZARCH_ASM_SUPPORT ++# define HAVE_WMEMSET_IFUNC 1 ++#else ++# define HAVE_WMEMSET_IFUNC 0 ++#endif ++ ++#ifdef HAVE_S390_VX_ASM_SUPPORT ++# define HAVE_WMEMSET_IFUNC_AND_VX_SUPPORT HAVE_WMEMSET_IFUNC ++#else ++# define HAVE_WMEMSET_IFUNC_AND_VX_SUPPORT 0 ++#endif ++ ++#if defined HAVE_S390_MIN_Z13_ZARCH_ASM_SUPPORT ++# define WMEMSET_DEFAULT WMEMSET_Z13 ++/* The z13 ifunc variant is using the common code variant as fallback! */ ++# define HAVE_WMEMSET_C 1 ++# define HAVE_WMEMSET_Z13 1 ++#else ++# define WMEMSET_DEFAULT WMEMSET_C ++# define HAVE_WMEMSET_C 1 ++# define HAVE_WMEMSET_Z13 HAVE_WMEMSET_IFUNC_AND_VX_SUPPORT ++#endif ++ ++#if HAVE_WMEMSET_C ++# define WMEMSET_C __wmemset_c ++#else ++# define WMEMSET_C NULL ++#endif ++ ++#if HAVE_WMEMSET_Z13 ++# define WMEMSET_Z13 __wmemset_vx ++#else ++# define WMEMSET_Z13 NULL ++#endif +diff --git a/sysdeps/s390/multiarch/Makefile b/sysdeps/s390/multiarch/Makefile +index 92e28dc45ddbae37..cc6dd7adb10ee8ad 100644 +--- a/sysdeps/s390/multiarch/Makefile ++++ b/sysdeps/s390/multiarch/Makefile +@@ -1,6 +1,5 @@ + ifeq ($(subdir),wcsmbs) +-sysdep_routines += wmemset wmemset-vx wmemset-c \ +- wmemcmp wmemcmp-vx wmemcmp-c ++sysdep_routines += wmemcmp wmemcmp-vx wmemcmp-c + endif + + ifeq ($(subdir),iconvdata) +diff --git a/sysdeps/s390/multiarch/ifunc-impl-list.c b/sysdeps/s390/multiarch/ifunc-impl-list.c +index b5f55deb7faae9c4..7040959269c1612b 100644 +--- a/sysdeps/s390/multiarch/ifunc-impl-list.c ++++ b/sysdeps/s390/multiarch/ifunc-impl-list.c +@@ -63,6 +63,7 @@ + #include + #include + #include ++#include + + /* Maximum number of IFUNC implementations. */ + #define MAX_IFUNC 3 +@@ -645,6 +646,18 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + ) + #endif /* HAVE_WMEMCHR_IFUNC */ + ++#if HAVE_WMEMSET_IFUNC ++ IFUNC_IMPL (i, name, wmemset, ++# if HAVE_WMEMSET_Z13 ++ IFUNC_IMPL_ADD (array, i, wmemset, ++ dl_hwcap & HWCAP_S390_VX, WMEMSET_Z13) ++# endif ++# if HAVE_WMEMSET_C ++ IFUNC_IMPL_ADD (array, i, wmemset, 1, WMEMSET_C) ++# endif ++ ) ++#endif /* HAVE_WMEMSET_IFUNC */ ++ + #ifdef HAVE_S390_VX_ASM_SUPPORT + + # define IFUNC_VX_IMPL(FUNC) \ +@@ -653,8 +666,6 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + __##FUNC##_vx) \ + IFUNC_IMPL_ADD (array, i, FUNC, 1, __##FUNC##_c)) + +- IFUNC_VX_IMPL (wmemset); +- + IFUNC_VX_IMPL (wmemcmp); + + #endif /* HAVE_S390_VX_ASM_SUPPORT */ +diff --git a/sysdeps/s390/multiarch/wmemset-c.c b/sysdeps/s390/wmemset-c.c +similarity index 59% +rename from sysdeps/s390/multiarch/wmemset-c.c +rename to sysdeps/s390/wmemset-c.c +index 1969cf93dcf08892..01e625496d8c2e4e 100644 +--- a/sysdeps/s390/multiarch/wmemset-c.c ++++ b/sysdeps/s390/wmemset-c.c +@@ -16,22 +16,29 @@ + License along with the GNU C Library; if not, see + . */ + +-#if defined HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc) +-# define WMEMSET __wmemset_c +- +-# include +-extern __typeof (__wmemset) __wmemset_c; +-# undef weak_alias +-# define weak_alias(name, alias) +-# ifdef SHARED +-# undef libc_hidden_def +-# define libc_hidden_def(name) \ +- __hidden_ver1 (__wmemset_c, __GI___wmemset, __wmemset_c); +-# undef libc_hidden_weak +-# define libc_hidden_weak(name) \ ++#include ++ ++#if HAVE_WMEMSET_C ++# if HAVE_WMEMSET_IFUNC || HAVE_WMEMSET_Z13 ++# define WMEMSET WMEMSET_C ++ ++# undef weak_alias ++# define weak_alias(name, alias) ++ ++# if defined SHARED && IS_IN (libc) ++# undef libc_hidden_weak ++# define libc_hidden_weak(name) ++# undef libc_hidden_def ++# if ! defined HAVE_S390_MIN_Z13_ZARCH_ASM_SUPPORT ++# define libc_hidden_def(name) \ ++ __hidden_ver1 (__wmemset_c, __GI_wmemset, __wmemset_c) __attribute__((weak)); \ + strong_alias (__wmemset_c, __wmemset_c_1); \ +- __hidden_ver1 (__wmemset_c_1, __GI_wmemset, __wmemset_c_1); +-# endif /* SHARED */ ++ __hidden_ver1 (__wmemset_c_1, __GI___wmemset, __wmemset_c_1); ++# else ++# define libc_hidden_def(name) ++# endif ++# endif ++# endif + + # include +-#endif /* HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc) */ ++#endif +diff --git a/sysdeps/s390/multiarch/wmemset-vx.S b/sysdeps/s390/wmemset-vx.S +similarity index 91% +rename from sysdeps/s390/multiarch/wmemset-vx.S +rename to sysdeps/s390/wmemset-vx.S +index 0c2f6337b0e554ec..4b6050b5accd732b 100644 +--- a/sysdeps/s390/multiarch/wmemset-vx.S ++++ b/sysdeps/s390/wmemset-vx.S +@@ -16,7 +16,8 @@ + License along with the GNU C Library; if not, see + . */ + +-#if defined HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc) ++#include ++#if HAVE_WMEMSET_Z13 + + # include "sysdep.h" + # include "asm-syntax.h" +@@ -38,7 +39,7 @@ + -v17,v18,v19=copy of v16 for vstm + -v31=saved dest for return + */ +-ENTRY(__wmemset_vx) ++ENTRY(WMEMSET_Z13) + .machine "z13" + .machinemode "zarch_nohighgprs" + +@@ -137,6 +138,17 @@ ENTRY(__wmemset_vx) + br %r14 + .Lfallback: + srlg %r4,%r4,2 /* Convert byte-count to character-count. */ +- jg __wmemset_c +-END(__wmemset_vx) +-#endif /* HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc) */ ++ jg WMEMSET_C ++END(WMEMSET_Z13) ++ ++# if ! HAVE_WMEMSET_IFUNC ++strong_alias (WMEMSET_Z13, __wmemset) ++weak_alias (__wmemset, wmemset) ++# endif ++ ++# if defined HAVE_S390_MIN_Z13_ZARCH_ASM_SUPPORT \ ++ && defined SHARED && IS_IN (libc) ++strong_alias (WMEMSET_Z13, __GI___wmemset) ++weak_alias (WMEMSET_Z13, __GI_wmemset) ++# endif ++#endif +diff --git a/sysdeps/s390/multiarch/wmemset.c b/sysdeps/s390/wmemset.c +similarity index 70% +rename from sysdeps/s390/multiarch/wmemset.c +rename to sysdeps/s390/wmemset.c +index 149b4814708d820a..6118754d1df71948 100644 +--- a/sysdeps/s390/multiarch/wmemset.c ++++ b/sysdeps/s390/wmemset.c +@@ -16,7 +16,9 @@ + License along with the GNU C Library; if not, see + . */ + +-#if defined HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc) ++#include ++ ++#if HAVE_WMEMSET_IFUNC + # define wmemset __redirect_wmemset + # define __wmemset __redirect___wmemset + # include +@@ -24,9 +26,18 @@ + # undef __wmemset + # include + +-s390_vx_libc_ifunc_redirected (__redirect___wmemset, __wmemset) +-weak_alias (__wmemset, wmemset) ++# if HAVE_WMEMSET_C ++extern __typeof (__redirect___wmemset) WMEMSET_C attribute_hidden; ++# endif + +-#else +-# include +-#endif /* !(defined HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc)) */ ++# if HAVE_WMEMSET_Z13 ++extern __typeof (__redirect___wmemset) WMEMSET_Z13 attribute_hidden; ++# endif ++ ++s390_libc_ifunc_expr (__redirect___wmemset, __wmemset, ++ (HAVE_WMEMSET_Z13 && (hwcap & HWCAP_S390_VX)) ++ ? WMEMSET_Z13 ++ : WMEMSET_DEFAULT ++ ) ++weak_alias (__wmemset, wmemset) ++#endif diff --git a/SOURCES/glibc-rh1659438-54.patch b/SOURCES/glibc-rh1659438-54.patch new file mode 100644 index 0000000..2bd37c0 --- /dev/null +++ b/SOURCES/glibc-rh1659438-54.patch @@ -0,0 +1,246 @@ +commit 25654a8c74dce51e162c29749c6bd6d2a67490e6 +Author: Stefan Liebler +Date: Tue Dec 18 13:57:25 2018 +0100 + + S390: Refactor wmemcmp ifunc handling. + + The ifunc handling for wmemcmp is adjusted in order to omit ifunc + variants if those will never be used as the minimum architecture level + already supports newer CPUs by default. + + ChangeLog: + + * sysdeps/s390/multiarch/Makefile + (sysdep_routines): Remove wmemcmp variants. + * sysdeps/s390/Makefile (sysdep_routines): Add wmemcmp variants. + * sysdeps/s390/multiarch/ifunc-impl-list.c + (__libc_ifunc_impl_list): Refactor ifunc handling for wmemcmp. + * sysdeps/s390/multiarch/wmemcmp-c.c: Move to ... + * sysdeps/s390/wmemcmp-c.c: ... here and adjust ifunc handling. + * sysdeps/s390/multiarch/wmemcmp-vx.S: Move to ... + * sysdeps/s390/wmemcmp-vx.S: ... here and adjust ifunc handling. + * sysdeps/s390/multiarch/wmemcmp.c: Move to ... + * sysdeps/s390/wmemcmp.c: ... here and adjust ifunc handling. + * sysdeps/s390/ifunc-wmemcmp.h: New file. + +diff --git a/sysdeps/s390/Makefile b/sysdeps/s390/Makefile +index f9a71276331b396a..3f7de6613c343819 100644 +--- a/sysdeps/s390/Makefile ++++ b/sysdeps/s390/Makefile +@@ -77,5 +77,6 @@ sysdep_routines += wcslen wcslen-vx wcslen-c \ + wcspbrk wcspbrk-vx wcspbrk-c \ + wcscspn wcscspn-vx wcscspn-c \ + wmemchr wmemchr-vx wmemchr-c \ +- wmemset wmemset-vx wmemset-c ++ wmemset wmemset-vx wmemset-c \ ++ wmemcmp wmemcmp-vx wmemcmp-c + endif +diff --git a/sysdeps/s390/ifunc-wmemcmp.h b/sysdeps/s390/ifunc-wmemcmp.h +new file mode 100644 +index 0000000000000000..1b38a014590ec060 +--- /dev/null ++++ b/sysdeps/s390/ifunc-wmemcmp.h +@@ -0,0 +1,52 @@ ++/* wmemcmp variant information on S/390 version. ++ 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 ++ . */ ++ ++#if defined USE_MULTIARCH && IS_IN (libc) \ ++ && ! defined HAVE_S390_MIN_Z13_ZARCH_ASM_SUPPORT ++# define HAVE_WMEMCMP_IFUNC 1 ++#else ++# define HAVE_WMEMCMP_IFUNC 0 ++#endif ++ ++#ifdef HAVE_S390_VX_ASM_SUPPORT ++# define HAVE_WMEMCMP_IFUNC_AND_VX_SUPPORT HAVE_WMEMCMP_IFUNC ++#else ++# define HAVE_WMEMCMP_IFUNC_AND_VX_SUPPORT 0 ++#endif ++ ++#if defined HAVE_S390_MIN_Z13_ZARCH_ASM_SUPPORT ++# define WMEMCMP_DEFAULT WMEMCMP_Z13 ++# define HAVE_WMEMCMP_C 0 ++# define HAVE_WMEMCMP_Z13 1 ++#else ++# define WMEMCMP_DEFAULT WMEMCMP_C ++# define HAVE_WMEMCMP_C 1 ++# define HAVE_WMEMCMP_Z13 HAVE_WMEMCMP_IFUNC_AND_VX_SUPPORT ++#endif ++ ++#if HAVE_WMEMCMP_C ++# define WMEMCMP_C __wmemcmp_c ++#else ++# define WMEMCMP_C NULL ++#endif ++ ++#if HAVE_WMEMCMP_Z13 ++# define WMEMCMP_Z13 __wmemcmp_vx ++#else ++# define WMEMCMP_Z13 NULL ++#endif +diff --git a/sysdeps/s390/multiarch/Makefile b/sysdeps/s390/multiarch/Makefile +index cc6dd7adb10ee8ad..fec36153047e4585 100644 +--- a/sysdeps/s390/multiarch/Makefile ++++ b/sysdeps/s390/multiarch/Makefile +@@ -1,7 +1,3 @@ +-ifeq ($(subdir),wcsmbs) +-sysdep_routines += wmemcmp wmemcmp-vx wmemcmp-c +-endif +- + ifeq ($(subdir),iconvdata) + override define generate-8bit-table + $(make-target-directory) +diff --git a/sysdeps/s390/multiarch/ifunc-impl-list.c b/sysdeps/s390/multiarch/ifunc-impl-list.c +index 7040959269c1612b..177c5fd6fe269d9b 100644 +--- a/sysdeps/s390/multiarch/ifunc-impl-list.c ++++ b/sysdeps/s390/multiarch/ifunc-impl-list.c +@@ -64,6 +64,7 @@ + #include + #include + #include ++#include + + /* Maximum number of IFUNC implementations. */ + #define MAX_IFUNC 3 +@@ -658,17 +659,17 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + ) + #endif /* HAVE_WMEMSET_IFUNC */ + +-#ifdef HAVE_S390_VX_ASM_SUPPORT +- +-# define IFUNC_VX_IMPL(FUNC) \ +- IFUNC_IMPL (i, name, FUNC, \ +- IFUNC_IMPL_ADD (array, i, FUNC, dl_hwcap & HWCAP_S390_VX, \ +- __##FUNC##_vx) \ +- IFUNC_IMPL_ADD (array, i, FUNC, 1, __##FUNC##_c)) +- +- IFUNC_VX_IMPL (wmemcmp); +- +-#endif /* HAVE_S390_VX_ASM_SUPPORT */ ++#if HAVE_WMEMCMP_IFUNC ++ IFUNC_IMPL (i, name, wmemcmp, ++# if HAVE_WMEMCMP_Z13 ++ IFUNC_IMPL_ADD (array, i, wmemcmp, ++ dl_hwcap & HWCAP_S390_VX, WMEMCMP_Z13) ++# endif ++# if HAVE_WMEMCMP_C ++ IFUNC_IMPL_ADD (array, i, wmemcmp, 1, WMEMCMP_C) ++# endif ++ ) ++#endif /* HAVE_WMEMCMP_IFUNC */ + + return i; + } +diff --git a/sysdeps/s390/multiarch/wmemcmp-c.c b/sysdeps/s390/wmemcmp-c.c +similarity index 85% +rename from sysdeps/s390/multiarch/wmemcmp-c.c +rename to sysdeps/s390/wmemcmp-c.c +index 2fd39d501360e6f8..0c73636adda82f8b 100644 +--- a/sysdeps/s390/multiarch/wmemcmp-c.c ++++ b/sysdeps/s390/wmemcmp-c.c +@@ -16,11 +16,12 @@ + License along with the GNU C Library; if not, see + . */ + +-#if defined HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc) +-# define WMEMCMP __wmemcmp_c ++#include + +-# include +-extern __typeof (wmemcmp) __wmemcmp_c; ++#if HAVE_WMEMCMP_C ++# if HAVE_WMEMCMP_IFUNC ++# define WMEMCMP WMEMCMP_C ++# endif + + # include + #endif +diff --git a/sysdeps/s390/multiarch/wmemcmp-vx.S b/sysdeps/s390/wmemcmp-vx.S +similarity index 95% +rename from sysdeps/s390/multiarch/wmemcmp-vx.S +rename to sysdeps/s390/wmemcmp-vx.S +index e2fc21e4192b0dd8..87ae21b4f13c5d69 100644 +--- a/sysdeps/s390/multiarch/wmemcmp-vx.S ++++ b/sysdeps/s390/wmemcmp-vx.S +@@ -16,7 +16,8 @@ + License along with the GNU C Library; if not, see + . */ + +-#if defined HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc) ++#include ++#if HAVE_WMEMCMP_Z13 + + # include "sysdep.h" + # include "asm-syntax.h" +@@ -37,7 +38,7 @@ + -v17=part of s2 + -v18=index of unequal + */ +-ENTRY(__wmemcmp_vx) ++ENTRY(WMEMCMP_Z13) + .machine "z13" + .machinemode "zarch_nohighgprs" + +@@ -145,5 +146,9 @@ ENTRY(__wmemcmp_vx) + la %r2,0(%r5,%r2) + la %r3,0(%r5,%r3) + j .Lremaining +-END(__wmemcmp_vx) +-#endif /* HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc) */ ++END(WMEMCMP_Z13) ++ ++# if ! HAVE_WMEMCMP_IFUNC ++strong_alias (WMEMCMP_Z13, wmemcmp) ++# endif ++#endif +diff --git a/sysdeps/s390/multiarch/wmemcmp.c b/sysdeps/s390/wmemcmp.c +similarity index 69% +rename from sysdeps/s390/multiarch/wmemcmp.c +rename to sysdeps/s390/wmemcmp.c +index a4cb440c452fd6a9..6c8ca5f0e8ffdb50 100644 +--- a/sysdeps/s390/multiarch/wmemcmp.c ++++ b/sysdeps/s390/wmemcmp.c +@@ -16,12 +16,23 @@ + License along with the GNU C Library; if not, see + . */ + +-#if defined HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc) ++#include ++ ++#if HAVE_WMEMCMP_IFUNC + # include + # include + +-s390_vx_libc_ifunc2 (__wmemcmp, wmemcmp) ++# if HAVE_WMEMCMP_C ++extern __typeof (wmemcmp) WMEMCMP_C attribute_hidden; ++# endif ++ ++# if HAVE_WMEMCMP_Z13 ++extern __typeof (wmemcmp) WMEMCMP_Z13 attribute_hidden; ++# endif + +-#else +-# include +-#endif /* !(defined HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc)) */ ++s390_libc_ifunc_expr (wmemcmp, wmemcmp, ++ (HAVE_WMEMCMP_Z13 && (hwcap & HWCAP_S390_VX)) ++ ? WMEMCMP_Z13 ++ : WMEMCMP_DEFAULT ++ ) ++#endif diff --git a/SOURCES/glibc-rh1659438-55.patch b/SOURCES/glibc-rh1659438-55.patch new file mode 100644 index 0000000..e4be220 --- /dev/null +++ b/SOURCES/glibc-rh1659438-55.patch @@ -0,0 +1,53 @@ +commit 12f0dcb8da2c7c74d673583ec3286c0354273f52 +Author: Stefan Liebler +Date: Tue Dec 18 13:57:25 2018 +0100 + + S390: Refactor gconv_simple ifunc handling. + + The ifunc handling for various __gconv_transform_* functions + which are using IFUNC on s390x are adjusted in order to omit ifunc + if the minimum architecture level already supports newer CPUs by default. + Instead those functions are just an alias to the vector variants. + + Furthermore the ifunc-macro s390_libc_ifunc_expr is now used instead of + s390_vx_libc_ifunc. + + ChangeLog: + + * sysdeps/s390/multiarch/gconv_simple.c (ICONV_VX_IFUNC): + Define macro dependent on HAVE_S390_MIN_Z13_ZARCH_ASM_SUPPORT. + +diff --git a/sysdeps/s390/multiarch/gconv_simple.c b/sysdeps/s390/multiarch/gconv_simple.c +index aaa1ebf74acf4dde..078d992c13eb548c 100644 +--- a/sysdeps/s390/multiarch/gconv_simple.c ++++ b/sysdeps/s390/multiarch/gconv_simple.c +@@ -27,17 +27,18 @@ + + # define ICONV_C_NAME(NAME) __##NAME##_c + # define ICONV_VX_NAME(NAME) __##NAME##_vx +-# define ICONV_VX_IFUNC(FUNC) \ +- extern __typeof (ICONV_C_NAME (FUNC)) __##FUNC; \ +- s390_vx_libc_ifunc (__##FUNC) \ +- int FUNC (struct __gconv_step *step, struct __gconv_step_data *data, \ +- const unsigned char **inptrp, const unsigned char *inend, \ +- unsigned char **outbufstart, size_t *irreversible, \ +- int do_flush, int consume_incomplete) \ +- { \ +- return __##FUNC (step, data, inptrp, inend,outbufstart, \ +- irreversible, do_flush, consume_incomplete); \ +- } ++# ifdef HAVE_S390_MIN_Z13_ZARCH_ASM_SUPPORT ++/* We support z13 instructions by default -> Just use the vector variant. */ ++# define ICONV_VX_IFUNC(FUNC) strong_alias (ICONV_VX_NAME (FUNC), FUNC) ++# else ++/* We have to use ifunc to determine if z13 instructions are supported. */ ++# define ICONV_VX_IFUNC(FUNC) \ ++ s390_libc_ifunc_expr (ICONV_C_NAME (FUNC), FUNC, \ ++ (hwcap & HWCAP_S390_VX) \ ++ ? ICONV_VX_NAME (FUNC) \ ++ : ICONV_C_NAME (FUNC) \ ++ ) ++# endif + # define ICONV_VX_SINGLE(NAME) \ + static __typeof (NAME##_single) __##NAME##_vx_single __attribute__((alias(#NAME "_single"))); + diff --git a/SOURCES/glibc-rh1659438-56.patch b/SOURCES/glibc-rh1659438-56.patch new file mode 100644 index 0000000..934b8da --- /dev/null +++ b/SOURCES/glibc-rh1659438-56.patch @@ -0,0 +1,152 @@ +commit 80190d2b0e3f48d973724218f37d2da5bf1a20ab +Author: Stefan Liebler +Date: Tue Dec 18 13:57:25 2018 +0100 + + S390: Cleanup ifunc-resolve.h. + + The ifunc macros s390_vx_libc* are no longer used and + can be removed as all users are now relying on + s390_libc_ifunc_expr. + + The same applies to s390_libc_ifunc. The macro + s390_libc_ifunc_init is now renamed to + s390_libc_ifunc_expr_stfle_init and the users are + adjusted accordingly. + + ChangeLog: + + * sysdeps/s390/multiarch/ifunc-resolve.h + (s390_vx_libc_ifunc, s390_vx_libc_ifunc_redirected, + s390_vx_libc_ifunc2, s390_vx_libc_ifunc_init, + s390_vx_libc_ifunc2_redirected, s390_libc_ifunc): + Delete macro definition. + (s390_libc_ifunc_init): Rename to + s390_libc_ifunc_expr_stfle_init. + * sysdeps/s390/bzero: Use + s390_libc_ifunc_expr_stfle_init instead of + s390_libc_ifunc_init. + * sysdeps/s390/memcmp.c: Likewise. + * sysdeps/s390/memcpy.c: Likewise. + * sysdeps/s390/mempcpy.c: Likewise. + * sysdeps/s390/memset.c: Likewise. + +diff --git a/sysdeps/s390/bzero.c b/sysdeps/s390/bzero.c +index 9f8d95781bf2fb68..6b5d471c40250543 100644 +--- a/sysdeps/s390/bzero.c ++++ b/sysdeps/s390/bzero.c +@@ -35,7 +35,7 @@ extern __typeof (__bzero) BZERO_Z196 attribute_hidden; + + s390_libc_ifunc_expr (__bzero, __bzero, + ({ +- s390_libc_ifunc_init (); ++ s390_libc_ifunc_expr_stfle_init (); + (HAVE_MEMSET_Z196 && S390_IS_Z196 (stfle_bits)) + ? BZERO_Z196 + : (HAVE_MEMSET_Z10 && S390_IS_Z10 (stfle_bits)) +diff --git a/sysdeps/s390/memcmp.c b/sysdeps/s390/memcmp.c +index 952ff6af7364fd92..6d9276320abbe332 100644 +--- a/sysdeps/s390/memcmp.c ++++ b/sysdeps/s390/memcmp.c +@@ -37,7 +37,7 @@ extern __typeof (__redirect_memcmp) MEMCMP_Z196 attribute_hidden; + + s390_libc_ifunc_expr (__redirect_memcmp, memcmp, + ({ +- s390_libc_ifunc_init (); ++ s390_libc_ifunc_expr_stfle_init (); + (HAVE_MEMCMP_Z196 && S390_IS_Z196 (stfle_bits)) + ? MEMCMP_Z196 + : (HAVE_MEMCMP_Z10 && S390_IS_Z10 (stfle_bits)) +diff --git a/sysdeps/s390/memcpy.c b/sysdeps/s390/memcpy.c +index 90a53ac27d4be755..0ff24f18cf3600da 100644 +--- a/sysdeps/s390/memcpy.c ++++ b/sysdeps/s390/memcpy.c +@@ -38,7 +38,7 @@ extern __typeof (__redirect_memcpy) MEMCPY_Z196 attribute_hidden; + + s390_libc_ifunc_expr (__redirect_memcpy, memcpy, + ({ +- s390_libc_ifunc_init (); ++ s390_libc_ifunc_expr_stfle_init (); + (HAVE_MEMCPY_Z196 && S390_IS_Z196 (stfle_bits)) + ? MEMCPY_Z196 + : (HAVE_MEMCPY_Z10 && S390_IS_Z10 (stfle_bits)) +diff --git a/sysdeps/s390/mempcpy.c b/sysdeps/s390/mempcpy.c +index a6a237312659c2c1..b687b3362034bfb0 100644 +--- a/sysdeps/s390/mempcpy.c ++++ b/sysdeps/s390/mempcpy.c +@@ -42,7 +42,7 @@ extern __typeof (__redirect___mempcpy) MEMPCPY_Z196 attribute_hidden; + + s390_libc_ifunc_expr (__redirect___mempcpy, __mempcpy, + ({ +- s390_libc_ifunc_init (); ++ s390_libc_ifunc_expr_stfle_init (); + (HAVE_MEMCPY_Z196 && S390_IS_Z196 (stfle_bits)) + ? MEMPCPY_Z196 + : (HAVE_MEMCPY_Z10 && S390_IS_Z10 (stfle_bits)) +diff --git a/sysdeps/s390/memset.c b/sysdeps/s390/memset.c +index 57a35aebc7d3c794..75b011f1a24f39bc 100644 +--- a/sysdeps/s390/memset.c ++++ b/sysdeps/s390/memset.c +@@ -37,7 +37,7 @@ extern __typeof (__redirect_memset) MEMSET_Z196 attribute_hidden; + + s390_libc_ifunc_expr (__redirect_memset, memset, + ({ +- s390_libc_ifunc_init (); ++ s390_libc_ifunc_expr_stfle_init (); + (HAVE_MEMSET_Z196 && S390_IS_Z196 (stfle_bits)) + ? MEMSET_Z196 + : (HAVE_MEMSET_Z10 && S390_IS_Z10 (stfle_bits)) +diff --git a/sysdeps/s390/multiarch/ifunc-resolve.h b/sysdeps/s390/multiarch/ifunc-resolve.h +index b7e20abc59638251..b2be015401313d4b 100644 +--- a/sysdeps/s390/multiarch/ifunc-resolve.h ++++ b/sysdeps/s390/multiarch/ifunc-resolve.h +@@ -40,7 +40,7 @@ + ".machine pop" "\n" \ + : "=QS" (STFLE_BITS), "+d" (reg0) \ + : : "cc"); +-#define s390_libc_ifunc_init() \ ++#define s390_libc_ifunc_expr_stfle_init() \ + unsigned long long stfle_bits = 0ULL; \ + if (__glibc_likely ((hwcap & HWCAP_S390_STFLE) \ + && (hwcap & HWCAP_S390_ZARCH) \ +@@ -49,41 +49,6 @@ + S390_STORE_STFLE (stfle_bits); \ + } + +-#define s390_libc_ifunc(TYPE_FUNC, RESOLVERFUNC, FUNC) \ +- /* Make the declarations of the optimized functions hidden in order +- to prevent GOT slots being generated for them. */ \ +- extern __typeof (TYPE_FUNC) RESOLVERFUNC##_z196 attribute_hidden; \ +- extern __typeof (TYPE_FUNC) RESOLVERFUNC##_z10 attribute_hidden; \ +- extern __typeof (TYPE_FUNC) RESOLVERFUNC##_default attribute_hidden; \ +- __ifunc (TYPE_FUNC, FUNC, \ +- __glibc_likely (S390_IS_Z196 (stfle_bits)) \ +- ? RESOLVERFUNC##_z196 \ +- : __glibc_likely (S390_IS_Z10 (stfle_bits)) \ +- ? RESOLVERFUNC##_z10 \ +- : RESOLVERFUNC##_default, \ +- unsigned long int hwcap, s390_libc_ifunc_init); +- +-#define s390_vx_libc_ifunc(FUNC) \ +- s390_vx_libc_ifunc2_redirected(FUNC, FUNC, FUNC) +- +-#define s390_vx_libc_ifunc_redirected(TYPE_FUNC, FUNC) \ +- s390_vx_libc_ifunc2_redirected(TYPE_FUNC, FUNC, FUNC) +- +-#define s390_vx_libc_ifunc2(RESOLVERFUNC, FUNC) \ +- s390_vx_libc_ifunc2_redirected(FUNC, RESOLVERFUNC, FUNC) +- +-#define s390_vx_libc_ifunc_init() +-#define s390_vx_libc_ifunc2_redirected(TYPE_FUNC, RESOLVERFUNC, FUNC) \ +- /* Make the declarations of the optimized functions hidden in order +- to prevent GOT slots being generated for them. */ \ +- extern __typeof (TYPE_FUNC) RESOLVERFUNC##_vx attribute_hidden; \ +- extern __typeof (TYPE_FUNC) RESOLVERFUNC##_c attribute_hidden; \ +- __ifunc (TYPE_FUNC, FUNC, \ +- (hwcap & HWCAP_S390_VX) \ +- ? RESOLVERFUNC##_vx \ +- : RESOLVERFUNC##_c, \ +- unsigned long int hwcap, s390_vx_libc_ifunc_init); +- + #define s390_libc_ifunc_expr_init() + #define s390_libc_ifunc_expr(TYPE_FUNC, FUNC, EXPR) \ + __ifunc (TYPE_FUNC, FUNC, EXPR, unsigned long int hwcap, \ diff --git a/SOURCES/glibc-rh1659438-57.patch b/SOURCES/glibc-rh1659438-57.patch new file mode 100644 index 0000000..50b5945 --- /dev/null +++ b/SOURCES/glibc-rh1659438-57.patch @@ -0,0 +1,29 @@ +commit 61f5e9470fb397a4c334938ac5a667427d9047df +Author: Stefan Liebler +Date: Thu Mar 21 09:14:26 2019 +0100 + + S390: Mark vx and vxe as important hwcap. + + This patch adds vx and vxe as important hwcaps + which allows one to provide shared libraries + tuned for platforms with non-vx/-vxe, vx or vxe. + + ChangeLog: + + * sysdeps/s390/dl-procinfo.h (HWCAP_IMPORTANT): + Add HWCAP_S390_VX and HWCAP_S390_VXE. + +diff --git a/sysdeps/s390/dl-procinfo.h b/sysdeps/s390/dl-procinfo.h +index b0383bfb4cef7972..f71d64c3ab24e715 100644 +--- a/sysdeps/s390/dl-procinfo.h ++++ b/sysdeps/s390/dl-procinfo.h +@@ -57,7 +57,8 @@ enum + }; + + #define HWCAP_IMPORTANT (HWCAP_S390_ZARCH | HWCAP_S390_LDISP \ +- | HWCAP_S390_EIMM | HWCAP_S390_DFP) ++ | HWCAP_S390_EIMM | HWCAP_S390_DFP \ ++ | HWCAP_S390_VX | HWCAP_S390_VXE) + + /* We cannot provide a general printing function. */ + #define _dl_procinfo(type, word) -1 diff --git a/SOURCES/glibc-rh1659438-58.patch b/SOURCES/glibc-rh1659438-58.patch new file mode 100644 index 0000000..3f16140 --- /dev/null +++ b/SOURCES/glibc-rh1659438-58.patch @@ -0,0 +1,88 @@ +commit 1a7df49c92f62e14d8727f083fd055eba7c91ad9 +Author: Stefan Liebler +Date: Fri Mar 22 11:14:07 2019 +0100 + + S390: Add new hwcap values for new cpu architecture arch13. + + The new hwcap values indicate support for: + -"Vector-Enhancements Facility 2" (tag "vxe2", hwcap 2^15) + -"Vector-Packed-Decimal-Enhancement Facility" (tag "vxp", hwcap 2^16) + -"Enhanced-Sort Facility" (tag "sort", hwcap 2^17) + -"Deflate-Conversion Facility" (tag "dflt", hwcap 2^18) + + The vxe2 hwcap is also marked as important hwcap. + + ChangeLog: + + * sysdeps/s390/dl-procinfo.c (_dl_s390_cap_flags): + Add vxe2, vxp, dflt, sort flags. + * sysdeps/s390/dl-procinfo.h: Add HWCAP_S390_VXRS_EXT2, + HWCAP_S390_VXRS_PDE, HWCAP_S390_SORT, HWCAP_S390_DFLT + capabilities. + (HWCAP_IMPORTANT): Add HWCAP_S390_VXRS_EXT2. + * sysdeps/unix/sysv/linux/s390/bits/hwcap.h + (HWCAP_S390_VXRS_EXT2, HWCAP_S390_VXRS_PDE, HWCAP_S390_SORT, + HWCAP_S390_DFLT): Define. + +diff --git a/sysdeps/s390/dl-procinfo.c b/sysdeps/s390/dl-procinfo.c +index 86c964caff6a1bc4..6ea220a171d8fab7 100644 +--- a/sysdeps/s390/dl-procinfo.c ++++ b/sysdeps/s390/dl-procinfo.c +@@ -46,12 +46,12 @@ + #if !defined PROCINFO_DECL && defined SHARED + ._dl_s390_cap_flags + #else +-PROCINFO_CLASS const char _dl_s390_cap_flags[15][9] ++PROCINFO_CLASS const char _dl_s390_cap_flags[19][9] + #endif + #ifndef PROCINFO_DECL + = { + "esan3", "zarch", "stfle", "msa", "ldisp", "eimm", "dfp", "edat", "etf3eh", +- "highgprs", "te", "vx", "vxd", "vxe", "gs" ++ "highgprs", "te", "vx", "vxd", "vxe", "gs", "vxe2", "vxp", "sort", "dflt" + } + #endif + #if !defined SHARED || defined PROCINFO_DECL +diff --git a/sysdeps/s390/dl-procinfo.h b/sysdeps/s390/dl-procinfo.h +index f71d64c3ab24e715..d03c69fffdbd06de 100644 +--- a/sysdeps/s390/dl-procinfo.h ++++ b/sysdeps/s390/dl-procinfo.h +@@ -21,7 +21,7 @@ + #define _DL_PROCINFO_H 1 + #include + +-#define _DL_HWCAP_COUNT 15 ++#define _DL_HWCAP_COUNT 19 + + #define _DL_PLATFORMS_COUNT 9 + +@@ -54,11 +54,16 @@ enum + HWCAP_S390_VXD = 1 << 12, + HWCAP_S390_VXE = 1 << 13, + HWCAP_S390_GS = 1 << 14, ++ HWCAP_S390_VXRS_EXT2 = 1 << 15, ++ HWCAP_S390_VXRS_PDE = 1 << 16, ++ HWCAP_S390_SORT = 1 << 17, ++ HWCAP_S390_DFLT = 1 << 18, + }; + + #define HWCAP_IMPORTANT (HWCAP_S390_ZARCH | HWCAP_S390_LDISP \ + | HWCAP_S390_EIMM | HWCAP_S390_DFP \ +- | HWCAP_S390_VX | HWCAP_S390_VXE) ++ | HWCAP_S390_VX | HWCAP_S390_VXE \ ++ | HWCAP_S390_VXRS_EXT2) + + /* We cannot provide a general printing function. */ + #define _dl_procinfo(type, word) -1 +diff --git a/sysdeps/unix/sysv/linux/s390/bits/hwcap.h b/sysdeps/unix/sysv/linux/s390/bits/hwcap.h +index 2564712399948375..6b9b59522e3d3bec 100644 +--- a/sysdeps/unix/sysv/linux/s390/bits/hwcap.h ++++ b/sysdeps/unix/sysv/linux/s390/bits/hwcap.h +@@ -39,3 +39,7 @@ + #define HWCAP_S390_VXD 4096 + #define HWCAP_S390_VXE 8192 + #define HWCAP_S390_GS 16384 ++#define HWCAP_S390_VXRS_EXT2 32768 ++#define HWCAP_S390_VXRS_PDE 65536 ++#define HWCAP_S390_SORT 131072 ++#define HWCAP_S390_DFLT 262144 diff --git a/SOURCES/glibc-rh1659438-59.patch b/SOURCES/glibc-rh1659438-59.patch new file mode 100644 index 0000000..8cb861c --- /dev/null +++ b/SOURCES/glibc-rh1659438-59.patch @@ -0,0 +1,195 @@ +commit a899a5512f618d5c4093a2d65e8dee07c791b0ab +Author: Stefan Liebler +Date: Fri Mar 22 11:14:08 2019 +0100 + + S390: Add configure check to detect support for arch13. + + Add two configure checks which detect if arch13 is supported + by the assembler at all - by explicitely setting the machine - + and if it is supported with default settings. + + ChangeLog: + + * config.h.in (HAVE_S390_MIN_ARCH13_ZARCH_ASM_SUPPORT, + HAVE_S390_ARCH13_ASM_SUPPORT): New undefine. + * sysdeps/s390/configure.ac: Add checks for arch13 support. + * sysdeps/s390/configure: Regenerated. + +diff --git a/config.h.in b/config.h.in +index 422a6036ab16e3b6..f63f6c8442914aa1 100644 +--- a/config.h.in ++++ b/config.h.in +@@ -71,6 +71,9 @@ + /* Define if assembler supports z13 zarch instructions as default on S390. */ + #undef HAVE_S390_MIN_Z13_ZARCH_ASM_SUPPORT + ++/* Define if assembler supports arch13 zarch instruction as default on S390. */ ++#undef HAVE_S390_MIN_ARCH13_ZARCH_ASM_SUPPORT ++ + /* Define if assembler supports vector instructions on S390. */ + #undef HAVE_S390_VX_ASM_SUPPORT + +@@ -78,6 +81,9 @@ + on S390. */ + #undef HAVE_S390_VX_GCC_SUPPORT + ++/* Define if assembler supports arch13 instructions on S390. */ ++#undef HAVE_S390_ARCH13_ASM_SUPPORT ++ + /* Define if assembler supports Intel MPX. */ + #undef HAVE_MPX_SUPPORT + +diff --git a/sysdeps/s390/configure b/sysdeps/s390/configure +index 4a44775e3083d8c3..fa46e9e351e37e55 100644 +--- a/sysdeps/s390/configure ++++ b/sysdeps/s390/configure +@@ -112,6 +112,43 @@ then + + fi + ++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for S390 arch13 zarch instruction support" >&5 ++$as_echo_n "checking for S390 arch13 zarch instruction support... " >&6; } ++if ${libc_cv_asm_s390_arch13+:} false; then : ++ $as_echo_n "(cached) " >&6 ++else ++ cat > conftest.c <<\EOF ++void testinsn (char *buf) ++{ ++ __asm__ (".machine \"arch13\" \n\t" ++ ".machinemode \"zarch_nohighgprs\" \n\t" ++ "lghi %%r0,16 \n\t" ++ "mvcrl 0(%0),32(%0)" : : "a" (buf) : "memory", "r0"); ++} ++EOF ++if { ac_try='${CC-cc} $CFLAGS $CPPFLAGS $LDFLAGS --shared conftest.c ++ -o conftest.o &> /dev/null' ++ { { 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; }; } ; ++then ++ libc_cv_asm_s390_arch13=yes ++else ++ libc_cv_asm_s390_arch13=no ++fi ++rm -f conftest* ++fi ++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libc_cv_asm_s390_arch13" >&5 ++$as_echo "$libc_cv_asm_s390_arch13" >&6; } ++if test "$libc_cv_asm_s390_arch13" = yes ; ++then ++ $as_echo "#define HAVE_S390_ARCH13_ASM_SUPPORT 1" >>confdefs.h ++ ++fi ++ ++ + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for S390 z10 zarch instruction support as default" >&5 + $as_echo_n "checking for S390 z10 zarch instruction support as default... " >&6; } + if ${libc_cv_asm_s390_min_z10_zarch+:} false; then : +@@ -225,5 +262,39 @@ then + + fi + ++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for S390 arch13 zarch instruction support as default" >&5 ++$as_echo_n "checking for S390 arch13 zarch instruction support as default... " >&6; } ++if ${libc_cv_asm_s390_min_arch13_zarch+:} false; then : ++ $as_echo_n "(cached) " >&6 ++else ++ cat > conftest.c <<\EOF ++void testinsn (char *buf) ++{ ++ __asm__ ("lghi %%r0,16 \n\t" ++ "mvcrl 0(%0),32(%0)" : : "a" (buf) : "memory", "r0"); ++} ++EOF ++if { ac_try='${CC-cc} $CFLAGS $CPPFLAGS $LDFLAGS --shared conftest.c ++ -o conftest.o &> /dev/null' ++ { { 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; }; } ; ++then ++ libc_cv_asm_s390_min_arch13_zarch=yes ++else ++ libc_cv_asm_s390_min_arch13_zarch=no ++fi ++rm -f conftest* ++fi ++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libc_cv_asm_s390_min_arch13_zarch" >&5 ++$as_echo "$libc_cv_asm_s390_min_arch13_zarch" >&6; } ++if test "$libc_cv_asm_s390_min_arch13_zarch" = yes ; ++then ++ $as_echo "#define HAVE_S390_MIN_ARCH13_ZARCH_ASM_SUPPORT 1" >>confdefs.h ++ ++fi ++ + test -n "$critic_missing" && as_fn_error $? " + *** $critic_missing" "$LINENO" 5 +diff --git a/sysdeps/s390/configure.ac b/sysdeps/s390/configure.ac +index 4dfb5574b49d5949..3ed5a8ef87f9694b 100644 +--- a/sysdeps/s390/configure.ac ++++ b/sysdeps/s390/configure.ac +@@ -80,6 +80,32 @@ then + AC_DEFINE(HAVE_S390_VX_GCC_SUPPORT) + fi + ++AC_CACHE_CHECK(for S390 arch13 zarch instruction support, ++ libc_cv_asm_s390_arch13, [dnl ++cat > conftest.c <<\EOF ++void testinsn (char *buf) ++{ ++ __asm__ (".machine \"arch13\" \n\t" ++ ".machinemode \"zarch_nohighgprs\" \n\t" ++ "lghi %%r0,16 \n\t" ++ "mvcrl 0(%0),32(%0)" : : "a" (buf) : "memory", "r0"); ++} ++EOF ++dnl test, if assembler supports S390 arch13 instructions ++if AC_TRY_COMMAND([${CC-cc} $CFLAGS $CPPFLAGS $LDFLAGS --shared conftest.c ++ -o conftest.o &> /dev/null]) ; ++then ++ libc_cv_asm_s390_arch13=yes ++else ++ libc_cv_asm_s390_arch13=no ++fi ++rm -f conftest* ]) ++if test "$libc_cv_asm_s390_arch13" = yes ; ++then ++ AC_DEFINE(HAVE_S390_ARCH13_ASM_SUPPORT) ++fi ++ ++ + AC_CACHE_CHECK(for S390 z10 zarch instruction support as default, + libc_cv_asm_s390_min_z10_zarch, [dnl + cat > conftest.c <<\EOF +@@ -163,5 +189,28 @@ then + AC_DEFINE(HAVE_S390_MIN_Z13_ZARCH_ASM_SUPPORT) + fi + ++AC_CACHE_CHECK(for S390 arch13 zarch instruction support as default, ++ libc_cv_asm_s390_min_arch13_zarch, [dnl ++cat > conftest.c <<\EOF ++void testinsn (char *buf) ++{ ++ __asm__ ("lghi %%r0,16 \n\t" ++ "mvcrl 0(%0),32(%0)" : : "a" (buf) : "memory", "r0"); ++} ++EOF ++dnl test, if assembler supports S390 arch13 zarch instructions as default ++if AC_TRY_COMMAND([${CC-cc} $CFLAGS $CPPFLAGS $LDFLAGS --shared conftest.c ++ -o conftest.o &> /dev/null]) ; ++then ++ libc_cv_asm_s390_min_arch13_zarch=yes ++else ++ libc_cv_asm_s390_min_arch13_zarch=no ++fi ++rm -f conftest* ]) ++if test "$libc_cv_asm_s390_min_arch13_zarch" = yes ; ++then ++ AC_DEFINE(HAVE_S390_MIN_ARCH13_ZARCH_ASM_SUPPORT) ++fi ++ + test -n "$critic_missing" && AC_MSG_ERROR([ + *** $critic_missing]) diff --git a/SOURCES/glibc-rh1659438-6.patch b/SOURCES/glibc-rh1659438-6.patch new file mode 100644 index 0000000..9f4157d --- /dev/null +++ b/SOURCES/glibc-rh1659438-6.patch @@ -0,0 +1,429 @@ +commit 6c6b8c747096d74b900e2711b9b0d463677f6d31 +Author: Stefan Liebler +Date: Tue Dec 18 13:57:05 2018 +0100 + + S390: Unify 31/64bit memcmp. + + The implementation of memcmp for s390-32 (31bit) and + s390-64 (64bit) is nearly the same. + This patch unifies it for maintability reasons. + + __memcmp_z10 and __memcmp_z196 differs between 31 and 64bit: + -31bit needs .machinemode "zarch_nohighgprs" and llgfr %r4,%r4 + -lr vs lgr and some other instructions: + But lgr and co can be also used on 31bit as this ifunc variant + is only called if we are on a zarch machine. + + __memcmp_default differs between 31 and 64bit: + -Some 31bit vs 64bit instructions (e.g. ltr vs ltgr. + Solved with 31/64 specific instruction macros). + -The address of mvc instruction is setup in different ways + (larl vs bras). Solved with #if defined __s390x__. + + Otherwise 31/64bit implementation has the same structure of the code. + + ChangeLog: + + * sysdeps/s390/s390-64/memcmp.S: Move to ... + * sysdeps/s390/memcmp.S: ... here. + Adjust to be usable for 31/64bit. + * sysdeps/s390/s390-32/memcmp.S: Delete File. + * sysdeps/s390/multiarch/Makefile (sysdep_routines): Add memcmp. + * sysdeps/s390/s390-32/multiarch/Makefile (sysdep_routines): + Remove memcmp. + * sysdeps/s390/s390-64/multiarch/Makefile: Likewise. + * sysdeps/s390/s390-64/multiarch/memcmp-s390x.S: Move to ... + * sysdeps/s390/multiarch/memcmp-s390x.S: ... here. + Adjust to be usable for 31/64bit. + * sysdeps/s390/s390-32/multiarch/memcmp-s390.S: Delete File. + * sysdeps/s390/s390-64/multiarch/memcmp.c: Move to ... + * sysdeps/s390/multiarch/memcmp.c: ... here. + * sysdeps/s390/s390-32/multiarch/memcmp.c: Delete File. + +diff --git a/sysdeps/s390/s390-64/memcmp.S b/sysdeps/s390/memcmp.S +similarity index 60% +rename from sysdeps/s390/s390-64/memcmp.S +rename to sysdeps/s390/memcmp.S +index 005b19de45fcd883..751293a99e34f530 100644 +--- a/sysdeps/s390/s390-64/memcmp.S ++++ b/sysdeps/s390/memcmp.S +@@ -1,4 +1,4 @@ +-/* memcmp - compare two memory blocks. 64 bit S/390 version. ++/* memcmp - compare two memory blocks. 31/64 bit S/390 version. + Copyright (C) 2012-2018 Free Software Foundation, Inc. + This file is part of the GNU C Library. + +@@ -26,34 +26,62 @@ + %r4 = number of bytes to compare. */ + + .text ++#if defined __s390x__ ++# define LTGR ltgr ++# define AGHI aghi ++# define BRCTG brctg ++#else ++# define LTGR ltr ++# define AGHI ahi ++# define BRCTG brct ++#endif /* ! defined __s390x__ */ ++ + #ifdef USE_MULTIARCH + ENTRY(__memcmp_default) + #else + ENTRY(memcmp) + #endif ++#if defined __s390x__ + .machine "z900" +- ltgr %r4,%r4 +- je .L_Z900_4 +- aghi %r4,-1 ++#else ++ .machine "g5" ++ basr %r5,0 ++.L_Z900_G5_16: ++# define Z900_G5_EX_D .L_Z900_G5_15-.L_Z900_G5_16 ++#endif /* ! defined __s390x__ */ ++ LTGR %r4,%r4 ++ je .L_Z900_G5_4 ++ AGHI %r4,-1 ++#if defined __s390x__ + srlg %r1,%r4,8 +- ltgr %r1,%r1 +- jne .L_Z900_12 +-.L_Z900_3: +- larl %r1,.L_Z900_15 +- ex %r4,0(%r1) +-.L_Z900_4: ++ larl %r5,.L_Z900_G5_15 ++# define Z900_G5_EX_D 0 ++#else ++ lr %r1,%r4 ++ srl %r1,8 ++#endif /* ! defined __s390x__ */ ++ LTGR %r1,%r1 ++ jne .L_Z900_G5_12 ++.L_Z900_G5_3: ++ ex %r4,Z900_G5_EX_D(%r5) ++.L_Z900_G5_4: + ipm %r2 ++#if defined __s390x__ + sllg %r2,%r2,34 + srag %r2,%r2,62 ++#else ++ sll %r2,2 ++ sra %r2,30 ++#endif /* ! defined __s390x__ */ + br %r14 +-.L_Z900_12: ++.L_Z900_G5_12: + clc 0(256,%r3),0(%r2) +- jne .L_Z900_4 ++ jne .L_Z900_G5_4 + la %r3,256(%r3) + la %r2,256(%r2) +- brctg %r1,.L_Z900_12 +- j .L_Z900_3 +-.L_Z900_15: ++ BRCTG %r1,.L_Z900_G5_12 ++ j .L_Z900_G5_3 ++.L_Z900_G5_15: + clc 0(1,%r3),0(%r2) + #ifdef USE_MULTIARCH + END(__memcmp_default) +@@ -62,3 +90,7 @@ END(memcmp) + libc_hidden_builtin_def (memcmp) + weak_alias (memcmp, bcmp) + #endif ++ ++#undef LTGR ++#undef AGHI ++#undef BRCTG +diff --git a/sysdeps/s390/multiarch/Makefile b/sysdeps/s390/multiarch/Makefile +index c893ebc5659fd4ae..53dd8654d73677db 100644 +--- a/sysdeps/s390/multiarch/Makefile ++++ b/sysdeps/s390/multiarch/Makefile +@@ -19,7 +19,8 @@ sysdep_routines += strlen strlen-vx strlen-c \ + rawmemchr rawmemchr-vx rawmemchr-c \ + memccpy memccpy-vx memccpy-c \ + memrchr memrchr-vx memrchr-c \ +- mempcpy ++ mempcpy \ ++ memcmp memcmp-s390x + endif + + ifeq ($(subdir),wcsmbs) +diff --git a/sysdeps/s390/s390-64/multiarch/memcmp-s390x.S b/sysdeps/s390/multiarch/memcmp-s390x.S +similarity index 89% +rename from sysdeps/s390/s390-64/multiarch/memcmp-s390x.S +rename to sysdeps/s390/multiarch/memcmp-s390x.S +index 35f9bf9cf72da503..6321737acec821ec 100644 +--- a/sysdeps/s390/s390-64/multiarch/memcmp-s390x.S ++++ b/sysdeps/s390/multiarch/memcmp-s390x.S +@@ -1,4 +1,4 @@ +-/* CPU specific memcmp implementations. 64 bit S/390 version. ++/* CPU specific memcmp implementations. 31/64 bit S/390 version. + Copyright (C) 2012-2018 Free Software Foundation, Inc. + This file is part of the GNU C Library. + +@@ -31,6 +31,10 @@ + + ENTRY(__memcmp_z196) + .machine "z196" ++ .machinemode "zarch_nohighgprs" ++# if !defined __s390x__ ++ llgfr %r4,%r4 ++# endif /* !defined __s390x__ */ + ltgr %r4,%r4 + je .L_Z196_4 + aghi %r4,-1 +@@ -64,6 +68,10 @@ END(__memcmp_z196) + + ENTRY(__memcmp_z10) + .machine "z10" ++ .machinemode "zarch_nohighgprs" ++# if !defined __s390x__ ++ llgfr %r4,%r4 ++# endif /* !defined __s390x__ */ + ltgr %r4,%r4 + je .L_Z10_4 + aghi %r4,-1 +diff --git a/sysdeps/s390/s390-32/multiarch/memcmp.c b/sysdeps/s390/multiarch/memcmp.c +similarity index 100% +rename from sysdeps/s390/s390-32/multiarch/memcmp.c +rename to sysdeps/s390/multiarch/memcmp.c +diff --git a/sysdeps/s390/s390-32/memcmp.S b/sysdeps/s390/s390-32/memcmp.S +deleted file mode 100644 +index f9ad0bc745daf05f..0000000000000000 +--- a/sysdeps/s390/s390-32/memcmp.S ++++ /dev/null +@@ -1,66 +0,0 @@ +-/* memcmp - compare two memory blocks. 32 bit S/390 version. +- Copyright (C) 2012-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 "sysdep.h" +-#include "asm-syntax.h" +- +-/* INPUT PARAMETERS +- %r2 = address of first memory area +- %r3 = address of second memory area +- %r4 = number of bytes to compare. */ +- +- .text +-#ifdef USE_MULTIARCH +-ENTRY(__memcmp_default) +-#else +-ENTRY(memcmp) +-#endif +- .machine "g5" +- basr %r5,0 +-.L_G5_16: +- ltr %r4,%r4 +- je .L_G5_4 +- ahi %r4,-1 +- lr %r1,%r4 +- srl %r1,8 +- ltr %r1,%r1 +- jne .L_G5_12 +- ex %r4,.L_G5_17-.L_G5_16(%r5) +-.L_G5_4: +- ipm %r2 +- sll %r2,2 +- sra %r2,30 +- br %r14 +-.L_G5_12: +- clc 0(256,%r3),0(%r2) +- jne .L_G5_4 +- la %r3,256(%r3) +- la %r2,256(%r2) +- brct %r1,.L_G5_12 +- ex %r4,.L_G5_17-.L_G5_16(%r5) +- j .L_G5_4 +-.L_G5_17: +- clc 0(1,%r3),0(%r2) +-#ifdef USE_MULTIARCH +-END(__memcmp_default) +-#else +-END(memcmp) +-libc_hidden_builtin_def (memcmp) +-weak_alias(memcmp, bcmp) +-#endif +diff --git a/sysdeps/s390/s390-32/multiarch/Makefile b/sysdeps/s390/s390-32/multiarch/Makefile +index 4b11e28656ac19ab..82a7492eb8436479 100644 +--- a/sysdeps/s390/s390-32/multiarch/Makefile ++++ b/sysdeps/s390/s390-32/multiarch/Makefile +@@ -1,3 +1,3 @@ + ifeq ($(subdir),string) +-sysdep_routines += memcpy memcpy-s390 memcmp memcmp-s390 ++sysdep_routines += memcpy memcpy-s390 + endif +diff --git a/sysdeps/s390/s390-32/multiarch/memcmp-s390.S b/sysdeps/s390/s390-32/multiarch/memcmp-s390.S +deleted file mode 100644 +index e53b508c98bebeba..0000000000000000 +--- a/sysdeps/s390/s390-32/multiarch/memcmp-s390.S ++++ /dev/null +@@ -1,107 +0,0 @@ +-/* CPU specific memcmp implementations. 32 bit S/390 version. +- Copyright (C) 2012-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 "sysdep.h" +-#include "asm-syntax.h" +- +-/* INPUT PARAMETERS +- %r2 = address of first memory area +- %r3 = address of second memory area +- %r4 = number of bytes to compare. */ +- +- .text +- +-#if IS_IN (libc) +- +-ENTRY(__memcmp_z196) +- .machine "z196" +- .machinemode "zarch_nohighgprs" +- ltr %r4,%r4 +- je .L_Z196_4 +- ahi %r4,-1 +- srlk %r1,%r4,8 +- ltr %r1,%r1 +- jne .L_Z196_2 +-.L_Z196_3: +- exrl %r4,.L_Z196_14 +-.L_Z196_4: +- ipm %r2 +- sll %r2,2 +- sra %r2,30 +- br %r14 +-.L_Z196_17: +- la %r3,256(%r3) +- la %r2,256(%r2) +- ahi %r1,-1 +- je .L_Z196_3 +-.L_Z196_2: +- pfd 1,512(%r3) +- pfd 1,512(%r2) +- clc 0(256,%r3),0(%r2) +- je .L_Z196_17 +- ipm %r2 +- sll %r2,2 +- sra %r2,30 +- br %r14 +-.L_Z196_14: +- clc 0(1,%r3),0(%r2) +-END(__memcmp_z196) +- +-ENTRY(__memcmp_z10) +- .machine "z10" +- .machinemode "zarch_nohighgprs" +- ltr %r4,%r4 +- je .L_Z10_4 +- ahi %r4,-1 +- lr %r1,%r4 +- srl %r1,8 +- cijlh %r1,0,.L_Z10_12 +-.L_Z10_3: +- exrl %r4,.L_Z10_15 +-.L_Z10_4: +- ipm %r2 +- sll %r2,2 +- sra %r2,30 +- br %r14 +-.L_Z10_12: +- pfd 1,512(%r3) +- pfd 1,512(%r2) +- clc 0(256,%r3),0(%r2) +- jne .L_Z10_4 +- la %r3,256(%r3) +- la %r2,256(%r2) +- brct %r1,.L_Z10_12 +- j .L_Z10_3 +-.L_Z10_15: +- clc 0(1,%r3),0(%r2) +-END(__memcmp_z10) +- +-#endif /* IS_IN (libc) */ +- +-#include "../memcmp.S" +- +-#if !IS_IN (libc) +-.globl memcmp +-.set memcmp,__memcmp_default +-.weak bcmp +-.set bcmp,__memcmp_default +-#elif defined SHARED && IS_IN (libc) +-.globl __GI_memcmp +-.set __GI_memcmp,__memcmp_default +-#endif +diff --git a/sysdeps/s390/s390-64/multiarch/Makefile b/sysdeps/s390/s390-64/multiarch/Makefile +index e4870c7ee177ad0d..8a043e3327a1527a 100644 +--- a/sysdeps/s390/s390-64/multiarch/Makefile ++++ b/sysdeps/s390/s390-64/multiarch/Makefile +@@ -1,3 +1,3 @@ + ifeq ($(subdir),string) +-sysdep_routines += memcpy memcpy-s390x memcmp memcmp-s390x ++sysdep_routines += memcpy memcpy-s390x + endif +diff --git a/sysdeps/s390/s390-64/multiarch/memcmp.c b/sysdeps/s390/s390-64/multiarch/memcmp.c +deleted file mode 100644 +index 1e6f31806e172d7d..0000000000000000 +--- a/sysdeps/s390/s390-64/multiarch/memcmp.c ++++ /dev/null +@@ -1,27 +0,0 @@ +-/* Multiple versions of memcmp. +- 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 +- . */ +- +-#if IS_IN (libc) +-# define memcmp __redirect_memcmp +-# include +-# undef memcmp +-# include +- +-s390_libc_ifunc (__redirect_memcmp, __memcmp, memcmp) +-weak_alias (memcmp, bcmp); +-#endif diff --git a/SOURCES/glibc-rh1659438-60.patch b/SOURCES/glibc-rh1659438-60.patch new file mode 100644 index 0000000..6eacc7f --- /dev/null +++ b/SOURCES/glibc-rh1659438-60.patch @@ -0,0 +1,202 @@ +commit 96fbb9a328232e42814334d6e29a9a9c7995c01d +Author: Stefan Liebler +Date: Fri Mar 22 11:14:08 2019 +0100 + + S390: Add arch13 memmove ifunc variant. + + This patch introduces the new arch13 ifunc variant for memmove. + For the forward or non-overlapping case it is just using memcpy. + For the backward case it relies on the new instruction mvcrl. + The instruction copies up to 256 bytes at once. + In case of an overlap, it copies the bytes like copying them + one by one starting from right to left. + + ChangeLog: + + * sysdeps/s390/ifunc-memcpy.h (HAVE_MEMMOVE_ARCH13, MEMMOVE_ARCH13 + HAVE_MEMMOVE_IFUNC_AND_ARCH13_SUPPORT): New defines. + * sysdeps/s390/memcpy-z900.S: Add arch13 memmove implementation. + * sysdeps/s390/memmove.c (memmove): Add arch13 variant in + ifunc selector. + * sysdeps/s390/multiarch/ifunc-impl-list.c + (__libc_ifunc_impl_list): Add ifunc variant for arch13 memmove. + * sysdeps/s390/multiarch/ifunc-resolve.h (S390_STFLE_BITS_ARCH13_MIE3, + S390_IS_ARCH13_MIE3): New defines. + +diff --git a/sysdeps/s390/ifunc-memcpy.h b/sysdeps/s390/ifunc-memcpy.h +index 0e701968c8f39014..e8cd794587b44922 100644 +--- a/sysdeps/s390/ifunc-memcpy.h ++++ b/sysdeps/s390/ifunc-memcpy.h +@@ -44,7 +44,7 @@ + #endif + + #if defined SHARED && defined USE_MULTIARCH && IS_IN (libc) \ +- && ! defined HAVE_S390_MIN_Z13_ZARCH_ASM_SUPPORT ++ && ! defined HAVE_S390_MIN_ARCH13_ZARCH_ASM_SUPPORT + # define HAVE_MEMMOVE_IFUNC 1 + #else + # define HAVE_MEMMOVE_IFUNC 0 +@@ -56,14 +56,27 @@ + # define HAVE_MEMMOVE_IFUNC_AND_VX_SUPPORT 0 + #endif + +-#if defined HAVE_S390_MIN_Z13_ZARCH_ASM_SUPPORT ++#ifdef HAVE_S390_ARCH13_ASM_SUPPORT ++# define HAVE_MEMMOVE_IFUNC_AND_ARCH13_SUPPORT HAVE_MEMMOVE_IFUNC ++#else ++# define HAVE_MEMMOVE_IFUNC_AND_ARCH13_SUPPORT 0 ++#endif ++ ++#if defined HAVE_S390_MIN_ARCH13_ZARCH_ASM_SUPPORT ++# define MEMMOVE_DEFAULT MEMMOVE_ARCH13 ++# define HAVE_MEMMOVE_C 0 ++# define HAVE_MEMMOVE_Z13 0 ++# define HAVE_MEMMOVE_ARCH13 1 ++#elif defined HAVE_S390_MIN_Z13_ZARCH_ASM_SUPPORT + # define MEMMOVE_DEFAULT MEMMOVE_Z13 + # define HAVE_MEMMOVE_C 0 + # define HAVE_MEMMOVE_Z13 1 ++# define HAVE_MEMMOVE_ARCH13 HAVE_MEMMOVE_IFUNC_AND_ARCH13_SUPPORT + #else + # define MEMMOVE_DEFAULT MEMMOVE_C + # define HAVE_MEMMOVE_C 1 + # define HAVE_MEMMOVE_Z13 HAVE_MEMMOVE_IFUNC_AND_VX_SUPPORT ++# define HAVE_MEMMOVE_ARCH13 HAVE_MEMMOVE_IFUNC_AND_ARCH13_SUPPORT + #endif + + #if HAVE_MEMCPY_Z900_G5 +@@ -101,3 +114,9 @@ + #else + # define MEMMOVE_Z13 NULL + #endif ++ ++#if HAVE_MEMMOVE_ARCH13 ++# define MEMMOVE_ARCH13 __memmove_arch13 ++#else ++# define MEMMOVE_ARCH13 NULL ++#endif +diff --git a/sysdeps/s390/memcpy-z900.S b/sysdeps/s390/memcpy-z900.S +index bd3b1950ee442c0c..45eddc67a48e991e 100644 +--- a/sysdeps/s390/memcpy-z900.S ++++ b/sysdeps/s390/memcpy-z900.S +@@ -277,6 +277,61 @@ ENTRY(MEMMOVE_Z13) + END(MEMMOVE_Z13) + #endif /* HAVE_MEMMOVE_Z13 */ + ++#if HAVE_MEMMOVE_ARCH13 ++ENTRY(MEMMOVE_ARCH13) ++ .machine "arch13" ++ .machinemode "zarch_nohighgprs" ++# if ! defined __s390x__ ++ /* Note: The 31bit dst and src pointers are prefixed with zeroes. */ ++ llgfr %r4,%r4 ++ llgfr %r3,%r3 ++ llgfr %r2,%r2 ++# endif /* ! defined __s390x__ */ ++ sgrk %r5,%r2,%r3 ++ aghik %r0,%r4,-1 /* Both vstl and mvcrl needs highest index. */ ++ clgijh %r4,16,.L_MEMMOVE_ARCH13_LARGE ++.L_MEMMOVE_ARCH13_SMALL: ++ jl .L_MEMMOVE_ARCH13_END /* Return if len was zero (cc of aghik). */ ++ /* Store up to 16 bytes with vll/vstl (needs highest index). */ ++ vll %v16,%r0,0(%r3) ++ vstl %v16,%r0,0(%r2) ++.L_MEMMOVE_ARCH13_END: ++ br %r14 ++.L_MEMMOVE_ARCH13_LARGE: ++ lgr %r1,%r2 /* For memcpy: r1: Use as dest ; r2: Return dest */ ++ /* The unsigned comparison (dst - src >= len) determines if we can ++ execute the forward case with memcpy. */ ++#if ! HAVE_MEMCPY_Z196 ++# error The arch13 variant of memmove needs the z196 variant of memcpy! ++#endif ++ /* Backward case. */ ++ clgrjhe %r5,%r4,.L_Z196_start2 ++ clgijh %r0,255,.L_MEMMOVE_ARCH13_LARGER_256B ++ /* Move up to 256bytes with mvcrl (move right to left). */ ++ mvcrl 0(%r1),0(%r3) /* Move (r0 + 1) bytes from r3 to r1. */ ++ br %r14 ++.L_MEMMOVE_ARCH13_LARGER_256B: ++ /* First move the "remaining" block of up to 256 bytes at the end of ++ src/dst buffers. Then move blocks of 256bytes in a loop starting ++ with the block at the end. ++ (If src/dst pointers are aligned e.g. to 256 bytes, then the pointers ++ passed to mvcrl instructions are aligned, too) */ ++ risbgn %r5,%r0,8,128+63,56 /* r5 = r0 / 256 */ ++ risbgn %r0,%r0,56,128+63,0 /* r0 = r0 & 0xFF */ ++ slgr %r4,%r0 ++ lay %r1,-1(%r4,%r1) ++ lay %r3,-1(%r4,%r3) ++ mvcrl 0(%r1),0(%r3) /* Move (r0 + 1) bytes from r3 to r1. */ ++ lghi %r0,255 /* Always copy 256 bytes in the loop below! */ ++.L_MEMMOVE_ARCH13_LARGE_256B_LOOP: ++ aghi %r1,-256 ++ aghi %r3,-256 ++ mvcrl 0(%r1),0(%r3) /* Move (r0 + 1) bytes from r3 to r1. */ ++ brctg %r5,.L_MEMMOVE_ARCH13_LARGE_256B_LOOP ++ br %r14 ++END(MEMMOVE_ARCH13) ++#endif /* HAVE_MEMMOVE_ARCH13 */ ++ + #if ! HAVE_MEMCPY_IFUNC + /* If we don't use ifunc, define an alias for mem[p]cpy here. + Otherwise see sysdeps/s390/mem[p]cpy.c. */ +diff --git a/sysdeps/s390/memmove.c b/sysdeps/s390/memmove.c +index ac34edf80f2678cd..f6d31a4fcd56355b 100644 +--- a/sysdeps/s390/memmove.c ++++ b/sysdeps/s390/memmove.c +@@ -36,9 +36,19 @@ extern __typeof (__redirect_memmove) MEMMOVE_C attribute_hidden; + extern __typeof (__redirect_memmove) MEMMOVE_Z13 attribute_hidden; + # endif + ++# if HAVE_MEMMOVE_ARCH13 ++extern __typeof (__redirect_memmove) MEMMOVE_ARCH13 attribute_hidden; ++# endif ++ + s390_libc_ifunc_expr (__redirect_memmove, memmove, +- (HAVE_MEMMOVE_Z13 && (hwcap & HWCAP_S390_VX)) +- ? MEMMOVE_Z13 +- : MEMMOVE_DEFAULT ++ ({ ++ s390_libc_ifunc_expr_stfle_init (); ++ (HAVE_MEMMOVE_ARCH13 ++ && S390_IS_ARCH13_MIE3 (stfle_bits)) ++ ? MEMMOVE_ARCH13 ++ : (HAVE_MEMMOVE_Z13 && (hwcap & HWCAP_S390_VX)) ++ ? MEMMOVE_Z13 ++ : MEMMOVE_DEFAULT; ++ }) + ) + #endif +diff --git a/sysdeps/s390/multiarch/ifunc-impl-list.c b/sysdeps/s390/multiarch/ifunc-impl-list.c +index 177c5fd6fe269d9b..c24bfc95f2d7a22d 100644 +--- a/sysdeps/s390/multiarch/ifunc-impl-list.c ++++ b/sysdeps/s390/multiarch/ifunc-impl-list.c +@@ -169,6 +169,11 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + + #if HAVE_MEMMOVE_IFUNC + IFUNC_IMPL (i, name, memmove, ++# if HAVE_MEMMOVE_ARCH13 ++ IFUNC_IMPL_ADD (array, i, memmove, ++ S390_IS_ARCH13_MIE3 (stfle_bits), ++ MEMMOVE_ARCH13) ++# endif + # if HAVE_MEMMOVE_Z13 + IFUNC_IMPL_ADD (array, i, memmove, + dl_hwcap & HWCAP_S390_VX, MEMMOVE_Z13) +diff --git a/sysdeps/s390/multiarch/ifunc-resolve.h b/sysdeps/s390/multiarch/ifunc-resolve.h +index b2be015401313d4b..db735bb341ab6b86 100644 +--- a/sysdeps/s390/multiarch/ifunc-resolve.h ++++ b/sysdeps/s390/multiarch/ifunc-resolve.h +@@ -22,6 +22,11 @@ + + #define S390_STFLE_BITS_Z10 34 /* General instructions extension */ + #define S390_STFLE_BITS_Z196 45 /* Distinct operands, pop ... */ ++#define S390_STFLE_BITS_ARCH13_MIE3 61 /* Miscellaneous-Instruction-Extensions ++ Facility 3, e.g. mvcrl. */ ++ ++#define S390_IS_ARCH13_MIE3(STFLE_BITS) \ ++ ((STFLE_BITS & (1ULL << (63 - S390_STFLE_BITS_ARCH13_MIE3))) != 0) + + #define S390_IS_Z196(STFLE_BITS) \ + ((STFLE_BITS & (1ULL << (63 - S390_STFLE_BITS_Z196))) != 0) diff --git a/SOURCES/glibc-rh1659438-61.patch b/SOURCES/glibc-rh1659438-61.patch new file mode 100644 index 0000000..32e535a --- /dev/null +++ b/SOURCES/glibc-rh1659438-61.patch @@ -0,0 +1,332 @@ +commit 6f47401bd5fc71209219779a0426170a9a7395b0 +Author: Stefan Liebler +Date: Fri Mar 22 11:14:08 2019 +0100 + + S390: Add arch13 strstr ifunc variant. + + This patch introduces the new arch13 ifunc variant for strstr. + For needles longer than 9 charachters it is relying on the common-code + implementation. For shorter needles it is using the new vstrs instruction + which is able to search a substring within a vector register. + + ChangeLog: + + * sysdeps/s390/Makefile (sysdep_routines): Add strstr-arch13. + * sysdeps/s390/ifunc-strstr.h (HAVE_STRSTR_ARCH13, STRSTR_ARCH13, + STRSTR_Z13_ONLY_USED_AS_FALLBACK, HAVE_STRSTR_IFUNC_AND_ARCH13_SUPPORT): + New defines. + * sysdeps/s390/multiarch/ifunc-impl-list.c + (__libc_ifunc_impl_list): Add ifunc variant for arch13 strstr. + * sysdeps/s390/strstr-arch13.S: New file. + * sysdeps/s390/strstr-vx.c: Omit GI symbol for z13 strstr ifunc variant + if it is only used as fallback. + * sysdeps/s390/strstr.c (strstr): Add arch13 variant in ifunc selector. + +diff --git a/sysdeps/s390/Makefile b/sysdeps/s390/Makefile +index 3f7de6613c343819..7287b1833da9500f 100644 +--- a/sysdeps/s390/Makefile ++++ b/sysdeps/s390/Makefile +@@ -35,7 +35,7 @@ sysdep_routines += bzero memset memset-z900 \ + memcmp memcmp-z900 \ + mempcpy memcpy memcpy-z900 \ + memmove memmove-c \ +- strstr strstr-vx strstr-c \ ++ strstr strstr-arch13 strstr-vx strstr-c \ + memmem memmem-vx memmem-c \ + strlen strlen-vx strlen-c \ + strnlen strnlen-vx strnlen-c \ +diff --git a/sysdeps/s390/ifunc-strstr.h b/sysdeps/s390/ifunc-strstr.h +index e6ccfd4e44a1a790..809184d425ad06b0 100644 +--- a/sysdeps/s390/ifunc-strstr.h ++++ b/sysdeps/s390/ifunc-strstr.h +@@ -17,7 +17,7 @@ + . */ + + #if defined USE_MULTIARCH && IS_IN (libc) \ +- && ! defined HAVE_S390_MIN_Z13_ZARCH_ASM_SUPPORT ++ && ! defined HAVE_S390_MIN_ARCH13_ZARCH_ASM_SUPPORT + # define HAVE_STRSTR_IFUNC 1 + #else + # define HAVE_STRSTR_IFUNC 0 +@@ -29,14 +29,32 @@ + # define HAVE_STRSTR_IFUNC_AND_VX_SUPPORT 0 + #endif + +-#if defined HAVE_S390_MIN_Z13_ZARCH_ASM_SUPPORT ++#ifdef HAVE_S390_ARCH13_ASM_SUPPORT ++# define HAVE_STRSTR_IFUNC_AND_ARCH13_SUPPORT HAVE_STRSTR_IFUNC ++#else ++# define HAVE_STRSTR_IFUNC_AND_ARCH13_SUPPORT 0 ++#endif ++ ++#if defined HAVE_S390_MIN_ARCH13_ZARCH_ASM_SUPPORT ++# define STRSTR_DEFAULT STRSTR_ARCH13 ++# define HAVE_STRSTR_C 0 ++# define HAVE_STRSTR_Z13 1 ++# define STRSTR_Z13_ONLY_USED_AS_FALLBACK 1 ++# define HAVE_STRSTR_ARCH13 1 ++#elif defined HAVE_S390_MIN_Z13_ZARCH_ASM_SUPPORT + # define STRSTR_DEFAULT STRSTR_Z13 + # define HAVE_STRSTR_C 0 + # define HAVE_STRSTR_Z13 1 ++# define HAVE_STRSTR_ARCH13 HAVE_STRSTR_IFUNC_AND_ARCH13_SUPPORT + #else + # define STRSTR_DEFAULT STRSTR_C + # define HAVE_STRSTR_C 1 + # define HAVE_STRSTR_Z13 HAVE_STRSTR_IFUNC_AND_VX_SUPPORT ++# define HAVE_STRSTR_ARCH13 HAVE_STRSTR_IFUNC_AND_ARCH13_SUPPORT ++#endif ++ ++#ifndef STRSTR_Z13_ONLY_USED_AS_FALLBACK ++# define STRSTR_Z13_ONLY_USED_AS_FALLBACK 0 + #endif + + #if HAVE_STRSTR_C +@@ -50,3 +68,9 @@ + #else + # define STRSTR_Z13 NULL + #endif ++ ++#if HAVE_STRSTR_ARCH13 ++# define STRSTR_ARCH13 __strstr_arch13 ++#else ++# define STRSTR_ARCH13 NULL ++#endif +diff --git a/sysdeps/s390/multiarch/ifunc-impl-list.c b/sysdeps/s390/multiarch/ifunc-impl-list.c +index c24bfc95f2d7a22d..67a6a9c94afccd48 100644 +--- a/sysdeps/s390/multiarch/ifunc-impl-list.c ++++ b/sysdeps/s390/multiarch/ifunc-impl-list.c +@@ -186,6 +186,10 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + + #if HAVE_STRSTR_IFUNC + IFUNC_IMPL (i, name, strstr, ++# if HAVE_STRSTR_ARCH13 ++ IFUNC_IMPL_ADD (array, i, strstr, ++ dl_hwcap & HWCAP_S390_VXRS_EXT2, STRSTR_ARCH13) ++# endif + # if HAVE_STRSTR_Z13 + IFUNC_IMPL_ADD (array, i, strstr, + dl_hwcap & HWCAP_S390_VX, STRSTR_Z13) +diff --git a/sysdeps/s390/strstr-arch13.S b/sysdeps/s390/strstr-arch13.S +new file mode 100644 +index 0000000000000000..929b026adfeba740 +--- /dev/null ++++ b/sysdeps/s390/strstr-arch13.S +@@ -0,0 +1,179 @@ ++/* Vector optimized 32/64 bit S/390 version of strstr. ++ 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, see ++ . */ ++ ++#include ++#if HAVE_STRSTR_ARCH13 ++# include "sysdep.h" ++# include "asm-syntax.h" ++ .text ++ ++/* char *strstr (const char *haystack=r2, const char *needle=r3) ++ Locate a substring. */ ++ENTRY(STRSTR_ARCH13) ++ .machine "arch13" ++ .machinemode "zarch_nohighgprs" ++ lcbb %r1,0(%r3),6 ++ jo .Lneedle_on_bb /* Needle on block-boundary? */ ++ vl %v18,0(%r3),6 /* Load needle. */ ++ vfenezb %v19,%v18,%v18 /* v19[7] contains the length of needle. */ ++.Lneedle_loaded: ++ vlgvb %r4,%v19,7 /* Get index of zero or 16 if not found. */ ++ lghi %r5,17 /* See below: min-skip-partial-match-index. */ ++ cgibe %r4,0,0(%r14) /* Test if needle is zero and return. */ ++ ++ /* The vstrs instruction is able to handle needles up to a length of 16, ++ but then we may have to load the next part of haystack with a ++ small offset. This will be slow - see examples: ++ haystack =mmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmmm...mmmmmmmmmmmmmmmmmmma ++ needle = mmmmmmmmmmmmmma0 ++ => needle_len=15; vstrs reports a partial match; haystack+=2 ++ haystack =mmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmmm...mmmmmmmmmmmmmmmmmmma ++ needle = mmmmmmmma0000000 ++ => needle_len=9; vstrs reports a partial match; haystack+=8 */ ++# if ! HAVE_STRSTR_Z13 ++# error The arch13 variant of strstr needs the z13 variant of strstr! ++# endif ++ clgfi %r4,9 ++ jh STRSTR_Z13 ++ ++ /* In case of a partial match, the vstrs instruction returns the index ++ of the partial match in a vector-register. Then we have to ++ reload the string at the "current-position plus this index" and run ++ vstrs again in order to determine if it was a full match or no match. ++ Transferring this index from vr to gr, compute the haystack-address ++ and loading with vl is quite slow as all instructions have data ++ dependencies. Thus we assume, that a partial match is always at the ++ first possible index and just load the next part of haystack from ++ there instead of waiting until the correct index is computed: ++ min-skip-partial-match-index = (16 - n_len) + 1 */ ++ sgr %r5,%r4 ++ ++.Lloop: ++ lcbb %r1,0(%r2),6 ++ jo .Lloop_haystack_on_bb /* Haystack on block-boundary? */ ++ vl %v16,0(%r2) /* Load next part of haystack. */ ++.Lloop_haystack_loaded: ++ /* Vector string search with zero search (cc=0 => no match). */ ++ vstrs %v20,%v16,%v18,%v19,0,2 ++ jne .Lloop_vstrs_nonzero_cc ++ lcbb %r1,16(%r2),6 /* Next part of haystack. */ ++ jo .Lloop_haystack_on_bb16 ++ vl %v16,16(%r2) ++ vstrs %v20,%v16,%v18,%v19,0,2 ++ jne .Lloop_vstrs_nonzero_cc16 ++ lcbb %r1,32(%r2),6 /* Next part of haystack. */ ++ jo .Lloop_haystack_on_bb32 ++ vl %v16,32(%r2) ++ vstrs %v20,%v16,%v18,%v19,0,2 ++ jne .Lloop_vstrs_nonzero_cc32 ++ lcbb %r1,48(%r2),6 /* Next part of haystack. */ ++ jo .Lloop_haystack_on_bb48 ++ vl %v16,48(%r2) ++ vstrs %v20,%v16,%v18,%v19,0,2 ++ jne .Lloop_vstrs_nonzero_cc48 ++ la %r2,64(%r2) ++ j .Lloop ++ ++.Lloop_vstrs_nonzero_cc48: ++ la %r2,16(%r2) ++.Lloop_vstrs_nonzero_cc32: ++ la %r2,16(%r2) ++.Lloop_vstrs_nonzero_cc16: ++ la %r2,16(%r2) ++.Lloop_vstrs_nonzero_cc: ++ jh .Lend_match_found /* cc == 2 (full match) */ ++ jl .Lend_no_match /* cc == 1 (no match, end of string) */ ++ /* cc == 3 (partial match) See above: min-skip-partial-match-index! */ ++ lcbb %r1,0(%r5,%r2),6 ++ la %r2,0(%r5,%r2) ++ jo .Lloop_haystack_on_bb ++ vl %v16,0(%r2) ++ vstrs %v20,%v16,%v18,%v19,0,2 ++.Lloop_vstrs_nonzero_cc_loop: ++ jh .Lend_match_found ++ jl .Lend_no_match ++ la %r2,0(%r5,%r2) ++ je .Lloop ++ lcbb %r1,0(%r2),6 /* Next part of haystack. */ ++ jo .Lloop_haystack_on_bb ++ vl %v16,0(%r2) ++ vstrs %v20,%v16,%v18,%v19,0,2 ++ jh .Lend_match_found ++ jl .Lend_no_match ++ la %r2,0(%r5,%r2) ++ je .Lloop ++ lcbb %r1,0(%r2),6 /* Next part of haystack. */ ++ jo .Lloop_haystack_on_bb ++ vl %v16,0(%r2) ++ vstrs %v20,%v16,%v18,%v19,0,2 ++ jh .Lend_match_found ++ jl .Lend_no_match ++ la %r2,0(%r5,%r2) ++ je .Lloop ++ lcbb %r1,0(%r2),6 /* Next part of haystack. */ ++ jo .Lloop_haystack_on_bb ++ vl %v16,0(%r2) ++ vstrs %v20,%v16,%v18,%v19,0,2 ++ j .Lloop_vstrs_nonzero_cc_loop ++ ++.Lend_no_match: ++ lghi %r2,0 ++ br %r14 ++.Lend_match_found: ++ vlgvb %r4,%v20,7 ++ la %r2,0(%r4,%r2) ++ br %r14 ++ ++.Lloop_haystack_on_bb48: ++ la %r2,16(%r2) ++.Lloop_haystack_on_bb32: ++ la %r2,16(%r2) ++.Lloop_haystack_on_bb16: ++ la %r2,16(%r2) ++.Lloop_haystack_on_bb: ++ /* Haystack located on page-boundary. */ ++ ahi %r1,-1 /* vll needs highest index instead of count. */ ++ vll %v16,%r1,0(%r2) ++ vlvgb %v21,%r1,7 ++ vfenezb %v17,%v16,%v16 /* Search zero in loaded haystack bytes. */ ++ veclb %v17,%v21 /* Zero index <= loaded byte index? */ ++ jle .Lloop_haystack_loaded /* -> v16 contains full haystack. */ ++ vl %v16,0(%r2) /* Load haystack beyond page boundary. */ ++ j .Lloop_haystack_loaded ++ ++.Lneedle_on_bb: ++ /* Needle located on page-boundary. */ ++ ahi %r1,-1 /* vll needs highest index instead of count. */ ++ vll %v18,%r1,0(%r3) ++ vlvgb %v21,%r1,7 ++ vfenezb %v19,%v18,%v18 /* Search zero in loaded needle bytes. */ ++ veclb %v19,%v21 /* Zero index <= max loaded byte index? */ ++ jle .Lneedle_loaded /* -> v18 contains full needle. */ ++ vl %v16,0(%r3) /* Load needle beyond page boundary. */ ++ vfenezb %v19,%v18,%v18 ++ j .Lneedle_loaded ++END(STRSTR_ARCH13) ++ ++# if ! HAVE_STRSTR_IFUNC ++strong_alias (STRSTR_ARCH13, strstr) ++# endif ++ ++# if STRSTR_Z13_ONLY_USED_AS_FALLBACK && defined SHARED && IS_IN (libc) ++strong_alias (STRSTR_ARCH13, __GI_strstr) ++# endif ++#endif +diff --git a/sysdeps/s390/strstr-vx.c b/sysdeps/s390/strstr-vx.c +index effae9d5eb7d2fb1..f69159ffc198b10b 100644 +--- a/sysdeps/s390/strstr-vx.c ++++ b/sysdeps/s390/strstr-vx.c +@@ -19,11 +19,11 @@ + #include + + #if HAVE_STRSTR_Z13 +-# if HAVE_STRSTR_IFUNC ++# if HAVE_STRSTR_IFUNC || STRSTR_Z13_ONLY_USED_AS_FALLBACK + # define STRSTR STRSTR_Z13 + # if defined SHARED && IS_IN (libc) + # undef libc_hidden_builtin_def +-# if HAVE_STRSTR_C ++# if HAVE_STRSTR_C || STRSTR_Z13_ONLY_USED_AS_FALLBACK + # define libc_hidden_builtin_def(name) + # else + # define libc_hidden_builtin_def(name) \ +diff --git a/sysdeps/s390/strstr.c b/sysdeps/s390/strstr.c +index f8432349a7254cc6..d2969fd0a68fadbf 100644 +--- a/sysdeps/s390/strstr.c ++++ b/sysdeps/s390/strstr.c +@@ -32,8 +32,14 @@ extern __typeof (__redirect_strstr) STRSTR_C attribute_hidden; + extern __typeof (__redirect_strstr) STRSTR_Z13 attribute_hidden; + # endif + ++# if HAVE_STRSTR_ARCH13 ++extern __typeof (__redirect_strstr) STRSTR_ARCH13 attribute_hidden; ++# endif ++ + s390_libc_ifunc_expr (__redirect_strstr, strstr, +- (HAVE_STRSTR_Z13 && (hwcap & HWCAP_S390_VX)) ++ (HAVE_STRSTR_ARCH13 && (hwcap & HWCAP_S390_VXRS_EXT2)) ++ ? STRSTR_ARCH13 ++ : (HAVE_STRSTR_Z13 && (hwcap & HWCAP_S390_VX)) + ? STRSTR_Z13 + : STRSTR_DEFAULT + ) diff --git a/SOURCES/glibc-rh1659438-62.patch b/SOURCES/glibc-rh1659438-62.patch new file mode 100644 index 0000000..9d430c0 --- /dev/null +++ b/SOURCES/glibc-rh1659438-62.patch @@ -0,0 +1,318 @@ +commit 421749d693c4147017bc55f5ac3227c3a6e4bf31 +Author: Stefan Liebler +Date: Fri Mar 22 11:14:09 2019 +0100 + + S390: Add arch13 memmem ifunc variant. + + This patch introduces the new arch13 ifunc variant for memmem. + For needles longer than 9 bytes it is relying on the common-code + implementation. For shorter needles it is using the new vstrs instruction + which is able to search a substring within a vector register. + + ChangeLog: + + * sysdeps/s390/Makefile (sysdep_routines): Add memmem-arch13. + * sysdeps/s390/ifunc-memmem.h (HAVE_MEMMEM_ARCH13, MEMMEM_ARCH13, + MEMMEM_Z13_ONLY_USED_AS_FALLBACK, HAVE_MEMMEM_IFUNC_AND_ARCH13_SUPPORT): + New defines. + * sysdeps/s390/memmem-arch13.S: New file. + * sysdeps/s390/memmem-vx.c: Omit GI symbol for z13 memmem ifunc variant + if it is only used as fallback. + * sysdeps/s390/memmem.c (memmem): Add arch13 variant in ifunc selector. + * sysdeps/s390/multiarch/ifunc-impl-list.c + (__libc_ifunc_impl_list): Add ifunc variant for arch13 memmem. + +diff --git a/sysdeps/s390/Makefile b/sysdeps/s390/Makefile +index 7287b1833da9500f..8bc82e523f9049db 100644 +--- a/sysdeps/s390/Makefile ++++ b/sysdeps/s390/Makefile +@@ -36,7 +36,7 @@ sysdep_routines += bzero memset memset-z900 \ + mempcpy memcpy memcpy-z900 \ + memmove memmove-c \ + strstr strstr-arch13 strstr-vx strstr-c \ +- memmem memmem-vx memmem-c \ ++ memmem memmem-arch13 memmem-vx memmem-c \ + strlen strlen-vx strlen-c \ + strnlen strnlen-vx strnlen-c \ + strcpy strcpy-vx strcpy-z900 \ +diff --git a/sysdeps/s390/ifunc-memmem.h b/sysdeps/s390/ifunc-memmem.h +index 0f860d8d40080acf..48079b22b070f381 100644 +--- a/sysdeps/s390/ifunc-memmem.h ++++ b/sysdeps/s390/ifunc-memmem.h +@@ -17,7 +17,7 @@ + . */ + + #if defined USE_MULTIARCH && IS_IN (libc) \ +- && ! defined HAVE_S390_MIN_Z13_ZARCH_ASM_SUPPORT ++ && ! defined HAVE_S390_MIN_ARCH13_ZARCH_ASM_SUPPORT + # define HAVE_MEMMEM_IFUNC 1 + #else + # define HAVE_MEMMEM_IFUNC 0 +@@ -29,14 +29,32 @@ + # define HAVE_MEMMEM_IFUNC_AND_VX_SUPPORT 0 + #endif + +-#if defined HAVE_S390_MIN_Z13_ZARCH_ASM_SUPPORT ++#ifdef HAVE_S390_ARCH13_ASM_SUPPORT ++# define HAVE_MEMMEM_IFUNC_AND_ARCH13_SUPPORT HAVE_MEMMEM_IFUNC ++#else ++# define HAVE_MEMMEM_IFUNC_AND_ARCH13_SUPPORT 0 ++#endif ++ ++#if defined HAVE_S390_MIN_ARCH13_ZARCH_ASM_SUPPORT ++# define MEMMEM_DEFAULT MEMMEM_ARCH13 ++# define HAVE_MEMMEM_C 0 ++# define HAVE_MEMMEM_Z13 1 ++# define MEMMEM_Z13_ONLY_USED_AS_FALLBACK 1 ++# define HAVE_MEMMEM_ARCH13 1 ++#elif defined HAVE_S390_MIN_Z13_ZARCH_ASM_SUPPORT + # define MEMMEM_DEFAULT MEMMEM_Z13 + # define HAVE_MEMMEM_C 0 + # define HAVE_MEMMEM_Z13 1 ++# define HAVE_MEMMEM_ARCH13 HAVE_MEMMEM_IFUNC_AND_ARCH13_SUPPORT + #else + # define MEMMEM_DEFAULT MEMMEM_C + # define HAVE_MEMMEM_C 1 + # define HAVE_MEMMEM_Z13 HAVE_MEMMEM_IFUNC_AND_VX_SUPPORT ++# define HAVE_MEMMEM_ARCH13 HAVE_MEMMEM_IFUNC_AND_ARCH13_SUPPORT ++#endif ++ ++#ifndef MEMMEM_Z13_ONLY_USED_AS_FALLBACK ++# define MEMMEM_Z13_ONLY_USED_AS_FALLBACK 0 + #endif + + #if HAVE_MEMMEM_C +@@ -50,3 +68,9 @@ + #else + # define MEMMEM_Z13 NULL + #endif ++ ++#if HAVE_MEMMEM_ARCH13 ++# define MEMMEM_ARCH13 __memmem_arch13 ++#else ++# define MEMMEM_ARCH13 NULL ++#endif +diff --git a/sysdeps/s390/memmem-arch13.S b/sysdeps/s390/memmem-arch13.S +new file mode 100644 +index 0000000000000000..b59d60acf0f6aaa0 +--- /dev/null ++++ b/sysdeps/s390/memmem-arch13.S +@@ -0,0 +1,161 @@ ++/* Vector optimized 32/64 bit S/390 version of memmem. ++ 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, see ++ . */ ++ ++#include ++#if HAVE_MEMMEM_ARCH13 ++# include "sysdep.h" ++# include "asm-syntax.h" ++ .text ++ ++/* void *memmem(const void *haystack=r2, size_t haystacklen=r3, ++ const void *needle=r4, size_t needlelen=r5); ++ Locate a substring. */ ++ENTRY(MEMMEM_ARCH13) ++ .machine "arch13" ++ .machinemode "zarch_nohighgprs" ++# if ! defined __s390x__ ++ llgfr %r3,%r3 ++ llgfr %r5,%r5 ++ llgfr %r4,%r4 ++ llgfr %r2,%r2 ++# endif /* ! defined __s390x__ */ ++ clgrjl %r3,%r5,.Lend_no_match /* Haystack < needle? */ ++ ++ /* Jump to fallback if needle > 9. See also strstr-arch13.S. */ ++# if ! HAVE_MEMMEM_Z13 ++# error The arch13 variant of memmem needs the z13 variant of memmem! ++# endif ++ clgfi %r5,9 ++ jh MEMMEM_Z13 ++ ++ aghik %r0,%r5,-1 /* vll needs highest index. */ ++ bc 4,0(%r14) /* cc==1: return if needle-len == 0. */ ++ vll %v18,%r0,0(%r4) /* Load needle. */ ++ vlvgb %v19,%r5,7 /* v19[7] contains length of needle. */ ++ ++ clgijh %r3,16,.Lhaystack_larger_16 ++.Lhaystack_smaller_16_on_bb: ++ aghik %r0,%r3,-1 /* vll needs highest index. */ ++ vll %v16,%r0,0(%r2) /* Load haystack. */ ++.Lhaystack_smaller_16: ++ sgr %r3,%r5 /* r3 = largest valid match-index. */ ++ jl .Lend_no_match /* Haystack-len < needle-len? */ ++ vstrs %v20,%v16,%v18,%v19,0,0 ++ /* Vector string search without zero search where v20 will contain ++ the index of a partial/full match or 16 (index is named k). ++ cc=0 (no match; k=16): .Lend_no_match ++ cc=1 (only available with zero-search): Ignore ++ cc=2 (full match; k<16): Needle found, but could be beyond haystack! ++ cc=3 (partial match; k<16): Always at end of v16 and thus beyond! */ ++ brc 9,.Lend_no_match /* Jump away if cc == 0 || cc == 3. */ ++ vlgvb %r1,%v20,7 ++ /* Verify that the full-match (cc=2) is valid! */ ++ clgrjh %r1,%r3,.Lend_no_match /* Jump away if match is beyond. */ ++ la %r2,0(%r1,%r2) ++ br %r14 ++.Lend_no_match: ++ lghi %r2,0 ++ br %r14 ++ ++.Lhaystack_larger_16: ++ vl %v16,0(%r2) ++ lghi %r1,17 ++ lay %r4,-16(%r3,%r2) /* Boundary for loading with vl. */ ++ lay %r0,-64(%r3,%r2) /* Boundary for loading with 4xvl. */ ++ /* See also strstr-arch13.S: ++ min-skip-partial-match-index = (16 - n_len) + 1 */ ++ sgr %r1,%r5 ++ clgfi %r3,64 /* Set Boundary to zero ... */ ++ la %r3,0(%r3,%r2) ++ locghil %r0,0 /* ... if haystack < 64bytes. */ ++ jh .Lloop64 ++.Lloop: ++ la %r2,16(%r2) ++ /* Vector string search with zero search. cc=0 => no match. */ ++ vstrs %v20,%v16,%v18,%v19,0,0 ++ jne .Lloop_vstrs_nonzero_cc ++ clgrjh %r2,%r4,.Lhaystack_too_small ++.Lloop16: ++ vl %v16,0(%r2) ++ la %r2,16(%r2) ++ vstrs %v20,%v16,%v18,%v19,0,0 ++ jne .Lloop_vstrs_nonzero_cc ++ clgrjle %r2,%r4,.Lloop16 ++.Lhaystack_too_small: ++ sgr %r3,%r2 /* r3 = (haystack + len) - curr_pos */ ++ je .Lend_no_match /* Remaining haystack is empty. */ ++ lcbb %r0,0(%r2),6 ++ jo .Lhaystack_smaller_16_on_bb ++ vl %v16,0(%r2) /* Load haystack. */ ++ j .Lhaystack_smaller_16 ++ ++.Lend_match_found: ++ vlgvb %r4,%v20,7 ++ sgr %r2,%r1 ++ la %r2,0(%r4,%r2) ++ br %r14 ++ ++.Lloop_vstrs_nonzero_cc32: ++ la %r2,16(%r2) ++.Lloop_vstrs_nonzero_cc16: ++ la %r2,16(%r2) ++.Lloop_vstrs_nonzero_cc0: ++ la %r2,16(%r2) ++.Lloop_vstrs_nonzero_cc: ++ lay %r2,-16(%r1,%r2) /* Compute next load address. */ ++ jh .Lend_match_found /* cc == 2 (full match) */ ++ clgrjh %r2,%r4,.Lhaystack_too_small ++ vl %v16,0(%r2) ++.Lloop_vstrs_nonzero_cc_loop: ++ la %r2,0(%r1,%r2) ++ vstrs %v20,%v16,%v18,%v19,0,0 ++ jh .Lend_match_found ++ clgrjh %r2,%r4,.Lhaystack_too_small ++ vl %v16,0(%r2) /* Next part of haystack. */ ++ jo .Lloop_vstrs_nonzero_cc_loop ++ /* Case: no-match. */ ++ clgrjh %r2,%r0,.Lloop /* Jump away if haystack has less than 64b. */ ++.Lloop64: ++ vstrs %v20,%v16,%v18,%v19,0,0 ++ jne .Lloop_vstrs_nonzero_cc0 ++ vl %v16,16(%r2) /* Next part of haystack. */ ++ vstrs %v20,%v16,%v18,%v19,0,0 ++ jne .Lloop_vstrs_nonzero_cc16 ++ vl %v16,32(%r2) /* Next part of haystack. */ ++ vstrs %v20,%v16,%v18,%v19,0,0 ++ jne .Lloop_vstrs_nonzero_cc32 ++ vl %v16,48(%r2) /* Next part of haystack. */ ++ la %r2,64(%r2) ++ vstrs %v20,%v16,%v18,%v19,0,0 ++ jne .Lloop_vstrs_nonzero_cc ++ clgrjh %r2,%r4,.Lhaystack_too_small ++ vl %v16,0(%r2) /* Next part of haystack. */ ++ clgrjle %r2,%r0,.Lloop64 ++ j .Lloop ++END(MEMMEM_ARCH13) ++ ++# if ! HAVE_MEMMEM_IFUNC ++strong_alias (MEMMEM_ARCH13, __memmem) ++weak_alias (__memmem, memmem) ++# endif ++ ++# if MEMMEM_Z13_ONLY_USED_AS_FALLBACK && defined SHARED && IS_IN (libc) ++weak_alias (MEMMEM_ARCH13, __GI_memmem) ++strong_alias (MEMMEM_ARCH13, __GI___memmem) ++# endif ++#endif +diff --git a/sysdeps/s390/memmem-vx.c b/sysdeps/s390/memmem-vx.c +index af6e200e4e0af1a5..e5608be77f05f2a9 100644 +--- a/sysdeps/s390/memmem-vx.c ++++ b/sysdeps/s390/memmem-vx.c +@@ -20,7 +20,7 @@ + + #if HAVE_MEMMEM_Z13 + # include +-# if HAVE_MEMMEM_IFUNC ++# if HAVE_MEMMEM_IFUNC || MEMMEM_Z13_ONLY_USED_AS_FALLBACK + + # ifndef _LIBC + # define memmem MEMMEM_Z13 +@@ -32,7 +32,7 @@ + # undef libc_hidden_def + # undef libc_hidden_weak + +-# if HAVE_MEMMEM_C ++# if HAVE_MEMMEM_C || MEMMEM_Z13_ONLY_USED_AS_FALLBACK + # define libc_hidden_def(name) + # define libc_hidden_weak(name) + # else +diff --git a/sysdeps/s390/memmem.c b/sysdeps/s390/memmem.c +index 8c50b3f403eb8d1f..28871cd4b24868cc 100644 +--- a/sysdeps/s390/memmem.c ++++ b/sysdeps/s390/memmem.c +@@ -34,8 +34,14 @@ extern __typeof (__redirect_memmem) MEMMEM_C attribute_hidden; + extern __typeof (__redirect_memmem) MEMMEM_Z13 attribute_hidden; + # endif + ++# if HAVE_MEMMEM_ARCH13 ++extern __typeof (__redirect_memmem) MEMMEM_ARCH13 attribute_hidden; ++# endif ++ + s390_libc_ifunc_expr (__redirect_memmem, __memmem, +- (HAVE_MEMMEM_Z13 && (hwcap & HWCAP_S390_VX)) ++ (HAVE_MEMMEM_ARCH13 && (hwcap & HWCAP_S390_VXRS_EXT2)) ++ ? MEMMEM_ARCH13 ++ : (HAVE_MEMMEM_Z13 && (hwcap & HWCAP_S390_VX)) + ? MEMMEM_Z13 + : MEMMEM_DEFAULT + ) +diff --git a/sysdeps/s390/multiarch/ifunc-impl-list.c b/sysdeps/s390/multiarch/ifunc-impl-list.c +index 67a6a9c94afccd48..787d40688f4110ff 100644 +--- a/sysdeps/s390/multiarch/ifunc-impl-list.c ++++ b/sysdeps/s390/multiarch/ifunc-impl-list.c +@@ -202,6 +202,10 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + + #if HAVE_MEMMEM_IFUNC + IFUNC_IMPL (i, name, memmem, ++# if HAVE_MEMMEM_ARCH13 ++ IFUNC_IMPL_ADD (array, i, memmem, ++ dl_hwcap & HWCAP_S390_VXRS_EXT2, MEMMEM_ARCH13) ++# endif + # if HAVE_MEMMEM_Z13 + IFUNC_IMPL_ADD (array, i, memmem, + dl_hwcap & HWCAP_S390_VX, MEMMEM_Z13) diff --git a/SOURCES/glibc-rh1659438-7.patch b/SOURCES/glibc-rh1659438-7.patch new file mode 100644 index 0000000..bad570b --- /dev/null +++ b/SOURCES/glibc-rh1659438-7.patch @@ -0,0 +1,503 @@ +commit b7e024a838452a85870256d8f1ab946dc8f931cd +Author: Stefan Liebler +Date: Tue Dec 18 13:57:05 2018 +0100 + + S390: Refactor memcmp ifunc handling. + + This patch moves all ifunc variants for memcmp + to sysdeps/s390/memcmp-z900.S. The configure-check/preprocessor logic + in sysdeps/s390/ifunc-memcmp.h decides if ifunc is needed at all + and which ifunc variants should be available. + E.g. if the compiler/assembler already supports z196 by default, + the older ifunc variants are not included. + If we only need the newest ifunc variant, + then we can skip ifunc at all. + + Therefore the ifunc-resolvers and __libc_ifunc_impl_list are adjusted + in order to handle only the available ifunc variants. + + ChangeLog: + + * sysdeps/s390/ifunc-memcmp.h: New File. + * sysdeps/s390/memcmp.S: Move to ... + * sysdeps/s390/memcmp-z900.S ... here. + Move implementations from memcmp-s390x.s to here. + * sysdeps/s390/multiarch/memcmp-s390x.S: Delete File. + * sysdeps/s390/multiarch/Makefile (sysdep_routines): + Remove memcmp variants. + * sysdeps/s390/Makefile (sysdep_routines): + Add memcmp variants. + * sysdeps/s390/multiarch/ifunc-impl-list.c + (__libc_ifunc_impl_list): Adjust ifunc variants for + memcmp. + * sysdeps/s390/multiarch/memcmp.c: Move ifunc resolver + to ... + * sysdeps/s390/memcmp.c: ... here. + Adjust ifunc variants for memcmp. + +diff --git a/sysdeps/s390/Makefile b/sysdeps/s390/Makefile +index e40e5bd982e54d89..c59cbdc25aad408a 100644 +--- a/sysdeps/s390/Makefile ++++ b/sysdeps/s390/Makefile +@@ -31,5 +31,6 @@ sysdeps-gconv-modules = ../sysdeps/s390/gconv-modules + endif + + ifeq ($(subdir),string) +-sysdep_routines += bzero memset memset-z900 ++sysdep_routines += bzero memset memset-z900 \ ++ memcmp memcmp-z900 + endif +diff --git a/sysdeps/s390/ifunc-memcmp.h b/sysdeps/s390/ifunc-memcmp.h +new file mode 100644 +index 0000000000000000..536ac455d177c027 +--- /dev/null ++++ b/sysdeps/s390/ifunc-memcmp.h +@@ -0,0 +1,59 @@ ++/* memcmp variant information on S/390 version. ++ 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 ++ . */ ++ ++#if defined USE_MULTIARCH && IS_IN (libc) \ ++ && ! defined HAVE_S390_MIN_Z196_ZARCH_ASM_SUPPORT ++# define HAVE_MEMCMP_IFUNC 1 ++#else ++# define HAVE_MEMCMP_IFUNC 0 ++#endif ++ ++#if defined HAVE_S390_MIN_Z196_ZARCH_ASM_SUPPORT ++# define MEMCMP_DEFAULT MEMCMP_Z196 ++# define HAVE_MEMCMP_Z900_G5 0 ++# define HAVE_MEMCMP_Z10 0 ++# define HAVE_MEMCMP_Z196 1 ++#elif defined HAVE_S390_MIN_Z10_ZARCH_ASM_SUPPORT ++# define MEMCMP_DEFAULT MEMCMP_Z10 ++# define HAVE_MEMCMP_Z900_G5 0 ++# define HAVE_MEMCMP_Z10 1 ++# define HAVE_MEMCMP_Z196 HAVE_MEMCMP_IFUNC ++#else ++# define MEMCMP_DEFAULT MEMCMP_Z900_G5 ++# define HAVE_MEMCMP_Z900_G5 1 ++# define HAVE_MEMCMP_Z10 HAVE_MEMCMP_IFUNC ++# define HAVE_MEMCMP_Z196 HAVE_MEMCMP_IFUNC ++#endif ++ ++#if HAVE_MEMCMP_Z900_G5 ++# define MEMCMP_Z900_G5 __memcmp_default ++#else ++# define MEMCMP_Z900_G5 NULL ++#endif ++ ++#if HAVE_MEMCMP_Z10 ++# define MEMCMP_Z10 __memcmp_z10 ++#else ++# define MEMCMP_Z10 NULL ++#endif ++ ++#if HAVE_MEMCMP_Z196 ++# define MEMCMP_Z196 __memcmp_z196 ++#else ++# define MEMCMP_Z196 NULL ++#endif +diff --git a/sysdeps/s390/multiarch/memcmp-s390x.S b/sysdeps/s390/memcmp-z900.S +similarity index 54% +rename from sysdeps/s390/multiarch/memcmp-s390x.S +rename to sysdeps/s390/memcmp-z900.S +index 6321737acec821ec..c3b3677ba78264ee 100644 +--- a/sysdeps/s390/multiarch/memcmp-s390x.S ++++ b/sysdeps/s390/memcmp-z900.S +@@ -1,4 +1,4 @@ +-/* CPU specific memcmp implementations. 31/64 bit S/390 version. ++/* memcmp - compare two memory blocks. 31/64 bit S/390 version. + Copyright (C) 2012-2018 Free Software Foundation, Inc. + This file is part of the GNU C Library. + +@@ -17,8 +17,9 @@ + . */ + + +-#include "sysdep.h" ++#include + #include "asm-syntax.h" ++#include + + /* INPUT PARAMETERS + %r2 = address of first memory area +@@ -27,46 +28,67 @@ + + .text + +-#if IS_IN (libc) +- +-ENTRY(__memcmp_z196) +- .machine "z196" +- .machinemode "zarch_nohighgprs" +-# if !defined __s390x__ +- llgfr %r4,%r4 +-# endif /* !defined __s390x__ */ +- ltgr %r4,%r4 +- je .L_Z196_4 +- aghi %r4,-1 ++#if HAVE_MEMCMP_Z900_G5 ++# if defined __s390x__ ++# define LTGR ltgr ++# define AGHI aghi ++# define BRCTG brctg ++# else ++# define LTGR ltr ++# define AGHI ahi ++# define BRCTG brct ++# endif /* ! defined __s390x__ */ ++ENTRY(MEMCMP_Z900_G5) ++# if defined __s390x__ ++ .machine "z900" ++# else ++ .machine "g5" ++ basr %r5,0 ++.L_Z900_G5_16: ++# define Z900_G5_EX_D .L_Z900_G5_15-.L_Z900_G5_16 ++# endif /* ! defined __s390x__ */ ++ LTGR %r4,%r4 ++ je .L_Z900_G5_4 ++ AGHI %r4,-1 ++# if defined __s390x__ + srlg %r1,%r4,8 +- ltgr %r1,%r1 +- jne .L_Z196_2 +-.L_Z196_3: +- exrl %r4,.L_Z196_14 +-.L_Z196_4: ++ larl %r5,.L_Z900_G5_15 ++# define Z900_G5_EX_D 0 ++# else ++ lr %r1,%r4 ++ srl %r1,8 ++# endif /* ! defined __s390x__ */ ++ LTGR %r1,%r1 ++ jne .L_Z900_G5_12 ++.L_Z900_G5_3: ++ ex %r4,Z900_G5_EX_D(%r5) ++.L_Z900_G5_4: + ipm %r2 ++# if defined __s390x__ + sllg %r2,%r2,34 + srag %r2,%r2,62 ++# else ++ sll %r2,2 ++ sra %r2,30 ++# endif /* ! defined __s390x__ */ + br %r14 +-.L_Z196_17: ++.L_Z900_G5_12: ++ clc 0(256,%r3),0(%r2) ++ jne .L_Z900_G5_4 + la %r3,256(%r3) + la %r2,256(%r2) +- aghi %r1,-1 +- je .L_Z196_3 +-.L_Z196_2: +- pfd 1,512(%r3) +- pfd 1,512(%r2) +- clc 0(256,%r3),0(%r2) +- je .L_Z196_17 +- ipm %r2 +- sllg %r2,%r2,34 +- srag %r2,%r2,62 +- br %r14 +-.L_Z196_14: ++ BRCTG %r1,.L_Z900_G5_12 ++ j .L_Z900_G5_3 ++.L_Z900_G5_15: + clc 0(1,%r3),0(%r2) +-END(__memcmp_z196) ++END(MEMCMP_Z900_G5) ++# undef LTGR ++# undef AGHI ++# undef BRCTG ++#endif /* HAVE_MEMCMP_Z900_G5 */ + +-ENTRY(__memcmp_z10) ++#if HAVE_MEMCMP_Z10 ++ENTRY(MEMCMP_Z10) + .machine "z10" + .machinemode "zarch_nohighgprs" + # if !defined __s390x__ +@@ -95,18 +117,57 @@ ENTRY(__memcmp_z10) + j .L_Z10_3 + .L_Z10_15: + clc 0(1,%r3),0(%r2) +-END(__memcmp_z10) ++END(MEMCMP_Z10) ++#endif /* HAVE_MEMCMP_Z10 */ + +-#endif /* IS_IN (libc) */ ++#if HAVE_MEMCMP_Z196 ++ENTRY(MEMCMP_Z196) ++ .machine "z196" ++ .machinemode "zarch_nohighgprs" ++# if !defined __s390x__ ++ llgfr %r4,%r4 ++# endif /* !defined __s390x__ */ ++ ltgr %r4,%r4 ++ je .L_Z196_4 ++ aghi %r4,-1 ++ srlg %r1,%r4,8 ++ ltgr %r1,%r1 ++ jne .L_Z196_2 ++.L_Z196_3: ++ exrl %r4,.L_Z196_14 ++.L_Z196_4: ++ ipm %r2 ++ sllg %r2,%r2,34 ++ srag %r2,%r2,62 ++ br %r14 ++.L_Z196_17: ++ la %r3,256(%r3) ++ la %r2,256(%r2) ++ aghi %r1,-1 ++ je .L_Z196_3 ++.L_Z196_2: ++ pfd 1,512(%r3) ++ pfd 1,512(%r2) ++ clc 0(256,%r3),0(%r2) ++ je .L_Z196_17 ++ ipm %r2 ++ sllg %r2,%r2,34 ++ srag %r2,%r2,62 ++ br %r14 ++.L_Z196_14: ++ clc 0(1,%r3),0(%r2) ++END(MEMCMP_Z196) ++#endif /* HAVE_MEMCMP_Z196 */ + +-#include "../memcmp.S" ++#if ! HAVE_MEMCMP_IFUNC ++/* If we don't use ifunc, define an alias for memcmp here. ++ Otherwise see sysdeps/s390/memcmp.c. */ ++strong_alias (MEMCMP_DEFAULT, memcmp) ++weak_alias (memcmp, bcmp) ++#endif + +-#if !IS_IN (libc) +-.globl memcmp +-.set memcmp,__memcmp_default +-.weak bcmp +-.set bcmp,__memcmp_default +-#elif defined SHARED && IS_IN (libc) +-.globl __GI_memcmp +-.set __GI_memcmp,__memcmp_default ++#if defined SHARED && IS_IN (libc) ++/* Defines the internal symbols. ++ Compare to libc_hidden_builtin_def (memcmp) in string/memcmp.c. */ ++strong_alias (MEMCMP_DEFAULT, __GI_memcmp) + #endif +diff --git a/sysdeps/s390/memcmp.S b/sysdeps/s390/memcmp.S +deleted file mode 100644 +index 751293a99e34f530..0000000000000000 +--- a/sysdeps/s390/memcmp.S ++++ /dev/null +@@ -1,96 +0,0 @@ +-/* memcmp - compare two memory blocks. 31/64 bit S/390 version. +- Copyright (C) 2012-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 "asm-syntax.h" +- +-/* INPUT PARAMETERS +- %r2 = address of first memory area +- %r3 = address of second memory area +- %r4 = number of bytes to compare. */ +- +- .text +-#if defined __s390x__ +-# define LTGR ltgr +-# define AGHI aghi +-# define BRCTG brctg +-#else +-# define LTGR ltr +-# define AGHI ahi +-# define BRCTG brct +-#endif /* ! defined __s390x__ */ +- +-#ifdef USE_MULTIARCH +-ENTRY(__memcmp_default) +-#else +-ENTRY(memcmp) +-#endif +-#if defined __s390x__ +- .machine "z900" +-#else +- .machine "g5" +- basr %r5,0 +-.L_Z900_G5_16: +-# define Z900_G5_EX_D .L_Z900_G5_15-.L_Z900_G5_16 +-#endif /* ! defined __s390x__ */ +- LTGR %r4,%r4 +- je .L_Z900_G5_4 +- AGHI %r4,-1 +-#if defined __s390x__ +- srlg %r1,%r4,8 +- larl %r5,.L_Z900_G5_15 +-# define Z900_G5_EX_D 0 +-#else +- lr %r1,%r4 +- srl %r1,8 +-#endif /* ! defined __s390x__ */ +- LTGR %r1,%r1 +- jne .L_Z900_G5_12 +-.L_Z900_G5_3: +- ex %r4,Z900_G5_EX_D(%r5) +-.L_Z900_G5_4: +- ipm %r2 +-#if defined __s390x__ +- sllg %r2,%r2,34 +- srag %r2,%r2,62 +-#else +- sll %r2,2 +- sra %r2,30 +-#endif /* ! defined __s390x__ */ +- br %r14 +-.L_Z900_G5_12: +- clc 0(256,%r3),0(%r2) +- jne .L_Z900_G5_4 +- la %r3,256(%r3) +- la %r2,256(%r2) +- BRCTG %r1,.L_Z900_G5_12 +- j .L_Z900_G5_3 +-.L_Z900_G5_15: +- clc 0(1,%r3),0(%r2) +-#ifdef USE_MULTIARCH +-END(__memcmp_default) +-#else +-END(memcmp) +-libc_hidden_builtin_def (memcmp) +-weak_alias (memcmp, bcmp) +-#endif +- +-#undef LTGR +-#undef AGHI +-#undef BRCTG +diff --git a/sysdeps/s390/multiarch/memcmp.c b/sysdeps/s390/memcmp.c +similarity index 60% +rename from sysdeps/s390/multiarch/memcmp.c +rename to sysdeps/s390/memcmp.c +index 1e6f31806e172d7d..952ff6af7364fd92 100644 +--- a/sysdeps/s390/multiarch/memcmp.c ++++ b/sysdeps/s390/memcmp.c +@@ -16,12 +16,34 @@ + License along with the GNU C Library; if not, see + . */ + +-#if IS_IN (libc) ++#include ++#if HAVE_MEMCMP_IFUNC + # define memcmp __redirect_memcmp + # include + # undef memcmp + # include + +-s390_libc_ifunc (__redirect_memcmp, __memcmp, memcmp) ++# if HAVE_MEMCMP_Z900_G5 ++extern __typeof (__redirect_memcmp) MEMCMP_Z900_G5 attribute_hidden; ++# endif ++ ++# if HAVE_MEMCMP_Z10 ++extern __typeof (__redirect_memcmp) MEMCMP_Z10 attribute_hidden; ++# endif ++ ++# if HAVE_MEMCMP_Z196 ++extern __typeof (__redirect_memcmp) MEMCMP_Z196 attribute_hidden; ++# endif ++ ++s390_libc_ifunc_expr (__redirect_memcmp, memcmp, ++ ({ ++ s390_libc_ifunc_init (); ++ (HAVE_MEMCMP_Z196 && S390_IS_Z196 (stfle_bits)) ++ ? MEMCMP_Z196 ++ : (HAVE_MEMCMP_Z10 && S390_IS_Z10 (stfle_bits)) ++ ? MEMCMP_Z10 ++ : MEMCMP_DEFAULT; ++ }) ++ ) + weak_alias (memcmp, bcmp); + #endif +diff --git a/sysdeps/s390/multiarch/Makefile b/sysdeps/s390/multiarch/Makefile +index 53dd8654d73677db..c893ebc5659fd4ae 100644 +--- a/sysdeps/s390/multiarch/Makefile ++++ b/sysdeps/s390/multiarch/Makefile +@@ -19,8 +19,7 @@ sysdep_routines += strlen strlen-vx strlen-c \ + rawmemchr rawmemchr-vx rawmemchr-c \ + memccpy memccpy-vx memccpy-c \ + memrchr memrchr-vx memrchr-c \ +- mempcpy \ +- memcmp memcmp-s390x ++ mempcpy + endif + + ifeq ($(subdir),wcsmbs) +diff --git a/sysdeps/s390/multiarch/ifunc-impl-list.c b/sysdeps/s390/multiarch/ifunc-impl-list.c +index 253f36045b57cc3c..2e57d01abc21522e 100644 +--- a/sysdeps/s390/multiarch/ifunc-impl-list.c ++++ b/sysdeps/s390/multiarch/ifunc-impl-list.c +@@ -22,6 +22,7 @@ + #include + #include + #include ++#include + + /* Maximum number of IFUNC implementations. */ + #define MAX_IFUNC 3 +@@ -78,12 +79,21 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + ) + #endif /* HAVE_MEMSET_IFUNC */ + ++#if HAVE_MEMCMP_IFUNC + IFUNC_IMPL (i, name, memcmp, ++# if HAVE_MEMCMP_Z196 + IFUNC_IMPL_ADD (array, i, memcmp, +- S390_IS_Z196 (stfle_bits), __memcmp_z196) ++ S390_IS_Z196 (stfle_bits), MEMCMP_Z196) ++# endif ++# if HAVE_MEMCMP_Z10 + IFUNC_IMPL_ADD (array, i, memcmp, +- S390_IS_Z10 (stfle_bits), __memcmp_z10) +- IFUNC_IMPL_ADD (array, i, memcmp, 1, __memcmp_default)) ++ S390_IS_Z10 (stfle_bits), MEMCMP_Z10) ++# endif ++# if HAVE_MEMCMP_Z900_G5 ++ IFUNC_IMPL_ADD (array, i, memcmp, 1, MEMCMP_Z900_G5) ++# endif ++ ) ++#endif /* HAVE_MEMCMP_IFUNC */ + + #ifdef SHARED + diff --git a/SOURCES/glibc-rh1659438-8.patch b/SOURCES/glibc-rh1659438-8.patch new file mode 100644 index 0000000..464f5d2 --- /dev/null +++ b/SOURCES/glibc-rh1659438-8.patch @@ -0,0 +1,538 @@ +commit df3eb8de31a530f285f54f3c41cd7b636816c062 +Author: Stefan Liebler +Date: Tue Dec 18 13:57:06 2018 +0100 + + S390: Unify 31/64bit memcpy. + + The implementation of memcpy/mempcpy for s390-32 (31bit) + and s390-64 (64bit) is nearly the same. + This patch unifies it for maintability reasons. + + __mem[p]cpy_z10 and __mem[p]cpy_z196 differs between 31 and 64bit: + -31bit needs .machinemode "zarch_nohighgprs" and llgfr %r4,%r4 + -lr vs lgr; lgr can be also used on 31bit as this ifunc variant + is only called if we are on a zarch machine. + + __mem[p]cpy_default differs between 31 and 64bit: + -Some 31bit vs 64bit instructions (e.g. ltr vs ltgr. + Solved with 31/64 specific instruction macros). + -The address of mvc instruction is setup in different ways + (larl vs bras). Solved with #if defined __s390x__. + + __memcpy_mvcle differs between 31 and 64bit: + -lr vs lgr; ahi vs aghi; + Solved with 31/64bit specific instruction macros. + + Otherwise 31/64bit implementation has the same structure of the code. + + ChangeLog: + + * sysdeps/s390/s390-64/memcpy.S: Move to ... + * sysdeps/s390/memcpy.S: ... here. + Adjust to be usable for 31/64bit. + * sysdeps/s390/s390-32/memcpy.S: Delete File. + * sysdeps/s390/multiarch/Makefile (sysdep_routines): Add memcpy. + * sysdeps/s390/s390-32/multiarch/Makefile: Delete file. + * sysdeps/s390/s390-64/multiarch/Makefile: Likewise. + * sysdeps/s390/s390-64/multiarch/memcpy-s390x.S: Move to ... + * sysdeps/s390/multiarch/memcpy-s390x.S: ... here. + Adjust to be usable for 31/64bit. + * sysdeps/s390/s390-32/multiarch/memcpy-s390.S: Delete File. + * sysdeps/s390/s390-64/multiarch/memcpy.c: Move to ... + * sysdeps/s390/multiarch/memcpy.c: ... here. + * sysdeps/s390/s390-32/multiarch/memcpy.c: Delete File. + +diff --git a/sysdeps/s390/s390-64/memcpy.S b/sysdeps/s390/memcpy.S +similarity index 52% +rename from sysdeps/s390/s390-64/memcpy.S +rename to sysdeps/s390/memcpy.S +index 2e5490df23d64325..2a6c6b750377c7bb 100644 +--- a/sysdeps/s390/s390-64/memcpy.S ++++ b/sysdeps/s390/memcpy.S +@@ -1,4 +1,4 @@ +-/* memcpy - copy a block from source to destination. 64 bit S/390 version. ++/* memcpy - copy a block from source to destination. 31/64 bit S/390 version. + Copyright (C) 2012-2018 Free Software Foundation, Inc. + This file is part of the GNU C Library. + +@@ -25,13 +25,31 @@ + %r3 = address of source memory area + %r4 = number of bytes to copy. */ + +- + .text ++ ++#if defined __s390x__ ++# define LTGR ltgr ++# define CGHI cghi ++# define LGR lgr ++# define AGHI aghi ++# define BRCTG brctg ++#else ++# define LTGR ltr ++# define CGHI chi ++# define LGR lr ++# define AGHI ahi ++# define BRCTG brct ++#endif /* ! defined __s390x__ */ ++ + ENTRY(__mempcpy) ++#if defined __s390x__ + .machine "z900" +- lgr %r1,%r2 # Use as dest ++#else ++ .machine "g5" ++#endif /* ! defined __s390x__ */ ++ LGR %r1,%r2 # Use as dest + la %r2,0(%r4,%r2) # Return dest + n +- j .L_Z900_start ++ j .L_Z900_G5_start + END(__mempcpy) + #ifndef USE_MULTIARCH + libc_hidden_def (__mempcpy) +@@ -40,30 +58,46 @@ libc_hidden_builtin_def (mempcpy) + #endif + + ENTRY(memcpy) ++#if defined __s390x__ + .machine "z900" +- lgr %r1,%r2 # r1: Use as dest ; r2: Return dest +-.L_Z900_start: +- ltgr %r4,%r4 +- je .L_Z900_4 +- aghi %r4,-1 +- srlg %r5,%r4,8 +- ltgr %r5,%r5 +- jne .L_Z900_13 +-.L_Z900_3: +- larl %r5,.L_Z900_15 +- ex %r4,0(%r5) +-.L_Z900_4: ++#else ++ .machine "g5" ++#endif /* ! defined __s390x__ */ ++ LGR %r1,%r2 # r1: Use as dest ; r2: Return dest ++.L_Z900_G5_start: ++ LTGR %r4,%r4 ++ je .L_Z900_G5_4 ++ AGHI %r4,-1 ++#if defined __s390x__ ++ srlg %r5,%r4,8 ++#else ++ lr %r5,%r4 ++ srl %r5,8 ++#endif /* ! defined __s390x__ */ ++ LTGR %r5,%r5 ++ jne .L_Z900_G5_13 ++.L_Z900_G5_3: ++#if defined __s390x__ ++ larl %r5,.L_Z900_G5_15 ++# define Z900_G5_EX_D 0 ++#else ++ basr %r5,0 ++.L_Z900_G5_14: ++# define Z900_G5_EX_D .L_Z900_G5_15-.L_Z900_G5_14 ++#endif /* ! defined __s390x__ */ ++ ex %r4,Z900_G5_EX_D(%r5) ++.L_Z900_G5_4: + br %r14 +-.L_Z900_13: +- cghi %r5,4096 # Switch to mvcle for copies >1MB ++.L_Z900_G5_13: ++ CGHI %r5,4096 # Switch to mvcle for copies >1MB + jh __memcpy_mvcle +-.L_Z900_12: ++.L_Z900_G5_12: + mvc 0(256,%r1),0(%r3) + la %r1,256(%r1) + la %r3,256(%r3) +- brctg %r5,.L_Z900_12 +- j .L_Z900_3 +-.L_Z900_15: ++ BRCTG %r5,.L_Z900_G5_12 ++ j .L_Z900_G5_3 ++.L_Z900_G5_15: + mvc 0(1,%r1),0(%r3) + END(memcpy) + #ifndef USE_MULTIARCH +@@ -74,15 +108,21 @@ ENTRY(__memcpy_mvcle) + # Using as standalone function will result in unexpected + # results since the length field is incremented by 1 in order to + # compensate the changes already done in the functions above. +- lgr %r0,%r2 # backup return dest [ + n ] +- aghi %r4,1 # length + 1 +- lgr %r5,%r4 # source length +- lgr %r4,%r3 # source address +- lgr %r2,%r1 # destination address +- lgr %r3,%r5 # destination length = source length ++ LGR %r0,%r2 # backup return dest [ + n ] ++ AGHI %r4,1 # length + 1 ++ LGR %r5,%r4 # source length ++ LGR %r4,%r3 # source address ++ LGR %r2,%r1 # destination address ++ LGR %r3,%r5 # destination length = source length + .L_MVCLE_1: + mvcle %r2,%r4,0 # thats it, MVCLE is your friend + jo .L_MVCLE_1 +- lgr %r2,%r0 # return destination address ++ LGR %r2,%r0 # return destination address + br %r14 + END(__memcpy_mvcle) ++ ++#undef LTGR ++#undef CGHI ++#undef LGR ++#undef AGHI ++#undef BRCTG +diff --git a/sysdeps/s390/multiarch/Makefile b/sysdeps/s390/multiarch/Makefile +index c893ebc5659fd4ae..3cbd5fad69e355a5 100644 +--- a/sysdeps/s390/multiarch/Makefile ++++ b/sysdeps/s390/multiarch/Makefile +@@ -19,7 +19,7 @@ sysdep_routines += strlen strlen-vx strlen-c \ + rawmemchr rawmemchr-vx rawmemchr-c \ + memccpy memccpy-vx memccpy-c \ + memrchr memrchr-vx memrchr-c \ +- mempcpy ++ mempcpy memcpy memcpy-s390x + endif + + ifeq ($(subdir),wcsmbs) +diff --git a/sysdeps/s390/s390-64/multiarch/memcpy-s390x.S b/sysdeps/s390/multiarch/memcpy-s390x.S +similarity index 89% +rename from sysdeps/s390/s390-64/multiarch/memcpy-s390x.S +rename to sysdeps/s390/multiarch/memcpy-s390x.S +index 6d60a70834c32120..b38caac72b8742e6 100644 +--- a/sysdeps/s390/s390-64/multiarch/memcpy-s390x.S ++++ b/sysdeps/s390/multiarch/memcpy-s390x.S +@@ -1,4 +1,4 @@ +-/* CPU specific memcpy implementations. 64 bit S/390 version. ++/* CPU specific memcpy implementations. 31/64 bit S/390 version. + Copyright (C) 2012-2018 Free Software Foundation, Inc. + This file is part of the GNU C Library. + +@@ -31,6 +31,7 @@ + + ENTRY(____mempcpy_z196) + .machine "z196" ++ .machinemode "zarch_nohighgprs" + lgr %r1,%r2 # Use as dest + la %r2,0(%r4,%r2) # Return dest + n + j .L_Z196_start +@@ -38,8 +39,12 @@ END(____mempcpy_z196) + + ENTRY(__memcpy_z196) + .machine "z196" ++ .machinemode "zarch_nohighgprs" + lgr %r1,%r2 # r1: Use as dest ; r2: Return dest + .L_Z196_start: ++# if !defined __s390x__ ++ llgfr %r4,%r4 ++# endif /* !defined __s390x__ */ + ltgr %r4,%r4 + je .L_Z196_4 + aghi %r4,-1 +@@ -68,6 +73,7 @@ END(__memcpy_z196) + + ENTRY(____mempcpy_z10) + .machine "z10" ++ .machinemode "zarch_nohighgprs" + lgr %r1,%r2 # Use as dest + la %r2,0(%r4,%r2) # Return dest + n + j .L_Z10_start +@@ -75,8 +81,12 @@ END(____mempcpy_z10) + + ENTRY(__memcpy_z10) + .machine "z10" ++ .machinemode "zarch_nohighgprs" + lgr %r1,%r2 # r1: Use as dest ; r2: Return dest + .L_Z10_start: ++# if !defined __s390x__ ++ llgfr %r4,%r4 ++# endif /* !defined __s390x__ */ + cgije %r4,0,.L_Z10_4 + aghi %r4,-1 + srlg %r5,%r4,8 +diff --git a/sysdeps/s390/s390-32/multiarch/memcpy.c b/sysdeps/s390/multiarch/memcpy.c +similarity index 100% +rename from sysdeps/s390/s390-32/multiarch/memcpy.c +rename to sysdeps/s390/multiarch/memcpy.c +diff --git a/sysdeps/s390/s390-32/memcpy.S b/sysdeps/s390/s390-32/memcpy.S +deleted file mode 100644 +index 493cc18aba67d6ec..0000000000000000 +--- a/sysdeps/s390/s390-32/memcpy.S ++++ /dev/null +@@ -1,89 +0,0 @@ +-/* memcpy - copy a block from source to destination. S/390 version. +- Copyright (C) 2012-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 "sysdep.h" +-#include "asm-syntax.h" +- +-/* INPUT PARAMETERS +- %r2 = address of destination memory area +- %r3 = address of source memory area +- %r4 = number of bytes to copy. */ +- +- .text +-ENTRY(__mempcpy) +- .machine "g5" +- lr %r1,%r2 # Use as dest +- la %r2,0(%r4,%r2) # Return dest + n +- j .L_G5_start +-END(__mempcpy) +-#ifndef USE_MULTIARCH +-libc_hidden_def (__mempcpy) +-weak_alias (__mempcpy, mempcpy) +-libc_hidden_builtin_def (mempcpy) +-#endif +- +-ENTRY(memcpy) +- .machine "g5" +- lr %r1,%r2 # r1: Use as dest ; r2: Return dest +-.L_G5_start: +- ltr %r4,%r4 +- je .L_G5_99 +- ahi %r4,-1 +- lr %r5,%r4 +- srl %r5,8 +- ltr %r5,%r5 +- jne .L_G5_13 +-.L_G5_4: +- basr %r5,0 +-.L_G5_16: +- ex %r4,.L_G5_17-.L_G5_16(%r5) +-.L_G5_99: +- br %r14 +-.L_G5_13: +- chi %r5,4096 # Switch to mvcle for copies >1MB +- jh __memcpy_mvcle +-.L_G5_12: +- mvc 0(256,%r1),0(%r3) +- la %r1,256(%r1) +- la %r3,256(%r3) +- brct %r5,.L_G5_12 +- j .L_G5_4 +-.L_G5_17: +- mvc 0(1,%r1),0(%r3) +-END(memcpy) +-#ifndef USE_MULTIARCH +-libc_hidden_builtin_def (memcpy) +-#endif +- +-ENTRY(__memcpy_mvcle) +- # Using as standalone function will result in unexpected +- # results since the length field is incremented by 1 in order to +- # compensate the changes already done in the functions above. +- lr %r0,%r2 # backup return dest [ + n ] +- ahi %r4,1 # length + 1 +- lr %r5,%r4 # source length +- lr %r4,%r3 # source address +- lr %r2,%r1 # destination address +- lr %r3,%r5 # destination length = source length +-.L_MVCLE_1: +- mvcle %r2,%r4,0 # thats it, MVCLE is your friend +- jo .L_MVCLE_1 +- lr %r2,%r0 # return destination address +- br %r14 +-END(__memcpy_mvcle) +diff --git a/sysdeps/s390/s390-32/multiarch/Makefile b/sysdeps/s390/s390-32/multiarch/Makefile +deleted file mode 100644 +index 82a7492eb8436479..0000000000000000 +--- a/sysdeps/s390/s390-32/multiarch/Makefile ++++ /dev/null +@@ -1,3 +0,0 @@ +-ifeq ($(subdir),string) +-sysdep_routines += memcpy memcpy-s390 +-endif +diff --git a/sysdeps/s390/s390-32/multiarch/memcpy-s390.S b/sysdeps/s390/s390-32/multiarch/memcpy-s390.S +deleted file mode 100644 +index aad13bd07c31dab9..0000000000000000 +--- a/sysdeps/s390/s390-32/multiarch/memcpy-s390.S ++++ /dev/null +@@ -1,128 +0,0 @@ +-/* CPU specific memcpy implementations. 32 bit S/390 version. +- Copyright (C) 2012-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 "sysdep.h" +-#include "asm-syntax.h" +- +-/* INPUT PARAMETERS +- %r2 = target operands address +- %r3 = source operands address +- %r4 = number of bytes to copy. */ +- +- .text +- +-#if defined SHARED && IS_IN (libc) +- +-ENTRY(____mempcpy_z196) +- .machine "z196" +- .machinemode "zarch_nohighgprs" +- lr %r1,%r2 # Use as dest +- la %r2,0(%r4,%r2) # Return dest + n +- j .L_Z196_start +-END(____mempcpy_z196) +- +-ENTRY(__memcpy_z196) +- .machine "z196" +- .machinemode "zarch_nohighgprs" +- lr %r1,%r2 # r1: Use as dest ; r2: Return dest +-.L_Z196_start: +- llgfr %r4,%r4 +- ltgr %r4,%r4 +- je .L_Z196_4 +- aghi %r4,-1 +- srlg %r5,%r4,8 +- ltgr %r5,%r5 +- jne .L_Z196_5 +-.L_Z196_3: +- exrl %r4,.L_Z196_14 +-.L_Z196_4: +- br %r14 +-.L_Z196_5: +- cgfi %r5,262144 # Switch to mvcle for copies >64MB +- jh __memcpy_mvcle +-.L_Z196_2: +- pfd 1,768(%r3) +- pfd 2,768(%r1) +- mvc 0(256,%r1),0(%r3) +- aghi %r5,-1 +- la %r1,256(%r1) +- la %r3,256(%r3) +- jne .L_Z196_2 +- j .L_Z196_3 +-.L_Z196_14: +- mvc 0(1,%r1),0(%r3) +-END(__memcpy_z196) +- +-ENTRY(____mempcpy_z10) +- .machine "z10" +- .machinemode "zarch_nohighgprs" +- lr %r1,%r2 # Use as dest +- la %r2,0(%r4,%r2) # Return dest + n +- j .L_Z10_start +-END(____mempcpy_z10) +- +-ENTRY(__memcpy_z10) +- .machine "z10" +- .machinemode "zarch_nohighgprs" +- lr %r1,%r2 # r1: Use as dest ; r2: Return dest +-.L_Z10_start: +- llgfr %r4,%r4 +- cgije %r4,0,.L_Z10_4 +- aghi %r4,-1 +- srlg %r5,%r4,8 +- cgijlh %r5,0,.L_Z10_13 +-.L_Z10_3: +- exrl %r4,.L_Z10_15 +-.L_Z10_4: +- br %r14 +-.L_Z10_13: +- cgfi %r5,65535 # Switch to mvcle for copies >16MB +- jh __memcpy_mvcle +-.L_Z10_12: +- pfd 1,768(%r3) +- pfd 2,768(%r1) +- mvc 0(256,%r1),0(%r3) +- la %r1,256(%r1) +- la %r3,256(%r3) +- brctg %r5,.L_Z10_12 +- j .L_Z10_3 +-.L_Z10_15: +- mvc 0(1,%r1),0(%r3) +-END(__memcpy_z10) +- +-# define __mempcpy ____mempcpy_default +-#endif /* SHARED && IS_IN (libc) */ +- +-#define memcpy __memcpy_default +-#include "../memcpy.S" +-#undef memcpy +- +-#if defined SHARED && IS_IN (libc) +-.globl __GI_memcpy +-.set __GI_memcpy,__memcpy_default +-.globl __GI_mempcpy +-.set __GI_mempcpy,____mempcpy_default +-.globl __GI___mempcpy +-.set __GI___mempcpy,____mempcpy_default +-#else +-.globl memcpy +-.set memcpy,__memcpy_default +-.weak mempcpy +-.set mempcpy,__mempcpy +-#endif +diff --git a/sysdeps/s390/s390-64/multiarch/Makefile b/sysdeps/s390/s390-64/multiarch/Makefile +deleted file mode 100644 +index 8a043e3327a1527a..0000000000000000 +--- a/sysdeps/s390/s390-64/multiarch/Makefile ++++ /dev/null +@@ -1,3 +0,0 @@ +-ifeq ($(subdir),string) +-sysdep_routines += memcpy memcpy-s390x +-endif +diff --git a/sysdeps/s390/s390-64/multiarch/memcpy.c b/sysdeps/s390/s390-64/multiarch/memcpy.c +deleted file mode 100644 +index c9577a854a0c7e68..0000000000000000 +--- a/sysdeps/s390/s390-64/multiarch/memcpy.c ++++ /dev/null +@@ -1,27 +0,0 @@ +-/* Multiple versions of memcpy. +- 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 +- . */ +- +-/* In the static lib memcpy is needed before the reloc is resolved. */ +-#if defined SHARED && IS_IN (libc) +-# define memcpy __redirect_memcpy +-# include +-# undef memcpy +-# include +- +-s390_libc_ifunc (__redirect_memcpy, __memcpy, memcpy) +-#endif diff --git a/SOURCES/glibc-rh1659438-9.patch b/SOURCES/glibc-rh1659438-9.patch new file mode 100644 index 0000000..d3387ca --- /dev/null +++ b/SOURCES/glibc-rh1659438-9.patch @@ -0,0 +1,656 @@ +commit 18eb862d454a41012ccdd5127715ef7cd2a711ec +Author: Stefan Liebler +Date: Tue Dec 18 13:57:06 2018 +0100 + + S390: Refactor memcpy/mempcpy ifunc handling. + + This patch moves all ifunc variants for memcpy/mempcpy + to sysdeps/s390/memcpy-z900.S. The configure-check/preprocessor logic + in sysdeps/s390/ifunc-memcpy.h decides if ifunc is needed at all + and which ifunc variants should be available. + E.g. if the compiler/assembler already supports z196 by default, + the older ifunc variants are not included. + If we only need the newest ifunc variant, + then we can skip ifunc at all. + + Therefore the ifunc-resolvers and __libc_ifunc_impl_list are adjusted + in order to handle only the available ifunc variants. + + ChangeLog: + + * sysdeps/s390/ifunc-memcpy.h: New File. + * sysdeps/s390/memcpy.S: Move to ... + * sysdeps/s390/memcpy-z900.S ... here. + Move implementations from memcpy-s390x.s to here. + * sysdeps/s390/multiarch/memcpy-s390x.S: Delete File. + * sysdeps/s390/multiarch/Makefile (sysdep_routines): + Remove memcpy/mempcpy variants. + * sysdeps/s390/Makefile (sysdep_routines): + Add memcpy/mempcpy variants. + * sysdeps/s390/multiarch/ifunc-impl-list.c + (__libc_ifunc_impl_list): Adjust ifunc variants for + memcpy and mempcpy. + * sysdeps/s390/multiarch/memcpy.c: Move ifunc resolver + to ... + * sysdeps/s390/memcpy.c: ... here. + Adjust ifunc variants for memcpy. + * sysdeps/s390/multiarch/mempcpy.c: Move to ... + * sysdeps/s390/mempcpy.c: ... here. + Adjust ifunc variants for mempcpy. + * sysdeps/s390/mempcpy.S: Delete file. + +diff --git a/sysdeps/s390/Makefile b/sysdeps/s390/Makefile +index c59cbdc25aad408a..838950a5ab958e31 100644 +--- a/sysdeps/s390/Makefile ++++ b/sysdeps/s390/Makefile +@@ -32,5 +32,6 @@ endif + + ifeq ($(subdir),string) + sysdep_routines += bzero memset memset-z900 \ +- memcmp memcmp-z900 ++ memcmp memcmp-z900 \ ++ mempcpy memcpy memcpy-z900 + endif +diff --git a/sysdeps/s390/ifunc-memcpy.h b/sysdeps/s390/ifunc-memcpy.h +new file mode 100644 +index 0000000000000000..51c71baa2c0b0452 +--- /dev/null ++++ b/sysdeps/s390/ifunc-memcpy.h +@@ -0,0 +1,68 @@ ++/* memcpy variant information on S/390 version. ++ 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 ++ . */ ++ ++#if defined SHARED && defined USE_MULTIARCH && IS_IN (libc) \ ++ && ! defined HAVE_S390_MIN_Z196_ZARCH_ASM_SUPPORT ++# define HAVE_MEMCPY_IFUNC 1 ++#else ++# define HAVE_MEMCPY_IFUNC 0 ++#endif ++ ++#if defined HAVE_S390_MIN_Z196_ZARCH_ASM_SUPPORT ++# define MEMCPY_DEFAULT MEMCPY_Z196 ++# define MEMPCPY_DEFAULT MEMPCPY_Z196 ++# define HAVE_MEMCPY_Z900_G5 0 ++# define HAVE_MEMCPY_Z10 0 ++# define HAVE_MEMCPY_Z196 1 ++#elif defined HAVE_S390_MIN_Z10_ZARCH_ASM_SUPPORT ++# define MEMCPY_DEFAULT MEMCPY_Z10 ++# define MEMPCPY_DEFAULT MEMPCPY_Z10 ++# define HAVE_MEMCPY_Z900_G5 0 ++# define HAVE_MEMCPY_Z10 1 ++# define HAVE_MEMCPY_Z196 HAVE_MEMCPY_IFUNC ++#else ++# define MEMCPY_DEFAULT MEMCPY_Z900_G5 ++# define MEMPCPY_DEFAULT MEMPCPY_Z900_G5 ++# define HAVE_MEMCPY_Z900_G5 1 ++# define HAVE_MEMCPY_Z10 HAVE_MEMCPY_IFUNC ++# define HAVE_MEMCPY_Z196 HAVE_MEMCPY_IFUNC ++#endif ++ ++#if HAVE_MEMCPY_Z900_G5 ++# define MEMCPY_Z900_G5 __memcpy_default ++# define MEMPCPY_Z900_G5 __mempcpy_default ++#else ++# define MEMCPY_Z900_G5 NULL ++# define MEMPCPY_Z900_G5 NULL ++#endif ++ ++#if HAVE_MEMCPY_Z10 ++# define MEMCPY_Z10 __memcpy_z10 ++# define MEMPCPY_Z10 __mempcpy_z10 ++#else ++# define MEMCPY_Z10 NULL ++# define MEMPCPY_Z10 NULL ++#endif ++ ++#if HAVE_MEMCPY_Z196 ++# define MEMCPY_Z196 __memcpy_z196 ++# define MEMPCPY_Z196 __mempcpy_z196 ++#else ++# define MEMCPY_Z196 NULL ++# define MEMPCPY_Z196 NULL ++#endif +diff --git a/sysdeps/s390/memcpy.S b/sysdeps/s390/memcpy-z900.S +similarity index 50% +rename from sysdeps/s390/memcpy.S +rename to sysdeps/s390/memcpy-z900.S +index 2a6c6b750377c7bb..3a50cf44d85d2417 100644 +--- a/sysdeps/s390/memcpy.S ++++ b/sysdeps/s390/memcpy-z900.S +@@ -19,6 +19,7 @@ + + #include + #include "asm-syntax.h" ++#include + + /* INPUT PARAMETERS + %r2 = address of destination memory area +@@ -41,50 +42,46 @@ + # define BRCTG brct + #endif /* ! defined __s390x__ */ + +-ENTRY(__mempcpy) +-#if defined __s390x__ ++#if HAVE_MEMCPY_Z900_G5 ++ENTRY(MEMPCPY_Z900_G5) ++# if defined __s390x__ + .machine "z900" +-#else ++# else + .machine "g5" +-#endif /* ! defined __s390x__ */ ++# endif /* ! defined __s390x__ */ + LGR %r1,%r2 # Use as dest + la %r2,0(%r4,%r2) # Return dest + n + j .L_Z900_G5_start +-END(__mempcpy) +-#ifndef USE_MULTIARCH +-libc_hidden_def (__mempcpy) +-weak_alias (__mempcpy, mempcpy) +-libc_hidden_builtin_def (mempcpy) +-#endif ++END(MEMPCPY_Z900_G5) + +-ENTRY(memcpy) +-#if defined __s390x__ ++ENTRY(MEMCPY_Z900_G5) ++# if defined __s390x__ + .machine "z900" +-#else ++# else + .machine "g5" +-#endif /* ! defined __s390x__ */ ++# endif /* ! defined __s390x__ */ + LGR %r1,%r2 # r1: Use as dest ; r2: Return dest + .L_Z900_G5_start: + LTGR %r4,%r4 + je .L_Z900_G5_4 + AGHI %r4,-1 +-#if defined __s390x__ ++# if defined __s390x__ + srlg %r5,%r4,8 +-#else ++# else + lr %r5,%r4 + srl %r5,8 +-#endif /* ! defined __s390x__ */ ++# endif /* ! defined __s390x__ */ + LTGR %r5,%r5 + jne .L_Z900_G5_13 + .L_Z900_G5_3: +-#if defined __s390x__ ++# if defined __s390x__ + larl %r5,.L_Z900_G5_15 +-# define Z900_G5_EX_D 0 +-#else ++# define Z900_G5_EX_D 0 ++# else + basr %r5,0 + .L_Z900_G5_14: +-# define Z900_G5_EX_D .L_Z900_G5_15-.L_Z900_G5_14 +-#endif /* ! defined __s390x__ */ ++# define Z900_G5_EX_D .L_Z900_G5_15-.L_Z900_G5_14 ++# endif /* ! defined __s390x__ */ + ex %r4,Z900_G5_EX_D(%r5) + .L_Z900_G5_4: + br %r14 +@@ -99,10 +96,8 @@ ENTRY(memcpy) + j .L_Z900_G5_3 + .L_Z900_G5_15: + mvc 0(1,%r1),0(%r3) +-END(memcpy) +-#ifndef USE_MULTIARCH +-libc_hidden_builtin_def (memcpy) +-#endif ++END(MEMCPY_Z900_G5) ++#endif /* HAVE_MEMCPY_Z900_G5 */ + + ENTRY(__memcpy_mvcle) + # Using as standalone function will result in unexpected +@@ -126,3 +121,104 @@ END(__memcpy_mvcle) + #undef LGR + #undef AGHI + #undef BRCTG ++ ++#if HAVE_MEMCPY_Z10 ++ENTRY(MEMPCPY_Z10) ++ .machine "z10" ++ .machinemode "zarch_nohighgprs" ++ lgr %r1,%r2 # Use as dest ++ la %r2,0(%r4,%r2) # Return dest + n ++ j .L_Z10_start ++END(MEMPCPY_Z10) ++ ++ENTRY(MEMCPY_Z10) ++ .machine "z10" ++ .machinemode "zarch_nohighgprs" ++ lgr %r1,%r2 # r1: Use as dest ; r2: Return dest ++.L_Z10_start: ++# if !defined __s390x__ ++ llgfr %r4,%r4 ++# endif /* !defined __s390x__ */ ++ cgije %r4,0,.L_Z10_4 ++ aghi %r4,-1 ++ srlg %r5,%r4,8 ++ cgijlh %r5,0,.L_Z10_13 ++.L_Z10_3: ++ exrl %r4,.L_Z10_15 ++.L_Z10_4: ++ br %r14 ++.L_Z10_13: ++ cgfi %r5,65535 # Switch to mvcle for copies >16MB ++ jh __memcpy_mvcle ++.L_Z10_12: ++ pfd 1,768(%r3) ++ pfd 2,768(%r1) ++ mvc 0(256,%r1),0(%r3) ++ la %r1,256(%r1) ++ la %r3,256(%r3) ++ brctg %r5,.L_Z10_12 ++ j .L_Z10_3 ++.L_Z10_15: ++ mvc 0(1,%r1),0(%r3) ++END(MEMCPY_Z10) ++#endif /* HAVE_MEMCPY_Z10 */ ++ ++#if HAVE_MEMCPY_Z196 ++ENTRY(MEMPCPY_Z196) ++ .machine "z196" ++ .machinemode "zarch_nohighgprs" ++ lgr %r1,%r2 # Use as dest ++ la %r2,0(%r4,%r2) # Return dest + n ++ j .L_Z196_start ++END(MEMPCPY_Z196) ++ ++ENTRY(MEMCPY_Z196) ++ .machine "z196" ++ .machinemode "zarch_nohighgprs" ++ lgr %r1,%r2 # r1: Use as dest ; r2: Return dest ++.L_Z196_start: ++# if !defined __s390x__ ++ llgfr %r4,%r4 ++# endif /* !defined __s390x__ */ ++ ltgr %r4,%r4 ++ je .L_Z196_4 ++ aghi %r4,-1 ++ srlg %r5,%r4,8 ++ ltgr %r5,%r5 ++ jne .L_Z196_5 ++.L_Z196_3: ++ exrl %r4,.L_Z196_14 ++.L_Z196_4: ++ br %r14 ++.L_Z196_5: ++ cgfi %r5,262144 # Switch to mvcle for copies >64MB ++ jh __memcpy_mvcle ++.L_Z196_2: ++ pfd 1,768(%r3) ++ pfd 2,768(%r1) ++ mvc 0(256,%r1),0(%r3) ++ aghi %r5,-1 ++ la %r1,256(%r1) ++ la %r3,256(%r3) ++ jne .L_Z196_2 ++ j .L_Z196_3 ++.L_Z196_14: ++ mvc 0(1,%r1),0(%r3) ++END(MEMCPY_Z196) ++#endif /* HAVE_MEMCPY_Z196 */ ++ ++#if ! HAVE_MEMCPY_IFUNC ++/* If we don't use ifunc, define an alias for mem[p]cpy here. ++ Otherwise see sysdeps/s390/mem[p]cpy.c. */ ++strong_alias (MEMCPY_DEFAULT, memcpy) ++strong_alias (MEMPCPY_DEFAULT, __mempcpy) ++weak_alias (__mempcpy, mempcpy) ++#endif ++ ++#if defined SHARED && IS_IN (libc) ++/* Defines the internal symbols. ++ Compare to libc_hidden_[builtin_]def (mem[p]cpy) in string/mem[p]cpy.c. */ ++strong_alias (MEMCPY_DEFAULT, __GI_memcpy) ++strong_alias (MEMPCPY_DEFAULT, __GI_mempcpy) ++strong_alias (MEMPCPY_DEFAULT, __GI___mempcpy) ++#endif +diff --git a/sysdeps/s390/multiarch/memcpy.c b/sysdeps/s390/memcpy.c +similarity index 60% +rename from sysdeps/s390/multiarch/memcpy.c +rename to sysdeps/s390/memcpy.c +index c9577a854a0c7e68..90a53ac27d4be755 100644 +--- a/sysdeps/s390/multiarch/memcpy.c ++++ b/sysdeps/s390/memcpy.c +@@ -16,12 +16,34 @@ + License along with the GNU C Library; if not, see + . */ + +-/* In the static lib memcpy is needed before the reloc is resolved. */ +-#if defined SHARED && IS_IN (libc) ++#include ++ ++#if HAVE_MEMCPY_IFUNC + # define memcpy __redirect_memcpy + # include + # undef memcpy + # include + +-s390_libc_ifunc (__redirect_memcpy, __memcpy, memcpy) ++# if HAVE_MEMCPY_Z900_G5 ++extern __typeof (__redirect_memcpy) MEMCPY_Z900_G5 attribute_hidden; ++# endif ++ ++# if HAVE_MEMCPY_Z10 ++extern __typeof (__redirect_memcpy) MEMCPY_Z10 attribute_hidden; ++# endif ++ ++# if HAVE_MEMCPY_Z196 ++extern __typeof (__redirect_memcpy) MEMCPY_Z196 attribute_hidden; ++# endif ++ ++s390_libc_ifunc_expr (__redirect_memcpy, memcpy, ++ ({ ++ s390_libc_ifunc_init (); ++ (HAVE_MEMCPY_Z196 && S390_IS_Z196 (stfle_bits)) ++ ? MEMCPY_Z196 ++ : (HAVE_MEMCPY_Z10 && S390_IS_Z10 (stfle_bits)) ++ ? MEMCPY_Z10 ++ : MEMCPY_DEFAULT; ++ }) ++ ) + #endif +diff --git a/sysdeps/s390/mempcpy.S b/sysdeps/s390/mempcpy.S +deleted file mode 100644 +index 18ef29213e26e76d..0000000000000000 +--- a/sysdeps/s390/mempcpy.S ++++ /dev/null +@@ -1,19 +0,0 @@ +-/* CPU specific mempcpy without multiarch - 32/64 bit S/390 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 +- . */ +- +-/* mempcpy is implemented in memcpy.S. */ +diff --git a/sysdeps/s390/multiarch/mempcpy.c b/sysdeps/s390/mempcpy.c +similarity index 63% +rename from sysdeps/s390/multiarch/mempcpy.c +rename to sysdeps/s390/mempcpy.c +index 363fe47aefb80978..a6a237312659c2c1 100644 +--- a/sysdeps/s390/multiarch/mempcpy.c ++++ b/sysdeps/s390/mempcpy.c +@@ -16,8 +16,9 @@ + License along with the GNU C Library; if not, see + . */ + ++#include + +-#if defined SHARED && IS_IN (libc) ++#if HAVE_MEMCPY_IFUNC + # define mempcpy __redirect_mempcpy + # define __mempcpy __redirect___mempcpy + # define __NO_STRING_INLINES +@@ -27,6 +28,27 @@ + # undef __mempcpy + # include + +-s390_libc_ifunc (__redirect___mempcpy, ____mempcpy, __mempcpy) ++# if HAVE_MEMCPY_Z900_G5 ++extern __typeof (__redirect___mempcpy) MEMPCPY_Z900_G5 attribute_hidden; ++# endif ++ ++# if HAVE_MEMCPY_Z10 ++extern __typeof (__redirect___mempcpy) MEMPCPY_Z10 attribute_hidden; ++# endif ++ ++# if HAVE_MEMCPY_Z196 ++extern __typeof (__redirect___mempcpy) MEMPCPY_Z196 attribute_hidden; ++# endif ++ ++s390_libc_ifunc_expr (__redirect___mempcpy, __mempcpy, ++ ({ ++ s390_libc_ifunc_init (); ++ (HAVE_MEMCPY_Z196 && S390_IS_Z196 (stfle_bits)) ++ ? MEMPCPY_Z196 ++ : (HAVE_MEMCPY_Z10 && S390_IS_Z10 (stfle_bits)) ++ ? MEMPCPY_Z10 ++ : MEMPCPY_DEFAULT; ++ }) ++ ) + weak_alias (__mempcpy, mempcpy); + #endif +diff --git a/sysdeps/s390/multiarch/Makefile b/sysdeps/s390/multiarch/Makefile +index 3cbd5fad69e355a5..24949cd3a88b8015 100644 +--- a/sysdeps/s390/multiarch/Makefile ++++ b/sysdeps/s390/multiarch/Makefile +@@ -18,8 +18,7 @@ sysdep_routines += strlen strlen-vx strlen-c \ + memchr memchr-vx \ + rawmemchr rawmemchr-vx rawmemchr-c \ + memccpy memccpy-vx memccpy-c \ +- memrchr memrchr-vx memrchr-c \ +- mempcpy memcpy memcpy-s390x ++ memrchr memrchr-vx memrchr-c + endif + + ifeq ($(subdir),wcsmbs) +diff --git a/sysdeps/s390/multiarch/ifunc-impl-list.c b/sysdeps/s390/multiarch/ifunc-impl-list.c +index 2e57d01abc21522e..6969c480cc40e0e2 100644 +--- a/sysdeps/s390/multiarch/ifunc-impl-list.c ++++ b/sysdeps/s390/multiarch/ifunc-impl-list.c +@@ -23,6 +23,7 @@ + #include + #include + #include ++#include + + /* Maximum number of IFUNC implementations. */ + #define MAX_IFUNC 3 +@@ -95,23 +96,35 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + ) + #endif /* HAVE_MEMCMP_IFUNC */ + +-#ifdef SHARED +- ++#if HAVE_MEMCPY_IFUNC + IFUNC_IMPL (i, name, memcpy, ++# if HAVE_MEMCPY_Z196 + IFUNC_IMPL_ADD (array, i, memcpy, +- S390_IS_Z196 (stfle_bits), __memcpy_z196) ++ S390_IS_Z196 (stfle_bits), MEMCPY_Z196) ++# endif ++# if HAVE_MEMCPY_Z10 + IFUNC_IMPL_ADD (array, i, memcpy, +- S390_IS_Z10 (stfle_bits), __memcpy_z10) +- IFUNC_IMPL_ADD (array, i, memcpy, 1, __memcpy_default)) ++ S390_IS_Z10 (stfle_bits), MEMCPY_Z10) ++# endif ++# if HAVE_MEMCPY_Z900_G5 ++ IFUNC_IMPL_ADD (array, i, memcpy, 1, MEMCPY_Z900_G5) ++# endif ++ ) + + IFUNC_IMPL (i, name, mempcpy, ++# if HAVE_MEMCPY_Z196 + IFUNC_IMPL_ADD (array, i, mempcpy, +- S390_IS_Z196 (stfle_bits), ____mempcpy_z196) ++ S390_IS_Z196 (stfle_bits), MEMPCPY_Z196) ++# endif ++# if HAVE_MEMCPY_Z10 + IFUNC_IMPL_ADD (array, i, mempcpy, +- S390_IS_Z10 (stfle_bits), ____mempcpy_z10) +- IFUNC_IMPL_ADD (array, i, mempcpy, 1, ____mempcpy_default)) +- +-#endif /* SHARED */ ++ S390_IS_Z10 (stfle_bits), MEMPCPY_Z10) ++# endif ++# if HAVE_MEMCPY_Z900_G5 ++ IFUNC_IMPL_ADD (array, i, mempcpy, 1, MEMPCPY_Z900_G5) ++# endif ++ ) ++#endif /* HAVE_MEMCPY_IFUNC */ + + #ifdef HAVE_S390_VX_ASM_SUPPORT + +diff --git a/sysdeps/s390/multiarch/memcpy-s390x.S b/sysdeps/s390/multiarch/memcpy-s390x.S +deleted file mode 100644 +index b38caac72b8742e6..0000000000000000 +--- a/sysdeps/s390/multiarch/memcpy-s390x.S ++++ /dev/null +@@ -1,132 +0,0 @@ +-/* CPU specific memcpy implementations. 31/64 bit S/390 version. +- Copyright (C) 2012-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 "sysdep.h" +-#include "asm-syntax.h" +- +-/* INPUT PARAMETERS +- %r2 = target operands address +- %r3 = source operands address +- %r4 = number of bytes to copy. */ +- +- .text +- +-#if defined SHARED && IS_IN (libc) +- +-ENTRY(____mempcpy_z196) +- .machine "z196" +- .machinemode "zarch_nohighgprs" +- lgr %r1,%r2 # Use as dest +- la %r2,0(%r4,%r2) # Return dest + n +- j .L_Z196_start +-END(____mempcpy_z196) +- +-ENTRY(__memcpy_z196) +- .machine "z196" +- .machinemode "zarch_nohighgprs" +- lgr %r1,%r2 # r1: Use as dest ; r2: Return dest +-.L_Z196_start: +-# if !defined __s390x__ +- llgfr %r4,%r4 +-# endif /* !defined __s390x__ */ +- ltgr %r4,%r4 +- je .L_Z196_4 +- aghi %r4,-1 +- srlg %r5,%r4,8 +- ltgr %r5,%r5 +- jne .L_Z196_5 +-.L_Z196_3: +- exrl %r4,.L_Z196_14 +-.L_Z196_4: +- br %r14 +-.L_Z196_5: +- cgfi %r5,262144 # Switch to mvcle for copies >64MB +- jh __memcpy_mvcle +-.L_Z196_2: +- pfd 1,768(%r3) +- pfd 2,768(%r1) +- mvc 0(256,%r1),0(%r3) +- aghi %r5,-1 +- la %r1,256(%r1) +- la %r3,256(%r3) +- jne .L_Z196_2 +- j .L_Z196_3 +-.L_Z196_14: +- mvc 0(1,%r1),0(%r3) +-END(__memcpy_z196) +- +-ENTRY(____mempcpy_z10) +- .machine "z10" +- .machinemode "zarch_nohighgprs" +- lgr %r1,%r2 # Use as dest +- la %r2,0(%r4,%r2) # Return dest + n +- j .L_Z10_start +-END(____mempcpy_z10) +- +-ENTRY(__memcpy_z10) +- .machine "z10" +- .machinemode "zarch_nohighgprs" +- lgr %r1,%r2 # r1: Use as dest ; r2: Return dest +-.L_Z10_start: +-# if !defined __s390x__ +- llgfr %r4,%r4 +-# endif /* !defined __s390x__ */ +- cgije %r4,0,.L_Z10_4 +- aghi %r4,-1 +- srlg %r5,%r4,8 +- cgijlh %r5,0,.L_Z10_13 +-.L_Z10_3: +- exrl %r4,.L_Z10_15 +-.L_Z10_4: +- br %r14 +-.L_Z10_13: +- cgfi %r5,65535 # Switch to mvcle for copies >16MB +- jh __memcpy_mvcle +-.L_Z10_12: +- pfd 1,768(%r3) +- pfd 2,768(%r1) +- mvc 0(256,%r1),0(%r3) +- la %r1,256(%r1) +- la %r3,256(%r3) +- brctg %r5,.L_Z10_12 +- j .L_Z10_3 +-.L_Z10_15: +- mvc 0(1,%r1),0(%r3) +-END(__memcpy_z10) +- +-# define __mempcpy ____mempcpy_default +-#endif /* SHARED && IS_IN (libc) */ +- +-#define memcpy __memcpy_default +-#include "../memcpy.S" +-#undef memcpy +- +-#if defined SHARED && IS_IN (libc) +-.globl __GI_memcpy +-.set __GI_memcpy,__memcpy_default +-.globl __GI_mempcpy +-.set __GI_mempcpy,____mempcpy_default +-.globl __GI___mempcpy +-.set __GI___mempcpy,____mempcpy_default +-#else +-.globl memcpy +-.set memcpy,__memcpy_default +-.weak mempcpy +-.set mempcpy,__mempcpy +-#endif diff --git a/SOURCES/glibc-rh1659512-1.patch b/SOURCES/glibc-rh1659512-1.patch new file mode 100644 index 0000000..71956e9 --- /dev/null +++ b/SOURCES/glibc-rh1659512-1.patch @@ -0,0 +1,312 @@ +commit c70271662aa53aee0c4794d480dca6d9ba3ccc3d +Author: Adhemerval Zanella +Date: Wed Sep 19 11:12:05 2018 -0700 + + Use libsupport for tst-spawn.c + + No function changes is done. Checked on x86_64-linux-gnu. + + * posix/tst-spawn.c (do_prepare, handle_restart, do_test): + Use libsupport. + +diff --git a/posix/tst-spawn.c b/posix/tst-spawn.c +index 7c785c430c..41f1a65243 100644 +--- a/posix/tst-spawn.c ++++ b/posix/tst-spawn.c +@@ -17,16 +17,20 @@ + License along with the GNU C Library; if not, see + . */ + ++#include ++#include + #include + #include + #include + #include + #include + #include +-#include + #include ++ + #include + #include ++#include ++#include + + + /* Nonzero if the program gets called via `exec'. */ +@@ -36,16 +40,6 @@ static int restart; + #define CMDLINE_OPTIONS \ + { "restart", no_argument, &restart, 1 }, + +-/* Prototype for our test function. */ +-extern void do_prepare (int argc, char *argv[]); +-extern int do_test (int argc, char *argv[]); +- +-/* We have a preparation function. */ +-#define PREPARE do_prepare +- +-#include "../test-skeleton.c" +- +- + /* Name of the temporary files. */ + static char *name1; + static char *name2; +@@ -63,19 +57,18 @@ static const char fd3string[] = "This file will be opened"; + + + /* We have a preparation function. */ +-void ++static void + do_prepare (int argc, char *argv[]) + { + /* We must not open any files in the restart case. */ + if (restart) + return; + +- temp_fd1 = create_temp_file ("spawn", &name1); +- temp_fd2 = create_temp_file ("spawn", &name2); +- temp_fd3 = create_temp_file ("spawn", &name3); +- if (temp_fd1 < 0 || temp_fd2 < 0 || temp_fd3 < 0) +- exit (1); ++ TEST_VERIFY_EXIT ((temp_fd1 = create_temp_file ("spawn", &name1)) != -1); ++ TEST_VERIFY_EXIT ((temp_fd2 = create_temp_file ("spawn", &name2)) != -1); ++ TEST_VERIFY_EXIT ((temp_fd3 = create_temp_file ("spawn", &name3)) != -1); + } ++#define PREPARE do_prepare + + + static int +@@ -95,64 +88,45 @@ handle_restart (const char *fd1s, const char *fd2s, const char *fd3s, + fd4 = atol (fd4s); + + /* Sanity check. */ +- if (fd1 == fd2) +- error (EXIT_FAILURE, 0, "value of fd1 and fd2 is the same"); +- if (fd1 == fd3) +- error (EXIT_FAILURE, 0, "value of fd1 and fd3 is the same"); +- if (fd1 == fd4) +- error (EXIT_FAILURE, 0, "value of fd1 and fd4 is the same"); +- if (fd2 == fd3) +- error (EXIT_FAILURE, 0, "value of fd2 and fd3 is the same"); +- if (fd2 == fd4) +- error (EXIT_FAILURE, 0, "value of fd2 and fd4 is the same"); +- if (fd3 == fd4) +- error (EXIT_FAILURE, 0, "value of fd3 and fd4 is the same"); ++ TEST_VERIFY_EXIT (fd1 != fd2); ++ TEST_VERIFY_EXIT (fd1 != fd3); ++ TEST_VERIFY_EXIT (fd1 != fd4); ++ TEST_VERIFY_EXIT (fd2 != fd3); ++ TEST_VERIFY_EXIT (fd2 != fd4); ++ TEST_VERIFY_EXIT (fd3 != fd4); + + /* First the easy part: read from the file descriptor which is + supposed to be open. */ +- if (lseek (fd2, 0, SEEK_CUR) != strlen (fd2string)) +- error (EXIT_FAILURE, errno, "file 2 not in right position"); ++ TEST_COMPARE (xlseek (fd2, 0, SEEK_CUR), strlen (fd2string)); + /* The duped descriptor must have the same position. */ +- if (lseek (fd4, 0, SEEK_CUR) != strlen (fd2string)) +- error (EXIT_FAILURE, errno, "file 4 not in right position"); +- if (lseek (fd2, 0, SEEK_SET) != 0) +- error (EXIT_FAILURE, 0, "cannot reset position in file 2"); +- if (lseek (fd4, 0, SEEK_CUR) != 0) +- error (EXIT_FAILURE, errno, "file 4 not set back, too"); +- if (read (fd2, buf, sizeof buf) != strlen (fd2string)) +- error (EXIT_FAILURE, 0, "cannot read file 2"); +- if (memcmp (fd2string, buf, strlen (fd2string)) != 0) +- error (EXIT_FAILURE, 0, "file 2 does not match"); ++ TEST_COMPARE (xlseek (fd4, 0, SEEK_CUR), strlen (fd2string)); ++ TEST_COMPARE (xlseek (fd2, 0, SEEK_SET), 0); ++ TEST_COMPARE (xlseek (fd4, 0, SEEK_CUR), 0); ++ TEST_COMPARE (read (fd2, buf, sizeof buf), strlen (fd2string)); ++ TEST_COMPARE_BLOB (fd2string, strlen (fd2string), buf, strlen (fd2string)); + + /* Now read from the third file. */ +- if (read (fd3, buf, sizeof buf) != strlen (fd3string)) +- error (EXIT_FAILURE, 0, "cannot read file 3"); +- if (memcmp (fd3string, buf, strlen (fd3string)) != 0) +- error (EXIT_FAILURE, 0, "file 3 does not match"); ++ TEST_COMPARE (read (fd3, buf, sizeof buf), strlen (fd3string)); ++ TEST_COMPARE_BLOB (fd3string, strlen (fd3string), buf, strlen (fd3string)); + /* Try to write to the file. This should not be allowed. */ +- if (write (fd3, "boo!", 4) != -1 || errno != EBADF) +- error (EXIT_FAILURE, 0, "file 3 is writable"); ++ TEST_COMPARE (write (fd3, "boo!", 4), -1); ++ TEST_COMPARE (errno, EBADF); + + /* Now try to read the first file. First make sure it is not opened. */ +- if (lseek (fd1, 0, SEEK_CUR) != (off_t) -1 || errno != EBADF) +- error (EXIT_FAILURE, 0, "file 1 (%d) is not closed", fd1); ++ TEST_COMPARE (lseek (fd1, 0, SEEK_CUR), (off_t) -1); ++ TEST_COMPARE (errno, EBADF); + + /* Now open the file and read it. */ +- fd1 = open (name, O_RDONLY); +- if (fd1 == -1) +- error (EXIT_FAILURE, errno, +- "cannot open first file \"%s\" for verification", name); ++ fd1 = xopen (name, O_RDONLY, 0600); + +- if (read (fd1, buf, sizeof buf) != strlen (fd1string)) +- error (EXIT_FAILURE, errno, "cannot read file 1"); +- if (memcmp (fd1string, buf, strlen (fd1string)) != 0) +- error (EXIT_FAILURE, 0, "file 1 does not match"); ++ TEST_COMPARE (read (fd1, buf, sizeof buf), strlen (fd1string)); ++ TEST_COMPARE_BLOB (fd1string, strlen (fd1string), buf, strlen (fd1string)); + + return 0; + } + + +-int ++static int + do_test (int argc, char *argv[]) + { + pid_t pid; +@@ -181,7 +155,7 @@ do_test (int argc, char *argv[]) + + the name of the closed descriptor + */ + if (argc != (restart ? 6 : 2) && argc != (restart ? 6 : 5)) +- error (EXIT_FAILURE, 0, "wrong number of arguments (%d)", argc); ++ FAIL_EXIT1 ("wrong number of arguments (%d)", argc); + + if (restart) + return handle_restart (argv[1], argv[2], argv[3], argv[4], argv[5]); +@@ -189,77 +163,73 @@ do_test (int argc, char *argv[]) + /* Prepare the test. We are creating two files: one which file descriptor + will be marked with FD_CLOEXEC, another which is not. */ + +- /* Write something in the files. */ +- if (write (temp_fd1, fd1string, strlen (fd1string)) != strlen (fd1string)) +- error (EXIT_FAILURE, errno, "cannot write to first file"); +- if (write (temp_fd2, fd2string, strlen (fd2string)) != strlen (fd2string)) +- error (EXIT_FAILURE, errno, "cannot write to second file"); +- if (write (temp_fd3, fd3string, strlen (fd3string)) != strlen (fd3string)) +- error (EXIT_FAILURE, errno, "cannot write to third file"); +- +- /* Close the third file. It'll be opened by `spawn'. */ +- close (temp_fd3); +- +- /* Tell `spawn' what to do. */ +- if (posix_spawn_file_actions_init (&actions) != 0) +- error (EXIT_FAILURE, errno, "posix_spawn_file_actions_init"); +- /* Close `temp_fd1'. */ +- if (posix_spawn_file_actions_addclose (&actions, temp_fd1) != 0) +- error (EXIT_FAILURE, errno, "posix_spawn_file_actions_addclose"); +- /* We want to open the third file. */ +- name3_copy = strdup (name3); +- if (name3_copy == NULL) +- error (EXIT_FAILURE, errno, "strdup"); +- if (posix_spawn_file_actions_addopen (&actions, temp_fd3, name3_copy, +- O_RDONLY, 0666) != 0) +- error (EXIT_FAILURE, errno, "posix_spawn_file_actions_addopen"); +- /* Overwrite the name to check that a copy has been made. */ +- memset (name3_copy, 'X', strlen (name3_copy)); +- +- /* We dup the second descriptor. */ +- fd4 = MAX (2, MAX (temp_fd1, MAX (temp_fd2, temp_fd3))) + 1; +- if (posix_spawn_file_actions_adddup2 (&actions, temp_fd2, fd4) != 0) +- error (EXIT_FAILURE, errno, "posix_spawn_file_actions_adddup2"); +- +- /* Now spawn the process. */ +- snprintf (fd1name, sizeof fd1name, "%d", temp_fd1); +- snprintf (fd2name, sizeof fd2name, "%d", temp_fd2); +- snprintf (fd3name, sizeof fd3name, "%d", temp_fd3); +- snprintf (fd4name, sizeof fd4name, "%d", fd4); +- +- for (i = 0; i < (argc == (restart ? 6 : 5) ? 4 : 1); i++) +- spargv[i] = argv[i + 1]; +- spargv[i++] = (char *) "--direct"; +- spargv[i++] = (char *) "--restart"; +- spargv[i++] = fd1name; +- spargv[i++] = fd2name; +- spargv[i++] = fd3name; +- spargv[i++] = fd4name; +- spargv[i++] = name1; +- spargv[i] = NULL; +- +- if (posix_spawn (&pid, argv[1], &actions, NULL, spargv, environ) != 0) +- error (EXIT_FAILURE, errno, "posix_spawn"); +- +- /* Same test but with a NULL pid argument. */ +- if (posix_spawn (NULL, argv[1], &actions, NULL, spargv, environ) != 0) +- error (EXIT_FAILURE, errno, "posix_spawn"); +- +- /* Cleanup. */ +- if (posix_spawn_file_actions_destroy (&actions) != 0) +- error (EXIT_FAILURE, errno, "posix_spawn_file_actions_destroy"); +- free (name3_copy); ++ /* Write something in the files. */ ++ xwrite (temp_fd1, fd1string, strlen (fd1string)); ++ xwrite (temp_fd2, fd2string, strlen (fd2string)); ++ xwrite (temp_fd3, fd3string, strlen (fd3string)); ++ ++ /* Close the third file. It'll be opened by `spawn'. */ ++ xclose (temp_fd3); ++ ++ /* Tell `spawn' what to do. */ ++ TEST_COMPARE (posix_spawn_file_actions_init (&actions), 0); ++ /* Close `temp_fd1'. */ ++ TEST_COMPARE (posix_spawn_file_actions_addclose (&actions, temp_fd1), 0); ++ /* We want to open the third file. */ ++ name3_copy = xstrdup (name3); ++ TEST_COMPARE (posix_spawn_file_actions_addopen (&actions, temp_fd3, ++ name3_copy, ++ O_RDONLY, 0666), ++ 0); ++ /* Overwrite the name to check that a copy has been made. */ ++ memset (name3_copy, 'X', strlen (name3_copy)); ++ ++ /* We dup the second descriptor. */ ++ fd4 = MAX (2, MAX (temp_fd1, MAX (temp_fd2, temp_fd3))) + 1; ++ TEST_COMPARE (posix_spawn_file_actions_adddup2 (&actions, temp_fd2, fd4), ++ 0); ++ ++ /* Now spawn the process. */ ++ snprintf (fd1name, sizeof fd1name, "%d", temp_fd1); ++ snprintf (fd2name, sizeof fd2name, "%d", temp_fd2); ++ snprintf (fd3name, sizeof fd3name, "%d", temp_fd3); ++ snprintf (fd4name, sizeof fd4name, "%d", fd4); ++ ++ for (i = 0; i < (argc == (restart ? 6 : 5) ? 4 : 1); i++) ++ spargv[i] = argv[i + 1]; ++ spargv[i++] = (char *) "--direct"; ++ spargv[i++] = (char *) "--restart"; ++ spargv[i++] = fd1name; ++ spargv[i++] = fd2name; ++ spargv[i++] = fd3name; ++ spargv[i++] = fd4name; ++ spargv[i++] = name1; ++ spargv[i] = NULL; ++ ++ TEST_COMPARE (posix_spawn (&pid, argv[1], &actions, NULL, spargv, environ), ++ 0); ++ ++ /* Same test but with a NULL pid argument. */ ++ TEST_COMPARE (posix_spawn (NULL, argv[1], &actions, NULL, spargv, environ), ++ 0); ++ ++ /* Cleanup. */ ++ TEST_COMPARE (posix_spawn_file_actions_destroy (&actions), 0); ++ free (name3_copy); + + /* Wait for the children. */ +- TEST_VERIFY (xwaitpid (pid, &status, 0) == pid); ++ TEST_COMPARE (xwaitpid (pid, &status, 0), pid); + TEST_VERIFY (WIFEXITED (status)); + TEST_VERIFY (!WIFSIGNALED (status)); +- TEST_VERIFY (WEXITSTATUS (status) == 0); ++ TEST_COMPARE (WEXITSTATUS (status), 0); + + xwaitpid (-1, &status, 0); + TEST_VERIFY (WIFEXITED (status)); + TEST_VERIFY (!WIFSIGNALED (status)); +- TEST_VERIFY (WEXITSTATUS (status) == 0); ++ TEST_COMPARE (WEXITSTATUS (status), 0); + + return 0; + } ++ ++#define TEST_FUNCTION_ARGV do_test ++#include diff --git a/SOURCES/glibc-rh1659512-2.patch b/SOURCES/glibc-rh1659512-2.patch new file mode 100644 index 0000000..ac36900 --- /dev/null +++ b/SOURCES/glibc-rh1659512-2.patch @@ -0,0 +1,62 @@ +commit 114f792eaea2505cd8aee02d330aad37238da6a5 +Author: Stefan Liebler +Date: Fri Feb 1 11:03:35 2019 +0100 + + posix/tst-spawn: Fix racy tests in spawned processes. + + From time to time I get fails in tst-spawn like: + tst-spawn.c:111: numeric comparison failure + left: 0 (0x0); from: xlseek (fd2, 0, SEEK_CUR) + right: 28 (0x1c); from: strlen (fd2string) + error: 1 test failures + tst-spawn.c:252: numeric comparison failure + left: 1 (0x1); from: WEXITSTATUS (status) + right: 0 (0x0); from: 0 + error: 1 test failures + + It turned out, that a child process is testing it's open file descriptors + with e.g. a sequence of testing the current position, setting the position + to zero and reading a specific amount of bytes. + + Unfortunately starting with commit 2a69f853c03034c2e383e0f9c35b5402ce8b5473 + the test is spawning a second child process which is sharing some of the + file descriptors. If the test sequence as mentioned above is running in parallel + it leads to test failures. + + As the second call of posix_spawn shall test a NULL pid argument, + this patch is just moving the waitpid of the first child + before the posix_spawn of the second child. + + ChangeLog: + + * posix/tst-spawn do_test(): Move waitpid before posix_spawn. + +diff --git a/posix/tst-spawn.c b/posix/tst-spawn.c +index eea5addbf3..9aa7e621e6 100644 +--- a/posix/tst-spawn.c ++++ b/posix/tst-spawn.c +@@ -237,6 +237,12 @@ do_test (int argc, char *argv[]) + TEST_COMPARE (posix_spawn (&pid, argv[1], &actions, NULL, spargv, environ), + 0); + ++ /* Wait for the children. */ ++ TEST_COMPARE (xwaitpid (pid, &status, 0), pid); ++ TEST_VERIFY (WIFEXITED (status)); ++ TEST_VERIFY (!WIFSIGNALED (status)); ++ TEST_COMPARE (WEXITSTATUS (status), 0); ++ + /* Same test but with a NULL pid argument. */ + TEST_COMPARE (posix_spawn (NULL, argv[1], &actions, NULL, spargv, environ), + 0); +@@ -246,11 +252,6 @@ do_test (int argc, char *argv[]) + free (name3_copy); + + /* Wait for the children. */ +- TEST_COMPARE (xwaitpid (pid, &status, 0), pid); +- TEST_VERIFY (WIFEXITED (status)); +- TEST_VERIFY (!WIFSIGNALED (status)); +- TEST_COMPARE (WEXITSTATUS (status), 0); +- + xwaitpid (-1, &status, 0); + TEST_VERIFY (WIFEXITED (status)); + TEST_VERIFY (!WIFSIGNALED (status)); diff --git a/SOURCES/glibc-rh1662843-1.patch b/SOURCES/glibc-rh1662843-1.patch new file mode 100644 index 0000000..5261045 --- /dev/null +++ b/SOURCES/glibc-rh1662843-1.patch @@ -0,0 +1,206 @@ +commit 1ecba1fafc160ca70f81211b23f688df8676e612 +Author: Florian Weimer +Date: Mon Nov 12 14:15:14 2018 +0100 + + malloc: Convert the unlink macro to the unlink_chunk function + + This commit is in preparation of turning the macro into a proper + function. The output arguments of the macro were in fact unused. + + Also clean up uses of __builtin_expect. + +diff --git a/malloc/arena.c b/malloc/arena.c +index 497ae475e7a85902..ff8fd5d2a7e51ac8 100644 +--- a/malloc/arena.c ++++ b/malloc/arena.c +@@ -596,7 +596,7 @@ heap_trim (heap_info *heap, size_t pad) + { + mstate ar_ptr = heap->ar_ptr; + unsigned long pagesz = GLRO (dl_pagesize); +- mchunkptr top_chunk = top (ar_ptr), p, bck, fwd; ++ mchunkptr top_chunk = top (ar_ptr), p; + heap_info *prev_heap; + long new_size, top_size, top_area, extra, prev_size, misalign; + +@@ -625,7 +625,7 @@ heap_trim (heap_info *heap, size_t pad) + if (!prev_inuse (p)) /* consolidate backward */ + { + p = prev_chunk (p); +- unlink (ar_ptr, p, bck, fwd); ++ unlink_chunk (ar_ptr, p); + } + assert (((unsigned long) ((char *) p + new_size) & (pagesz - 1)) == 0); + assert (((char *) p + new_size) == ((char *) heap + heap->size)); +diff --git a/malloc/malloc.c b/malloc/malloc.c +index e450597e2e527fb7..7bfa66a56786d110 100644 +--- a/malloc/malloc.c ++++ b/malloc/malloc.c +@@ -1384,39 +1384,6 @@ typedef struct malloc_chunk *mbinptr; + #define first(b) ((b)->fd) + #define last(b) ((b)->bk) + +-/* Take a chunk off a bin list */ +-#define unlink(AV, P, BK, FD) { \ +- if (__builtin_expect (chunksize(P) != prev_size (next_chunk(P)), 0)) \ +- malloc_printerr ("corrupted size vs. prev_size"); \ +- FD = P->fd; \ +- BK = P->bk; \ +- if (__builtin_expect (FD->bk != P || BK->fd != P, 0)) \ +- malloc_printerr ("corrupted double-linked list"); \ +- else { \ +- FD->bk = BK; \ +- BK->fd = FD; \ +- if (!in_smallbin_range (chunksize_nomask (P)) \ +- && __builtin_expect (P->fd_nextsize != NULL, 0)) { \ +- if (__builtin_expect (P->fd_nextsize->bk_nextsize != P, 0) \ +- || __builtin_expect (P->bk_nextsize->fd_nextsize != P, 0)) \ +- malloc_printerr ("corrupted double-linked list (not small)"); \ +- if (FD->fd_nextsize == NULL) { \ +- if (P->fd_nextsize == P) \ +- FD->fd_nextsize = FD->bk_nextsize = FD; \ +- else { \ +- FD->fd_nextsize = P->fd_nextsize; \ +- FD->bk_nextsize = P->bk_nextsize; \ +- P->fd_nextsize->bk_nextsize = FD; \ +- P->bk_nextsize->fd_nextsize = FD; \ +- } \ +- } else { \ +- P->fd_nextsize->bk_nextsize = P->bk_nextsize; \ +- P->bk_nextsize->fd_nextsize = P->fd_nextsize; \ +- } \ +- } \ +- } \ +-} +- + /* + Indexing + +@@ -1489,6 +1456,46 @@ typedef struct malloc_chunk *mbinptr; + #define bin_index(sz) \ + ((in_smallbin_range (sz)) ? smallbin_index (sz) : largebin_index (sz)) + ++/* Take a chunk off a bin list. */ ++static void ++unlink_chunk (mstate av, mchunkptr p) ++{ ++ if (chunksize (p) != prev_size (next_chunk (p))) ++ malloc_printerr ("corrupted size vs. prev_size"); ++ ++ mchunkptr fd = p->fd; ++ mchunkptr bk = p->bk; ++ ++ if (__builtin_expect (fd->bk != p || bk->fd != p, 0)) ++ malloc_printerr ("corrupted double-linked list"); ++ ++ fd->bk = bk; ++ bk->fd = fd; ++ if (!in_smallbin_range (chunksize_nomask (p)) && p->fd_nextsize != NULL) ++ { ++ if (p->fd_nextsize->bk_nextsize != p ++ || p->bk_nextsize->fd_nextsize != p) ++ malloc_printerr ("corrupted double-linked list (not small)"); ++ ++ if (fd->fd_nextsize == NULL) ++ { ++ if (p->fd_nextsize == p) ++ fd->fd_nextsize = fd->bk_nextsize = fd; ++ else ++ { ++ fd->fd_nextsize = p->fd_nextsize; ++ fd->bk_nextsize = p->bk_nextsize; ++ p->fd_nextsize->bk_nextsize = fd; ++ p->bk_nextsize->fd_nextsize = fd; ++ } ++ } ++ else ++ { ++ p->fd_nextsize->bk_nextsize = p->bk_nextsize; ++ p->bk_nextsize->fd_nextsize = p->fd_nextsize; ++ } ++ } ++} + + /* + Unsorted chunks +@@ -3917,7 +3924,7 @@ _int_malloc (mstate av, size_t bytes) + victim = victim->fd; + + remainder_size = size - nb; +- unlink (av, victim, bck, fwd); ++ unlink_chunk (av, victim); + + /* Exhaust */ + if (remainder_size < MINSIZE) +@@ -4019,7 +4026,7 @@ _int_malloc (mstate av, size_t bytes) + remainder_size = size - nb; + + /* unlink */ +- unlink (av, victim, bck, fwd); ++ unlink_chunk (av, victim); + + /* Exhaust */ + if (remainder_size < MINSIZE) +@@ -4308,7 +4315,7 @@ _int_free (mstate av, mchunkptr p, int have_lock) + p = chunk_at_offset(p, -((long) prevsize)); + if (__glibc_unlikely (chunksize(p) != prevsize)) + malloc_printerr ("corrupted size vs. prev_size while consolidating"); +- unlink(av, p, bck, fwd); ++ unlink_chunk (av, p); + } + + if (nextchunk != av->top) { +@@ -4317,7 +4324,7 @@ _int_free (mstate av, mchunkptr p, int have_lock) + + /* consolidate forward */ + if (!nextinuse) { +- unlink(av, nextchunk, bck, fwd); ++ unlink_chunk (av, nextchunk); + size += nextsize; + } else + clear_inuse_bit_at_offset(nextchunk, 0); +@@ -4430,8 +4437,6 @@ static void malloc_consolidate(mstate av) + INTERNAL_SIZE_T nextsize; + INTERNAL_SIZE_T prevsize; + int nextinuse; +- mchunkptr bck; +- mchunkptr fwd; + + atomic_store_relaxed (&av->have_fastchunks, false); + +@@ -4471,7 +4476,7 @@ static void malloc_consolidate(mstate av) + p = chunk_at_offset(p, -((long) prevsize)); + if (__glibc_unlikely (chunksize(p) != prevsize)) + malloc_printerr ("corrupted size vs. prev_size in fastbins"); +- unlink(av, p, bck, fwd); ++ unlink_chunk (av, p); + } + + if (nextchunk != av->top) { +@@ -4479,7 +4484,7 @@ static void malloc_consolidate(mstate av) + + if (!nextinuse) { + size += nextsize; +- unlink(av, nextchunk, bck, fwd); ++ unlink_chunk (av, nextchunk); + } else + clear_inuse_bit_at_offset(nextchunk, 0); + +@@ -4527,9 +4532,6 @@ _int_realloc(mstate av, mchunkptr oldp, INTERNAL_SIZE_T oldsize, + mchunkptr remainder; /* extra space at end of newp */ + unsigned long remainder_size; /* its size */ + +- mchunkptr bck; /* misc temp for linking */ +- mchunkptr fwd; /* misc temp for linking */ +- + unsigned long copysize; /* bytes to copy */ + unsigned int ncopies; /* INTERNAL_SIZE_T words to copy */ + INTERNAL_SIZE_T* s; /* copy source */ +@@ -4579,7 +4581,7 @@ _int_realloc(mstate av, mchunkptr oldp, INTERNAL_SIZE_T oldsize, + (unsigned long) (nb)) + { + newp = oldp; +- unlink (av, next, bck, fwd); ++ unlink_chunk (av, next); + } + + /* allocate, copy, free */ diff --git a/SOURCES/glibc-rh1662843-2.patch b/SOURCES/glibc-rh1662843-2.patch new file mode 100644 index 0000000..27fe8c8 --- /dev/null +++ b/SOURCES/glibc-rh1662843-2.patch @@ -0,0 +1,73 @@ +commit b50dd3bc8cbb1efe85399b03d7e6c0310c2ead84 +Author: Florian Weimer +Date: Mon Dec 31 22:04:36 2018 +0100 + + malloc: Always call memcpy in _int_realloc [BZ #24027] + + This commit removes the custom memcpy implementation from _int_realloc + for small chunk sizes. The ncopies variable has the wrong type, and + an integer wraparound could cause the existing code to copy too few + elements (leaving the new memory region mostly uninitialized). + Therefore, removing this code fixes bug 24027. + +diff --git a/malloc/malloc.c b/malloc/malloc.c +index 7bfa66a56786d110..0234d968c0ce65a0 100644 +--- a/malloc/malloc.c ++++ b/malloc/malloc.c +@@ -4532,11 +4532,6 @@ _int_realloc(mstate av, mchunkptr oldp, INTERNAL_SIZE_T oldsize, + mchunkptr remainder; /* extra space at end of newp */ + unsigned long remainder_size; /* its size */ + +- unsigned long copysize; /* bytes to copy */ +- unsigned int ncopies; /* INTERNAL_SIZE_T words to copy */ +- INTERNAL_SIZE_T* s; /* copy source */ +- INTERNAL_SIZE_T* d; /* copy destination */ +- + /* oldmem size */ + if (__builtin_expect (chunksize_nomask (oldp) <= 2 * SIZE_SZ, 0) + || __builtin_expect (oldsize >= av->system_mem, 0)) +@@ -4604,43 +4599,7 @@ _int_realloc(mstate av, mchunkptr oldp, INTERNAL_SIZE_T oldsize, + } + else + { +- /* +- Unroll copy of <= 36 bytes (72 if 8byte sizes) +- We know that contents have an odd number of +- INTERNAL_SIZE_T-sized words; minimally 3. +- */ +- +- copysize = oldsize - SIZE_SZ; +- s = (INTERNAL_SIZE_T *) (chunk2mem (oldp)); +- d = (INTERNAL_SIZE_T *) (newmem); +- ncopies = copysize / sizeof (INTERNAL_SIZE_T); +- assert (ncopies >= 3); +- +- if (ncopies > 9) +- memcpy (d, s, copysize); +- +- else +- { +- *(d + 0) = *(s + 0); +- *(d + 1) = *(s + 1); +- *(d + 2) = *(s + 2); +- if (ncopies > 4) +- { +- *(d + 3) = *(s + 3); +- *(d + 4) = *(s + 4); +- if (ncopies > 6) +- { +- *(d + 5) = *(s + 5); +- *(d + 6) = *(s + 6); +- if (ncopies > 8) +- { +- *(d + 7) = *(s + 7); +- *(d + 8) = *(s + 8); +- } +- } +- } +- } +- ++ memcpy (newmem, chunk2mem (oldp), oldsize - SIZE_SZ); + _int_free (av, oldp, 1); + check_inuse_chunk (av, newp); + return chunk2mem (newp); diff --git a/SOURCES/glibc-rh1663035.patch b/SOURCES/glibc-rh1663035.patch new file mode 100644 index 0000000..ec38f0a --- /dev/null +++ b/SOURCES/glibc-rh1663035.patch @@ -0,0 +1,22 @@ +commit 8c1aafc1f34d090a5b41dc527c33e8687f6a1287 +Author: Florian Weimer +Date: Fri Dec 21 16:08:55 2018 +0100 + + intl: Do not return NULL on asprintf failure in gettext [BZ #24018] + + Fixes commit 9695dd0c9309712ed8e9c17a7040fe7af347f2dc ("DCIGETTEXT: + Use getcwd, asprintf to construct absolute pathname"). + +diff --git a/intl/dcigettext.c b/intl/dcigettext.c +index 2a5036994824875b..25f47c5bd3b0ea04 100644 +--- a/intl/dcigettext.c ++++ b/intl/dcigettext.c +@@ -631,7 +631,7 @@ DCIGETTEXT (const char *domainname, const char *msgid1, const char *msgid2, + int ret = __asprintf (&xdirname, "%s/%s", cwd, dirname); + free (cwd); + if (ret < 0) +- return NULL; ++ goto return_untranslated; + dirname = xdirname; + } + #ifndef IN_LIBGLOCALE diff --git a/SOURCES/glibc-rh1664408.patch b/SOURCES/glibc-rh1664408.patch new file mode 100644 index 0000000..f2f960f --- /dev/null +++ b/SOURCES/glibc-rh1664408.patch @@ -0,0 +1,131 @@ +commit 2ef427168818ce04b03cecb7b739f9db0156e3e4 +Author: Aurelien Jarno +Date: Thu Jan 3 15:51:37 2019 +0100 + + Only build libm with -fno-math-errno (bug 24024) + + Commit 1294b1892e ("Add support for sqrt asm redirects") added the + -fno-math-errno flag to build most of the glibc in order to enable GCC + to inline math functions. Due to GCC bug #88576, saving and restoring + errno around calls to malloc are optimized-out. In turn this causes + strerror to set errno to ENOMEM if it get passed an invalid error number + and if malloc sets errno to ENOMEM (which might happen even if it + succeeds). This is not allowed by POSIX. + + This patch changes the build flags, building only libm with + -fno-math-errno and all the remaining code with -fno-math-errno. This + should be safe as libm doesn't contain any code saving and restoring + errno around malloc. This patch can probably be reverted once the GCC + bug is fixed and available in stable releases. + + Tested on x86-64, no regression in the testsuite. + + Changelog: + [BZ #24024] + * Makeconfig: Build libm with -fno-math-errno but build the remaining + code with -fmath-errno. + * string/Makefile [$(build-shared)] (tests): Add test-strerror-errno. + [$(build-shared)] (LDLIBS-test-strerror-errno): New variable. + * string/test-strerror-errno.c: New file. + +diff --git a/Makeconfig b/Makeconfig +index 92e76d6200bbcd5b..8dc2fec9dc683416 100644 +--- a/Makeconfig ++++ b/Makeconfig +@@ -831,8 +831,10 @@ endif + # disable any optimization that assume default rounding mode. + +math-flags = -frounding-math + +-# Build libc/libm using -fno-math-errno, but run testsuite with -fmath-errno. +-+extra-math-flags = $(if $(filter libnldbl nonlib testsuite,$(in-module)),-fmath-errno,-fno-math-errno) ++# Logically only "libnldbl", "nonlib" and "testsuite" should be using ++# -fno-math-errno. However due to GCC bug #88576, only "libm" can use ++# -fno-math-errno. +++extra-math-flags = $(if $(filter libm,$(in-module)),-fno-math-errno,-fmath-errno) + + # We might want to compile with some stack-protection flag. + ifneq ($(stack-protector),) +diff --git a/string/Makefile b/string/Makefile +index 680431f92185f914..aa2da9ca72262886 100644 +--- a/string/Makefile ++++ b/string/Makefile +@@ -64,6 +64,12 @@ tests := tester inl-tester noinl-tester testcopy test-ffs \ + # This test allocates a lot of memory and can run for a long time. + xtests = tst-strcoll-overflow + ++# This test needs libdl. ++ifeq (yes,$(build-shared)) ++tests += test-strerror-errno ++LDLIBS-test-strerror-errno = $(libdl) ++endif ++ + ifeq ($(run-built-tests),yes) + tests-special += $(objpfx)tst-svc-cmp.out + endif +diff --git a/string/test-strerror-errno.c b/string/test-strerror-errno.c +new file mode 100644 +index 0000000000000000..8e744e7ed9df5924 +--- /dev/null ++++ b/string/test-strerror-errno.c +@@ -0,0 +1,61 @@ ++/* BZ #24024 strerror and errno test. ++ ++ 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, see ++ . */ ++ ++#include ++#include ++#include ++ ++#include ++#include ++ ++/* malloc is allowed to change errno to a value different than 0, even when ++ there is no actual error. This happens for example when the memory ++ allocation through sbrk fails. Simulate this by interposing our own ++ malloc implementation which sets errno to ENOMEM and calls the original ++ malloc. */ ++void ++*malloc (size_t size) ++{ ++ static void *(*real_malloc) (size_t size); ++ ++ if (!real_malloc) ++ real_malloc = dlsym (RTLD_NEXT, "malloc"); ++ ++ errno = ENOMEM; ++ ++ return (*real_malloc) (size); ++} ++ ++/* strerror must not change the value of errno. Unfortunately due to GCC bug ++ #88576, this happens when -fmath-errno is used. This simple test checks ++ that it doesn't happen. */ ++static int ++do_test (void) ++{ ++ char *msg; ++ ++ errno = 0; ++ msg = strerror (-3); ++ (void) msg; ++ TEST_COMPARE (errno, 0); ++ ++ return 0; ++} ++ ++#include diff --git a/SOURCES/glibc-rh1670043-1.patch b/SOURCES/glibc-rh1670043-1.patch new file mode 100644 index 0000000..73939d9 --- /dev/null +++ b/SOURCES/glibc-rh1670043-1.patch @@ -0,0 +1,104 @@ +commit 08504de71813ddbd447bfbca4a325cbe8ce8bcda +Author: Florian Weimer +Date: Tue Mar 12 11:40:47 2019 +0100 + + resolv: Enable full ICMP errors for UDP DNS sockets [BZ #24047] + + The Linux kernel suppresses some ICMP error messages by default for + UDP sockets. This commit enables full ICMP error reporting, + hopefully resulting in faster failover to working name servers. + +diff --git a/resolv/Makefile b/resolv/Makefile +index 8f22e6a154..ebe1b733f2 100644 +--- a/resolv/Makefile ++++ b/resolv/Makefile +@@ -105,7 +105,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 \ ++ ns_samedomain ns_date res_enable_icmp \ + compat-hooks compat-gethnamaddr + + libanl-routines := gai_cancel gai_error gai_misc gai_notify gai_suspend \ +diff --git a/resolv/res_enable_icmp.c b/resolv/res_enable_icmp.c +new file mode 100644 +index 0000000000..bdc9220f08 +--- /dev/null ++++ b/resolv/res_enable_icmp.c +@@ -0,0 +1,37 @@ ++/* Enable full ICMP errors on a socket. ++ 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, see ++ . */ ++ ++#include ++#include ++#include ++ ++int ++__res_enable_icmp (int family, int fd) ++{ ++ int one = 1; ++ switch (family) ++ { ++ case AF_INET: ++ return setsockopt (fd, SOL_IP, IP_RECVERR, &one, sizeof (one)); ++ case AF_INET6: ++ return setsockopt (fd, SOL_IPV6, IPV6_RECVERR, &one, sizeof (one)); ++ default: ++ __set_errno (EAFNOSUPPORT); ++ return -1; ++ } ++} +diff --git a/resolv/res_send.c b/resolv/res_send.c +index fa040c1198..0f6ec83a7b 100644 +--- a/resolv/res_send.c ++++ b/resolv/res_send.c +@@ -943,6 +943,18 @@ reopen (res_state statp, int *terrno, int ns) + return (-1); + } + ++ /* Enable full ICMP error reporting for this ++ socket. */ ++ if (__res_enable_icmp (nsap->sa_family, ++ EXT (statp).nssocks[ns]) < 0) ++ { ++ int saved_errno = errno; ++ __res_iclose (statp, false); ++ __set_errno (saved_errno); ++ *terrno = saved_errno; ++ return -1; ++ } ++ + /* + * On a 4.3BSD+ machine (client and server, + * actually), sending to a nameserver datagram +diff --git a/resolv/resolv-internal.h b/resolv/resolv-internal.h +index 6ab8f2af09..1500adc607 100644 +--- a/resolv/resolv-internal.h ++++ b/resolv/resolv-internal.h +@@ -100,4 +100,10 @@ libc_hidden_proto (__inet_pton_length) + /* Called as part of the thread shutdown sequence. */ + void __res_thread_freeres (void) attribute_hidden; + ++/* The Linux kernel does not enable all ICMP messages on a UDP socket ++ by default. A call this function enables full error reporting for ++ the socket FD. FAMILY must be AF_INET or AF_INET6. Returns 0 on ++ success, -1 on failure. */ ++int __res_enable_icmp (int family, int fd) attribute_hidden; ++ + #endif /* _RESOLV_INTERNAL_H */ diff --git a/SOURCES/glibc-rh1670043-2.patch b/SOURCES/glibc-rh1670043-2.patch new file mode 100644 index 0000000..d73d211 --- /dev/null +++ b/SOURCES/glibc-rh1670043-2.patch @@ -0,0 +1,47 @@ +commit 043440e761d395e1f507d9faa6e82b3fe4536c3f +Author: Florian Weimer +Date: Wed Mar 13 14:58:58 2019 +0100 + + hurd: Add no-op version of __res_enable_icmp [BZ #24047] + + Mach does not support IP_RECVERR, so replace this function with a + stub in a sysdeps override for Hurd. + + This fixes commit 08504de71813ddbd447bfbca4a325cbe8ce8bcda + ("resolv: Enable full ICMP errors for UDP DNS sockets [BZ #24047]"). + + Reviewed-by: Carlos O'Donell + +diff --git a/sysdeps/mach/hurd/res_enable_icmp.c b/sysdeps/mach/hurd/res_enable_icmp.c +new file mode 100644 +index 0000000000..4b0456340c +--- /dev/null ++++ b/sysdeps/mach/hurd/res_enable_icmp.c +@@ -0,0 +1,27 @@ ++/* Enable full ICMP errors on a socket. No-op version for Hurd. ++ 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, see ++ . */ ++ ++/* Mach does not support the IP_RECVERR extension. */ ++ ++#include ++ ++int ++__res_enable_icmp (int family, int fd) ++{ ++ return 0; ++} diff --git a/SOURCES/glibc-rh1672773.patch b/SOURCES/glibc-rh1672773.patch new file mode 100644 index 0000000..1e34531 --- /dev/null +++ b/SOURCES/glibc-rh1672773.patch @@ -0,0 +1,199 @@ +commit 823624bdc47f1f80109c9c52dee7939b9386d708 +Author: Stefan Liebler +Date: Thu Feb 7 15:18:36 2019 +0100 + + Add compiler barriers around modifications of the robust mutex list for pthread_mutex_trylock. [BZ #24180] + + While debugging a kernel warning, Thomas Gleixner, Sebastian Sewior and + Heiko Carstens found a bug in pthread_mutex_trylock due to misordered + instructions: + 140: a5 1b 00 01 oill %r1,1 + 144: e5 48 a0 f0 00 00 mvghi 240(%r10),0 <--- THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL); + 14a: e3 10 a0 e0 00 24 stg %r1,224(%r10) <--- last THREAD_SETMEM of ENQUEUE_MUTEX_PI + + vs (with compiler barriers): + 140: a5 1b 00 01 oill %r1,1 + 144: e3 10 a0 e0 00 24 stg %r1,224(%r10) + 14a: e5 48 a0 f0 00 00 mvghi 240(%r10),0 + + Please have a look at the discussion: + "Re: WARN_ON_ONCE(!new_owner) within wake_futex_pi() triggerede" + (https://lore.kernel.org/lkml/20190202112006.GB3381@osiris/) + + This patch is introducing the same compiler barriers and comments + for pthread_mutex_trylock as introduced for pthread_mutex_lock and + pthread_mutex_timedlock by commit 8f9450a0b7a9e78267e8ae1ab1000ebca08e473e + "Add compiler barriers around modifications of the robust mutex list." + + ChangeLog: + + [BZ #24180] + * nptl/pthread_mutex_trylock.c (__pthread_mutex_trylock): + +diff --git a/nptl/pthread_mutex_trylock.c b/nptl/pthread_mutex_trylock.c +index 8fe43b8f0f..bf2869eca2 100644 +--- a/nptl/pthread_mutex_trylock.c ++++ b/nptl/pthread_mutex_trylock.c +@@ -94,6 +94,9 @@ __pthread_mutex_trylock (pthread_mutex_t *mutex) + case PTHREAD_MUTEX_ROBUST_ADAPTIVE_NP: + THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, + &mutex->__data.__list.__next); ++ /* We need to set op_pending before starting the operation. Also ++ see comments at ENQUEUE_MUTEX. */ ++ __asm ("" ::: "memory"); + + oldval = mutex->__data.__lock; + do +@@ -119,7 +122,12 @@ __pthread_mutex_trylock (pthread_mutex_t *mutex) + /* But it is inconsistent unless marked otherwise. */ + mutex->__data.__owner = PTHREAD_MUTEX_INCONSISTENT; + ++ /* We must not enqueue the mutex before we have acquired it. ++ Also see comments at ENQUEUE_MUTEX. */ ++ __asm ("" ::: "memory"); + ENQUEUE_MUTEX (mutex); ++ /* We need to clear op_pending after we enqueue the mutex. */ ++ __asm ("" ::: "memory"); + THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL); + + /* Note that we deliberately exist here. If we fall +@@ -135,6 +143,8 @@ __pthread_mutex_trylock (pthread_mutex_t *mutex) + int kind = PTHREAD_MUTEX_TYPE (mutex); + if (kind == PTHREAD_MUTEX_ROBUST_ERRORCHECK_NP) + { ++ /* We do not need to ensure ordering wrt another memory ++ access. Also see comments at ENQUEUE_MUTEX. */ + THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, + NULL); + return EDEADLK; +@@ -142,6 +152,8 @@ __pthread_mutex_trylock (pthread_mutex_t *mutex) + + if (kind == PTHREAD_MUTEX_ROBUST_RECURSIVE_NP) + { ++ /* We do not need to ensure ordering wrt another memory ++ access. */ + THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, + NULL); + +@@ -160,6 +172,9 @@ __pthread_mutex_trylock (pthread_mutex_t *mutex) + id, 0); + if (oldval != 0 && (oldval & FUTEX_OWNER_DIED) == 0) + { ++ /* We haven't acquired the lock as it is already acquired by ++ another owner. We do not need to ensure ordering wrt another ++ memory access. */ + THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL); + + return EBUSY; +@@ -173,13 +188,20 @@ __pthread_mutex_trylock (pthread_mutex_t *mutex) + if (oldval == id) + lll_unlock (mutex->__data.__lock, + PTHREAD_ROBUST_MUTEX_PSHARED (mutex)); ++ /* FIXME This violates the mutex destruction requirements. See ++ __pthread_mutex_unlock_full. */ + THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL); + return ENOTRECOVERABLE; + } + } + while ((oldval & FUTEX_OWNER_DIED) != 0); + ++ /* We must not enqueue the mutex before we have acquired it. ++ Also see comments at ENQUEUE_MUTEX. */ ++ __asm ("" ::: "memory"); + ENQUEUE_MUTEX (mutex); ++ /* We need to clear op_pending after we enqueue the mutex. */ ++ __asm ("" ::: "memory"); + THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL); + + mutex->__data.__owner = id; +@@ -211,10 +233,15 @@ __pthread_mutex_trylock (pthread_mutex_t *mutex) + } + + if (robust) +- /* Note: robust PI futexes are signaled by setting bit 0. */ +- THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, +- (void *) (((uintptr_t) &mutex->__data.__list.__next) +- | 1)); ++ { ++ /* Note: robust PI futexes are signaled by setting bit 0. */ ++ THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, ++ (void *) (((uintptr_t) &mutex->__data.__list.__next) ++ | 1)); ++ /* We need to set op_pending before starting the operation. Also ++ see comments at ENQUEUE_MUTEX. */ ++ __asm ("" ::: "memory"); ++ } + + oldval = mutex->__data.__lock; + +@@ -223,12 +250,16 @@ __pthread_mutex_trylock (pthread_mutex_t *mutex) + { + if (kind == PTHREAD_MUTEX_ERRORCHECK_NP) + { ++ /* We do not need to ensure ordering wrt another memory ++ access. */ + THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL); + return EDEADLK; + } + + if (kind == PTHREAD_MUTEX_RECURSIVE_NP) + { ++ /* We do not need to ensure ordering wrt another memory ++ access. */ + THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL); + + /* Just bump the counter. */ +@@ -250,6 +281,9 @@ __pthread_mutex_trylock (pthread_mutex_t *mutex) + { + if ((oldval & FUTEX_OWNER_DIED) == 0) + { ++ /* We haven't acquired the lock as it is already acquired by ++ another owner. We do not need to ensure ordering wrt another ++ memory access. */ + THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL); + + return EBUSY; +@@ -270,6 +304,9 @@ __pthread_mutex_trylock (pthread_mutex_t *mutex) + if (INTERNAL_SYSCALL_ERROR_P (e, __err) + && INTERNAL_SYSCALL_ERRNO (e, __err) == EWOULDBLOCK) + { ++ /* The kernel has not yet finished the mutex owner death. ++ We do not need to ensure ordering wrt another memory ++ access. */ + THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL); + + return EBUSY; +@@ -287,7 +324,12 @@ __pthread_mutex_trylock (pthread_mutex_t *mutex) + /* But it is inconsistent unless marked otherwise. */ + mutex->__data.__owner = PTHREAD_MUTEX_INCONSISTENT; + ++ /* We must not enqueue the mutex before we have acquired it. ++ Also see comments at ENQUEUE_MUTEX. */ ++ __asm ("" ::: "memory"); + ENQUEUE_MUTEX (mutex); ++ /* We need to clear op_pending after we enqueue the mutex. */ ++ __asm ("" ::: "memory"); + THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL); + + /* Note that we deliberately exit here. If we fall +@@ -310,13 +352,20 @@ __pthread_mutex_trylock (pthread_mutex_t *mutex) + PTHREAD_ROBUST_MUTEX_PSHARED (mutex)), + 0, 0); + ++ /* To the kernel, this will be visible after the kernel has ++ acquired the mutex in the syscall. */ + THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL); + return ENOTRECOVERABLE; + } + + if (robust) + { ++ /* We must not enqueue the mutex before we have acquired it. ++ Also see comments at ENQUEUE_MUTEX. */ ++ __asm ("" ::: "memory"); + ENQUEUE_MUTEX_PI (mutex); ++ /* We need to clear op_pending after we enqueue the mutex. */ ++ __asm ("" ::: "memory"); + THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL); + } + diff --git a/SOURCES/glibc-rh1682954.patch b/SOURCES/glibc-rh1682954.patch new file mode 100644 index 0000000..4892f52 --- /dev/null +++ b/SOURCES/glibc-rh1682954.patch @@ -0,0 +1,545 @@ +From 0d3905b110000463775b3fb189213833acaebf81 Mon Sep 17 00:00:00 2001 +From: "H.J. Lu" +Date: Mon, 1 Jul 2019 12:23:10 -0700 +Subject: Call _dl_open_check after relocation [BZ #24259] + +This is a workaround for [BZ #20839] which doesn't remove the NODELETE +object when _dl_open_check throws an exception. Move it after relocation +in dl_open_worker to avoid leaving the NODELETE object mapped without +relocation. + + [BZ #24259] + * elf/dl-open.c (dl_open_worker): Call _dl_open_check after + relocation. + * sysdeps/x86/Makefile (tests): Add tst-cet-legacy-5a, + tst-cet-legacy-5b, tst-cet-legacy-6a and tst-cet-legacy-6b. + (modules-names): Add tst-cet-legacy-mod-5a, tst-cet-legacy-mod-5b, + tst-cet-legacy-mod-5c, tst-cet-legacy-mod-6a, tst-cet-legacy-mod-6b + and tst-cet-legacy-mod-6c. + (CFLAGS-tst-cet-legacy-5a.c): New. + (CFLAGS-tst-cet-legacy-5b.c): Likewise. + (CFLAGS-tst-cet-legacy-mod-5a.c): Likewise. + (CFLAGS-tst-cet-legacy-mod-5b.c): Likewise. + (CFLAGS-tst-cet-legacy-mod-5c.c): Likewise. + (CFLAGS-tst-cet-legacy-6a.c): Likewise. + (CFLAGS-tst-cet-legacy-6b.c): Likewise. + (CFLAGS-tst-cet-legacy-mod-6a.c): Likewise. + (CFLAGS-tst-cet-legacy-mod-6b.c): Likewise. + (CFLAGS-tst-cet-legacy-mod-6c.c): Likewise. + ($(objpfx)tst-cet-legacy-5a): Likewise. + ($(objpfx)tst-cet-legacy-5a.out): Likewise. + ($(objpfx)tst-cet-legacy-mod-5a.so): Likewise. + ($(objpfx)tst-cet-legacy-mod-5b.so): Likewise. + ($(objpfx)tst-cet-legacy-5b): Likewise. + ($(objpfx)tst-cet-legacy-5b.out): Likewise. + (tst-cet-legacy-5b-ENV): Likewise. + ($(objpfx)tst-cet-legacy-6a): Likewise. + ($(objpfx)tst-cet-legacy-6a.out): Likewise. + ($(objpfx)tst-cet-legacy-mod-6a.so): Likewise. + ($(objpfx)tst-cet-legacy-mod-6b.so): Likewise. + ($(objpfx)tst-cet-legacy-6b): Likewise. + ($(objpfx)tst-cet-legacy-6b.out): Likewise. + (tst-cet-legacy-6b-ENV): Likewise. + * sysdeps/x86/tst-cet-legacy-5.c: New file. + * sysdeps/x86/tst-cet-legacy-5a.c: Likewise. + * sysdeps/x86/tst-cet-legacy-5b.c: Likewise. + * sysdeps/x86/tst-cet-legacy-6.c: Likewise. + * sysdeps/x86/tst-cet-legacy-6a.c: Likewise. + * sysdeps/x86/tst-cet-legacy-6b.c: Likewise. + * sysdeps/x86/tst-cet-legacy-mod-5.c: Likewise. + * sysdeps/x86/tst-cet-legacy-mod-5a.c: Likewise. + * sysdeps/x86/tst-cet-legacy-mod-5b.c: Likewise. + * sysdeps/x86/tst-cet-legacy-mod-5c.c: Likewise. + * sysdeps/x86/tst-cet-legacy-mod-6.c: Likewise. + * sysdeps/x86/tst-cet-legacy-mod-6a.c: Likewise. + * sysdeps/x86/tst-cet-legacy-mod-6b.c: Likewise. + * sysdeps/x86/tst-cet-legacy-mod-6c.c: Likewise. + +(cherry picked from commit d0093c5cefb7f7a4143f3bb03743633823229cc6) + +diff --git a/elf/dl-open.c b/elf/dl-open.c +index f6c8ef1043..518a6cad69 100644 +--- a/elf/dl-open.c ++++ b/elf/dl-open.c +@@ -292,8 +292,6 @@ dl_open_worker (void *a) + _dl_debug_state (); + LIBC_PROBE (map_complete, 3, args->nsid, r, new); + +- _dl_open_check (new); +- + /* Print scope information. */ + if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_SCOPES)) + _dl_show_scope (new, 0); +@@ -366,6 +364,12 @@ dl_open_worker (void *a) + _dl_relocate_object (l, l->l_scope, reloc_mode, 0); + } + ++ /* NB: Workaround for [BZ #20839] which doesn't remove the NODELETE ++ object when _dl_open_check throws an exception. Move it after ++ relocation to avoid leaving the NODELETE object mapped without ++ relocation. */ ++ _dl_open_check (new); ++ + /* If the file is not loaded now as a dependency, add the search + list of the newly loaded object to the scope. */ + bool any_tls = false; +diff --git a/sysdeps/x86/Makefile b/sysdeps/x86/Makefile +index 337b0b63dc..43ad4a79ff 100644 +--- a/sysdeps/x86/Makefile ++++ b/sysdeps/x86/Makefile +@@ -19,12 +19,17 @@ ifeq ($(subdir),elf) + sysdep-dl-routines += dl-cet + + tests += tst-cet-legacy-1 tst-cet-legacy-2 tst-cet-legacy-2a \ +- tst-cet-legacy-3 tst-cet-legacy-4 ++ tst-cet-legacy-3 tst-cet-legacy-4 \ ++ tst-cet-legacy-5a tst-cet-legacy-6a + ifneq (no,$(have-tunables)) +-tests += tst-cet-legacy-4a tst-cet-legacy-4b tst-cet-legacy-4c ++tests += tst-cet-legacy-4a tst-cet-legacy-4b tst-cet-legacy-4c \ ++ tst-cet-legacy-5b tst-cet-legacy-6b + endif + modules-names += tst-cet-legacy-mod-1 tst-cet-legacy-mod-2 \ +- tst-cet-legacy-mod-4 ++ tst-cet-legacy-mod-4 tst-cet-legacy-mod-5a \ ++ tst-cet-legacy-mod-5b tst-cet-legacy-mod-5c \ ++ tst-cet-legacy-mod-6a tst-cet-legacy-mod-6b \ ++ tst-cet-legacy-mod-6c + + CFLAGS-tst-cet-legacy-2.c += -fcf-protection=branch + CFLAGS-tst-cet-legacy-2a.c += -fcf-protection +@@ -35,6 +40,16 @@ CFLAGS-tst-cet-legacy-4.c += -fcf-protection=branch + CFLAGS-tst-cet-legacy-4a.c += -fcf-protection + CFLAGS-tst-cet-legacy-4b.c += -fcf-protection + CFLAGS-tst-cet-legacy-mod-4.c += -fcf-protection=none ++CFLAGS-tst-cet-legacy-5a.c += -fcf-protection ++CFLAGS-tst-cet-legacy-5b.c += -fcf-protection ++CFLAGS-tst-cet-legacy-mod-5a.c += -fcf-protection=none ++CFLAGS-tst-cet-legacy-mod-5b.c += -fcf-protection ++CFLAGS-tst-cet-legacy-mod-5c.c += -fcf-protection ++CFLAGS-tst-cet-legacy-6a.c += -fcf-protection ++CFLAGS-tst-cet-legacy-6b.c += -fcf-protection ++CFLAGS-tst-cet-legacy-mod-6a.c += -fcf-protection=none ++CFLAGS-tst-cet-legacy-mod-6b.c += -fcf-protection ++CFLAGS-tst-cet-legacy-mod-6c.c += -fcf-protection + + $(objpfx)tst-cet-legacy-1: $(objpfx)tst-cet-legacy-mod-1.so \ + $(objpfx)tst-cet-legacy-mod-2.so +@@ -44,6 +59,17 @@ $(objpfx)tst-cet-legacy-2a: $(objpfx)tst-cet-legacy-mod-2.so $(libdl) + $(objpfx)tst-cet-legacy-2a.out: $(objpfx)tst-cet-legacy-mod-1.so + $(objpfx)tst-cet-legacy-4: $(libdl) + $(objpfx)tst-cet-legacy-4.out: $(objpfx)tst-cet-legacy-mod-4.so ++$(objpfx)tst-cet-legacy-5a: $(libdl) ++$(objpfx)tst-cet-legacy-5a.out: $(objpfx)tst-cet-legacy-mod-5a.so \ ++ $(objpfx)tst-cet-legacy-mod-5b.so ++$(objpfx)tst-cet-legacy-mod-5a.so: $(objpfx)tst-cet-legacy-mod-5c.so ++$(objpfx)tst-cet-legacy-mod-5b.so: $(objpfx)tst-cet-legacy-mod-5c.so ++$(objpfx)tst-cet-legacy-6a: $(libdl) ++$(objpfx)tst-cet-legacy-6a.out: $(objpfx)tst-cet-legacy-mod-6a.so \ ++ $(objpfx)tst-cet-legacy-mod-6b.so ++$(objpfx)tst-cet-legacy-mod-6a.so: $(objpfx)tst-cet-legacy-mod-6c.so ++$(objpfx)tst-cet-legacy-mod-6b.so: $(objpfx)tst-cet-legacy-mod-6c.so ++LDFLAGS-tst-cet-legacy-mod-6c.so = -Wl,--enable-new-dtags,-z,nodelete + ifneq (no,$(have-tunables)) + $(objpfx)tst-cet-legacy-4a: $(libdl) + $(objpfx)tst-cet-legacy-4a.out: $(objpfx)tst-cet-legacy-mod-4.so +@@ -54,6 +80,14 @@ tst-cet-legacy-4b-ENV = GLIBC_TUNABLES=glibc.tune.x86_shstk=on + $(objpfx)tst-cet-legacy-4c: $(libdl) + $(objpfx)tst-cet-legacy-4c.out: $(objpfx)tst-cet-legacy-mod-4.so + tst-cet-legacy-4c-ENV = GLIBC_TUNABLES=glibc.tune.x86_shstk=off ++$(objpfx)tst-cet-legacy-5b: $(libdl) ++$(objpfx)tst-cet-legacy-5b.out: $(objpfx)tst-cet-legacy-mod-5a.so \ ++ $(objpfx)tst-cet-legacy-mod-5b.so ++tst-cet-legacy-5b-ENV = GLIBC_TUNABLES=glibc.tune.x86_ibt=off:glibc.tune.x86_shstk=off ++$(objpfx)tst-cet-legacy-6b: $(libdl) ++$(objpfx)tst-cet-legacy-6b.out: $(objpfx)tst-cet-legacy-mod-6a.so \ ++ $(objpfx)tst-cet-legacy-mod-6b.so ++tst-cet-legacy-6b-ENV = GLIBC_TUNABLES=glibc.tune.x86_ibt=off:glibc.tune.x86_shstk=off + endif + endif + +diff --git a/sysdeps/x86/tst-cet-legacy-5.c b/sysdeps/x86/tst-cet-legacy-5.c +new file mode 100644 +index 0000000000..fbf640f664 +--- /dev/null ++++ b/sysdeps/x86/tst-cet-legacy-5.c +@@ -0,0 +1,76 @@ ++/* Check compatibility of CET-enabled executable with dlopened legacy ++ shared object. ++ 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, see ++ . */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++static void ++do_test_1 (const char *modname, bool fail) ++{ ++ int (*fp) (void); ++ void *h; ++ ++ h = dlopen (modname, RTLD_LAZY); ++ if (h == NULL) ++ { ++ if (fail) ++ { ++ const char *err = dlerror (); ++ if (strstr (err, "shadow stack isn't enabled") == NULL) ++ { ++ printf ("incorrect dlopen '%s' error: %s\n", modname, ++ dlerror ()); ++ exit (1); ++ } ++ ++ return; ++ } ++ ++ printf ("cannot open '%s': %s\n", modname, dlerror ()); ++ exit (1); ++ } ++ ++ fp = dlsym (h, "test"); ++ if (fp == NULL) ++ { ++ printf ("cannot get symbol 'test': %s\n", dlerror ()); ++ exit (1); ++ } ++ ++ if (fp () != 0) ++ { ++ puts ("test () != 0"); ++ exit (1); ++ } ++ ++ dlclose (h); ++} ++ ++static int ++do_test (void) ++{ ++ do_test_1 ("tst-cet-legacy-mod-5a.so", true); ++ do_test_1 ("tst-cet-legacy-mod-5b.so", false); ++ return 0; ++} ++ ++#include +diff --git a/sysdeps/x86/tst-cet-legacy-5a.c b/sysdeps/x86/tst-cet-legacy-5a.c +new file mode 100644 +index 0000000000..fc5a609dff +--- /dev/null ++++ b/sysdeps/x86/tst-cet-legacy-5a.c +@@ -0,0 +1 @@ ++#include "tst-cet-legacy-5.c" +diff --git a/sysdeps/x86/tst-cet-legacy-5b.c b/sysdeps/x86/tst-cet-legacy-5b.c +new file mode 100644 +index 0000000000..fc5a609dff +--- /dev/null ++++ b/sysdeps/x86/tst-cet-legacy-5b.c +@@ -0,0 +1 @@ ++#include "tst-cet-legacy-5.c" +diff --git a/sysdeps/x86/tst-cet-legacy-6.c b/sysdeps/x86/tst-cet-legacy-6.c +new file mode 100644 +index 0000000000..9151225264 +--- /dev/null ++++ b/sysdeps/x86/tst-cet-legacy-6.c +@@ -0,0 +1,76 @@ ++/* Check compatibility of CET-enabled executable with dlopened legacy ++ shared object. ++ 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, see ++ . */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++static void ++do_test_1 (const char *modname, bool fail) ++{ ++ int (*fp) (void); ++ void *h; ++ ++ h = dlopen (modname, RTLD_LAZY); ++ if (h == NULL) ++ { ++ if (fail) ++ { ++ const char *err = dlerror (); ++ if (strstr (err, "shadow stack isn't enabled") == NULL) ++ { ++ printf ("incorrect dlopen '%s' error: %s\n", modname, ++ dlerror ()); ++ exit (1); ++ } ++ ++ return; ++ } ++ ++ printf ("cannot open '%s': %s\n", modname, dlerror ()); ++ exit (1); ++ } ++ ++ fp = dlsym (h, "test"); ++ if (fp == NULL) ++ { ++ printf ("cannot get symbol 'test': %s\n", dlerror ()); ++ exit (1); ++ } ++ ++ if (fp () != 0) ++ { ++ puts ("test () != 0"); ++ exit (1); ++ } ++ ++ dlclose (h); ++} ++ ++static int ++do_test (void) ++{ ++ do_test_1 ("tst-cet-legacy-mod-6a.so", true); ++ do_test_1 ("tst-cet-legacy-mod-6b.so", false); ++ return 0; ++} ++ ++#include +diff --git a/sysdeps/x86/tst-cet-legacy-6a.c b/sysdeps/x86/tst-cet-legacy-6a.c +new file mode 100644 +index 0000000000..2d1546d36b +--- /dev/null ++++ b/sysdeps/x86/tst-cet-legacy-6a.c +@@ -0,0 +1 @@ ++#include "tst-cet-legacy-6.c" +diff --git a/sysdeps/x86/tst-cet-legacy-6b.c b/sysdeps/x86/tst-cet-legacy-6b.c +new file mode 100644 +index 0000000000..2d1546d36b +--- /dev/null ++++ b/sysdeps/x86/tst-cet-legacy-6b.c +@@ -0,0 +1 @@ ++#include "tst-cet-legacy-6.c" +diff --git a/sysdeps/x86/tst-cet-legacy-mod-5.c b/sysdeps/x86/tst-cet-legacy-mod-5.c +new file mode 100644 +index 0000000000..3c1071c2ef +--- /dev/null ++++ b/sysdeps/x86/tst-cet-legacy-mod-5.c +@@ -0,0 +1,31 @@ ++/* Check compatibility of CET-enabled executable with dlopened legacy ++ shared object. ++ 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, see ++ . */ ++ ++#include ++#include ++#include ++ ++extern void foo (void); ++ ++int ++test (void) ++{ ++ foo (); ++ return 0; ++} +diff --git a/sysdeps/x86/tst-cet-legacy-mod-5a.c b/sysdeps/x86/tst-cet-legacy-mod-5a.c +new file mode 100644 +index 0000000000..daa43e4e8d +--- /dev/null ++++ b/sysdeps/x86/tst-cet-legacy-mod-5a.c +@@ -0,0 +1 @@ ++#include "tst-cet-legacy-mod-5.c" +diff --git a/sysdeps/x86/tst-cet-legacy-mod-5b.c b/sysdeps/x86/tst-cet-legacy-mod-5b.c +new file mode 100644 +index 0000000000..daa43e4e8d +--- /dev/null ++++ b/sysdeps/x86/tst-cet-legacy-mod-5b.c +@@ -0,0 +1 @@ ++#include "tst-cet-legacy-mod-5.c" +diff --git a/sysdeps/x86/tst-cet-legacy-mod-5c.c b/sysdeps/x86/tst-cet-legacy-mod-5c.c +new file mode 100644 +index 0000000000..e529a42ac0 +--- /dev/null ++++ b/sysdeps/x86/tst-cet-legacy-mod-5c.c +@@ -0,0 +1,36 @@ ++/* Check compatibility of CET-enabled executable with dlopened legacy ++ shared object. ++ 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, see ++ . */ ++ ++#include ++ ++static int called = 0; ++ ++static void ++__attribute__ ((constructor)) ++init (void) ++{ ++ called = 1; ++} ++ ++void ++foo (void) ++{ ++ if (!called) ++ abort (); ++} +diff --git a/sysdeps/x86/tst-cet-legacy-mod-6.c b/sysdeps/x86/tst-cet-legacy-mod-6.c +new file mode 100644 +index 0000000000..3c1071c2ef +--- /dev/null ++++ b/sysdeps/x86/tst-cet-legacy-mod-6.c +@@ -0,0 +1,31 @@ ++/* Check compatibility of CET-enabled executable with dlopened legacy ++ shared object. ++ 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, see ++ . */ ++ ++#include ++#include ++#include ++ ++extern void foo (void); ++ ++int ++test (void) ++{ ++ foo (); ++ return 0; ++} +diff --git a/sysdeps/x86/tst-cet-legacy-mod-6a.c b/sysdeps/x86/tst-cet-legacy-mod-6a.c +new file mode 100644 +index 0000000000..c89b8fe8ff +--- /dev/null ++++ b/sysdeps/x86/tst-cet-legacy-mod-6a.c +@@ -0,0 +1 @@ ++#include "tst-cet-legacy-mod-6.c" +diff --git a/sysdeps/x86/tst-cet-legacy-mod-6b.c b/sysdeps/x86/tst-cet-legacy-mod-6b.c +new file mode 100644 +index 0000000000..c89b8fe8ff +--- /dev/null ++++ b/sysdeps/x86/tst-cet-legacy-mod-6b.c +@@ -0,0 +1 @@ ++#include "tst-cet-legacy-mod-6.c" +diff --git a/sysdeps/x86/tst-cet-legacy-mod-6c.c b/sysdeps/x86/tst-cet-legacy-mod-6c.c +new file mode 100644 +index 0000000000..e529a42ac0 +--- /dev/null ++++ b/sysdeps/x86/tst-cet-legacy-mod-6c.c +@@ -0,0 +1,36 @@ ++/* Check compatibility of CET-enabled executable with dlopened legacy ++ shared object. ++ 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, see ++ . */ ++ ++#include ++ ++static int called = 0; ++ ++static void ++__attribute__ ((constructor)) ++init (void) ++{ ++ called = 1; ++} ++ ++void ++foo (void) ++{ ++ if (!called) ++ abort (); ++} +diff --git a/sysdeps/x86/tst-cet-legacy-mod-6d.c b/sysdeps/x86/tst-cet-legacy-mod-6d.c +new file mode 100644 +index 0000000000..eb233a1d10 +--- /dev/null ++++ b/sysdeps/x86/tst-cet-legacy-mod-6d.c +@@ -0,0 +1 @@ ++#include "tst-cet-legacy-mod-6c.c" diff --git a/SOURCES/glibc-rh1691528-1.patch b/SOURCES/glibc-rh1691528-1.patch new file mode 100644 index 0000000..9f07b78 --- /dev/null +++ b/SOURCES/glibc-rh1691528-1.patch @@ -0,0 +1,48 @@ +commit ac64195ccd4f320659fd0058bc7524c6fd0b37b4 +Author: DJ Delorie +Date: Wed Mar 20 23:56:59 2019 -0400 + + iconv, localedef: avoid floating point rounding differences [BZ #24372] + + Two cases of "int * 1.4" may result in imprecise results, which + in at least one case resulted in i686 and x86-64 producing + different locale files. This replaced that floating point multiply + with integer operations. While the hash table margin is increased + from 40% to 50%, testing shows only 2% increase in overall size + of the locale archive. + + https://bugzilla.redhat.com/show_bug.cgi?id=1311954 + + Reviewed-by: Carlos O'Donell + +diff --git a/iconv/iconvconfig.c b/iconv/iconvconfig.c +index d5e8e714233f78d8..696fc8d31231ca2d 100644 +--- a/iconv/iconvconfig.c ++++ b/iconv/iconvconfig.c +@@ -1079,9 +1079,9 @@ write_output (void) + + /* Create the hashing table. We know how many strings we have. + Creating a perfect hash table is not reasonable here. Therefore +- we use open hashing and a table size which is the next prime 40% ++ we use open hashing and a table size which is the next prime 50% + larger than the number of strings. */ +- hash_size = next_prime (nnames * 1.4); ++ hash_size = next_prime (nnames + nnames >> 1); + hash_table = (struct hash_entry *) xcalloc (hash_size, + sizeof (struct hash_entry)); + /* Fill the hash table. */ +diff --git a/locale/programs/ld-collate.c b/locale/programs/ld-collate.c +index d2eebcfdbb0677e5..9a1639b999d0e2aa 100644 +--- a/locale/programs/ld-collate.c ++++ b/locale/programs/ld-collate.c +@@ -2401,8 +2401,8 @@ collate_output (struct localedef_t *locale, const struct charmap_t *charmap, + + runp = runp->next; + } +- /* Add 40% and find the next prime number. */ +- elem_size = next_prime (elem_size * 1.4); ++ /* Add 50% and find the next prime number. */ ++ elem_size = next_prime (elem_size + elem_size >> 1); + + /* Allocate the table. Each entry consists of two words: the hash + value and an index in a secondary table which provides the index diff --git a/SOURCES/glibc-rh1691528-2.patch b/SOURCES/glibc-rh1691528-2.patch new file mode 100644 index 0000000..568320e --- /dev/null +++ b/SOURCES/glibc-rh1691528-2.patch @@ -0,0 +1,49 @@ +commit 5abcddd7949270998c6e8d99fdbbba821b664f8b +Author: Gabriel F. T. Gomes +Date: Thu Mar 21 17:24:30 2019 -0300 + + Fix parentheses error in iconvconfig.c and ld-collate.c [BZ #24372] + + When -Werror=parentheses is in use, iconvconfig.c builds fail with: + + iconvconfig.c: In function ‘write_output’: + iconvconfig.c:1084:34: error: suggest parentheses around ‘+’ inside ‘>>’ [-Werror=parentheses] + hash_size = next_prime (nnames + nnames >> 1); + ~~~~~~~^~~~~~~~ + + This patch adds parentheses to the expression. Not where suggested by + the compiler warning, but where it produces the expected result, i.e.: + where it has the effect of multiplying nnames by 1.5. + + Likewise for elem_size in ld-collate.c. + + Tested for powerpc64le. + + Reviewed-by: Carlos O'Donell + +diff --git a/iconv/iconvconfig.c b/iconv/iconvconfig.c +index 696fc8d31231ca2d..b6fef1553cbbdd3d 100644 +--- a/iconv/iconvconfig.c ++++ b/iconv/iconvconfig.c +@@ -1081,7 +1081,7 @@ write_output (void) + Creating a perfect hash table is not reasonable here. Therefore + we use open hashing and a table size which is the next prime 50% + larger than the number of strings. */ +- hash_size = next_prime (nnames + nnames >> 1); ++ hash_size = next_prime (nnames + (nnames >> 1)); + hash_table = (struct hash_entry *) xcalloc (hash_size, + sizeof (struct hash_entry)); + /* Fill the hash table. */ +diff --git a/locale/programs/ld-collate.c b/locale/programs/ld-collate.c +index 9a1639b999d0e2aa..a5530655fd5638b5 100644 +--- a/locale/programs/ld-collate.c ++++ b/locale/programs/ld-collate.c +@@ -2402,7 +2402,7 @@ collate_output (struct localedef_t *locale, const struct charmap_t *charmap, + runp = runp->next; + } + /* Add 50% and find the next prime number. */ +- elem_size = next_prime (elem_size + elem_size >> 1); ++ elem_size = next_prime (elem_size + (elem_size >> 1)); + + /* Allocate the table. Each entry consists of two words: the hash + value and an index in a secondary table which provides the index diff --git a/SOURCES/glibc-rh1699194-1.patch b/SOURCES/glibc-rh1699194-1.patch new file mode 100644 index 0000000..3db05de --- /dev/null +++ b/SOURCES/glibc-rh1699194-1.patch @@ -0,0 +1,23 @@ +commit 4e75c2a43bb3208f32556a2b19c939cfe1f54ba6 +Author: Florian Weimer +Date: Wed Jun 12 10:41:19 2019 +0200 + + : Add __glibc_has_include macro + +diff --git a/misc/sys/cdefs.h b/misc/sys/cdefs.h +index 3f6fe3cc8563b493..0500779d0c1b64c2 100644 +--- a/misc/sys/cdefs.h ++++ b/misc/sys/cdefs.h +@@ -412,6 +412,12 @@ + # define __glibc_has_attribute(attr) 0 + #endif + ++#ifdef __has_include ++# define __glibc_has_include(header) __has_include (header) ++#else ++# define __glibc_has_include(header) 0 ++#endif ++ + #if (!defined _Noreturn \ + && (defined __STDC_VERSION__ ? __STDC_VERSION__ : 0) < 201112 \ + && !__GNUC_PREREQ (4,7)) diff --git a/SOURCES/glibc-rh1699194-2.patch b/SOURCES/glibc-rh1699194-2.patch new file mode 100644 index 0000000..e292641 --- /dev/null +++ b/SOURCES/glibc-rh1699194-2.patch @@ -0,0 +1,383 @@ +commit 5dad6ffbb2b76215cfcd38c3001778536ada8e8a +Author: Florian Weimer +Date: Wed Jun 12 12:04:09 2019 +0200 + + : Use Linux UAPI header for statx if available and useful + + This will automatically import new STATX_* constants. It also avoids + a conflict between and . + +Conflicts: + io/bits/statx.h + (Year range in copyright header.) + +diff --git a/include/bits/statx-generic.h b/include/bits/statx-generic.h +new file mode 100644 +index 0000000000000000..21674721b6d85265 +--- /dev/null ++++ b/include/bits/statx-generic.h +@@ -0,0 +1 @@ ++#include +diff --git a/include/bits/types/struct_statx.h b/include/bits/types/struct_statx.h +new file mode 100644 +index 0000000000000000..82add6484f2ee963 +--- /dev/null ++++ b/include/bits/types/struct_statx.h +@@ -0,0 +1 @@ ++#include +diff --git a/include/bits/types/struct_statx_timestamp.h b/include/bits/types/struct_statx_timestamp.h +new file mode 100644 +index 0000000000000000..9fbedd5749fc1172 +--- /dev/null ++++ b/include/bits/types/struct_statx_timestamp.h +@@ -0,0 +1 @@ ++#include +diff --git a/io/Makefile b/io/Makefile +index ec5c6d7a2fb87914..787a5c550ab64b17 100644 +--- a/io/Makefile ++++ b/io/Makefile +@@ -25,7 +25,9 @@ include ../Makeconfig + headers := sys/stat.h bits/stat.h sys/statfs.h bits/statfs.h sys/vfs.h \ + sys/statvfs.h bits/statvfs.h fcntl.h sys/fcntl.h bits/fcntl.h \ + poll.h sys/poll.h bits/poll.h bits/fcntl2.h bits/poll2.h \ +- bits/statx.h utime.h ftw.h fts.h sys/sendfile.h ++ bits/statx.h bits/statx-generic.h bits/types/struct_statx.h \ ++ bits/types/struct_statx_timestamp.h \ ++ utime.h ftw.h fts.h sys/sendfile.h + + routines := \ + utime \ +diff --git a/io/bits/statx-generic.h b/io/bits/statx-generic.h +new file mode 100644 +index 0000000000000000..1f5abbf148681e9b +--- /dev/null ++++ b/io/bits/statx-generic.h +@@ -0,0 +1,60 @@ ++/* Generic statx-related definitions and declarations. ++ Copyright (C) 2018-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, see ++ . */ ++ ++/* This interface is based on in Linux. */ ++ ++#ifndef _SYS_STAT_H ++# error Never include directly, include instead. ++#endif ++ ++#include ++#include ++ ++#ifndef STATX_TYPE ++# define STATX_TYPE 0x0001U ++# define STATX_MODE 0x0002U ++# define STATX_NLINK 0x0004U ++# define STATX_UID 0x0008U ++# define STATX_GID 0x0010U ++# define STATX_ATIME 0x0020U ++# define STATX_MTIME 0x0040U ++# define STATX_CTIME 0x0080U ++# define STATX_INO 0x0100U ++# define STATX_SIZE 0x0200U ++# define STATX_BLOCKS 0x0400U ++# define STATX_BASIC_STATS 0x07ffU ++# define STATX_ALL 0x0fffU ++# define STATX_BTIME 0x0800U ++# define STATX__RESERVED 0x80000000U ++ ++# define STATX_ATTR_COMPRESSED 0x0004 ++# define STATX_ATTR_IMMUTABLE 0x0010 ++# define STATX_ATTR_APPEND 0x0020 ++# define STATX_ATTR_NODUMP 0x0040 ++# define STATX_ATTR_ENCRYPTED 0x0800 ++# define STATX_ATTR_AUTOMOUNT 0x1000 ++#endif /* !STATX_TYPE */ ++ ++__BEGIN_DECLS ++ ++/* Fill *BUF with information about PATH in DIRFD. */ ++int statx (int __dirfd, const char *__restrict __path, int __flags, ++ unsigned int __mask, struct statx *__restrict __buf) ++ __THROW __nonnull ((2, 5)); ++ ++__END_DECLS +diff --git a/io/bits/statx.h b/io/bits/statx.h +index e31254e3617bb17b..b3147bfa8af1818f 100644 +--- a/io/bits/statx.h ++++ b/io/bits/statx.h +@@ -1,5 +1,5 @@ +-/* statx-related definitions and declarations. +- Copyright (C) 2018 Free Software Foundation, Inc. ++/* statx-related definitions and declarations. Generic version. ++ Copyright (C) 2018-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 +@@ -19,73 +19,8 @@ + /* This interface is based on in Linux. */ + + #ifndef _SYS_STAT_H +-# error Never include directly, include instead. ++# error Never include directly, include instead. + #endif + +-struct statx_timestamp +-{ +- __int64_t tv_sec; +- __uint32_t tv_nsec; +- __int32_t __statx_timestamp_pad1[1]; +-}; +- +-/* Warning: The kernel may add additional fields to this struct in the +- future. Only use this struct for calling the statx function, not +- for storing data. (Expansion will be controlled by the mask +- argument of the statx function.) */ +-struct statx +-{ +- __uint32_t stx_mask; +- __uint32_t stx_blksize; +- __uint64_t stx_attributes; +- __uint32_t stx_nlink; +- __uint32_t stx_uid; +- __uint32_t stx_gid; +- __uint16_t stx_mode; +- __uint16_t __statx_pad1[1]; +- __uint64_t stx_ino; +- __uint64_t stx_size; +- __uint64_t stx_blocks; +- __uint64_t stx_attributes_mask; +- struct statx_timestamp stx_atime; +- struct statx_timestamp stx_btime; +- struct statx_timestamp stx_ctime; +- struct statx_timestamp stx_mtime; +- __uint32_t stx_rdev_major; +- __uint32_t stx_rdev_minor; +- __uint32_t stx_dev_major; +- __uint32_t stx_dev_minor; +- __uint64_t __statx_pad2[14]; +-}; +- +-#define STATX_TYPE 0x0001U +-#define STATX_MODE 0x0002U +-#define STATX_NLINK 0x0004U +-#define STATX_UID 0x0008U +-#define STATX_GID 0x0010U +-#define STATX_ATIME 0x0020U +-#define STATX_MTIME 0x0040U +-#define STATX_CTIME 0x0080U +-#define STATX_INO 0x0100U +-#define STATX_SIZE 0x0200U +-#define STATX_BLOCKS 0x0400U +-#define STATX_BASIC_STATS 0x07ffU +-#define STATX_ALL 0x0fffU +-#define STATX_BTIME 0x0800U +-#define STATX__RESERVED 0x80000000U +- +-#define STATX_ATTR_COMPRESSED 0x0004 +-#define STATX_ATTR_IMMUTABLE 0x0010 +-#define STATX_ATTR_APPEND 0x0020 +-#define STATX_ATTR_NODUMP 0x0040 +-#define STATX_ATTR_ENCRYPTED 0x0800 +-#define STATX_ATTR_AUTOMOUNT 0x1000 +- +-__BEGIN_DECLS +- +-/* Fill *BUF with information about PATH in DIRFD. */ +-int statx (int __dirfd, const char *__restrict __path, int __flags, +- unsigned int __mask, struct statx *__restrict __buf) +- __THROW __nonnull ((2, 5)); +- +-__END_DECLS ++/* Use the generic definitions. */ ++#include +diff --git a/io/bits/types/struct_statx.h b/io/bits/types/struct_statx.h +new file mode 100644 +index 0000000000000000..4f3ae3ece62a0ad2 +--- /dev/null ++++ b/io/bits/types/struct_statx.h +@@ -0,0 +1,55 @@ ++/* Definition of the generic version of struct statx. ++ Copyright (C) 2018-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, see ++ . */ ++ ++#ifndef _SYS_STAT_H ++# error Never include directly, include instead. ++#endif ++ ++#ifndef __statx_defined ++#define __statx_defined 1 ++ ++/* Warning: The kernel may add additional fields to this struct in the ++ future. Only use this struct for calling the statx function, not ++ for storing data. (Expansion will be controlled by the mask ++ argument of the statx function.) */ ++struct statx ++{ ++ __uint32_t stx_mask; ++ __uint32_t stx_blksize; ++ __uint64_t stx_attributes; ++ __uint32_t stx_nlink; ++ __uint32_t stx_uid; ++ __uint32_t stx_gid; ++ __uint16_t stx_mode; ++ __uint16_t __statx_pad1[1]; ++ __uint64_t stx_ino; ++ __uint64_t stx_size; ++ __uint64_t stx_blocks; ++ __uint64_t stx_attributes_mask; ++ struct statx_timestamp stx_atime; ++ struct statx_timestamp stx_btime; ++ struct statx_timestamp stx_ctime; ++ struct statx_timestamp stx_mtime; ++ __uint32_t stx_rdev_major; ++ __uint32_t stx_rdev_minor; ++ __uint32_t stx_dev_major; ++ __uint32_t stx_dev_minor; ++ __uint64_t __statx_pad2[14]; ++}; ++ ++#endif /* __statx_defined */ +diff --git a/io/bits/types/struct_statx_timestamp.h b/io/bits/types/struct_statx_timestamp.h +new file mode 100644 +index 0000000000000000..0f104ef84ed7d356 +--- /dev/null ++++ b/io/bits/types/struct_statx_timestamp.h +@@ -0,0 +1,33 @@ ++/* Definition of the generic version of struct statx_timestamp. ++ Copyright (C) 2018-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, see ++ . */ ++ ++#ifndef _SYS_STAT_H ++# error Never include directly, include instead. ++#endif ++ ++#ifndef __statx_timestamp_defined ++#define __statx_timestamp_defined 1 ++ ++struct statx_timestamp ++{ ++ __int64_t tv_sec; ++ __uint32_t tv_nsec; ++ __int32_t __statx_timestamp_pad1[1]; ++}; ++ ++#endif /* __statx_timestamp_defined */ +diff --git a/io/statx_generic.c b/io/statx_generic.c +index df327f8c525f748c..987c84fb45f5db63 100644 +--- a/io/statx_generic.c ++++ b/io/statx_generic.c +@@ -18,9 +18,16 @@ + + #include + #include ++#include + #include + #include + ++/* Obtain the original definition of struct statx. */ ++#undef __statx_defined ++#define statx original_statx ++#include ++#undef statx ++ + static inline struct statx_timestamp + statx_convert_timestamp (struct timespec tv) + { +@@ -57,7 +64,7 @@ statx_generic (int fd, const char *path, int flags, + /* The interface is defined in such a way that unused (padding) + fields have to be cleared. STATX_BASIC_STATS corresponds to the + data which is available via fstatat64. */ +- *buf = (struct statx) ++ struct original_statx obuf = + { + .stx_mask = STATX_BASIC_STATS, + .stx_blksize = st.st_blksize, +@@ -76,6 +83,8 @@ statx_generic (int fd, const char *path, int flags, + .stx_dev_major = major (st.st_dev), + .stx_dev_minor = minor (st.st_dev), + }; ++ _Static_assert (sizeof (*buf) >= sizeof (obuf), "struct statx size"); ++ memcpy (buf, &obuf, sizeof (obuf)); + + return 0; + } +diff --git a/sysdeps/unix/sysv/linux/bits/statx.h b/sysdeps/unix/sysv/linux/bits/statx.h +new file mode 100644 +index 0000000000000000..d36f44efc60a0bed +--- /dev/null ++++ b/sysdeps/unix/sysv/linux/bits/statx.h +@@ -0,0 +1,34 @@ ++/* statx-related definitions and declarations. Linux version. ++ Copyright (C) 2018-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, see ++ . */ ++ ++/* This interface is based on in Linux. */ ++ ++#ifndef _SYS_STAT_H ++# error Never include directly, include instead. ++#endif ++ ++/* Use the Linux kernel header if available. */ ++#if __glibc_has_include () ++# include ++# ifdef STATX_TYPE ++# define __statx_timestamp_defined 1 ++# define __statx_defined 1 ++# endif ++#endif ++ ++#include diff --git a/SOURCES/glibc-rh1699194-3.patch b/SOURCES/glibc-rh1699194-3.patch new file mode 100644 index 0000000..ced417e --- /dev/null +++ b/SOURCES/glibc-rh1699194-3.patch @@ -0,0 +1,28 @@ +commit 8d141877e07cc594e9fefc3795b8ba729288093c +Author: Florian Weimer +Date: Fri Jun 14 15:46:02 2019 +0200 + + : Inhibit macro expansion for __glibc_has_include + + This is currently ineffective with GCC because of GCC PR 80005, but + it makes sense to anticipate a fix for this defect. + + Suggested by Zack Weinberg. + + Reviewed-by: Carlos O'Donell + +diff --git a/misc/sys/cdefs.h b/misc/sys/cdefs.h +index 0500779d0c1b64c2..9e840e602f815d86 100644 +--- a/misc/sys/cdefs.h ++++ b/misc/sys/cdefs.h +@@ -413,7 +413,9 @@ + #endif + + #ifdef __has_include +-# define __glibc_has_include(header) __has_include (header) ++/* Do not use a function-like macro, so that __has_include can inhibit ++ macro expansion. */ ++# define __glibc_has_include __has_include + #else + # define __glibc_has_include(header) 0 + #endif diff --git a/SOURCES/glibc-rh1699194-4.patch b/SOURCES/glibc-rh1699194-4.patch new file mode 100644 index 0000000..1892855 --- /dev/null +++ b/SOURCES/glibc-rh1699194-4.patch @@ -0,0 +1,37 @@ +commit 48c3c1238925410b4e777dc94e2fde4cc9132d44 +Author: Florian Weimer +Date: Fri Jun 14 16:28:41 2019 +0200 + + Linux: Fix __glibc_has_include use for and statx + + The identifier linux is used as a predefined macro, so the actually + used path is 1/stat.h or 1/stat64.h. Using the quote-based version + triggers a file lookup for /usr/include/bits/linux/stat.h (or whatever + directory is used to store bits/statx.h), but since bits/ is pretty + much reserved by glibc, this appears to be acceptable. + + This is related to GCC PR 80005: incorrect macro expansion of the + argument of __has_include. + + Suggested by Zack Weinberg. + + Reviewed-by: Carlos O'Donell + +diff --git a/sysdeps/unix/sysv/linux/bits/statx.h b/sysdeps/unix/sysv/linux/bits/statx.h +index d36f44efc60a0bed..206878723fd37881 100644 +--- a/sysdeps/unix/sysv/linux/bits/statx.h ++++ b/sysdeps/unix/sysv/linux/bits/statx.h +@@ -23,8 +23,11 @@ + #endif + + /* Use the Linux kernel header if available. */ +-#if __glibc_has_include () +-# include ++ ++/* Use "" to work around incorrect macro expansion of the ++ __has_include argument (GCC PR 80005). */ ++#if __glibc_has_include ("linux/stat.h") ++# include "linux/stat.h" + # ifdef STATX_TYPE + # define __statx_timestamp_defined 1 + # define __statx_defined 1 diff --git a/SOURCES/glibc-rh1701605-1.patch b/SOURCES/glibc-rh1701605-1.patch new file mode 100644 index 0000000..b21720c --- /dev/null +++ b/SOURCES/glibc-rh1701605-1.patch @@ -0,0 +1,298 @@ +commit e485b2b6e006a7efa5d73e6be7e357a395c77fe3 +Author: Florian Weimer +Date: Tue Apr 23 18:16:26 2019 +0200 + + locale: Add LOCPATH diagnostics to the locale program + + The implementation of quote_string is based on support_quote_blob. + + Reviewed-by: Carlos O'Donell + +diff --git a/locale/Makefile b/locale/Makefile +index fd9972279ba7fe0b..42bb36c7d374eebe 100644 +--- a/locale/Makefile ++++ b/locale/Makefile +@@ -28,6 +28,7 @@ routines = setlocale findlocale loadlocale loadarchive \ + localeconv nl_langinfo nl_langinfo_l mb_cur_max \ + newlocale duplocale freelocale uselocale + tests = tst-C-locale tst-locname tst-duplocale ++tests-special = $(objpfx)tst-locale-locpath.out + categories = ctype messages monetary numeric time paper name \ + address telephone measurement identification collate + aux = $(categories:%=lc-%) $(categories:%=C-%) SYS_libc C_name \ +@@ -104,3 +105,7 @@ cpp-srcs-left := $(localedef-modules) $(localedef-aux) $(locale-modules) \ + $(lib-modules) + lib := locale-programs + include $(patsubst %,$(..)libof-iterator.mk,$(cpp-srcs-left)) ++ ++$(objpfx)tst-locale-locpath.out : tst-locale-locpath.sh $(objpfx)locale ++ $(SHELL) $< '$(common-objpfx)' '$(test-wrapper)' '$(test-wrapper-env)' > $@; \ ++ $(evaluate-test) +diff --git a/locale/programs/locale.c b/locale/programs/locale.c +index 86941e4ef6e67d78..0e2e3e4e5788246f 100644 +--- a/locale/programs/locale.c ++++ b/locale/programs/locale.c +@@ -173,6 +173,9 @@ static int write_archive_locales (void **all_datap, char *linebuf); + static void write_charmaps (void); + static void show_locale_vars (void); + static void show_info (const char *name); ++static void try_setlocale (int category, const char *category_name); ++static char *quote_string (const char *input); ++static void setlocale_diagnostics (void); + + + int +@@ -186,10 +189,8 @@ main (int argc, char *argv[]) + + /* Set locale. Do not set LC_ALL because the other categories must + not be affected (according to POSIX.2). */ +- if (setlocale (LC_CTYPE, "") == NULL) +- error (0, errno, gettext ("Cannot set LC_CTYPE to default locale")); +- if (setlocale (LC_MESSAGES, "") == NULL) +- error (0, errno, gettext ("Cannot set LC_MESSAGES to default locale")); ++ try_setlocale (LC_CTYPE, "LC_CTYPE"); ++ try_setlocale (LC_MESSAGES, "LC_MESSAGES"); + + /* Initialize the message catalog. */ + textdomain (PACKAGE); +@@ -200,9 +201,8 @@ main (int argc, char *argv[]) + /* `-a' requests the names of all available locales. */ + if (do_all != 0) + { +- if (setlocale (LC_COLLATE, "") == NULL) +- error (0, errno, +- gettext ("Cannot set LC_COLLATE to default locale")); ++ setlocale_diagnostics (); ++ try_setlocale (LC_COLLATE, "LC_COLLATE"); + write_locales (); + exit (EXIT_SUCCESS); + } +@@ -211,14 +211,15 @@ main (int argc, char *argv[]) + used for the -f argument to localedef(1). */ + if (do_charmaps != 0) + { ++ setlocale_diagnostics (); + write_charmaps (); + exit (EXIT_SUCCESS); + } + + /* Specific information about the current locale are requested. + Change to this locale now. */ +- if (setlocale (LC_ALL, "") == NULL) +- error (0, errno, gettext ("Cannot set LC_ALL to default locale")); ++ try_setlocale (LC_ALL, "LC_ALL"); ++ setlocale_diagnostics (); + + /* If no real argument is given we have to print the contents of the + current locale definition variables. These are LANG and the LC_*. */ +@@ -983,3 +984,121 @@ show_info (const char *name) + For testing and perhaps advanced use allow some more symbols. */ + locale_special (name, show_category_name, show_keyword_name); + } ++ ++/* Set to true by try_setlocale if setlocale fails. Used by ++ setlocale_diagnostics. */ ++static bool setlocale_failed; ++ ++/* Call setlocale, with non-fatal error reporting. */ ++static void ++try_setlocale (int category, const char *category_name) ++{ ++ if (setlocale (category, "") == NULL) ++ { ++ error (0, errno, gettext ("Cannot set %s to default locale"), ++ category_name); ++ setlocale_failed = true; ++ } ++} ++ ++/* Return a quoted version of the passed string, or NULL on error. */ ++static char * ++quote_string (const char *input) ++{ ++ char *buffer; ++ size_t length; ++ FILE *stream = open_memstream (&buffer, &length); ++ if (stream == NULL) ++ return NULL; ++ ++ while (true) ++ { ++ unsigned char ch = *input++; ++ if (ch == '\0') ++ break; ++ ++ /* Use C backslash escapes for those control characters for ++ which they are defined. */ ++ switch (ch) ++ { ++ case '\a': ++ putc_unlocked ('\\', stream); ++ putc_unlocked ('a', stream); ++ break; ++ case '\b': ++ putc_unlocked ('\\', stream); ++ putc_unlocked ('b', stream); ++ break; ++ case '\f': ++ putc_unlocked ('\\', stream); ++ putc_unlocked ('f', stream); ++ break; ++ case '\n': ++ putc_unlocked ('\\', stream); ++ putc_unlocked ('n', stream); ++ break; ++ case '\r': ++ putc_unlocked ('\\', stream); ++ putc_unlocked ('r', stream); ++ break; ++ case '\t': ++ putc_unlocked ('\\', stream); ++ putc_unlocked ('t', stream); ++ break; ++ case '\v': ++ putc_unlocked ('\\', stream); ++ putc_unlocked ('v', stream); ++ break; ++ case '\\': ++ case '\'': ++ case '\"': ++ putc_unlocked ('\\', stream); ++ putc_unlocked (ch, stream); ++ break; ++ default: ++ if (ch < ' ' || ch > '~') ++ /* Use octal sequences because they are fixed width, ++ unlike hexadecimal sequences. */ ++ fprintf (stream, "\\%03o", ch); ++ else ++ putc_unlocked (ch, stream); ++ } ++ } ++ ++ if (ferror (stream)) ++ { ++ fclose (stream); ++ free (buffer); ++ return NULL; ++ } ++ if (fclose (stream) != 0) ++ { ++ free (buffer); ++ return NULL; ++ } ++ ++ return buffer; ++} ++ ++/* Print additional information if there was a setlocale error (during ++ try_setlocale). */ ++static void ++setlocale_diagnostics (void) ++{ ++ if (setlocale_failed) ++ { ++ const char *locpath = getenv ("LOCPATH"); ++ if (locpath != NULL) ++ { ++ char *quoted = quote_string (locpath); ++ if (quoted != NULL) ++ fprintf (stderr, ++ gettext ("\ ++warning: The LOCPATH variable is set to \"%s\"\n"), ++ quoted); ++ else ++ fputs ("warning: The LOCPATH variable is set\n", stderr); ++ free (quoted); ++ } ++ } ++} +diff --git a/locale/tst-locale-locpath.sh b/locale/tst-locale-locpath.sh +new file mode 100644 +index 0000000000000000..b83de90a39121af6 +--- /dev/null ++++ b/locale/tst-locale-locpath.sh +@@ -0,0 +1,83 @@ ++#!/bin/sh ++# Test that locale prints LOCPATH on failure. ++# 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, see ++# . ++ ++set -ex ++ ++common_objpfx=$1 ++test_wrapper_env=$2 ++run_program_env=$3 ++ ++LIBPATH="$common_objpfx" ++ ++testroot="${common_objpfx}locale/tst-locale-locpath-directory" ++cleanup () { ++ rm -rf "$testroot" ++} ++trap cleanup 0 ++ ++rm -rf "$testroot" ++mkdir -p $testroot ++ ++unset LANG ++ ++${test_wrapper_env} \ ++${run_program_env} LC_ALL=invalid-locale LOCPATH=does-not-exist \ ++${common_objpfx}elf/ld.so --library-path "$LIBPATH" \ ++ "${common_objpfx}locale/locale" \ ++ > "$testroot/stdout" 2> "$testroot/stderr" ++ ++echo "* standard error" ++cat "$testroot/stderr" ++echo "* standard output" ++cat "$testroot/stdout" ++ ++cat > "$testroot/stderr-expected" < "$testroot/stdout-expected" < +Date: Wed Apr 24 07:31:29 2019 +0200 + + locale/tst-locale-locpath: Run test only for $(run-built-tests) == yes + +diff --git a/locale/Makefile b/locale/Makefile +index 42bb36c7d374eebe..23a71321b6646c49 100644 +--- a/locale/Makefile ++++ b/locale/Makefile +@@ -28,7 +28,6 @@ routines = setlocale findlocale loadlocale loadarchive \ + localeconv nl_langinfo nl_langinfo_l mb_cur_max \ + newlocale duplocale freelocale uselocale + tests = tst-C-locale tst-locname tst-duplocale +-tests-special = $(objpfx)tst-locale-locpath.out + categories = ctype messages monetary numeric time paper name \ + address telephone measurement identification collate + aux = $(categories:%=lc-%) $(categories:%=C-%) SYS_libc C_name \ +@@ -61,6 +60,10 @@ lib-modules := charmap-dir simple-hash xmalloc xstrdup \ + GPERF = gperf + GPERFFLAGS = -acCgopt -k1,2,5,9,$$ -L ANSI-C + ++ifeq ($(run-built-tests),yes) ++tests-special += $(objpfx)tst-locale-locpath.out ++endif ++ + include ../Rules + + CFLAGS-md5.c += -I../crypt diff --git a/SOURCES/glibc-rh1702539-1.patch b/SOURCES/glibc-rh1702539-1.patch new file mode 100644 index 0000000..8023b6c --- /dev/null +++ b/SOURCES/glibc-rh1702539-1.patch @@ -0,0 +1,789 @@ +This patch is a rework of the following upstream patch: + +commit 0e169691290a6d2187a4ff41495fc5678cbfdcdc +Author: Adhemerval Zanella +Date: Fri Apr 12 17:39:53 2019 -0300 + + support: Add support_capture_subprogram + + Its API is similar to support_capture_subprocess, but rather creates a + new process based on the input path and arguments. Under the hoods it + uses posix_spawn to create the new process. + + It also allows the use of other support_capture_* functions to check + for expected results and free the resources. + + Checked on x86_64-linux-gnu. + + * support/Makefile (libsupport-routines): Add support_subprocess, + xposix_spawn, xposix_spawn_file_actions_addclose, and + xposix_spawn_file_actions_adddup2. + (tst-support_capture_subprocess-ARGS): New rule. + * support/capture_subprocess.h (support_capture_subprogram): New + prototype. + * support/support_capture_subprocess.c (support_capture_subprocess): + Refactor to use support_subprocess and support_capture_poll. + (support_capture_subprogram): New function. + * support/tst-support_capture_subprocess.c (write_mode_to_str, + str_to_write_mode, test_common, parse_int, handle_restart, + do_subprocess, do_subprogram, do_multiple_tests): New functions. + (do_test): Add support_capture_subprogram tests. + * support/subprocess.h: New file. + * support/support_subprocess.c: Likewise. + * support/xposix_spawn.c: Likewise. + * support/xposix_spawn_file_actions_addclose.c: Likewise. + * support/xposix_spawn_file_actions_adddup2.c: Likewise. + * support/xspawn.h: Likewise. + + Reviewed-by: Carlos O'Donell + + + +diff -Nrup a/support/capture_subprocess.h b/support/capture_subprocess.h +--- a/support/capture_subprocess.h 2018-08-01 01:10:47.000000000 -0400 ++++ b/support/capture_subprocess.h 2019-05-16 23:37:19.903845257 -0400 +@@ -35,6 +35,12 @@ struct support_capture_subprocess + struct support_capture_subprocess support_capture_subprocess + (void (*callback) (void *), void *closure); + ++/* Issue FILE with ARGV arguments by using posix_spawn and capture standard ++ output, standard error, and the exit status. The out.buffer and err.buffer ++ are handle as support_capture_subprocess. */ ++struct support_capture_subprocess support_capture_subprogram ++ (const char *file, char *const argv[]); ++ + /* Deallocate the subprocess data captured by + support_capture_subprocess. */ + void support_capture_subprocess_free (struct support_capture_subprocess *); +diff -Nrup a/support/Makefile b/support/Makefile +--- a/support/Makefile 2019-05-16 23:36:51.066665814 -0400 ++++ b/support/Makefile 2019-05-17 10:31:24.268313761 -0400 +@@ -63,6 +63,7 @@ libsupport-routines = \ + support_record_failure \ + support_run_diff \ + support_shared_allocate \ ++ support_subprocess \ + support_test_compare_blob \ + support_test_compare_failure \ + support_test_compare_string \ +@@ -147,6 +148,9 @@ libsupport-routines = \ + xsigaction \ + xsignal \ + xsocket \ ++ xposix_spawn \ ++ xposix_spawn_file_actions_addclose \ ++ xposix_spawn_file_actions_adddup2 \ + xstrdup \ + xstrndup \ + xsymlink \ +@@ -221,4 +225,6 @@ endif + + $(objpfx)tst-support_format_dns_packet: $(common-objpfx)resolv/libresolv.so + ++tst-support_capture_subprocess-ARGS = -- $(host-test-program-cmd) ++ + include ../Rules +diff -Nrup a/support/subprocess.h b/support/subprocess.h +--- a/support/subprocess.h 1969-12-31 19:00:00.000000000 -0500 ++++ b/support/subprocess.h 2019-05-16 23:37:19.903845257 -0400 +@@ -0,0 +1,49 @@ ++/* Create a subprocess. ++ 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, see ++ . */ ++ ++#ifndef SUPPORT_SUBPROCESS_H ++#define SUPPORT_SUBPROCESS_H ++ ++#include ++ ++struct support_subprocess ++{ ++ int stdout_pipe[2]; ++ int stderr_pipe[2]; ++ pid_t pid; ++}; ++ ++/* Invoke CALLBACK (CLOSURE) in a subprocess created with fork and return ++ its PID, a pipe redirected to STDOUT, and a pipe redirected to STDERR. */ ++struct support_subprocess support_subprocess ++ (void (*callback) (void *), void *closure); ++ ++/* Issue FILE with ARGV arguments by using posix_spawn and return is PID, a ++ pipe redirected to STDOUT, and a pipe redirected to STDERR. */ ++struct support_subprocess support_subprogram ++ (const char *file, char *const argv[]); ++ ++/* Wait for the subprocess indicated by PROC::PID. Return the status ++ indicate by waitpid call. */ ++int support_process_wait (struct support_subprocess *proc); ++ ++/* Terminate the subprocess indicated by PROC::PID, first with a SIGTERM and ++ then with a SIGKILL. Return the status as for waitpid call. */ ++int support_process_terminate (struct support_subprocess *proc); ++ ++#endif +diff -Nrup a/support/support_capture_subprocess.c b/support/support_capture_subprocess.c +--- a/support/support_capture_subprocess.c 2019-05-16 23:36:50.672677025 -0400 ++++ b/support/support_capture_subprocess.c 2019-05-16 23:38:34.298728367 -0400 +@@ -16,6 +16,7 @@ + License along with the GNU C Library; if not, see + . */ + ++#include + #include + + #include +@@ -23,6 +24,7 @@ + #include + #include + #include ++#include + + static void + transfer (const char *what, struct pollfd *pfd, struct xmemstream *stream) +@@ -50,59 +52,52 @@ transfer (const char *what, struct pollf + } + } + +-struct support_capture_subprocess +-support_capture_subprocess (void (*callback) (void *), void *closure) ++static void ++support_capture_poll (struct support_capture_subprocess *result, ++ struct support_subprocess *proc) + { +- struct support_capture_subprocess result; +- xopen_memstream (&result.out); +- xopen_memstream (&result.err); +- +- int stdout_pipe[2]; +- xpipe (stdout_pipe); +- TEST_VERIFY (stdout_pipe[0] > STDERR_FILENO); +- TEST_VERIFY (stdout_pipe[1] > STDERR_FILENO); +- int stderr_pipe[2]; +- xpipe (stderr_pipe); +- TEST_VERIFY (stderr_pipe[0] > STDERR_FILENO); +- TEST_VERIFY (stderr_pipe[1] > STDERR_FILENO); +- +- TEST_VERIFY (fflush (stdout) == 0); +- TEST_VERIFY (fflush (stderr) == 0); +- +- pid_t pid = xfork (); +- if (pid == 0) +- { +- xclose (stdout_pipe[0]); +- xclose (stderr_pipe[0]); +- xdup2 (stdout_pipe[1], STDOUT_FILENO); +- xdup2 (stderr_pipe[1], STDERR_FILENO); +- xclose (stdout_pipe[1]); +- xclose (stderr_pipe[1]); +- callback (closure); +- _exit (0); +- } +- xclose (stdout_pipe[1]); +- xclose (stderr_pipe[1]); +- + struct pollfd fds[2] = + { +- { .fd = stdout_pipe[0], .events = POLLIN }, +- { .fd = stderr_pipe[0], .events = POLLIN }, ++ { .fd = proc->stdout_pipe[0], .events = POLLIN }, ++ { .fd = proc->stderr_pipe[0], .events = POLLIN }, + }; + + do + { + xpoll (fds, 2, -1); +- transfer ("stdout", &fds[0], &result.out); +- transfer ("stderr", &fds[1], &result.err); ++ transfer ("stdout", &fds[0], &result->out); ++ transfer ("stderr", &fds[1], &result->err); + } + while (fds[0].events != 0 || fds[1].events != 0); +- xclose (stdout_pipe[0]); +- xclose (stderr_pipe[0]); ++ xfclose_memstream (&result->out); ++ xfclose_memstream (&result->err); ++ ++ result->status = support_process_wait (proc); ++} ++ ++struct support_capture_subprocess ++support_capture_subprocess (void (*callback) (void *), void *closure) ++{ ++ struct support_capture_subprocess result; ++ xopen_memstream (&result.out); ++ xopen_memstream (&result.err); ++ ++ struct support_subprocess proc = support_subprocess (callback, closure); ++ ++ support_capture_poll (&result, &proc); ++ return result; ++} ++ ++struct support_capture_subprocess ++support_capture_subprogram (const char *file, char *const argv[]) ++{ ++ struct support_capture_subprocess result; ++ xopen_memstream (&result.out); ++ xopen_memstream (&result.err); ++ ++ struct support_subprocess proc = support_subprogram (file, argv); + +- xfclose_memstream (&result.out); +- xfclose_memstream (&result.err); +- xwaitpid (pid, &result.status, 0); ++ support_capture_poll (&result, &proc); + return result; + } + +diff -Nrup a/support/support_subprocess.c b/support/support_subprocess.c +--- a/support/support_subprocess.c 1969-12-31 19:00:00.000000000 -0500 ++++ b/support/support_subprocess.c 2019-05-16 23:37:19.903845257 -0400 +@@ -0,0 +1,152 @@ ++/* Create subprocess. ++ 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, see ++ . */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++static struct support_subprocess ++support_suprocess_init (void) ++{ ++ struct support_subprocess result; ++ ++ xpipe (result.stdout_pipe); ++ TEST_VERIFY (result.stdout_pipe[0] > STDERR_FILENO); ++ TEST_VERIFY (result.stdout_pipe[1] > STDERR_FILENO); ++ ++ xpipe (result.stderr_pipe); ++ TEST_VERIFY (result.stderr_pipe[0] > STDERR_FILENO); ++ TEST_VERIFY (result.stderr_pipe[1] > STDERR_FILENO); ++ ++ TEST_VERIFY (fflush (stdout) == 0); ++ TEST_VERIFY (fflush (stderr) == 0); ++ ++ return result; ++} ++ ++struct support_subprocess ++support_subprocess (void (*callback) (void *), void *closure) ++{ ++ struct support_subprocess result = support_suprocess_init (); ++ ++ result.pid = xfork (); ++ if (result.pid == 0) ++ { ++ xclose (result.stdout_pipe[0]); ++ xclose (result.stderr_pipe[0]); ++ xdup2 (result.stdout_pipe[1], STDOUT_FILENO); ++ xdup2 (result.stderr_pipe[1], STDERR_FILENO); ++ xclose (result.stdout_pipe[1]); ++ xclose (result.stderr_pipe[1]); ++ callback (closure); ++ _exit (0); ++ } ++ xclose (result.stdout_pipe[1]); ++ xclose (result.stderr_pipe[1]); ++ ++ return result; ++} ++ ++struct support_subprocess ++support_subprogram (const char *file, char *const argv[]) ++{ ++ struct support_subprocess result = support_suprocess_init (); ++ ++ posix_spawn_file_actions_t fa; ++ /* posix_spawn_file_actions_init does not fail. */ ++ posix_spawn_file_actions_init (&fa); ++ ++ xposix_spawn_file_actions_addclose (&fa, result.stdout_pipe[0]); ++ xposix_spawn_file_actions_addclose (&fa, result.stderr_pipe[0]); ++ xposix_spawn_file_actions_adddup2 (&fa, result.stdout_pipe[1], STDOUT_FILENO); ++ xposix_spawn_file_actions_adddup2 (&fa, result.stderr_pipe[1], STDERR_FILENO); ++ xposix_spawn_file_actions_addclose (&fa, result.stdout_pipe[1]); ++ xposix_spawn_file_actions_addclose (&fa, result.stderr_pipe[1]); ++ ++ result.pid = xposix_spawn (file, &fa, NULL, argv, NULL); ++ ++ xclose (result.stdout_pipe[1]); ++ xclose (result.stderr_pipe[1]); ++ ++ return result; ++} ++ ++int ++support_process_wait (struct support_subprocess *proc) ++{ ++ xclose (proc->stdout_pipe[0]); ++ xclose (proc->stderr_pipe[0]); ++ ++ int status; ++ xwaitpid (proc->pid, &status, 0); ++ return status; ++} ++ ++ ++static bool ++support_process_kill (int pid, int signo, int *status) ++{ ++ /* Kill the whole process group. */ ++ kill (-pid, signo); ++ /* In case setpgid failed in the child, kill it individually too. */ ++ kill (pid, signo); ++ ++ /* Wait for it to terminate. */ ++ pid_t killed; ++ for (int i = 0; i < 5; ++i) ++ { ++ int status; ++ killed = xwaitpid (pid, &status, WNOHANG|WUNTRACED); ++ if (killed != 0) ++ break; ++ ++ /* Delay, give the system time to process the kill. If the ++ nanosleep() call return prematurely, all the better. We ++ won't restart it since this probably means the child process ++ finally died. */ ++ nanosleep (&((struct timespec) { 0, 100000000 }), NULL); ++ } ++ if (killed != 0 && killed != pid) ++ return false; ++ ++ return true; ++} ++ ++int ++support_process_terminate (struct support_subprocess *proc) ++{ ++ xclose (proc->stdout_pipe[0]); ++ xclose (proc->stderr_pipe[0]); ++ ++ int status; ++ pid_t killed = xwaitpid (proc->pid, &status, WNOHANG|WUNTRACED); ++ if (killed != 0 && killed == proc->pid) ++ return status; ++ ++ /* Subprocess is still running, terminate it. */ ++ if (!support_process_kill (proc->pid, SIGTERM, &status) ) ++ support_process_kill (proc->pid, SIGKILL, &status); ++ ++ return status; ++} +diff -Nrup a/support/tst-support_capture_subprocess.c b/support/tst-support_capture_subprocess.c +--- a/support/tst-support_capture_subprocess.c 2018-08-01 01:10:47.000000000 -0400 ++++ b/support/tst-support_capture_subprocess.c 2019-05-16 23:37:19.904845228 -0400 +@@ -23,8 +23,20 @@ + #include + #include + #include ++#include + #include + #include ++#include ++#include ++#include ++#include ++#include ++ ++/* Nonzero if the program gets called via 'exec'. */ ++static int restart; ++ ++/* Hold the four initial argument used to respawn the process. */ ++static char *initial_argv[5]; + + /* Write one byte at *P to FD and advance *P. Do nothing if *P is + '\0'. */ +@@ -42,6 +54,30 @@ transfer (const unsigned char **p, int f + enum write_mode { out_first, err_first, interleave, + write_mode_last = interleave }; + ++static const char * ++write_mode_to_str (enum write_mode mode) ++{ ++ switch (mode) ++ { ++ case out_first: return "out_first"; ++ case err_first: return "err_first"; ++ case interleave: return "interleave"; ++ default: return "write_mode_last"; ++ } ++} ++ ++static enum write_mode ++str_to_write_mode (const char *mode) ++{ ++ if (strcmp (mode, "out_first") == 0) ++ return out_first; ++ else if (strcmp (mode, "err_first") == 0) ++ return err_first; ++ else if (strcmp (mode, "interleave") == 0) ++ return interleave; ++ return write_mode_last; ++} ++ + /* Describe what to write in the subprocess. */ + struct test + { +@@ -52,11 +88,9 @@ struct test + int status; + }; + +-/* For use with support_capture_subprocess. */ +-static void +-callback (void *closure) ++_Noreturn static void ++test_common (const struct test *test) + { +- const struct test *test = closure; + bool mode_ok = false; + switch (test->write_mode) + { +@@ -95,6 +129,40 @@ callback (void *closure) + exit (test->status); + } + ++static int ++parse_int (const char *str) ++{ ++ char *endptr; ++ long int ret = strtol (str, &endptr, 10); ++ TEST_COMPARE (errno, 0); ++ TEST_VERIFY (ret >= 0 && ret <= INT_MAX); ++ return ret; ++} ++ ++/* For use with support_capture_subprogram. */ ++_Noreturn static void ++handle_restart (char *out, char *err, const char *write_mode, ++ const char *signal, const char *status) ++{ ++ struct test test = ++ { ++ out, ++ err, ++ str_to_write_mode (write_mode), ++ parse_int (signal), ++ parse_int (status) ++ }; ++ test_common (&test); ++} ++ ++/* For use with support_capture_subprocess. */ ++_Noreturn static void ++callback (void *closure) ++{ ++ const struct test *test = closure; ++ test_common (test); ++} ++ + /* Create a heap-allocated random string of letters. */ + static char * + random_string (size_t length) +@@ -130,12 +198,59 @@ check_stream (const char *what, const st + } + } + ++static struct support_capture_subprocess ++do_subprocess (struct test *test) ++{ ++ return support_capture_subprocess (callback, test); ++} ++ ++static struct support_capture_subprocess ++do_subprogram (const struct test *test) ++{ ++ /* Three digits per byte plus null terminator. */ ++ char signalstr[3 * sizeof(int) + 1]; ++ snprintf (signalstr, sizeof (signalstr), "%d", test->signal); ++ char statusstr[3 * sizeof(int) + 1]; ++ snprintf (statusstr, sizeof (statusstr), "%d", test->status); ++ ++ int argc = 0; ++ enum { ++ /* 4 elements from initial_argv (path to ld.so, '--library-path', the ++ path', and application name'), 2 for restart argument ('--direct', ++ '--restart'), 5 arguments plus NULL. */ ++ argv_size = 12 ++ }; ++ char *args[argv_size]; ++ ++ for (char **arg = initial_argv; *arg != NULL; arg++) ++ args[argc++] = *arg; ++ ++ args[argc++] = (char*) "--direct"; ++ args[argc++] = (char*) "--restart"; ++ ++ args[argc++] = test->out; ++ args[argc++] = test->err; ++ args[argc++] = (char*) write_mode_to_str (test->write_mode); ++ args[argc++] = signalstr; ++ args[argc++] = statusstr; ++ args[argc] = NULL; ++ TEST_VERIFY (argc < argv_size); ++ ++ return support_capture_subprogram (args[0], args); ++} ++ ++enum test_type ++{ ++ subprocess, ++ subprogram, ++}; ++ + static int +-do_test (void) ++do_multiple_tests (enum test_type type) + { + const int lengths[] = {0, 1, 17, 512, 20000, -1}; + +- /* Test multiple combinations of support_capture_subprocess. ++ /* Test multiple combinations of support_capture_sub{process,program}. + + length_idx_stdout: Index into the lengths array above, + controls how many bytes are written by the subprocess to +@@ -164,8 +279,10 @@ do_test (void) + TEST_VERIFY (strlen (test.out) == lengths[length_idx_stdout]); + TEST_VERIFY (strlen (test.err) == lengths[length_idx_stderr]); + +- struct support_capture_subprocess result +- = support_capture_subprocess (callback, &test); ++ struct support_capture_subprocess result ++ = type == subprocess ? do_subprocess (&test) ++ : do_subprogram (&test); ++ + check_stream ("stdout", &result.out, test.out); + check_stream ("stderr", &result.err, test.err); + if (test.signal != 0) +@@ -185,4 +302,54 @@ do_test (void) + return 0; + } + ++static int ++do_test (int argc, char *argv[]) ++{ ++ /* We must have either: ++ ++ - one or four parameters if called initially: ++ + argv[1]: path for ld.so optional ++ + argv[2]: "--library-path" optional ++ + argv[3]: the library path optional ++ + argv[4]: the application name ++ ++ - six parameters left if called through re-execution: ++ + argv[1]: the application name ++ + argv[2]: the stdout to print ++ + argv[3]: the stderr to print ++ + argv[4]: the write mode to use ++ + argv[5]: the signal to issue ++ + argv[6]: the exit status code to use ++ ++ * When built with --enable-hardcoded-path-in-tests or issued without ++ using the loader directly. ++ */ ++ ++ if (argc != (restart ? 6 : 5) && argc != (restart ? 6 : 2)) ++ FAIL_EXIT1 ("wrong number of arguments (%d)", argc); ++ ++ if (restart) ++ { ++ handle_restart (argv[1], /* stdout */ ++ argv[2], /* stderr */ ++ argv[3], /* write_mode */ ++ argv[4], /* signal */ ++ argv[5]); /* status */ ++ } ++ ++ initial_argv[0] = argv[1]; /* path for ld.so */ ++ initial_argv[1] = argv[2]; /* "--library-path" */ ++ initial_argv[2] = argv[3]; /* the library path */ ++ initial_argv[3] = argv[4]; /* the application name */ ++ initial_argv[4] = NULL; ++ ++ do_multiple_tests (subprocess); ++ do_multiple_tests (subprogram); ++ ++ return 0; ++} ++ ++#define CMDLINE_OPTIONS \ ++ { "restart", no_argument, &restart, 1 }, ++#define TEST_FUNCTION_ARGV do_test + #include +diff -Nrup a/support/xposix_spawn.c b/support/xposix_spawn.c +--- a/support/xposix_spawn.c 1969-12-31 19:00:00.000000000 -0500 ++++ b/support/xposix_spawn.c 2019-05-16 23:37:19.904845228 -0400 +@@ -0,0 +1,32 @@ ++/* xposix_spawn implementation. ++ 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, see ++ . */ ++ ++#include ++#include ++ ++pid_t ++xposix_spawn (const char *file, const posix_spawn_file_actions_t *fa, ++ const posix_spawnattr_t *attr, char *const args[], ++ char *const envp[]) ++{ ++ pid_t pid; ++ int status = posix_spawn (&pid, file, fa, attr, args, envp); ++ if (status != 0) ++ FAIL_EXIT1 ("posix_spawn to %s file failed: %m", file); ++ return pid; ++} +diff -Nrup a/support/xposix_spawn_file_actions_addclose.c b/support/xposix_spawn_file_actions_addclose.c +--- a/support/xposix_spawn_file_actions_addclose.c 1969-12-31 19:00:00.000000000 -0500 ++++ b/support/xposix_spawn_file_actions_addclose.c 2019-05-16 23:37:19.904845228 -0400 +@@ -0,0 +1,29 @@ ++/* xposix_spawn_file_actions_addclose implementation. ++ 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, see ++ . */ ++ ++#include ++#include ++ ++int ++xposix_spawn_file_actions_addclose (posix_spawn_file_actions_t *fa, int fd) ++{ ++ int status = posix_spawn_file_actions_addclose (fa, fd); ++ if (status == -1) ++ FAIL_EXIT1 ("posix_spawn_file_actions_addclose failed: %m\n"); ++ return status; ++} +diff -Nrup a/support/xposix_spawn_file_actions_adddup2.c b/support/xposix_spawn_file_actions_adddup2.c +--- a/support/xposix_spawn_file_actions_adddup2.c 1969-12-31 19:00:00.000000000 -0500 ++++ b/support/xposix_spawn_file_actions_adddup2.c 2019-05-16 23:37:19.904845228 -0400 +@@ -0,0 +1,30 @@ ++/* xposix_spawn_file_actions_adddup2 implementation. ++ 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, see ++ . */ ++ ++#include ++#include ++ ++int ++xposix_spawn_file_actions_adddup2 (posix_spawn_file_actions_t *fa, int fd, ++ int newfd) ++{ ++ int status = posix_spawn_file_actions_adddup2 (fa, fd, newfd); ++ if (status == -1) ++ FAIL_EXIT1 ("posix_spawn_file_actions_adddup2 failed: %m\n"); ++ return status; ++} +diff -Nrup a/support/xspawn.h b/support/xspawn.h +--- a/support/xspawn.h 1969-12-31 19:00:00.000000000 -0500 ++++ b/support/xspawn.h 2019-05-16 23:37:19.904845228 -0400 +@@ -0,0 +1,34 @@ ++/* posix_spawn with support checks. ++ 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, see ++ . */ ++ ++#ifndef SUPPORT_XSPAWN_H ++#define SUPPORT_XSPAWN_H ++ ++#include ++ ++__BEGIN_DECLS ++ ++int xposix_spawn_file_actions_addclose (posix_spawn_file_actions_t *, int); ++int xposix_spawn_file_actions_adddup2 (posix_spawn_file_actions_t *, int, int); ++ ++pid_t xposix_spawn (const char *, const posix_spawn_file_actions_t *, ++ const posix_spawnattr_t *, char *const [], char *const []); ++ ++__END_DECLS ++ ++#endif diff --git a/SOURCES/glibc-rh1702539-2.patch b/SOURCES/glibc-rh1702539-2.patch new file mode 100644 index 0000000..1c1b8bb --- /dev/null +++ b/SOURCES/glibc-rh1702539-2.patch @@ -0,0 +1,558 @@ +This patch is a rework of the following upstream patch: + +commit 1a4c27355e146b6d8cc6487b998462c7fdd1048f +Author: Adhemerval Zanella +Date: Thu Apr 11 18:12:00 2019 -0300 + + elf: Fix pldd (BZ#18035) + + Since 9182aa67994 (Fix vDSO l_name for GDB's, BZ#387) the initial link_map + for executable itself and loader will have both l_name and l_libname->name + holding the same value due: + + elf/dl-object.c + + 95 new->l_name = *realname ? realname : (char *) newname->name + libname_len - 1; + + Since newname->name points to new->l_libname->name. + + This leads to pldd to an infinite call at: + + elf/pldd-xx.c + + 203 again: + 204 while (1) + 205 { + 206 ssize_t n = pread64 (memfd, tmpbuf.data, tmpbuf.length, name_offset); + + 228 /* Try the l_libname element. */ + 229 struct E(libname_list) ln; + 230 if (pread64 (memfd, &ln, sizeof (ln), m.l_libname) == sizeof (ln)) + 231 { + 232 name_offset = ln.name; + 233 goto again; + 234 } + + Since the value at ln.name (l_libname->name) will be the same as previously + read. The straightforward fix is just avoid the check and read the new list + entry. + + I checked also against binaries issues with old loaders with fix for BZ#387, + and pldd could dump the shared objects. + + Checked on x86_64-linux-gnu, i686-linux-gnu, aarch64-linux-gnu, and + powerpc64le-linux-gnu. + +diff -Nrup a/elf/Makefile b/elf/Makefile +--- a/elf/Makefile 2019-05-17 12:35:12.663074766 -0400 ++++ b/elf/Makefile 2019-05-17 12:35:45.816147975 -0400 +@@ -201,6 +201,7 @@ tests-internal += loadtest unload unload + neededtest neededtest2 neededtest3 neededtest4 \ + tst-tls3 tst-tls6 tst-tls7 tst-tls8 tst-dlmopen2 \ + tst-ptrguard1 tst-stackguard1 tst-libc_dlvsym ++tests-container += tst-pldd + ifeq ($(build-hardcoded-path-in-tests),yes) + tests += tst-dlopen-aout + tst-dlopen-aout-no-pie = yes +diff -Nrup a/elf/pldd.c b/elf/pldd.c +--- a/elf/pldd.c 2018-08-01 01:10:47.000000000 -0400 ++++ b/elf/pldd.c 2019-05-17 12:35:45.817147947 -0400 +@@ -17,23 +17,17 @@ + License along with the GNU C Library; if not, see + . */ + +-#include ++#define _FILE_OFFSET_BITS 64 ++ + #include +-#include + #include +-#include +-#include + #include + #include + #include +-#include +-#include + #include + #include +-#include + #include + #include +-#include + #include + #include + +@@ -76,14 +70,8 @@ static struct argp argp = + options, parse_opt, args_doc, doc, NULL, more_help, NULL + }; + +-// File descriptor of /proc/*/mem file. +-static int memfd; +- +-/* Name of the executable */ +-static char *exe; +- + /* Local functions. */ +-static int get_process_info (int dfd, long int pid); ++static int get_process_info (const char *exe, int dfd, long int pid); + static void wait_for_ptrace_stop (long int pid); + + +@@ -102,8 +90,10 @@ main (int argc, char *argv[]) + return 1; + } + +- assert (sizeof (pid_t) == sizeof (int) +- || sizeof (pid_t) == sizeof (long int)); ++ _Static_assert (sizeof (pid_t) == sizeof (int) ++ || sizeof (pid_t) == sizeof (long int), ++ "sizeof (pid_t) != sizeof (int) or sizeof (long int)"); ++ + char *endp; + errno = 0; + long int pid = strtol (argv[remaining], &endp, 10); +@@ -119,25 +109,24 @@ main (int argc, char *argv[]) + if (dfd == -1) + error (EXIT_FAILURE, errno, gettext ("cannot open %s"), buf); + +- struct scratch_buffer exebuf; +- scratch_buffer_init (&exebuf); ++ /* Name of the executable */ ++ struct scratch_buffer exe; ++ scratch_buffer_init (&exe); + ssize_t nexe; + while ((nexe = readlinkat (dfd, "exe", +- exebuf.data, exebuf.length)) == exebuf.length) ++ exe.data, exe.length)) == exe.length) + { +- if (!scratch_buffer_grow (&exebuf)) ++ if (!scratch_buffer_grow (&exe)) + { + nexe = -1; + break; + } + } + if (nexe == -1) +- exe = (char *) ""; ++ /* Default stack allocation is at least 1024. */ ++ snprintf (exe.data, exe.length, ""); + else +- { +- exe = exebuf.data; +- exe[nexe] = '\0'; +- } ++ ((char*)exe.data)[nexe] = '\0'; + + /* Stop all threads since otherwise the list of loaded modules might + change while we are reading it. */ +@@ -155,8 +144,8 @@ main (int argc, char *argv[]) + error (EXIT_FAILURE, errno, gettext ("cannot prepare reading %s/task"), + buf); + +- struct dirent64 *d; +- while ((d = readdir64 (dir)) != NULL) ++ struct dirent *d; ++ while ((d = readdir (dir)) != NULL) + { + if (! isdigit (d->d_name[0])) + continue; +@@ -182,7 +171,7 @@ main (int argc, char *argv[]) + + wait_for_ptrace_stop (tid); + +- struct thread_list *newp = alloca (sizeof (*newp)); ++ struct thread_list *newp = xmalloc (sizeof (*newp)); + newp->tid = tid; + newp->next = thread_list; + thread_list = newp; +@@ -190,17 +179,22 @@ main (int argc, char *argv[]) + + closedir (dir); + +- int status = get_process_info (dfd, pid); ++ if (thread_list == NULL) ++ error (EXIT_FAILURE, 0, gettext ("no valid %s/task entries"), buf); ++ ++ int status = get_process_info (exe.data, dfd, pid); + +- assert (thread_list != NULL); + do + { + ptrace (PTRACE_DETACH, thread_list->tid, NULL, NULL); ++ struct thread_list *prev = thread_list; + thread_list = thread_list->next; ++ free (prev); + } + while (thread_list != NULL); + + close (dfd); ++ scratch_buffer_free (&exe); + + return status; + } +@@ -281,9 +275,10 @@ warranty; not even for MERCHANTABILITY o + + + static int +-get_process_info (int dfd, long int pid) ++get_process_info (const char *exe, int dfd, long int pid) + { +- memfd = openat (dfd, "mem", O_RDONLY); ++ /* File descriptor of /proc//mem file. */ ++ int memfd = openat (dfd, "mem", O_RDONLY); + if (memfd == -1) + goto no_info; + +@@ -333,9 +328,9 @@ get_process_info (int dfd, long int pid) + + int retval; + if (e_ident[EI_CLASS] == ELFCLASS32) +- retval = find_maps32 (pid, auxv, auxv_size); ++ retval = find_maps32 (exe, memfd, pid, auxv, auxv_size); + else +- retval = find_maps64 (pid, auxv, auxv_size); ++ retval = find_maps64 (exe, memfd, pid, auxv, auxv_size); + + free (auxv); + close (memfd); +diff -Nrup a/elf/pldd-xx.c b/elf/pldd-xx.c +--- a/elf/pldd-xx.c 2018-08-01 01:10:47.000000000 -0400 ++++ b/elf/pldd-xx.c 2019-05-17 13:05:29.587147445 -0400 +@@ -23,10 +23,6 @@ + #define EW_(e, w, t) EW__(e, w, _##t) + #define EW__(e, w, t) e##w##t + +-#define pldd_assert(name, exp) \ +- typedef int __assert_##name[((exp) != 0) - 1] +- +- + struct E(link_map) + { + EW(Addr) l_addr; +@@ -39,12 +35,12 @@ struct E(link_map) + EW(Addr) l_libname; + }; + #if CLASS == __ELF_NATIVE_CLASS +-pldd_assert (l_addr, (offsetof (struct link_map, l_addr) +- == offsetof (struct E(link_map), l_addr))); +-pldd_assert (l_name, (offsetof (struct link_map, l_name) +- == offsetof (struct E(link_map), l_name))); +-pldd_assert (l_next, (offsetof (struct link_map, l_next) +- == offsetof (struct E(link_map), l_next))); ++_Static_assert (offsetof (struct link_map, l_addr) ++ == offsetof (struct E(link_map), l_addr), "l_addr"); ++_Static_assert (offsetof (struct link_map, l_name) ++ == offsetof (struct E(link_map), l_name), "l_name"); ++_Static_assert (offsetof (struct link_map, l_next) ++ == offsetof (struct E(link_map), l_next), "l_next"); + #endif + + +@@ -54,10 +50,10 @@ struct E(libname_list) + EW(Addr) next; + }; + #if CLASS == __ELF_NATIVE_CLASS +-pldd_assert (name, (offsetof (struct libname_list, name) +- == offsetof (struct E(libname_list), name))); +-pldd_assert (next, (offsetof (struct libname_list, next) +- == offsetof (struct E(libname_list), next))); ++_Static_assert (offsetof (struct libname_list, name) ++ == offsetof (struct E(libname_list), name), "name"); ++_Static_assert (offsetof (struct libname_list, next) ++ == offsetof (struct E(libname_list), next), "next"); + #endif + + struct E(r_debug) +@@ -69,16 +65,17 @@ struct E(r_debug) + EW(Addr) r_map; + }; + #if CLASS == __ELF_NATIVE_CLASS +-pldd_assert (r_version, (offsetof (struct r_debug, r_version) +- == offsetof (struct E(r_debug), r_version))); +-pldd_assert (r_map, (offsetof (struct r_debug, r_map) +- == offsetof (struct E(r_debug), r_map))); ++_Static_assert (offsetof (struct r_debug, r_version) ++ == offsetof (struct E(r_debug), r_version), "r_version"); ++_Static_assert (offsetof (struct r_debug, r_map) ++ == offsetof (struct E(r_debug), r_map), "r_map"); + #endif + + + static int + +-E(find_maps) (pid_t pid, void *auxv, size_t auxv_size) ++E(find_maps) (const char *exe, int memfd, pid_t pid, void *auxv, ++ size_t auxv_size) + { + EW(Addr) phdr = 0; + unsigned int phnum = 0; +@@ -104,12 +101,9 @@ E(find_maps) (pid_t pid, void *auxv, siz + if (phdr == 0 || phnum == 0 || phent == 0) + error (EXIT_FAILURE, 0, gettext ("cannot find program header of process")); + +- EW(Phdr) *p = alloca (phnum * phent); +- if (pread64 (memfd, p, phnum * phent, phdr) != phnum * phent) +- { +- error (0, 0, gettext ("cannot read program header")); +- return EXIT_FAILURE; +- } ++ EW(Phdr) *p = xmalloc (phnum * phent); ++ if (pread (memfd, p, phnum * phent, phdr) != phnum * phent) ++ error (EXIT_FAILURE, 0, gettext ("cannot read program header")); + + /* Determine the load offset. We need this for interpreting the + other program header entries so we do this in a separate loop. +@@ -129,24 +123,18 @@ E(find_maps) (pid_t pid, void *auxv, siz + if (p[i].p_type == PT_DYNAMIC) + { + EW(Dyn) *dyn = xmalloc (p[i].p_filesz); +- if (pread64 (memfd, dyn, p[i].p_filesz, offset + p[i].p_vaddr) ++ if (pread (memfd, dyn, p[i].p_filesz, offset + p[i].p_vaddr) + != p[i].p_filesz) +- { +- error (0, 0, gettext ("cannot read dynamic section")); +- return EXIT_FAILURE; +- } ++ error (EXIT_FAILURE, 0, gettext ("cannot read dynamic section")); + + /* Search for the DT_DEBUG entry. */ + for (unsigned int j = 0; j < p[i].p_filesz / sizeof (EW(Dyn)); ++j) + if (dyn[j].d_tag == DT_DEBUG && dyn[j].d_un.d_ptr != 0) + { + struct E(r_debug) r; +- if (pread64 (memfd, &r, sizeof (r), dyn[j].d_un.d_ptr) ++ if (pread (memfd, &r, sizeof (r), dyn[j].d_un.d_ptr) + != sizeof (r)) +- { +- error (0, 0, gettext ("cannot read r_debug")); +- return EXIT_FAILURE; +- } ++ error (EXIT_FAILURE, 0, gettext ("cannot read r_debug")); + + if (r.r_map != 0) + { +@@ -160,13 +148,10 @@ E(find_maps) (pid_t pid, void *auxv, siz + } + else if (p[i].p_type == PT_INTERP) + { +- interp = alloca (p[i].p_filesz); +- if (pread64 (memfd, interp, p[i].p_filesz, offset + p[i].p_vaddr) ++ interp = xmalloc (p[i].p_filesz); ++ if (pread (memfd, interp, p[i].p_filesz, offset + p[i].p_vaddr) + != p[i].p_filesz) +- { +- error (0, 0, gettext ("cannot read program interpreter")); +- return EXIT_FAILURE; +- } ++ error (EXIT_FAILURE, 0, gettext ("cannot read program interpreter")); + } + + if (list == 0) +@@ -174,14 +159,16 @@ E(find_maps) (pid_t pid, void *auxv, siz + if (interp == NULL) + { + // XXX check whether the executable itself is the loader +- return EXIT_FAILURE; ++ exit (EXIT_FAILURE); + } + + // XXX perhaps try finding ld.so and _r_debug in it +- +- return EXIT_FAILURE; ++ exit (EXIT_FAILURE); + } + ++ free (p); ++ free (interp); ++ + /* Print the PID and program name first. */ + printf ("%lu:\t%s\n", (unsigned long int) pid, exe); + +@@ -192,47 +179,27 @@ E(find_maps) (pid_t pid, void *auxv, siz + do + { + struct E(link_map) m; +- if (pread64 (memfd, &m, sizeof (m), list) != sizeof (m)) +- { +- error (0, 0, gettext ("cannot read link map")); +- status = EXIT_FAILURE; +- goto out; +- } ++ if (pread (memfd, &m, sizeof (m), list) != sizeof (m)) ++ error (EXIT_FAILURE, 0, gettext ("cannot read link map")); + + EW(Addr) name_offset = m.l_name; +- again: + while (1) + { +- ssize_t n = pread64 (memfd, tmpbuf.data, tmpbuf.length, name_offset); ++ ssize_t n = pread (memfd, tmpbuf.data, tmpbuf.length, name_offset); + if (n == -1) +- { +- error (0, 0, gettext ("cannot read object name")); +- status = EXIT_FAILURE; +- goto out; +- } ++ error (EXIT_FAILURE, 0, gettext ("cannot read object name")); + + if (memchr (tmpbuf.data, '\0', n) != NULL) + break; + + if (!scratch_buffer_grow (&tmpbuf)) +- { +- error (0, 0, gettext ("cannot allocate buffer for object name")); +- status = EXIT_FAILURE; +- goto out; +- } ++ error (EXIT_FAILURE, 0, ++ gettext ("cannot allocate buffer for object name")); + } + +- if (((char *)tmpbuf.data)[0] == '\0' && name_offset == m.l_name +- && m.l_libname != 0) +- { +- /* Try the l_libname element. */ +- struct E(libname_list) ln; +- if (pread64 (memfd, &ln, sizeof (ln), m.l_libname) == sizeof (ln)) +- { +- name_offset = ln.name; +- goto again; +- } +- } ++ /* The m.l_name and m.l_libname.name for loader linkmap points to same ++ values (since BZ#387 fix). Trying to use l_libname name as the ++ shared object name might lead to an infinite loop (BZ#18035). */ + + /* Skip over the executable. */ + if (((char *)tmpbuf.data)[0] != '\0') +@@ -242,7 +209,6 @@ E(find_maps) (pid_t pid, void *auxv, siz + } + while (list != 0); + +- out: + scratch_buffer_free (&tmpbuf); + return status; + } +diff -Nrup a/elf/tst-pldd.c b/elf/tst-pldd.c +--- a/elf/tst-pldd.c 1969-12-31 19:00:00.000000000 -0500 ++++ b/elf/tst-pldd.c 2019-05-17 12:35:45.817147947 -0400 +@@ -0,0 +1,118 @@ ++/* Basic tests for pldd program. ++ 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, see ++ . */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++#include ++#include ++#include ++ ++static void ++target_process (void *arg) ++{ ++ pause (); ++} ++ ++/* The test runs in a container because pldd does not support tracing ++ a binary started by the loader iself (as with testrun.sh). */ ++ ++static int ++do_test (void) ++{ ++ /* Create a copy of current test to check with pldd. */ ++ struct support_subprocess target = support_subprocess (target_process, NULL); ++ ++ /* Run 'pldd' on test subprocess. */ ++ struct support_capture_subprocess pldd; ++ { ++ /* Three digits per byte plus null terminator. */ ++ char pid[3 * sizeof (uint32_t) + 1]; ++ snprintf (pid, array_length (pid), "%d", target.pid); ++ ++ const char prog[] = "/usr/bin/pldd"; ++ ++ pldd = support_capture_subprogram (prog, ++ (char *const []) { (char *) prog, pid, NULL }); ++ ++ support_capture_subprocess_check (&pldd, "pldd", 0, sc_allow_stdout); ++ } ++ ++ /* Check 'pldd' output. The test is expected to be linked against only ++ loader and libc. */ ++ { ++ pid_t pid; ++ char buffer[512]; ++#define STRINPUT(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 (512), &pid, buffer), 2); ++ ++ TEST_COMPARE (pid, target.pid); ++ TEST_COMPARE (strcmp (basename (buffer), "tst-pldd"), 0); ++ ++ /* It expects only one loader and libc loaded by the program. */ ++ bool interpreter_found = false, libc_found = false; ++ while (fgets (buffer, array_length (buffer), out) != NULL) ++ { ++ /* Ignore vDSO. */ ++ if (buffer[0] != '/') ++ continue; ++ ++ /* Remove newline so baseline (buffer) can compare against the ++ LD_SO and LIBC_SO macros unmodified. */ ++ if (buffer[strlen(buffer)-1] == '\n') ++ buffer[strlen(buffer)-1] = '\0'; ++ ++ if (strcmp (basename (buffer), LD_SO) == 0) ++ { ++ TEST_COMPARE (interpreter_found, false); ++ interpreter_found = true; ++ continue; ++ } ++ ++ if (strcmp (basename (buffer), LIBC_SO) == 0) ++ { ++ TEST_COMPARE (libc_found, false); ++ libc_found = true; ++ continue; ++ } ++ } ++ TEST_COMPARE (interpreter_found, true); ++ TEST_COMPARE (libc_found, true); ++ ++ fclose (out); ++ } ++ ++ support_capture_subprocess_free (&pldd); ++ support_process_terminate (&target); ++ ++ return 0; ++} ++ ++#include diff --git a/SOURCES/glibc-rh1704868-1.patch b/SOURCES/glibc-rh1704868-1.patch new file mode 100644 index 0000000..324aaf1 --- /dev/null +++ b/SOURCES/glibc-rh1704868-1.patch @@ -0,0 +1,1365 @@ +commit 91927b7c76437db860cd86a7714476b56bb39d07 +Author: Arjun Shankar +Date: Tue Jul 7 20:31:48 2020 +0200 + + Rewrite iconv option parsing [BZ #19519] + + This commit replaces string manipulation during `iconv_open' and iconv_prog + option parsing with a structured, flag based conversion specification. In + doing so, it alters the internal `__gconv_open' interface and accordingly + adjusts its uses. + + This change fixes several hangs in the iconv program and therefore includes + a new test to exercise iconv_prog options that originally led to these hangs. + It also includes a new regression test for option handling in the iconv + function. + + Reviewed-by: Florian Weimer + Reviewed-by: Siddhesh Poyarekar + Reviewed-by: Carlos O'Donell + +diff --git a/iconv/Makefile b/iconv/Makefile +index d71319b39e772fde..d09b8ac842731780 100644 +--- a/iconv/Makefile ++++ b/iconv/Makefile +@@ -26,7 +26,7 @@ headers = iconv.h gconv.h + routines = iconv_open iconv iconv_close \ + gconv_open gconv gconv_close gconv_db gconv_conf \ + gconv_builtin gconv_simple gconv_trans gconv_cache +-routines += gconv_dl ++routines += gconv_dl gconv_charset + + vpath %.c ../locale/programs ../intl + +@@ -43,7 +43,8 @@ CFLAGS-charmap.c += -DCHARMAP_PATH='"$(i18ndir)/charmaps"' \ + CFLAGS-linereader.c += -DNO_TRANSLITERATION + CFLAGS-simple-hash.c += -I../locale + +-tests = tst-iconv1 tst-iconv2 tst-iconv3 tst-iconv4 tst-iconv5 tst-iconv6 ++tests = tst-iconv1 tst-iconv2 tst-iconv3 tst-iconv4 tst-iconv5 tst-iconv6 \ ++ tst-iconv-opt + + others = iconv_prog iconvconfig + install-others-programs = $(inst_bindir)/iconv +@@ -60,6 +61,7 @@ include $(patsubst %,$(..)libof-iterator.mk,$(cpp-srcs-left)) + + ifeq ($(run-built-tests),yes) + xtests-special += $(objpfx)test-iconvconfig.out ++tests-special += $(objpfx)tst-iconv_prog.out + endif + + # Make a copy of the file because gconv module names are constructed +@@ -78,6 +80,13 @@ endif + + include ../Rules + ++ifeq ($(run-built-tests),yes) ++LOCALES := en_US.UTF-8 ++include ../gen-locales.mk ++ ++$(objpfx)tst-iconv-opt.out: $(gen-locales) ++endif ++ + $(inst_bindir)/iconv: $(objpfx)iconv_prog $(+force) + $(do-install-program) + +@@ -92,3 +101,8 @@ $(objpfx)test-iconvconfig.out: /dev/null $(objpfx)iconvconfig + cmp $$tmp $(inst_gconvdir)/gconv-modules.cache; \ + rm -f $$tmp) > $@; \ + $(evaluate-test) ++ ++$(objpfx)tst-iconv_prog.out: tst-iconv_prog.sh $(objpfx)iconv_prog ++ $(BASH) $< $(common-objdir) '$(test-wrapper-env)' \ ++ '$(run-program-env)' > $@; \ ++ $(evaluate-test) +diff --git a/iconv/Versions b/iconv/Versions +index 60ab10a277588515..8a5f4cf780b18925 100644 +--- a/iconv/Versions ++++ b/iconv/Versions +@@ -6,6 +6,7 @@ libc { + GLIBC_PRIVATE { + # functions shared with iconv program + __gconv_get_alias_db; __gconv_get_cache; __gconv_get_modules_db; ++ __gconv_open; __gconv_create_spec; + + # function used by the gconv modules + __gconv_transliterate; +diff --git a/iconv/gconv_charset.c b/iconv/gconv_charset.c +new file mode 100644 +index 0000000000000000..6ccd0773ccb6cd27 +--- /dev/null ++++ b/iconv/gconv_charset.c +@@ -0,0 +1,218 @@ ++/* Charset name normalization. ++ 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 "gconv_int.h" ++#include "gconv_charset.h" ++ ++ ++/* This function returns a pointer to the last suffix in a conversion code ++ string. Valid suffixes matched by this function are of the form: '/' or ',' ++ followed by arbitrary text that doesn't contain '/' or ','. It does not ++ edit the string in any way. The caller is expected to parse the suffix and ++ remove it (by e.g. truncating the string) before the next call. */ ++static char * ++find_suffix (char *s) ++{ ++ /* The conversion code is in the form of a triplet, separated by '/' chars. ++ The third component of the triplet contains suffixes. If we don't have two ++ slashes, we don't have a suffix. */ ++ ++ int slash_count = 0; ++ char *suffix_term = NULL; ++ ++ for (int i = 0; s[i] != '\0'; i++) ++ switch (s[i]) ++ { ++ case '/': ++ slash_count++; ++ /* Fallthrough */ ++ case ',': ++ suffix_term = &s[i]; ++ } ++ ++ if (slash_count >= 2) ++ return suffix_term; ++ ++ return NULL; ++} ++ ++ ++struct gconv_parsed_code ++{ ++ char *code; ++ bool translit; ++ bool ignore; ++}; ++ ++ ++/* This function parses an iconv_open encoding PC.CODE, strips any suffixes ++ (such as TRANSLIT or IGNORE) from it and sets corresponding flags in it. */ ++static void ++gconv_parse_code (struct gconv_parsed_code *pc) ++{ ++ pc->translit = false; ++ pc->ignore = false; ++ ++ while (1) ++ { ++ /* First drop any trailing whitespaces and separators. */ ++ size_t len = strlen (pc->code); ++ while ((len > 0) ++ && (isspace (pc->code[len - 1]) ++ || pc->code[len - 1] == ',' ++ || pc->code[len - 1] == '/')) ++ len--; ++ ++ pc->code[len] = '\0'; ++ ++ if (len == 0) ++ return; ++ ++ char * suffix = find_suffix (pc->code); ++ if (suffix == NULL) ++ { ++ /* At this point, we have processed and removed all suffixes from the ++ code and what remains of the code is suffix free. */ ++ return; ++ } ++ else ++ { ++ /* A suffix is processed from the end of the code array going ++ backwards, one suffix at a time. The suffix is an index into the ++ code character array and points to: one past the end of the code ++ and any unprocessed suffixes, and to the beginning of the suffix ++ currently being processed during this iteration. We must process ++ this suffix and then drop it from the code by terminating the ++ preceding text with NULL. ++ ++ We want to allow and recognize suffixes such as: ++ ++ "/TRANSLIT" i.e. single suffix ++ "//TRANSLIT" i.e. single suffix and multiple separators ++ "//TRANSLIT/IGNORE" i.e. suffixes separated by "/" ++ "/TRANSLIT//IGNORE" i.e. suffixes separated by "//" ++ "//IGNORE,TRANSLIT" i.e. suffixes separated by "," ++ "//IGNORE," i.e. trailing "," ++ "//TRANSLIT/" i.e. trailing "/" ++ "//TRANSLIT//" i.e. trailing "//" ++ "/" i.e. empty suffix. ++ ++ Unknown suffixes are silently discarded and ignored. */ ++ ++ if ((__strcasecmp_l (suffix, ++ GCONV_TRIPLE_SEPARATOR ++ GCONV_TRANSLIT_SUFFIX, ++ _nl_C_locobj_ptr) == 0) ++ || (__strcasecmp_l (suffix, ++ GCONV_SUFFIX_SEPARATOR ++ GCONV_TRANSLIT_SUFFIX, ++ _nl_C_locobj_ptr) == 0)) ++ pc->translit = true; ++ ++ if ((__strcasecmp_l (suffix, ++ GCONV_TRIPLE_SEPARATOR ++ GCONV_IGNORE_ERRORS_SUFFIX, ++ _nl_C_locobj_ptr) == 0) ++ || (__strcasecmp_l (suffix, ++ GCONV_SUFFIX_SEPARATOR ++ GCONV_IGNORE_ERRORS_SUFFIX, ++ _nl_C_locobj_ptr) == 0)) ++ pc->ignore = true; ++ ++ /* We just processed this suffix. We can now drop it from the ++ code string by truncating it at the suffix's position. */ ++ suffix[0] = '\0'; ++ } ++ } ++} ++ ++ ++/* This function accepts the charset names of the source and destination of the ++ conversion and populates *conv_spec with an equivalent conversion ++ specification that may later be used by __gconv_open. The charset names ++ might contain options in the form of suffixes that alter the conversion, ++ e.g. "ISO-10646/UTF-8/TRANSLIT". It processes the charset names, ignoring ++ and truncating any suffix options in fromcode, and processing and truncating ++ any suffix options in tocode. Supported suffix options ("TRANSLIT" or ++ "IGNORE") when found in tocode lead to the corresponding flag in *conv_spec ++ to be set to true. Unrecognized suffix options are silently discarded. If ++ the function succeeds, it returns conv_spec back to the caller. It returns ++ NULL upon failure. conv_spec must be allocated and freed by the caller. */ ++struct gconv_spec * ++__gconv_create_spec (struct gconv_spec *conv_spec, const char *fromcode, ++ const char *tocode) ++{ ++ struct gconv_parsed_code pfc, ptc; ++ struct gconv_spec *ret = NULL; ++ ++ pfc.code = __strdup (fromcode); ++ ptc.code = __strdup (tocode); ++ ++ if ((pfc.code == NULL) ++ || (ptc.code == NULL)) ++ goto out; ++ ++ gconv_parse_code (&pfc); ++ gconv_parse_code (&ptc); ++ ++ /* We ignore suffixes in the fromcode because that is how the current ++ implementation has always handled them. Only suffixes in the tocode are ++ processed and handled. The reality is that invalid input in the input ++ character set should only be ignored if the fromcode specifies IGNORE. ++ The current implementation ignores invalid intput in the input character ++ set if the tocode contains IGNORE. We preserve this behavior for ++ backwards compatibility. In the future we may split the handling of ++ IGNORE to allow a finer grained specification of ignorning invalid input ++ and/or ignoring invalid output. */ ++ conv_spec->translit = ptc.translit; ++ conv_spec->ignore = ptc.ignore; ++ ++ /* 3 extra bytes because 1 extra for '\0', and 2 extra so strip might ++ be able to add one or two trailing '/' characters if necessary. */ ++ conv_spec->fromcode = malloc (strlen (fromcode) + 3); ++ if (conv_spec->fromcode == NULL) ++ goto out; ++ ++ conv_spec->tocode = malloc (strlen (tocode) + 3); ++ if (conv_spec->tocode == NULL) ++ { ++ free (conv_spec->fromcode); ++ conv_spec->fromcode = NULL; ++ goto out; ++ } ++ ++ /* Strip unrecognized characters and ensure that the code has two '/' ++ characters as per conversion code triplet specification. */ ++ strip (conv_spec->fromcode, pfc.code); ++ strip (conv_spec->tocode, ptc.code); ++ ret = conv_spec; ++ ++out: ++ free (pfc.code); ++ free (ptc.code); ++ ++ return ret; ++} ++libc_hidden_def (__gconv_create_spec) +diff --git a/iconv/gconv_charset.h b/iconv/gconv_charset.h +index 123e2a62cefdc017..b85d80313030b649 100644 +--- a/iconv/gconv_charset.h ++++ b/iconv/gconv_charset.h +@@ -19,9 +19,68 @@ + + #include + #include ++#include ++#include ++#include ++#include ++#include "gconv_int.h" + + +-static void ++/* An iconv encoding is in the form of a triplet, with parts separated by ++ a '/' character. The first part is the standard name, the second part is ++ the character set, and the third part is the error handler. If the first ++ part is sufficient to identify both the standard and the character set ++ then the second part can be empty e.g. UTF-8//. If the first part is not ++ sufficient to identify both the standard and the character set then the ++ second part is required e.g. ISO-10646/UTF8/. If neither the first or ++ second parts are provided e.g. //, then the current locale is used. ++ The actual values used in the first and second parts are not entirely ++ relevant to the implementation. The values themselves are used in a hash ++ table to lookup modules and so the naming convention of the first two parts ++ is somewhat arbitrary and only helps locate the entries in the cache. ++ The third part is the error handler and is comprised of a ',' or '/' ++ separated list of suffixes. Currently, we support "TRANSLIT" for ++ transliteration and "IGNORE" for ignoring conversion errors due to ++ unrecognized input characters. */ ++#define GCONV_TRIPLE_SEPARATOR "/" ++#define GCONV_SUFFIX_SEPARATOR "," ++#define GCONV_TRANSLIT_SUFFIX "TRANSLIT" ++#define GCONV_IGNORE_ERRORS_SUFFIX "IGNORE" ++ ++ ++/* This function accepts the charset names of the source and destination of the ++ conversion and populates *conv_spec with an equivalent conversion ++ specification that may later be used by __gconv_open. The charset names ++ might contain options in the form of suffixes that alter the conversion, ++ e.g. "ISO-10646/UTF-8/TRANSLIT". It processes the charset names, ignoring ++ and truncating any suffix options in fromcode, and processing and truncating ++ any suffix options in tocode. Supported suffix options ("TRANSLIT" or ++ "IGNORE") when found in tocode lead to the corresponding flag in *conv_spec ++ to be set to true. Unrecognized suffix options are silently discarded. If ++ the function succeeds, it returns conv_spec back to the caller. It returns ++ NULL upon failure. */ ++struct gconv_spec * ++__gconv_create_spec (struct gconv_spec *conv_spec, const char *fromcode, ++ const char *tocode); ++libc_hidden_proto (__gconv_create_spec) ++ ++ ++/* This function frees all heap memory allocated by __gconv_create_spec. */ ++static void __attribute__ ((unused)) ++gconv_destroy_spec (struct gconv_spec *conv_spec) ++{ ++ free (conv_spec->fromcode); ++ free (conv_spec->tocode); ++ return; ++} ++ ++ ++/* This function copies in-order, characters from the source 's' that are ++ either alpha-numeric or one in one of these: "_-.,:/" - into the destination ++ 'wp' while dropping all other characters. In the process, it converts all ++ alphabetical characters to upper case. It then appends up to two '/' ++ characters so that the total number of '/'es in the destination is 2. */ ++static inline void __attribute__ ((unused, always_inline)) + strip (char *wp, const char *s) + { + int slash_count = 0; +diff --git a/iconv/gconv_int.h b/iconv/gconv_int.h +index 3742557caed05c9a..4748e9b1fa3b5426 100644 +--- a/iconv/gconv_int.h ++++ b/iconv/gconv_int.h +@@ -92,6 +92,15 @@ struct gconv_module + }; + + ++/* The specification of the conversion that needs to be performed. */ ++struct gconv_spec ++{ ++ char *fromcode; ++ char *tocode; ++ bool translit; ++ bool ignore; ++}; ++ + /* Flags for `gconv_open'. */ + enum + { +@@ -154,10 +163,12 @@ __libc_lock_define (extern, __gconv_lock attribute_hidden) + }) + + +-/* Return in *HANDLE decriptor for transformation from FROMSET to TOSET. */ +-extern int __gconv_open (const char *toset, const char *fromset, +- __gconv_t *handle, int flags) +- attribute_hidden; ++/* Return in *HANDLE, a decriptor for the transformation. The function expects ++ the specification of the transformation in the structure pointed to by ++ CONV_SPEC. It only reads *CONV_SPEC and does not take ownership of it. */ ++extern int __gconv_open (struct gconv_spec *conv_spec, ++ __gconv_t *handle, int flags); ++libc_hidden_proto (__gconv_open) + + /* Free resources associated with transformation descriptor CD. */ + extern int __gconv_close (__gconv_t cd) +diff --git a/iconv/gconv_open.c b/iconv/gconv_open.c +index f739561f6edba8a8..002faa111a0b9016 100644 +--- a/iconv/gconv_open.c ++++ b/iconv/gconv_open.c +@@ -27,7 +27,7 @@ + + + int +-__gconv_open (const char *toset, const char *fromset, __gconv_t *handle, ++__gconv_open (struct gconv_spec *conv_spec, __gconv_t *handle, + int flags) + { + struct __gconv_step *steps; +@@ -36,77 +36,38 @@ __gconv_open (const char *toset, const char *fromset, __gconv_t *handle, + size_t cnt = 0; + int res; + int conv_flags = 0; +- const char *errhand; +- const char *ignore; + bool translit = false; ++ char *tocode, *fromcode; + + /* Find out whether any error handling method is specified. */ +- errhand = strchr (toset, '/'); +- if (errhand != NULL) +- errhand = strchr (errhand + 1, '/'); +- if (__glibc_likely (errhand != NULL)) +- { +- if (*++errhand == '\0') +- errhand = NULL; +- else +- { +- /* Make copy without the error handling description. */ +- char *newtoset = (char *) alloca (errhand - toset + 1); +- char *tok; +- char *ptr = NULL /* Work around a bogus warning */; +- +- newtoset[errhand - toset] = '\0'; +- toset = memcpy (newtoset, toset, errhand - toset); ++ translit = conv_spec->translit; + +- /* Find the appropriate transliteration handlers. */ +- tok = strdupa (errhand); ++ if (conv_spec->ignore) ++ conv_flags |= __GCONV_IGNORE_ERRORS; + +- tok = __strtok_r (tok, ",", &ptr); +- while (tok != NULL) +- { +- if (__strcasecmp_l (tok, "TRANSLIT", _nl_C_locobj_ptr) == 0) +- translit = true; +- else if (__strcasecmp_l (tok, "IGNORE", _nl_C_locobj_ptr) == 0) +- /* Set the flag to ignore all errors. */ +- conv_flags |= __GCONV_IGNORE_ERRORS; +- +- tok = __strtok_r (NULL, ",", &ptr); +- } +- } +- } +- +- /* For the source character set we ignore the error handler specification. +- XXX Is this really always the best? */ +- ignore = strchr (fromset, '/'); +- if (ignore != NULL && (ignore = strchr (ignore + 1, '/')) != NULL +- && *++ignore != '\0') +- { +- char *newfromset = (char *) alloca (ignore - fromset + 1); +- +- newfromset[ignore - fromset] = '\0'; +- fromset = memcpy (newfromset, fromset, ignore - fromset); +- } ++ tocode = conv_spec->tocode; ++ fromcode = conv_spec->fromcode; + + /* If the string is empty define this to mean the charset of the + currently selected locale. */ +- if (strcmp (toset, "//") == 0) ++ if (strcmp (tocode, "//") == 0) + { + const char *codeset = _NL_CURRENT (LC_CTYPE, CODESET); + size_t len = strlen (codeset); + char *dest; +- toset = dest = (char *) alloca (len + 3); ++ tocode = dest = (char *) alloca (len + 3); + memcpy (__mempcpy (dest, codeset, len), "//", 3); + } +- if (strcmp (fromset, "//") == 0) ++ if (strcmp (fromcode, "//") == 0) + { + const char *codeset = _NL_CURRENT (LC_CTYPE, CODESET); + size_t len = strlen (codeset); + char *dest; +- fromset = dest = (char *) alloca (len + 3); ++ fromcode = dest = (char *) alloca (len + 3); + memcpy (__mempcpy (dest, codeset, len), "//", 3); + } + +- res = __gconv_find_transform (toset, fromset, &steps, &nsteps, flags); ++ res = __gconv_find_transform (tocode, fromcode, &steps, &nsteps, flags); + if (res == __GCONV_OK) + { + /* Allocate room for handle. */ +@@ -205,3 +166,4 @@ __gconv_open (const char *toset, const char *fromset, __gconv_t *handle, + *handle = result; + return res; + } ++libc_hidden_def (__gconv_open) +diff --git a/iconv/iconv_open.c b/iconv/iconv_open.c +index 9f5c32c02096254a..59d1ef4f07ed1022 100644 +--- a/iconv/iconv_open.c ++++ b/iconv/iconv_open.c +@@ -31,49 +31,15 @@ + iconv_t + iconv_open (const char *tocode, const char *fromcode) + { +- /* Normalize the name. We remove all characters beside alpha-numeric, +- '_', '-', '/', '.', and ':'. */ +- size_t tocode_len = strlen (tocode) + 3; +- char *tocode_conv; +- bool tocode_usealloca = __libc_use_alloca (tocode_len); +- if (tocode_usealloca) +- tocode_conv = (char *) alloca (tocode_len); +- else +- { +- tocode_conv = (char *) malloc (tocode_len); +- if (tocode_conv == NULL) +- return (iconv_t) -1; +- } +- strip (tocode_conv, tocode); +- tocode = (tocode_conv[2] == '\0' && tocode[0] != '\0' +- ? upstr (tocode_conv, tocode) : tocode_conv); ++ __gconv_t cd; ++ struct gconv_spec conv_spec; + +- size_t fromcode_len = strlen (fromcode) + 3; +- char *fromcode_conv; +- bool fromcode_usealloca = __libc_use_alloca (fromcode_len); +- if (fromcode_usealloca) +- fromcode_conv = (char *) alloca (fromcode_len); +- else +- { +- fromcode_conv = (char *) malloc (fromcode_len); +- if (fromcode_conv == NULL) +- { +- if (! tocode_usealloca) +- free (tocode_conv); +- return (iconv_t) -1; +- } +- } +- strip (fromcode_conv, fromcode); +- fromcode = (fromcode_conv[2] == '\0' && fromcode[0] != '\0' +- ? upstr (fromcode_conv, fromcode) : fromcode_conv); ++ if (__gconv_create_spec (&conv_spec, fromcode, tocode) == NULL) ++ return (iconv_t) -1; + +- __gconv_t cd; +- int res = __gconv_open (tocode, fromcode, &cd, 0); ++ int res = __gconv_open (&conv_spec, &cd, 0); + +- if (! fromcode_usealloca) +- free (fromcode_conv); +- if (! tocode_usealloca) +- free (tocode_conv); ++ gconv_destroy_spec (&conv_spec); + + if (__builtin_expect (res, __GCONV_OK) != __GCONV_OK) + { +diff --git a/iconv/iconv_prog.c b/iconv/iconv_prog.c +index 52e9d3f3ddec3b2e..552efac81660e82a 100644 +--- a/iconv/iconv_prog.c ++++ b/iconv/iconv_prog.c +@@ -39,6 +39,7 @@ + #include + #include "iconv_prog.h" + #include "iconvconfig.h" ++#include "gconv_charset.h" + + /* Get libc version number. */ + #include "../version.h" +@@ -118,8 +119,7 @@ main (int argc, char *argv[]) + { + int status = EXIT_SUCCESS; + int remaining; +- iconv_t cd; +- const char *orig_to_code; ++ __gconv_t cd; + struct charmap_t *from_charmap = NULL; + struct charmap_t *to_charmap = NULL; + +@@ -139,39 +139,6 @@ main (int argc, char *argv[]) + exit (EXIT_SUCCESS); + } + +- /* If we have to ignore errors make sure we use the appropriate name for +- the to-character-set. */ +- orig_to_code = to_code; +- if (omit_invalid) +- { +- const char *errhand = strchrnul (to_code, '/'); +- int nslash = 2; +- char *newp; +- char *cp; +- +- if (*errhand == '/') +- { +- --nslash; +- errhand = strchrnul (errhand + 1, '/'); +- +- if (*errhand == '/') +- { +- --nslash; +- errhand = strchr (errhand, '\0'); +- } +- } +- +- newp = (char *) alloca (errhand - to_code + nslash + 7 + 1); +- cp = mempcpy (newp, to_code, errhand - to_code); +- while (nslash-- > 0) +- *cp++ = '/'; +- if (cp[-1] != '/') +- *cp++ = ','; +- memcpy (cp, "IGNORE", sizeof ("IGNORE")); +- +- to_code = newp; +- } +- + /* POSIX 1003.2b introduces a silly thing: the arguments to -t anf -f + can be file names of charmaps. In this case iconv will have to read + those charmaps and use them to do the conversion. But there are +@@ -184,10 +151,10 @@ main (int argc, char *argv[]) + file. */ + from_charmap = charmap_read (from_code, /*0, 1*/1, 0, 0, 0); + +- if (strchr (orig_to_code, '/') != NULL) ++ if (strchr (to_code, '/') != NULL) + /* The to-name might be a charmap file name. Try reading the + file. */ +- to_charmap = charmap_read (orig_to_code, /*0, 1,*/1, 0, 0, 0); ++ to_charmap = charmap_read (to_code, /*0, 1,*/1, 0, 0, 0); + + + /* At this point we have to handle two cases. The first one is +@@ -201,9 +168,25 @@ main (int argc, char *argv[]) + argc, remaining, argv, output_file); + else + { ++ struct gconv_spec conv_spec; ++ int res; ++ ++ if (__gconv_create_spec (&conv_spec, from_code, to_code) == NULL) ++ { ++ error (EXIT_FAILURE, errno, ++ _("failed to start conversion processing")); ++ exit (1); ++ } ++ ++ if (omit_invalid) ++ conv_spec.ignore = true; ++ + /* Let's see whether we have these coded character sets. */ +- cd = iconv_open (to_code, from_code); +- if (cd == (iconv_t) -1) ++ res = __gconv_open (&conv_spec, &cd, 0); ++ ++ gconv_destroy_spec (&conv_spec); ++ ++ if (res != __GCONV_OK) + { + if (errno == EINVAL) + { +@@ -221,7 +204,7 @@ main (int argc, char *argv[]) + const char *from_pretty = + (from_code[0] ? from_code : nl_langinfo (CODESET)); + const char *to_pretty = +- (orig_to_code[0] ? orig_to_code : nl_langinfo (CODESET)); ++ (to_code[0] ? to_code : nl_langinfo (CODESET)); + + if (from_wrong) + { +diff --git a/iconv/tst-iconv-opt.c b/iconv/tst-iconv-opt.c +new file mode 100644 +index 0000000000000000..669d812a6a9b8749 +--- /dev/null ++++ b/iconv/tst-iconv-opt.c +@@ -0,0 +1,347 @@ ++/* Test iconv's TRANSLIT and IGNORE option handling ++ ++ 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 ++ ++ ++/* Run one iconv test. Arguments: ++ to: destination character set and options ++ from: source character set ++ input: input string to be converted ++ exp_in: expected number of bytes consumed ++ exp_ret: expected return value (error or number of irreversible conversions) ++ exp_out: expected output string ++ exp_err: expected value of `errno' after iconv returns. */ ++static void ++test_iconv (const char *to, const char *from, char *input, size_t exp_in, ++ size_t exp_ret, const char *exp_out, int exp_err) ++{ ++ iconv_t cd; ++ char outbuf[500]; ++ size_t inlen, outlen; ++ char *inptr, *outptr; ++ size_t n; ++ ++ cd = iconv_open (to, from); ++ TEST_VERIFY (cd != (iconv_t) -1); ++ ++ inlen = strlen (input); ++ outlen = sizeof (outbuf); ++ inptr = input; ++ outptr = outbuf; ++ ++ errno = 0; ++ n = iconv (cd, &inptr, &inlen, &outptr, &outlen); ++ ++ TEST_COMPARE (n, exp_ret); ++ TEST_VERIFY (inptr == input + exp_in); ++ TEST_COMPARE (errno, exp_err); ++ TEST_COMPARE_BLOB (outbuf, outptr - outbuf, exp_out, strlen (exp_out)); ++ TEST_VERIFY (iconv_close (cd) == 0); ++} ++ ++ ++/* We test option parsing by converting UTF-8 inputs to ASCII under various ++ option combinations. The UTF-8 inputs fall into three categories: ++ - ASCII-only, ++ - non-ASCII, ++ - non-ASCII with invalid UTF-8 characters. */ ++ ++/* 1. */ ++char ascii[] = "Just some ASCII text"; ++ ++/* 2. Valid UTF-8 input and some corresponding expected outputs with various ++ options. The two non-ASCII characters below are accented alphabets: ++ an `a' then an `o'. */ ++char utf8[] = "UTF-8 text with \u00E1 couple \u00F3f non-ASCII characters"; ++char u2a[] = "UTF-8 text with "; ++char u2a_translit[] = "UTF-8 text with a couple of non-ASCII characters"; ++char u2a_ignore[] = "UTF-8 text with couple f non-ASCII characters"; ++ ++/* 3. Invalid UTF-8 input and some corresponding expected outputs. \xff is ++ invalid UTF-8. It's followed by some valid but non-ASCII UTF-8. */ ++char iutf8[] = "Invalid UTF-8 \xff\u27E6text\u27E7"; ++char iu2a[] = "Invalid UTF-8 "; ++char iu2a_ignore[] = "Invalid UTF-8 text"; ++char iu2a_both[] = "Invalid UTF-8 [|text|]"; ++ ++/* 4. Another invalid UTF-8 input and corresponding expected outputs. This time ++ the valid non-ASCII UTF-8 characters appear before the invalid \xff. */ ++char jutf8[] = "Invalid \u27E6UTF-8\u27E7 \xfftext"; ++char ju2a[] = "Invalid "; ++char ju2a_translit[] = "Invalid [|UTF-8|] "; ++char ju2a_ignore[] = "Invalid UTF-8 text"; ++char ju2a_both[] = "Invalid [|UTF-8|] text"; ++ ++/* We also test option handling for character set names that have the form ++ "A/B". In this test, we test conversions "ISO-10646/UTF-8", and either ++ ISO-8859-1 or ASCII. */ ++ ++/* 5. Accented 'A' and 'a' characters in ISO-8859-1 and UTF-8, and an ++ equivalent ASCII transliteration. */ ++char iso8859_1_a[] = {0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, /* Accented A's. */ ++ 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, /* Accented a's. */ ++ 0x00}; ++char utf8_a[] = "\u00C0\u00C1\u00C2\u00C3\u00C4\u00C5" ++ "\u00E0\u00E1\u00E2\u00E3\u00E4\u00E5"; ++char ascii_a[] = "AAAAAAaaaaaa"; ++ ++/* 6. An invalid ASCII string where [0] is invalid and [1] is '~'. */ ++char iascii [] = {0x80, '~', '\0'}; ++char empty[] = ""; ++char ia2u_ignore[] = "~"; ++ ++static int ++do_test (void) ++{ ++ xsetlocale (LC_ALL, "en_US.UTF-8"); ++ ++ ++ /* 0. iconv_open should gracefully fail for invalid character sets. */ ++ ++ TEST_VERIFY (iconv_open ("INVALID", "UTF-8") == (iconv_t) -1); ++ TEST_VERIFY (iconv_open ("UTF-8", "INVALID") == (iconv_t) -1); ++ TEST_VERIFY (iconv_open ("INVALID", "INVALID") == (iconv_t) -1); ++ ++ ++ /* 1. ASCII-only UTF-8 input should convert to ASCII with no changes: */ ++ ++ test_iconv ("ASCII", "UTF-8", ascii, strlen (ascii), 0, ascii, 0); ++ test_iconv ("ASCII//", "UTF-8", ascii, strlen (ascii), 0, ascii, 0); ++ test_iconv ("ASCII//TRANSLIT", "UTF-8", ascii, strlen (ascii), 0, ascii, 0); ++ test_iconv ("ASCII//TRANSLIT//", "UTF-8", ascii, strlen (ascii), 0, ascii, ++ 0); ++ test_iconv ("ASCII//IGNORE", "UTF-8", ascii, strlen (ascii), 0, ascii, 0); ++ test_iconv ("ASCII//IGNORE//", "UTF-8", ascii, strlen (ascii), 0, ascii, 0); ++ ++ ++ /* 2. Valid UTF-8 input with non-ASCII characters: */ ++ ++ /* EILSEQ when converted to ASCII. */ ++ test_iconv ("ASCII", "UTF-8", utf8, strlen (u2a), (size_t) -1, u2a, EILSEQ); ++ ++ /* Converted without error with TRANSLIT enabled. */ ++ test_iconv ("ASCII//TRANSLIT", "UTF-8", utf8, strlen (utf8), 2, u2a_translit, ++ 0); ++ ++ /* EILSEQ with IGNORE enabled. Non-ASCII chars dropped from output. */ ++ test_iconv ("ASCII//IGNORE", "UTF-8", utf8, strlen (utf8), (size_t) -1, ++ u2a_ignore, EILSEQ); ++ ++ /* With TRANSLIT and IGNORE enabled, transliterated without error. We test ++ four combinations. */ ++ ++ test_iconv ("ASCII//TRANSLIT,IGNORE", "UTF-8", utf8, strlen (utf8), 2, ++ u2a_translit, 0); ++ test_iconv ("ASCII//TRANSLIT//IGNORE", "UTF-8", utf8, strlen (utf8), 2, ++ u2a_translit, 0); ++ test_iconv ("ASCII//IGNORE,TRANSLIT", "UTF-8", utf8, strlen (utf8), 2, ++ u2a_translit, 0); ++ /* Due to bug 19519, iconv was ignoring TRANSLIT for the following input. */ ++ test_iconv ("ASCII//IGNORE//TRANSLIT", "UTF-8", utf8, strlen (utf8), 2, ++ u2a_translit, 0); ++ ++ /* Misspellings of TRANSLIT and IGNORE are ignored, but conversion still ++ works while respecting any other correctly spelled options. */ ++ ++ test_iconv ("ASCII//T", "UTF-8", utf8, strlen (u2a), (size_t) -1, u2a, ++ EILSEQ); ++ test_iconv ("ASCII//TRANSLITERATE", "UTF-8", utf8, strlen (u2a), (size_t) -1, ++ u2a, EILSEQ); ++ test_iconv ("ASCII//I", "UTF-8", utf8, strlen (u2a), (size_t) -1, u2a, ++ EILSEQ); ++ test_iconv ("ASCII//IGNORED", "UTF-8", utf8, strlen (u2a), (size_t) -1, u2a, ++ EILSEQ); ++ test_iconv ("ASCII//TRANSLITERATE//IGNORED", "UTF-8", utf8, strlen (u2a), ++ (size_t) -1, u2a, EILSEQ); ++ test_iconv ("ASCII//IGNORED,TRANSLITERATE", "UTF-8", utf8, strlen (u2a), ++ (size_t) -1, u2a, EILSEQ); ++ test_iconv ("ASCII//T//I", "UTF-8", utf8, strlen (u2a), (size_t) -1, u2a, ++ EILSEQ); ++ ++ test_iconv ("ASCII//TRANSLIT//I", "UTF-8", utf8, strlen (utf8), 2, ++ u2a_translit, 0); ++ /* Due to bug 19519, iconv was ignoring TRANSLIT for the following input. */ ++ test_iconv ("ASCII//I//TRANSLIT", "UTF-8", utf8, strlen (utf8), 2, ++ u2a_translit, 0); ++ test_iconv ("ASCII//IGNORED,TRANSLIT", "UTF-8", utf8, strlen (utf8), 2, ++ u2a_translit, 0); ++ test_iconv ("ASCII//TRANSLIT,IGNORED", "UTF-8", utf8, strlen (utf8), 2, ++ u2a_translit, 0); ++ ++ test_iconv ("ASCII//IGNORE,T", "UTF-8", utf8, strlen (utf8), (size_t) -1, ++ u2a_ignore, EILSEQ); ++ test_iconv ("ASCII//T,IGNORE", "UTF-8", utf8, strlen (utf8), (size_t) -1, ++ u2a_ignore, EILSEQ); ++ /* Due to bug 19519, iconv was ignoring IGNORE for the following input. */ ++ test_iconv ("ASCII//TRANSLITERATE//IGNORE", "UTF-8", utf8, strlen (utf8), ++ (size_t) -1, u2a_ignore, EILSEQ); ++ test_iconv ("ASCII//IGNORE//TRANSLITERATE", "UTF-8", utf8, strlen (utf8), ++ (size_t) -1, u2a_ignore, EILSEQ); ++ ++ ++ /* 3. Invalid UTF-8 followed by some valid non-ASCII UTF-8 characters: */ ++ ++ /* EILSEQ; output is truncated at the first invalid UTF-8 character. */ ++ test_iconv ("ASCII", "UTF-8", iutf8, strlen (iu2a), (size_t) -1, iu2a, ++ EILSEQ); ++ ++ /* With TRANSLIT enabled: EILSEQ; output still truncated at the first invalid ++ UTF-8 character. */ ++ test_iconv ("ASCII//TRANSLIT", "UTF-8", iutf8, strlen (iu2a), (size_t) -1, ++ iu2a, EILSEQ); ++ ++ /* With IGNORE enabled: EILSEQ; output omits invalid UTF-8 characters and ++ valid UTF-8 non-ASCII characters. */ ++ test_iconv ("ASCII//IGNORE", "UTF-8", iutf8, strlen (iutf8), (size_t) -1, ++ iu2a_ignore, EILSEQ); ++ ++ /* With TRANSLIT and IGNORE enabled, output omits only invalid UTF-8 ++ characters and transliterates valid non-ASCII UTF-8 characters. We test ++ four combinations. */ ++ ++ test_iconv ("ASCII//TRANSLIT,IGNORE", "UTF-8", iutf8, strlen (iutf8), 2, ++ iu2a_both, 0); ++ /* Due to bug 19519, iconv was ignoring IGNORE for the following input. */ ++ test_iconv ("ASCII//TRANSLIT//IGNORE", "UTF-8", iutf8, strlen (iutf8), 2, ++ iu2a_both, 0); ++ test_iconv ("ASCII//IGNORE,TRANSLIT", "UTF-8", iutf8, strlen (iutf8), 2, ++ iu2a_both, 0); ++ /* Due to bug 19519, iconv was ignoring TRANSLIT for the following input. */ ++ test_iconv ("ASCII//IGNORE//TRANSLIT", "UTF-8", iutf8, strlen (iutf8), 2, ++ iu2a_both, 0); ++ ++ ++ /* 4. Invalid UTF-8 with valid non-ASCII UTF-8 chars appearing first: */ ++ ++ /* EILSEQ; output is truncated at the first non-ASCII character. */ ++ test_iconv ("ASCII", "UTF-8", jutf8, strlen (ju2a), (size_t) -1, ju2a, ++ EILSEQ); ++ ++ /* With TRANSLIT enabled: EILSEQ; output now truncated at the first invalid ++ UTF-8 character. */ ++ test_iconv ("ASCII//TRANSLIT", "UTF-8", jutf8, strlen (jutf8) - 5, ++ (size_t) -1, ju2a_translit, EILSEQ); ++ test_iconv ("ASCII//translit", "UTF-8", jutf8, strlen (jutf8) - 5, ++ (size_t) -1, ju2a_translit, EILSEQ); ++ ++ /* With IGNORE enabled: EILSEQ; output omits invalid UTF-8 characters and ++ valid UTF-8 non-ASCII characters. */ ++ test_iconv ("ASCII//IGNORE", "UTF-8", jutf8, strlen (jutf8), (size_t) -1, ++ ju2a_ignore, EILSEQ); ++ test_iconv ("ASCII//ignore", "UTF-8", jutf8, strlen (jutf8), (size_t) -1, ++ ju2a_ignore, EILSEQ); ++ ++ /* With TRANSLIT and IGNORE enabled, output omits only invalid UTF-8 ++ characters and transliterates valid non-ASCII UTF-8 characters. We test ++ several combinations. */ ++ ++ test_iconv ("ASCII//TRANSLIT,IGNORE", "UTF-8", jutf8, strlen (jutf8), 2, ++ ju2a_both, 0); ++ /* Due to bug 19519, iconv was ignoring IGNORE for the following input. */ ++ test_iconv ("ASCII//TRANSLIT//IGNORE", "UTF-8", jutf8, strlen (jutf8), 2, ++ ju2a_both, 0); ++ test_iconv ("ASCII//IGNORE,TRANSLIT", "UTF-8", jutf8, strlen (jutf8), 2, ++ ju2a_both, 0); ++ /* Due to bug 19519, iconv was ignoring TRANSLIT for the following input. */ ++ test_iconv ("ASCII//IGNORE//TRANSLIT", "UTF-8", jutf8, strlen (jutf8), 2, ++ ju2a_both, 0); ++ test_iconv ("ASCII//translit,ignore", "UTF-8", jutf8, strlen (jutf8), 2, ++ ju2a_both, 0); ++ /* Trailing whitespace and separators should be ignored. */ ++ test_iconv ("ASCII//IGNORE,TRANSLIT ", "UTF-8", jutf8, strlen (jutf8), 2, ++ ju2a_both, 0); ++ test_iconv ("ASCII//IGNORE,TRANSLIT/", "UTF-8", jutf8, strlen (jutf8), 2, ++ ju2a_both, 0); ++ test_iconv ("ASCII//IGNORE,TRANSLIT//", "UTF-8", jutf8, strlen (jutf8), 2, ++ ju2a_both, 0); ++ test_iconv ("ASCII//IGNORE,TRANSLIT,", "UTF-8", jutf8, strlen (jutf8), 2, ++ ju2a_both, 0); ++ test_iconv ("ASCII//IGNORE,TRANSLIT,,", "UTF-8", jutf8, strlen (jutf8), 2, ++ ju2a_both, 0); ++ test_iconv ("ASCII//IGNORE,TRANSLIT /,", "UTF-8", jutf8, strlen (jutf8), 2, ++ ju2a_both, 0); ++ ++ /* TRANSLIT or IGNORE suffixes in fromcode should be ignored. */ ++ test_iconv ("ASCII", "UTF-8//TRANSLIT", jutf8, strlen (ju2a), (size_t) -1, ++ ju2a, EILSEQ); ++ test_iconv ("ASCII", "UTF-8//IGNORE", jutf8, strlen (ju2a), (size_t) -1, ++ ju2a, EILSEQ); ++ test_iconv ("ASCII", "UTF-8//TRANSLIT,IGNORE", jutf8, strlen (ju2a), ++ (size_t) -1, ju2a, EILSEQ); ++ ++ ++ /* 5. Charset names of the form "A/B/": */ ++ ++ /* ISO-8859-1 is converted to UTF-8 without needing transliteration. */ ++ test_iconv ("ISO-10646/UTF-8", "ISO-8859-1", iso8859_1_a, ++ strlen (iso8859_1_a), 0, utf8_a, 0); ++ test_iconv ("ISO-10646/UTF-8/", "ISO-8859-1", iso8859_1_a, ++ strlen (iso8859_1_a), 0, utf8_a, 0); ++ test_iconv ("ISO-10646/UTF-8/IGNORE", "ISO-8859-1", iso8859_1_a, ++ strlen (iso8859_1_a), 0, utf8_a, 0); ++ test_iconv ("ISO-10646/UTF-8//IGNORE", "ISO-8859-1", iso8859_1_a, ++ strlen (iso8859_1_a), 0, utf8_a, 0); ++ test_iconv ("ISO-10646/UTF-8/TRANSLIT", "ISO-8859-1", iso8859_1_a, ++ strlen (iso8859_1_a), 0, utf8_a, 0); ++ test_iconv ("ISO-10646/UTF-8//TRANSLIT", "ISO-8859-1", iso8859_1_a, ++ strlen (iso8859_1_a), 0, utf8_a, 0); ++ test_iconv ("ISO-10646/UTF-8//TRANSLIT/IGNORE", "ISO-8859-1", iso8859_1_a, ++ strlen (iso8859_1_a), 0, utf8_a, 0); ++ test_iconv ("ISO-10646/UTF-8//TRANSLIT//IGNORE", "ISO-8859-1", iso8859_1_a, ++ strlen (iso8859_1_a), 0, utf8_a, 0); ++ test_iconv ("ISO-10646/UTF-8/TRANSLIT,IGNORE", "ISO-8859-1", iso8859_1_a, ++ strlen (iso8859_1_a), 0, utf8_a, 0); ++ ++ /* UTF-8 with accented A's is converted to ASCII with transliteration. */ ++ test_iconv ("ASCII", "ISO-10646/UTF-8", utf8_a, ++ 0, (size_t) -1, empty, EILSEQ); ++ test_iconv ("ASCII//IGNORE", "ISO-10646/UTF-8", utf8_a, ++ strlen (utf8_a), (size_t) -1, empty, EILSEQ); ++ test_iconv ("ASCII//TRANSLIT", "ISO-10646/UTF-8", utf8_a, ++ strlen (utf8_a), 12, ascii_a, 0); ++ ++ /* Invalid ASCII is converted to UTF-8 only with IGNORE. */ ++ test_iconv ("ISO-10646/UTF-8", "ASCII", iascii, strlen (empty), (size_t) -1, ++ empty, EILSEQ); ++ test_iconv ("ISO-10646/UTF-8/TRANSLIT", "ASCII", iascii, strlen (empty), ++ (size_t) -1, empty, EILSEQ); ++ test_iconv ("ISO-10646/UTF-8/IGNORE", "ASCII", iascii, strlen (iascii), ++ (size_t) -1, ia2u_ignore, EILSEQ); ++ test_iconv ("ISO-10646/UTF-8/TRANSLIT,IGNORE", "ASCII", iascii, ++ strlen (iascii), (size_t) -1, ia2u_ignore, EILSEQ); ++ /* Due to bug 19519, iconv was ignoring IGNORE for the following three ++ inputs: */ ++ test_iconv ("ISO-10646/UTF-8/TRANSLIT/IGNORE", "ASCII", iascii, ++ strlen (iascii), (size_t) -1, ia2u_ignore, EILSEQ); ++ test_iconv ("ISO-10646/UTF-8//TRANSLIT,IGNORE", "ASCII", iascii, ++ strlen (iascii), (size_t) -1, ia2u_ignore, EILSEQ); ++ test_iconv ("ISO-10646/UTF-8//TRANSLIT//IGNORE", "ASCII", iascii, ++ strlen (iascii), (size_t) -1, ia2u_ignore, EILSEQ); ++ ++ return 0; ++} ++ ++#include +diff --git a/iconv/tst-iconv_prog.sh b/iconv/tst-iconv_prog.sh +new file mode 100644 +index 0000000000000000..8298136b7f45d855 +--- /dev/null ++++ b/iconv/tst-iconv_prog.sh +@@ -0,0 +1,280 @@ ++#!/bin/bash ++# Test for some known iconv(1) hangs from bug 19519, and miscellaneous ++# iconv(1) program error conditions. ++# 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 ++# . ++ ++codir=$1 ++test_wrapper_env="$2" ++run_program_env="$3" ++ ++# We have to have some directories in the library path. ++LIBPATH=$codir:$codir/iconvdata ++ ++# How the start the iconv(1) program. $from is not defined/expanded yet. ++ICONV=' ++$codir/elf/ld.so --library-path $LIBPATH --inhibit-rpath ${from}.so ++$codir/iconv/iconv_prog ++' ++ICONV="$test_wrapper_env $run_program_env $ICONV" ++ ++# List of known hangs; ++# Gathered by running an exhaustive 2 byte input search against glibc-2.28 ++hangarray=( ++"\x00\x23;-c;ANSI_X3.110;UTF-8//TRANSLIT//IGNORE" ++"\x00\xa1;-c;ARMSCII-8;UTF-8//TRANSLIT//IGNORE" ++"\x00\xa1;-c;ASMO_449;UTF-8//TRANSLIT//IGNORE" ++"\x00\x81;-c;BIG5;UTF-8//TRANSLIT//IGNORE" ++"\x00\xff;-c;BIG5HKSCS;UTF-8//TRANSLIT//IGNORE" ++"\x00\xff;-c;BRF;UTF-8//TRANSLIT//IGNORE" ++"\x00\xff;-c;BS_4730;UTF-8//TRANSLIT//IGNORE" ++"\x00\x81;-c;CP1250;UTF-8//TRANSLIT//IGNORE" ++"\x00\x98;-c;CP1251;UTF-8//TRANSLIT//IGNORE" ++"\x00\x81;-c;CP1252;UTF-8//TRANSLIT//IGNORE" ++"\x00\x81;-c;CP1253;UTF-8//TRANSLIT//IGNORE" ++"\x00\x81;-c;CP1254;UTF-8//TRANSLIT//IGNORE" ++"\x00\x81;-c;CP1255;UTF-8//TRANSLIT//IGNORE" ++"\x00\x81;-c;CP1257;UTF-8//TRANSLIT//IGNORE" ++"\x00\x81;-c;CP1258;UTF-8//TRANSLIT//IGNORE" ++"\xff\xff;-c;CP932;UTF-8//TRANSLIT//IGNORE" ++"\xff\xff;-c;CSA_Z243.4-1985-1;UTF-8//TRANSLIT//IGNORE" ++"\xff\xff;-c;CSA_Z243.4-1985-2;UTF-8//TRANSLIT//IGNORE" ++"\xff\xff;-c;DEC-MCS;UTF-8//TRANSLIT//IGNORE" ++"\xff\xff;-c;DIN_66003;UTF-8//TRANSLIT//IGNORE" ++"\xff\xff;-c;DS_2089;UTF-8//TRANSLIT//IGNORE" ++"\x00\x41;-c;EBCDIC-AT-DE;UTF-8//TRANSLIT//IGNORE" ++"\x00\x41;-c;EBCDIC-AT-DE-A;UTF-8//TRANSLIT//IGNORE" ++"\x00\x41;-c;EBCDIC-CA-FR;UTF-8//TRANSLIT//IGNORE" ++"\x00\x41;-c;EBCDIC-DK-NO;UTF-8//TRANSLIT//IGNORE" ++"\x00\x41;-c;EBCDIC-DK-NO-A;UTF-8//TRANSLIT//IGNORE" ++"\x00\x41;-c;EBCDIC-ES;UTF-8//TRANSLIT//IGNORE" ++"\x00\x41;-c;EBCDIC-ES-A;UTF-8//TRANSLIT//IGNORE" ++"\x00\x41;-c;EBCDIC-ES-S;UTF-8//TRANSLIT//IGNORE" ++"\x00\x41;-c;EBCDIC-FI-SE;UTF-8//TRANSLIT//IGNORE" ++"\x00\x41;-c;EBCDIC-FI-SE-A;UTF-8//TRANSLIT//IGNORE" ++"\x00\x41;-c;EBCDIC-FR;UTF-8//TRANSLIT//IGNORE" ++"\x00\x41;-c;EBCDIC-IS-FRISS;UTF-8//TRANSLIT//IGNORE" ++"\x00\x41;-c;EBCDIC-IT;UTF-8//TRANSLIT//IGNORE" ++"\x00\x41;-c;EBCDIC-PT;UTF-8//TRANSLIT//IGNORE" ++"\x00\x41;-c;EBCDIC-UK;UTF-8//TRANSLIT//IGNORE" ++"\x00\x41;-c;EBCDIC-US;UTF-8//TRANSLIT//IGNORE" ++"\xff\xff;-c;ES;UTF-8//TRANSLIT//IGNORE" ++"\xff\xff;-c;ES2;UTF-8//TRANSLIT//IGNORE" ++"\xff\xff;-c;EUC-CN;UTF-8//TRANSLIT//IGNORE" ++"\xff\xff;-c;EUC-JISX0213;UTF-8//TRANSLIT//IGNORE" ++"\xff\xff;-c;EUC-JP;UTF-8//TRANSLIT//IGNORE" ++"\xff\xff;-c;EUC-JP-MS;UTF-8//TRANSLIT//IGNORE" ++"\xff\xff;-c;EUC-KR;UTF-8//TRANSLIT//IGNORE" ++"\xff\xff;-c;EUC-TW;UTF-8//TRANSLIT//IGNORE" ++"\xff\xff;-c;GB18030;UTF-8//TRANSLIT//IGNORE" ++"\xff\xff;-c;GB_1988-80;UTF-8//TRANSLIT//IGNORE" ++"\xff\xff;-c;GBK;UTF-8//TRANSLIT//IGNORE" ++"\xff\xff;-c;GOST_19768-74;UTF-8//TRANSLIT//IGNORE" ++"\xff\xff;-c;GREEK7;UTF-8//TRANSLIT//IGNORE" ++"\xff\xff;-c;GREEK7-OLD;UTF-8//TRANSLIT//IGNORE" ++"\xff\xff;-c;GREEK-CCITT;UTF-8//TRANSLIT//IGNORE" ++"\xff\xff;-c;HP-GREEK8;UTF-8//TRANSLIT//IGNORE" ++"\xff\xff;-c;HP-ROMAN8;UTF-8//TRANSLIT//IGNORE" ++"\xff\xff;-c;HP-ROMAN9;UTF-8//TRANSLIT//IGNORE" ++"\xff\xff;-c;HP-THAI8;UTF-8//TRANSLIT//IGNORE" ++"\xff\xff;-c;HP-TURKISH8;UTF-8//TRANSLIT//IGNORE" ++"\x00\x41;-c;IBM038;UTF-8//TRANSLIT//IGNORE" ++"\x00\x80;-c;IBM1004;UTF-8//TRANSLIT//IGNORE" ++"\x00\xff;-c;IBM1008;UTF-8//TRANSLIT//IGNORE" ++"\xff\xff;-c;IBM1046;UTF-8//TRANSLIT//IGNORE" ++"\x00\x51;-c;IBM1132;UTF-8//TRANSLIT//IGNORE" ++"\x00\xa0;-c;IBM1133;UTF-8//TRANSLIT//IGNORE" ++"\x00\xce;-c;IBM1137;UTF-8//TRANSLIT//IGNORE" ++"\x00\x80;-c;IBM1161;UTF-8//TRANSLIT//IGNORE" ++"\x00\xdb;-c;IBM1162;UTF-8//TRANSLIT//IGNORE" ++"\x00\x70;-c;IBM12712;UTF-8//TRANSLIT//IGNORE" ++# These are known hangs that are yet to be fixed: ++# "\x00\x0f;-c;IBM1364;UTF-8" ++# "\x00\x0f;-c;IBM1371;UTF-8" ++# "\x00\x0f;-c;IBM1388;UTF-8" ++# "\x00\x0f;-c;IBM1390;UTF-8" ++# "\x00\x0f;-c;IBM1399;UTF-8" ++"\x00\x53;-c;IBM16804;UTF-8//TRANSLIT//IGNORE" ++"\x00\x41;-c;IBM274;UTF-8//TRANSLIT//IGNORE" ++"\x00\x41;-c;IBM275;UTF-8//TRANSLIT//IGNORE" ++"\x00\x41;-c;IBM281;UTF-8//TRANSLIT//IGNORE" ++"\x00\x57;-c;IBM290;UTF-8//TRANSLIT//IGNORE" ++"\x00\x45;-c;IBM420;UTF-8//TRANSLIT//IGNORE" ++"\x00\x68;-c;IBM423;UTF-8//TRANSLIT//IGNORE" ++"\x00\x70;-c;IBM424;UTF-8//TRANSLIT//IGNORE" ++"\x00\x53;-c;IBM4517;UTF-8//TRANSLIT//IGNORE" ++"\x00\x53;-c;IBM4899;UTF-8//TRANSLIT//IGNORE" ++"\x00\xa5;-c;IBM4909;UTF-8//TRANSLIT//IGNORE" ++"\x00\xdc;-c;IBM4971;UTF-8//TRANSLIT//IGNORE" ++"\x00\x41;-c;IBM803;UTF-8//TRANSLIT//IGNORE" ++"\x00\x91;-c;IBM851;UTF-8//TRANSLIT//IGNORE" ++"\x00\x9b;-c;IBM856;UTF-8//TRANSLIT//IGNORE" ++"\x00\xd5;-c;IBM857;UTF-8//TRANSLIT//IGNORE" ++"\xff\xff;-c;IBM864;UTF-8//TRANSLIT//IGNORE" ++"\x00\x94;-c;IBM868;UTF-8//TRANSLIT//IGNORE" ++"\x00\x94;-c;IBM869;UTF-8//TRANSLIT//IGNORE" ++"\xff\xff;-c;IBM874;UTF-8//TRANSLIT//IGNORE" ++"\x00\x6a;-c;IBM875;UTF-8//TRANSLIT//IGNORE" ++"\x00\x41;-c;IBM880;UTF-8//TRANSLIT//IGNORE" ++"\x00\x80;-c;IBM891;UTF-8//TRANSLIT//IGNORE" ++"\xff\xff;-c;IBM903;UTF-8//TRANSLIT//IGNORE" ++"\xff\xff;-c;IBM904;UTF-8//TRANSLIT//IGNORE" ++"\x00\x41;-c;IBM905;UTF-8//TRANSLIT//IGNORE" ++"\x00\x80;-c;IBM9066;UTF-8//TRANSLIT//IGNORE" ++"\x00\x48;-c;IBM918;UTF-8//TRANSLIT//IGNORE" ++"\x00\x57;-c;IBM930;UTF-8//TRANSLIT//IGNORE" ++"\x00\x80;-c;IBM932;UTF-8//TRANSLIT//IGNORE" ++"\x00\x41;-c;IBM933;UTF-8//TRANSLIT//IGNORE" ++"\x00\x41;-c;IBM935;UTF-8//TRANSLIT//IGNORE" ++"\x00\x41;-c;IBM937;UTF-8//TRANSLIT//IGNORE" ++"\x00\x41;-c;IBM939;UTF-8//TRANSLIT//IGNORE" ++"\x00\x80;-c;IBM943;UTF-8//TRANSLIT//IGNORE" ++"\xff\xff;-c;INIS;UTF-8//TRANSLIT//IGNORE" ++"\xff\xff;-c;INIS-8;UTF-8//TRANSLIT//IGNORE" ++"\xff\xff;-c;INIS-CYRILLIC;UTF-8//TRANSLIT//IGNORE" ++"\x00\xec;-c;ISIRI-3342;UTF-8//TRANSLIT//IGNORE" ++"\x00\xec;-c;ISO_10367-BOX;UTF-8//TRANSLIT//IGNORE" ++"\xff\xff;-c;ISO-2022-CN;UTF-8//TRANSLIT//IGNORE" ++"\xff\xff;-c;ISO-2022-CN-EXT;UTF-8//TRANSLIT//IGNORE" ++"\xff\xff;-c;ISO-2022-JP;UTF-8//TRANSLIT//IGNORE" ++"\xff\xff;-c;ISO-2022-JP-2;UTF-8//TRANSLIT//IGNORE" ++"\xff\xff;-c;ISO-2022-JP-3;UTF-8//TRANSLIT//IGNORE" ++"\xff\xff;-c;ISO-2022-KR;UTF-8//TRANSLIT//IGNORE" ++"\xff\xff;-c;ISO_2033;UTF-8//TRANSLIT//IGNORE" ++"\xff\xff;-c;ISO_5427;UTF-8//TRANSLIT//IGNORE" ++"\xff\xff;-c;ISO_5427-EXT;UTF-8//TRANSLIT//IGNORE" ++"\xff\xff;-c;ISO_5428;UTF-8//TRANSLIT//IGNORE" ++"\x00\xa4;-c;ISO_6937;UTF-8//TRANSLIT//IGNORE" ++"\x00\xa0;-c;ISO_6937-2;UTF-8//TRANSLIT//IGNORE" ++"\xff\xff;-c;ISO-8859-11;UTF-8//TRANSLIT//IGNORE" ++"\x00\xa5;-c;ISO-8859-3;UTF-8//TRANSLIT//IGNORE" ++"\xff\xff;-c;ISO-8859-6;UTF-8//TRANSLIT//IGNORE" ++"\xff\xff;-c;ISO-8859-7;UTF-8//TRANSLIT//IGNORE" ++"\xff\xff;-c;ISO-8859-8;UTF-8//TRANSLIT//IGNORE" ++"\x00\x80;-c;ISO-IR-197;UTF-8//TRANSLIT//IGNORE" ++"\x00\x80;-c;ISO-IR-209;UTF-8//TRANSLIT//IGNORE" ++"\x00\x80;-c;IT;UTF-8//TRANSLIT//IGNORE" ++"\x00\x80;-c;JIS_C6220-1969-RO;UTF-8//TRANSLIT//IGNORE" ++"\x00\x80;-c;JIS_C6229-1984-B;UTF-8//TRANSLIT//IGNORE" ++"\x00\x80;-c;JOHAB;UTF-8//TRANSLIT//IGNORE" ++"\x00\x80;-c;JUS_I.B1.002;UTF-8//TRANSLIT//IGNORE" ++"\x00\x80;-c;KOI-8;UTF-8//TRANSLIT//IGNORE" ++"\x00\x88;-c;KOI8-T;UTF-8//TRANSLIT//IGNORE" ++"\xff\xff;-c;KSC5636;UTF-8//TRANSLIT//IGNORE" ++"\xff\xff;-c;LATIN-GREEK;UTF-8//TRANSLIT//IGNORE" ++"\xff\xff;-c;LATIN-GREEK-1;UTF-8//TRANSLIT//IGNORE" ++"\x00\xf6;-c;MAC-IS;UTF-8//TRANSLIT//IGNORE" ++"\xff\xff;-c;MSZ_7795.3;UTF-8//TRANSLIT//IGNORE" ++"\xff\xff;-c;NATS-DANO;UTF-8//TRANSLIT//IGNORE" ++"\xff\xff;-c;NATS-SEFI;UTF-8//TRANSLIT//IGNORE" ++"\xff\xff;-c;NC_NC00-10;UTF-8//TRANSLIT//IGNORE" ++"\xff\xff;-c;NF_Z_62-010;UTF-8//TRANSLIT//IGNORE" ++"\xff\xff;-c;NF_Z_62-010_1973;UTF-8//TRANSLIT//IGNORE" ++"\xff\xff;-c;NS_4551-1;UTF-8//TRANSLIT//IGNORE" ++"\xff\xff;-c;NS_4551-2;UTF-8//TRANSLIT//IGNORE" ++"\xff\xff;-c;PT;UTF-8//TRANSLIT//IGNORE" ++"\xff\xff;-c;PT2;UTF-8//TRANSLIT//IGNORE" ++"\x00\x98;-c;RK1048;UTF-8//TRANSLIT//IGNORE" ++"\x00\x98;-c;SEN_850200_B;UTF-8//TRANSLIT//IGNORE" ++"\x00\x98;-c;SEN_850200_C;UTF-8//TRANSLIT//IGNORE" ++"\x00\x80;-c;Shift_JISX0213;UTF-8//TRANSLIT//IGNORE" ++"\x00\x80;-c;SJIS;UTF-8//TRANSLIT//IGNORE" ++"\x00\x23;-c;T.61-8BIT;UTF-8//TRANSLIT//IGNORE" ++"\xff\xff;-c;TIS-620;UTF-8//TRANSLIT//IGNORE" ++"\xff\xff;-c;TSCII;UTF-8//TRANSLIT//IGNORE" ++"\xff\xff;-c;UHC;UTF-8//TRANSLIT//IGNORE" ++"\x00\xd8;-c;UNICODE;UTF-8//TRANSLIT//IGNORE" ++"\x00\xdc;-c;UTF-16;UTF-8//TRANSLIT//IGNORE" ++"\xdc\x00;-c;UTF-16BE;UTF-8//TRANSLIT//IGNORE" ++"\x00\xdc;-c;UTF-16LE;UTF-8//TRANSLIT//IGNORE" ++"\xff\xff;-c;UTF-7;UTF-8//TRANSLIT//IGNORE" ++"\x00\x81;-c;WIN-SAMI-2;UTF-8//TRANSLIT//IGNORE" ++) ++ ++# List of option combinations that *should* lead to an error ++errorarray=( ++# Converting from/to invalid character sets should cause error ++"\x00\x00;;INVALID;INVALID" ++"\x00\x00;;INVALID;UTF-8" ++"\x00\x00;;UTF-8;INVALID" ++) ++ ++# Requires $twobyte input, $c flag, $from, and $to to be set; sets $ret ++execute_test () ++{ ++ eval PROG=\"$ICONV\" ++ echo -en "$twobyte" \ ++ | timeout -k 4 3 $PROG $c -f $from -t "$to" &>/dev/null ++ ret=$? ++} ++ ++check_hangtest_result () ++{ ++ if [ "$ret" -eq "124" ] || [ "$ret" -eq "137" ]; then # timeout/hang ++ result="HANG" ++ else ++ if [ "$ret" -eq "139" ]; then # segfault ++ result="SEGFAULT" ++ else ++ if [ "$ret" -gt "127" ]; then # unexpected error ++ result="UNEXPECTED" ++ else ++ result="OK" ++ fi ++ fi ++ fi ++ ++ echo -n "$result: from: \"$from\", to: \"$to\"," ++ echo " input \"$twobyte\", flags \"$c\"" ++ ++ if [ "$result" != "OK" ]; then ++ exit 1 ++ fi ++} ++ ++for hangcommand in "${hangarray[@]}"; do ++ twobyte="$(echo "$hangcommand" | cut -d";" -f 1)" ++ c="$(echo "$hangcommand" | cut -d";" -f 2)" ++ from="$(echo "$hangcommand" | cut -d";" -f 3)" ++ to="$(echo "$hangcommand" | cut -d";" -f 4)" ++ execute_test ++ check_hangtest_result ++done ++ ++check_errtest_result () ++{ ++ if [ "$ret" -eq "1" ]; then # we errored out as expected ++ result="PASS" ++ else ++ result="FAIL" ++ fi ++ echo -n "$result: from: \"$from\", to: \"$to\"," ++ echo " input \"$twobyte\", flags \"$c\", return code $ret" ++ ++ if [ "$result" != "PASS" ]; then ++ exit 1 ++ fi ++} ++ ++for errorcommand in "${errorarray[@]}"; do ++ twobyte="$(echo "$errorcommand" | cut -d";" -f 1)" ++ c="$(echo "$errorcommand" | cut -d";" -f 2)" ++ from="$(echo "$errorcommand" | cut -d";" -f 3)" ++ to="$(echo "$errorcommand" | cut -d";" -f 4)" ++ execute_test ++ check_errtest_result ++done +diff --git a/intl/dcigettext.c b/intl/dcigettext.c +index 25f47c5bd3b0ea04..ed48fc8d3e96c7ba 100644 +--- a/intl/dcigettext.c ++++ b/intl/dcigettext.c +@@ -1120,11 +1120,16 @@ _nl_find_msg (struct loaded_l10nfile *domain_file, + outcharset = encoding; + + # ifdef _LIBC +- /* We always want to use transliteration. */ +- outcharset = norm_add_slashes (outcharset, "TRANSLIT"); +- charset = norm_add_slashes (charset, ""); +- int r = __gconv_open (outcharset, charset, &convd->conv, +- GCONV_AVOID_NOCONV); ++ ++ struct gconv_spec conv_spec ++ = { .fromcode = norm_add_slashes (charset, ""), ++ .tocode = norm_add_slashes (outcharset, ""), ++ /* We always want to use transliteration. */ ++ .translit = true, ++ .ignore = false ++ }; ++ int r = __gconv_open (&conv_spec, &convd->conv, ++ GCONV_AVOID_NOCONV); + if (__builtin_expect (r != __GCONV_OK, 0)) + { + /* If the output encoding is the same there is diff --git a/SOURCES/glibc-rh1704868-2.patch b/SOURCES/glibc-rh1704868-2.patch new file mode 100644 index 0000000..50b7ad7 --- /dev/null +++ b/SOURCES/glibc-rh1704868-2.patch @@ -0,0 +1,235 @@ +commit 7d4ec75e111291851620c6aa2c4460647b7fd50d +Author: Arjun Shankar +Date: Fri Sep 25 14:47:06 2020 +0200 + + intl: Handle translation output codesets with suffixes [BZ #26383] + + Commit 91927b7c7643 (Rewrite iconv option parsing [BZ #19519]) did not + handle cases where the output codeset for translations (via the `gettext' + family of functions) might have a caller specified encoding suffix such as + TRANSLIT or IGNORE. This led to a regression where translations did not + work when the codeset had a suffix. + + This commit fixes the above issue by parsing any suffixes passed to + __dcigettext and adds two new test-cases to intl/tst-codeset.c to + verify correct behaviour. The iconv-internal function __gconv_create_spec + and the static iconv-internal function gconv_destroy_spec are now visible + internally within glibc and used in intl/dcigettext.c. + +diff --git a/iconv/Versions b/iconv/Versions +index 8a5f4cf780b18925..d51af52fa34b8793 100644 +--- a/iconv/Versions ++++ b/iconv/Versions +@@ -6,7 +6,9 @@ libc { + GLIBC_PRIVATE { + # functions shared with iconv program + __gconv_get_alias_db; __gconv_get_cache; __gconv_get_modules_db; +- __gconv_open; __gconv_create_spec; ++ ++ # functions used elsewhere in glibc ++ __gconv_open; __gconv_create_spec; __gconv_destroy_spec; + + # function used by the gconv modules + __gconv_transliterate; +diff --git a/iconv/gconv_charset.c b/iconv/gconv_charset.c +index 6ccd0773ccb6cd27..4ba0aa99f5dae7f7 100644 +--- a/iconv/gconv_charset.c ++++ b/iconv/gconv_charset.c +@@ -216,3 +216,13 @@ out: + return ret; + } + libc_hidden_def (__gconv_create_spec) ++ ++ ++void ++__gconv_destroy_spec (struct gconv_spec *conv_spec) ++{ ++ free (conv_spec->fromcode); ++ free (conv_spec->tocode); ++ return; ++} ++libc_hidden_def (__gconv_destroy_spec) +diff --git a/iconv/gconv_charset.h b/iconv/gconv_charset.h +index b85d80313030b649..4b98073389bd8707 100644 +--- a/iconv/gconv_charset.h ++++ b/iconv/gconv_charset.h +@@ -48,33 +48,6 @@ + #define GCONV_IGNORE_ERRORS_SUFFIX "IGNORE" + + +-/* This function accepts the charset names of the source and destination of the +- conversion and populates *conv_spec with an equivalent conversion +- specification that may later be used by __gconv_open. The charset names +- might contain options in the form of suffixes that alter the conversion, +- e.g. "ISO-10646/UTF-8/TRANSLIT". It processes the charset names, ignoring +- and truncating any suffix options in fromcode, and processing and truncating +- any suffix options in tocode. Supported suffix options ("TRANSLIT" or +- "IGNORE") when found in tocode lead to the corresponding flag in *conv_spec +- to be set to true. Unrecognized suffix options are silently discarded. If +- the function succeeds, it returns conv_spec back to the caller. It returns +- NULL upon failure. */ +-struct gconv_spec * +-__gconv_create_spec (struct gconv_spec *conv_spec, const char *fromcode, +- const char *tocode); +-libc_hidden_proto (__gconv_create_spec) +- +- +-/* This function frees all heap memory allocated by __gconv_create_spec. */ +-static void __attribute__ ((unused)) +-gconv_destroy_spec (struct gconv_spec *conv_spec) +-{ +- free (conv_spec->fromcode); +- free (conv_spec->tocode); +- return; +-} +- +- + /* This function copies in-order, characters from the source 's' that are + either alpha-numeric or one in one of these: "_-.,:/" - into the destination + 'wp' while dropping all other characters. In the process, it converts all +diff --git a/iconv/gconv_int.h b/iconv/gconv_int.h +index 4748e9b1fa3b5426..8067a341b0903e1b 100644 +--- a/iconv/gconv_int.h ++++ b/iconv/gconv_int.h +@@ -170,6 +170,27 @@ extern int __gconv_open (struct gconv_spec *conv_spec, + __gconv_t *handle, int flags); + libc_hidden_proto (__gconv_open) + ++/* This function accepts the charset names of the source and destination of the ++ conversion and populates *conv_spec with an equivalent conversion ++ specification that may later be used by __gconv_open. The charset names ++ might contain options in the form of suffixes that alter the conversion, ++ e.g. "ISO-10646/UTF-8/TRANSLIT". It processes the charset names, ignoring ++ and truncating any suffix options in fromcode, and processing and truncating ++ any suffix options in tocode. Supported suffix options ("TRANSLIT" or ++ "IGNORE") when found in tocode lead to the corresponding flag in *conv_spec ++ to be set to true. Unrecognized suffix options are silently discarded. If ++ the function succeeds, it returns conv_spec back to the caller. It returns ++ NULL upon failure. */ ++extern struct gconv_spec * ++__gconv_create_spec (struct gconv_spec *conv_spec, const char *fromcode, ++ const char *tocode); ++libc_hidden_proto (__gconv_create_spec) ++ ++/* This function frees all heap memory allocated by __gconv_create_spec. */ ++extern void ++__gconv_destroy_spec (struct gconv_spec *conv_spec); ++libc_hidden_proto (__gconv_destroy_spec) ++ + /* Free resources associated with transformation descriptor CD. */ + extern int __gconv_close (__gconv_t cd) + attribute_hidden; +diff --git a/iconv/iconv_open.c b/iconv/iconv_open.c +index 59d1ef4f07ed1022..46da33bca6c24af0 100644 +--- a/iconv/iconv_open.c ++++ b/iconv/iconv_open.c +@@ -39,7 +39,7 @@ iconv_open (const char *tocode, const char *fromcode) + + int res = __gconv_open (&conv_spec, &cd, 0); + +- gconv_destroy_spec (&conv_spec); ++ __gconv_destroy_spec (&conv_spec); + + if (__builtin_expect (res, __GCONV_OK) != __GCONV_OK) + { +diff --git a/iconv/iconv_prog.c b/iconv/iconv_prog.c +index 552efac81660e82a..e26e9d02ca4121a7 100644 +--- a/iconv/iconv_prog.c ++++ b/iconv/iconv_prog.c +@@ -184,7 +184,7 @@ main (int argc, char *argv[]) + /* Let's see whether we have these coded character sets. */ + res = __gconv_open (&conv_spec, &cd, 0); + +- gconv_destroy_spec (&conv_spec); ++ __gconv_destroy_spec (&conv_spec); + + if (res != __GCONV_OK) + { +diff --git a/intl/dcigettext.c b/intl/dcigettext.c +index ed48fc8d3e96c7ba..7ebe67b4ac2113e9 100644 +--- a/intl/dcigettext.c ++++ b/intl/dcigettext.c +@@ -1121,15 +1121,18 @@ _nl_find_msg (struct loaded_l10nfile *domain_file, + + # ifdef _LIBC + +- struct gconv_spec conv_spec +- = { .fromcode = norm_add_slashes (charset, ""), +- .tocode = norm_add_slashes (outcharset, ""), +- /* We always want to use transliteration. */ +- .translit = true, +- .ignore = false +- }; ++ struct gconv_spec conv_spec; ++ ++ __gconv_create_spec (&conv_spec, charset, outcharset); ++ ++ /* We always want to use transliteration. */ ++ conv_spec.translit = true; ++ + int r = __gconv_open (&conv_spec, &convd->conv, + GCONV_AVOID_NOCONV); ++ ++ __gconv_destroy_spec (&conv_spec); ++ + if (__builtin_expect (r != __GCONV_OK, 0)) + { + /* If the output encoding is the same there is +diff --git a/intl/tst-codeset.c b/intl/tst-codeset.c +index e71382aeeeca477b..52e4aaa6ffd3afdb 100644 +--- a/intl/tst-codeset.c ++++ b/intl/tst-codeset.c +@@ -22,13 +22,11 @@ + #include + #include + #include ++#include + + static int + do_test (void) + { +- char *s; +- int result = 0; +- + unsetenv ("LANGUAGE"); + unsetenv ("OUTPUT_CHARSET"); + setlocale (LC_ALL, "de_DE.ISO-8859-1"); +@@ -36,25 +34,21 @@ do_test (void) + bindtextdomain ("codeset", OBJPFX "domaindir"); + + /* Here we expect output in ISO-8859-1. */ +- s = gettext ("cheese"); +- if (strcmp (s, "K\344se")) +- { +- printf ("call 1 returned: %s\n", s); +- result = 1; +- } ++ TEST_COMPARE_STRING (gettext ("cheese"), "K\344se"); + ++ /* Here we expect output in UTF-8. */ + bind_textdomain_codeset ("codeset", "UTF-8"); ++ TEST_COMPARE_STRING (gettext ("cheese"), "K\303\244se"); + +- /* Here we expect output in UTF-8. */ +- s = gettext ("cheese"); +- if (strcmp (s, "K\303\244se")) +- { +- printf ("call 2 returned: %s\n", s); +- result = 1; +- } +- +- return result; ++ /* `a with umlaut' is transliterated to `ae'. */ ++ bind_textdomain_codeset ("codeset", "ASCII//TRANSLIT"); ++ TEST_COMPARE_STRING (gettext ("cheese"), "Kaese"); ++ ++ /* Transliteration also works by default even if not set. */ ++ bind_textdomain_codeset ("codeset", "ASCII"); ++ TEST_COMPARE_STRING (gettext ("cheese"), "Kaese"); ++ ++ return 0; + } + +-#define TEST_FUNCTION do_test () +-#include "../test-skeleton.c" ++#include diff --git a/SOURCES/glibc-rh1704868-3.patch b/SOURCES/glibc-rh1704868-3.patch new file mode 100644 index 0000000..c5b79c2 --- /dev/null +++ b/SOURCES/glibc-rh1704868-3.patch @@ -0,0 +1,77 @@ +commit 9a99c682144bdbd40792ebf822fe9264e0376fb5 +Author: Arjun Shankar +Date: Wed Nov 4 12:19:38 2020 +0100 + + iconv: Accept redundant shift sequences in IBM1364 [BZ #26224] + + The IBM1364, IBM1371, IBM1388, IBM1390 and IBM1399 character sets + share converter logic (iconvdata/ibm1364.c) which would reject + redundant shift sequences when processing input in these character + sets. This led to a hang in the iconv program (CVE-2020-27618). + + This commit adjusts the converter to ignore redundant shift sequences + and adds test cases for iconv_prog hangs that would be triggered upon + their rejection. This brings the implementation in line with other + converters that also ignore redundant shift sequences (e.g. IBM930 + etc., fixed in commit 692de4b3960d). + + Reviewed-by: Carlos O'Donell + +diff --git a/iconv/tst-iconv_prog.sh b/iconv/tst-iconv_prog.sh +index 8298136b7f45d855..d8db7b335c1fcca2 100644 +--- a/iconv/tst-iconv_prog.sh ++++ b/iconv/tst-iconv_prog.sh +@@ -102,12 +102,16 @@ hangarray=( + "\x00\x80;-c;IBM1161;UTF-8//TRANSLIT//IGNORE" + "\x00\xdb;-c;IBM1162;UTF-8//TRANSLIT//IGNORE" + "\x00\x70;-c;IBM12712;UTF-8//TRANSLIT//IGNORE" +-# These are known hangs that are yet to be fixed: +-# "\x00\x0f;-c;IBM1364;UTF-8" +-# "\x00\x0f;-c;IBM1371;UTF-8" +-# "\x00\x0f;-c;IBM1388;UTF-8" +-# "\x00\x0f;-c;IBM1390;UTF-8" +-# "\x00\x0f;-c;IBM1399;UTF-8" ++"\x00\x0f;-c;IBM1364;UTF-8" ++"\x0e\x0e;-c;IBM1364;UTF-8" ++"\x00\x0f;-c;IBM1371;UTF-8" ++"\x0e\x0e;-c;IBM1371;UTF-8" ++"\x00\x0f;-c;IBM1388;UTF-8" ++"\x0e\x0e;-c;IBM1388;UTF-8" ++"\x00\x0f;-c;IBM1390;UTF-8" ++"\x0e\x0e;-c;IBM1390;UTF-8" ++"\x00\x0f;-c;IBM1399;UTF-8" ++"\x0e\x0e;-c;IBM1399;UTF-8" + "\x00\x53;-c;IBM16804;UTF-8//TRANSLIT//IGNORE" + "\x00\x41;-c;IBM274;UTF-8//TRANSLIT//IGNORE" + "\x00\x41;-c;IBM275;UTF-8//TRANSLIT//IGNORE" +diff --git a/iconvdata/ibm1364.c b/iconvdata/ibm1364.c +index 517fe60813be0472..ecc3f8ddddbdbc8c 100644 +--- a/iconvdata/ibm1364.c ++++ b/iconvdata/ibm1364.c +@@ -158,24 +158,14 @@ enum + \ + if (__builtin_expect (ch, 0) == SO) \ + { \ +- /* Shift OUT, change to DBCS converter. */ \ +- if (curcs == db) \ +- { \ +- result = __GCONV_ILLEGAL_INPUT; \ +- break; \ +- } \ ++ /* Shift OUT, change to DBCS converter (redundant escape okay). */ \ + curcs = db; \ + ++inptr; \ + continue; \ + } \ + if (__builtin_expect (ch, 0) == SI) \ + { \ +- /* Shift IN, change to SBCS converter. */ \ +- if (curcs == sb) \ +- { \ +- result = __GCONV_ILLEGAL_INPUT; \ +- break; \ +- } \ ++ /* Shift IN, change to SBCS converter (redundant escape okay). */ \ + curcs = sb; \ + ++inptr; \ + continue; \ diff --git a/SOURCES/glibc-rh1704868-4.patch b/SOURCES/glibc-rh1704868-4.patch new file mode 100644 index 0000000..7bfb219 --- /dev/null +++ b/SOURCES/glibc-rh1704868-4.patch @@ -0,0 +1,66 @@ +commit cce35a50c1de0cec5cd1f6c18979ff6ee3ea1dd1 +Author: Arjun Shankar +Date: Mon Nov 11 14:57:23 2019 +0100 + + support: Add xsetlocale function + +diff --git a/support/Makefile b/support/Makefile +index 37d5dcc92a5c6dee..6afaa6836c944398 100644 +--- a/support/Makefile ++++ b/support/Makefile +@@ -148,6 +148,7 @@ libsupport-routines = \ + xrealloc \ + xrecvfrom \ + xsendto \ ++ xsetlocale \ + xsetsockopt \ + xsigaction \ + xsignal \ +diff --git a/support/support.h b/support/support.h +index 61a10c34982134ff..97d142e9b6f68188 100644 +--- a/support/support.h ++++ b/support/support.h +@@ -91,6 +91,7 @@ char *xasprintf (const char *format, ...) + __attribute__ ((format (printf, 1, 2), malloc)); + char *xstrdup (const char *); + char *xstrndup (const char *, size_t); ++char *xsetlocale (int category, const char *locale); + + /* These point to the TOP of the source/build tree, not your (or + support's) subdirectory. */ +diff --git a/support/xsetlocale.c b/support/xsetlocale.c +new file mode 100644 +index 0000000000000000..063ed4b0d63af884 +--- /dev/null ++++ b/support/xsetlocale.c +@@ -0,0 +1,30 @@ ++/* setlocale with error checking. ++ 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, see ++ . */ ++ ++#include ++ ++#include ++ ++char * ++xsetlocale (int category, const char *locale) ++{ ++ char *p = setlocale (category, locale); ++ if (p == NULL) ++ FAIL_EXIT1 ("error: setlocale (%d, \"%s\")\n", category, locale); ++ return p; ++} diff --git a/SOURCES/glibc-rh1704868-5.patch b/SOURCES/glibc-rh1704868-5.patch new file mode 100644 index 0000000..1ffdb97 --- /dev/null +++ b/SOURCES/glibc-rh1704868-5.patch @@ -0,0 +1,35 @@ +The patch (glibc-rh1704868-1.patch) for commit 91927b7c7643 +(Rewrite iconv option parsing) contains a test that depends on +commit 513aaa0d782f (Add Transliterations for Unicode Misc. +Mathematical Symbols-A/B), which is not applied in RHEL-8. This +patch edits the test so as not to depend on the unapplied patch +and its additional transliterations. + +diff --git a/iconv/tst-iconv-opt.c b/iconv/tst-iconv-opt.c +index 669d812a6a9b8749..21e6d887501450a7 100644 +--- a/iconv/tst-iconv-opt.c ++++ b/iconv/tst-iconv-opt.c +@@ -82,18 +82,18 @@ char u2a_ignore[] = "UTF-8 text with couple f non-ASCII characters"; + + /* 3. Invalid UTF-8 input and some corresponding expected outputs. \xff is + invalid UTF-8. It's followed by some valid but non-ASCII UTF-8. */ +-char iutf8[] = "Invalid UTF-8 \xff\u27E6text\u27E7"; ++char iutf8[] = "Invalid UTF-8 \xff\u00B7text\u00B7"; + char iu2a[] = "Invalid UTF-8 "; + char iu2a_ignore[] = "Invalid UTF-8 text"; +-char iu2a_both[] = "Invalid UTF-8 [|text|]"; ++char iu2a_both[] = "Invalid UTF-8 .text."; + + /* 4. Another invalid UTF-8 input and corresponding expected outputs. This time + the valid non-ASCII UTF-8 characters appear before the invalid \xff. */ +-char jutf8[] = "Invalid \u27E6UTF-8\u27E7 \xfftext"; ++char jutf8[] = "Invalid \u00B7UTF-8\u00B7 \xfftext"; + char ju2a[] = "Invalid "; +-char ju2a_translit[] = "Invalid [|UTF-8|] "; ++char ju2a_translit[] = "Invalid .UTF-8. "; + char ju2a_ignore[] = "Invalid UTF-8 text"; +-char ju2a_both[] = "Invalid [|UTF-8|] text"; ++char ju2a_both[] = "Invalid .UTF-8. text"; + + /* We also test option handling for character set names that have the form + "A/B". In this test, we test conversions "ISO-10646/UTF-8", and either diff --git a/SOURCES/glibc-rh1706777.patch b/SOURCES/glibc-rh1706777.patch new file mode 100644 index 0000000..9e64daa --- /dev/null +++ b/SOURCES/glibc-rh1706777.patch @@ -0,0 +1,44 @@ +commit 38b0593e9a862c3b35392a0f5b202696b8116aa3 +Author: Tobias Klauser +Date: Tue Aug 21 17:22:53 2018 +0000 + + Add PF_XDP, AF_XDP and SOL_XDP from Linux 4.18 to bits/socket.h. + + This patch adds the PF_XDP, AF_XDP and SOL_XDP macros from Linux 4.18 to + sysdeps/unix/sysv/linux/bits/socket.h. + + * sysdeps/unix/sysv/linux/bits/socket.h (PF_MAX): Set to 45. + (PF_XDP): New macro. + (AF_XDP): New macro. + (SOL_XDP): New macro. + +diff --git a/sysdeps/unix/sysv/linux/bits/socket.h b/sysdeps/unix/sysv/linux/bits/socket.h +index fa409f0fabc22d33..c3fbb2110296273c 100644 +--- a/sysdeps/unix/sysv/linux/bits/socket.h ++++ b/sysdeps/unix/sysv/linux/bits/socket.h +@@ -85,7 +85,8 @@ typedef __socklen_t socklen_t; + #define PF_KCM 41 /* Kernel Connection Multiplexor. */ + #define PF_QIPCRTR 42 /* Qualcomm IPC Router. */ + #define PF_SMC 43 /* SMC sockets. */ +-#define PF_MAX 44 /* For now.. */ ++#define PF_XDP 44 /* XDP sockets. */ ++#define PF_MAX 45 /* For now.. */ + + /* Address families. */ + #define AF_UNSPEC PF_UNSPEC +@@ -135,6 +136,7 @@ typedef __socklen_t socklen_t; + #define AF_KCM PF_KCM + #define AF_QIPCRTR PF_QIPCRTR + #define AF_SMC PF_SMC ++#define AF_XDP PF_XDP + #define AF_MAX PF_MAX + + /* Socket level values. Others are defined in the appropriate headers. +@@ -164,6 +166,7 @@ typedef __socklen_t socklen_t; + #define SOL_NFC 280 + #define SOL_KCM 281 + #define SOL_TLS 282 ++#define SOL_XDP 283 + + /* Maximum queue length specifiable by listen. */ + #define SOMAXCONN 128 diff --git a/SOURCES/glibc-rh1710478.patch b/SOURCES/glibc-rh1710478.patch new file mode 100644 index 0000000..3546690 --- /dev/null +++ b/SOURCES/glibc-rh1710478.patch @@ -0,0 +1,107 @@ +commit 32ff397533715988c19cbf3675dcbd727ec13e18 +Author: Andreas Schwab +Date: Tue May 14 17:14:59 2019 +0200 + + Fix crash in _IO_wfile_sync (bug 20568) + + When computing the length of the converted part of the stdio buffer, use + the number of consumed wide characters, not the (negative) distance to the + end of the wide buffer. + +Conflicts: + libio/Makefile + (Usual conflict when adding tests due to missing backports.) + +diff --git a/libio/Makefile b/libio/Makefile +index cab0eae946b1f307..cbfaf3832a45fc22 100644 +--- a/libio/Makefile ++++ b/libio/Makefile +@@ -64,7 +64,8 @@ tests = tst_swprintf tst_wprintf tst_swscanf tst_wscanf tst_getwc tst_putwc \ + bug-memstream1 bug-wmemstream1 \ + tst-setvbuf1 tst-popen1 tst-fgetwc bug-wsetpos tst-fseek \ + tst-fwrite-error tst-ftell-partial-wide tst-ftell-active-handler \ +- tst-ftell-append tst-fputws tst-bz22415 tst-fgetc-after-eof ++ tst-ftell-append tst-fputws tst-bz22415 tst-fgetc-after-eof \ ++ tst-wfile-sync + + tests-internal = tst-vtables tst-vtables-interposed tst-readline + +@@ -207,6 +208,7 @@ $(objpfx)tst-ungetwc1.out: $(gen-locales) + $(objpfx)tst-ungetwc2.out: $(gen-locales) + $(objpfx)tst-widetext.out: $(gen-locales) + $(objpfx)tst_wprintf2.out: $(gen-locales) ++$(objpfx)tst-wfile-sync.out: $(gen-locales) + endif + + $(objpfx)test-freopen.out: test-freopen.sh $(objpfx)test-freopen +diff --git a/libio/tst-wfile-sync.c b/libio/tst-wfile-sync.c +new file mode 100644 +index 0000000000000000..618682064da4035c +--- /dev/null ++++ b/libio/tst-wfile-sync.c +@@ -0,0 +1,39 @@ ++/* Test that _IO_wfile_sync does not crash (bug 20568). ++ 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, see ++ . */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++static int ++do_test (void) ++{ ++ TEST_VERIFY_EXIT (setlocale (LC_ALL, "de_DE.UTF-8") != NULL); ++ /* Fill the stdio buffer and advance the read pointer. */ ++ TEST_VERIFY_EXIT (fgetwc (stdin) != WEOF); ++ /* This calls _IO_wfile_sync, it should not crash. */ ++ TEST_VERIFY_EXIT (setvbuf (stdin, NULL, _IONBF, 0) == 0); ++ /* Verify that the external file offset has been synchronized. */ ++ TEST_COMPARE (xlseek (0, 0, SEEK_CUR), 1); ++ ++ return 0; ++} ++ ++#include +diff --git a/libio/tst-wfile-sync.input b/libio/tst-wfile-sync.input +new file mode 100644 +index 0000000000000000..12d0958f7aaa3865 +--- /dev/null ++++ b/libio/tst-wfile-sync.input +@@ -0,0 +1 @@ ++This is a test of _IO_wfile_sync. +diff --git a/libio/wfileops.c b/libio/wfileops.c +index 63cb687652c72ce1..10e7343f8fdb8781 100644 +--- a/libio/wfileops.c ++++ b/libio/wfileops.c +@@ -508,11 +508,12 @@ _IO_wfile_sync (FILE *fp) + generate the wide characters up to the current reading + position. */ + int nread; +- ++ size_t wnread = (fp->_wide_data->_IO_read_ptr ++ - fp->_wide_data->_IO_read_base); + fp->_wide_data->_IO_state = fp->_wide_data->_IO_last_state; + nread = (*cv->__codecvt_do_length) (cv, &fp->_wide_data->_IO_state, + fp->_IO_read_base, +- fp->_IO_read_end, delta); ++ fp->_IO_read_end, wnread); + fp->_IO_read_ptr = fp->_IO_read_base + nread; + delta = -(fp->_IO_read_end - fp->_IO_read_base - nread); + } diff --git a/SOURCES/glibc-rh1710894.patch b/SOURCES/glibc-rh1710894.patch new file mode 100644 index 0000000..790d27a --- /dev/null +++ b/SOURCES/glibc-rh1710894.patch @@ -0,0 +1,310 @@ +commit a9368c34d70cef91ca59b09941f496df11d6b146 +Author: Florian Weimer +Date: Wed May 15 13:51:35 2019 +0200 + + nss: Turn __nss_database_lookup into a compatibility symbol + + The function uses the internal service_user type, so it is not + really usable from the outside of glibc. Rename the function + to __nss_database_lookup2 for internal use, and change + __nss_database_lookup to always indicate failure to the caller. + + __nss_next already was a compatibility symbol. The new + implementation always fails and no longer calls __nss_next2. + + unscd, the alternative nscd implementation, does not use + __nss_database_lookup, so it is not affected by this change. + +DJ - Added 2.30 clause to nss/Versions as RHEL 8 will always be 2.28. + +diff -rup a/grp/initgroups.c b/grp/initgroups.c +--- a/grp/initgroups.c 2019-06-06 17:15:32.184092617 -0400 ++++ b/grp/initgroups.c 2019-06-06 17:16:59.136114679 -0400 +@@ -79,12 +79,12 @@ internal_getgrouplist (const char *user, + + if (__nss_initgroups_database == NULL) + { +- if (__nss_database_lookup ("initgroups", NULL, "", +- &__nss_initgroups_database) < 0) ++ if (__nss_database_lookup2 ("initgroups", NULL, "", ++ &__nss_initgroups_database) < 0) + { + if (__nss_group_database == NULL) +- no_more = __nss_database_lookup ("group", NULL, DEFAULT_CONFIG, +- &__nss_group_database); ++ no_more = __nss_database_lookup2 ("group", NULL, DEFAULT_CONFIG, ++ &__nss_group_database); + + __nss_initgroups_database = __nss_group_database; + } +diff -rup a/nscd/aicache.c b/nscd/aicache.c +--- a/nscd/aicache.c 2018-08-01 01:10:47.000000000 -0400 ++++ b/nscd/aicache.c 2019-06-06 17:16:59.501114771 -0400 +@@ -93,9 +93,9 @@ addhstaiX (struct database_dyn *db, int + int herrno = 0; + + if (hosts_database == NULL) +- no_more = __nss_database_lookup ("hosts", NULL, +- "dns [!UNAVAIL=return] files", +- &hosts_database); ++ no_more = __nss_database_lookup2 ("hosts", NULL, ++ "dns [!UNAVAIL=return] files", ++ &hosts_database); + else + no_more = 0; + nip = hosts_database; +diff -rup a/nscd/initgrcache.c b/nscd/initgrcache.c +--- a/nscd/initgrcache.c 2019-06-06 17:15:32.205092622 -0400 ++++ b/nscd/initgrcache.c 2019-06-06 17:16:59.510114774 -0400 +@@ -88,8 +88,8 @@ addinitgroupsX (struct database_dyn *db, + int no_more; + + if (group_database == NULL) +- no_more = __nss_database_lookup ("group", NULL, DEFAULT_CONFIG, +- &group_database); ++ no_more = __nss_database_lookup2 ("group", NULL, DEFAULT_CONFIG, ++ &group_database); + else + no_more = 0; + nip = group_database; +diff -rup a/nscd/netgroupcache.c b/nscd/netgroupcache.c +--- a/nscd/netgroupcache.c 2019-06-06 17:15:32.151092608 -0400 ++++ b/nscd/netgroupcache.c 2019-06-06 17:16:59.514114775 -0400 +@@ -143,7 +143,7 @@ addgetnetgrentX (struct database_dyn *db + *tofreep = NULL; + + if (netgroup_database == NULL +- && __nss_database_lookup ("netgroup", NULL, NULL, &netgroup_database)) ++ && __nss_database_lookup2 ("netgroup", NULL, NULL, &netgroup_database)) + { + /* No such service. */ + cacheable = do_notfound (db, fd, req, key, &dataset, &total, &timeout, +diff -rup a/nss/Versions b/nss/Versions +--- a/nss/Versions 2018-08-01 01:10:47.000000000 -0400 ++++ b/nss/Versions 2019-06-10 16:59:34.920054974 -0400 +@@ -1,21 +1,26 @@ + libc { + GLIBC_2.0 { +- # functions used in other libraries ++ __nss_configure_lookup; ++ ++ # Functions exported as no-op compat symbols. + __nss_passwd_lookup; __nss_group_lookup; __nss_hosts_lookup; __nss_next; +- __nss_database_lookup; __nss_configure_lookup; ++ __nss_database_lookup; + } + GLIBC_2.2.2 { + __nss_hostname_digits_dots; + } + GLIBC_2.27 { + } ++ GLIBC_2.30 { ++ # Added for rhbz 1710894 ++ } + GLIBC_PRIVATE { + _nss_files_parse_grent; _nss_files_parse_pwent; _nss_files_parse_spent; + __nss_disable_nscd; __nss_lookup_function; _nss_files_parse_sgent; + + __nss_passwd_lookup2; __nss_group_lookup2; __nss_hosts_lookup2; + __nss_services_lookup2; __nss_next2; __nss_lookup; +- __nss_hash; ++ __nss_hash; __nss_database_lookup2; + } + } + +diff -rup a/nss/XXX-lookup.c b/nss/XXX-lookup.c +--- a/nss/XXX-lookup.c 2018-08-01 01:10:47.000000000 -0400 ++++ b/nss/XXX-lookup.c 2019-06-06 17:16:59.562114786 -0400 +@@ -57,8 +57,8 @@ DB_LOOKUP_FCT (service_user **ni, const + void **fctp) + { + if (DATABASE_NAME_SYMBOL == NULL +- && __nss_database_lookup (DATABASE_NAME_STRING, ALTERNATE_NAME_STRING, +- DEFAULT_CONFIG, &DATABASE_NAME_SYMBOL) < 0) ++ && __nss_database_lookup2 (DATABASE_NAME_STRING, ALTERNATE_NAME_STRING, ++ DEFAULT_CONFIG, &DATABASE_NAME_SYMBOL) < 0) + return -1; + + *ni = DATABASE_NAME_SYMBOL; +diff -rup a/nss/compat-lookup.c b/nss/compat-lookup.c +--- a/nss/compat-lookup.c 2018-08-01 01:10:47.000000000 -0400 ++++ b/nss/compat-lookup.c 2019-06-07 22:14:09.057668330 -0400 +@@ -16,11 +16,12 @@ + License along with the GNU C Library; if not, see + . */ + ++#include ++ + #include + #if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_27) + + # include +-# include + + /* On i386, the function calling convention changed from the standard + ABI calling convention to three register parameters in glibc 2.8. +@@ -40,3 +41,31 @@ strong_alias (__nss_passwd_lookup, __nss + compat_symbol (libc, __nss_hosts_lookup, __nss_hosts_lookup, GLIBC_2_0); + + #endif /* SHLIB_COMPAT */ ++ ++ ++#if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_30) ++ ++/* These functions were exported under a non-GLIBC_PRIVATE version, ++ even though it is not usable externally due to the service_user ++ type dependency. */ ++ ++int ++attribute_compat_text_section ++__nss_next (service_user **ni, const char *fct_name, void **fctp, int status, ++ int all_values) ++{ ++ return -1; ++} ++compat_symbol (libc, __nss_next, __nss_next, GLIBC_2_0); ++ ++int ++attribute_compat_text_section ++__nss_database_lookup (const char *database, const char *alternate_name, ++ const char *defconfig, service_user **ni) ++{ ++ *ni = NULL; ++ return -1; ++} ++compat_symbol (libc, __nss_database_lookup, __nss_database_lookup, GLIBC_2_0); ++ ++#endif /* SHLIB_COMPAT */ +diff -rup a/nss/nss_compat/compat-grp.c b/nss/nss_compat/compat-grp.c +--- a/nss/nss_compat/compat-grp.c 2018-08-01 01:10:47.000000000 -0400 ++++ b/nss/nss_compat/compat-grp.c 2019-06-06 17:16:59.618114799 -0400 +@@ -78,7 +78,7 @@ static bool in_blacklist (const char *, + static void + init_nss_interface (void) + { +- if (__nss_database_lookup ("group_compat", NULL, "nis", &ni) >= 0) ++ if (__nss_database_lookup2 ("group_compat", NULL, "nis", &ni) >= 0) + { + nss_setgrent = __nss_lookup_function (ni, "setgrent"); + nss_getgrnam_r = __nss_lookup_function (ni, "getgrnam_r"); +diff -rup a/nss/nss_compat/compat-initgroups.c b/nss/nss_compat/compat-initgroups.c +--- a/nss/nss_compat/compat-initgroups.c 2018-08-01 01:10:47.000000000 -0400 ++++ b/nss/nss_compat/compat-initgroups.c 2019-06-06 17:16:59.646114807 -0400 +@@ -89,7 +89,7 @@ init_nss_interface (void) + + /* Retest. */ + if (ni == NULL +- && __nss_database_lookup ("group_compat", NULL, "nis", &ni) >= 0) ++ && __nss_database_lookup2 ("group_compat", NULL, "nis", &ni) >= 0) + { + nss_initgroups_dyn = __nss_lookup_function (ni, "initgroups_dyn"); + nss_getgrnam_r = __nss_lookup_function (ni, "getgrnam_r"); +diff -rup a/nss/nss_compat/compat-pwd.c b/nss/nss_compat/compat-pwd.c +--- a/nss/nss_compat/compat-pwd.c 2018-08-01 01:10:47.000000000 -0400 ++++ b/nss/nss_compat/compat-pwd.c 2019-06-06 17:16:59.654114809 -0400 +@@ -88,7 +88,7 @@ static bool in_blacklist (const char *, + static void + init_nss_interface (void) + { +- if (__nss_database_lookup ("passwd_compat", NULL, "nis", &ni) >= 0) ++ if (__nss_database_lookup2 ("passwd_compat", NULL, "nis", &ni) >= 0) + { + nss_setpwent = __nss_lookup_function (ni, "setpwent"); + nss_getpwnam_r = __nss_lookup_function (ni, "getpwnam_r"); +diff -rup a/nss/nss_compat/compat-spwd.c b/nss/nss_compat/compat-spwd.c +--- a/nss/nss_compat/compat-spwd.c 2018-08-01 01:10:47.000000000 -0400 ++++ b/nss/nss_compat/compat-spwd.c 2019-06-06 17:16:59.668114812 -0400 +@@ -85,8 +85,8 @@ static bool in_blacklist (const char *, + static void + init_nss_interface (void) + { +- if (__nss_database_lookup ("shadow_compat", "passwd_compat", +- "nis", &ni) >= 0) ++ if (__nss_database_lookup2 ("shadow_compat", "passwd_compat", ++ "nis", &ni) >= 0) + { + nss_setspent = __nss_lookup_function (ni, "setspent"); + nss_getspnam_r = __nss_lookup_function (ni, "getspnam_r"); +diff -rup a/nss/nsswitch.c b/nss/nsswitch.c +--- a/nss/nsswitch.c 2019-06-06 17:15:32.210092623 -0400 ++++ b/nss/nsswitch.c 2019-06-06 17:16:59.672114813 -0400 +@@ -115,8 +115,8 @@ static void (*nscd_init_cb) (size_t, str + /* -1 == database not found + 0 == database entry pointer stored */ + int +-__nss_database_lookup (const char *database, const char *alternate_name, +- const char *defconfig, service_user **ni) ++__nss_database_lookup2 (const char *database, const char *alternate_name, ++ const char *defconfig, service_user **ni) + { + /* Prevent multiple threads to change the service table. */ + __libc_lock_lock (lock); +@@ -185,7 +185,7 @@ __nss_database_lookup (const char *datab + + return *ni != NULL ? 0 : -1; + } +-libc_hidden_def (__nss_database_lookup) ++libc_hidden_def (__nss_database_lookup2) + + + /* -1 == not found +@@ -260,16 +260,6 @@ __nss_next2 (service_user **ni, const ch + } + libc_hidden_def (__nss_next2) + +- +-int +-attribute_compat_text_section +-__nss_next (service_user **ni, const char *fct_name, void **fctp, int status, +- int all_values) +-{ +- return __nss_next2 (ni, fct_name, NULL, fctp, status, all_values); +-} +- +- + int + __nss_configure_lookup (const char *dbname, const char *service_line) + { +@@ -835,7 +825,7 @@ nss_load_all_libraries (const char *serv + { + service_user *ni = NULL; + +- if (__nss_database_lookup (service, NULL, def, &ni) == 0) ++ if (__nss_database_lookup2 (service, NULL, def, &ni) == 0) + while (ni != NULL) + { + nss_load_library (ni); +diff -rup a/nss/nsswitch.h b/nss/nsswitch.h +--- a/nss/nsswitch.h 2018-08-01 01:10:47.000000000 -0400 ++++ b/nss/nsswitch.h 2019-06-06 17:16:59.691114818 -0400 +@@ -125,10 +125,10 @@ extern bool __nss_database_custom[NSS_DB + If there is no configuration for this database in the file, + parse a service list from DEFCONFIG and use that. More + than one function can use the database. */ +-extern int __nss_database_lookup (const char *database, +- const char *alternative_name, +- const char *defconfig, service_user **ni); +-libc_hidden_proto (__nss_database_lookup) ++extern int __nss_database_lookup2 (const char *database, ++ const char *alternative_name, ++ const char *defconfig, service_user **ni); ++libc_hidden_proto (__nss_database_lookup2) + + /* Put first function with name FCT_NAME for SERVICE in FCTP. The + position is remembered in NI. The function returns a value < 0 if +diff -rup a/sysdeps/posix/getaddrinfo.c b/sysdeps/posix/getaddrinfo.c +--- a/sysdeps/posix/getaddrinfo.c 2018-08-01 01:10:47.000000000 -0400 ++++ b/sysdeps/posix/getaddrinfo.c 2019-06-06 17:16:59.724114827 -0400 +@@ -737,9 +737,9 @@ gaih_inet (const char *name, const struc + #endif + + if (__nss_hosts_database == NULL) +- no_more = __nss_database_lookup ("hosts", NULL, +- "dns [!UNAVAIL=return] files", +- &__nss_hosts_database); ++ no_more = __nss_database_lookup2 ("hosts", NULL, ++ "dns [!UNAVAIL=return] files", ++ &__nss_hosts_database); + else + no_more = 0; + nip = __nss_hosts_database; diff --git a/SOURCES/glibc-rh1717438.patch b/SOURCES/glibc-rh1717438.patch new file mode 100644 index 0000000..8bfaec8 --- /dev/null +++ b/SOURCES/glibc-rh1717438.patch @@ -0,0 +1,71 @@ +commit 11b451c8868d8a2b0edc5dfd44fc58d9ee538be0 +Author: Mark Wielaard +Date: Wed May 15 17:14:01 2019 +0200 + + dlfcn: Guard __dlerror_main_freeres with __libc_once_get (once) [BZ# 24476] + + dlerror.c (__dlerror_main_freeres) will try to free resources which only + have been initialized when init () has been called. That function is + called when resources are needed using __libc_once (once, init) where + once is a __libc_once_define (static, once) in the dlerror.c file. + Trying to free those resources if init () hasn't been called will + produce errors under valgrind memcheck. So guard the freeing of those + resources using __libc_once_get (once) and make sure we have a valid + key. Also add a similar guard to __dlerror (). + + * dlfcn/dlerror.c (__dlerror_main_freeres): Guard using + __libc_once_get (once) and static_bug == NULL. + (__dlerror): Check we have a valid key, set result to static_buf + otherwise. + + Reviewed-by: Carlos O'Donell + +diff --git a/dlfcn/dlerror.c b/dlfcn/dlerror.c +index 96bf92533335036b..06732460ea1512cd 100644 +--- a/dlfcn/dlerror.c ++++ b/dlfcn/dlerror.c +@@ -72,9 +72,16 @@ __dlerror (void) + __libc_once (once, init); + + /* Get error string. */ +- result = (struct dl_action_result *) __libc_getspecific (key); +- if (result == NULL) +- result = &last_result; ++ if (static_buf != NULL) ++ result = static_buf; ++ else ++ { ++ /* 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; ++ } + + /* Test whether we already returned the string. */ + if (result->returned != 0) +@@ -230,13 +237,19 @@ free_key_mem (void *mem) + void + __dlerror_main_freeres (void) + { +- void *mem; + /* Free the global memory if used. */ + check_free (&last_result); +- /* Free the TSD memory if used. */ +- mem = __libc_getspecific (key); +- if (mem != NULL) +- free_key_mem (mem); ++ ++ 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)); diff --git a/SOURCES/glibc-rh1722215.patch b/SOURCES/glibc-rh1722215.patch new file mode 100644 index 0000000..cbda401 --- /dev/null +++ b/SOURCES/glibc-rh1722215.patch @@ -0,0 +1,186 @@ +commit 21cc130b78a4db9113fb6695e2b951e697662440 +Author: Dmitry V. Levin +Date: Wed Feb 13 01:20:51 2019 +0000 + + libio: do not attempt to free wide buffers of legacy streams [BZ #24228] + + Commit a601b74d31ca086de38441d316a3dee24c866305 aka glibc-2.23~693 + ("In preparation for fixing BZ#16734, fix failure in misc/tst-error1-mem + when _G_HAVE_MMAP is turned off.") introduced a regression: + _IO_unbuffer_all now invokes _IO_wsetb to free wide buffers of all + files, including legacy standard files which are small statically + allocated objects that do not have wide buffers and the _mode member, + causing memory corruption. + + Another memory corruption in _IO_unbuffer_all happens when -1 + is assigned to the _mode member of legacy standard files that + do not have it. + + [BZ #24228] + * libio/genops.c (_IO_unbuffer_all) + [SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_1)]: Do not attempt to free wide + buffers and access _IO_FILE_complete members of legacy libio streams. + * libio/tst-bz24228.c: New file. + * libio/tst-bz24228.map: Likewise. + * libio/Makefile [build-shared] (tests): Add tst-bz24228. + [build-shared] (generated): Add tst-bz24228.mtrace and + tst-bz24228.check. + [run-built-tests && build-shared] (tests-special): Add + $(objpfx)tst-bz24228-mem.out. + (LDFLAGS-tst-bz24228, tst-bz24228-ENV): New variables. + ($(objpfx)tst-bz24228-mem.out): New rule. + +# Conflicts: +# libio/Makefile + +diff --git a/libio/Makefile b/libio/Makefile +index cbfaf3832a45fc22..314e03d5ce72be2d 100644 +--- a/libio/Makefile ++++ b/libio/Makefile +@@ -73,6 +73,9 @@ ifeq (yes,$(build-shared)) + # Add test-fopenloc only if shared library is enabled since it depends on + # shared localedata objects. + tests += tst-fopenloc ++# Add tst-bz24228 only if shared library is enabled since it can never meet its ++# objective with static linking because the relevant code just is not there. ++tests += tst-bz24228 + endif + test-srcs = test-freopen + +@@ -153,11 +156,14 @@ CFLAGS-oldtmpfile.c += -fexceptions + + CFLAGS-tst_putwc.c += -DOBJPFX=\"$(objpfx)\" + ++LDFLAGS-tst-bz24228 = -Wl,--version-script=tst-bz24228.map ++ + tst_wprintf2-ARGS = "Some Text" + + test-fmemopen-ENV = MALLOC_TRACE=$(objpfx)test-fmemopen.mtrace + tst-fopenloc-ENV = MALLOC_TRACE=$(objpfx)tst-fopenloc.mtrace + tst-bz22415-ENV = MALLOC_TRACE=$(objpfx)tst-bz22415.mtrace ++tst-bz24228-ENV = MALLOC_TRACE=$(objpfx)tst-bz24228.mtrace + + generated += test-fmemopen.mtrace test-fmemopen.check + generated += tst-fopenloc.mtrace tst-fopenloc.check +@@ -166,6 +172,7 @@ generated += tst-bz22415.mtrace tst-bz22415.check + aux := fileops genops stdfiles stdio strops + + ifeq ($(build-shared),yes) ++generated += tst-bz24228.mtrace tst-bz24228.check + aux += oldfileops oldstdfiles + endif + +@@ -180,7 +187,8 @@ tests-special += $(objpfx)test-freopen.out $(objpfx)test-fmemopen-mem.out \ + ifeq (yes,$(build-shared)) + # Run tst-fopenloc-cmp.out and tst-openloc-mem.out only if shared + # library is enabled since they depend on tst-fopenloc.out. +-tests-special += $(objpfx)tst-fopenloc-cmp.out $(objpfx)tst-fopenloc-mem.out ++tests-special += $(objpfx)tst-fopenloc-cmp.out $(objpfx)tst-fopenloc-mem.out \ ++ $(objpfx)tst-bz24228-mem.out + endif + endif + +@@ -232,3 +240,7 @@ $(objpfx)tst-fopenloc-mem.out: $(objpfx)tst-fopenloc.out + $(objpfx)tst-bz22415-mem.out: $(objpfx)tst-bz22415.out + $(common-objpfx)malloc/mtrace $(objpfx)tst-bz22415.mtrace > $@; \ + $(evaluate-test) ++ ++$(objpfx)tst-bz24228-mem.out: $(objpfx)tst-bz24228.out ++ $(common-objpfx)malloc/mtrace $(objpfx)tst-bz24228.mtrace > $@; \ ++ $(evaluate-test) +diff --git a/libio/genops.c b/libio/genops.c +index 2fec221b99729718..a8241dd26640bbcb 100644 +--- a/libio/genops.c ++++ b/libio/genops.c +@@ -789,9 +789,16 @@ _IO_unbuffer_all (void) + + for (fp = (FILE *) _IO_list_all; fp; fp = fp->_chain) + { ++ int legacy = 0; ++ ++#if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_1) ++ if (__glibc_unlikely (_IO_vtable_offset (fp) != 0)) ++ legacy = 1; ++#endif ++ + if (! (fp->_flags & _IO_UNBUFFERED) + /* Iff stream is un-orientated, it wasn't used. */ +- && fp->_mode != 0) ++ && (legacy || fp->_mode != 0)) + { + #ifdef _IO_MTSAFE_IO + int cnt; +@@ -805,7 +812,7 @@ _IO_unbuffer_all (void) + __sched_yield (); + #endif + +- if (! dealloc_buffers && !(fp->_flags & _IO_USER_BUF)) ++ if (! legacy && ! dealloc_buffers && !(fp->_flags & _IO_USER_BUF)) + { + fp->_flags |= _IO_USER_BUF; + +@@ -816,7 +823,7 @@ _IO_unbuffer_all (void) + + _IO_SETBUF (fp, NULL, 0); + +- if (fp->_mode > 0) ++ if (! legacy && fp->_mode > 0) + _IO_wsetb (fp, NULL, NULL, 0); + + #ifdef _IO_MTSAFE_IO +@@ -827,7 +834,8 @@ _IO_unbuffer_all (void) + + /* Make sure that never again the wide char functions can be + used. */ +- fp->_mode = -1; ++ if (! legacy) ++ fp->_mode = -1; + } + + #ifdef _IO_MTSAFE_IO +diff --git a/libio/tst-bz24228.c b/libio/tst-bz24228.c +new file mode 100644 +index 0000000000000000..6a74500d473ceeab +--- /dev/null ++++ b/libio/tst-bz24228.c +@@ -0,0 +1,29 @@ ++/* BZ #24228 check for memory corruption in legacy libio ++ 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, see ++ . */ ++ ++#include ++#include ++ ++static int ++do_test (void) ++{ ++ mtrace (); ++ return 0; ++} ++ ++#include +diff --git a/libio/tst-bz24228.map b/libio/tst-bz24228.map +new file mode 100644 +index 0000000000000000..4383e0817d7f5583 +--- /dev/null ++++ b/libio/tst-bz24228.map +@@ -0,0 +1,5 @@ ++# Hide the symbol from libc.so.6 to switch to the libio/oldfileops.c ++# implementation when it is available for the architecture. ++{ ++ local: _IO_stdin_used; ++}; diff --git a/SOURCES/glibc-rh1724975.patch b/SOURCES/glibc-rh1724975.patch new file mode 100644 index 0000000..7ea3267 --- /dev/null +++ b/SOURCES/glibc-rh1724975.patch @@ -0,0 +1,1013 @@ +commit 5a659ccc0ec217ab02a4c273a1f6d346a359560a +Author: Florian Weimer +Date: Fri Jun 28 09:39:21 2019 +0200 + + io: Remove copy_file_range emulation [BZ #24744] + + The kernel is evolving this interface (e.g., removal of the + restriction on cross-device copies), and keeping up with that + is difficult. Applications which need the function should + run kernels which support the system call instead of relying on + the imperfect glibc emulation. + + Reviewed-by: Adhemerval Zanella + +# Conflicts: +# io/copy_file_range-compat.c +# io/copy_file_range.c +# io/tst-copy_file_range-compat.c +# io/tst-copy_file_range.c +# sysdeps/unix/sysv/linux/arm/kernel-features.h +# sysdeps/unix/sysv/linux/microblaze/kernel-features.h +# sysdeps/unix/sysv/linux/sh/kernel-features.h + +diff --git a/io/Makefile b/io/Makefile +index 787a5c550ab64b17..62e71b4cbe879dbc 100644 +--- a/io/Makefile ++++ b/io/Makefile +@@ -75,11 +75,6 @@ tests := test-utime test-stat test-stat2 test-lfs tst-getcwd \ + tst-fts tst-fts-lfs tst-open-tmpfile \ + tst-copy_file_range tst-getcwd-abspath \ + +-# This test includes the compat implementation of copy_file_range, +-# which uses internal, unexported libc functions. +-tests-static += tst-copy_file_range-compat +-tests-internal += tst-copy_file_range-compat +- + # Likewise for statx, but we do not need static linking here. + tests-internal += tst-statx + +diff --git a/io/copy_file_range-compat.c b/io/copy_file_range-compat.c +deleted file mode 100644 +index 4ab22cad19146ca9..0000000000000000 +--- a/io/copy_file_range-compat.c ++++ /dev/null +@@ -1,160 +0,0 @@ +-/* Emulation of copy_file_range. +- 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 +- . */ +- +-/* The following macros should be defined before including this +- file: +- +- COPY_FILE_RANGE_DECL Declaration specifiers for the function below. +- COPY_FILE_RANGE Name of the function to define. */ +- +-#include +-#include +-#include +-#include +-#include +-#include +-#include +- +-COPY_FILE_RANGE_DECL +-ssize_t +-COPY_FILE_RANGE (int infd, __off64_t *pinoff, +- int outfd, __off64_t *poutoff, +- size_t length, unsigned int flags) +-{ +- if (flags != 0) +- { +- __set_errno (EINVAL); +- return -1; +- } +- +- { +- struct stat64 instat; +- struct stat64 outstat; +- if (fstat64 (infd, &instat) != 0 || fstat64 (outfd, &outstat) != 0) +- return -1; +- if (S_ISDIR (instat.st_mode) || S_ISDIR (outstat.st_mode)) +- { +- __set_errno (EISDIR); +- return -1; +- } +- if (!S_ISREG (instat.st_mode) || !S_ISREG (outstat.st_mode)) +- { +- /* We need a regular input file so that the we can seek +- backwards in case of a write failure. */ +- __set_errno (EINVAL); +- return -1; +- } +- if (instat.st_dev != outstat.st_dev) +- { +- /* Cross-device copies are not supported. */ +- __set_errno (EXDEV); +- return -1; +- } +- } +- +- /* The output descriptor must not have O_APPEND set. */ +- { +- int flags = __fcntl (outfd, F_GETFL); +- if (flags & O_APPEND) +- { +- __set_errno (EBADF); +- return -1; +- } +- } +- +- /* Avoid an overflow in the result. */ +- if (length > SSIZE_MAX) +- length = SSIZE_MAX; +- +- /* Main copying loop. The buffer size is arbitrary and is a +- trade-off between stack size consumption, cache usage, and +- amortization of system call overhead. */ +- size_t copied = 0; +- char buf[8192]; +- while (length > 0) +- { +- size_t to_read = length; +- if (to_read > sizeof (buf)) +- to_read = sizeof (buf); +- +- /* Fill the buffer. */ +- ssize_t read_count; +- if (pinoff == NULL) +- read_count = read (infd, buf, to_read); +- else +- read_count = __libc_pread64 (infd, buf, to_read, *pinoff); +- if (read_count == 0) +- /* End of file reached prematurely. */ +- return copied; +- if (read_count < 0) +- { +- if (copied > 0) +- /* Report the number of bytes copied so far. */ +- return copied; +- return -1; +- } +- if (pinoff != NULL) +- *pinoff += read_count; +- +- /* Write the buffer part which was read to the destination. */ +- char *end = buf + read_count; +- for (char *p = buf; p < end; ) +- { +- ssize_t write_count; +- if (poutoff == NULL) +- write_count = write (outfd, p, end - p); +- else +- write_count = __libc_pwrite64 (outfd, p, end - p, *poutoff); +- if (write_count < 0) +- { +- /* Adjust the input read position to match what we have +- written, so that the caller can pick up after the +- error. */ +- size_t written = p - buf; +- /* NB: This needs to be signed so that we can form the +- negative value below. */ +- ssize_t overread = read_count - written; +- if (pinoff == NULL) +- { +- if (overread > 0) +- { +- /* We are on an error recovery path, so we +- cannot deal with failure here. */ +- int save_errno = errno; +- (void) __libc_lseek64 (infd, -overread, SEEK_CUR); +- __set_errno (save_errno); +- } +- } +- else /* pinoff != NULL */ +- *pinoff -= overread; +- +- if (copied + written > 0) +- /* Report the number of bytes copied so far. */ +- return copied + written; +- return -1; +- } +- p += write_count; +- if (poutoff != NULL) +- *poutoff += write_count; +- } /* Write loop. */ +- +- copied += read_count; +- length -= read_count; +- } +- return copied; +-} +diff --git a/io/copy_file_range.c b/io/copy_file_range.c +index 98bff8bd2615b214..59fb979773b2b202 100644 +--- a/io/copy_file_range.c ++++ b/io/copy_file_range.c +@@ -1,5 +1,5 @@ +-/* Generic implementation of copy_file_range. +- Copyright (C) 2017-2018 Free Software Foundation, Inc. ++/* Stub implementation of copy_file_range. ++ Copyright (C) 2017-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 +@@ -16,7 +16,15 @@ + License along with the GNU C Library; if not, see + . */ + +-#define COPY_FILE_RANGE_DECL +-#define COPY_FILE_RANGE copy_file_range ++#include ++#include + +-#include ++ssize_t ++copy_file_range (int infd, __off64_t *pinoff, ++ int outfd, __off64_t *poutoff, ++ size_t length, unsigned int flags) ++{ ++ __set_errno (ENOSYS); ++ return -1; ++} ++stub_warning (copy_file_range) +diff --git a/io/tst-copy_file_range-compat.c b/io/tst-copy_file_range-compat.c +deleted file mode 100644 +index 00c109a74d3c9d64..0000000000000000 +--- a/io/tst-copy_file_range-compat.c ++++ /dev/null +@@ -1,30 +0,0 @@ +-/* Test the fallback implementation of copy_file_range. +- 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 +- . */ +- +-/* Get the declaration of the official copy_of_range function. */ +-#include +- +-/* Compile a local version of copy_file_range. */ +-#define COPY_FILE_RANGE_DECL static +-#define COPY_FILE_RANGE copy_file_range_compat +-#include +- +-/* Re-use the test, but run it against copy_file_range_compat defined +- above. */ +-#define copy_file_range copy_file_range_compat +-#include "tst-copy_file_range.c" +diff --git a/io/tst-copy_file_range.c b/io/tst-copy_file_range.c +index 3d531a19370911e5..4504020d2ee7d2ee 100644 +--- a/io/tst-copy_file_range.c ++++ b/io/tst-copy_file_range.c +@@ -20,22 +20,15 @@ + #include + #include + #include +-#include +-#include +-#include + #include + #include + #include + #include + #include +-#include + #include + #include + #include + #include +-#ifdef CLONE_NEWNS +-# include +-#endif + + /* Boolean flags which indicate whether to use pointers with explicit + output flags. */ +@@ -49,10 +42,6 @@ static int infd; + static char *outfile; + static int outfd; + +-/* Like the above, but on a different file system. xdevfile can be +- NULL if no suitable file system has been found. */ +-static char *xdevfile; +- + /* Input and output offsets. Set according to do_inoff and do_outoff + before the test. The offsets themselves are always set to + zero. */ +@@ -61,13 +50,10 @@ static off64_t *pinoff; + static off64_t outoff; + static off64_t *poutoff; + +-/* These are a collection of copy sizes used in tests. The selection +- takes into account that the fallback implementation uses an +- internal buffer of 8192 bytes. */ ++/* These are a collection of copy sizes used in tests. */ + enum { maximum_size = 99999 }; + static const int typical_sizes[] = +- { 0, 1, 2, 3, 1024, 2048, 4096, 8191, 8192, 8193, 16383, 16384, 16385, +- maximum_size }; ++ { 0, 1, 2, 3, 1024, 2048, 4096, 8191, 8192, 8193, maximum_size }; + + /* The random contents of this array can be used as a pattern to check + for correct write operations. */ +@@ -76,101 +62,6 @@ static unsigned char random_data[maximum_size]; + /* The size chosen by the test harness. */ + static int current_size; + +-/* Maximum writable file offset. Updated by find_maximum_offset +- below. */ +-static off64_t maximum_offset; +- +-/* Error code when crossing the offset. */ +-static int maximum_offset_errno; +- +-/* If true: Writes which cross the limit will fail. If false: Writes +- which cross the limit will result in a partial write. */ +-static bool maximum_offset_hard_limit; +- +-/* Fills maximum_offset etc. above. Truncates outfd as a side +- effect. */ +-static void +-find_maximum_offset (void) +-{ +- xftruncate (outfd, 0); +- if (maximum_offset != 0) +- return; +- +- uint64_t upper = -1; +- upper >>= 1; /* Maximum of off64_t. */ +- TEST_VERIFY ((off64_t) upper > 0); +- TEST_VERIFY ((off64_t) (upper + 1) < 0); +- if (lseek64 (outfd, upper, SEEK_SET) >= 0) +- { +- if (write (outfd, "", 1) == 1) +- FAIL_EXIT1 ("created a file larger than the off64_t range"); +- } +- +- uint64_t lower = 1024 * 1024; /* A reasonable minimum file size. */ +- /* Loop invariant: writing at lower succeeds, writing at upper fails. */ +- while (lower + 1 < upper) +- { +- uint64_t middle = (lower + upper) / 2; +- if (test_verbose > 0) +- printf ("info: %s: remaining test range %" PRIu64 " .. %" PRIu64 +- ", probe at %" PRIu64 "\n", __func__, lower, upper, middle); +- xftruncate (outfd, 0); +- if (lseek64 (outfd, middle, SEEK_SET) >= 0 +- && write (outfd, "", 1) == 1) +- lower = middle; +- else +- upper = middle; +- } +- TEST_VERIFY (lower + 1 == upper); +- maximum_offset = lower; +- printf ("info: maximum writable file offset: %" PRIu64 " (%" PRIx64 ")\n", +- lower, lower); +- +- /* Check that writing at the valid offset actually works. */ +- xftruncate (outfd, 0); +- xlseek (outfd, lower, SEEK_SET); +- TEST_COMPARE (write (outfd, "", 1), 1); +- +- /* Cross the boundary with a two-byte write. This can either result +- in a short write, or a failure. */ +- xlseek (outfd, lower, SEEK_SET); +- ssize_t ret = write (outfd, " ", 2); +- if (ret < 0) +- { +- maximum_offset_errno = errno; +- maximum_offset_hard_limit = true; +- } +- else +- maximum_offset_hard_limit = false; +- +- /* Check that writing at the next offset actually fails. This also +- obtains the expected errno value. */ +- xftruncate (outfd, 0); +- const char *action; +- if (lseek64 (outfd, lower + 1, SEEK_SET) != 0) +- { +- if (write (outfd, "", 1) != -1) +- FAIL_EXIT1 ("write to impossible offset %" PRIu64 " succeeded", +- lower + 1); +- action = "writing"; +- int errno_copy = errno; +- if (maximum_offset_hard_limit) +- TEST_COMPARE (errno_copy, maximum_offset_errno); +- else +- maximum_offset_errno = errno_copy; +- } +- else +- { +- action = "seeking"; +- maximum_offset_errno = errno; +- } +- printf ("info: %s out of range fails with %m (%d)\n", +- action, maximum_offset_errno); +- +- xftruncate (outfd, 0); +- xlseek (outfd, 0, SEEK_SET); +-} +- + /* Perform a copy of a file. */ + static void + simple_file_copy (void) +@@ -247,390 +138,6 @@ simple_file_copy (void) + free (bytes); + } + +-/* Test that reading from a pipe willfails. */ +-static void +-pipe_as_source (void) +-{ +- int pipefds[2]; +- xpipe (pipefds); +- +- for (int length = 0; length < 2; ++length) +- { +- if (test_verbose > 0) +- printf ("info: %s: length=%d\n", __func__, length); +- +- /* Make sure that there is something to copy in the pipe. */ +- xwrite (pipefds[1], "@", 1); +- +- TEST_COMPARE (copy_file_range (pipefds[0], pinoff, outfd, poutoff, +- length, 0), -1); +- /* Linux 4.10 and later return EINVAL. Older kernels return +- EXDEV. */ +- TEST_VERIFY (errno == EINVAL || errno == EXDEV); +- TEST_COMPARE (inoff, 0); +- TEST_COMPARE (outoff, 0); +- TEST_COMPARE (xlseek (outfd, 0, SEEK_CUR), 0); +- +- /* Make sure that nothing was read. */ +- char buf = 'A'; +- TEST_COMPARE (read (pipefds[0], &buf, 1), 1); +- TEST_COMPARE (buf, '@'); +- } +- +- xclose (pipefds[0]); +- xclose (pipefds[1]); +-} +- +-/* Test that writing to a pipe fails. */ +-static void +-pipe_as_destination (void) +-{ +- /* Make sure that there is something to read in the input file. */ +- xwrite (infd, "abc", 3); +- xlseek (infd, 0, SEEK_SET); +- +- int pipefds[2]; +- xpipe (pipefds); +- +- for (int length = 0; length < 2; ++length) +- { +- if (test_verbose > 0) +- printf ("info: %s: length=%d\n", __func__, length); +- +- TEST_COMPARE (copy_file_range (infd, pinoff, pipefds[1], poutoff, +- length, 0), -1); +- /* Linux 4.10 and later return EINVAL. Older kernels return +- EXDEV. */ +- TEST_VERIFY (errno == EINVAL || errno == EXDEV); +- TEST_COMPARE (inoff, 0); +- TEST_COMPARE (outoff, 0); +- TEST_COMPARE (xlseek (infd, 0, SEEK_CUR), 0); +- +- /* Make sure that nothing was written. */ +- struct pollfd pollfd = { .fd = pipefds[0], .events = POLLIN, }; +- TEST_COMPARE (poll (&pollfd, 1, 0), 0); +- } +- +- xclose (pipefds[0]); +- xclose (pipefds[1]); +-} +- +-/* Test a write failure after (potentially) writing some bytes. +- Failure occurs near the start of the buffer. */ +-static void +-delayed_write_failure_beginning (void) +-{ +- /* We need to write something to provoke the error. */ +- if (current_size == 0) +- return; +- xwrite (infd, random_data, sizeof (random_data)); +- xlseek (infd, 0, SEEK_SET); +- +- /* Write failure near the start. The actual error code varies among +- file systems. */ +- find_maximum_offset (); +- off64_t where = maximum_offset; +- +- if (current_size == 1) +- ++where; +- outoff = where; +- if (do_outoff) +- xlseek (outfd, 1, SEEK_SET); +- else +- xlseek (outfd, where, SEEK_SET); +- if (maximum_offset_hard_limit || where > maximum_offset) +- { +- TEST_COMPARE (copy_file_range (infd, pinoff, outfd, poutoff, +- sizeof (random_data), 0), -1); +- TEST_COMPARE (errno, maximum_offset_errno); +- TEST_COMPARE (xlseek (infd, 0, SEEK_CUR), 0); +- TEST_COMPARE (inoff, 0); +- if (do_outoff) +- TEST_COMPARE (xlseek (outfd, 0, SEEK_CUR), 1); +- else +- TEST_COMPARE (xlseek (outfd, 0, SEEK_CUR), where); +- TEST_COMPARE (outoff, where); +- struct stat64 st; +- xfstat (outfd, &st); +- TEST_COMPARE (st.st_size, 0); +- } +- else +- { +- /* The offset is not a hard limit. This means we write one +- byte. */ +- TEST_COMPARE (copy_file_range (infd, pinoff, outfd, poutoff, +- sizeof (random_data), 0), 1); +- if (do_inoff) +- { +- TEST_COMPARE (inoff, 1); +- TEST_COMPARE (xlseek (infd, 0, SEEK_CUR), 0); +- } +- else +- { +- TEST_COMPARE (xlseek (infd, 0, SEEK_CUR), 1); +- TEST_COMPARE (inoff, 0); +- } +- if (do_outoff) +- { +- TEST_COMPARE (xlseek (outfd, 0, SEEK_CUR), 1); +- TEST_COMPARE (outoff, where + 1); +- } +- else +- { +- TEST_COMPARE (xlseek (outfd, 0, SEEK_CUR), where + 1); +- TEST_COMPARE (outoff, where); +- } +- struct stat64 st; +- xfstat (outfd, &st); +- TEST_COMPARE (st.st_size, where + 1); +- } +-} +- +-/* Test a write failure after (potentially) writing some bytes. +- Failure occurs near the end of the buffer. */ +-static void +-delayed_write_failure_end (void) +-{ +- if (current_size <= 1) +- /* This would be same as the first test because there is not +- enough data to write to make a difference. */ +- return; +- xwrite (infd, random_data, sizeof (random_data)); +- xlseek (infd, 0, SEEK_SET); +- +- find_maximum_offset (); +- off64_t where = maximum_offset - current_size + 1; +- if (current_size == sizeof (random_data)) +- /* Otherwise we do not reach the non-writable byte. */ +- ++where; +- outoff = where; +- if (do_outoff) +- xlseek (outfd, 1, SEEK_SET); +- else +- xlseek (outfd, where, SEEK_SET); +- ssize_t ret = copy_file_range (infd, pinoff, outfd, poutoff, +- sizeof (random_data), 0); +- if (ret < 0) +- { +- TEST_COMPARE (ret, -1); +- TEST_COMPARE (errno, maximum_offset_errno); +- struct stat64 st; +- xfstat (outfd, &st); +- TEST_COMPARE (st.st_size, 0); +- } +- else +- { +- /* The first copy succeeded. This happens in the emulation +- because the internal buffer of limited size does not +- necessarily cross the off64_t boundary on the first write +- operation. */ +- if (test_verbose > 0) +- printf ("info: copy_file_range (%zu) returned %zd\n", +- sizeof (random_data), ret); +- TEST_VERIFY (ret > 0); +- TEST_VERIFY (ret < maximum_size); +- struct stat64 st; +- xfstat (outfd, &st); +- TEST_COMPARE (st.st_size, where + ret); +- if (do_inoff) +- { +- TEST_COMPARE (inoff, ret); +- TEST_COMPARE (xlseek (infd, 0, SEEK_CUR), 0); +- } +- else +- TEST_COMPARE (xlseek (infd, 0, SEEK_CUR), ret); +- +- char *buffer = xmalloc (ret); +- TEST_COMPARE (pread64 (outfd, buffer, ret, where), ret); +- TEST_VERIFY (memcmp (buffer, random_data, ret) == 0); +- free (buffer); +- +- /* The second copy fails. */ +- TEST_COMPARE (copy_file_range (infd, pinoff, outfd, poutoff, +- sizeof (random_data), 0), -1); +- TEST_COMPARE (errno, maximum_offset_errno); +- } +-} +- +-/* Test a write failure across devices. */ +-static void +-cross_device_failure (void) +-{ +- if (xdevfile == NULL) +- /* Subtest not supported due to missing cross-device file. */ +- return; +- +- /* We need something to write. */ +- xwrite (infd, random_data, sizeof (random_data)); +- xlseek (infd, 0, SEEK_SET); +- +- int xdevfd = xopen (xdevfile, O_RDWR | O_LARGEFILE, 0); +- TEST_COMPARE (copy_file_range (infd, pinoff, xdevfd, poutoff, +- current_size, 0), -1); +- TEST_COMPARE (errno, EXDEV); +- TEST_COMPARE (xlseek (infd, 0, SEEK_CUR), 0); +- struct stat64 st; +- xfstat (xdevfd, &st); +- TEST_COMPARE (st.st_size, 0); +- +- xclose (xdevfd); +-} +- +-/* Try to exercise ENOSPC behavior with a tempfs file system (so that +- we do not have to fill up a regular file system to get the error). +- This function runs in a subprocess, so that we do not change the +- mount namespace of the actual test process. */ +-static void +-enospc_failure_1 (void *closure) +-{ +-#ifdef CLONE_NEWNS +- support_become_root (); +- +- /* Make sure that we do not alter the file system mounts of the +- parents. */ +- if (! support_enter_mount_namespace ()) +- { +- printf ("warning: ENOSPC test skipped\n"); +- return; +- } +- +- char *mountpoint = closure; +- if (mount ("none", mountpoint, "tmpfs", MS_NODEV | MS_NOEXEC, +- "size=500k") != 0) +- { +- printf ("warning: could not mount tmpfs at %s: %m\n", mountpoint); +- return; +- } +- +- /* The source file must reside on the same file system. */ +- char *intmpfsfile = xasprintf ("%s/%s", mountpoint, "in"); +- int intmpfsfd = xopen (intmpfsfile, O_RDWR | O_CREAT | O_LARGEFILE, 0600); +- xwrite (intmpfsfd, random_data, sizeof (random_data)); +- xlseek (intmpfsfd, 1, SEEK_SET); +- inoff = 1; +- +- char *outtmpfsfile = xasprintf ("%s/%s", mountpoint, "out"); +- int outtmpfsfd = xopen (outtmpfsfile, O_RDWR | O_CREAT | O_LARGEFILE, 0600); +- +- /* Fill the file with data until ENOSPC is reached. */ +- while (true) +- { +- ssize_t ret = write (outtmpfsfd, random_data, sizeof (random_data)); +- if (ret < 0 && errno != ENOSPC) +- FAIL_EXIT1 ("write to %s: %m", outtmpfsfile); +- if (ret < sizeof (random_data)) +- break; +- } +- TEST_COMPARE (write (outtmpfsfd, "", 1), -1); +- TEST_COMPARE (errno, ENOSPC); +- off64_t maxsize = xlseek (outtmpfsfd, 0, SEEK_CUR); +- TEST_VERIFY_EXIT (maxsize > sizeof (random_data)); +- +- /* Constructed the expected file contents. */ +- char *expected = xmalloc (maxsize); +- TEST_COMPARE (pread64 (outtmpfsfd, expected, maxsize, 0), maxsize); +- /* Go back a little, so some bytes can be written. */ +- enum { offset = 20000 }; +- TEST_VERIFY_EXIT (offset < maxsize); +- TEST_VERIFY_EXIT (offset < sizeof (random_data)); +- memcpy (expected + maxsize - offset, random_data + 1, offset); +- +- if (do_outoff) +- { +- outoff = maxsize - offset; +- xlseek (outtmpfsfd, 2, SEEK_SET); +- } +- else +- xlseek (outtmpfsfd, -offset, SEEK_CUR); +- +- /* First call is expected to succeed because we made room for some +- bytes. */ +- TEST_COMPARE (copy_file_range (intmpfsfd, pinoff, outtmpfsfd, poutoff, +- maximum_size, 0), offset); +- if (do_inoff) +- { +- TEST_COMPARE (inoff, 1 + offset); +- TEST_COMPARE (xlseek (intmpfsfd, 0, SEEK_CUR), 1); +- } +- else +- TEST_COMPARE (xlseek (intmpfsfd, 0, SEEK_CUR), 1 + offset); +- if (do_outoff) +- { +- TEST_COMPARE (outoff, maxsize); +- TEST_COMPARE (xlseek (outtmpfsfd, 0, SEEK_CUR), 2); +- } +- else +- TEST_COMPARE (xlseek (outtmpfsfd, 0, SEEK_CUR), maxsize); +- struct stat64 st; +- xfstat (outtmpfsfd, &st); +- TEST_COMPARE (st.st_size, maxsize); +- char *actual = xmalloc (st.st_size); +- TEST_COMPARE (pread64 (outtmpfsfd, actual, st.st_size, 0), st.st_size); +- TEST_VERIFY (memcmp (expected, actual, maxsize) == 0); +- +- /* Second call should fail with ENOSPC. */ +- TEST_COMPARE (copy_file_range (intmpfsfd, pinoff, outtmpfsfd, poutoff, +- maximum_size, 0), -1); +- TEST_COMPARE (errno, ENOSPC); +- +- /* Offsets should be unchanged. */ +- if (do_inoff) +- { +- TEST_COMPARE (inoff, 1 + offset); +- TEST_COMPARE (xlseek (intmpfsfd, 0, SEEK_CUR), 1); +- } +- else +- TEST_COMPARE (xlseek (intmpfsfd, 0, SEEK_CUR), 1 + offset); +- if (do_outoff) +- { +- TEST_COMPARE (outoff, maxsize); +- TEST_COMPARE (xlseek (outtmpfsfd, 0, SEEK_CUR), 2); +- } +- else +- TEST_COMPARE (xlseek (outtmpfsfd, 0, SEEK_CUR), maxsize); +- TEST_COMPARE (xlseek (outtmpfsfd, 0, SEEK_END), maxsize); +- TEST_COMPARE (pread64 (outtmpfsfd, actual, maxsize, 0), maxsize); +- TEST_VERIFY (memcmp (expected, actual, maxsize) == 0); +- +- free (actual); +- free (expected); +- +- xclose (intmpfsfd); +- xclose (outtmpfsfd); +- free (intmpfsfile); +- free (outtmpfsfile); +- +-#else /* !CLONE_NEWNS */ +- puts ("warning: ENOSPC test skipped (no mount namespaces)"); +-#endif +-} +- +-/* Call enospc_failure_1 in a subprocess. */ +-static void +-enospc_failure (void) +-{ +- char *mountpoint +- = support_create_temp_directory ("tst-copy_file_range-enospc-"); +- support_isolate_in_subprocess (enospc_failure_1, mountpoint); +- free (mountpoint); +-} +- +-/* The target file descriptor must have O_APPEND enabled. */ +-static void +-oappend_failure (void) +-{ +- /* Add data, to make sure we do not fail because there is +- insufficient input data. */ +- xwrite (infd, random_data, current_size); +- xlseek (infd, 0, SEEK_SET); +- +- xclose (outfd); +- outfd = xopen (outfile, O_RDWR | O_APPEND, 0); +- TEST_COMPARE (copy_file_range (infd, pinoff, outfd, poutoff, +- current_size, 0), -1); +- TEST_COMPARE (errno, EBADF); +-} +- + /* Test that a short input file results in a shortened copy. */ + static void + short_copy (void) +@@ -721,14 +228,6 @@ struct test_case + static struct test_case tests[] = + { + { "simple_file_copy", simple_file_copy, .sizes = true }, +- { "pipe_as_source", pipe_as_source, }, +- { "pipe_as_destination", pipe_as_destination, }, +- { "delayed_write_failure_beginning", delayed_write_failure_beginning, +- .sizes = true }, +- { "delayed_write_failure_end", delayed_write_failure_end, .sizes = true }, +- { "cross_device_failure", cross_device_failure, .sizes = true }, +- { "enospc_failure", enospc_failure, }, +- { "oappend_failure", oappend_failure, .sizes = true }, + { "short_copy", short_copy, .sizes = true }, + }; + +@@ -739,53 +238,18 @@ do_test (void) + *p = rand () >> 24; + + infd = create_temp_file ("tst-copy_file_range-in-", &infile); +- xclose (create_temp_file ("tst-copy_file_range-out-", &outfile)); +- +- /* Try to find a different directory from the default input/output +- file. */ ++ outfd = create_temp_file ("tst-copy_file_range-out-", &outfile); + { +- struct stat64 instat; +- xfstat (infd, &instat); +- static const char *const candidates[] = +- { NULL, "/var/tmp", "/dev/shm" }; +- for (const char *const *c = candidates; c < array_end (candidates); ++c) +- { +- const char *path = *c; +- char *to_free = NULL; +- if (path == NULL) +- { +- to_free = xreadlink ("/proc/self/exe"); +- path = dirname (to_free); +- } +- +- struct stat64 cstat; +- xstat (path, &cstat); +- if (cstat.st_dev == instat.st_dev) +- { +- free (to_free); +- continue; +- } +- +- printf ("info: using alternate temporary files directory: %s\n", path); +- xdevfile = xasprintf ("%s/tst-copy_file_range-xdev-XXXXXX", path); +- free (to_free); +- break; +- } +- if (xdevfile != NULL) ++ ssize_t ret = copy_file_range (infd, NULL, outfd, NULL, 0, 0); ++ if (ret != 0) + { +- int xdevfd = mkstemp (xdevfile); +- if (xdevfd < 0) +- FAIL_EXIT1 ("mkstemp (\"%s\"): %m", xdevfile); +- struct stat64 xdevst; +- xfstat (xdevfd, &xdevst); +- TEST_VERIFY (xdevst.st_dev != instat.st_dev); +- add_temp_file (xdevfile); +- xclose (xdevfd); ++ if (errno == ENOSYS) ++ FAIL_UNSUPPORTED ("copy_file_range is not support on this system"); ++ FAIL_EXIT1 ("copy_file_range probing call: %m"); + } +- else +- puts ("warning: no alternate directory on different file system found"); + } + xclose (infd); ++ xclose (outfd); + + for (do_inoff = 0; do_inoff < 2; ++do_inoff) + for (do_outoff = 0; do_outoff < 2; ++do_outoff) +@@ -827,7 +291,6 @@ do_test (void) + + free (infile); + free (outfile); +- free (xdevfile); + + return 0; + } +diff --git a/manual/llio.texi b/manual/llio.texi +index 2733b9cb7331df07..26f7d2cb3ea220d9 100644 +--- a/manual/llio.texi ++++ b/manual/llio.texi +@@ -1404,10 +1404,13 @@ failure occurs. The return value is zero if the end of the input file + is encountered immediately. + + If no bytes can be copied, to report an error, @code{copy_file_range} +-returns the value @math{-1} and sets @code{errno}. The following +-@code{errno} error conditions are specific to this function: ++returns the value @math{-1} and sets @code{errno}. The table below ++lists some of the error conditions for this function. + + @table @code ++@item ENOSYS ++The kernel does not implement the required functionality. ++ + @item EISDIR + At least one of the descriptors @var{inputfd} or @var{outputfd} refers + to a directory. +@@ -1437,9 +1440,6 @@ reading. + + The argument @var{outputfd} is not a valid file descriptor open for + writing, or @var{outputfd} has been opened with @code{O_APPEND}. +- +-@item EXDEV +-The input and output files reside on different file systems. + @end table + + In addition, @code{copy_file_range} can fail with the error codes +diff --git a/sysdeps/unix/sysv/linux/alpha/kernel-features.h b/sysdeps/unix/sysv/linux/alpha/kernel-features.h +index 402d2573d75794d5..26344cd610a1f8e7 100644 +--- a/sysdeps/unix/sysv/linux/alpha/kernel-features.h ++++ b/sysdeps/unix/sysv/linux/alpha/kernel-features.h +@@ -48,7 +48,6 @@ + /* Support for copy_file_range, statx was added in kernel 4.13. */ + #if __LINUX_KERNEL_VERSION < 0x040D00 + # undef __ASSUME_MLOCK2 +-# undef __ASSUME_COPY_FILE_RANGE + # undef __ASSUME_STATX + #endif + +diff --git a/sysdeps/unix/sysv/linux/copy_file_range.c b/sysdeps/unix/sysv/linux/copy_file_range.c +index 7b1a50f7529f2a84..b88b7c9e2ecd825f 100644 +--- a/sysdeps/unix/sysv/linux/copy_file_range.c ++++ b/sysdeps/unix/sysv/linux/copy_file_range.c +@@ -20,27 +20,16 @@ + #include + #include + +-/* Include the fallback implementation. */ +-#ifndef __ASSUME_COPY_FILE_RANGE +-#define COPY_FILE_RANGE_DECL static +-#define COPY_FILE_RANGE copy_file_range_compat +-#include +-#endif +- + ssize_t + copy_file_range (int infd, __off64_t *pinoff, + int outfd, __off64_t *poutoff, + size_t length, unsigned int flags) + { + #ifdef __NR_copy_file_range +- ssize_t ret = SYSCALL_CANCEL (copy_file_range, infd, pinoff, outfd, poutoff, +- length, flags); +-# ifndef __ASSUME_COPY_FILE_RANGE +- if (ret == -1 && errno == ENOSYS) +- ret = copy_file_range_compat (infd, pinoff, outfd, poutoff, length, flags); +-# endif +- return ret; +-#else /* !__NR_copy_file_range */ +- return copy_file_range_compat (infd, pinoff, outfd, poutoff, length, flags); ++ return SYSCALL_CANCEL (copy_file_range, infd, pinoff, outfd, poutoff, ++ length, flags); ++#else ++ __set_errno (ENOSYS); ++ return -1; + #endif + } +diff --git a/sysdeps/unix/sysv/linux/kernel-features.h b/sysdeps/unix/sysv/linux/kernel-features.h +index 5543d92d7e32e501..7a74835495250268 100644 +--- a/sysdeps/unix/sysv/linux/kernel-features.h ++++ b/sysdeps/unix/sysv/linux/kernel-features.h +@@ -111,10 +111,6 @@ + # define __ASSUME_MLOCK2 1 + #endif + +-#if __LINUX_KERNEL_VERSION >= 0x040500 +-# define __ASSUME_COPY_FILE_RANGE 1 +-#endif +- + /* Support for statx was added in kernel 4.11. */ + #if __LINUX_KERNEL_VERSION >= 0x040B00 + # define __ASSUME_STATX 1 +diff --git a/sysdeps/unix/sysv/linux/microblaze/kernel-features.h b/sysdeps/unix/sysv/linux/microblaze/kernel-features.h +index e8e2ac6a873126ac..1c49f099b7993f1d 100644 +--- a/sysdeps/unix/sysv/linux/microblaze/kernel-features.h ++++ b/sysdeps/unix/sysv/linux/microblaze/kernel-features.h +@@ -58,11 +58,6 @@ + # undef __ASSUME_EXECVEAT + #endif + +-/* Support for the copy_file_range syscall was added in 4.10. */ +-#if __LINUX_KERNEL_VERSION < 0x040A00 +-# undef __ASSUME_COPY_FILE_RANGE +-#endif +- + /* Support for statx was added in kernel 4.12. */ + #if __LINUX_KERNEL_VERSION < 0X040C00 + # undef __ASSUME_STATX diff --git a/SOURCES/glibc-rh1726638-1.patch b/SOURCES/glibc-rh1726638-1.patch new file mode 100644 index 0000000..96c2b21 --- /dev/null +++ b/SOURCES/glibc-rh1726638-1.patch @@ -0,0 +1,35 @@ +commit 55f82d328d2dd1c7c13c1992f4b9bf9c95b57551 +Author: Szabolcs Nagy +Date: Thu Apr 25 15:35:35 2019 +0100 + + aarch64: add STO_AARCH64_VARIANT_PCS and DT_AARCH64_VARIANT_PCS + + STO_AARCH64_VARIANT_PCS is a non-visibility st_other flag for marking + symbols that reference functions that may follow a variant PCS with + different register usage convention from the base PCS. + + DT_AARCH64_VARIANT_PCS is a dynamic tag that marks ELF modules that + have R_*_JUMP_SLOT relocations for symbols marked with + STO_AARCH64_VARIANT_PCS (i.e. have variant PCS calls via a PLT). + + * elf/elf.h (STO_AARCH64_VARIANT_PCS): Define. + (DT_AARCH64_VARIANT_PCS): Define. + +diff --git a/elf/elf.h b/elf/elf.h +index 7e2b072a7f75451c..74f7f479ce817040 100644 +--- a/elf/elf.h ++++ b/elf/elf.h +@@ -2847,6 +2847,13 @@ enum + #define R_AARCH64_TLSDESC 1031 /* TLS Descriptor. */ + #define R_AARCH64_IRELATIVE 1032 /* STT_GNU_IFUNC relocation. */ + ++/* AArch64 specific values for the Dyn d_tag field. */ ++#define DT_AARCH64_VARIANT_PCS (DT_LOPROC + 5) ++#define DT_AARCH64_NUM 6 ++ ++/* AArch64 specific values for the st_other field. */ ++#define STO_AARCH64_VARIANT_PCS 0x80 ++ + /* ARM relocs. */ + + #define R_ARM_NONE 0 /* No reloc */ diff --git a/SOURCES/glibc-rh1726638-2.patch b/SOURCES/glibc-rh1726638-2.patch new file mode 100644 index 0000000..f321c7a --- /dev/null +++ b/SOURCES/glibc-rh1726638-2.patch @@ -0,0 +1,138 @@ +commit 82bc69c012838a381c4167c156a06f4598f34227 +Author: Szabolcs Nagy +Date: Thu Apr 25 15:35:35 2019 +0100 + + aarch64: handle STO_AARCH64_VARIANT_PCS + + Avoid lazy binding of symbols that may follow a variant PCS with different + register usage convention from the base PCS. + + Currently the lazy binding entry code does not preserve all the registers + required for AdvSIMD and SVE vector calls. Saving and restoring all + registers unconditionally may break existing binaries, even if they never + use vector calls, because of the larger stack requirement for lazy + resolution, which can be significant on an SVE system. + + The solution is to mark all symbols in the symbol table that may follow + a variant PCS so the dynamic linker can handle them specially. In this + patch such symbols are always resolved at load time, not lazily. + + So currently LD_AUDIT for variant PCS symbols are not supported, for that + the _dl_runtime_profile entry needs to be changed e.g. to unconditionally + save/restore all registers (but pass down arg and retval registers to + pltentry/exit callbacks according to the base PCS). + + This patch also removes a __builtin_expect from the modified code because + the branch prediction hint did not seem useful. + + * sysdeps/aarch64/dl-dtprocnum.h: New file. + * sysdeps/aarch64/dl-machine.h (DT_AARCH64): Define. + (elf_machine_runtime_setup): Handle DT_AARCH64_VARIANT_PCS. + (elf_machine_lazy_rel): Check STO_AARCH64_VARIANT_PCS and bind such + symbols at load time. + * sysdeps/aarch64/linkmap.h (struct link_map_machine): Add variant_pcs. + +diff --git a/sysdeps/aarch64/dl-dtprocnum.h b/sysdeps/aarch64/dl-dtprocnum.h +new file mode 100644 +index 0000000000000000..4ac2adf23458e02d +--- /dev/null ++++ b/sysdeps/aarch64/dl-dtprocnum.h +@@ -0,0 +1,21 @@ ++/* Configuration of lookup functions. AArch64 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, see ++ . */ ++ ++/* Number of extra dynamic section entries for this architecture. By ++ default there are none. */ ++#define DT_THISPROCNUM DT_AARCH64_NUM +diff --git a/sysdeps/aarch64/dl-machine.h b/sysdeps/aarch64/dl-machine.h +index 4935aa7c543876db..d4494852b32b8783 100644 +--- a/sysdeps/aarch64/dl-machine.h ++++ b/sysdeps/aarch64/dl-machine.h +@@ -27,6 +27,9 @@ + #include + #include + ++/* Translate a processor specific dynamic tag to the index in l_info array. */ ++#define DT_AARCH64(x) (DT_AARCH64_##x - DT_LOPROC + DT_NUM) ++ + /* Return nonzero iff ELF header is compatible with the running host. */ + static inline int __attribute__ ((unused)) + elf_machine_matches_host (const ElfW(Ehdr) *ehdr) +@@ -102,6 +105,10 @@ elf_machine_runtime_setup (struct link_map *l, int lazy, int profile) + } + } + ++ /* Check if STO_AARCH64_VARIANT_PCS needs to be handled. */ ++ if (l->l_info[DT_AARCH64 (VARIANT_PCS)]) ++ l->l_mach.variant_pcs = 1; ++ + return lazy; + } + +@@ -388,10 +395,37 @@ elf_machine_lazy_rel (struct link_map *map, + /* Check for unexpected PLT reloc type. */ + if (__builtin_expect (r_type == AARCH64_R(JUMP_SLOT), 1)) + { +- if (__builtin_expect (map->l_mach.plt, 0) == 0) +- *reloc_addr += l_addr; +- else +- *reloc_addr = map->l_mach.plt; ++ if (map->l_mach.plt == 0) ++ { ++ /* Prelinking. */ ++ *reloc_addr += l_addr; ++ return; ++ } ++ ++ if (__glibc_unlikely (map->l_mach.variant_pcs)) ++ { ++ /* Check the symbol table for variant PCS symbols. */ ++ const Elf_Symndx symndx = ELFW (R_SYM) (reloc->r_info); ++ const ElfW (Sym) *symtab = ++ (const void *)D_PTR (map, l_info[DT_SYMTAB]); ++ const ElfW (Sym) *sym = &symtab[symndx]; ++ if (__glibc_unlikely (sym->st_other & STO_AARCH64_VARIANT_PCS)) ++ { ++ /* Avoid lazy resolution of variant PCS symbols. */ ++ const struct r_found_version *version = NULL; ++ if (map->l_info[VERSYMIDX (DT_VERSYM)] != NULL) ++ { ++ const ElfW (Half) *vernum = ++ (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, ++ skip_ifunc); ++ return; ++ } ++ } ++ ++ *reloc_addr = map->l_mach.plt; + } + else if (__builtin_expect (r_type == AARCH64_R(TLSDESC), 1)) + { +diff --git a/sysdeps/aarch64/linkmap.h b/sysdeps/aarch64/linkmap.h +index 6852f343a1efd150..dd8597470c3d2174 100644 +--- a/sysdeps/aarch64/linkmap.h ++++ b/sysdeps/aarch64/linkmap.h +@@ -20,4 +20,5 @@ struct link_map_machine + { + ElfW(Addr) plt; /* Address of .plt */ + void *tlsdesc_table; /* Address of TLS descriptor hash table. */ ++ int variant_pcs; /* If set, PLT calls may follow a variant PCS. */ + }; diff --git a/SOURCES/glibc-rh1726638-3.patch b/SOURCES/glibc-rh1726638-3.patch new file mode 100644 index 0000000..6c37873 --- /dev/null +++ b/SOURCES/glibc-rh1726638-3.patch @@ -0,0 +1,49 @@ +commit 30ba0375464f34e4bf8129f3d3dc14d0c09add17 +Author: Szabolcs Nagy +Date: Tue Jul 9 12:11:39 2019 +0100 + + aarch64: simplify the DT_AARCH64_VARIANT_PCS handling code + + Remove unnecessary variant_pcs field: the dynamic tag can be checked + directly. + + * sysdeps/aarch64/dl-machine.h (elf_machine_runtime_setup): Remove the + DT_AARCH64_VARIANT_PCS check. + (elf_machine_lazy_rel): Use l_info[DT_AARCH64 (VARIANT_PCS)]. + * sysdeps/aarch64/linkmap.h (struct link_map_machine): Remove + variant_pcs. + +diff --git a/sysdeps/aarch64/dl-machine.h b/sysdeps/aarch64/dl-machine.h +index d4494852b32b8783..b39eae4acf4086ee 100644 +--- a/sysdeps/aarch64/dl-machine.h ++++ b/sysdeps/aarch64/dl-machine.h +@@ -105,10 +105,6 @@ elf_machine_runtime_setup (struct link_map *l, int lazy, int profile) + } + } + +- /* Check if STO_AARCH64_VARIANT_PCS needs to be handled. */ +- if (l->l_info[DT_AARCH64 (VARIANT_PCS)]) +- l->l_mach.variant_pcs = 1; +- + return lazy; + } + +@@ -402,7 +398,7 @@ elf_machine_lazy_rel (struct link_map *map, + return; + } + +- if (__glibc_unlikely (map->l_mach.variant_pcs)) ++ if (__glibc_unlikely (map->l_info[DT_AARCH64 (VARIANT_PCS)] != NULL)) + { + /* Check the symbol table for variant PCS symbols. */ + const Elf_Symndx symndx = ELFW (R_SYM) (reloc->r_info); +diff --git a/sysdeps/aarch64/linkmap.h b/sysdeps/aarch64/linkmap.h +index dd8597470c3d2174..6852f343a1efd150 100644 +--- a/sysdeps/aarch64/linkmap.h ++++ b/sysdeps/aarch64/linkmap.h +@@ -20,5 +20,4 @@ struct link_map_machine + { + ElfW(Addr) plt; /* Address of .plt */ + void *tlsdesc_table; /* Address of TLS descriptor hash table. */ +- int variant_pcs; /* If set, PLT calls may follow a variant PCS. */ + }; diff --git a/SOURCES/glibc-rh1727152.patch b/SOURCES/glibc-rh1727152.patch new file mode 100644 index 0000000..8a5ed92 --- /dev/null +++ b/SOURCES/glibc-rh1727152.patch @@ -0,0 +1,22 @@ +commit 61595e3d36ded374f97961503e843a314b0203c2 +Author: Andreas Schwab +Date: Tue May 15 14:42:37 2018 +0200 + + nscd: avoid assertion failure during persistent db check + + nscd should not abort when it finds inconsistencies in the persistent db. + +diff --git a/nscd/connections.c b/nscd/connections.c +index 47fbb9923aa2aac7..98182007646a33d5 100644 +--- a/nscd/connections.c ++++ b/nscd/connections.c +@@ -304,7 +304,8 @@ static int + check_use (const char *data, nscd_ssize_t first_free, uint8_t *usemap, + enum usekey use, ref_t start, size_t len) + { +- assert (len >= 2); ++ if (len < 2) ++ return 0; + + if (start > first_free || start + len > first_free + || (start & BLOCK_ALIGN_M1)) diff --git a/SOURCES/glibc-rh1727241-1.patch b/SOURCES/glibc-rh1727241-1.patch new file mode 100644 index 0000000..5842b08 --- /dev/null +++ b/SOURCES/glibc-rh1727241-1.patch @@ -0,0 +1,221 @@ +commit 5e30b8ef0758763effa115634e0ed7d8938e4bc0 +Author: Florian Weimer +Date: Mon Jan 21 08:59:42 2019 +0100 + + resolv: Reformat inet_addr, inet_aton to GNU style + +diff --git a/resolv/inet_addr.c b/resolv/inet_addr.c +index 022f7ea0841b6bae..32f58b0e13598b32 100644 +--- a/resolv/inet_addr.c ++++ b/resolv/inet_addr.c +@@ -1,3 +1,21 @@ ++/* Legacy IPv4 text-to-address functions. ++ 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, see ++ . */ ++ + /* + * Copyright (c) 1983, 1990, 1993 + * The Regents of the University of California. All rights reserved. +@@ -78,105 +96,97 @@ + #include + #include + +-/* +- * Ascii internet address interpretation routine. +- * The value returned is in network order. +- */ ++/* ASCII IPv4 Internet address interpretation routine. The value ++ returned is in network order. */ + in_addr_t +-__inet_addr(const char *cp) { +- struct in_addr val; ++__inet_addr (const char *cp) ++{ ++ struct in_addr val; + +- if (__inet_aton(cp, &val)) +- return (val.s_addr); +- return (INADDR_NONE); ++ if (__inet_aton (cp, &val)) ++ return val.s_addr; ++ return INADDR_NONE; + } + weak_alias (__inet_addr, inet_addr) + +-/* +- * Check whether "cp" is a valid ascii representation +- * of an Internet address and convert to a binary address. +- * Returns 1 if the address is valid, 0 if not. +- * This replaces inet_addr, the return value from which +- * cannot distinguish between failure and a local broadcast address. +- */ ++/* Check whether "cp" is a valid ASCII representation of an IPv4 ++ Internet address and convert it to a binary address. Returns 1 if ++ the address is valid, 0 if not. This replaces inet_addr, the ++ return value from which cannot distinguish between failure and a ++ local broadcast address. */ + int +-__inet_aton(const char *cp, struct in_addr *addr) ++__inet_aton (const char *cp, struct in_addr *addr) + { +- static const in_addr_t max[4] = { 0xffffffff, 0xffffff, 0xffff, 0xff }; +- in_addr_t val; +- char c; +- union iaddr { +- uint8_t bytes[4]; +- uint32_t word; +- } res; +- uint8_t *pp = res.bytes; +- int digit; +- +- int saved_errno = errno; +- __set_errno (0); +- +- res.word = 0; +- +- c = *cp; +- for (;;) { +- /* +- * Collect number up to ``.''. +- * Values are specified as for C: +- * 0x=hex, 0=octal, isdigit=decimal. +- */ +- if (!isdigit(c)) +- goto ret_0; +- { +- char *endp; +- unsigned long ul = strtoul (cp, (char **) &endp, 0); +- if (ul == ULONG_MAX && errno == ERANGE) +- goto ret_0; +- if (ul > 0xfffffffful) +- goto ret_0; +- val = ul; +- digit = cp != endp; +- cp = endp; +- } +- c = *cp; +- if (c == '.') { +- /* +- * Internet format: +- * a.b.c.d +- * a.b.c (with c treated as 16 bits) +- * a.b (with b treated as 24 bits) +- */ +- if (pp > res.bytes + 2 || val > 0xff) +- goto ret_0; +- *pp++ = val; +- c = *++cp; +- } else +- break; +- } +- /* +- * Check for trailing characters. +- */ +- if (c != '\0' && (!isascii(c) || !isspace(c))) +- goto ret_0; +- /* +- * Did we get a valid digit? +- */ +- if (!digit) +- goto ret_0; +- +- /* Check whether the last part is in its limits depending on +- the number of parts in total. */ +- if (val > max[pp - res.bytes]) ++ static const in_addr_t max[4] = { 0xffffffff, 0xffffff, 0xffff, 0xff }; ++ in_addr_t val; ++ char c; ++ union iaddr ++ { ++ uint8_t bytes[4]; ++ uint32_t word; ++ } res; ++ uint8_t *pp = res.bytes; ++ int digit; ++ ++ int saved_errno = errno; ++ __set_errno (0); ++ ++ res.word = 0; ++ ++ c = *cp; ++ for (;;) ++ { ++ /* Collect number up to ``.''. Values are specified as for C: ++ 0x=hex, 0=octal, isdigit=decimal. */ ++ if (!isdigit (c)) ++ goto ret_0; ++ { ++ char *endp; ++ unsigned long ul = strtoul (cp, &endp, 0); ++ if (ul == ULONG_MAX && errno == ERANGE) + goto ret_0; +- +- if (addr != NULL) +- addr->s_addr = res.word | htonl (val); +- +- __set_errno (saved_errno); +- return (1); +- +-ret_0: +- __set_errno (saved_errno); +- return (0); ++ if (ul > 0xfffffffful) ++ goto ret_0; ++ val = ul; ++ digit = cp != endp; ++ cp = endp; ++ } ++ c = *cp; ++ if (c == '.') ++ { ++ /* Internet format: ++ a.b.c.d ++ a.b.c (with c treated as 16 bits) ++ a.b (with b treated as 24 bits). */ ++ if (pp > res.bytes + 2 || val > 0xff) ++ goto ret_0; ++ *pp++ = val; ++ c = *++cp; ++ } ++ else ++ break; ++ } ++ /* Check for trailing characters. */ ++ if (c != '\0' && (!isascii (c) || !isspace (c))) ++ goto ret_0; ++ /* Did we get a valid digit? */ ++ if (!digit) ++ goto ret_0; ++ ++ /* Check whether the last part is in its limits depending on the ++ number of parts in total. */ ++ if (val > max[pp - res.bytes]) ++ goto ret_0; ++ ++ if (addr != NULL) ++ addr->s_addr = res.word | htonl (val); ++ ++ __set_errno (saved_errno); ++ return 1; ++ ++ ret_0: ++ __set_errno (saved_errno); ++ return 0; + } + weak_alias (__inet_aton, inet_aton) + libc_hidden_def (__inet_aton) diff --git a/SOURCES/glibc-rh1727241-2.patch b/SOURCES/glibc-rh1727241-2.patch new file mode 100644 index 0000000..7f9f417 --- /dev/null +++ b/SOURCES/glibc-rh1727241-2.patch @@ -0,0 +1,80 @@ +commit 6ca53a2453598804a2559a548a08424fca96434a +Author: Florian Weimer +Date: Mon Jan 21 09:26:41 2019 +0100 + + resolv: Do not send queries for non-host-names in nss_dns [BZ #24112] + + Before this commit, nss_dns would send a query which did not contain a + host name as the query name (such as invalid\032name.example.com) and + then reject the answer in getanswer_r and gaih_getanswer_slice, using + a check based on res_hnok. With this commit, no query is sent, and a + host-not-found error is returned to NSS without network interaction. + +diff --git a/resolv/nss_dns/dns-host.c b/resolv/nss_dns/dns-host.c +index 5dc2829cd148a568..99c3b61e1cee4d42 100644 +--- a/resolv/nss_dns/dns-host.c ++++ b/resolv/nss_dns/dns-host.c +@@ -274,11 +274,26 @@ gethostbyname3_context (struct resolv_context *ctx, + return status; + } + ++/* Verify that the name looks like a host name. There is no point in ++ sending a query which will not produce a usable name in the ++ response. */ ++static enum nss_status ++check_name (const char *name, int *h_errnop) ++{ ++ if (res_hnok (name)) ++ return NSS_STATUS_SUCCESS; ++ *h_errnop = HOST_NOT_FOUND; ++ return NSS_STATUS_NOTFOUND; ++} ++ + enum nss_status + _nss_dns_gethostbyname2_r (const char *name, int af, struct hostent *result, + char *buffer, size_t buflen, int *errnop, + int *h_errnop) + { ++ enum nss_status status = check_name (name, h_errnop); ++ if (status != NSS_STATUS_SUCCESS) ++ return status; + return _nss_dns_gethostbyname3_r (name, af, result, buffer, buflen, errnop, + h_errnop, NULL, NULL); + } +@@ -289,6 +304,9 @@ _nss_dns_gethostbyname_r (const char *name, struct hostent *result, + char *buffer, size_t buflen, int *errnop, + int *h_errnop) + { ++ enum nss_status status = check_name (name, h_errnop); ++ if (status != NSS_STATUS_SUCCESS) ++ return status; + struct resolv_context *ctx = __resolv_context_get (); + if (ctx == NULL) + { +@@ -296,7 +314,7 @@ _nss_dns_gethostbyname_r (const char *name, struct hostent *result, + *h_errnop = NETDB_INTERNAL; + return NSS_STATUS_UNAVAIL; + } +- enum nss_status status = NSS_STATUS_NOTFOUND; ++ status = NSS_STATUS_NOTFOUND; + if (res_use_inet6 ()) + status = gethostbyname3_context (ctx, name, AF_INET6, result, buffer, + buflen, errnop, h_errnop, NULL, NULL); +@@ -313,6 +331,9 @@ _nss_dns_gethostbyname4_r (const char *name, struct gaih_addrtuple **pat, + char *buffer, size_t buflen, int *errnop, + int *herrnop, int32_t *ttlp) + { ++ enum nss_status status = check_name (name, herrnop); ++ if (status != NSS_STATUS_SUCCESS) ++ return status; + struct resolv_context *ctx = __resolv_context_get (); + if (ctx == NULL) + { +@@ -347,7 +368,6 @@ _nss_dns_gethostbyname4_r (const char *name, struct gaih_addrtuple **pat, + int ans2p_malloced = 0; + + int olderr = errno; +- enum nss_status status; + int 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); diff --git a/SOURCES/glibc-rh1727241-3.patch b/SOURCES/glibc-rh1727241-3.patch new file mode 100644 index 0000000..f578ebd --- /dev/null +++ b/SOURCES/glibc-rh1727241-3.patch @@ -0,0 +1,698 @@ +commit 108bc4049f8ae82710aec26a92ffdb4b439c83fd +Author: Florian Weimer +Date: Mon Jan 21 21:26:03 2019 +0100 + + CVE-2016-10739: getaddrinfo: Fully parse IPv4 address strings [BZ #20018] + + The IPv4 address parser in the getaddrinfo function is changed so that + it does not ignore trailing whitespace and all characters after it. + For backwards compatibility, the getaddrinfo function still recognizes + legacy name syntax, such as 192.000.002.010 interpreted as 192.0.2.8 + (octal). + + This commit does not change the behavior of inet_addr and inet_aton. + gethostbyname already had additional sanity checks (but is switched + over to the new __inet_aton_exact function for completeness as well). + + To avoid sending the problematic query names over DNS, commit + 6ca53a2453598804a2559a548a08424fca96434a ("resolv: Do not send queries + for non-host-names in nss_dns [BZ #24112]") is needed. + +diff --git a/include/arpa/inet.h b/include/arpa/inet.h +index c3f28f2baaa2ed66..19aec74275069a45 100644 +--- a/include/arpa/inet.h ++++ b/include/arpa/inet.h +@@ -1,10 +1,10 @@ + #include + + #ifndef _ISOMAC +-extern int __inet_aton (const char *__cp, struct in_addr *__inp); +-libc_hidden_proto (__inet_aton) ++/* Variant of inet_aton which rejects trailing garbage. */ ++extern int __inet_aton_exact (const char *__cp, struct in_addr *__inp); ++libc_hidden_proto (__inet_aton_exact) + +-libc_hidden_proto (inet_aton) + libc_hidden_proto (inet_ntop) + libc_hidden_proto (inet_pton) + extern __typeof (inet_pton) __inet_pton; +diff --git a/nscd/gai.c b/nscd/gai.c +index 24bdfee1db3791e2..f57f396f574a6e52 100644 +--- a/nscd/gai.c ++++ b/nscd/gai.c +@@ -19,7 +19,6 @@ + + /* This file uses the getaddrinfo code but it compiles it without NSCD + support. We just need a few symbol renames. */ +-#define __inet_aton inet_aton + #define __ioctl ioctl + #define __getsockname getsockname + #define __socket socket +diff --git a/nscd/gethstbynm3_r.c b/nscd/gethstbynm3_r.c +index 7beb9dce9f4b350c..f792c4fcd042d13d 100644 +--- a/nscd/gethstbynm3_r.c ++++ b/nscd/gethstbynm3_r.c +@@ -38,8 +38,6 @@ + #define HAVE_LOOKUP_BUFFER 1 + #define HAVE_AF 1 + +-#define __inet_aton inet_aton +- + /* We are nscd, so we don't want to be talking to ourselves. */ + #undef USE_NSCD + +diff --git a/nss/digits_dots.c b/nss/digits_dots.c +index 39bff38865a1ac5b..5441bce16ea8b2e9 100644 +--- a/nss/digits_dots.c ++++ b/nss/digits_dots.c +@@ -29,7 +29,6 @@ + #include "nsswitch.h" + + #ifdef USE_NSCD +-# define inet_aton __inet_aton + # include + #endif + +@@ -160,7 +159,7 @@ __nss_hostname_digits_dots_context (struct resolv_context *ctx, + 255.255.255.255? The test below will succeed + spuriously... ??? */ + if (af == AF_INET) +- ok = __inet_aton (name, (struct in_addr *) host_addr); ++ ok = __inet_aton_exact (name, (struct in_addr *) host_addr); + else + { + assert (af == AF_INET6); +diff --git a/resolv/Makefile b/resolv/Makefile +index 56718654eeab85a3..72a0f196506ac489 100644 +--- a/resolv/Makefile ++++ b/resolv/Makefile +@@ -34,6 +34,9 @@ routines := herror inet_addr inet_ntop inet_pton nsap_addr res_init \ + tests = tst-aton tst-leaks tst-inet_ntop + xtests = tst-leaks2 + ++tests-internal += tst-inet_aton_exact ++ ++ + generate := mtrace-tst-leaks.out tst-leaks.mtrace tst-leaks2.mtrace + + extra-libs := libresolv libnss_dns +@@ -54,8 +57,10 @@ tests += \ + tst-resolv-binary \ + tst-resolv-edns \ + tst-resolv-network \ ++ tst-resolv-nondecimal \ + tst-resolv-res_init-multi \ + tst-resolv-search \ ++ tst-resolv-trailing \ + + # These tests need libdl. + ifeq (yes,$(build-shared)) +@@ -190,9 +195,11 @@ $(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-nondecimal: $(objpfx)libresolv.so $(shared-thread-library) + $(objpfx)tst-resolv-qtypes: $(objpfx)libresolv.so $(shared-thread-library) + $(objpfx)tst-resolv-rotate: $(objpfx)libresolv.so $(shared-thread-library) + $(objpfx)tst-resolv-search: $(objpfx)libresolv.so $(shared-thread-library) ++$(objpfx)tst-resolv-trailing: $(objpfx)libresolv.so $(shared-thread-library) + $(objpfx)tst-resolv-threads: \ + $(libdl) $(objpfx)libresolv.so $(shared-thread-library) + $(objpfx)tst-resolv-canonname: \ +diff --git a/resolv/Versions b/resolv/Versions +index b05778d9654aa0f2..9a82704af75f789b 100644 +--- a/resolv/Versions ++++ b/resolv/Versions +@@ -27,6 +27,7 @@ libc { + __h_errno; __resp; + + __res_iclose; ++ __inet_aton_exact; + __inet_pton_length; + __resolv_context_get; + __resolv_context_get_preinit; +diff --git a/resolv/inet_addr.c b/resolv/inet_addr.c +index 32f58b0e13598b32..41b6166a5bd5a44b 100644 +--- a/resolv/inet_addr.c ++++ b/resolv/inet_addr.c +@@ -96,26 +96,14 @@ + #include + #include + +-/* ASCII IPv4 Internet address interpretation routine. The value +- returned is in network order. */ +-in_addr_t +-__inet_addr (const char *cp) +-{ +- struct in_addr val; +- +- if (__inet_aton (cp, &val)) +- return val.s_addr; +- return INADDR_NONE; +-} +-weak_alias (__inet_addr, inet_addr) +- + /* Check whether "cp" is a valid ASCII representation of an IPv4 + Internet address and convert it to a binary address. Returns 1 if + the address is valid, 0 if not. This replaces inet_addr, the + return value from which cannot distinguish between failure and a +- local broadcast address. */ +-int +-__inet_aton (const char *cp, struct in_addr *addr) ++ local broadcast address. Write a pointer to the first ++ non-converted character to *endp. */ ++static int ++inet_aton_end (const char *cp, struct in_addr *addr, const char **endp) + { + static const in_addr_t max[4] = { 0xffffffff, 0xffffff, 0xffff, 0xff }; + in_addr_t val; +@@ -180,6 +168,7 @@ __inet_aton (const char *cp, struct in_addr *addr) + + if (addr != NULL) + addr->s_addr = res.word | htonl (val); ++ *endp = cp; + + __set_errno (saved_errno); + return 1; +@@ -188,6 +177,41 @@ __inet_aton (const char *cp, struct in_addr *addr) + __set_errno (saved_errno); + return 0; + } +-weak_alias (__inet_aton, inet_aton) +-libc_hidden_def (__inet_aton) +-libc_hidden_weak (inet_aton) ++ ++int ++__inet_aton_exact (const char *cp, struct in_addr *addr) ++{ ++ struct in_addr val; ++ const char *endp; ++ /* Check that inet_aton_end parsed the entire string. */ ++ if (inet_aton_end (cp, &val, &endp) != 0 && *endp == 0) ++ { ++ *addr = val; ++ return 1; ++ } ++ else ++ return 0; ++} ++libc_hidden_def (__inet_aton_exact) ++ ++/* inet_aton ignores trailing garbage. */ ++int ++__inet_aton_ignore_trailing (const char *cp, struct in_addr *addr) ++{ ++ const char *endp; ++ return inet_aton_end (cp, addr, &endp); ++} ++weak_alias (__inet_aton_ignore_trailing, inet_aton) ++ ++/* ASCII IPv4 Internet address interpretation routine. The value ++ returned is in network order. */ ++in_addr_t ++__inet_addr (const char *cp) ++{ ++ struct in_addr val; ++ const char *endp; ++ if (inet_aton_end (cp, &val, &endp)) ++ return val.s_addr; ++ return INADDR_NONE; ++} ++weak_alias (__inet_addr, inet_addr) +diff --git a/resolv/res_init.c b/resolv/res_init.c +index f5e52cbbb9377762..94743a252e39d64a 100644 +--- a/resolv/res_init.c ++++ b/resolv/res_init.c +@@ -399,8 +399,16 @@ res_vinit_1 (FILE *fp, struct resolv_conf_parser *parser) + cp = parser->buffer + sizeof ("nameserver") - 1; + while (*cp == ' ' || *cp == '\t') + cp++; ++ ++ /* Ignore trailing contents on the name server line. */ ++ { ++ char *el; ++ if ((el = strpbrk (cp, " \t\n")) != NULL) ++ *el = '\0'; ++ } ++ + struct sockaddr *sa; +- if ((*cp != '\0') && (*cp != '\n') && __inet_aton (cp, &a)) ++ if ((*cp != '\0') && (*cp != '\n') && __inet_aton_exact (cp, &a)) + { + sa = allocate_address_v4 (a, NAMESERVER_PORT); + if (sa == NULL) +@@ -410,9 +418,6 @@ res_vinit_1 (FILE *fp, struct resolv_conf_parser *parser) + { + struct in6_addr a6; + char *el; +- +- if ((el = strpbrk (cp, " \t\n")) != NULL) +- *el = '\0'; + if ((el = strchr (cp, SCOPE_DELIMITER)) != NULL) + *el = '\0'; + if ((*cp != '\0') && (__inet_pton (AF_INET6, cp, &a6) > 0)) +@@ -472,7 +477,7 @@ res_vinit_1 (FILE *fp, struct resolv_conf_parser *parser) + char separator = *cp; + *cp = 0; + struct resolv_sortlist_entry e; +- if (__inet_aton (net, &a)) ++ if (__inet_aton_exact (net, &a)) + { + e.addr = a; + if (is_sort_mask (separator)) +@@ -484,7 +489,7 @@ res_vinit_1 (FILE *fp, struct resolv_conf_parser *parser) + cp++; + separator = *cp; + *cp = 0; +- if (__inet_aton (net, &a)) ++ if (__inet_aton_exact (net, &a)) + e.mask = a.s_addr; + else + e.mask = net_mask (e.addr); +diff --git a/resolv/tst-aton.c b/resolv/tst-aton.c +index 08110a007af909ff..eb734d7758d6ed87 100644 +--- a/resolv/tst-aton.c ++++ b/resolv/tst-aton.c +@@ -1,11 +1,29 @@ ++/* Test legacy IPv4 text-to-address function inet_aton. ++ Copyright (C) 1998-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, see ++ . */ ++ ++#include + #include + #include + #include + #include + #include + +- +-static struct tests ++static const struct tests + { + const char *input; + int valid; +@@ -16,6 +34,7 @@ static struct tests + { "-1", 0, 0 }, + { "256", 1, 0x00000100 }, + { "256.", 0, 0 }, ++ { "255a", 0, 0 }, + { "256a", 0, 0 }, + { "0x100", 1, 0x00000100 }, + { "0200.0x123456", 1, 0x80123456 }, +@@ -40,7 +59,12 @@ static struct tests + { "1.2.256.4", 0, 0 }, + { "1.2.3.0x100", 0, 0 }, + { "323543357756889", 0, 0 }, +- { "10.1.2.3.4", 0, 0}, ++ { "10.1.2.3.4", 0, 0 }, ++ { "192.0.2.1", 1, 0xc0000201 }, ++ { "192.0.2.2\nX", 1, 0xc0000202 }, ++ { "192.0.2.3 Y", 1, 0xc0000203 }, ++ { "192.0.2.3Z", 0, 0 }, ++ { "192.000.002.010", 1, 0xc0000208 }, + }; + + +@@ -50,7 +74,7 @@ do_test (void) + int result = 0; + size_t cnt; + +- for (cnt = 0; cnt < sizeof (tests) / sizeof (tests[0]); ++cnt) ++ for (cnt = 0; cnt < array_length (tests); ++cnt) + { + struct in_addr addr; + +@@ -73,5 +97,4 @@ do_test (void) + return result; + } + +-#define TEST_FUNCTION do_test () +-#include "../test-skeleton.c" ++#include +diff --git a/resolv/tst-inet_aton_exact.c b/resolv/tst-inet_aton_exact.c +new file mode 100644 +index 0000000000000000..0fdfa3d6aa9aef91 +--- /dev/null ++++ b/resolv/tst-inet_aton_exact.c +@@ -0,0 +1,47 @@ ++/* Test internal legacy IPv4 text-to-address function __inet_aton_exact. ++ 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, see ++ . */ ++ ++#include ++#include ++ ++static int ++do_test (void) ++{ ++ struct in_addr addr = { }; ++ ++ TEST_COMPARE (__inet_aton_exact ("192.0.2.1", &addr), 1); ++ TEST_COMPARE (ntohl (addr.s_addr), 0xC0000201); ++ ++ TEST_COMPARE (__inet_aton_exact ("192.000.002.010", &addr), 1); ++ TEST_COMPARE (ntohl (addr.s_addr), 0xC0000208); ++ TEST_COMPARE (__inet_aton_exact ("0xC0000234", &addr), 1); ++ TEST_COMPARE (ntohl (addr.s_addr), 0xC0000234); ++ ++ /* Trailing content is not accepted. */ ++ TEST_COMPARE (__inet_aton_exact ("192.0.2.2X", &addr), 0); ++ TEST_COMPARE (__inet_aton_exact ("192.0.2.3 Y", &addr), 0); ++ TEST_COMPARE (__inet_aton_exact ("192.0.2.4\nZ", &addr), 0); ++ TEST_COMPARE (__inet_aton_exact ("192.0.2.5\tT", &addr), 0); ++ TEST_COMPARE (__inet_aton_exact ("192.0.2.6 Y", &addr), 0); ++ TEST_COMPARE (__inet_aton_exact ("192.0.2.7\n", &addr), 0); ++ TEST_COMPARE (__inet_aton_exact ("192.0.2.8\t", &addr), 0); ++ ++ return 0; ++} ++ ++#include +diff --git a/resolv/tst-resolv-nondecimal.c b/resolv/tst-resolv-nondecimal.c +new file mode 100644 +index 0000000000000000..a0df6f332ae8faf7 +--- /dev/null ++++ b/resolv/tst-resolv-nondecimal.c +@@ -0,0 +1,139 @@ ++/* Test name resolution behavior for octal, hexadecimal IPv4 addresses. ++ 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, see ++ . */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++static void ++response (const struct resolv_response_context *ctx, ++ struct resolv_response_builder *b, ++ const char *qname, uint16_t qclass, uint16_t qtype) ++{ ++ /* The tests are not supposed send any DNS queries. */ ++ FAIL_EXIT1 ("unexpected DNS query for %s/%d/%d", qname, qclass, qtype); ++} ++ ++static void ++run_query_addrinfo (const char *query, const char *address) ++{ ++ char *quoted_query = support_quote_string (query); ++ ++ struct addrinfo *ai; ++ struct addrinfo hints = ++ { ++ .ai_socktype = SOCK_STREAM, ++ .ai_protocol = IPPROTO_TCP, ++ }; ++ ++ char *context = xasprintf ("getaddrinfo \"%s\" AF_INET", quoted_query); ++ char *expected = xasprintf ("address: STREAM/TCP %s 80\n", address); ++ hints.ai_family = AF_INET; ++ int ret = getaddrinfo (query, "80", &hints, &ai); ++ check_addrinfo (context, ai, ret, expected); ++ if (ret == 0) ++ freeaddrinfo (ai); ++ free (context); ++ ++ context = xasprintf ("getaddrinfo \"%s\" AF_UNSPEC", quoted_query); ++ hints.ai_family = AF_UNSPEC; ++ ret = getaddrinfo (query, "80", &hints, &ai); ++ check_addrinfo (context, ai, ret, expected); ++ if (ret == 0) ++ freeaddrinfo (ai); ++ free (expected); ++ free (context); ++ ++ context = xasprintf ("getaddrinfo \"%s\" AF_INET6", quoted_query); ++ expected = xasprintf ("flags: AI_V4MAPPED\n" ++ "address: STREAM/TCP ::ffff:%s 80\n", ++ address); ++ hints.ai_family = AF_INET6; ++ hints.ai_flags = AI_V4MAPPED; ++ ret = getaddrinfo (query, "80", &hints, &ai); ++ check_addrinfo (context, ai, ret, expected); ++ if (ret == 0) ++ freeaddrinfo (ai); ++ free (expected); ++ free (context); ++ ++ free (quoted_query); ++} ++ ++static void ++run_query (const char *query, const char *address) ++{ ++ char *quoted_query = support_quote_string (query); ++ char *context = xasprintf ("gethostbyname (\"%s\")", quoted_query); ++ char *expected = xasprintf ("name: %s\n" ++ "address: %s\n", query, address); ++ check_hostent (context, gethostbyname (query), expected); ++ free (context); ++ ++ context = xasprintf ("gethostbyname_r \"%s\"", quoted_query); ++ struct hostent storage; ++ char buf[4096]; ++ struct hostent *e = NULL; ++ TEST_COMPARE (gethostbyname_r (query, &storage, buf, sizeof (buf), ++ &e, &h_errno), 0); ++ check_hostent (context, e, expected); ++ free (context); ++ ++ context = xasprintf ("gethostbyname2 (\"%s\", AF_INET)", quoted_query); ++ check_hostent (context, gethostbyname2 (query, AF_INET), expected); ++ free (context); ++ ++ context = xasprintf ("gethostbyname2_r \"%s\" AF_INET", quoted_query); ++ e = NULL; ++ TEST_COMPARE (gethostbyname2_r (query, AF_INET, &storage, buf, sizeof (buf), ++ &e, &h_errno), 0); ++ check_hostent (context, e, expected); ++ free (context); ++ free (expected); ++ ++ free (quoted_query); ++ ++ /* The gethostbyname tests are always valid for getaddrinfo, but not ++ vice versa. */ ++ run_query_addrinfo (query, address); ++} ++ ++static int ++do_test (void) ++{ ++ struct resolv_test *aux = resolv_test_start ++ ((struct resolv_redirect_config) ++ { ++ .response_callback = response, ++ }); ++ ++ run_query ("192.000.002.010", "192.0.2.8"); ++ ++ /* Hexadecimal numbers are not accepted by gethostbyname. */ ++ run_query_addrinfo ("0xc0000210", "192.0.2.16"); ++ run_query_addrinfo ("192.0x234", "192.0.2.52"); ++ ++ resolv_test_end (aux); ++ ++ return 0; ++} ++ ++#include +diff --git a/resolv/tst-resolv-trailing.c b/resolv/tst-resolv-trailing.c +new file mode 100644 +index 0000000000000000..7504bdae572ed8d0 +--- /dev/null ++++ b/resolv/tst-resolv-trailing.c +@@ -0,0 +1,136 @@ ++/* Test name resolution behavior with trailing characters. ++ 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, see ++ . */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++static void ++response (const struct resolv_response_context *ctx, ++ struct resolv_response_builder *b, ++ const char *qname, uint16_t qclass, uint16_t qtype) ++{ ++ /* The tests are not supposed send any DNS queries. */ ++ FAIL_EXIT1 ("unexpected DNS query for %s/%d/%d", qname, qclass, qtype); ++} ++ ++static int ++do_test (void) ++{ ++ struct resolv_test *aux = resolv_test_start ++ ((struct resolv_redirect_config) ++ { ++ .response_callback = response, ++ }); ++ ++ static const char *const queries[] = ++ { ++ "192.0.2.1 ", ++ "192.0.2.2\t", ++ "192.0.2.3\n", ++ "192.0.2.4 X", ++ "192.0.2.5\tY", ++ "192.0.2.6\nZ", ++ "192.0.2. ", ++ "192.0.2.\t", ++ "192.0.2.\n", ++ "192.0.2. X", ++ "192.0.2.\tY", ++ "192.0.2.\nZ", ++ "2001:db8::1 ", ++ "2001:db8::2\t", ++ "2001:db8::3\n", ++ "2001:db8::4 X", ++ "2001:db8::5\tY", ++ "2001:db8::6\nZ", ++ }; ++ for (size_t query_idx = 0; query_idx < array_length (queries); ++query_idx) ++ { ++ const char *query = queries[query_idx]; ++ struct hostent storage; ++ char buf[4096]; ++ struct hostent *e; ++ ++ h_errno = 0; ++ TEST_VERIFY (gethostbyname (query) == NULL); ++ TEST_COMPARE (h_errno, HOST_NOT_FOUND); ++ ++ h_errno = 0; ++ e = NULL; ++ TEST_COMPARE (gethostbyname_r (query, &storage, buf, sizeof (buf), ++ &e, &h_errno), 0); ++ TEST_VERIFY (e == NULL); ++ TEST_COMPARE (h_errno, HOST_NOT_FOUND); ++ ++ h_errno = 0; ++ TEST_VERIFY (gethostbyname2 (query, AF_INET) == NULL); ++ TEST_COMPARE (h_errno, HOST_NOT_FOUND); ++ ++ h_errno = 0; ++ e = NULL; ++ TEST_COMPARE (gethostbyname2_r (query, AF_INET, ++ &storage, buf, sizeof (buf), ++ &e, &h_errno), 0); ++ TEST_VERIFY (e == NULL); ++ TEST_COMPARE (h_errno, HOST_NOT_FOUND); ++ ++ h_errno = 0; ++ TEST_VERIFY (gethostbyname2 (query, AF_INET6) == NULL); ++ TEST_COMPARE (h_errno, HOST_NOT_FOUND); ++ ++ h_errno = 0; ++ e = NULL; ++ TEST_COMPARE (gethostbyname2_r (query, AF_INET6, ++ &storage, buf, sizeof (buf), ++ &e, &h_errno), 0); ++ TEST_VERIFY (e == NULL); ++ TEST_COMPARE (h_errno, HOST_NOT_FOUND); ++ ++ static const int gai_flags[] = ++ { ++ 0, ++ AI_ADDRCONFIG, ++ AI_NUMERICHOST, ++ AI_IDN, ++ AI_IDN | AI_NUMERICHOST, ++ AI_V4MAPPED, ++ AI_V4MAPPED | AI_NUMERICHOST, ++ }; ++ for (size_t gai_flags_idx; gai_flags_idx < array_length (gai_flags); ++ ++gai_flags_idx) ++ { ++ struct addrinfo hints = { .ai_flags = gai_flags[gai_flags_idx], }; ++ struct addrinfo *ai; ++ hints.ai_family = AF_INET; ++ TEST_COMPARE (getaddrinfo (query, "80", &hints, &ai), EAI_NONAME); ++ hints.ai_family = AF_INET6; ++ TEST_COMPARE (getaddrinfo (query, "80", &hints, &ai), EAI_NONAME); ++ hints.ai_family = AF_UNSPEC; ++ TEST_COMPARE (getaddrinfo (query, "80", &hints, &ai), EAI_NONAME); ++ } ++ }; ++ ++ resolv_test_end (aux); ++ ++ return 0; ++} ++ ++#include +diff --git a/sysdeps/posix/getaddrinfo.c b/sysdeps/posix/getaddrinfo.c +index 00e0d94a8f5bb30d..6a5805c9e63a257c 100644 +--- a/sysdeps/posix/getaddrinfo.c ++++ b/sysdeps/posix/getaddrinfo.c +@@ -488,7 +488,7 @@ gaih_inet (const char *name, const struct gaih_service *service, + malloc_name = true; + } + +- if (__inet_aton (name, (struct in_addr *) at->addr) != 0) ++ if (__inet_aton_exact (name, (struct in_addr *) at->addr) != 0) + { + if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET) + at->family = AF_INET; diff --git a/SOURCES/glibc-rh1735747-1.patch b/SOURCES/glibc-rh1735747-1.patch new file mode 100644 index 0000000..04c4136 --- /dev/null +++ b/SOURCES/glibc-rh1735747-1.patch @@ -0,0 +1,25 @@ +commit 6d750b18999b52ec74102c046cd27181f943bda8 +Author: Florian Weimer +Date: Thu Aug 1 14:06:24 2019 +0200 + + malloc: Remove unwanted leading whitespace in malloc_info [BZ #24867] + + It was introduced in commit 6c8dbf00f536d78b1937b5af6f57be47fd376344 + ("Reformat malloc to gnu style."). + + Reviewed-by: Carlos O'Donell + (cherry picked from commit b0f6679bcd738ea244a14acd879d974901e56c8e) + +diff --git a/malloc/malloc.c b/malloc/malloc.c +index e6a483d5cf7c4312..4fc7f175fe42d6c6 100644 +--- a/malloc/malloc.c ++++ b/malloc/malloc.c +@@ -5518,7 +5518,7 @@ __malloc_info (int options, FILE *fp) + + for (size_t i = 0; i < nsizes; ++i) + if (sizes[i].count != 0 && i != NFASTBINS) +- fprintf (fp, " \ ++ fprintf (fp, "\ + \n", + sizes[i].from, sizes[i].to, sizes[i].total, sizes[i].count); + diff --git a/SOURCES/glibc-rh1735747-2.patch b/SOURCES/glibc-rh1735747-2.patch new file mode 100644 index 0000000..e2afd28 --- /dev/null +++ b/SOURCES/glibc-rh1735747-2.patch @@ -0,0 +1,35 @@ +commit 91d5989356325759503311df67e750b358ef4148 +Author: Niklas Hambüchen +Date: Thu Aug 8 22:02:27 2019 +0200 + + malloc: Fix missing accounting of top chunk in malloc_info [BZ #24026] + + Fixes ` incorrectly showing as 0 most + of the time. + + The rest value being wrong is significant because to compute the + actual amount of memory handed out via malloc, the user must subtract + it from . That result being wrong + makes investigating memory fragmentation issues like + close to + impossible. + + (cherry picked from commit b6d2c4475d5abc05dd009575b90556bdd3c78ad0) + +diff --git a/malloc/malloc.c b/malloc/malloc.c +index 4fc7f175fe42d6c6..fcf480acdaea1b86 100644 +--- a/malloc/malloc.c ++++ b/malloc/malloc.c +@@ -5433,6 +5433,12 @@ __malloc_info (int options, FILE *fp) + + __libc_lock_lock (ar_ptr->mutex); + ++ /* Account for top chunk. The top-most available chunk is ++ treated specially and is never in any bin. See "initial_top" ++ comments. */ ++ avail = chunksize (ar_ptr->top); ++ nblocks = 1; /* Top always exists. */ ++ + for (size_t i = 0; i < NFASTBINS; ++i) + { + mchunkptr p = fastbin (ar_ptr, i); diff --git a/SOURCES/glibc-rh1743445-1.patch b/SOURCES/glibc-rh1743445-1.patch new file mode 100644 index 0000000..759879a --- /dev/null +++ b/SOURCES/glibc-rh1743445-1.patch @@ -0,0 +1,151 @@ +From: Ian Kent +Date: Mon, 2 Sep 2019 11:26:14 +0000 (+0200) +Subject: Use autofs "ignore" mount hint in getmntent_r/getmntent +X-Git-Tag: changelog-ends-here~75 +X-Git-Url: https://sourceware.org/git/?p=glibc.git;a=commitdiff_plain;h=08b7e9988272113ca5640cf5e115ea51449fb392 + +Use autofs "ignore" mount hint in getmntent_r/getmntent + +Historically autofs mounts were not included in mount table +listings. This is the case in other SysV autofs implementations +and was also the case with Linux autofs. + +But now that /etc/mtab is a symlink to the proc filesystem +mount table the autofs mount entries appear in the mount table +on Linux. + +Prior to the symlinking of /etc/mtab mount table it was +sufficient to call mount(2) and simply not update /etc/mtab +to exclude autofs mounts from mount listings. + +Also, with the symlinking of /etc/mtab we have seen a shift in +usage toward using the proc mount tables directly. + +But the autofs mount entries need to be retained when coming +from the proc file system for applications that need them +(largely autofs file system users themselves) so filtering out +these entries within the kernel itself can't be done. So it +needs be done in user space. + +There are three reasons to omit the autofs mount entries. + +One is that certain types of auto-mounts have an autofs mount +for every entry in their autofs mount map and these maps can +be quite large. This leads to mount table listings containing +a lot of unnecessary entries. + +Also, this change in behaviour between autofs implementations +can cause problems for applications that use getmntent(3) in +other OS implementations as well as Linux. + +Lastly, there's very little that user space can do with autofs +mount entries since this must be left to the autofs mount owner, +typically the automount daemon. But it can also lead to attempts +to access automount managed paths resulting mounts being triggered +when they aren't needed or mounts staying mounted for much longer +thay they need be. While the point of this change ins't to help +with these problems (and it can be quite a problem) it may be +a welcome side effect. + +So the Linux autofs file system has been modified to accept a +pseudo mount option of "ignore" (as is used in other OS +implementations) so that user space can use this as a hint to +skip autofs entries on reading the mount table. + +The Linux autofs automount daemon used getmntent(3) itself and +has been modified to use the proc file system directly so that +it can "ignore" mount option. + +The use of this mount option is opt-in and a configuration +option has been added which defaults to not use this option +so if there are applications that need these entries, other +than autofs itself, they can be retained. Also, since this +filtering is based on an added mount option earlier versions +of Linux autofs iand other autofs file system users will not +use the option and so won't be affected by the change. +--- + +diff --git a/misc/mntent_r.c b/misc/mntent_r.c +index 5d88c45c6f..d90e8d7087 100644 +--- a/misc/mntent_r.c ++++ b/misc/mntent_r.c +@@ -18,6 +18,7 @@ + + #include + #include ++#include + #include + #include + #include +@@ -112,26 +113,18 @@ decode_name (char *buf) + return buf; + } + +- +-/* Read one mount table entry from STREAM. Returns a pointer to storage +- reused on the next call, or null for EOF or error (use feof/ferror to +- check). */ +-struct mntent * +-__getmntent_r (FILE *stream, struct mntent *mp, char *buffer, int bufsiz) ++static bool ++get_mnt_entry (FILE *stream, struct mntent *mp, char *buffer, int bufsiz) + { + char *cp; + char *head; + +- flockfile (stream); + do + { + char *end_ptr; + + if (__fgets_unlocked (buffer, bufsiz, stream) == NULL) +- { +- funlockfile (stream); +- return NULL; +- } ++ return false; + + end_ptr = strchr (buffer, '\n'); + if (end_ptr != NULL) /* chop newline */ +@@ -181,9 +174,40 @@ __getmntent_r (FILE *stream, struct mntent *mp, char *buffer, int bufsiz) + case 2: + break; + } ++ ++ return true; ++} ++ ++/* Read one mount table entry from STREAM. Returns a pointer to storage ++ reused on the next call, or null for EOF or error (use feof/ferror to ++ check). */ ++struct mntent * ++__getmntent_r (FILE *stream, struct mntent *mp, char *buffer, int bufsiz) ++{ ++ struct mntent *result; ++ ++ flockfile (stream); ++ while (true) ++ if (get_mnt_entry (stream, mp, buffer, bufsiz)) ++ { ++ /* If the file system is autofs look for a mount option hint ++ ("ignore") to skip the entry. */ ++ if (strcmp (mp->mnt_type, "autofs") == 0 && __hasmntopt (mp, "ignore")) ++ memset (mp, 0, sizeof (*mp)); ++ else ++ { ++ result = mp; ++ break; ++ } ++ } ++ else ++ { ++ result = NULL; ++ break; ++ } + funlockfile (stream); + +- return mp; ++ return result; + } + libc_hidden_def (__getmntent_r) + weak_alias (__getmntent_r, getmntent_r) diff --git a/SOURCES/glibc-rh1743445-2.patch b/SOURCES/glibc-rh1743445-2.patch new file mode 100644 index 0000000..a14fe60 --- /dev/null +++ b/SOURCES/glibc-rh1743445-2.patch @@ -0,0 +1,169 @@ +From: Florian Weimer +Date: Mon, 2 Sep 2019 10:40:38 +0000 (+0200) +Subject: Add misc/tst-mntent-autofs, testing autofs "ignore" filtering +X-Git-Tag: changelog-ends-here~74 +X-Git-Url: https://sourceware.org/git/?p=glibc.git;a=commitdiff_plain;h=9a1e7257a4292d3aea45c8317df3956f4331d8ce + +Add misc/tst-mntent-autofs, testing autofs "ignore" filtering +--- + +diff -rup a/misc/Makefile b/misc/Makefile +--- a/misc/Makefile 2020-03-25 18:30:42.275895917 -0400 ++++ b/misc/Makefile 2020-03-25 18:37:55.527738814 -0400 +@@ -84,7 +84,8 @@ tests := tst-dirname tst-tsearch tst-fds + tst-error1 tst-pselect tst-insremque tst-mntent2 bug-hsearch1 \ + tst-mntent-blank-corrupt tst-mntent-blank-passno bug18240 \ + tst-preadvwritev tst-preadvwritev64 tst-makedev tst-empty \ +- tst-preadvwritev2 tst-preadvwritev64v2 ++ tst-preadvwritev2 tst-preadvwritev64v2 \ ++ tst-mntent-autofs + + # Tests which need libdl. + ifeq (yes,$(build-shared)) +diff --git a/misc/tst-mntent-autofs.c b/misc/tst-mntent-autofs.c +new file mode 100644 +index 0000000000..bf4d4e73b4 +--- /dev/null ++++ b/misc/tst-mntent-autofs.c +@@ -0,0 +1,141 @@ ++/* Test autofs "ignore" filtering for getment_r. ++ 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, see ++ . */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++struct test_case ++{ ++ const char *line; ++ struct ++ { ++ /* Like struct mntent, but with const pointers. */ ++ const char *mnt_fsname; ++ const char *mnt_dir; ++ const char *mnt_type; ++ const char *mnt_opts; ++ int mnt_freq; ++ int mnt_passno; ++ } expected; ++}; ++ ++static struct test_case test_cases[] = ++ { ++ { "/etc/auto.direct /mnt/auto/1 autofs defaults 0 0", ++ { "/etc/auto.direct", "/mnt/auto/1", "autofs", "defaults", 0, 0 } }, ++ ++ /* These entries are filtered out. */ ++ { "/etc/auto.2 /mnt/auto/2 autofs ignore 0 0", { NULL, } }, ++ { "/etc/auto.3 /mnt/auto/3 autofs ignore,other 1 2", { NULL, } }, ++ { "/etc/auto.4 /mnt/auto/4 autofs other,ignore 3 4", { NULL, } }, ++ { "/etc/auto.5 /mnt/auto/5 autofs opt1,ignore,opt2 5 6", { NULL, } }, ++ ++ /* Dummy entry to make the desynchronization more obvious. */ ++ { "/dev/sda1 / xfs defaults 0 0", ++ { "/dev/sda1", "/", "xfs", "defaults", 0, 0 } }, ++ ++ /* These are not filtered because the file system is not autofs. */ ++ { "/etc/auto.direct /mnt/auto/6 autofs1 ignore 0 0", ++ { "/etc/auto.direct", "/mnt/auto/6", "autofs1", "ignore", 0, 0 } }, ++ { "/etc/auto.direct /mnt/auto/7 autofs1 ignore,other 0 0", ++ { "/etc/auto.direct", "/mnt/auto/7", "autofs1", "ignore,other", 0, 0 } }, ++ { "/etc/auto.direct /mnt/auto/8 autofs1 other,ignore 0 0", ++ { "/etc/auto.direct", "/mnt/auto/8", "autofs1", "other,ignore", 0, 0 } }, ++ { "/etc/auto.direct /mnt/auto/9 autofs1 opt1,ignore,opt2 0 0", ++ { "/etc/auto.direct", "/mnt/auto/9", "autofs1", "opt1,ignore,opt2", } }, ++ ++ /* These are not filtered because the string "ignore" is not an ++ option name. */ ++ { "/etc/auto.direct /mnt/auto/10 autofs noignore 1 2", ++ { "/etc/auto.direct", "/mnt/auto/10", "autofs", "noignore", 1, 2 } }, ++ { "/etc/auto.direct /mnt/auto/11 autofs noignore,other 0 0", ++ { "/etc/auto.direct", "/mnt/auto/11", "autofs", "noignore,other", } }, ++ { "/etc/auto.direct /mnt/auto/12 autofs other,noignore 0 0", ++ { "/etc/auto.direct", "/mnt/auto/12", "autofs", "other,noignore", } }, ++ { "/etc/auto.direct /mnt/auto/13 autofs errors=ignore 0 0", ++ { "/etc/auto.direct", "/mnt/auto/13", "autofs", "errors=ignore", } }, ++ { "/etc/auto.direct /mnt/auto/14 autofs errors=ignore,other 0 0", ++ { "/etc/auto.direct", "/mnt/auto/14", "autofs", ++ "errors=ignore,other", } }, ++ { "/etc/auto.direct /mnt/auto/15 autofs other,errors=ignore 0 0", ++ { "/etc/auto.direct", "/mnt/auto/15", "autofs", ++ "other,errors=ignore", } }, ++ ++ /* These are not filtered because the string is escaped. '\151' ++ is 'i', but it is not actually decoded by the parser. */ ++ { "/etc/auto.\\151gnore /mnt/auto/16 autofs \\151gnore 0 0", ++ { "/etc/auto.\\151gnore", "/mnt/auto/16", "autofs", ++ "\\151gnore", } }, ++ }; ++ ++static int ++do_test (void) ++{ ++ char *path; ++ xclose (create_temp_file ("tst-mntent-autofs-", &path)); ++ ++ /* Write the test file. */ ++ FILE *fp = xfopen (path, "w"); ++ for (size_t i = 0; i < array_length (test_cases); ++i) ++ fprintf (fp, "%s\n", test_cases[i].line); ++ xfclose (fp); ++ ++ /* Open the test file again, this time for parsing. */ ++ fp = setmntent (path, "r"); ++ TEST_VERIFY_EXIT (fp != NULL); ++ char buffer[512]; ++ struct mntent me; ++ ++ for (size_t i = 0; i < array_length (test_cases); ++i) ++ { ++ if (test_cases[i].expected.mnt_type == NULL) ++ continue; ++ ++ memset (buffer, 0xcc, sizeof (buffer)); ++ memset (&me, 0xcc, sizeof (me)); ++ struct mntent *pme = getmntent_r (fp, &me, buffer, sizeof (buffer)); ++ TEST_VERIFY_EXIT (pme != NULL); ++ TEST_VERIFY (pme == &me); ++ TEST_COMPARE_STRING (test_cases[i].expected.mnt_fsname, me.mnt_fsname); ++ TEST_COMPARE_STRING (test_cases[i].expected.mnt_dir, me.mnt_dir); ++ TEST_COMPARE_STRING (test_cases[i].expected.mnt_type, me.mnt_type); ++ TEST_COMPARE_STRING (test_cases[i].expected.mnt_opts, me.mnt_opts); ++ TEST_COMPARE (test_cases[i].expected.mnt_freq, me.mnt_freq); ++ TEST_COMPARE (test_cases[i].expected.mnt_passno, me.mnt_passno); ++ } ++ ++ TEST_VERIFY (getmntent_r (fp, &me, buffer, sizeof (buffer)) == NULL); ++ ++ TEST_COMPARE (feof (fp), 1); ++ TEST_COMPARE (ferror (fp), 0); ++ errno = 0; ++ TEST_COMPARE (endmntent (fp), 1); ++ TEST_COMPARE (errno, 0); ++ free (path); ++ return 0; ++} ++ ++#include diff --git a/SOURCES/glibc-rh1746928.patch b/SOURCES/glibc-rh1746928.patch new file mode 100644 index 0000000..c21eb1d --- /dev/null +++ b/SOURCES/glibc-rh1746928.patch @@ -0,0 +1,117 @@ +commit 669ff911e2571f74a2668493e326ac9a505776bd +Author: Florian Weimer +Date: Fri Feb 8 12:46:19 2019 +0100 + + nptl: Avoid fork handler lock for async-signal-safe fork [BZ #24161] + + Commit 27761a1042daf01987e7d79636d0c41511c6df3c ("Refactor atfork + handlers") introduced a lock, atfork_lock, around fork handler list + accesses. It turns out that this lock occasionally results in + self-deadlocks in malloc/tst-mallocfork2: + + (gdb) bt + #0 __lll_lock_wait_private () + at ../sysdeps/unix/sysv/linux/x86_64/lowlevellock.S:63 + #1 0x00007f160c6f927a in __run_fork_handlers (who=(unknown: 209394016), + who@entry=atfork_run_prepare) at register-atfork.c:116 + #2 0x00007f160c6b7897 in __libc_fork () at ../sysdeps/nptl/fork.c:58 + #3 0x00000000004027d6 in sigusr1_handler (signo=) + at tst-mallocfork2.c:80 + #4 sigusr1_handler (signo=) at tst-mallocfork2.c:64 + #5 + #6 0x00007f160c6f92e4 in __run_fork_handlers (who=who@entry=atfork_run_parent) + at register-atfork.c:136 + #7 0x00007f160c6b79a2 in __libc_fork () at ../sysdeps/nptl/fork.c:152 + #8 0x0000000000402567 in do_test () at tst-mallocfork2.c:156 + #9 0x0000000000402dd2 in support_test_main (argc=1, argv=0x7ffc81ef1ab0, + config=config@entry=0x7ffc81ef1970) at support_test_main.c:350 + #10 0x0000000000402362 in main (argc=, argv=) + at ../support/test-driver.c:168 + + If no locking happens in the single-threaded case (where fork is + expected to be async-signal-safe), this deadlock is avoided. + (pthread_atfork is not required to be async-signal-safe, so a fork + call from a signal handler interrupting pthread_atfork is not + a problem.) + +diff --git a/nptl/register-atfork.c b/nptl/register-atfork.c +index bc797b7..80a1bec 100644 +--- a/nptl/register-atfork.c ++++ b/nptl/register-atfork.c +@@ -107,13 +107,14 @@ __unregister_atfork (void *dso_handle) + } + + void +-__run_fork_handlers (enum __run_fork_handler_type who) ++__run_fork_handlers (enum __run_fork_handler_type who, _Bool do_locking) + { + struct fork_handler *runp; + + if (who == atfork_run_prepare) + { +- lll_lock (atfork_lock, LLL_PRIVATE); ++ 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--) + { +@@ -133,7 +134,8 @@ __run_fork_handlers (enum __run_fork_handler_type who) + else if (who == atfork_run_parent && runp->parent_handler) + runp->parent_handler (); + } +- lll_unlock (atfork_lock, LLL_PRIVATE); ++ if (do_locking) ++ lll_unlock (atfork_lock, LLL_PRIVATE); + } + } + +diff --git a/sysdeps/nptl/fork.c b/sysdeps/nptl/fork.c +index bd68f18..14b69a6 100644 +--- a/sysdeps/nptl/fork.c ++++ b/sysdeps/nptl/fork.c +@@ -55,7 +55,7 @@ __libc_fork (void) + but our current fork implementation is not. */ + bool multiple_threads = THREAD_GETMEM (THREAD_SELF, header.multiple_threads); + +- __run_fork_handlers (atfork_run_prepare); ++ __run_fork_handlers (atfork_run_prepare, 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 +@@ -134,7 +134,7 @@ __libc_fork (void) + __rtld_lock_initialize (GL(dl_load_lock)); + + /* Run the handlers registered for the child. */ +- __run_fork_handlers (atfork_run_child); ++ __run_fork_handlers (atfork_run_child, multiple_threads); + } + else + { +@@ -149,7 +149,7 @@ __libc_fork (void) + } + + /* Run the handlers registered for the parent. */ +- __run_fork_handlers (atfork_run_parent); ++ __run_fork_handlers (atfork_run_parent, multiple_threads); + } + + return pid; +diff --git a/sysdeps/nptl/fork.h b/sysdeps/nptl/fork.h +index a1c3b26..99ed760 100644 +--- a/sysdeps/nptl/fork.h ++++ b/sysdeps/nptl/fork.h +@@ -52,9 +52,11 @@ enum __run_fork_handler_type + - 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. */ +-extern void __run_fork_handlers (enum __run_fork_handler_type who) +- attribute_hidden; ++ lock. ++ ++ Perform locking only if DO_LOCKING. */ ++extern void __run_fork_handlers (enum __run_fork_handler_type who, ++ _Bool do_locking) attribute_hidden; + + /* C library side function to register new fork handlers. */ + extern int __register_atfork (void (*__prepare) (void), diff --git a/SOURCES/glibc-rh1746933-1.patch b/SOURCES/glibc-rh1746933-1.patch new file mode 100644 index 0000000..4697916 --- /dev/null +++ b/SOURCES/glibc-rh1746933-1.patch @@ -0,0 +1,60 @@ +commit 58d2672f64176fcb323859d3bd5240fb1cf8f25c +Author: Wilco Dijkstra +Date: Fri May 10 16:38:21 2019 +0100 + + Fix tcache count maximum (BZ #24531) + + The tcache counts[] array is a char, which has a very small range and thus + may overflow. When setting tcache_count tunable, there is no overflow check. + However the tunable must not be larger than the maximum value of the tcache + counts[] array, otherwise it can overflow when filling the tcache. + + [BZ #24531] + * malloc/malloc.c (MAX_TCACHE_COUNT): New define. + (do_set_tcache_count): Only update if count is small enough. + * manual/tunables.texi (glibc.malloc.tcache_count): Document max value. + + (cherry picked from commit 5ad533e8e65092be962e414e0417112c65d154fb) + +diff --git a/malloc/malloc.c b/malloc/malloc.c +index 723d393f529bdb4c..92239b3324584060 100644 +--- a/malloc/malloc.c ++++ b/malloc/malloc.c +@@ -2919,6 +2919,8 @@ typedef struct tcache_perthread_struct + tcache_entry *entries[TCACHE_MAX_BINS]; + } tcache_perthread_struct; + ++#define MAX_TCACHE_COUNT 127 /* Maximum value of counts[] entries. */ ++ + static __thread bool tcache_shutting_down = false; + static __thread tcache_perthread_struct *tcache = NULL; + +@@ -5124,8 +5126,11 @@ static inline int + __always_inline + do_set_tcache_count (size_t value) + { +- LIBC_PROBE (memory_tunable_tcache_count, 2, value, mp_.tcache_count); +- mp_.tcache_count = value; ++ if (value <= MAX_TCACHE_COUNT) ++ { ++ LIBC_PROBE (memory_tunable_tcache_count, 2, value, mp_.tcache_count); ++ mp_.tcache_count = value; ++ } + return 1; + } + +diff --git a/manual/tunables.texi b/manual/tunables.texi +index bb4819bdf1de273e..9dccf2ee7f8eec17 100644 +--- a/manual/tunables.texi ++++ b/manual/tunables.texi +@@ -188,8 +188,8 @@ per-thread cache. The default (and maximum) value is 1032 bytes on + + @deftp Tunable glibc.malloc.tcache_count + The maximum number of chunks of each size to cache. The default is 7. +-There is no upper limit, other than available system memory. If set +-to zero, the per-thread cache is effectively disabled. ++The upper limit is 127. If set to zero, the per-thread cache is effectively ++disabled. + + The approximate maximum overhead of the per-thread cache is thus equal + to the number of bins times the chunk count in each bin times the size diff --git a/SOURCES/glibc-rh1746933-2.patch b/SOURCES/glibc-rh1746933-2.patch new file mode 100644 index 0000000..97fc261 --- /dev/null +++ b/SOURCES/glibc-rh1746933-2.patch @@ -0,0 +1,37 @@ +commit 3640758943c856268bc12a3307838c2a65d2f9ea +Author: Joseph Myers +Date: Mon Feb 4 23:46:58 2019 +0000 + + Fix assertion in malloc.c:tcache_get. + + One of the warnings that appears with -Wextra is "ordered comparison + of pointer with integer zero" in malloc.c:tcache_get, for the + assertion: + + assert (tcache->entries[tc_idx] > 0); + + Indeed, a "> 0" comparison does not make sense for + tcache->entries[tc_idx], which is a pointer. My guess is that + tcache->counts[tc_idx] is what's intended here, and this patch changes + the assertion accordingly. + + Tested for x86_64. + + * malloc/malloc.c (tcache_get): Compare tcache->counts[tc_idx] + with 0, not tcache->entries[tc_idx]. + + (cherry picked from commit 77dc0d8643aa99c92bf671352b0a8adde705896f) + +diff --git a/malloc/malloc.c b/malloc/malloc.c +index 92239b3324584060..998879aededf0d7c 100644 +--- a/malloc/malloc.c ++++ b/malloc/malloc.c +@@ -2948,7 +2948,7 @@ tcache_get (size_t tc_idx) + { + tcache_entry *e = tcache->entries[tc_idx]; + assert (tc_idx < TCACHE_MAX_BINS); +- assert (tcache->entries[tc_idx] > 0); ++ assert (tcache->counts[tc_idx] > 0); + tcache->entries[tc_idx] = e->next; + --(tcache->counts[tc_idx]); + e->key = NULL; diff --git a/SOURCES/glibc-rh1746933-3.patch b/SOURCES/glibc-rh1746933-3.patch new file mode 100644 index 0000000..f4c1c95 --- /dev/null +++ b/SOURCES/glibc-rh1746933-3.patch @@ -0,0 +1,92 @@ +commit f88c59f4657ac2e0bab8f51f60022ecbe7f12e2e +Author: Wilco Dijkstra +Date: Fri May 17 18:16:20 2019 +0100 + + Small tcache improvements + + Change the tcache->counts[] entries to uint16_t - this removes + the limit set by char and allows a larger tcache. Remove a few + redundant asserts. + + bench-malloc-thread with 4 threads is ~15% faster on Cortex-A72. + + Reviewed-by: DJ Delorie + + * malloc/malloc.c (MAX_TCACHE_COUNT): Increase to UINT16_MAX. + (tcache_put): Remove redundant assert. + (tcache_get): Remove redundant asserts. + (__libc_malloc): Check tcache count is not zero. + * manual/tunables.texi (glibc.malloc.tcache_count): Update maximum. + + (cherry picked from commit 1f50f2ad854c84ead522bfc7331b46dbe6057d53) + +diff --git a/malloc/malloc.c b/malloc/malloc.c +index 998879aededf0d7c..e6a483d5cf7c4312 100644 +--- a/malloc/malloc.c ++++ b/malloc/malloc.c +@@ -321,6 +321,10 @@ __malloc_assert (const char *assertion, const char *file, unsigned int line, + /* This is another arbitrary limit, which tunables can change. Each + tcache bin will hold at most this number of chunks. */ + # define TCACHE_FILL_COUNT 7 ++ ++/* Maximum chunks in tcache bins for tunables. This value must fit the range ++ of tcache->counts[] entries, else they may overflow. */ ++# define MAX_TCACHE_COUNT UINT16_MAX + #endif + + +@@ -2915,12 +2919,10 @@ typedef struct tcache_entry + time), this is for performance reasons. */ + typedef struct tcache_perthread_struct + { +- char counts[TCACHE_MAX_BINS]; ++ uint16_t counts[TCACHE_MAX_BINS]; + tcache_entry *entries[TCACHE_MAX_BINS]; + } tcache_perthread_struct; + +-#define MAX_TCACHE_COUNT 127 /* Maximum value of counts[] entries. */ +- + static __thread bool tcache_shutting_down = false; + static __thread tcache_perthread_struct *tcache = NULL; + +@@ -2930,7 +2932,6 @@ static __always_inline void + tcache_put (mchunkptr chunk, size_t tc_idx) + { + tcache_entry *e = (tcache_entry *) chunk2mem (chunk); +- assert (tc_idx < TCACHE_MAX_BINS); + + /* Mark this chunk as "in the tcache" so the test in _int_free will + detect a double free. */ +@@ -2947,8 +2948,6 @@ static __always_inline void * + tcache_get (size_t tc_idx) + { + tcache_entry *e = tcache->entries[tc_idx]; +- assert (tc_idx < TCACHE_MAX_BINS); +- assert (tcache->counts[tc_idx] > 0); + tcache->entries[tc_idx] = e->next; + --(tcache->counts[tc_idx]); + e->key = NULL; +@@ -3053,9 +3052,8 @@ __libc_malloc (size_t bytes) + + DIAG_PUSH_NEEDS_COMMENT; + if (tc_idx < mp_.tcache_bins +- /*&& tc_idx < TCACHE_MAX_BINS*/ /* to appease gcc */ + && tcache +- && tcache->entries[tc_idx] != NULL) ++ && tcache->counts[tc_idx] > 0) + { + return tcache_get (tc_idx); + } +diff --git a/manual/tunables.texi b/manual/tunables.texi +index 9dccf2ee7f8eec17..f6c49250e3889ddd 100644 +--- a/manual/tunables.texi ++++ b/manual/tunables.texi +@@ -188,7 +188,7 @@ per-thread cache. The default (and maximum) value is 1032 bytes on + + @deftp Tunable glibc.malloc.tcache_count + The maximum number of chunks of each size to cache. The default is 7. +-The upper limit is 127. If set to zero, the per-thread cache is effectively ++The upper limit is 65535. If set to zero, the per-thread cache is effectively + disabled. + + The approximate maximum overhead of the per-thread cache is thus equal diff --git a/SOURCES/glibc-rh1747453.patch b/SOURCES/glibc-rh1747453.patch new file mode 100644 index 0000000..d02b6b2 --- /dev/null +++ b/SOURCES/glibc-rh1747453.patch @@ -0,0 +1,156 @@ +commit 8692ebdb1259be60c545fa509d4852b26703777e +Author: David Newall +Date: Mon Feb 4 13:35:11 2019 +0100 + + elf: Implement --preload option for the dynamic linker + +diff --git a/elf/Makefile b/elf/Makefile +index 9cf5cd8dfd..db6a2a0c29 100644 +--- a/elf/Makefile ++++ b/elf/Makefile +@@ -354,7 +354,8 @@ endif + + ifeq (yes,$(build-shared)) + ifeq ($(run-built-tests),yes) +-tests-special += $(objpfx)tst-pathopt.out $(objpfx)tst-rtld-load-self.out ++tests-special += $(objpfx)tst-pathopt.out $(objpfx)tst-rtld-load-self.out \ ++ $(objpfx)tst-rtld-preload.out + endif + tests-special += $(objpfx)check-textrel.out $(objpfx)check-execstack.out \ + $(objpfx)check-localplt.out $(objpfx)check-initfini.out +@@ -883,6 +884,15 @@ $(objpfx)tst-rtld-load-self.out: tst-rtld-load-self.sh $(objpfx)ld.so + $(SHELL) $^ '$(test-wrapper)' '$(test-wrapper-env)' > $@; \ + $(evaluate-test) + ++tst-rtld-preload-OBJS = $(subst $(empty) ,:,$(strip $(preloadtest-preloads:=.so))) ++$(objpfx)tst-rtld-preload.out: tst-rtld-preload.sh $(objpfx)ld.so \ ++ $(objpfx)preloadtest \ ++ $(preloadtest-preloads:%=$(objpfx)%.so) ++ $(SHELL) $< $(objpfx)ld.so $(objpfx)preloadtest \ ++ '$(test-wrapper)' '$(test-wrapper-env)' '$(run_program_env)' \ ++ '$(rpath-link)' '$(tst-rtld-preload-OBJS)' > $@; \ ++ $(evaluate-test) ++ + $(objpfx)initfirst: $(libdl) + $(objpfx)initfirst.out: $(objpfx)firstobj.so + +diff --git a/elf/rtld.c b/elf/rtld.c +index 5d97f41b7b..5a90e78ed6 100644 +--- a/elf/rtld.c ++++ b/elf/rtld.c +@@ -826,15 +826,18 @@ static const char *library_path attribute_relro; + static const char *preloadlist attribute_relro; + /* Nonzero if information about versions has to be printed. */ + static int version_info attribute_relro; ++/* The preload list passed as a command argument. */ ++static const char *preloadarg attribute_relro; + + /* The LD_PRELOAD environment variable gives list of libraries + separated by white space or colons that are loaded before the + executable's dependencies and prepended to the global scope list. + (If the binary is running setuid all elements containing a '/' are + ignored since it is insecure.) Return the number of preloads +- performed. */ ++ performed. Ditto for --preload command argument. */ + unsigned int +-handle_ld_preload (const char *preloadlist, struct link_map *main_map) ++handle_preload_list (const char *preloadlist, struct link_map *main_map, ++ const char *where) + { + unsigned int npreloads = 0; + const char *p = preloadlist; +@@ -858,7 +861,7 @@ handle_ld_preload (const char *preloadlist, struct link_map *main_map) + ++p; + + if (dso_name_valid_for_suid (fname)) +- npreloads += do_preload (fname, main_map, "LD_PRELOAD"); ++ npreloads += do_preload (fname, main_map, where); + } + return npreloads; + } +@@ -974,6 +977,13 @@ dl_main (const ElfW(Phdr) *phdr, + { + process_dl_audit (_dl_argv[2]); + ++ _dl_skip_args += 2; ++ _dl_argc -= 2; ++ _dl_argv += 2; ++ } ++ else if (! strcmp (_dl_argv[1], "--preload") && _dl_argc > 2) ++ { ++ preloadarg = _dl_argv[2]; + _dl_skip_args += 2; + _dl_argc -= 2; + _dl_argv += 2; +@@ -1006,7 +1016,8 @@ of this helper program; chances are you did not intend to run this program.\n\ + variable LD_LIBRARY_PATH\n\ + --inhibit-rpath LIST ignore RUNPATH and RPATH information in object names\n\ + in LIST\n\ +- --audit LIST use objects named in LIST as auditors\n"); ++ --audit LIST use objects named in LIST as auditors\n\ ++ --preload LIST preload objects named in LIST\n"); + + ++_dl_skip_args; + --_dl_argc; +@@ -1620,7 +1631,16 @@ ERROR: ld.so: object '%s' cannot be loaded as audit interface: %s; ignored.\n", + if (__glibc_unlikely (preloadlist != NULL)) + { + HP_TIMING_NOW (start); +- npreloads += handle_ld_preload (preloadlist, main_map); ++ npreloads += handle_preload_list (preloadlist, main_map, "LD_PRELOAD"); ++ HP_TIMING_NOW (stop); ++ HP_TIMING_DIFF (diff, start, stop); ++ HP_TIMING_ACCUM_NT (load_time, diff); ++ } ++ ++ if (__glibc_unlikely (preloadarg != NULL)) ++ { ++ HP_TIMING_NOW (start); ++ npreloads += handle_preload_list (preloadarg, main_map, "--preload"); + HP_TIMING_NOW (stop); + HP_TIMING_DIFF (diff, start, stop); + HP_TIMING_ACCUM_NT (load_time, diff); +diff --git a/elf/tst-rtld-preload.sh b/elf/tst-rtld-preload.sh +new file mode 100755 +index 0000000000..f0c0ca11ba +--- /dev/null ++++ b/elf/tst-rtld-preload.sh +@@ -0,0 +1,38 @@ ++#!/bin/sh ++# Test --preload argument ld.so. ++# 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, see ++# . ++ ++set -e ++ ++rtld=$1 ++test_program=$2 ++test_wrapper=$3 ++test_wrapper_env=$4 ++run_program_env=$5 ++library_path=$6 ++preload=$7 ++ ++echo "# [${test_wrapper}] [$rtld] [--library-path] [$library_path]" \ ++ "[--preload] [$preload] [$test_program]" ++${test_wrapper_env} \ ++${run_program_env} \ ++${test_wrapper} $rtld --library-path "$library_path" \ ++ --preload "$preload" $test_program 2>&1 && rc=0 || rc=$? ++echo "# exit status $rc" ++ ++exit $rc diff --git a/SOURCES/glibc-rh1747502-1.patch b/SOURCES/glibc-rh1747502-1.patch new file mode 100644 index 0000000..b57f046 --- /dev/null +++ b/SOURCES/glibc-rh1747502-1.patch @@ -0,0 +1,168 @@ +commit 561b0bec4448f0302cb4915bf67c919bde4a1c57 +Author: DJ Delorie +Date: Fri Jul 6 01:10:41 2018 -0400 + + Add test-in-container infrastructure. + + * Makefile (testroot.pristine): New rules to initialize the + test-in-container "testroot". + * Makerules (all-testsuite): Add tests-container. + * Rules (tests-expected): Add tests-container. + (binaries-all-tests): Likewise. + (tests-container): New, run these tests in the testroot container. + * support/links-dso-program-c.c: New. + * support/links-dso-program.cc: New. + * support/test-container.c: New. + * support/shell-container.c: New. + * support/echo-container.c: New. + * support/true-container.c: New. + * support/xmkdirp.c: New. + * support/xsymlink.c: New. + * support/support_paths.c: New. + * support/support.h: Add support paths prototypes. + * support/xunistd.h: Add xmkdirp () and xsymlink (). + + * nss/tst-nss-test3.c: Convert to test-in-container. + * nss/tst-nss-test3.root/: New. + +(note: support/ already present, not needed; sample test not included) + +diff --git a/Makefile b/Makefile +index d3f25a5..3df55e6 100644 +--- a/Makefile ++++ b/Makefile +@@ -340,6 +340,62 @@ define summarize-tests + @! egrep -q -v '^(X?PASS|XFAIL|UNSUPPORTED):' $(objpfx)$1 + endef + ++# The intention here is to do ONE install of our build into the ++# testroot.pristine/ directory, then rsync (internal to ++# support/test-container) that to testroot.root/ at the start of each ++# test. That way we can promise each test a "clean" install, without ++# having to do the install for each test. ++# ++# In addition, we have to copy some files (which we build) into this ++# root in addition to what glibc installs. For example, many tests ++# require additional programs including /bin/sh, /bin/true, and ++# /bin/echo, all of which we build below to limit library dependencies ++# to just those things in glibc and language support libraries which ++# we also copy into the into the rootfs. To determine what language ++# support libraries we need we build a "test" program in either C or ++# (if available) C++ just so we can copy in any shared objects ++# (which we do not build) that GCC-compiled programs depend on. ++ ++ ++ifeq (,$(CXX)) ++LINKS_DSO_PROGRAM = links-dso-program-c ++else ++LINKS_DSO_PROGRAM = links-dso-program ++endif ++ ++$(tests-container) $(addsuffix /tests,$(subdirs)) : \ ++ $(objpfx)testroot.pristine/install.stamp ++$(objpfx)testroot.pristine/install.stamp : ++ test -d $(objpfx)testroot.pristine || \ ++ mkdir $(objpfx)testroot.pristine ++ # We need a working /bin/sh for some of the tests. ++ test -d $(objpfx)testroot.pristine/bin || \ ++ mkdir $(objpfx)testroot.pristine/bin ++ cp $(objpfx)support/shell-container $(objpfx)testroot.pristine/bin/sh ++ cp $(objpfx)support/echo-container $(objpfx)testroot.pristine/bin/echo ++ cp $(objpfx)support/true-container $(objpfx)testroot.pristine/bin/true ++ # Copy these DSOs first so we can overwrite them with our own. ++ for dso in `$(test-wrapper-env) LD_TRACE_LOADED_OBJECTS=1 \ ++ $(objpfx)elf/$(rtld-installed-name) \ ++ $(objpfx)testroot.pristine/bin/sh \ ++ | grep / | sed 's/^[^/]*//' | sed 's/ .*//'` ;\ ++ do \ ++ test -d `dirname $(objpfx)testroot.pristine$$dso` || \ ++ mkdir -p `dirname $(objpfx)testroot.pristine$$dso` ;\ ++ $(test-wrapper) cp $$dso $(objpfx)testroot.pristine$$dso ;\ ++ done ++ for dso in `$(test-wrapper-env) LD_TRACE_LOADED_OBJECTS=1 \ ++ $(objpfx)elf/$(rtld-installed-name) \ ++ $(objpfx)support/$(LINKS_DSO_PROGRAM) \ ++ | grep / | sed 's/^[^/]*//' | sed 's/ .*//'` ;\ ++ do \ ++ test -d `dirname $(objpfx)testroot.pristine$$dso` || \ ++ mkdir -p `dirname $(objpfx)testroot.pristine$$dso` ;\ ++ $(test-wrapper) cp $$dso $(objpfx)testroot.pristine$$dso ;\ ++ done ++ $(MAKE) install DESTDIR=$(objpfx)testroot.pristine ++ touch $(objpfx)testroot.pristine/install.stamp ++ + tests-special-notdir = $(patsubst $(objpfx)%, %, $(tests-special)) + tests: $(tests-special) + $(..)scripts/merge-test-results.sh -s $(objpfx) "" \ +diff --git a/Makerules b/Makerules +index a10a0b4..5d6434c 100644 +--- a/Makerules ++++ b/Makerules +@@ -1369,7 +1369,8 @@ xcheck: xtests + # The only difference between MODULE_NAME=testsuite and MODULE_NAME=nonlib is + # that almost all internal declarations from config.h, libc-symbols.h, and + # include/*.h are not available to 'testsuite' code, but are to 'nonlib' code. +-all-testsuite := $(strip $(tests) $(xtests) $(test-srcs) $(test-extras)) ++all-testsuite := $(strip $(tests) $(xtests) $(test-srcs) $(test-extras) \ ++ $(tests-container)) + ifneq (,$(all-testsuite)) + cpp-srcs-left = $(all-testsuite) + lib := testsuite +diff --git a/Rules b/Rules +index 706c8a7..5abb727 100644 +--- a/Rules ++++ b/Rules +@@ -130,12 +130,14 @@ others: $(py-const) + + ifeq ($(run-built-tests),no) + tests: $(addprefix $(objpfx),$(filter-out $(tests-unsupported), \ +- $(tests) $(tests-internal)) \ ++ $(tests) $(tests-internal) \ ++ $(tests-container)) \ + $(test-srcs)) $(tests-special) \ + $(tests-printers-programs) + xtests: tests $(xtests-special) + else + tests: $(tests:%=$(objpfx)%.out) $(tests-internal:%=$(objpfx)%.out) \ ++ $(tests-container:%=$(objpfx)%.out) \ + $(tests-special) $(tests-printers-out) + xtests: tests $(xtests:%=$(objpfx)%.out) $(xtests-special) + endif +@@ -145,7 +147,8 @@ xtests-special-notdir = $(patsubst $(objpfx)%, %, $(xtests-special)) + ifeq ($(run-built-tests),no) + tests-expected = + else +-tests-expected = $(tests) $(tests-internal) $(tests-printers) ++tests-expected = $(tests) $(tests-internal) $(tests-printers) \ ++ $(tests-container) + endif + tests: + $(..)scripts/merge-test-results.sh -s $(objpfx) $(subdir) \ +@@ -158,7 +161,8 @@ xtests: + + ifeq ($(build-programs),yes) + binaries-all-notests = $(others) $(sysdep-others) +-binaries-all-tests = $(tests) $(tests-internal) $(xtests) $(test-srcs) ++binaries-all-tests = $(tests) $(tests-internal) $(xtests) $(test-srcs) \ ++ $(tests-container) + binaries-all = $(binaries-all-notests) $(binaries-all-tests) + binaries-static-notests = $(others-static) + binaries-static-tests = $(tests-static) $(xtests-static) +@@ -248,6 +252,17 @@ $(objpfx)%.out: /dev/null $(objpfx)% # Make it 2nd arg for canned sequence. + $(make-test-out) > $@; \ + $(evaluate-test) + ++ ++# Any tests that require an isolated container (filesystem, network ++# and pid namespaces) in which to run, should be added to ++# tests-container. ++$(tests-container:%=$(objpfx)%.out): $(objpfx)%.out : $(if $(wildcard $(objpfx)%.files),$(objpfx)%.files,/dev/null) $(objpfx)% ++ $(test-wrapper-env) $(run-program-env) $(run-via-rtld-prefix) \ ++ $(common-objpfx)support/test-container env $(run-program-env) $($*-ENV) \ ++ $(host-test-program-cmd) $($*-ARGS) > $@; \ ++ $(evaluate-test) ++ ++ + # tests-unsupported lists tests that we will not try to build at all in + # this configuration. Note this runs every time because it does not + # actually create its target. The dependency on Makefile is meant to diff --git a/SOURCES/glibc-rh1747502-2.patch b/SOURCES/glibc-rh1747502-2.patch new file mode 100644 index 0000000..17a53e1 --- /dev/null +++ b/SOURCES/glibc-rh1747502-2.patch @@ -0,0 +1,48 @@ +commit bd598da9f454bc1091b4ebe0303b07e6f96ca130 +Author: Joseph Myers +Date: Tue Dec 4 16:52:39 2018 +0000 + + Stop test-in-container trying to run other-OS binaries. + + I noticed that, now that build-many-glibcs.py no longer copies glibc + sources, I was getting core dumps in my glibc source directories. The + cause appears to be, from the i686-gnu build: + + for dso in ` env LD_TRACE_LOADED_OBJECTS=1 \ + /scratch/jmyers/glibc-bot/build/glibcs/i686-gnu/glibc/elf/ld.so.1 \ + /scratch/jmyers/glibc-bot/build/glibcs/i686-gnu/glibc/testroot.pristine/bin/sh \ + [...] + Segmentation fault (core dumped) + + In this case, the x86 architecture means the binary executes, but + dumps core rather than actually working. + + Anything involving running the newly built glibc should only be done + ifeq ($(run-built-tests),yes). This patch conditions the relevant + part of the testroot setup accordingly. + + Tested for x86_64, and with build-many-glibcs.py for i686-gnu. + + * Makefile ($(objpfx)testroot.pristine/install.stamp): Do not run + dynamic linker unless [$(run-built-tests) = yes]. + +diff --git a/Makefile b/Makefile +index b4703e4..fd73d9b 100644 +--- a/Makefile ++++ b/Makefile +@@ -374,6 +374,7 @@ $(objpfx)testroot.pristine/install.stamp : + cp $(objpfx)support/shell-container $(objpfx)testroot.pristine/bin/sh + cp $(objpfx)support/echo-container $(objpfx)testroot.pristine/bin/echo + cp $(objpfx)support/true-container $(objpfx)testroot.pristine/bin/true ++ifeq ($(run-built-tests),yes) + # Copy these DSOs first so we can overwrite them with our own. + for dso in `$(test-wrapper-env) LD_TRACE_LOADED_OBJECTS=1 \ + $(objpfx)elf/$(rtld-installed-name) \ +@@ -393,6 +394,7 @@ $(objpfx)testroot.pristine/install.stamp : + mkdir -p `dirname $(objpfx)testroot.pristine$$dso` ;\ + $(test-wrapper) cp $$dso $(objpfx)testroot.pristine$$dso ;\ + done ++endif + $(MAKE) install DESTDIR=$(objpfx)testroot.pristine + touch $(objpfx)testroot.pristine/install.stamp + diff --git a/SOURCES/glibc-rh1747502-3.patch b/SOURCES/glibc-rh1747502-3.patch new file mode 100644 index 0000000..f0c5027 --- /dev/null +++ b/SOURCES/glibc-rh1747502-3.patch @@ -0,0 +1,40 @@ +commit 95da14dac04b494149290d85bc5306226e30839e +Author: Tulio Magno Quites Machado Filho +Date: Mon Jul 22 16:30:45 2019 -0300 + + test-container: Avoid copying unintended system libraries + + Some DSOs are distributed in hardware capability directories, e.g. + /usr/lib64/power7/libc.so.6 + Whenever the processor is able to use one of these hardware-enabled + DSOs, testroot.pristine ends up with copies of glibc-provided libraries + from the system because it can't overwrite or remove them. + + This patch avoids the unintended copies by executing ld.so with the same + arguments passed to each glibc test. + + * Makefile (testroot.pristine/install.stamp): Execute ld.so with + the same arguments used in all tests. + +diff --git a/Makefile b/Makefile +index dc5de7a..a4ed747 100644 +--- a/Makefile ++++ b/Makefile +@@ -383,7 +383,7 @@ $(objpfx)testroot.pristine/install.stamp : + ifeq ($(run-built-tests),yes) + # Copy these DSOs first so we can overwrite them with our own. + for dso in `$(test-wrapper-env) LD_TRACE_LOADED_OBJECTS=1 \ +- $(objpfx)elf/$(rtld-installed-name) \ ++ $(rtld-prefix) \ + $(objpfx)testroot.pristine/bin/sh \ + | grep / | sed 's/^[^/]*//' | sed 's/ .*//'` ;\ + do \ +@@ -392,7 +392,7 @@ ifeq ($(run-built-tests),yes) + $(test-wrapper) cp $$dso $(objpfx)testroot.pristine$$dso ;\ + done + for dso in `$(test-wrapper-env) LD_TRACE_LOADED_OBJECTS=1 \ +- $(objpfx)elf/$(rtld-installed-name) \ ++ $(rtld-prefix) \ + $(objpfx)support/$(LINKS_DSO_PROGRAM) \ + | grep / | sed 's/^[^/]*//' | sed 's/ .*//'` ;\ + do \ diff --git a/SOURCES/glibc-rh1747502-4.patch b/SOURCES/glibc-rh1747502-4.patch new file mode 100644 index 0000000..2e25309 --- /dev/null +++ b/SOURCES/glibc-rh1747502-4.patch @@ -0,0 +1,31 @@ +commit 35e038c1d2ccb3a75395662f9c4f28d85a61444f +Author: Tulio Magno Quites Machado Filho +Date: Mon Jul 22 17:34:13 2019 -0300 + + test-container: Install with $(all-subdirs) [BZ #24794] + + Whenever a sub-make is created, it inherits the variable subdirs from its + parent. This is also true when make check is called with a restricted + list of subdirs. In this scenario, make install is executed "partially" + and testroot.pristine ends up with an incomplete installation. + + [BZ #24794] + * Makefile (testroot.pristine/install.stamp): Pass + subdirs='$(all-subdirs)' to make install. + + Reviewed-by: DJ Delorie + +diff --git a/Makefile b/Makefile +index a4ed747..9fbf705 100644 +--- a/Makefile ++++ b/Makefile +@@ -401,7 +401,8 @@ ifeq ($(run-built-tests),yes) + $(test-wrapper) cp $$dso $(objpfx)testroot.pristine$$dso ;\ + done + endif +- $(MAKE) install DESTDIR=$(objpfx)testroot.pristine ++ $(MAKE) install DESTDIR=$(objpfx)testroot.pristine \ ++ subdirs='$(all-subdirs)' + touch $(objpfx)testroot.pristine/install.stamp + + tests-special-notdir = $(patsubst $(objpfx)%, %, $(tests-special)) diff --git a/SOURCES/glibc-rh1747502-5.patch b/SOURCES/glibc-rh1747502-5.patch new file mode 100644 index 0000000..30dd75e --- /dev/null +++ b/SOURCES/glibc-rh1747502-5.patch @@ -0,0 +1,56 @@ +commit 7db1fe38de21831d53ceab9ae83493d8d1aec601 +Author: Joseph Myers +Date: Tue Oct 22 20:24:10 2019 +0000 + + Fix testroot.pristine creation copying dynamic linker. + + This patch addresses an issue reported in + where the + creation of testroot.pristine, on encountering + LD_TRACE_LOADED_OBJECTS=1 of the form + + libc.so.6 => /scratch/jmyers/glibc/mbs/obj/glibc-8-0-mips64-linux-gnu-x86_64-linux-gnu/default/libc.so.6 (0x772dd000) + /lib32/ld.so.1 => /scratch/jmyers/glibc/mbs/obj/glibc-8-0-mips64-linux-gnu-x86_64-linux-gnu/default/elf/ld.so.1 (0x7747b000) + + tries to copy /lib32/ld.so.1 (which does not exist) into the testroot + instead of copying the path on the RHS of "=>", which does exist, + because the Makefile logic assumes that the path on such a line with + '/' should be copied, when if there are such paths on both the LHS and + the RHS of "=>", only the one on the RHS necessarily exists and so + only that should be copied. The patch follows the approach suggested + by DJ in , + with the suggestion from Andreas in + of a + single sed command in place of pipeline of grep and three sed + commands. + + Tested for x86_64, with and without --enable-hardcoded-path-in-tests; + a previous version with multiple sed commands, implementing the same + logic, also tested for MIPS, with and without + --enable-hardcoded-path-in-tests, to confirm it fixes the original + problem. + + Co-authored-by: DJ Delorie + +diff --git a/Makefile b/Makefile +index d7e4be9..0711b97 100644 +--- a/Makefile ++++ b/Makefile +@@ -564,7 +564,7 @@ ifeq ($(run-built-tests),yes) + for dso in `$(test-wrapper-env) LD_TRACE_LOADED_OBJECTS=1 \ + $(rtld-prefix) \ + $(objpfx)testroot.pristine/bin/sh \ +- | grep / | sed 's/^[^/]*//' | sed 's/ .*//'` ;\ ++ | sed -n '/\//{s@.*=> /@/@;s/^[^/]*//;s/ .*//p;}'` ;\ + do \ + test -d `dirname $(objpfx)testroot.pristine$$dso` || \ + mkdir -p `dirname $(objpfx)testroot.pristine$$dso` ;\ +@@ -573,7 +573,7 @@ ifeq ($(run-built-tests),yes) + for dso in `$(test-wrapper-env) LD_TRACE_LOADED_OBJECTS=1 \ + $(rtld-prefix) \ + $(objpfx)support/$(LINKS_DSO_PROGRAM) \ +- | grep / | sed 's/^[^/]*//' | sed 's/ .*//'` ;\ ++ | sed -n '/\//{s@.*=> /@/@;s/^[^/]*//;s/ .*//p;}'` ;\ + do \ + test -d `dirname $(objpfx)testroot.pristine$$dso` || \ + mkdir -p `dirname $(objpfx)testroot.pristine$$dso` ;\ diff --git a/SOURCES/glibc-rh1747502-6.patch b/SOURCES/glibc-rh1747502-6.patch new file mode 100644 index 0000000..c84940c --- /dev/null +++ b/SOURCES/glibc-rh1747502-6.patch @@ -0,0 +1,56 @@ +commit c7ac9caaae6f8d02d4e0c7618d4991324a084c66 +Author: Adhemerval Zanella +Date: Mon May 13 13:57:37 2019 -0300 + + support: Export bindir path on support_path + + Checked on x86_64-linux-gnu. + + * support/Makefile (CFLAGS-support_paths.c): Add -DBINDIR_PATH. + * support/support.h (support_bindir_prefix): New variable. + * support/support_paths.c [BINDIR_PATH] (support_bindir_prefix): + + Reviewed-by: DJ Delorie + +diff --git a/support/Makefile b/support/Makefile +index 64044f6..fe416cd 100644 +--- a/support/Makefile ++++ b/support/Makefile +@@ -179,7 +179,8 @@ CFLAGS-support_paths.c = \ + -DOBJDIR_PATH=\"`cd $(objpfx)/..; pwd`\" \ + -DOBJDIR_ELF_LDSO_PATH=\"`cd $(objpfx)/..; pwd`/elf/$(rtld-installed-name)\" \ + -DINSTDIR_PATH=\"$(prefix)\" \ +- -DLIBDIR_PATH=\"$(libdir)\" ++ -DLIBDIR_PATH=\"$(libdir)\" \ ++ -DBINDIR_PATH=\"$(bindir)\" + + ifeq (,$(CXX)) + LINKS_DSO_PROGRAM = links-dso-program-c +diff --git a/support/support.h b/support/support.h +index 97fef2c..b162491 100644 +--- a/support/support.h ++++ b/support/support.h +@@ -105,6 +105,8 @@ extern const char support_objdir_elf_ldso[]; + extern const char support_install_prefix[]; + /* Corresponds to the install's lib/ or lib64/ directory. */ + extern const char support_libdir_prefix[]; ++/* Corresponds to the install's bin/ directory. */ ++extern const char support_bindir_prefix[]; + + extern ssize_t support_copy_file_range (int, off64_t *, int, off64_t *, + size_t, unsigned int); +diff --git a/support/support_paths.c b/support/support_paths.c +index 937e6e1..75634aa 100644 +--- a/support/support_paths.c ++++ b/support/support_paths.c +@@ -57,3 +57,10 @@ const char support_libdir_prefix[] = LIBDIR_PATH; + #else + # error please -DLIBDIR_PATH=something in the Makefile + #endif ++ ++#ifdef BINDIR_PATH ++/* Corresponds to the install's bin/ directory. */ ++const char support_bindir_prefix[] = BINDIR_PATH; ++#else ++# error please -DBINDIR_PATH=something in the Makefile ++#endif diff --git a/SOURCES/glibc-rh1747502-7.patch b/SOURCES/glibc-rh1747502-7.patch new file mode 100644 index 0000000..fa6a63d --- /dev/null +++ b/SOURCES/glibc-rh1747502-7.patch @@ -0,0 +1,46 @@ +From 354e4c1adddb1da19c1043e3e5db61ee2148d912 Mon Sep 17 00:00:00 2001 +From: Tulio Magno Quites Machado Filho +Date: Wed, 24 Jul 2019 19:49:00 -0300 +Subject: test-container: Install with $(sorted-subdirs) [BZ #24794] + +Commit 35e038c1d2ccb3a75395662f9c4f28d85a61444f started to use an +incomplete list of subdirs based on $(all-subdirs) causing +testroot.pristine to miss files from nss. + +Tested if the list of files in testroot.pristine remains the same. + + [BZ #24794] + * Makeconfig (all-subdirs): Improved source comments. + * Makefile (testroot.pristine/install.stamp): Pass + subdirs='$(sorted-subdirs)' to make install. + +diff --git a/Makeconfig b/Makeconfig +index 0e386fbc19..fd36c58c04 100644 +--- a/Makeconfig ++++ b/Makeconfig +@@ -1267,9 +1267,9 @@ else + libsupport = $(common-objpfx)support/libsupport.a + endif + +-# These are the subdirectories containing the library source. The order +-# is more or less arbitrary. The sorting step will take care of the +-# dependencies. ++# This is a partial list of subdirectories containing the library source. ++# The order is more or less arbitrary. The sorting step will take care of the ++# dependencies and generate sorted-subdirs dynamically. + all-subdirs = csu assert ctype locale intl catgets math setjmp signal \ + stdlib stdio-common libio malloc string wcsmbs time dirent \ + grp pwd posix io termios resource misc socket sysvipc gmon \ +diff --git a/Makefile b/Makefile +index 9fbf705200..ac1125853b 100644 +--- a/Makefile ++++ b/Makefile +@@ -402,7 +402,7 @@ ifeq ($(run-built-tests),yes) + done + endif + $(MAKE) install DESTDIR=$(objpfx)testroot.pristine \ +- subdirs='$(all-subdirs)' ++ subdirs='$(sorted-subdirs)' + touch $(objpfx)testroot.pristine/install.stamp + + tests-special-notdir = $(patsubst $(objpfx)%, %, $(tests-special)) diff --git a/SOURCES/glibc-rh1747502-8.patch b/SOURCES/glibc-rh1747502-8.patch new file mode 100644 index 0000000..16f6bf7 --- /dev/null +++ b/SOURCES/glibc-rh1747502-8.patch @@ -0,0 +1,50 @@ +commit d50f09181eca10a91fd9035bb90711b265770dc9 +Author: Alexandra Hájková +Date: Mon May 13 19:31:53 2019 +0200 + + support: Add support_install_rootsbindir + + Reviewed by: Adhemerval Zanella + +diff --git a/support/Makefile b/support/Makefile +index fe416cd..18d39f5 100644 +--- a/support/Makefile ++++ b/support/Makefile +@@ -180,7 +180,8 @@ CFLAGS-support_paths.c = \ + -DOBJDIR_ELF_LDSO_PATH=\"`cd $(objpfx)/..; pwd`/elf/$(rtld-installed-name)\" \ + -DINSTDIR_PATH=\"$(prefix)\" \ + -DLIBDIR_PATH=\"$(libdir)\" \ +- -DBINDIR_PATH=\"$(bindir)\" ++ -DBINDIR_PATH=\"$(bindir)\" \ ++ -DROOTSBINDIR_PATH=\"$(rootsbindir)\" + + ifeq (,$(CXX)) + LINKS_DSO_PROGRAM = links-dso-program-c +diff --git a/support/support.h b/support/support.h +index b162491..13076b7 100644 +--- a/support/support.h ++++ b/support/support.h +@@ -107,6 +107,8 @@ extern const char support_install_prefix[]; + extern const char support_libdir_prefix[]; + /* Corresponds to the install's bin/ directory. */ + extern const char support_bindir_prefix[]; ++/* Corresponds to the install's sbin/ directory. */ ++extern const char support_install_rootsbindir[]; + + extern ssize_t support_copy_file_range (int, off64_t *, int, off64_t *, + size_t, unsigned int); +diff --git a/support/support_paths.c b/support/support_paths.c +index 75634aa..1fe3283 100644 +--- a/support/support_paths.c ++++ b/support/support_paths.c +@@ -64,3 +64,10 @@ const char support_bindir_prefix[] = BINDIR_PATH; + #else + # error please -DBINDIR_PATH=something in the Makefile + #endif ++ ++#ifdef ROOTSBINDIR_PATH ++/* Corresponds to the install's sbin/ directory. */ ++const char support_install_rootsbindir[] = ROOTSBINDIR_PATH; ++#else ++# error please -DROOTSBINDIR_PATH=something in the Makefile ++#endif diff --git a/SOURCES/glibc-rh1747502-9.patch b/SOURCES/glibc-rh1747502-9.patch new file mode 100644 index 0000000..8bf528d --- /dev/null +++ b/SOURCES/glibc-rh1747502-9.patch @@ -0,0 +1,86 @@ +From 304c61a24f909168c16793ccf7c686237e53d003 Mon Sep 17 00:00:00 2001 +From: DJ Delorie +Date: Wed, 5 Dec 2018 12:39:47 -0500 +Subject: test-container: move postclean outside of namespace changes + +During postclean.req testing it was found that the fork in the +parent process (after the unshare syscall) would fail with ENOMEM +(see recursive_remove() in test-container.c). While failing with +ENOMEM is certainly unexpected, it is simply easier to refactor +the design and have the parent remain outside of the namespace. +This change moves the postclean.req processing to a distinct +process (the parent) that then forks the test process (which will +have to fork once more to complete uid/gid transitions). When the +test process exists the cleanup process will ensure all files are +deleted when a post clean is requested. + +Signed-off-by: DJ Delorie +Reviewed-by: Carlos O'Donell + +[BZ #23948] +* support/test-container.c: Move postclean step to before we +change namespaces. + +diff --git a/support/test-container.c b/support/test-container.c +index df450adfdb..1d1aebeaf3 100644 +--- a/support/test-container.c ++++ b/support/test-container.c +@@ -921,6 +921,43 @@ main (int argc, char **argv) + } + } + ++ if (do_postclean) ++ { ++ pid_t pc_pid = fork (); ++ ++ if (pc_pid < 0) ++ { ++ FAIL_EXIT1 ("Can't fork for post-clean"); ++ } ++ else if (pc_pid > 0) ++ { ++ /* Parent. */ ++ int status; ++ waitpid (pc_pid, &status, 0); ++ ++ /* Child has exited, we can post-clean the test root. */ ++ printf("running post-clean rsync\n"); ++ rsync (pristine_root_path, new_root_path, 1); ++ ++ if (WIFEXITED (status)) ++ exit (WEXITSTATUS (status)); ++ ++ if (WIFSIGNALED (status)) ++ { ++ printf ("%%SIGNALLED%%\n"); ++ exit (77); ++ } ++ ++ printf ("%%EXITERROR%%\n"); ++ exit (78); ++ } ++ ++ /* Child continues. */ ++ } ++ ++ /* This is the last point in the program where we're still in the ++ "normal" namespace. */ ++ + #ifdef CLONE_NEWNS + /* The unshare here gives us our own spaces and capabilities. */ + if (unshare (CLONE_NEWUSER | CLONE_NEWPID | CLONE_NEWNS) < 0) +@@ -974,14 +1011,6 @@ main (int argc, char **argv) + int status; + waitpid (child, &status, 0); + +- /* There's a bit of magic here, since the buildroot is mounted +- in our space, the paths are still valid, and since the mounts +- aren't recursive, it sees *only* the built root, not anything +- we would normally se if we rsync'd to "/" like mounted /dev +- files. */ +- if (do_postclean) +- rsync (pristine_root_path, new_root_path, 1); +- + if (WIFEXITED (status)) + exit (WEXITSTATUS (status)); + diff --git a/SOURCES/glibc-rh1747502.patch b/SOURCES/glibc-rh1747502.patch new file mode 100644 index 0000000..e28de98 --- /dev/null +++ b/SOURCES/glibc-rh1747502.patch @@ -0,0 +1,268 @@ +commit 99135114ba23c3110b7e4e650fabdc5e639746b7 +Author: DJ Delorie +Date: Fri Jun 28 18:30:00 2019 -0500 + + nss_db: fix endent wrt NULL mappings [BZ #24695] [BZ #24696] + + nss_db allows for getpwent et al to be called without a set*ent, + but it only works once. After the last get*ent a set*ent is + required to restart, because the end*ent did not properly reset + the module. Resetting it to NULL allows for a proper restart. + + If the database doesn't exist, however, end*ent erroniously called + munmap which set errno. + + The test case runs "makedb" inside the testroot, so needs selinux + DSOs installed. + +diff -rupN a/nss/Makefile b/nss/Makefile +--- a/nss/Makefile 2019-11-04 15:14:16.721221038 -0500 ++++ b/nss/Makefile 2019-11-04 15:15:46.447544678 -0500 +@@ -60,6 +60,10 @@ tests = test-netdb test-digits-dots ts + tst-nss-test5 + xtests = bug-erange + ++tests-container = \ ++ tst-nss-db-endpwent \ ++ tst-nss-db-endgrent ++ + # Tests which need libdl + ifeq (yes,$(build-shared)) + tests += tst-nss-files-hosts-erange +diff -rupN a/nss/nss_db/db-open.c b/nss/nss_db/db-open.c +--- a/nss/nss_db/db-open.c 2018-08-01 01:10:47.000000000 -0400 ++++ b/nss/nss_db/db-open.c 2019-11-04 15:15:10.520213846 -0500 +@@ -63,5 +63,9 @@ internal_setent (const char *file, struc + void + internal_endent (struct nss_db_map *mapping) + { +- munmap (mapping->header, mapping->len); ++ if (mapping->header != NULL) ++ { ++ munmap (mapping->header, mapping->len); ++ mapping->header = NULL; ++ } + } +diff -rupN a/nss/tst-nss-db-endgrent.c b/nss/tst-nss-db-endgrent.c +--- a/nss/tst-nss-db-endgrent.c 1969-12-31 19:00:00.000000000 -0500 ++++ b/nss/tst-nss-db-endgrent.c 2019-11-04 15:15:10.526214069 -0500 +@@ -0,0 +1,54 @@ ++/* Test for endgrent changing errno for BZ #24696 ++ 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, see ++ . */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++/* The following test verifies that if the db NSS Service is initialized ++ with no database (getgrent), that a subsequent closure (endgrent) does ++ not set errno. In the case of the db service it is not an error to close ++ the service and so it should not set errno. */ ++ ++static int ++do_test (void) ++{ ++ /* Just make sure it's not there, although usually it won't be. */ ++ unlink ("/var/db/group.db"); ++ ++ /* This, in conjunction with the testroot's nsswitch.conf, causes ++ the nss_db module to be "connected" and initialized - but the ++ testroot has no group.db, so no mapping will be created. */ ++ getgrent (); ++ ++ errno = 0; ++ ++ /* Before the fix, this would call munmap (NULL) and set errno. */ ++ endgrent (); ++ ++ if (errno != 0) ++ FAIL_EXIT1 ("endgrent set errno to %d\n", errno); ++ ++ return 0; ++} ++#include +diff -rupN a/nss/tst-nss-db-endgrent.root/etc/nsswitch.conf b/nss/tst-nss-db-endgrent.root/etc/nsswitch.conf +--- a/nss/tst-nss-db-endgrent.root/etc/nsswitch.conf 1969-12-31 19:00:00.000000000 -0500 ++++ b/nss/tst-nss-db-endgrent.root/etc/nsswitch.conf 2019-11-04 15:15:10.539214550 -0500 +@@ -0,0 +1 @@ ++group : db files +diff -rupN a/nss/tst-nss-db-endpwent.c b/nss/tst-nss-db-endpwent.c +--- a/nss/tst-nss-db-endpwent.c 1969-12-31 19:00:00.000000000 -0500 ++++ b/nss/tst-nss-db-endpwent.c 2019-11-04 15:15:10.545214772 -0500 +@@ -0,0 +1,66 @@ ++/* Test for endpwent->getpwent crash for BZ #24695 ++ 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, see ++ . */ ++ ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++/* It is entirely allowed to start with a getpwent call without ++ resetting the state of the service via a call to setpwent. ++ You can also call getpwent more times than you have entries in ++ the service, and it should not fail. This test iteratates the ++ database once, gets to the end, and then attempts a second ++ iteration to look for crashes. */ ++ ++static void ++try_it (void) ++{ ++ struct passwd *pw; ++ ++ /* setpwent is intentionally omitted here. The first call to ++ getpwent detects that it's first and initializes. The second ++ time try_it is called, this "first call" was not detected before ++ the fix, and getpwent would crash. */ ++ ++ while ((pw = getpwent ()) != NULL) ++ ; ++ ++ /* We only care if this segfaults or not. */ ++ endpwent (); ++} ++ ++static int ++do_test (void) ++{ ++ char *cmd; ++ ++ cmd = xasprintf ("%s/makedb -o /var/db/passwd.db /var/db/passwd.in", ++ support_bindir_prefix); ++ system (cmd); ++ free (cmd); ++ ++ try_it (); ++ try_it (); ++ ++ return 0; ++} ++#include +diff -rupN a/nss/tst-nss-db-endpwent.root/etc/nsswitch.conf b/nss/tst-nss-db-endpwent.root/etc/nsswitch.conf +--- a/nss/tst-nss-db-endpwent.root/etc/nsswitch.conf 1969-12-31 19:00:00.000000000 -0500 ++++ b/nss/tst-nss-db-endpwent.root/etc/nsswitch.conf 2019-11-04 15:15:10.556215180 -0500 +@@ -0,0 +1 @@ ++passwd: db +diff -rupN a/nss/tst-nss-db-endpwent.root/var/db/passwd.in b/nss/tst-nss-db-endpwent.root/var/db/passwd.in +--- a/nss/tst-nss-db-endpwent.root/var/db/passwd.in 1969-12-31 19:00:00.000000000 -0500 ++++ b/nss/tst-nss-db-endpwent.root/var/db/passwd.in 2019-11-04 15:15:10.567215588 -0500 +@@ -0,0 +1,4 @@ ++.root root:x:0:0:root:/root:/bin/bash ++=0 root:x:0:0:root:/root:/bin/bash ++.bin bin:x:1:1:bin:/bin:/sbin/nologin ++=1 bin:x:1:1:bin:/bin:/sbin/nologin +diff -rupN a/support/Makefile b/support/Makefile +--- a/support/Makefile 2019-11-04 15:14:20.416357911 -0500 ++++ b/support/Makefile 2019-11-04 15:15:10.574215847 -0500 +@@ -180,6 +180,11 @@ LINKS_DSO_PROGRAM = links-dso-program + LDLIBS-links-dso-program = -lstdc++ -lgcc -lgcc_s $(libunwind) + endif + ++ifeq (yes,$(have-selinux)) ++LDLIBS-$(LINKS_DSO_PROGRAM) += -lselinux ++endif ++ ++ + LDLIBS-test-container = $(libsupport) + + others += test-container +diff -rupN a/support/links-dso-program-c.c b/support/links-dso-program-c.c +--- a/support/links-dso-program-c.c 2019-11-04 15:14:17.073234077 -0500 ++++ b/support/links-dso-program-c.c 2019-11-04 15:15:10.580216069 -0500 +@@ -1,9 +1,26 @@ + #include + ++/* makedb needs selinux dso's. */ ++#ifdef HAVE_SELINUX ++# include ++#endif ++ ++/* The purpose of this file is to indicate to the build system which ++ shared objects need to be copied into the testroot, such as gcc or ++ selinux support libraries. This program is never executed, only ++ scanned for dependencies on shared objects, so the code below may ++ seem weird - it's written to survive gcc optimization and force ++ such dependencies. ++*/ ++ + int + main (int argc, char **argv) + { + /* Complexity to keep gcc from optimizing this away. */ + printf ("This is a test %s.\n", argc > 1 ? argv[1] : "null"); ++#ifdef HAVE_SELINUX ++ /* This exists to force libselinux.so to be required. */ ++ printf ("selinux %d\n", is_selinux_enabled ()); ++#endif + return 0; + } +diff -rupN a/support/links-dso-program.cc b/support/links-dso-program.cc +--- a/support/links-dso-program.cc 2019-11-04 15:14:17.079234300 -0500 ++++ b/support/links-dso-program.cc 2019-11-04 15:15:10.587216328 -0500 +@@ -1,11 +1,28 @@ + #include + ++/* makedb needs selinux dso's. */ ++#ifdef HAVE_SELINUX ++# include ++#endif ++ + using namespace std; + ++/* The purpose of this file is to indicate to the build system which ++ shared objects need to be copied into the testroot, such as gcc or ++ selinux support libraries. This program is never executed, only ++ scanned for dependencies on shared objects, so the code below may ++ seem weird - it's written to survive gcc optimization and force ++ such dependencies. ++*/ ++ + int + main (int argc, char **argv) + { + /* Complexity to keep gcc from optimizing this away. */ + cout << (argc > 1 ? argv[1] : "null"); ++#ifdef HAVE_SELINUX ++ /* This exists to force libselinux.so to be required. */ ++ cout << "selinux " << is_selinux_enabled (); ++#endif + return 0; + } diff --git a/SOURCES/glibc-rh1747505-1.patch b/SOURCES/glibc-rh1747505-1.patch new file mode 100644 index 0000000..7569dff --- /dev/null +++ b/SOURCES/glibc-rh1747505-1.patch @@ -0,0 +1,196 @@ +commit 4b7c74179c8928d971d370e1137d202f891a4cf5 +Author: Carlos O'Donell +Date: Wed Mar 20 12:40:18 2019 -0400 + + nss: Make nsswitch.conf more distribution friendly. + + The current default nsswitch.conf file provided by glibc is not very + distribution friendly. The file contains some minimal directives that no + real distribution uses. This update aims to provide a rich set of + comments which are useful for all distributions, and a broader set of + service defines which should work for all distributions. + + Tested defaults on x86_64 and they work. The nsswitch.conf file more + closely matches what we have in Fedora now, and I'll adjust Fedora to + use this version with minor changes to enable Fedora-specific service + providers. + + v2 + - Add missing databases to manual. + - Add link to manual from default nsswitch.conf. + - Sort nsswitch.conf according to most used database first. + + v3 + - Only mention implemented services in 'NSS Basics.' + - Mention 'automount' in 'Services in the NSS configuration.' + - Sort services in alphabetical order. + + v4 + - Project name is 'Samba'. + + v5 + - Fix typo in manual/nss.texi. + + v6 + - Fix another typo in manual/nss.texi. Ran spell checker this time. + +diff --git a/manual/nss.texi b/manual/nss.texi +index 164ae33246..821469a78a 100644 +--- a/manual/nss.texi ++++ b/manual/nss.texi +@@ -56,13 +56,17 @@ functions to access the databases. + @noindent + The databases available in the NSS are + ++@cindex aliases + @cindex ethers + @cindex group ++@cindex gshadow + @cindex hosts ++@cindex initgroups + @cindex netgroup + @cindex networks +-@cindex protocols + @cindex passwd ++@cindex protocols ++@cindex publickey + @cindex rpc + @cindex services + @cindex shadow +@@ -75,16 +79,22 @@ Ethernet numbers, + @comment @pxref{Ethernet Numbers}. + @item group + Groups of users, @pxref{Group Database}. ++@item gshadow ++Group passphrase hashes and related information. + @item hosts + Host names and numbers, @pxref{Host Names}. ++@item initgroups ++Supplementary group access list. + @item netgroup + Network wide list of host and users, @pxref{Netgroup Database}. + @item networks + Network names and numbers, @pxref{Networks Database}. +-@item protocols +-Network protocols, @pxref{Protocols Database}. + @item passwd + User identities, @pxref{User Database}. ++@item protocols ++Network protocols, @pxref{Protocols Database}. ++@item publickey ++Public keys for Secure RPC. + @item rpc + Remote procedure call names and numbers. + @comment @pxref{RPC Database}. +@@ -96,8 +106,8 @@ User passphrase hashes and related information. + @end table + + @noindent +-There will be some more added later (@code{automount}, @code{bootparams}, +-@code{netmasks}, and @code{publickey}). ++@c We currently don't implement automount, netmasks, or bootparams. ++More databases may be added later. + + @node NSS Configuration File, NSS Module Internals, NSS Basics, Name Service Switch + @section The NSS Configuration File +@@ -159,6 +169,10 @@ these files since they should be placed in a directory where they are + found automatically. Only the names of all available services are + important. + ++Lastly, some system software may make use of the NSS configuration file ++to store their own configuration for similar purposes. Examples of this ++include the @code{automount} service which is used by @code{autofs}. ++ + @node Actions in the NSS configuration, Notes on NSS Configuration File, Services in the NSS configuration, NSS Configuration File + @subsection Actions in the NSS configuration + +diff --git a/nss/nsswitch.conf b/nss/nsswitch.conf +index 39ca88bf51..f553588114 100644 +--- a/nss/nsswitch.conf ++++ b/nss/nsswitch.conf +@@ -1,20 +1,69 @@ ++# + # /etc/nsswitch.conf + # +-# Example configuration of GNU Name Service Switch functionality. ++# An example Name Service Switch config file. This file should be ++# sorted with the most-used services at the beginning. + # ++# Valid databases are: aliases, ethers, group, gshadow, hosts, ++# initgroups, netgroup, networks, passwd, protocols, publickey, ++# rpc, services, and shadow. ++# ++# Valid service provider entries include (in alphabetical order): ++# ++# compat Use /etc files plus *_compat pseudo-db ++# db Use the pre-processed /var/db files ++# dns Use DNS (Domain Name Service) ++# files Use the local files in /etc ++# hesiod Use Hesiod (DNS) for user lookups ++# nis Use NIS (NIS version 2), also called YP ++# nisplus Use NIS+ (NIS version 3) ++# ++# See `info libc 'NSS Basics'` for more information. ++# ++# Commonly used alternative service providers (may need installation): ++# ++# ldap Use LDAP directory server ++# myhostname Use systemd host names ++# mymachines Use systemd machine names ++# mdns*, mdns*_minimal Use Avahi mDNS/DNS-SD ++# resolve Use systemd resolved resolver ++# sss Use System Security Services Daemon (sssd) ++# systemd Use systemd for dynamic user option ++# winbind Use Samba winbind support ++# wins Use Samba wins support ++# wrapper Use wrapper module for testing ++# ++# Notes: ++# ++# 'sssd' performs its own 'files'-based caching, so it should generally ++# come before 'files'. ++# ++# WARNING: Running nscd with a secondary caching service like sssd may ++# lead to unexpected behaviour, especially with how long ++# entries are cached. ++# ++# Installation instructions: ++# ++# To use 'db', install the appropriate package(s) (provide 'makedb' and ++# libnss_db.so.*), and place the 'db' in front of 'files' for entries ++# you want to be looked up first in the databases, like this: ++# ++# passwd: db files ++# shadow: db files ++# group: db files + +-passwd: db files +-group: db files +-initgroups: db [SUCCESS=continue] files +-shadow: db files +-gshadow: files +- +-hosts: files dns +-networks: files dns +- +-protocols: db files +-services: db files +-ethers: db files +-rpc: db files +- +-netgroup: db files ++# In alphabetical order. Re-order as required to optimize peformance. ++aliases: files ++ethers: files ++group: files ++gshadow: files ++hosts: files dns ++initgroups: files ++netgroup: files ++networks: files dns ++passwd: files ++protocols: files ++publickey: files ++rpc: files ++shadow: files ++services: files diff --git a/SOURCES/glibc-rh1747505-2.patch b/SOURCES/glibc-rh1747505-2.patch new file mode 100644 index 0000000..085c2c3 --- /dev/null +++ b/SOURCES/glibc-rh1747505-2.patch @@ -0,0 +1,38 @@ +commit d34d4c80226b3f5a1b51a8e5b005a52fba07d7ba +Author: Carlos O'Donell +Date: Wed Mar 20 22:11:32 2019 -0400 + + nscd: Improve nscd.conf comments. + + This change adds a warning to nscd.conf about running multiple caching + services together and that it may lead to unexpected behaviours. Also we + add a note that enabling the 'shared' option will cause cache hit rates + to be misreported (a side effect of the implementation). + + v2 + - Rewrite comment to avoid implementation details. + +diff --git a/nscd/nscd.conf b/nscd/nscd.conf +index 39b875912d..487ffe461d 100644 +--- a/nscd/nscd.conf ++++ b/nscd/nscd.conf +@@ -3,6 +3,9 @@ + # + # An example Name Service Cache config file. This file is needed by nscd. + # ++# WARNING: Running nscd with a secondary caching service like sssd may lead to ++# unexpected behaviour, especially with how long entries are cached. ++# + # Legal entries are: + # + # logfile +@@ -23,6 +26,9 @@ + # check-files + # persistent + # shared ++# NOTE: Setting 'shared' to a value of 'yes' will accelerate the lookup, ++# but those lookups will not be counted as cache hits ++# i.e. 'nscd -g' may show '0%'. + # max-db-size + # auto-propagate + # diff --git a/SOURCES/glibc-rh1747505-3.patch b/SOURCES/glibc-rh1747505-3.patch new file mode 100644 index 0000000..01e4959 --- /dev/null +++ b/SOURCES/glibc-rh1747505-3.patch @@ -0,0 +1,40 @@ +diff -Nrup a/nss/nsswitch.conf b/nss/nsswitch.conf +--- a/nss/nsswitch.conf 2019-10-25 12:14:09.255834866 -0400 ++++ b/nss/nsswitch.conf 2019-10-25 12:50:08.425769248 -0400 +@@ -1,7 +1,7 @@ + # + # /etc/nsswitch.conf + # +-# An example Name Service Switch config file. This file should be ++# Name Service Switch config file. This file should be + # sorted with the most-used services at the beginning. + # + # Valid databases are: aliases, ethers, group, gshadow, hosts, +@@ -52,18 +52,20 @@ + # shadow: db files + # group: db files + +-# In alphabetical order. Re-order as required to optimize peformance. ++# In order of likelihood of use to accelerate lookup. ++passwd: sss files ++shadow: files sss ++group: sss files ++hosts: files dns myhostname ++services: files sss ++netgroup: sss ++automount: files sss ++ + aliases: files + ethers: files +-group: files + gshadow: files +-hosts: files dns + initgroups: files +-netgroup: files + networks: files dns +-passwd: files + protocols: files + publickey: files + rpc: files +-shadow: files +-services: files diff --git a/SOURCES/glibc-rh1747505-4.patch b/SOURCES/glibc-rh1747505-4.patch new file mode 100644 index 0000000..c0a9b7f --- /dev/null +++ b/SOURCES/glibc-rh1747505-4.patch @@ -0,0 +1,27 @@ +commit eed1f6fcdb0526498223ebfe95f91ef5dec2172a +Author: Carlos O'Donell +Date: Tue Oct 29 11:58:03 2019 -0400 + + Comment out initgroups from example nsswitch.conf (Bug 25146) + + In commit 4b7c74179c8928d971d370e1137d202f891a4cf5 the nsswitch.conf + file was harmonized with downstream distributions, but this change + included adding "initgroups: files". We should not add initgroups by + default, we can have it, but it should be commented out to allow it + to inherit the settings for group. The problem is principally that + downstream authconfig won't update initgroups and it will get out of + sync with the setting for group. + +diff -Nrup a/nss/nsswitch.conf b/nss/nsswitch.conf +--- a/nss/nsswitch.conf 2019-10-29 14:13:15.883199544 -0400 ++++ b/nss/nsswitch.conf 2019-10-29 14:15:44.860978858 -0400 +@@ -64,7 +64,8 @@ automount: files sss + aliases: files + ethers: files + gshadow: files +-initgroups: files ++# Allow initgroups to default to the setting for group. ++# initgroups: files + networks: files dns + protocols: files + publickey: files diff --git a/SOURCES/glibc-rh1748197-1.patch b/SOURCES/glibc-rh1748197-1.patch new file mode 100644 index 0000000..4a68281 --- /dev/null +++ b/SOURCES/glibc-rh1748197-1.patch @@ -0,0 +1,18 @@ +commit 27cec9aed97447dff887a88f4241604fffd8c525 +Author: Florian Weimer +Date: Tue Jul 2 16:45:52 2019 +0200 + + malloc: Add nptl, htl dependency for the subdirectory [BZ #24757] + + memusagestat may indirectly link against libpthread. The built + libpthread should be used, but that is only possible if it has been + built before the malloc programs. + +diff --git a/malloc/Depend b/malloc/Depend +index 910c6d915211870f..f5e248047c4c46dd 100644 +--- a/malloc/Depend ++++ b/malloc/Depend +@@ -1 +1,3 @@ + dlfcn ++nptl ++htl diff --git a/SOURCES/glibc-rh1748197-2.patch b/SOURCES/glibc-rh1748197-2.patch new file mode 100644 index 0000000..483c4f9 --- /dev/null +++ b/SOURCES/glibc-rh1748197-2.patch @@ -0,0 +1,996 @@ +commit 41d6f74e6cb6a92ab428c11ee1e408b2a16aa1b0 +Author: Florian Weimer +Date: Tue Jul 2 15:12:20 2019 +0200 + + nptl: Remove vfork IFUNC-based forwarder from libpthread [BZ #20188] + + With commit f0b2132b35248c1f4a80f62a2c38cddcc802aa8c ("ld.so: + Support moving versioned symbols between sonames [BZ #24741]"), the + dynamic linker will find the definition of vfork in libc and binds + a vfork reference to that symbol, even if the soname in the version + reference says that the symbol should be located in libpthread. + + As a result, the forwarder (whether it's IFUNC-based or a duplicate + of the libc implementation) is no longer necessary. + + On older architectures, a placeholder symbol is required, to make sure + that the GLIBC_2.1.2 symbol version does not go away, or is turned in + to a weak symbol definition by the link editor. (The symbol version + needs to preserved so that the symbol coverage check in + elf/dl-version.c does not fail for old binaries.) + + mips32 is an outlier: It defined __vfork@@GLIBC_2.2, but the + baseline is GLIBC_2.0. Since there are other @@GLIBC_2.2 symbols, + the placeholder symbol is not needed there. + +Conflicts: + nptl/Makefile + (Missing lll_timedwait_tid removal, missing pthread_mutex_conf.) + nptl/pt-vfork.c + sysdeps/unix/sysv/linux/aarch64/pt-vfork.c + sysdeps/unix/sysv/linux/alpha/pt-vfork.S + sysdeps/unix/sysv/linux/hppa/pt-vfork.S + sysdeps/unix/sysv/linux/ia64/pt-vfork.S + sysdeps/unix/sysv/linux/microblaze/pt-vfork.S + (Removal after copyright year change upstream.) + +diff --git a/nptl/Makefile b/nptl/Makefile +index 071c53866d14d2fe..447dce0590295c9c 100644 +--- a/nptl/Makefile ++++ b/nptl/Makefile +@@ -121,7 +121,7 @@ libpthread-routines = nptl-init nptlfreeres vars events version pt-interp \ + cancellation \ + lowlevellock \ + lll_timedlock_wait lll_timedwait_tid \ +- pt-fork pt-vfork pt-fcntl \ ++ pt-fork pt-fcntl \ + $(pthread-compat-wrappers) \ + pt-raise pt-system \ + flockfile ftrylockfile funlockfile \ +@@ -145,7 +145,8 @@ libpthread-routines = nptl-init nptlfreeres vars events version pt-interp \ + mtx_destroy mtx_init mtx_lock mtx_timedlock \ + mtx_trylock mtx_unlock call_once cnd_broadcast \ + cnd_destroy cnd_init cnd_signal cnd_timedwait cnd_wait \ +- tss_create tss_delete tss_get tss_set ++ tss_create tss_delete tss_get tss_set \ ++ libpthread-compat + # pthread_setuid pthread_seteuid pthread_setreuid \ + # pthread_setresuid \ + # pthread_setgid pthread_setegid pthread_setregid \ +diff --git a/nptl/Versions b/nptl/Versions +index e7f691da7a15e9c3..6007fd03e7ed117c 100644 +--- a/nptl/Versions ++++ b/nptl/Versions +@@ -36,7 +36,6 @@ libc { + __libc_alloca_cutoff; + # Internal libc interface to libpthread + __libc_dl_error_tsd; +- __libc_vfork; + __libc_pthread_init; + __libc_current_sigrtmin_private; __libc_current_sigrtmax_private; + __libc_allocate_rtsig_private; +@@ -98,7 +97,7 @@ libpthread { + sem_destroy; sem_getvalue; sem_init; sem_post; sem_trywait; sem_wait; + + # Special fork handling. +- fork; __fork; vfork; ++ fork; __fork; + + # Cancellation points. + close; __close; fcntl; __fcntl; read; __read; write; __write; accept; +@@ -152,7 +151,7 @@ libpthread { + } + + GLIBC_2.1.2 { +- __vfork; ++ __libpthread_version_placeholder; + } + + GLIBC_2.2 { +diff --git a/nptl/libpthread-compat.c b/nptl/libpthread-compat.c +new file mode 100644 +index 0000000000000000..ea29e9f47b698a25 +--- /dev/null ++++ b/nptl/libpthread-compat.c +@@ -0,0 +1,37 @@ ++/* Placeholder definitions to pull in removed symbol versions. ++ 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, see ++ . */ ++ ++#include ++ ++/* This is an unused compatibility symbol definition, to prevent ld ++ from creating a weak version definition for GLIBC_2.1.2. (__vfork ++ used to be defined at that version, but it is now provided by libc, ++ and there are no versions left in libpthread for that symbol ++ version.) If the ABI baseline for glibc is the GLIBC_2.2 symbol ++ version or later, the placeholder symbol is not needed because ++ there are plenty of other symbols which populate those later ++ versions. */ ++#if (SHLIB_COMPAT (libpthread, GLIBC_2_1_2, GLIBC_2_2)) ++void ++attribute_compat_text_section ++__libpthread_version_placeholder (void) ++{ ++} ++compat_symbol (libpthread, __libpthread_version_placeholder, ++ __libpthread_version_placeholder, GLIBC_2_1_2); ++#endif +diff --git a/nptl/pt-vfork.c b/nptl/pt-vfork.c +deleted file mode 100644 +index 2f890d3f3070d0e2..0000000000000000 +--- a/nptl/pt-vfork.c ++++ /dev/null +@@ -1,65 +0,0 @@ +-/* vfork ABI-compatibility entry points for libpthread. +- Copyright (C) 2014-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 +- +-/* libpthread used to have its own vfork implementation that differed +- from libc's only in having a pointless micro-optimization. There +- is no longer any use to having a separate copy in libpthread, but +- the historical ABI requires it. For static linking, there is no +- need to provide anything here--the libc version will be linked in. +- For shared library ABI compatibility, there must be __vfork and +- vfork symbols in libpthread.so; so we define them using IFUNC to +- redirect to the libc function. */ +- +-/* Note! If the architecture doesn't support IFUNC, then we need an +- alternate target-specific mechanism to implement this. So we just +- assume IFUNC here and require that the target override this file +- if necessary. +- +- If the architecture can assume all supported versions of gcc will +- produce a tail-call to __libc_vfork, consider including the version +- in sysdeps/unix/sysv/linux/aarch64/pt-vfork.c. */ +- +-#if !HAVE_IFUNC +-# error "must write pt-vfork for this machine or get IFUNC support" +-#endif +- +-#if (SHLIB_COMPAT (libpthread, GLIBC_2_0, GLIBC_2_20) \ +- || SHLIB_COMPAT (libpthread, GLIBC_2_1_2, GLIBC_2_20)) +- +-extern __typeof (vfork) __libc_vfork; /* Defined in libc. */ +- +-# undef INIT_ARCH +-# define INIT_ARCH() +-# define DEFINE_VFORK(name) libc_ifunc (name, &__libc_vfork) +- +-#endif +- +-#if SHLIB_COMPAT (libpthread, GLIBC_2_0, GLIBC_2_20) +-extern __typeof(vfork) vfork_ifunc; +-DEFINE_VFORK (vfork_ifunc) +-compat_symbol (libpthread, vfork_ifunc, vfork, GLIBC_2_0); +-#endif +- +-#if SHLIB_COMPAT (libpthread, GLIBC_2_1_2, GLIBC_2_20) +-extern __typeof(vfork) __vfork_ifunc; +-DEFINE_VFORK (__vfork_ifunc) +-compat_symbol (libpthread, __vfork_ifunc, __vfork, GLIBC_2_1_2); +-#endif +diff --git a/sysdeps/unix/sysv/linux/aarch64/libpthread.abilist b/sysdeps/unix/sysv/linux/aarch64/libpthread.abilist +index 9a9e4cee85b18a35..6945b7cbe4c2bde8 100644 +--- a/sysdeps/unix/sysv/linux/aarch64/libpthread.abilist ++++ b/sysdeps/unix/sysv/linux/aarch64/libpthread.abilist +@@ -45,7 +45,6 @@ GLIBC_2.17 __read F + GLIBC_2.17 __res_state F + GLIBC_2.17 __send F + GLIBC_2.17 __sigaction F +-GLIBC_2.17 __vfork F + GLIBC_2.17 __wait F + GLIBC_2.17 __write F + GLIBC_2.17 _pthread_cleanup_pop F +@@ -216,7 +215,6 @@ GLIBC_2.17 siglongjmp F + GLIBC_2.17 sigwait F + GLIBC_2.17 system F + GLIBC_2.17 tcdrain F +-GLIBC_2.17 vfork F + GLIBC_2.17 wait F + GLIBC_2.17 waitpid F + GLIBC_2.17 write F +diff --git a/sysdeps/unix/sysv/linux/aarch64/pt-vfork.c b/sysdeps/unix/sysv/linux/aarch64/pt-vfork.c +deleted file mode 100644 +index 2b277f25ec200be2..0000000000000000 +--- a/sysdeps/unix/sysv/linux/aarch64/pt-vfork.c ++++ /dev/null +@@ -1,54 +0,0 @@ +-/* vfork ABI-compatibility entry points for libpthread. +- Copyright (C) 2014-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 +- +-/* libpthread used to have its own vfork implementation that differed +- from libc's only in having a pointless micro-optimization. There +- is no longer any use to having a separate copy in libpthread, but +- the historical ABI requires it. For static linking, there is no +- need to provide anything here--the libc version will be linked in. +- For shared library ABI compatibility, there must be __vfork and +- vfork symbols in libpthread.so. */ +- +-#if HAVE_IFUNC +-# include +-#elif (SHLIB_COMPAT (libpthread, GLIBC_2_0, GLIBC_2_20) \ +- || SHLIB_COMPAT (libpthread, GLIBC_2_1_2, GLIBC_2_20)) +- +-/* Thankfully, on AArch64 we can rely on the compiler generating +- a tail call here. */ +- +-extern void __libc_vfork (void); +- +-void +-vfork_compat (void) +-{ +- __libc_vfork (); +-} +- +-# if SHLIB_COMPAT (libpthread, GLIBC_2_0, GLIBC_2_20) +-compat_symbol (libpthread, vfork_compat, vfork, GLIBC_2_0); +-# endif +- +-# if SHLIB_COMPAT (libpthread, GLIBC_2_1_2, GLIBC_2_20) +-strong_alias (vfork_compat, vfork_compat2) +-compat_symbol (libpthread, vfork_compat2, __vfork, GLIBC_2_1_2); +-# endif +- +-#endif +diff --git a/sysdeps/unix/sysv/linux/alpha/libpthread.abilist b/sysdeps/unix/sysv/linux/alpha/libpthread.abilist +index b413007ccbd2b7b3..2d9b958efa99feb8 100644 +--- a/sysdeps/unix/sysv/linux/alpha/libpthread.abilist ++++ b/sysdeps/unix/sysv/linux/alpha/libpthread.abilist +@@ -114,7 +114,6 @@ GLIBC_2.0 siglongjmp F + GLIBC_2.0 sigwait F + GLIBC_2.0 system F + GLIBC_2.0 tcdrain F +-GLIBC_2.0 vfork F + GLIBC_2.0 wait F + GLIBC_2.0 waitpid F + GLIBC_2.0 write F +@@ -155,7 +154,7 @@ GLIBC_2.1 sem_wait F + GLIBC_2.1.1 sem_close F + GLIBC_2.1.1 sem_open F + GLIBC_2.1.1 sem_unlink F +-GLIBC_2.1.2 __vfork F ++GLIBC_2.1.2 __libpthread_version_placeholder F + GLIBC_2.11 pthread_sigqueue F + GLIBC_2.12 pthread_getname_np F + GLIBC_2.12 pthread_mutex_consistent F +diff --git a/sysdeps/unix/sysv/linux/alpha/pt-vfork.S b/sysdeps/unix/sysv/linux/alpha/pt-vfork.S +deleted file mode 100644 +index 7ecaa78dd0eda2fe..0000000000000000 +--- a/sysdeps/unix/sysv/linux/alpha/pt-vfork.S ++++ /dev/null +@@ -1,43 +0,0 @@ +-/* vfork ABI-compatibility entry points for libpthread. +- Copyright (C) 2014-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 +- +-/* libpthread used to have its own vfork implementation that differed +- from libc's only in having a pointless micro-optimization. There +- is no longer any use to having a separate copy in libpthread, but +- the historical ABI requires it. For static linking, there is no +- need to provide anything here--the libc version will be linked in. +- For shared library ABI compatibility, there must be __vfork and +- vfork symbols in libpthread.so. */ +- +-#if (SHLIB_COMPAT (libpthread, GLIBC_2_0, GLIBC_2_20) \ +- || SHLIB_COMPAT (libpthread, GLIBC_2_1_2, GLIBC_2_20)) +- +-#include +- +-#endif +- +-#if SHLIB_COMPAT (libpthread, GLIBC_2_0, GLIBC_2_20) +-compat_symbol (libpthread, __libc_vfork, vfork, GLIBC_2_0); +-#endif +- +-#if SHLIB_COMPAT (libpthread, GLIBC_2_1_2, GLIBC_2_20) +-strong_alias (__libc_vfork, __vfork_compat) +-compat_symbol (libpthread, __vfork_compat, __vfork, GLIBC_2_1_2); +-#endif +diff --git a/sysdeps/unix/sysv/linux/arm/libpthread.abilist b/sysdeps/unix/sysv/linux/arm/libpthread.abilist +index af82a4c632988185..ee3d0290d01f184e 100644 +--- a/sysdeps/unix/sysv/linux/arm/libpthread.abilist ++++ b/sysdeps/unix/sysv/linux/arm/libpthread.abilist +@@ -74,7 +74,6 @@ GLIBC_2.4 __read F + GLIBC_2.4 __res_state F + GLIBC_2.4 __send F + GLIBC_2.4 __sigaction F +-GLIBC_2.4 __vfork F + GLIBC_2.4 __wait F + GLIBC_2.4 __write F + GLIBC_2.4 _pthread_cleanup_pop F +@@ -239,7 +238,6 @@ GLIBC_2.4 siglongjmp F + GLIBC_2.4 sigwait F + GLIBC_2.4 system F + GLIBC_2.4 tcdrain F +-GLIBC_2.4 vfork F + GLIBC_2.4 wait F + GLIBC_2.4 waitpid F + GLIBC_2.4 write F +diff --git a/sysdeps/unix/sysv/linux/hppa/libpthread.abilist b/sysdeps/unix/sysv/linux/hppa/libpthread.abilist +index bcba07f57558174f..e9b3be6ac8e8f367 100644 +--- a/sysdeps/unix/sysv/linux/hppa/libpthread.abilist ++++ b/sysdeps/unix/sysv/linux/hppa/libpthread.abilist +@@ -46,7 +46,6 @@ GLIBC_2.2 __read F + GLIBC_2.2 __res_state F + GLIBC_2.2 __send F + GLIBC_2.2 __sigaction F +-GLIBC_2.2 __vfork F + GLIBC_2.2 __wait F + GLIBC_2.2 __write F + GLIBC_2.2 _pthread_cleanup_pop F +@@ -192,7 +191,6 @@ GLIBC_2.2 siglongjmp F + GLIBC_2.2 sigwait F + GLIBC_2.2 system F + GLIBC_2.2 tcdrain F +-GLIBC_2.2 vfork F + GLIBC_2.2 wait F + GLIBC_2.2 waitpid F + GLIBC_2.2 write F +diff --git a/sysdeps/unix/sysv/linux/hppa/localplt.data b/sysdeps/unix/sysv/linux/hppa/localplt.data +index 5f3475de191778f6..867413f0c54d3d71 100644 +--- a/sysdeps/unix/sysv/linux/hppa/localplt.data ++++ b/sysdeps/unix/sysv/linux/hppa/localplt.data +@@ -10,7 +10,6 @@ libc.so: __sigsetjmp + libc.so: _IO_funlockfile + libc.so: __errno_location + libm.so: matherr +-libpthread.so: __errno_location + # The main malloc is interposed into the dynamic linker, for + # allocations after the initial link (when dlopen is used). + ld.so: malloc +diff --git a/sysdeps/unix/sysv/linux/hppa/pt-vfork.S b/sysdeps/unix/sysv/linux/hppa/pt-vfork.S +deleted file mode 100644 +index 45f7620d90cb5b8f..0000000000000000 +--- a/sysdeps/unix/sysv/linux/hppa/pt-vfork.S ++++ /dev/null +@@ -1,82 +0,0 @@ +-/* 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 +- . */ +- +-#include +-#define _ERRNO_H 1 +-#include +-#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. */ +- +-.Lthread_start: ASM_LINE_SEP +- +- /* r26, r25, r24, r23 are free since vfork has no arguments */ +-ENTRY(__vfork) +- /* We must not create a frame. When the child unwinds to call +- exec it will clobber the same frame that the parent +- needs to unwind. */ +- +- /* Save the PIC register. */ +-#ifdef PIC +- copy %r19, %r25 /* parent */ +-#endif +- +- /* Syscall saves and restores all register states */ +- ble 0x100(%sr2,%r0) +- ldi __NR_vfork,%r20 +- +- /* Check for error */ +- ldi -4096,%r1 +- comclr,>>= %r1,%ret0,%r0 /* Note: unsigned compare. */ +- b,n .Lerror +- +- /* Return, and DO NOT restore rp. The child may have called +- functions that updated the frame's rp. This works because +- the kernel ensures rp is preserved across the vfork +- syscall. */ +- bv,n %r0(%rp) +- +-.Lerror: +- /* Now we need a stack to call a function. We are assured +- that there is no child now, so it's safe to create +- a frame. */ +- stw %rp, -20(%sp) +- .cfi_offset 2, -20 +- stwm %r3, 64(%sp) +- .cfi_def_cfa_offset -64 +- .cfi_offset 3, 0 +- stw %sp, -4(%sp) +- +- sub %r0,%ret0,%r3 +- SYSCALL_ERROR_HANDLER +- /* Restore the PIC register (in delay slot) on error */ +-#ifdef PIC +- copy %r25, %r19 /* parent */ +-#else +- nop +-#endif +- /* Write syscall return into errno location */ +- stw %r3, 0(%ret0) +- ldw -84(%sp), %rp +- bv %r0(%rp) +- ldwm -64(%sp), %r3 +-PSEUDO_END (__vfork) +-libc_hidden_def (__vfork) +-weak_alias (__vfork, vfork) +diff --git a/sysdeps/unix/sysv/linux/i386/libpthread.abilist b/sysdeps/unix/sysv/linux/i386/libpthread.abilist +index bece86d24624ea26..7199aae573649f49 100644 +--- a/sysdeps/unix/sysv/linux/i386/libpthread.abilist ++++ b/sysdeps/unix/sysv/linux/i386/libpthread.abilist +@@ -114,7 +114,6 @@ GLIBC_2.0 siglongjmp F + GLIBC_2.0 sigwait F + GLIBC_2.0 system F + GLIBC_2.0 tcdrain F +-GLIBC_2.0 vfork F + GLIBC_2.0 wait F + GLIBC_2.0 waitpid F + GLIBC_2.0 write F +@@ -155,7 +154,7 @@ GLIBC_2.1 sem_wait F + GLIBC_2.1.1 sem_close F + GLIBC_2.1.1 sem_open F + GLIBC_2.1.1 sem_unlink F +-GLIBC_2.1.2 __vfork F ++GLIBC_2.1.2 __libpthread_version_placeholder F + GLIBC_2.11 pthread_sigqueue F + GLIBC_2.12 pthread_getname_np F + GLIBC_2.12 pthread_mutex_consistent F +diff --git a/sysdeps/unix/sysv/linux/ia64/libpthread.abilist b/sysdeps/unix/sysv/linux/ia64/libpthread.abilist +index ccc94498268a5c74..e8a65642caec7ff1 100644 +--- a/sysdeps/unix/sysv/linux/ia64/libpthread.abilist ++++ b/sysdeps/unix/sysv/linux/ia64/libpthread.abilist +@@ -46,7 +46,6 @@ GLIBC_2.2 __read F + GLIBC_2.2 __res_state F + GLIBC_2.2 __send F + GLIBC_2.2 __sigaction F +-GLIBC_2.2 __vfork F + GLIBC_2.2 __wait F + GLIBC_2.2 __write F + GLIBC_2.2 _pthread_cleanup_pop F +@@ -192,7 +191,6 @@ GLIBC_2.2 siglongjmp F + GLIBC_2.2 sigwait F + GLIBC_2.2 system F + GLIBC_2.2 tcdrain F +-GLIBC_2.2 vfork F + GLIBC_2.2 wait F + GLIBC_2.2 waitpid F + GLIBC_2.2 write F +diff --git a/sysdeps/unix/sysv/linux/ia64/pt-vfork.S b/sysdeps/unix/sysv/linux/ia64/pt-vfork.S +deleted file mode 100644 +index 61f3e387b455d731..0000000000000000 +--- a/sysdeps/unix/sysv/linux/ia64/pt-vfork.S ++++ /dev/null +@@ -1,48 +0,0 @@ +-/* vfork ABI-compatibility entry points for libpthread. IA64 version. +- Copyright (C) 2014-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 +- +-/* libpthread used to have its own vfork implementation that differed +- from libc's only in having a pointless micro-optimization. There +- is no longer any use to having a separate copy in libpthread, but +- the historical ABI requires it. For static linking, there is no +- need to provide anything here--the libc version will be linked in. +- For shared library ABI compatibility, there must be __vfork and +- vfork symbols in libpthread.so. */ +- +-#if (SHLIB_COMPAT (libpthread, GLIBC_2_0, GLIBC_2_20) \ +- || SHLIB_COMPAT (libpthread, GLIBC_2_1_2, GLIBC_2_20)) +- +-LOCAL_LEAF (vfork_compat) +- br __libc_vfork +- ;; +-END (vfork_compat) +- +-#endif +- +-#if SHLIB_COMPAT (libpthread, GLIBC_2_0, GLIBC_2_20) +-weak_alias (vfork_compat, vfork) +-compat_symbol (libpthread, vfork_compat, vfork, GLIBC_2_0); +-#endif +- +-#if SHLIB_COMPAT (libpthread, GLIBC_2_1_2, GLIBC_2_20) +-strong_alias (vfork_compat, __vfork_compat) +-compat_symbol (libpthread, __vfork_compat, __vfork, GLIBC_2_1_2); +-#endif +diff --git a/sysdeps/unix/sysv/linux/m68k/coldfire/libpthread.abilist b/sysdeps/unix/sysv/linux/m68k/coldfire/libpthread.abilist +index af82a4c632988185..ee3d0290d01f184e 100644 +--- a/sysdeps/unix/sysv/linux/m68k/coldfire/libpthread.abilist ++++ b/sysdeps/unix/sysv/linux/m68k/coldfire/libpthread.abilist +@@ -74,7 +74,6 @@ GLIBC_2.4 __read F + GLIBC_2.4 __res_state F + GLIBC_2.4 __send F + GLIBC_2.4 __sigaction F +-GLIBC_2.4 __vfork F + GLIBC_2.4 __wait F + GLIBC_2.4 __write F + GLIBC_2.4 _pthread_cleanup_pop F +@@ -239,7 +238,6 @@ GLIBC_2.4 siglongjmp F + GLIBC_2.4 sigwait F + GLIBC_2.4 system F + GLIBC_2.4 tcdrain F +-GLIBC_2.4 vfork F + GLIBC_2.4 wait F + GLIBC_2.4 waitpid F + GLIBC_2.4 write F +diff --git a/sysdeps/unix/sysv/linux/m68k/m680x0/libpthread.abilist b/sysdeps/unix/sysv/linux/m68k/m680x0/libpthread.abilist +index bece86d24624ea26..7199aae573649f49 100644 +--- a/sysdeps/unix/sysv/linux/m68k/m680x0/libpthread.abilist ++++ b/sysdeps/unix/sysv/linux/m68k/m680x0/libpthread.abilist +@@ -114,7 +114,6 @@ GLIBC_2.0 siglongjmp F + GLIBC_2.0 sigwait F + GLIBC_2.0 system F + GLIBC_2.0 tcdrain F +-GLIBC_2.0 vfork F + GLIBC_2.0 wait F + GLIBC_2.0 waitpid F + GLIBC_2.0 write F +@@ -155,7 +154,7 @@ GLIBC_2.1 sem_wait F + GLIBC_2.1.1 sem_close F + GLIBC_2.1.1 sem_open F + GLIBC_2.1.1 sem_unlink F +-GLIBC_2.1.2 __vfork F ++GLIBC_2.1.2 __libpthread_version_placeholder F + GLIBC_2.11 pthread_sigqueue F + GLIBC_2.12 pthread_getname_np F + GLIBC_2.12 pthread_mutex_consistent F +diff --git a/sysdeps/unix/sysv/linux/m68k/pt-vfork.c b/sysdeps/unix/sysv/linux/m68k/pt-vfork.c +deleted file mode 100644 +index 5fbc6526aa2af493..0000000000000000 +--- a/sysdeps/unix/sysv/linux/m68k/pt-vfork.c ++++ /dev/null +@@ -1 +0,0 @@ +-#include +diff --git a/sysdeps/unix/sysv/linux/microblaze/libpthread.abilist b/sysdeps/unix/sysv/linux/microblaze/libpthread.abilist +index 5067375d237a0c9f..e0fbe6848f7945bd 100644 +--- a/sysdeps/unix/sysv/linux/microblaze/libpthread.abilist ++++ b/sysdeps/unix/sysv/linux/microblaze/libpthread.abilist +@@ -45,7 +45,6 @@ GLIBC_2.18 __read F + GLIBC_2.18 __res_state F + GLIBC_2.18 __send F + GLIBC_2.18 __sigaction F +-GLIBC_2.18 __vfork F + GLIBC_2.18 __wait F + GLIBC_2.18 __write F + GLIBC_2.18 _pthread_cleanup_pop F +@@ -218,7 +217,6 @@ GLIBC_2.18 siglongjmp F + GLIBC_2.18 sigwait F + GLIBC_2.18 system F + GLIBC_2.18 tcdrain F +-GLIBC_2.18 vfork F + GLIBC_2.18 wait F + GLIBC_2.18 waitpid F + GLIBC_2.18 write F +diff --git a/sysdeps/unix/sysv/linux/microblaze/pt-vfork.S b/sysdeps/unix/sysv/linux/microblaze/pt-vfork.S +deleted file mode 100644 +index 74bc1cdf7455f597..0000000000000000 +--- a/sysdeps/unix/sysv/linux/microblaze/pt-vfork.S ++++ /dev/null +@@ -1,49 +0,0 @@ +-/* vfork ABI-compatibility entry points for libpthread. +- Copyright (C) 2014-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 +- +-/* libpthread used to have its own vfork implementation that differed +- from libc's only in having a pointless micro-optimization. There +- is no longer any use to having a separate copy in libpthread, but +- the historical ABI requires it. For static linking, there is no +- need to provide anything here--the libc version will be linked in. +- For shared library ABI compatibility, there must be __vfork and +- vfork symbols in libpthread.so. +- +- As of GCC 7, microblaze can *not* rely on the compiler to generate +- a tail call from this vfork to __libc_vfork. */ +- +-#if (SHLIB_COMPAT (libpthread, GLIBC_2_0, GLIBC_2_20) \ +- || SHLIB_COMPAT (libpthread, GLIBC_2_1_2, GLIBC_2_20)) +- +-ENTRY (vfork_compat) +- bri __libc_vfork@PLT +-END (vfork_compat) +- +-#endif +- +-#if SHLIB_COMPAT (libpthread, GLIBC_2_0, GLIBC_2_20) +-compat_symbol (libpthread, vfork_compat, vfork, GLIBC_2_0) +-#endif +- +-#if SHLIB_COMPAT (libpthread, GLIBC_2_1_2, GLIBC_2_20) +-strong_alias (vfork_compat, vfork_compat2) +-compat_symbol (libpthread, vfork_compat2, __vfork, GLIBC_2_1_2) +-#endif +diff --git a/sysdeps/unix/sysv/linux/mips/mips32/libpthread.abilist b/sysdeps/unix/sysv/linux/mips/mips32/libpthread.abilist +index 02144967c638cdbe..f60b22efb5b5f683 100644 +--- a/sysdeps/unix/sysv/linux/mips/mips32/libpthread.abilist ++++ b/sysdeps/unix/sysv/linux/mips/mips32/libpthread.abilist +@@ -114,7 +114,6 @@ GLIBC_2.0 siglongjmp F + GLIBC_2.0 sigwait F + GLIBC_2.0 system F + GLIBC_2.0 tcdrain F +-GLIBC_2.0 vfork F + GLIBC_2.0 wait F + GLIBC_2.0 waitpid F + GLIBC_2.0 write F +@@ -140,7 +139,6 @@ 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 __vfork F + GLIBC_2.2 lseek64 F + GLIBC_2.2 open64 F + GLIBC_2.2 pread F +diff --git a/sysdeps/unix/sysv/linux/mips/mips64/libpthread.abilist b/sysdeps/unix/sysv/linux/mips/mips64/libpthread.abilist +index 02144967c638cdbe..f60b22efb5b5f683 100644 +--- a/sysdeps/unix/sysv/linux/mips/mips64/libpthread.abilist ++++ b/sysdeps/unix/sysv/linux/mips/mips64/libpthread.abilist +@@ -114,7 +114,6 @@ GLIBC_2.0 siglongjmp F + GLIBC_2.0 sigwait F + GLIBC_2.0 system F + GLIBC_2.0 tcdrain F +-GLIBC_2.0 vfork F + GLIBC_2.0 wait F + GLIBC_2.0 waitpid F + GLIBC_2.0 write F +@@ -140,7 +139,6 @@ 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 __vfork F + GLIBC_2.2 lseek64 F + GLIBC_2.2 open64 F + GLIBC_2.2 pread F +diff --git a/sysdeps/unix/sysv/linux/mips/pt-vfork.S b/sysdeps/unix/sysv/linux/mips/pt-vfork.S +deleted file mode 100644 +index 65cc3823ac872b35..0000000000000000 +--- a/sysdeps/unix/sysv/linux/mips/pt-vfork.S ++++ /dev/null +@@ -1 +0,0 @@ +-#include +diff --git a/sysdeps/unix/sysv/linux/nios2/pt-vfork.S b/sysdeps/unix/sysv/linux/nios2/pt-vfork.S +deleted file mode 100644 +index 147427a42d2d74a7..0000000000000000 +--- a/sysdeps/unix/sysv/linux/nios2/pt-vfork.S ++++ /dev/null +@@ -1 +0,0 @@ +-# Nios2 does not require a stub for vfork in libpthread. +diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/libpthread.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/libpthread.abilist +index 09e8447b06f828be..c7d9b7898640730d 100644 +--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/libpthread.abilist ++++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/libpthread.abilist +@@ -114,7 +114,6 @@ GLIBC_2.0 siglongjmp F + GLIBC_2.0 sigwait F + GLIBC_2.0 system F + GLIBC_2.0 tcdrain F +-GLIBC_2.0 vfork F + GLIBC_2.0 wait F + GLIBC_2.0 waitpid F + GLIBC_2.0 write F +@@ -155,7 +154,7 @@ GLIBC_2.1 sem_wait F + GLIBC_2.1.1 sem_close F + GLIBC_2.1.1 sem_open F + GLIBC_2.1.1 sem_unlink F +-GLIBC_2.1.2 __vfork F ++GLIBC_2.1.2 __libpthread_version_placeholder F + GLIBC_2.11 pthread_sigqueue F + GLIBC_2.12 pthread_getname_np F + GLIBC_2.12 pthread_mutex_consistent F +diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/libpthread-le.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/libpthread-le.abilist +index 9a9e4cee85b18a35..6945b7cbe4c2bde8 100644 +--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/libpthread-le.abilist ++++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/libpthread-le.abilist +@@ -45,7 +45,6 @@ GLIBC_2.17 __read F + GLIBC_2.17 __res_state F + GLIBC_2.17 __send F + GLIBC_2.17 __sigaction F +-GLIBC_2.17 __vfork F + GLIBC_2.17 __wait F + GLIBC_2.17 __write F + GLIBC_2.17 _pthread_cleanup_pop F +@@ -216,7 +215,6 @@ GLIBC_2.17 siglongjmp F + GLIBC_2.17 sigwait F + GLIBC_2.17 system F + GLIBC_2.17 tcdrain F +-GLIBC_2.17 vfork F + GLIBC_2.17 wait F + GLIBC_2.17 waitpid F + GLIBC_2.17 write F +diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/libpthread.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/libpthread.abilist +index 8300958d4721d6a6..3500cce6c1124996 100644 +--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/libpthread.abilist ++++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/libpthread.abilist +@@ -68,7 +68,6 @@ GLIBC_2.3 __read F + GLIBC_2.3 __res_state F + GLIBC_2.3 __send F + GLIBC_2.3 __sigaction F +-GLIBC_2.3 __vfork F + GLIBC_2.3 __wait F + GLIBC_2.3 __write F + GLIBC_2.3 _pthread_cleanup_pop F +@@ -214,7 +213,6 @@ GLIBC_2.3 siglongjmp F + GLIBC_2.3 sigwait F + GLIBC_2.3 system F + GLIBC_2.3 tcdrain F +-GLIBC_2.3 vfork F + GLIBC_2.3 wait F + GLIBC_2.3 waitpid F + GLIBC_2.3 write F +diff --git a/sysdeps/unix/sysv/linux/riscv/pt-vfork.S b/sysdeps/unix/sysv/linux/riscv/pt-vfork.S +deleted file mode 100644 +index 1cc8931700702e65..0000000000000000 +--- a/sysdeps/unix/sysv/linux/riscv/pt-vfork.S ++++ /dev/null +@@ -1 +0,0 @@ +-/* Not needed. */ +diff --git a/sysdeps/unix/sysv/linux/s390/pt-vfork.S b/sysdeps/unix/sysv/linux/s390/pt-vfork.S +deleted file mode 100644 +index 65cc3823ac872b35..0000000000000000 +--- a/sysdeps/unix/sysv/linux/s390/pt-vfork.S ++++ /dev/null +@@ -1 +0,0 @@ +-#include +diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/libpthread.abilist b/sysdeps/unix/sysv/linux/s390/s390-32/libpthread.abilist +index d05468f3b2732e92..f093634d7edce2f2 100644 +--- a/sysdeps/unix/sysv/linux/s390/s390-32/libpthread.abilist ++++ b/sysdeps/unix/sysv/linux/s390/s390-32/libpthread.abilist +@@ -114,7 +114,6 @@ GLIBC_2.0 siglongjmp F + GLIBC_2.0 sigwait F + GLIBC_2.0 system F + GLIBC_2.0 tcdrain F +-GLIBC_2.0 vfork F + GLIBC_2.0 wait F + GLIBC_2.0 waitpid F + GLIBC_2.0 write F +@@ -155,7 +154,7 @@ GLIBC_2.1 sem_wait F + GLIBC_2.1.1 sem_close F + GLIBC_2.1.1 sem_open F + GLIBC_2.1.1 sem_unlink F +-GLIBC_2.1.2 __vfork F ++GLIBC_2.1.2 __libpthread_version_placeholder F + GLIBC_2.11 pthread_sigqueue F + GLIBC_2.12 pthread_getname_np F + GLIBC_2.12 pthread_mutex_consistent F +diff --git a/sysdeps/unix/sysv/linux/s390/s390-64/libpthread.abilist b/sysdeps/unix/sysv/linux/s390/s390-64/libpthread.abilist +index e8161aa747402b72..47204f166c29a773 100644 +--- a/sysdeps/unix/sysv/linux/s390/s390-64/libpthread.abilist ++++ b/sysdeps/unix/sysv/linux/s390/s390-64/libpthread.abilist +@@ -48,7 +48,6 @@ GLIBC_2.2 __read F + GLIBC_2.2 __res_state F + GLIBC_2.2 __send F + GLIBC_2.2 __sigaction F +-GLIBC_2.2 __vfork F + GLIBC_2.2 __wait F + GLIBC_2.2 __write F + GLIBC_2.2 _pthread_cleanup_pop F +@@ -194,7 +193,6 @@ GLIBC_2.2 siglongjmp F + GLIBC_2.2 sigwait F + GLIBC_2.2 system F + GLIBC_2.2 tcdrain F +-GLIBC_2.2 vfork F + GLIBC_2.2 wait F + GLIBC_2.2 waitpid F + GLIBC_2.2 write F +diff --git a/sysdeps/unix/sysv/linux/sh/libpthread.abilist b/sysdeps/unix/sysv/linux/sh/libpthread.abilist +index bcba07f57558174f..e9b3be6ac8e8f367 100644 +--- a/sysdeps/unix/sysv/linux/sh/libpthread.abilist ++++ b/sysdeps/unix/sysv/linux/sh/libpthread.abilist +@@ -46,7 +46,6 @@ GLIBC_2.2 __read F + GLIBC_2.2 __res_state F + GLIBC_2.2 __send F + GLIBC_2.2 __sigaction F +-GLIBC_2.2 __vfork F + GLIBC_2.2 __wait F + GLIBC_2.2 __write F + GLIBC_2.2 _pthread_cleanup_pop F +@@ -192,7 +191,6 @@ GLIBC_2.2 siglongjmp F + GLIBC_2.2 sigwait F + GLIBC_2.2 system F + GLIBC_2.2 tcdrain F +-GLIBC_2.2 vfork F + GLIBC_2.2 wait F + GLIBC_2.2 waitpid F + GLIBC_2.2 write F +diff --git a/sysdeps/unix/sysv/linux/sh/pt-vfork.S b/sysdeps/unix/sysv/linux/sh/pt-vfork.S +deleted file mode 100644 +index 65cc3823ac872b35..0000000000000000 +--- a/sysdeps/unix/sysv/linux/sh/pt-vfork.S ++++ /dev/null +@@ -1 +0,0 @@ +-#include +diff --git a/sysdeps/unix/sysv/linux/sparc/pt-vfork.S b/sysdeps/unix/sysv/linux/sparc/pt-vfork.S +deleted file mode 100644 +index 65cc3823ac872b35..0000000000000000 +--- a/sysdeps/unix/sysv/linux/sparc/pt-vfork.S ++++ /dev/null +@@ -1 +0,0 @@ +-#include +diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/libpthread.abilist b/sysdeps/unix/sysv/linux/sparc/sparc32/libpthread.abilist +index b413007ccbd2b7b3..2d9b958efa99feb8 100644 +--- a/sysdeps/unix/sysv/linux/sparc/sparc32/libpthread.abilist ++++ b/sysdeps/unix/sysv/linux/sparc/sparc32/libpthread.abilist +@@ -114,7 +114,6 @@ GLIBC_2.0 siglongjmp F + GLIBC_2.0 sigwait F + GLIBC_2.0 system F + GLIBC_2.0 tcdrain F +-GLIBC_2.0 vfork F + GLIBC_2.0 wait F + GLIBC_2.0 waitpid F + GLIBC_2.0 write F +@@ -155,7 +154,7 @@ GLIBC_2.1 sem_wait F + GLIBC_2.1.1 sem_close F + GLIBC_2.1.1 sem_open F + GLIBC_2.1.1 sem_unlink F +-GLIBC_2.1.2 __vfork F ++GLIBC_2.1.2 __libpthread_version_placeholder F + GLIBC_2.11 pthread_sigqueue F + GLIBC_2.12 pthread_getname_np F + GLIBC_2.12 pthread_mutex_consistent F +diff --git a/sysdeps/unix/sysv/linux/sparc/sparc64/libpthread.abilist b/sysdeps/unix/sysv/linux/sparc/sparc64/libpthread.abilist +index ccc94498268a5c74..e8a65642caec7ff1 100644 +--- a/sysdeps/unix/sysv/linux/sparc/sparc64/libpthread.abilist ++++ b/sysdeps/unix/sysv/linux/sparc/sparc64/libpthread.abilist +@@ -46,7 +46,6 @@ GLIBC_2.2 __read F + GLIBC_2.2 __res_state F + GLIBC_2.2 __send F + GLIBC_2.2 __sigaction F +-GLIBC_2.2 __vfork F + GLIBC_2.2 __wait F + GLIBC_2.2 __write F + GLIBC_2.2 _pthread_cleanup_pop F +@@ -192,7 +191,6 @@ GLIBC_2.2 siglongjmp F + GLIBC_2.2 sigwait F + GLIBC_2.2 system F + GLIBC_2.2 tcdrain F +-GLIBC_2.2 vfork F + GLIBC_2.2 wait F + GLIBC_2.2 waitpid F + GLIBC_2.2 write F +diff --git a/sysdeps/unix/sysv/linux/x86_64/64/libpthread.abilist b/sysdeps/unix/sysv/linux/x86_64/64/libpthread.abilist +index 931c8277a859999e..4fbb72ffb37ba689 100644 +--- a/sysdeps/unix/sysv/linux/x86_64/64/libpthread.abilist ++++ b/sysdeps/unix/sysv/linux/x86_64/64/libpthread.abilist +@@ -46,7 +46,6 @@ GLIBC_2.2.5 __read F + GLIBC_2.2.5 __res_state F + GLIBC_2.2.5 __send F + GLIBC_2.2.5 __sigaction F +-GLIBC_2.2.5 __vfork F + GLIBC_2.2.5 __wait F + GLIBC_2.2.5 __write F + GLIBC_2.2.5 _pthread_cleanup_pop F +@@ -193,7 +192,6 @@ GLIBC_2.2.5 siglongjmp F + GLIBC_2.2.5 sigwait F + GLIBC_2.2.5 system F + GLIBC_2.2.5 tcdrain F +-GLIBC_2.2.5 vfork F + GLIBC_2.2.5 wait F + GLIBC_2.2.5 waitpid F + GLIBC_2.2.5 write F +diff --git a/sysdeps/unix/sysv/linux/x86_64/x32/libpthread.abilist b/sysdeps/unix/sysv/linux/x86_64/x32/libpthread.abilist +index c09c9b015a66f8f9..eec4b99b8bb69d74 100644 +--- a/sysdeps/unix/sysv/linux/x86_64/x32/libpthread.abilist ++++ b/sysdeps/unix/sysv/linux/x86_64/x32/libpthread.abilist +@@ -45,7 +45,6 @@ GLIBC_2.16 __read F + GLIBC_2.16 __res_state F + GLIBC_2.16 __send F + GLIBC_2.16 __sigaction F +-GLIBC_2.16 __vfork F + GLIBC_2.16 __wait F + GLIBC_2.16 __write F + GLIBC_2.16 _pthread_cleanup_pop F +@@ -216,7 +215,6 @@ GLIBC_2.16 siglongjmp F + GLIBC_2.16 sigwait F + GLIBC_2.16 system F + GLIBC_2.16 tcdrain F +-GLIBC_2.16 vfork F + GLIBC_2.16 wait F + GLIBC_2.16 waitpid F + GLIBC_2.16 write F diff --git a/SOURCES/glibc-rh1748197-3.patch b/SOURCES/glibc-rh1748197-3.patch new file mode 100644 index 0000000..dbc4b09 --- /dev/null +++ b/SOURCES/glibc-rh1748197-3.patch @@ -0,0 +1,51 @@ +commit f289e656ec8221756519a601042bc9fbe1b310fb +Author: Florian Weimer +Date: Fri Feb 8 10:21:56 2019 +0100 + + rt: Turn forwards from librt to libc into compat symbols [BZ #24194] + + As the result of commit 6e6249d0b461b952d0f544792372663feb6d792a + ("BZ#14743: Move clock_* symbols from librt to libc."), in glibc 2.17, + clock_gettime, clock_getres, clock_settime, clock_getcpuclockid, + clock_nanosleep were added to libc, and the file rt/clock-compat.c + was added with forwarders to the actual implementations in libc. + These forwarders were wrapped in + + #if SHLIB_COMPAT (librt, GLIBC_2_2, GLIBC_2_17) + + so that they are not present for newer architectures (such as + powerpc64le) with a 2.17 or later ABI baseline. But the forwarders + were not marked as compatibility symbols. As a result, on older + architectures, historic configure checks such as + + AC_CHECK_LIB(rt, clock_gettime) + + still cause linking against librt, even though this is completely + unnecessary. It also creates a needless porting hazard because + architectures behave differently when it comes to symbol availability. + + Reviewed-by: Carlos O'Donell + +diff --git a/rt/clock-compat.c b/rt/clock-compat.c +index f816973c05c29d5d..11e71aa89019b173 100644 +--- a/rt/clock-compat.c ++++ b/rt/clock-compat.c +@@ -30,14 +30,16 @@ + #if HAVE_IFUNC + # undef INIT_ARCH + # define INIT_ARCH() +-# define COMPAT_REDIRECT(name, proto, arglist) libc_ifunc (name, &__##name) ++# define COMPAT_REDIRECT(name, proto, arglist) libc_ifunc (name, &__##name) \ ++ compat_symbol (librt, name, name, GLIBC_2_2); + #else + # define COMPAT_REDIRECT(name, proto, arglist) \ + int \ + name proto \ + { \ + return __##name arglist; \ +- } ++ } \ ++ compat_symbol (librt, name, name, GLIBC_2_2); + #endif + + COMPAT_REDIRECT (clock_getres, diff --git a/SOURCES/glibc-rh1748197-4.patch b/SOURCES/glibc-rh1748197-4.patch new file mode 100644 index 0000000..795f673 --- /dev/null +++ b/SOURCES/glibc-rh1748197-4.patch @@ -0,0 +1,256 @@ +commit b06f4c0094d3c68be39ada0ed26ae99d51f48013 +Author: Wilco Dijkstra +Date: Fri Feb 1 12:19:42 2019 +0000 + + Cleanup clock_*time includes + + Clock_gettime, settime and getres implementations are unncessarily + complex due to using defines and C file inclusion. Simplify the + code by replacing the redundant defines and removing the inclusion, + making it much easier to understand. No functional changes. + + * sysdeps/posix/clock_getres.c (__clock_getres): Cleanup. + * sysdeps/unix/clock_gettime.c (__clock_gettime): Cleanup. + * sysdeps/unix/clock_settime.c (__clock_settime): Cleanup. + * sysdeps/unix/sysv/linux/clock_getres.c (__clock_getres): Cleanup. + * sysdeps/unix/sysv/linux/clock_gettime.c (__clock_gettime): Cleanup. + * sysdeps/unix/sysv/linux/clock_settime.c (__clock_settime): Cleanup. + +diff --git a/sysdeps/posix/clock_getres.c b/sysdeps/posix/clock_getres.c +index e7924e0891b0a476..43228c381e6a73f1 100644 +--- a/sysdeps/posix/clock_getres.c ++++ b/sysdeps/posix/clock_getres.c +@@ -82,20 +82,11 @@ __clock_getres (clockid_t clock_id, struct timespec *res) + + switch (clock_id) + { +-#ifdef SYSDEP_GETRES +- SYSDEP_GETRES; +-#endif +- +-#ifndef HANDLED_REALTIME + case CLOCK_REALTIME: + retval = realtime_getres (res); + break; +-#endif /* handled REALTIME */ + + default: +-#ifdef SYSDEP_GETRES_CPU +- SYSDEP_GETRES_CPU; +-#endif + #if HP_TIMING_AVAIL + if ((clock_id & ((1 << CLOCK_IDFIELD_SIZE) - 1)) + == CLOCK_THREAD_CPUTIME_ID) +@@ -105,7 +96,7 @@ __clock_getres (clockid_t clock_id, struct timespec *res) + __set_errno (EINVAL); + break; + +-#if HP_TIMING_AVAIL && !defined HANDLED_CPUTIME ++#if HP_TIMING_AVAIL + case CLOCK_PROCESS_CPUTIME_ID: + case CLOCK_THREAD_CPUTIME_ID: + retval = hp_timing_getres (res); +diff --git a/sysdeps/unix/clock_gettime.c b/sysdeps/unix/clock_gettime.c +index 96df78ab1ed09c04..f19fdf7e5f310973 100644 +--- a/sysdeps/unix/clock_gettime.c ++++ b/sysdeps/unix/clock_gettime.c +@@ -95,11 +95,6 @@ __clock_gettime (clockid_t clock_id, struct timespec *tp) + + switch (clock_id) + { +-#ifdef SYSDEP_GETTIME +- SYSDEP_GETTIME; +-#endif +- +-#ifndef HANDLED_REALTIME + case CLOCK_REALTIME: + { + struct timeval tv; +@@ -108,12 +103,8 @@ __clock_gettime (clockid_t clock_id, struct timespec *tp) + TIMEVAL_TO_TIMESPEC (&tv, tp); + } + break; +-#endif + + default: +-#ifdef SYSDEP_GETTIME_CPU +- SYSDEP_GETTIME_CPU (clock_id, tp); +-#endif + #if HP_TIMING_AVAIL + if ((clock_id & ((1 << CLOCK_IDFIELD_SIZE) - 1)) + == CLOCK_THREAD_CPUTIME_ID) +@@ -123,7 +114,7 @@ __clock_gettime (clockid_t clock_id, struct timespec *tp) + __set_errno (EINVAL); + break; + +-#if HP_TIMING_AVAIL && !defined HANDLED_CPUTIME ++#if HP_TIMING_AVAIL + case CLOCK_PROCESS_CPUTIME_ID: + retval = hp_timing_gettime (clock_id, tp); + break; +diff --git a/sysdeps/unix/clock_settime.c b/sysdeps/unix/clock_settime.c +index 38813eddf7b66ca1..9d5857e61b966b44 100644 +--- a/sysdeps/unix/clock_settime.c ++++ b/sysdeps/unix/clock_settime.c +@@ -21,7 +21,7 @@ + #include + + +-#if HP_TIMING_AVAIL && !defined HANDLED_CPUTIME ++#if HP_TIMING_AVAIL + /* Clock frequency of the processor. We make it a 64-bit variable + because some jokers are already playing with processors with more + than 4GHz. */ +@@ -84,29 +84,15 @@ __clock_settime (clockid_t clock_id, const struct timespec *tp) + + switch (clock_id) + { +-#define HANDLE_REALTIME \ +- do { \ +- struct timeval tv; \ +- TIMESPEC_TO_TIMEVAL (&tv, tp); \ +- \ +- retval = __settimeofday (&tv, NULL); \ +- } while (0) +- +-#ifdef SYSDEP_SETTIME +- SYSDEP_SETTIME; +-#endif +- +-#ifndef HANDLED_REALTIME + case CLOCK_REALTIME: +- HANDLE_REALTIME; ++ { ++ struct timeval tv; ++ TIMESPEC_TO_TIMEVAL (&tv, tp); ++ retval = __settimeofday (&tv, NULL); ++ } + break; +-#endif + + default: +-#ifdef SYSDEP_SETTIME_CPU +- SYSDEP_SETTIME_CPU; +-#endif +-#ifndef HANDLED_CPUTIME + # if HP_TIMING_AVAIL + if (CPUCLOCK_WHICH (clock_id) == CLOCK_PROCESS_CPUTIME_ID + || CPUCLOCK_WHICH (clock_id) == CLOCK_THREAD_CPUTIME_ID) +@@ -117,7 +103,6 @@ __clock_settime (clockid_t clock_id, const struct timespec *tp) + __set_errno (EINVAL); + retval = -1; + } +-#endif + break; + } + +diff --git a/sysdeps/unix/sysv/linux/clock_getres.c b/sysdeps/unix/sysv/linux/clock_getres.c +index 5d94f59afee80fa9..2517e66910a79d93 100644 +--- a/sysdeps/unix/sysv/linux/clock_getres.c ++++ b/sysdeps/unix/sysv/linux/clock_getres.c +@@ -26,26 +26,10 @@ + #endif + #include + +-#define SYSCALL_GETRES \ +- retval = INLINE_VSYSCALL (clock_getres, 2, clock_id, res); \ +- break +- +-/* The REALTIME and MONOTONIC clock are definitely supported in the +- kernel. */ +-#define SYSDEP_GETRES \ +- SYSDEP_GETRES_CPUTIME \ +- case CLOCK_REALTIME: \ +- case CLOCK_MONOTONIC: \ +- case CLOCK_MONOTONIC_RAW: \ +- case CLOCK_REALTIME_COARSE: \ +- case CLOCK_MONOTONIC_COARSE: \ +- SYSCALL_GETRES +- +-/* We handled the REALTIME clock here. */ +-#define HANDLED_REALTIME 1 +-#define HANDLED_CPUTIME 1 +- +-#define SYSDEP_GETRES_CPU SYSCALL_GETRES +-#define SYSDEP_GETRES_CPUTIME /* Default catches them too. */ +- +-#include ++/* Get resolution of clock. */ ++int ++__clock_getres (clockid_t clock_id, struct timespec *res) ++{ ++ return INLINE_VSYSCALL (clock_getres, 2, clock_id, res); ++} ++weak_alias (__clock_getres, clock_getres) +diff --git a/sysdeps/unix/sysv/linux/clock_gettime.c b/sysdeps/unix/sysv/linux/clock_gettime.c +index d837fa36b1b901e5..dadfc518b74baea0 100644 +--- a/sysdeps/unix/sysv/linux/clock_gettime.c ++++ b/sysdeps/unix/sysv/linux/clock_gettime.c +@@ -26,22 +26,11 @@ + #endif + #include + +-/* The REALTIME and MONOTONIC clock are definitely supported in the +- kernel. */ +-#define SYSDEP_GETTIME \ +- SYSDEP_GETTIME_CPUTIME; \ +- case CLOCK_REALTIME: \ +- case CLOCK_MONOTONIC: \ +- retval = INLINE_VSYSCALL (clock_gettime, 2, clock_id, tp); \ +- break +- +-/* We handled the REALTIME clock here. */ +-#define HANDLED_REALTIME 1 +-#define HANDLED_CPUTIME 1 +- +-#define SYSDEP_GETTIME_CPU(clock_id, tp) \ +- retval = INLINE_VSYSCALL (clock_gettime, 2, clock_id, tp); \ +- break +-#define SYSDEP_GETTIME_CPUTIME /* Default catches them too. */ +- +-#include ++/* Get current value of CLOCK and store it in TP. */ ++int ++__clock_gettime (clockid_t clock_id, struct timespec *tp) ++{ ++ return INLINE_VSYSCALL (clock_gettime, 2, clock_id, tp); ++} ++weak_alias (__clock_gettime, clock_gettime) ++libc_hidden_def (__clock_gettime) +diff --git a/sysdeps/unix/sysv/linux/clock_settime.c b/sysdeps/unix/sysv/linux/clock_settime.c +index 5f3f22f74b3e745c..c71461a4f6deac5a 100644 +--- a/sysdeps/unix/sysv/linux/clock_settime.c ++++ b/sysdeps/unix/sysv/linux/clock_settime.c +@@ -21,18 +21,17 @@ + + #include "kernel-posix-cpu-timers.h" + +- +-/* The REALTIME clock is definitely supported in the kernel. */ +-#define SYSDEP_SETTIME \ +- case CLOCK_REALTIME: \ +- retval = INLINE_SYSCALL (clock_settime, 2, clock_id, tp); \ +- break +- +-/* We handled the REALTIME clock here. */ +-#define HANDLED_REALTIME 1 +- +-#define HANDLED_CPUTIME 1 +-#define SYSDEP_SETTIME_CPU \ +- retval = INLINE_SYSCALL (clock_settime, 2, clock_id, tp) +- +-#include ++/* Set CLOCK to value TP. */ ++int ++__clock_settime (clockid_t clock_id, const struct timespec *tp) ++{ ++ /* Make sure the time cvalue is OK. */ ++ if (tp->tv_nsec < 0 || tp->tv_nsec >= 1000000000) ++ { ++ __set_errno (EINVAL); ++ return -1; ++ } ++ ++ return INLINE_SYSCALL_CALL (clock_settime, clock_id, tp); ++} ++weak_alias (__clock_settime, clock_settime) diff --git a/SOURCES/glibc-rh1748197-5.patch b/SOURCES/glibc-rh1748197-5.patch new file mode 100644 index 0000000..4a98157 --- /dev/null +++ b/SOURCES/glibc-rh1748197-5.patch @@ -0,0 +1,735 @@ +commit 38cc11daa43b11b12a7774405accee1007de1adf +Author: Adhemerval Zanella +Date: Wed Jan 16 16:22:29 2019 +0000 + + nptl: Remove pthread_clock_gettime pthread_clock_settime + + This patch removes CLOCK_THREAD_CPUTIME_ID and CLOCK_PROCESS_CPUTIME_ID support + from clock_gettime and clock_settime generic implementation. For Linux, kernel + already provides supports through the syscall and Hurd HTL lacks + __pthread_clock_gettime and __pthread_clock_settime internal implementation. + + As described in clock_gettime man-page [1] on 'Historical note for SMP + system', implementing CLOCK_{THREAD,PROCESS}_CPUTIME_ID with timer registers + is error-prone and susceptible to timing and accurary issues that the libc + can not deal without kernel support. + + This allows removes unused code which, however, still incur in some runtime + overhead in thread creation (the struct pthread cpuclock_offset + initialization). + + If hurd eventually wants to support them it should either either implement as + a kernel facility (or something related due its architecture) or in system + specific implementation. + + Checked on aarch64-linux-gnu, x86_64-linux-gnu, and i686-linux-gnu. I also + checked on a i686-gnu build. + + * nptl/Makefile (libpthread-routines): Remove pthread_clock_gettime and + pthread_clock_settime. + * nptl/pthreadP.h (__find_thread_by_id): Remove prototype. + * elf/dl-support.c [!HP_TIMING_NOAVAIL] (_dl_cpuclock_offset): Remove. + (_dl_non_dynamic_init): Remove _dl_cpuclock_offset setting. + * elf/rtld.c (_dl_start_final): Likewise. + * nptl/allocatestack.c (__find_thread_by_id): Remove function. + * sysdeps/generic/ldsodefs.h [!HP_TIMING_NOAVAIL] (_dl_cpuclock_offset): + Remove. + * sysdeps/mach/hurd/dl-sysdep.c [!HP_TIMING_NOAVAIL] + (_dl_cpuclock_offset): Remove. + * nptl/descr.h (struct pthread): Rename cpuclock_offset to + cpuclock_offset_ununsed. + * nptl/nptl-init.c (__pthread_initialize_minimal_internal): Remove + cpuclock_offset set. + * nptl/pthread_create.c (START_THREAD_DEFN): Likewise. + * sysdeps/nptl/fork.c (__libc_fork): Likewise. + * nptl/pthread_clock_gettime.c: Remove file. + * nptl/pthread_clock_settime.c: Likewise. + * sysdeps/unix/clock_gettime.c (hp_timing_gettime): Remove function. + [HP_TIMING_AVAIL] (realtime_gettime): Remove CLOCK_THREAD_CPUTIME_ID + and CLOCK_PROCESS_CPUTIME_ID support. + * sysdeps/unix/clock_settime.c (hp_timing_gettime): Likewise. + [HP_TIMING_AVAIL] (realtime_gettime): Likewise. + * sysdeps/posix/clock_getres.c (hp_timing_getres): Likewise. + [HP_TIMING_AVAIL] (__clock_getres): Likewise. + * sysdeps/unix/clock_nanosleep.c (CPUCLOCK_P, INVALID_CLOCK_P): + Likewise. + (__clock_nanosleep): Remove CPUCLOCK_P and INVALID_CLOCK_P usage. + + [1] http://man7.org/linux/man-pages/man2/clock_gettime.2.html + +Conflicts: + nptl/pthread_clock_gettime.c + nptl/pthread_clock_settime.c + (Removal after copyright year update upstream.) + +diff --git a/elf/dl-support.c b/elf/dl-support.c +index c8439fcc53d126f3..ef5455b91c17ca30 100644 +--- a/elf/dl-support.c ++++ b/elf/dl-support.c +@@ -127,11 +127,6 @@ void *_dl_random; + #include + #include + +-/* Initial value of the CPU clock. */ +-#ifndef HP_TIMING_NONAVAIL +-hp_timing_t _dl_cpuclock_offset; +-#endif +- + void (*_dl_init_static_tls) (struct link_map *) = &_dl_nothread_init_static_tls; + + size_t _dl_pagesize = EXEC_PAGESIZE; +@@ -312,9 +307,6 @@ _dl_non_dynamic_init (void) + _dl_main_map.l_phdr = GL(dl_phdr); + _dl_main_map.l_phnum = GL(dl_phnum); + +- if (HP_SMALL_TIMING_AVAIL) +- HP_TIMING_NOW (_dl_cpuclock_offset); +- + _dl_verbose = *(getenv ("LD_WARN") ?: "") == '\0' ? 0 : 1; + + /* Set up the data structures for the system-supplied DSO early, +diff --git a/elf/rtld.c b/elf/rtld.c +index 0aa1a2a19f649e16..e107bd14f9478a90 100644 +--- a/elf/rtld.c ++++ b/elf/rtld.c +@@ -401,8 +401,6 @@ _dl_start_final (void *arg, struct dl_start_final_info *info) + # endif + #endif + +- HP_TIMING_NOW (GL(dl_cpuclock_offset)); +- + /* Initialize the stack end variable. */ + __libc_stack_end = __builtin_frame_address (0); + +diff --git a/nptl/Makefile b/nptl/Makefile +index 447dce0590295c9c..d6b37b6efd3b7d78 100644 +--- a/nptl/Makefile ++++ b/nptl/Makefile +@@ -109,7 +109,6 @@ libpthread-routines = nptl-init nptlfreeres vars events version pt-interp \ + pthread_once \ + old_pthread_atfork \ + pthread_getcpuclockid \ +- pthread_clock_gettime pthread_clock_settime \ + shm-directory \ + sem_init sem_destroy \ + sem_open sem_close sem_unlink \ +diff --git a/nptl/allocatestack.c b/nptl/allocatestack.c +index d0971a97fdbe098e..5fa45b19987717e1 100644 +--- a/nptl/allocatestack.c ++++ b/nptl/allocatestack.c +@@ -964,54 +964,6 @@ __reclaim_stacks (void) + } + + +-#if HP_TIMING_AVAIL +-# undef __find_thread_by_id +-/* Find a thread given the thread ID. */ +-attribute_hidden +-struct pthread * +-__find_thread_by_id (pid_t tid) +-{ +- struct pthread *result = NULL; +- +- lll_lock (stack_cache_lock, LLL_PRIVATE); +- +- /* Iterate over the list with system-allocated threads first. */ +- list_t *runp; +- list_for_each (runp, &stack_used) +- { +- struct pthread *curp; +- +- curp = list_entry (runp, struct pthread, list); +- +- if (curp->tid == tid) +- { +- result = curp; +- goto out; +- } +- } +- +- /* Now the list with threads using user-allocated stacks. */ +- list_for_each (runp, &__stack_user) +- { +- struct pthread *curp; +- +- curp = list_entry (runp, struct pthread, list); +- +- if (curp->tid == tid) +- { +- result = curp; +- goto out; +- } +- } +- +- out: +- lll_unlock (stack_cache_lock, LLL_PRIVATE); +- +- return result; +-} +-#endif +- +- + #ifdef SIGSETXID + static void + setxid_mark_thread (struct xid_command *cmdp, struct pthread *t) +diff --git a/nptl/descr.h b/nptl/descr.h +index 9c01e1b9863b178c..c3b81d8b27839502 100644 +--- a/nptl/descr.h ++++ b/nptl/descr.h +@@ -343,8 +343,7 @@ struct pthread + unsigned int setxid_futex; + + #if HP_TIMING_AVAIL +- /* Offset of the CPU clock at start thread start time. */ +- hp_timing_t cpuclock_offset; ++ hp_timing_t cpuclock_offset_ununsed; + #endif + + /* If the thread waits to join another one the ID of the latter is +diff --git a/nptl/nptl-init.c b/nptl/nptl-init.c +index 907411d5bca2af79..098bc059f4771ef2 100644 +--- a/nptl/nptl-init.c ++++ b/nptl/nptl-init.c +@@ -275,9 +275,6 @@ __pthread_initialize_minimal_internal (void) + THREAD_SETMEM (pd, user_stack, true); + if (LLL_LOCK_INITIALIZER != 0) + THREAD_SETMEM (pd, lock, LLL_LOCK_INITIALIZER); +-#if HP_TIMING_AVAIL +- THREAD_SETMEM (pd, cpuclock_offset, GL(dl_cpuclock_offset)); +-#endif + + /* Initialize the robust mutex data. */ + { +diff --git a/nptl/pthreadP.h b/nptl/pthreadP.h +index 19efe1e35feed5be..00be8f92793e8710 100644 +--- a/nptl/pthreadP.h ++++ b/nptl/pthreadP.h +@@ -406,16 +406,6 @@ extern int __pthread_multiple_threads attribute_hidden; + extern int *__libc_multiple_threads_ptr attribute_hidden; + #endif + +-/* Find a thread given its TID. */ +-extern struct pthread *__find_thread_by_id (pid_t tid) attribute_hidden +-#ifdef SHARED +-; +-#else +-weak_function; +-#define __find_thread_by_id(tid) \ +- (__find_thread_by_id ? (__find_thread_by_id) (tid) : (struct pthread *) NULL) +-#endif +- + extern void __pthread_init_static_tls (struct link_map *) attribute_hidden; + + extern size_t __pthread_get_minstack (const pthread_attr_t *attr); +diff --git a/nptl/pthread_clock_gettime.c b/nptl/pthread_clock_gettime.c +deleted file mode 100644 +index 6bc75cfe3f1ff856..0000000000000000 +--- a/nptl/pthread_clock_gettime.c ++++ /dev/null +@@ -1,67 +0,0 @@ +-/* 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; see the file COPYING.LIB. If +- not, see . */ +- +-#include +-#include +-#include +-#include "pthreadP.h" +- +- +-#if HP_TIMING_AVAIL +-int +-__pthread_clock_gettime (clockid_t clock_id, hp_timing_t freq, +- struct timespec *tp) +-{ +- hp_timing_t tsc; +- +- /* Get the current counter. */ +- HP_TIMING_NOW (tsc); +- +- /* This is the ID of the thread we are looking for. */ +- pid_t tid = ((unsigned int) clock_id) >> CLOCK_IDFIELD_SIZE; +- +- /* Compute the offset since the start time of the process. */ +- if (tid == 0 || tid == THREAD_GETMEM (THREAD_SELF, tid)) +- /* Our own clock. */ +- tsc -= THREAD_GETMEM (THREAD_SELF, cpuclock_offset); +- else +- { +- /* This is more complicated. We have to locate the thread based +- on the ID. This means walking the list of existing +- threads. */ +- struct pthread *thread = __find_thread_by_id (tid); +- if (thread == NULL) +- { +- __set_errno (EINVAL); +- return -1; +- } +- +- /* There is a race here. The thread might terminate and the stack +- become unusable. But this is the user's problem. */ +- tsc -= thread->cpuclock_offset; +- } +- +- /* Compute the seconds. */ +- tp->tv_sec = tsc / freq; +- +- /* And the nanoseconds. This computation should be stable until +- we get machines with about 16GHz frequency. */ +- tp->tv_nsec = ((tsc % freq) * 1000000000ull) / freq; +- +- return 0; +-} +-#endif +diff --git a/nptl/pthread_clock_settime.c b/nptl/pthread_clock_settime.c +deleted file mode 100644 +index 29d35c64cfa817a3..0000000000000000 +--- a/nptl/pthread_clock_settime.c ++++ /dev/null +@@ -1,54 +0,0 @@ +-/* 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; see the file COPYING.LIB. If +- not, see . */ +- +-#include +-#include +-#include +-#include "pthreadP.h" +- +- +-#if HP_TIMING_AVAIL +-int +-__pthread_clock_settime (clockid_t clock_id, hp_timing_t offset) +-{ +- /* This is the ID of the thread we are looking for. */ +- pid_t tid = ((unsigned int) clock_id) >> CLOCK_IDFIELD_SIZE; +- +- /* Compute the offset since the start time of the process. */ +- if (tid == 0 || tid == THREAD_GETMEM (THREAD_SELF, tid)) +- /* Our own clock. */ +- THREAD_SETMEM (THREAD_SELF, cpuclock_offset, offset); +- else +- { +- /* This is more complicated. We have to locate the thread based +- on the ID. This means walking the list of existing +- threads. */ +- struct pthread *thread = __find_thread_by_id (tid); +- if (thread == NULL) +- { +- __set_errno (EINVAL); +- return -1; +- } +- +- /* There is a race here. The thread might terminate and the stack +- become unusable. But this is the user's problem. */ +- thread->cpuclock_offset = offset; +- } +- +- return 0; +-} +-#endif +diff --git a/nptl/pthread_create.c b/nptl/pthread_create.c +index fe75d04113b8aa3f..f58a15cd1c7bbb6f 100644 +--- a/nptl/pthread_create.c ++++ b/nptl/pthread_create.c +@@ -379,13 +379,6 @@ START_THREAD_DEFN + { + struct pthread *pd = START_THREAD_SELF; + +-#if HP_TIMING_AVAIL +- /* Remember the time when the thread was started. */ +- hp_timing_t now; +- HP_TIMING_NOW (now); +- THREAD_SETMEM (pd, cpuclock_offset, now); +-#endif +- + /* Initialize resolver state pointer. */ + __resp = &pd->res; + +diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h +index c6b7e61badbfd513..f0185ce0d16c0f69 100644 +--- a/sysdeps/generic/ldsodefs.h ++++ b/sysdeps/generic/ldsodefs.h +@@ -359,11 +359,6 @@ struct rtld_global + /* The object to be initialized first. */ + EXTERN struct link_map *_dl_initfirst; + +-#if HP_SMALL_TIMING_AVAIL +- /* Start time on CPU clock. */ +- EXTERN hp_timing_t _dl_cpuclock_offset; +-#endif +- + /* Map of shared object to be profiled. */ + EXTERN struct link_map *_dl_profile_map; + +diff --git a/sysdeps/mach/hurd/dl-sysdep.c b/sysdeps/mach/hurd/dl-sysdep.c +index b72913d3baaed1d9..7bd1d70c96c229e0 100644 +--- a/sysdeps/mach/hurd/dl-sysdep.c ++++ b/sysdeps/mach/hurd/dl-sysdep.c +@@ -62,10 +62,6 @@ int __libc_multiple_libcs = 0; /* Defining this here avoids the inclusion + void *__libc_stack_end = NULL; + rtld_hidden_data_def(__libc_stack_end) + +-#if HP_TIMING_AVAIL +-hp_timing_t _dl_cpuclock_offset; +-#endif +- + /* TODO: Initialize. */ + void *_dl_random attribute_relro = NULL; + +@@ -246,10 +242,6 @@ unfmh(); /* XXX */ + /* Initialize frequently used global variable. */ + GLRO(dl_pagesize) = __getpagesize (); + +-#if HP_TIMING_AVAIL +- HP_TIMING_NOW (_dl_cpuclock_offset); +-#endif +- + fmh(); /* XXX */ + + /* See hurd/hurdstartup.c; this deals with getting information +diff --git a/sysdeps/nptl/fork.c b/sysdeps/nptl/fork.c +index 1a9429b579cd346e..37db30f3d1e846b6 100644 +--- a/sysdeps/nptl/fork.c ++++ b/sysdeps/nptl/fork.c +@@ -83,14 +83,6 @@ __libc_fork (void) + if (__fork_generation_pointer != NULL) + *__fork_generation_pointer += __PTHREAD_ONCE_FORK_GEN_INCR; + +-#if HP_TIMING_AVAIL +- /* The CPU clock of the thread and process have to be set to zero. */ +- hp_timing_t now; +- HP_TIMING_NOW (now); +- THREAD_SETMEM (self, cpuclock_offset, now); +- GL(dl_cpuclock_offset) = now; +-#endif +- + #ifdef __NR_set_robust_list + /* Initialize the robust mutex list setting in the kernel which has + been reset during the fork. We do not check for errors because if +diff --git a/sysdeps/posix/clock_getres.c b/sysdeps/posix/clock_getres.c +index 43228c381e6a73f1..5b0d8eb8a1a0593e 100644 +--- a/sysdeps/posix/clock_getres.c ++++ b/sysdeps/posix/clock_getres.c +@@ -24,37 +24,6 @@ + #include + + +-#if HP_TIMING_AVAIL +-static long int nsec; /* Clock frequency of the processor. */ +- +-static int +-hp_timing_getres (struct timespec *res) +-{ +- if (__glibc_unlikely (nsec == 0)) +- { +- hp_timing_t freq; +- +- /* This can only happen if we haven't initialized the `nsec' +- variable yet. Do this now. We don't have to protect this +- code against multiple execution since all of them should +- lead to the same result. */ +- freq = __get_clockfreq (); +- if (__glibc_unlikely (freq == 0)) +- /* Something went wrong. */ +- return -1; +- +- nsec = MAX (UINT64_C (1000000000) / freq, 1); +- } +- +- /* Fill in the values. +- The seconds are always zero (unless we have a 1Hz machine). */ +- res->tv_sec = 0; +- res->tv_nsec = nsec; +- +- return 0; +-} +-#endif +- + static inline int + realtime_getres (struct timespec *res) + { +@@ -87,21 +56,8 @@ __clock_getres (clockid_t clock_id, struct timespec *res) + break; + + default: +-#if HP_TIMING_AVAIL +- if ((clock_id & ((1 << CLOCK_IDFIELD_SIZE) - 1)) +- == CLOCK_THREAD_CPUTIME_ID) +- retval = hp_timing_getres (res); +- else +-#endif +- __set_errno (EINVAL); +- break; +- +-#if HP_TIMING_AVAIL +- case CLOCK_PROCESS_CPUTIME_ID: +- case CLOCK_THREAD_CPUTIME_ID: +- retval = hp_timing_getres (res); ++ __set_errno (EINVAL); + break; +-#endif + } + + return retval; +diff --git a/sysdeps/unix/clock_gettime.c b/sysdeps/unix/clock_gettime.c +index f19fdf7e5f310973..f3ebbe15ccc2e95e 100644 +--- a/sysdeps/unix/clock_gettime.c ++++ b/sysdeps/unix/clock_gettime.c +@@ -24,57 +24,6 @@ + #include + + +-#if HP_TIMING_AVAIL +-/* Clock frequency of the processor. We make it a 64-bit variable +- because some jokers are already playing with processors with more +- than 4GHz. */ +-static hp_timing_t freq; +- +- +-/* This function is defined in the thread library. */ +-extern int __pthread_clock_gettime (clockid_t clock_id, hp_timing_t freq, +- struct timespec *tp) +- __attribute__ ((__weak__)); +- +-static int +-hp_timing_gettime (clockid_t clock_id, struct timespec *tp) +-{ +- hp_timing_t tsc; +- +- if (__glibc_unlikely (freq == 0)) +- { +- /* This can only happen if we haven't initialized the `freq' +- variable yet. Do this now. We don't have to protect this +- code against multiple execution since all of them should +- lead to the same result. */ +- freq = __get_clockfreq (); +- if (__glibc_unlikely (freq == 0)) +- /* Something went wrong. */ +- return -1; +- } +- +- if (clock_id != CLOCK_PROCESS_CPUTIME_ID +- && __pthread_clock_gettime != NULL) +- return __pthread_clock_gettime (clock_id, freq, tp); +- +- /* Get the current counter. */ +- HP_TIMING_NOW (tsc); +- +- /* Compute the offset since the start time of the process. */ +- tsc -= GL(dl_cpuclock_offset); +- +- /* Compute the seconds. */ +- tp->tv_sec = tsc / freq; +- +- /* And the nanoseconds. This computation should be stable until +- we get machines with about 16GHz frequency. */ +- tp->tv_nsec = ((tsc % freq) * UINT64_C (1000000000)) / freq; +- +- return 0; +-} +-#endif +- +- + static inline int + realtime_gettime (struct timespec *tp) + { +@@ -105,20 +54,8 @@ __clock_gettime (clockid_t clock_id, struct timespec *tp) + break; + + default: +-#if HP_TIMING_AVAIL +- if ((clock_id & ((1 << CLOCK_IDFIELD_SIZE) - 1)) +- == CLOCK_THREAD_CPUTIME_ID) +- retval = hp_timing_gettime (clock_id, tp); +- else +-#endif +- __set_errno (EINVAL); +- break; +- +-#if HP_TIMING_AVAIL +- case CLOCK_PROCESS_CPUTIME_ID: +- retval = hp_timing_gettime (clock_id, tp); ++ __set_errno (EINVAL); + break; +-#endif + } + + return retval; +diff --git a/sysdeps/unix/clock_nanosleep.c b/sysdeps/unix/clock_nanosleep.c +index 97b3d6b6ab9e4581..13dd0f4b905ec631 100644 +--- a/sysdeps/unix/clock_nanosleep.c ++++ b/sysdeps/unix/clock_nanosleep.c +@@ -19,23 +19,8 @@ + #include + #include + #include +-#include + #include + +-#if HP_TIMING_AVAIL +-# define CPUCLOCK_P(clock) \ +- ((clock) == CLOCK_PROCESS_CPUTIME_ID \ +- || ((clock) & ((1 << CLOCK_IDFIELD_SIZE) - 1)) == CLOCK_THREAD_CPUTIME_ID) +-#else +-# define CPUCLOCK_P(clock) 0 +-#endif +- +-#ifndef INVALID_CLOCK_P +-# define INVALID_CLOCK_P(cl) \ +- ((cl) < CLOCK_REALTIME || (cl) > CLOCK_THREAD_CPUTIME_ID) +-#endif +- +- + /* This implementation assumes that these is only a `nanosleep' system + call. So we have to remap all other activities. */ + int +@@ -51,14 +36,7 @@ __clock_nanosleep (clockid_t clock_id, int flags, const struct timespec *req, + if (clock_id == CLOCK_THREAD_CPUTIME_ID) + return EINVAL; /* POSIX specifies EINVAL for this case. */ + +-#ifdef SYSDEP_NANOSLEEP +- SYSDEP_NANOSLEEP; +-#endif +- +- if (CPUCLOCK_P (clock_id)) +- return ENOTSUP; +- +- if (INVALID_CLOCK_P (clock_id)) ++ if (clock_id < CLOCK_REALTIME || clock_id > CLOCK_THREAD_CPUTIME_ID) + return EINVAL; + + /* If we got an absolute time, remap it. */ +@@ -71,7 +49,7 @@ __clock_nanosleep (clockid_t clock_id, int flags, const struct timespec *req, + assert (sizeof (sec) >= sizeof (now.tv_sec)); + + /* Get the current time for this clock. */ +- if (__builtin_expect (__clock_gettime (clock_id, &now), 0) != 0) ++ if (__clock_gettime (clock_id, &now) != 0) + return errno; + + /* Compute the difference. */ +@@ -90,12 +68,12 @@ __clock_nanosleep (clockid_t clock_id, int flags, const struct timespec *req, + /* Make sure we are not modifying the struct pointed to by REM. */ + rem = NULL; + } +- else if (__builtin_expect (flags, 0) != 0) ++ else if (flags != 0) + return EINVAL; + else if (clock_id != CLOCK_REALTIME) + /* Not supported. */ + return ENOTSUP; + +- return __builtin_expect (__nanosleep (req, rem), 0) ? errno : 0; ++ return __nanosleep (req, rem), 0 ? errno : 0; + } + weak_alias (__clock_nanosleep, clock_nanosleep) +diff --git a/sysdeps/unix/clock_settime.c b/sysdeps/unix/clock_settime.c +index 9d5857e61b966b44..4f5640f67047cef6 100644 +--- a/sysdeps/unix/clock_settime.c ++++ b/sysdeps/unix/clock_settime.c +@@ -21,59 +21,11 @@ + #include + + +-#if HP_TIMING_AVAIL +-/* Clock frequency of the processor. We make it a 64-bit variable +- because some jokers are already playing with processors with more +- than 4GHz. */ +-static hp_timing_t freq; +- +- +-/* This function is defined in the thread library. */ +-extern void __pthread_clock_settime (clockid_t clock_id, hp_timing_t offset) +- __attribute__ ((__weak__)); +- +- +-static int +-hp_timing_settime (clockid_t clock_id, const struct timespec *tp) +-{ +- hp_timing_t tsc; +- hp_timing_t usertime; +- +- /* First thing is to get the current time. */ +- HP_TIMING_NOW (tsc); +- +- if (__glibc_unlikely (freq == 0)) +- { +- /* This can only happen if we haven't initialized the `freq' +- variable yet. Do this now. We don't have to protect this +- code against multiple execution since all of them should lead +- to the same result. */ +- freq = __get_clockfreq (); +- if (__glibc_unlikely (freq == 0)) +- /* Something went wrong. */ +- return -1; +- } +- +- /* Convert the user-provided time into CPU ticks. */ +- usertime = tp->tv_sec * freq + (tp->tv_nsec * freq) / 1000000000ull; +- +- /* Determine the offset and use it as the new base value. */ +- if (clock_id == CLOCK_PROCESS_CPUTIME_ID +- || __pthread_clock_settime == NULL) +- GL(dl_cpuclock_offset) = tsc - usertime; +- else +- __pthread_clock_settime (clock_id, tsc - usertime); +- +- return 0; +-} +-#endif +- +- + /* Set CLOCK to value TP. */ + int + __clock_settime (clockid_t clock_id, const struct timespec *tp) + { +- int retval; ++ int retval = -1; + + /* Make sure the time cvalue is OK. */ + if (tp->tv_nsec < 0 || tp->tv_nsec >= 1000000000) +@@ -93,16 +45,7 @@ __clock_settime (clockid_t clock_id, const struct timespec *tp) + break; + + default: +-# if HP_TIMING_AVAIL +- if (CPUCLOCK_WHICH (clock_id) == CLOCK_PROCESS_CPUTIME_ID +- || CPUCLOCK_WHICH (clock_id) == CLOCK_THREAD_CPUTIME_ID) +- retval = hp_timing_settime (clock_id, tp); +- else +-# endif +- { +- __set_errno (EINVAL); +- retval = -1; +- } ++ __set_errno (EINVAL); + break; + } + diff --git a/SOURCES/glibc-rh1748197-6.patch b/SOURCES/glibc-rh1748197-6.patch new file mode 100644 index 0000000..65b59c9 --- /dev/null +++ b/SOURCES/glibc-rh1748197-6.patch @@ -0,0 +1,745 @@ +commit 6e8ba7fd574f530afb9681f21604475d5756d773 +Author: Adhemerval Zanella +Date: Fri Feb 8 16:53:40 2019 +0000 + + Remove __get_clockfreq + + With clock_getres, clock_gettime, and clock_settime refactor to remove the + generic CLOCK_PROCESS_CPUTIME_ID and CLOCK_THREAD_CPUTIME_ID support through + hp-timing, there is no usage of internal __get_clockfreq. This patch removes + both generic and Linux implementation.. + + Checked with a build against aarch64-linux-gnu, i686-linux-gnu, ia64-linux-gnu, + sparc64-linux-gnu, powerpc-linux-gnu-power4. + + * include/libc-internal.h (__get_clockfreq): Remove prototype. + * rt/Makefile (clock-routines): Remove get_clockfreq. + * rt/get_clockfreq.c: Remove file. + * sysdeps/unix/sysv/linux/i386/get_clockfreq.c: Likewise. + * sysdeps/unix/sysv/linux/ia64/get_clockfreq.c: Likewise. + * sysdeps/unix/sysv/linux/sparc/sparc64/get_clockfreq.c: Likewise. + * sysdeps/unix/sysv/linux/powerpc/get_clockfreq.c: Move code to ... + * sysdeps/unix/sysv/linux/powerpc/get_timebase_freq.c: ... here. + +Conflicts: + rt/get_clockfreq.c + sysdeps/unix/sysv/linux/i386/get_clockfreq.c + sysdeps/unix/sysv/linux/ia64/get_clockfreq.c + sysdeps/unix/sysv/linux/powerpc/get_clockfreq.c + (Removal after copyright year change upstream.) + sysdeps/unix/sysv/linux/sparc/sparc64/get_clockfreq.c + (Likewise. Missing backport of aa0e46636a5b71 ("Break + further lines before not after operators.").) + +diff --git a/include/libc-internal.h b/include/libc-internal.h +index 2167990c52bd708b..2ec07d9355db1808 100644 +--- a/include/libc-internal.h ++++ b/include/libc-internal.h +@@ -36,9 +36,6 @@ libc_hidden_proto (__profile_frequency) + extern void __cyg_profile_func_enter (void *this_fn, void *call_site); + extern void __cyg_profile_func_exit (void *this_fn, void *call_site); + +-/* Get frequency of the system processor. */ +-extern hp_timing_t __get_clockfreq (void); +- + /* Free all allocated resources. */ + extern void __libc_freeres (void); + libc_hidden_proto (__libc_freeres) +diff --git a/rt/Makefile b/rt/Makefile +index 6d6b896ee9817c5c..14f38ef74d262188 100644 +--- a/rt/Makefile ++++ b/rt/Makefile +@@ -28,7 +28,7 @@ aio-routines := aio_cancel aio_error aio_fsync aio_misc aio_read \ + aio_read64 aio_return aio_suspend aio_write \ + aio_write64 lio_listio lio_listio64 aio_sigqueue \ + aio_notify +-clock-routines := get_clockfreq clock_getcpuclockid \ ++clock-routines := clock_getcpuclockid \ + clock_getres clock_gettime clock_settime \ + clock_nanosleep + timer-routines := timer_create timer_delete timer_getoverr \ +diff --git a/rt/get_clockfreq.c b/rt/get_clockfreq.c +deleted file mode 100644 +index e695a6018c0b8322..0000000000000000 +--- a/rt/get_clockfreq.c ++++ /dev/null +@@ -1,27 +0,0 @@ +-/* Get frequency of the system processor. +- 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 +- +-hp_timing_t +-__get_clockfreq (void) +-{ +- /* There is no generic way to find this out since we have in general +- no counter register either. */ +- return 0; +-} +diff --git a/sysdeps/unix/sysv/linux/i386/get_clockfreq.c b/sysdeps/unix/sysv/linux/i386/get_clockfreq.c +deleted file mode 100644 +index 633f186be80f10b0..0000000000000000 +--- a/sysdeps/unix/sysv/linux/i386/get_clockfreq.c ++++ /dev/null +@@ -1,88 +0,0 @@ +-/* Get frequency of the system processor. i386/Linux version. +- 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 +-#include +- +-hp_timing_t +-__get_clockfreq (void) +-{ +- /* We read the information from the /proc filesystem. It contains at +- least one line like +- cpu MHz : 497.840237 +- or also +- cpu MHz : 497.841 +- We search for this line and convert the number in an integer. */ +- static hp_timing_t result; +- int fd; +- +- /* If this function was called before, we know the result. */ +- if (result != 0) +- return result; +- +- fd = __open ("/proc/cpuinfo", O_RDONLY); +- if (__glibc_likely (fd != -1)) +- { +- /* XXX AFAIK the /proc filesystem can generate "files" only up +- to a size of 4096 bytes. */ +- char buf[4096]; +- ssize_t n; +- +- n = __read (fd, buf, sizeof buf); +- if (__builtin_expect (n, 1) > 0) +- { +- char *mhz = memmem (buf, n, "cpu MHz", 7); +- +- if (__glibc_likely (mhz != NULL)) +- { +- char *endp = buf + n; +- int seen_decpoint = 0; +- int ndigits = 0; +- +- /* Search for the beginning of the string. */ +- while (mhz < endp && (*mhz < '0' || *mhz > '9') && *mhz != '\n') +- ++mhz; +- +- while (mhz < endp && *mhz != '\n') +- { +- if (*mhz >= '0' && *mhz <= '9') +- { +- result *= 10; +- result += *mhz - '0'; +- if (seen_decpoint) +- ++ndigits; +- } +- else if (*mhz == '.') +- seen_decpoint = 1; +- +- ++mhz; +- } +- +- /* Compensate for missing digits at the end. */ +- while (ndigits++ < 6) +- result *= 10; +- } +- } +- +- __close (fd); +- } +- +- return result; +-} +diff --git a/sysdeps/unix/sysv/linux/ia64/get_clockfreq.c b/sysdeps/unix/sysv/linux/ia64/get_clockfreq.c +deleted file mode 100644 +index f9d683a90247ac60..0000000000000000 +--- a/sysdeps/unix/sysv/linux/ia64/get_clockfreq.c ++++ /dev/null +@@ -1,87 +0,0 @@ +-/* Get frequency of the system processor. IA-64/Linux version. +- 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 +- . */ +- +-#include +-#include +-#include +-#include +- +- +-hp_timing_t +-__get_clockfreq (void) +-{ +- /* We read the information from the /proc filesystem. It contains at +- least one line like +- itc MHz : 733.390988 +- We search for this line and convert the number in an integer. */ +- static hp_timing_t result; +- int fd; +- +- /* If this function was called before, we know the result. */ +- if (result != 0) +- return result; +- +- fd = __open ("/proc/cpuinfo", O_RDONLY); +- if (__builtin_expect (fd != -1, 1)) +- { +- /* XXX AFAIK the /proc filesystem can generate "files" only up +- to a size of 4096 bytes. */ +- char buf[4096]; +- ssize_t n; +- +- n = __read (fd, buf, sizeof buf); +- if (__builtin_expect (n, 1) > 0) +- { +- char *mhz = memmem (buf, n, "itc MHz", 7); +- +- if (__builtin_expect (mhz != NULL, 1)) +- { +- char *endp = buf + n; +- int seen_decpoint = 0; +- int ndigits = 0; +- +- /* Search for the beginning of the string. */ +- while (mhz < endp && (*mhz < '0' || *mhz > '9') && *mhz != '\n') +- ++mhz; +- +- while (mhz < endp && *mhz != '\n') +- { +- if (*mhz >= '0' && *mhz <= '9') +- { +- result *= 10; +- result += *mhz - '0'; +- if (seen_decpoint) +- ++ndigits; +- } +- else if (*mhz == '.') +- seen_decpoint = 1; +- +- ++mhz; +- } +- +- /* Compensate for missing digits at the end. */ +- while (ndigits++ < 6) +- result *= 10; +- } +- } +- +- __close (fd); +- } +- +- return result; +-} +diff --git a/sysdeps/unix/sysv/linux/powerpc/get_clockfreq.c b/sysdeps/unix/sysv/linux/powerpc/get_clockfreq.c +deleted file mode 100644 +index 3a2216021bfb5408..0000000000000000 +--- a/sysdeps/unix/sysv/linux/powerpc/get_clockfreq.c ++++ /dev/null +@@ -1,107 +0,0 @@ +-/* Get frequency of the system processor. powerpc/Linux version. +- 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 +-#include +-#include +-#include +-#include +-#include +- +-hp_timing_t +-__get_clockfreq (void) +-{ +- hp_timing_t result = 0L; +- +-#ifdef SHARED +- /* The vDSO does not return an error (it clear cr0.so on returning). */ +- INTERNAL_SYSCALL_DECL (err); +- result = +- INTERNAL_VSYSCALL_NO_SYSCALL_FALLBACK (get_tbfreq, err, uint64_t, 0); +-#else +- /* We read the information from the /proc filesystem. /proc/cpuinfo +- contains at least one line like: +- timebase : 33333333 +- We search for this line and convert the number into an integer. */ +- int fd = __open_nocancel ("/proc/cpuinfo", O_RDONLY); +- if (__glibc_likely (fd != -1)) +- return result; +- +- /* The timebase will be in the 1st 1024 bytes for systems with up +- to 8 processors. If the first read returns less then 1024 +- bytes read, we have the whole cpuinfo and can start the scan. +- Otherwise we will have to read more to insure we have the +- timebase value in the scan. */ +- char buf[1024]; +- ssize_t n; +- +- n = __read_nocancel (fd, buf, sizeof (buf)); +- if (n == sizeof (buf)) +- { +- /* We are here because the 1st read returned exactly sizeof +- (buf) bytes. This implies that we are not at EOF and may +- not have read the timebase value yet. So we need to read +- more bytes until we know we have EOF. We copy the lower +- half of buf to the upper half and read sizeof (buf)/2 +- bytes into the lower half of buf and repeat until we +- reach EOF. We can assume that the timebase will be in +- the last 512 bytes of cpuinfo, so two 512 byte half_bufs +- will be sufficient to contain the timebase and will +- handle the case where the timebase spans the half_buf +- boundry. */ +- const ssize_t half_buf = sizeof (buf) / 2; +- while (n >= half_buf) +- { +- memcpy (buf, buf + half_buf, half_buf); +- n = __read_nocancel (fd, buf + half_buf, half_buf); +- } +- if (n >= 0) +- n += half_buf; +- } +- __close_nocancel (fd); +- +- if (__glibc_likely (n > 0)) +- { +- char *mhz = memmem (buf, n, "timebase", 7); +- +- if (__glibc_likely (mhz != NULL)) +- { +- char *endp = buf + n; +- +- /* Search for the beginning of the string. */ +- while (mhz < endp && (*mhz < '0' || *mhz > '9') && *mhz != '\n') +- ++mhz; +- +- while (mhz < endp && *mhz != '\n') +- { +- if (*mhz >= '0' && *mhz <= '9') +- { +- result *= 10; +- result += *mhz - '0'; +- } +- +- ++mhz; +- } +- } +- } +-#endif +- +- return result; +-} +diff --git a/sysdeps/unix/sysv/linux/powerpc/get_timebase_freq.c b/sysdeps/unix/sysv/linux/powerpc/get_timebase_freq.c +index 6435e1f31529c7de..1177ccbc8faeafe7 100644 +--- a/sysdeps/unix/sysv/linux/powerpc/get_timebase_freq.c ++++ b/sysdeps/unix/sysv/linux/powerpc/get_timebase_freq.c +@@ -17,11 +17,90 @@ + . */ + + #include ++#include ++ + #include ++#include ++#include + + uint64_t + __get_timebase_freq (void) + { +- return (uint64_t) __get_clockfreq (); ++ hp_timing_t result = 0L; ++ ++#ifdef SHARED ++ /* The vDSO does not return an error (it clear cr0.so on returning). */ ++ INTERNAL_SYSCALL_DECL (err); ++ result = ++ INTERNAL_VSYSCALL_NO_SYSCALL_FALLBACK (get_tbfreq, err, uint64_t, 0); ++#else ++ /* We read the information from the /proc filesystem. /proc/cpuinfo ++ contains at least one line like: ++ timebase : 33333333 ++ We search for this line and convert the number into an integer. */ ++ int fd = __open_nocancel ("/proc/cpuinfo", O_RDONLY); ++ if (__glibc_likely (fd != -1)) ++ return result; ++ ++ /* The timebase will be in the 1st 1024 bytes for systems with up ++ to 8 processors. If the first read returns less then 1024 ++ bytes read, we have the whole cpuinfo and can start the scan. ++ Otherwise we will have to read more to insure we have the ++ timebase value in the scan. */ ++ char buf[1024]; ++ ssize_t n; ++ ++ n = __read_nocancel (fd, buf, sizeof (buf)); ++ if (n == sizeof (buf)) ++ { ++ /* We are here because the 1st read returned exactly sizeof ++ (buf) bytes. This implies that we are not at EOF and may ++ not have read the timebase value yet. So we need to read ++ more bytes until we know we have EOF. We copy the lower ++ half of buf to the upper half and read sizeof (buf)/2 ++ bytes into the lower half of buf and repeat until we ++ reach EOF. We can assume that the timebase will be in ++ the last 512 bytes of cpuinfo, so two 512 byte half_bufs ++ will be sufficient to contain the timebase and will ++ handle the case where the timebase spans the half_buf ++ boundry. */ ++ const ssize_t half_buf = sizeof (buf) / 2; ++ while (n >= half_buf) ++ { ++ memcpy (buf, buf + half_buf, half_buf); ++ n = __read_nocancel (fd, buf + half_buf, half_buf); ++ } ++ if (n >= 0) ++ n += half_buf; ++ } ++ __close_nocancel (fd); ++ ++ if (__glibc_likely (n > 0)) ++ { ++ char *mhz = memmem (buf, n, "timebase", 7); ++ ++ if (__glibc_likely (mhz != NULL)) ++ { ++ char *endp = buf + n; ++ ++ /* Search for the beginning of the string. */ ++ while (mhz < endp && (*mhz < '0' || *mhz > '9') && *mhz != '\n') ++ ++mhz; ++ ++ while (mhz < endp && *mhz != '\n') ++ { ++ if (*mhz >= '0' && *mhz <= '9') ++ { ++ result *= 10; ++ result += *mhz - '0'; ++ } ++ ++ ++mhz; ++ } ++ } ++ } ++#endif ++ ++ return result; + } + weak_alias (__get_timebase_freq, __ppc_get_timebase_freq) +diff --git a/sysdeps/unix/sysv/linux/sparc/sparc64/get_clockfreq.c b/sysdeps/unix/sysv/linux/sparc/sparc64/get_clockfreq.c +deleted file mode 100644 +index 6838a77a769ddae8..0000000000000000 +--- a/sysdeps/unix/sysv/linux/sparc/sparc64/get_clockfreq.c ++++ /dev/null +@@ -1,250 +0,0 @@ +-/* Get frequency of the system processor. sparc64 version. +- 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 +- . */ +- +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +- +-static hp_timing_t +-__get_clockfreq_via_cpuinfo (void) +-{ +- hp_timing_t result; +- int fd; +- +- result = 0; +- +- fd = __open ("/proc/cpuinfo", O_RDONLY); +- if (fd != -1) +- { +- char buf[8192]; +- ssize_t n; +- +- n = __read (fd, buf, sizeof buf); +- if (n > 0) +- { +- char *mhz = memmem (buf, n, "Cpu0ClkTck", 7); +- +- if (mhz != NULL) +- { +- char *endp = buf + n; +- +- /* Search for the beginning of the string. */ +- while (mhz < endp +- && (*mhz < '0' || *mhz > '9') +- && (*mhz < 'a' || *mhz > 'f') +- && *mhz != '\n') +- ++mhz; +- +- while (mhz < endp && *mhz != '\n') +- { +- if ((*mhz >= '0' && *mhz <= '9') || +- (*mhz >= 'a' && *mhz <= 'f')) +- { +- result <<= 4; +- if (*mhz >= '0' && *mhz <= '9') +- result += *mhz - '0'; +- else +- result += (*mhz - 'a') + 10; +- } +- ++mhz; +- } +- } +- } +- +- __close (fd); +- } +- +- return result; +-} +- +-static hp_timing_t +-__get_clockfreq_via_proc_openprom (void) +-{ +- hp_timing_t result; +- int obp_fd; +- +- result = 0; +- +- obp_fd = __open ("/proc/openprom", O_RDONLY); +- if (obp_fd != -1) +- { +- unsigned long int buf[4096 / sizeof (unsigned long int)]; +- struct dirent64 *dirp = (struct dirent64 *) buf; +- ssize_t len; +- +- while ((len = __getdents64 (obp_fd, (char *) dirp, sizeof (buf))) > 0) +- { +- struct dirent64 *this_dirp = dirp; +- +- while (len > 0) +- { +- char node[strlen ("/proc/openprom/") +- + _D_ALLOC_NAMLEN (this_dirp) +- + strlen ("/clock-frequency")]; +- char *prop; +- int fd; +- +- /* Note that +- strlen("/clock-frequency") > strlen("/device_type") +- */ +- __stpcpy (prop = __stpcpy (__stpcpy (node, "/proc/openprom/"), +- this_dirp->d_name), +- "/device_type"); +- fd = __open (node, O_RDONLY); +- if (fd != -1) +- { +- char type_string[128]; +- int ret; +- +- ret = __read (fd, type_string, sizeof (type_string)); +- if (ret > 0 && strncmp (type_string, "'cpu'", 5) == 0) +- { +- int clkfreq_fd; +- +- __stpcpy (prop, "/clock-frequency"); +- clkfreq_fd = __open (node, O_RDONLY); +- if (clkfreq_fd != -1) +- { +- if (__read (clkfreq_fd, type_string, +- sizeof (type_string)) > 0) +- result = (hp_timing_t) +- strtoumax (type_string, NULL, 16); +- __close (clkfreq_fd); +- } +- } +- __close (fd); +- } +- +- if (result != 0) +- break; +- +- len -= this_dirp->d_reclen; +- this_dirp = (struct dirent64 *) +- ((char *) this_dirp + this_dirp->d_reclen); +- } +- if (result != 0) +- break; +- } +- __close (obp_fd); +- } +- +- return result; +-} +- +-static void set_obp_int (struct openpromio *op, int val) +-{ +- char *cp = op->oprom_array; +- int *ip = (int *) cp; +- +- *ip = val; +-} +- +-static int get_obp_int (struct openpromio *op) +-{ +- char *cp = op->oprom_array; +- int *ip = (int *) cp; +- +- return *ip; +-} +- +-static hp_timing_t +-__get_clockfreq_via_dev_openprom (void) +-{ +- hp_timing_t result; +- int obp_dev_fd; +- +- result = 0; +- +- obp_dev_fd = __open ("/dev/openprom", O_RDONLY); +- if (obp_dev_fd != -1) +- { +- char obp_buf[8192]; +- struct openpromio *obp_cmd = (struct openpromio *)obp_buf; +- int ret; +- +- obp_cmd->oprom_size = +- sizeof (obp_buf) - sizeof (unsigned int); +- set_obp_int (obp_cmd, 0); +- ret = __ioctl (obp_dev_fd, OPROMCHILD, (char *) obp_cmd); +- if (ret == 0) +- { +- int cur_node = get_obp_int (obp_cmd); +- +- while (cur_node != 0 && cur_node != -1) +- { +- obp_cmd->oprom_size = sizeof (obp_buf) - sizeof (unsigned int); +- strcpy (obp_cmd->oprom_array, "device_type"); +- ret = __ioctl (obp_dev_fd, OPROMGETPROP, (char *) obp_cmd); +- if (ret == 0 +- && strncmp (obp_cmd->oprom_array, "cpu", 3) == 0) +- { +- obp_cmd->oprom_size = (sizeof (obp_buf) +- - sizeof (unsigned int)); +- strcpy (obp_cmd->oprom_array, "clock-frequency"); +- ret = __ioctl (obp_dev_fd, OPROMGETPROP, (char *) obp_cmd); +- if (ret == 0) +- result = (hp_timing_t) get_obp_int (obp_cmd); +- } +- obp_cmd->oprom_size = sizeof (obp_buf) - sizeof (unsigned int); +- set_obp_int (obp_cmd, cur_node); +- ret = __ioctl (obp_dev_fd, OPROMNEXT, (char *) obp_cmd); +- if (ret < 0) +- break; +- cur_node = get_obp_int (obp_cmd); +- } +- } +- } +- +- return result; +-} +- +-hp_timing_t +-__get_clockfreq (void) +-{ +- static hp_timing_t result; +- +- /* If this function was called before, we know the result. */ +- if (result != 0) +- return result; +- +- /* We first read the information from the /proc/cpuinfo file. +- It contains at least one line like +- Cpu0ClkTick : 000000002cb41780 +- We search for this line and convert the number in an integer. */ +- result = __get_clockfreq_via_cpuinfo (); +- if (result != 0) +- return result; +- +- /* If that did not work, try to find an OpenPROM node +- with device_type equal to 'cpu' using /dev/openprom +- and fetch the clock-frequency property from there. */ +- result = __get_clockfreq_via_dev_openprom (); +- if (result != 0) +- return result; +- +- /* Finally, try the same lookup as above but using /proc/openprom. */ +- result = __get_clockfreq_via_proc_openprom (); +- +- return result; +-} diff --git a/SOURCES/glibc-rh1748197-7.patch b/SOURCES/glibc-rh1748197-7.patch new file mode 100644 index 0000000..805da52 --- /dev/null +++ b/SOURCES/glibc-rh1748197-7.patch @@ -0,0 +1,1335 @@ +commit 7b5af2d8f2a2b858319a792678b15a0db08764c7 +Author: Zack Weinberg +Date: Wed Sep 4 08:18:57 2019 +0200 + + Finish move of clock_* functions to libc. [BZ #24959] + + In glibc 2.17, the functions clock_getcpuclockid, clock_getres, + clock_gettime, clock_nanosleep, and clock_settime were moved from + librt.so to libc.so, leaving compatibility stubs behind. Now that the + dynamic linker no longer insists on finding versioned symbols in the + same library that originally defined them, we do not need the stubs + anymore, and this means we don't need GLIBC_PRIVATE __-prefix aliases + for most of the functions anymore either. (clock_gettime still needs + one.) For ports added before 2.17, libc.so needs to provide two + symbol versions for each, the default at GLIBC_2.17 plus a compat + version matching what librt had. + + While I'm at it, move the clock_*.c files and their tests from rt/ to + time/. + + Conflicts: + rt/clock-compat.c + (Removal after copyright year update upstream.) + sysdeps/unix/sysv/linux/arm/be/libc.abilist + sysdeps/unix/sysv/linux/arm/le/librt.abilist + sysdeps/unix/sysv/linux/microblaze/le/librt.abilist + sysdeps/unix/sysv/linux/sh/be/libc.abilist + sysdeps/unix/sysv/linux/sh/le/librt.abilist + (These ABI lists were split into be/le variants upstream. + The choice of files here reflects the decision of the Git + rename detection for the source of the unsplit ABI list + update.) + time/Makefile + (Missing tests downstream.) + +diff --git a/include/time.h b/include/time.h +index 23d2580528b02490..832ee6896e1ca537 100644 +--- a/include/time.h ++++ b/include/time.h +@@ -16,12 +16,10 @@ libc_hidden_proto (localtime) + libc_hidden_proto (strftime) + libc_hidden_proto (strptime) + +-extern __typeof (clock_getres) __clock_getres; + extern __typeof (clock_gettime) __clock_gettime; + libc_hidden_proto (__clock_gettime) + extern __typeof (clock_settime) __clock_settime; +-extern __typeof (clock_nanosleep) __clock_nanosleep; +-extern __typeof (clock_getcpuclockid) __clock_getcpuclockid; ++libc_hidden_proto (__clock_settime) + + /* Now define the internal interfaces. */ + struct tm; +diff --git a/rt/Makefile b/rt/Makefile +index 14f38ef74d262188..de53133cedc778f6 100644 +--- a/rt/Makefile ++++ b/rt/Makefile +@@ -28,9 +28,6 @@ aio-routines := aio_cancel aio_error aio_fsync aio_misc aio_read \ + aio_read64 aio_return aio_suspend aio_write \ + aio_write64 lio_listio lio_listio64 aio_sigqueue \ + aio_notify +-clock-routines := clock_getcpuclockid \ +- clock_getres clock_gettime clock_settime \ +- clock_nanosleep + timer-routines := timer_create timer_delete timer_getoverr \ + timer_gettime timer_settime + shm-routines := shm_open shm_unlink +@@ -38,22 +35,18 @@ mq-routines := mq_open mq_close mq_unlink mq_getattr mq_setattr \ + mq_notify mq_send mq_receive mq_timedsend \ + mq_timedreceive + +-routines = $(clock-routines) +- + librt-routines = $(aio-routines) \ + $(timer-routines) \ +- $(shm-routines) $(mq-routines) \ +- clock-compat ++ $(shm-routines) $(mq-routines) + +-tests := tst-shm tst-clock tst-clock_nanosleep tst-timer tst-timer2 \ ++tests := tst-shm tst-timer tst-timer2 \ + tst-aio tst-aio64 tst-aio2 tst-aio3 tst-aio4 tst-aio5 tst-aio6 \ + tst-aio7 tst-aio8 tst-aio9 tst-aio10 \ + tst-mqueue1 tst-mqueue2 tst-mqueue3 tst-mqueue4 \ + tst-mqueue5 tst-mqueue6 tst-mqueue7 tst-mqueue8 tst-mqueue9 \ + tst-timer3 tst-timer4 tst-timer5 \ +- tst-cpuclock1 tst-cpuclock2 \ +- tst-cputimer1 tst-cputimer2 tst-cputimer3 \ +- tst-clock2 tst-shm-cancel ++ tst-cpuclock2 tst-cputimer1 tst-cputimer2 tst-cputimer3 \ ++ tst-shm-cancel + + extra-libs := librt + extra-libs-others := $(extra-libs) +diff --git a/rt/Versions b/rt/Versions +index 91e3fd2a204ded9c..84d1345420dc4dc4 100644 +--- a/rt/Versions ++++ b/rt/Versions +@@ -1,15 +1,3 @@ +-libc { +- GLIBC_2.17 { +- # c* +- clock_getres; clock_gettime; clock_settime; clock_getcpuclockid; +- clock_nanosleep; +- } +- GLIBC_PRIVATE { +- __clock_getres; __clock_gettime; __clock_settime; __clock_getcpuclockid; +- __clock_nanosleep; +- } +-} +- + librt { + GLIBC_2.1 { + # AIO functions. +@@ -18,10 +6,6 @@ librt { + aio_suspend64; aio_write; aio_write64; lio_listio; lio_listio64; + } + GLIBC_2.2 { +- # These have moved to libc and are still here only for compatibility. +- clock_getres; clock_gettime; clock_settime; clock_getcpuclockid; +- clock_nanosleep; +- + # s* + shm_open; shm_unlink; + +diff --git a/rt/clock-compat.c b/rt/clock-compat.c +deleted file mode 100644 +index 11e71aa89019b173..0000000000000000 +--- a/rt/clock-compat.c ++++ /dev/null +@@ -1,63 +0,0 @@ +-/* ABI compatibility redirects for clock_* symbols in librt. +- Copyright (C) 2012-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 +- +-/* The clock_* symbols were originally defined in librt and so +- are part of its ABI. As of 2.17, they have moved to libc. +- So we supply definitions for librt that just redirect to +- their libc counterparts. */ +- +-#if SHLIB_COMPAT (librt, GLIBC_2_2, GLIBC_2_17) +- +-#include +- +-#if HAVE_IFUNC +-# undef INIT_ARCH +-# define INIT_ARCH() +-# define COMPAT_REDIRECT(name, proto, arglist) libc_ifunc (name, &__##name) \ +- compat_symbol (librt, name, name, GLIBC_2_2); +-#else +-# define COMPAT_REDIRECT(name, proto, arglist) \ +- int \ +- name proto \ +- { \ +- return __##name arglist; \ +- } \ +- compat_symbol (librt, name, name, GLIBC_2_2); +-#endif +- +-COMPAT_REDIRECT (clock_getres, +- (clockid_t clock_id, struct timespec *res), +- (clock_id, res)) +-COMPAT_REDIRECT (clock_gettime, +- (clockid_t clock_id, struct timespec *tp), +- (clock_id, tp)) +-COMPAT_REDIRECT (clock_settime, +- (clockid_t clock_id, const struct timespec *tp), +- (clock_id, tp)) +-COMPAT_REDIRECT (clock_getcpuclockid, +- (pid_t pid, clockid_t *clock_id), +- (pid, clock_id)) +-COMPAT_REDIRECT (clock_nanosleep, +- (clockid_t clock_id, int flags, +- const struct timespec *req, +- struct timespec *rem), +- (clock_id, flags, req, rem)) +- +-#endif +diff --git a/sysdeps/mach/hurd/i386/libc.abilist b/sysdeps/mach/hurd/i386/libc.abilist +index e3fc05137b18194b..f89ef9a43251c164 100644 +--- a/sysdeps/mach/hurd/i386/libc.abilist ++++ b/sysdeps/mach/hurd/i386/libc.abilist +@@ -711,6 +711,11 @@ GLIBC_2.2.6 clntudp_bufcreate F + GLIBC_2.2.6 clntudp_create F + GLIBC_2.2.6 clntunix_create F + GLIBC_2.2.6 clock F ++GLIBC_2.2.6 clock_getcpuclockid F ++GLIBC_2.2.6 clock_getres F ++GLIBC_2.2.6 clock_gettime F ++GLIBC_2.2.6 clock_nanosleep F ++GLIBC_2.2.6 clock_settime F + GLIBC_2.2.6 close F + GLIBC_2.2.6 closedir F + GLIBC_2.2.6 closelog F +diff --git a/sysdeps/mach/hurd/i386/librt.abilist b/sysdeps/mach/hurd/i386/librt.abilist +index d5fe32b3a9917254..3726e41f06cc500c 100644 +--- a/sysdeps/mach/hurd/i386/librt.abilist ++++ b/sysdeps/mach/hurd/i386/librt.abilist +@@ -13,11 +13,6 @@ GLIBC_2.2.6 aio_suspend F + GLIBC_2.2.6 aio_suspend64 F + GLIBC_2.2.6 aio_write F + GLIBC_2.2.6 aio_write64 F +-GLIBC_2.2.6 clock_getcpuclockid F +-GLIBC_2.2.6 clock_getres F +-GLIBC_2.2.6 clock_gettime F +-GLIBC_2.2.6 clock_nanosleep F +-GLIBC_2.2.6 clock_settime F + GLIBC_2.2.6 lio_listio F + GLIBC_2.2.6 lio_listio64 F + GLIBC_2.2.6 shm_open F +diff --git a/sysdeps/posix/clock_getres.c b/sysdeps/posix/clock_getres.c +index 5b0d8eb8a1a0593e..7408197420b14aad 100644 +--- a/sysdeps/posix/clock_getres.c ++++ b/sysdeps/posix/clock_getres.c +@@ -22,7 +22,7 @@ + #include + #include + #include +- ++#include + + static inline int + realtime_getres (struct timespec *res) +@@ -62,4 +62,11 @@ __clock_getres (clockid_t clock_id, struct timespec *res) + + return retval; + } +-weak_alias (__clock_getres, clock_getres) ++ ++versioned_symbol (libc, __clock_getres, clock_getres, GLIBC_2_17); ++/* clock_getres moved to libc in version 2.17; ++ old binaries may expect the symbol version it had in librt. */ ++#if SHLIB_COMPAT (libc, GLIBC_2_2, GLIBC_2_17) ++strong_alias (__clock_getres, __clock_getres_2); ++compat_symbol (libc, __clock_getres_2, clock_getres, GLIBC_2_2); ++#endif +diff --git a/sysdeps/unix/clock_gettime.c b/sysdeps/unix/clock_gettime.c +index f3ebbe15ccc2e95e..3ad8ea87bb7d379b 100644 +--- a/sysdeps/unix/clock_gettime.c ++++ b/sysdeps/unix/clock_gettime.c +@@ -17,24 +17,9 @@ + . */ + + #include +-#include + #include + #include +-#include +-#include +- +- +-static inline int +-realtime_gettime (struct timespec *tp) +-{ +- struct timeval tv; +- int retval = __gettimeofday (&tv, NULL); +- if (retval == 0) +- /* Convert into `timespec'. */ +- TIMEVAL_TO_TIMESPEC (&tv, tp); +- return retval; +-} +- ++#include + + /* Get current value of CLOCK and store it in TP. */ + int +@@ -60,5 +45,12 @@ __clock_gettime (clockid_t clock_id, struct timespec *tp) + + return retval; + } +-weak_alias (__clock_gettime, clock_gettime) + libc_hidden_def (__clock_gettime) ++ ++versioned_symbol (libc, __clock_gettime, clock_gettime, GLIBC_2_17); ++/* clock_gettime moved to libc in version 2.17; ++ old binaries may expect the symbol version it had in librt. */ ++#if SHLIB_COMPAT (libc, GLIBC_2_2, GLIBC_2_17) ++strong_alias (__clock_gettime, __clock_gettime_2); ++compat_symbol (libc, __clock_gettime_2, clock_gettime, GLIBC_2_2); ++#endif +diff --git a/sysdeps/unix/clock_nanosleep.c b/sysdeps/unix/clock_nanosleep.c +index 13dd0f4b905ec631..6513e2d64614c561 100644 +--- a/sysdeps/unix/clock_nanosleep.c ++++ b/sysdeps/unix/clock_nanosleep.c +@@ -20,6 +20,7 @@ + #include + #include + #include ++#include + + /* This implementation assumes that these is only a `nanosleep' system + call. So we have to remap all other activities. */ +@@ -76,4 +77,11 @@ __clock_nanosleep (clockid_t clock_id, int flags, const struct timespec *req, + + return __nanosleep (req, rem), 0 ? errno : 0; + } +-weak_alias (__clock_nanosleep, clock_nanosleep) ++ ++versioned_symbol (libc, __clock_nanosleep, clock_nanosleep, GLIBC_2_17); ++/* clock_nanosleep moved to libc in version 2.17; ++ old binaries may expect the symbol version it had in librt. */ ++#if SHLIB_COMPAT (libc, GLIBC_2_2, GLIBC_2_17) ++strong_alias (__clock_nanosleep, __clock_nanosleep_2); ++compat_symbol (libc, __clock_nanosleep_2, clock_nanosleep, GLIBC_2_2); ++#endif +diff --git a/sysdeps/unix/clock_settime.c b/sysdeps/unix/clock_settime.c +index 4f5640f67047cef6..123b6f44ee3831d9 100644 +--- a/sysdeps/unix/clock_settime.c ++++ b/sysdeps/unix/clock_settime.c +@@ -18,8 +18,7 @@ + #include + #include + #include +-#include +- ++#include + + /* Set CLOCK to value TP. */ + int +@@ -51,4 +50,12 @@ __clock_settime (clockid_t clock_id, const struct timespec *tp) + + return retval; + } +-weak_alias (__clock_settime, clock_settime) ++libc_hidden_def (__clock_settime) ++ ++versioned_symbol (libc, __clock_settime, clock_settime, GLIBC_2_17); ++/* clock_settime moved to libc in version 2.17; ++ old binaries may expect the symbol version it had in librt. */ ++#if SHLIB_COMPAT (libc, GLIBC_2_2, GLIBC_2_17) ++strong_alias (__clock_settime, __clock_settime_2); ++compat_symbol (libc, __clock_settime_2, clock_settime, GLIBC_2_2); ++#endif +diff --git a/sysdeps/unix/sysv/linux/alpha/libc.abilist b/sysdeps/unix/sysv/linux/alpha/libc.abilist +index e22b91655dd5f7e0..77f0432d0f1f5aab 100644 +--- a/sysdeps/unix/sysv/linux/alpha/libc.abilist ++++ b/sysdeps/unix/sysv/linux/alpha/libc.abilist +@@ -1863,6 +1863,11 @@ GLIBC_2.2 __xpg_sigpause F + GLIBC_2.2 _flushlbf F + GLIBC_2.2 _res_hconf D 0x48 + GLIBC_2.2 bind_textdomain_codeset F ++GLIBC_2.2 clock_getcpuclockid F ++GLIBC_2.2 clock_getres F ++GLIBC_2.2 clock_gettime F ++GLIBC_2.2 clock_nanosleep F ++GLIBC_2.2 clock_settime F + GLIBC_2.2 dcngettext F + GLIBC_2.2 dngettext F + GLIBC_2.2 fgetpos F +diff --git a/sysdeps/unix/sysv/linux/alpha/librt.abilist b/sysdeps/unix/sysv/linux/alpha/librt.abilist +index d7a049cf600e2966..71f86e03ce67fd19 100644 +--- a/sysdeps/unix/sysv/linux/alpha/librt.abilist ++++ b/sysdeps/unix/sysv/linux/alpha/librt.abilist +@@ -15,11 +15,6 @@ GLIBC_2.1 aio_write F + GLIBC_2.1 aio_write64 F + GLIBC_2.1 lio_listio F + GLIBC_2.1 lio_listio64 F +-GLIBC_2.2 clock_getcpuclockid F +-GLIBC_2.2 clock_getres F +-GLIBC_2.2 clock_gettime F +-GLIBC_2.2 clock_nanosleep F +-GLIBC_2.2 clock_settime F + GLIBC_2.2 shm_open F + GLIBC_2.2 shm_unlink F + GLIBC_2.2 timer_create F +diff --git a/sysdeps/unix/sysv/linux/arm/libc.abilist b/sysdeps/unix/sysv/linux/arm/libc.abilist +index a231812eea6dc556..e748ec28912ce773 100644 +--- a/sysdeps/unix/sysv/linux/arm/libc.abilist ++++ b/sysdeps/unix/sysv/linux/arm/libc.abilist +@@ -759,6 +759,11 @@ GLIBC_2.4 clntudp_bufcreate F + GLIBC_2.4 clntudp_create F + GLIBC_2.4 clntunix_create F + GLIBC_2.4 clock F ++GLIBC_2.4 clock_getcpuclockid F ++GLIBC_2.4 clock_getres F ++GLIBC_2.4 clock_gettime F ++GLIBC_2.4 clock_nanosleep F ++GLIBC_2.4 clock_settime F + GLIBC_2.4 clone F + GLIBC_2.4 close F + GLIBC_2.4 closedir F +diff --git a/sysdeps/unix/sysv/linux/arm/librt.abilist b/sysdeps/unix/sysv/linux/arm/librt.abilist +index cfbbd2755765e720..3c0647b2516bb51d 100644 +--- a/sysdeps/unix/sysv/linux/arm/librt.abilist ++++ b/sysdeps/unix/sysv/linux/arm/librt.abilist +@@ -13,11 +13,6 @@ GLIBC_2.4 aio_suspend F + GLIBC_2.4 aio_suspend64 F + GLIBC_2.4 aio_write F + GLIBC_2.4 aio_write64 F +-GLIBC_2.4 clock_getcpuclockid F +-GLIBC_2.4 clock_getres F +-GLIBC_2.4 clock_gettime F +-GLIBC_2.4 clock_nanosleep F +-GLIBC_2.4 clock_settime F + GLIBC_2.4 lio_listio F + GLIBC_2.4 lio_listio64 F + GLIBC_2.4 mq_close F +diff --git a/sysdeps/unix/sysv/linux/clock_getcpuclockid.c b/sysdeps/unix/sysv/linux/clock_getcpuclockid.c +index 190a47950eb1d177..877f4f3c7916a534 100644 +--- a/sysdeps/unix/sysv/linux/clock_getcpuclockid.c ++++ b/sysdeps/unix/sysv/linux/clock_getcpuclockid.c +@@ -20,6 +20,7 @@ + #include + #include + #include "kernel-posix-cpu-timers.h" ++#include + + int + __clock_getcpuclockid (pid_t pid, clockid_t *clock_id) +@@ -45,4 +46,11 @@ __clock_getcpuclockid (pid_t pid, clockid_t *clock_id) + else + return INTERNAL_SYSCALL_ERRNO (r, err); + } +-weak_alias (__clock_getcpuclockid, clock_getcpuclockid) ++ ++versioned_symbol (libc, __clock_getcpuclockid, clock_getcpuclockid, GLIBC_2_17); ++/* clock_getcpuclockid moved to libc in version 2.17; ++ old binaries may expect the symbol version it had in librt. */ ++#if SHLIB_COMPAT (libc, GLIBC_2_2, GLIBC_2_17) ++strong_alias (__clock_getcpuclockid, __clock_getcpuclockid_2); ++compat_symbol (libc, __clock_getcpuclockid_2, clock_getcpuclockid, GLIBC_2_2); ++#endif +diff --git a/sysdeps/unix/sysv/linux/clock_getres.c b/sysdeps/unix/sysv/linux/clock_getres.c +index 2517e66910a79d93..1fbb638097ba4a80 100644 +--- a/sysdeps/unix/sysv/linux/clock_getres.c ++++ b/sysdeps/unix/sysv/linux/clock_getres.c +@@ -26,10 +26,19 @@ + #endif + #include + ++#include ++ + /* Get resolution of clock. */ + int + __clock_getres (clockid_t clock_id, struct timespec *res) + { + return INLINE_VSYSCALL (clock_getres, 2, clock_id, res); + } +-weak_alias (__clock_getres, clock_getres) ++ ++versioned_symbol (libc, __clock_getres, clock_getres, GLIBC_2_17); ++/* clock_getres moved to libc in version 2.17; ++ old binaries may expect the symbol version it had in librt. */ ++#if SHLIB_COMPAT (libc, GLIBC_2_2, GLIBC_2_17) ++strong_alias (__clock_getres, __clock_getres_2); ++compat_symbol (libc, __clock_getres_2, clock_getres, GLIBC_2_2); ++#endif +diff --git a/sysdeps/unix/sysv/linux/clock_gettime.c b/sysdeps/unix/sysv/linux/clock_gettime.c +index dadfc518b74baea0..3f8feb37a1795306 100644 +--- a/sysdeps/unix/sysv/linux/clock_gettime.c ++++ b/sysdeps/unix/sysv/linux/clock_gettime.c +@@ -26,11 +26,20 @@ + #endif + #include + ++#include ++ + /* Get current value of CLOCK and store it in TP. */ + int + __clock_gettime (clockid_t clock_id, struct timespec *tp) + { + return INLINE_VSYSCALL (clock_gettime, 2, clock_id, tp); + } +-weak_alias (__clock_gettime, clock_gettime) + libc_hidden_def (__clock_gettime) ++ ++versioned_symbol (libc, __clock_gettime, clock_gettime, GLIBC_2_17); ++/* clock_gettime moved to libc in version 2.17; ++ old binaries may expect the symbol version it had in librt. */ ++#if SHLIB_COMPAT (libc, GLIBC_2_2, GLIBC_2_17) ++strong_alias (__clock_gettime, __clock_gettime_2); ++compat_symbol (libc, __clock_gettime_2, clock_gettime, GLIBC_2_2); ++#endif +diff --git a/sysdeps/unix/sysv/linux/clock_nanosleep.c b/sysdeps/unix/sysv/linux/clock_nanosleep.c +index 93d5d6ef120ca9ef..a90da63069b7f0f8 100644 +--- a/sysdeps/unix/sysv/linux/clock_nanosleep.c ++++ b/sysdeps/unix/sysv/linux/clock_nanosleep.c +@@ -21,6 +21,7 @@ + #include + #include "kernel-posix-cpu-timers.h" + ++#include + + /* We can simply use the syscall. The CPU clocks are not supported + with this function. */ +@@ -51,4 +52,11 @@ __clock_nanosleep (clockid_t clock_id, int flags, const struct timespec *req, + return (INTERNAL_SYSCALL_ERROR_P (r, err) + ? INTERNAL_SYSCALL_ERRNO (r, err) : 0); + } +-weak_alias (__clock_nanosleep, clock_nanosleep) ++ ++versioned_symbol (libc, __clock_nanosleep, clock_nanosleep, GLIBC_2_17); ++/* clock_nanosleep moved to libc in version 2.17; ++ old binaries may expect the symbol version it had in librt. */ ++#if SHLIB_COMPAT (libc, GLIBC_2_2, GLIBC_2_17) ++strong_alias (__clock_nanosleep, __clock_nanosleep_2); ++compat_symbol (libc, __clock_nanosleep_2, clock_nanosleep, GLIBC_2_2); ++#endif +diff --git a/sysdeps/unix/sysv/linux/clock_settime.c b/sysdeps/unix/sysv/linux/clock_settime.c +index c71461a4f6deac5a..21efc6c982c084b4 100644 +--- a/sysdeps/unix/sysv/linux/clock_settime.c ++++ b/sysdeps/unix/sysv/linux/clock_settime.c +@@ -18,6 +18,7 @@ + #include + #include + #include ++#include + + #include "kernel-posix-cpu-timers.h" + +@@ -34,4 +35,12 @@ __clock_settime (clockid_t clock_id, const struct timespec *tp) + + return INLINE_SYSCALL_CALL (clock_settime, clock_id, tp); + } +-weak_alias (__clock_settime, clock_settime) ++libc_hidden_def (__clock_settime) ++ ++versioned_symbol (libc, __clock_settime, clock_settime, GLIBC_2_17); ++/* clock_settime moved to libc in version 2.17; ++ old binaries may expect the symbol version it had in librt. */ ++#if SHLIB_COMPAT (libc, GLIBC_2_2, GLIBC_2_17) ++strong_alias (__clock_settime, __clock_settime_2); ++compat_symbol (libc, __clock_settime_2, clock_settime, GLIBC_2_2); ++#endif +diff --git a/sysdeps/unix/sysv/linux/hppa/libc.abilist b/sysdeps/unix/sysv/linux/hppa/libc.abilist +index 24b11b15c0e71140..d34f040d85cc5bb2 100644 +--- a/sysdeps/unix/sysv/linux/hppa/libc.abilist ++++ b/sysdeps/unix/sysv/linux/hppa/libc.abilist +@@ -615,6 +615,11 @@ GLIBC_2.2 clntudp_bufcreate F + GLIBC_2.2 clntudp_create F + GLIBC_2.2 clntunix_create F + GLIBC_2.2 clock F ++GLIBC_2.2 clock_getcpuclockid F ++GLIBC_2.2 clock_getres F ++GLIBC_2.2 clock_gettime F ++GLIBC_2.2 clock_nanosleep F ++GLIBC_2.2 clock_settime F + GLIBC_2.2 clone F + GLIBC_2.2 close F + GLIBC_2.2 closedir F +diff --git a/sysdeps/unix/sysv/linux/hppa/librt.abilist b/sysdeps/unix/sysv/linux/hppa/librt.abilist +index 595f1b712a4e8d70..bb03781dcc04d219 100644 +--- a/sysdeps/unix/sysv/linux/hppa/librt.abilist ++++ b/sysdeps/unix/sysv/linux/hppa/librt.abilist +@@ -15,11 +15,6 @@ GLIBC_2.1 aio_write F + GLIBC_2.1 aio_write64 F + GLIBC_2.1 lio_listio F + GLIBC_2.1 lio_listio64 F +-GLIBC_2.2 clock_getcpuclockid F +-GLIBC_2.2 clock_getres F +-GLIBC_2.2 clock_gettime F +-GLIBC_2.2 clock_nanosleep F +-GLIBC_2.2 clock_settime F + GLIBC_2.2 shm_open F + GLIBC_2.2 shm_unlink F + GLIBC_2.2 timer_create F +diff --git a/sysdeps/unix/sysv/linux/i386/libc.abilist b/sysdeps/unix/sysv/linux/i386/libc.abilist +index 9762c81365b0abcd..48e838fc2813df0d 100644 +--- a/sysdeps/unix/sysv/linux/i386/libc.abilist ++++ b/sysdeps/unix/sysv/linux/i386/libc.abilist +@@ -1869,6 +1869,11 @@ GLIBC_2.2 _flushlbf F + GLIBC_2.2 _res_hconf D 0x30 + GLIBC_2.2 alphasort64 F + GLIBC_2.2 bind_textdomain_codeset F ++GLIBC_2.2 clock_getcpuclockid F ++GLIBC_2.2 clock_getres F ++GLIBC_2.2 clock_gettime F ++GLIBC_2.2 clock_nanosleep F ++GLIBC_2.2 clock_settime F + GLIBC_2.2 dcngettext F + GLIBC_2.2 dngettext F + GLIBC_2.2 fgetpos F +diff --git a/sysdeps/unix/sysv/linux/i386/librt.abilist b/sysdeps/unix/sysv/linux/i386/librt.abilist +index 595f1b712a4e8d70..bb03781dcc04d219 100644 +--- a/sysdeps/unix/sysv/linux/i386/librt.abilist ++++ b/sysdeps/unix/sysv/linux/i386/librt.abilist +@@ -15,11 +15,6 @@ GLIBC_2.1 aio_write F + GLIBC_2.1 aio_write64 F + GLIBC_2.1 lio_listio F + GLIBC_2.1 lio_listio64 F +-GLIBC_2.2 clock_getcpuclockid F +-GLIBC_2.2 clock_getres F +-GLIBC_2.2 clock_gettime F +-GLIBC_2.2 clock_nanosleep F +-GLIBC_2.2 clock_settime F + GLIBC_2.2 shm_open F + GLIBC_2.2 shm_unlink F + GLIBC_2.2 timer_create F +diff --git a/sysdeps/unix/sysv/linux/ia64/libc.abilist b/sysdeps/unix/sysv/linux/ia64/libc.abilist +index 50c94adff93b5bb4..e9fe0697b784be64 100644 +--- a/sysdeps/unix/sysv/linux/ia64/libc.abilist ++++ b/sysdeps/unix/sysv/linux/ia64/libc.abilist +@@ -627,6 +627,11 @@ GLIBC_2.2 clntudp_bufcreate F + GLIBC_2.2 clntudp_create F + GLIBC_2.2 clntunix_create F + GLIBC_2.2 clock F ++GLIBC_2.2 clock_getcpuclockid F ++GLIBC_2.2 clock_getres F ++GLIBC_2.2 clock_gettime F ++GLIBC_2.2 clock_nanosleep F ++GLIBC_2.2 clock_settime F + GLIBC_2.2 close F + GLIBC_2.2 closedir F + GLIBC_2.2 closelog F +diff --git a/sysdeps/unix/sysv/linux/ia64/librt.abilist b/sysdeps/unix/sysv/linux/ia64/librt.abilist +index 804622a14abd8ea9..08384c906518837d 100644 +--- a/sysdeps/unix/sysv/linux/ia64/librt.abilist ++++ b/sysdeps/unix/sysv/linux/ia64/librt.abilist +@@ -15,11 +15,6 @@ GLIBC_2.1 aio_write F + GLIBC_2.1 aio_write64 F + GLIBC_2.1 lio_listio F + GLIBC_2.1 lio_listio64 F +-GLIBC_2.2 clock_getcpuclockid F +-GLIBC_2.2 clock_getres F +-GLIBC_2.2 clock_gettime F +-GLIBC_2.2 clock_nanosleep F +-GLIBC_2.2 clock_settime F + GLIBC_2.2 shm_open F + GLIBC_2.2 shm_unlink F + GLIBC_2.2 timer_create F +diff --git a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist +index f57be98e494d0701..98f07b79918d1c17 100644 +--- a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist ++++ b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist +@@ -748,6 +748,11 @@ GLIBC_2.4 clntudp_bufcreate F + GLIBC_2.4 clntudp_create F + GLIBC_2.4 clntunix_create F + GLIBC_2.4 clock F ++GLIBC_2.4 clock_getcpuclockid F ++GLIBC_2.4 clock_getres F ++GLIBC_2.4 clock_gettime F ++GLIBC_2.4 clock_nanosleep F ++GLIBC_2.4 clock_settime F + GLIBC_2.4 clone F + GLIBC_2.4 close F + GLIBC_2.4 closedir F +diff --git a/sysdeps/unix/sysv/linux/m68k/coldfire/librt.abilist b/sysdeps/unix/sysv/linux/m68k/coldfire/librt.abilist +index cfbbd2755765e720..3c0647b2516bb51d 100644 +--- a/sysdeps/unix/sysv/linux/m68k/coldfire/librt.abilist ++++ b/sysdeps/unix/sysv/linux/m68k/coldfire/librt.abilist +@@ -13,11 +13,6 @@ GLIBC_2.4 aio_suspend F + GLIBC_2.4 aio_suspend64 F + GLIBC_2.4 aio_write F + GLIBC_2.4 aio_write64 F +-GLIBC_2.4 clock_getcpuclockid F +-GLIBC_2.4 clock_getres F +-GLIBC_2.4 clock_gettime F +-GLIBC_2.4 clock_nanosleep F +-GLIBC_2.4 clock_settime F + GLIBC_2.4 lio_listio F + GLIBC_2.4 lio_listio64 F + GLIBC_2.4 mq_close F +diff --git a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist +index ddc7ebca673a466c..6a60d7876120f2f2 100644 +--- a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist ++++ b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist +@@ -1825,6 +1825,11 @@ GLIBC_2.2 _flushlbf F + GLIBC_2.2 _res_hconf D 0x30 + GLIBC_2.2 alphasort64 F + GLIBC_2.2 bind_textdomain_codeset F ++GLIBC_2.2 clock_getcpuclockid F ++GLIBC_2.2 clock_getres F ++GLIBC_2.2 clock_gettime F ++GLIBC_2.2 clock_nanosleep F ++GLIBC_2.2 clock_settime F + GLIBC_2.2 dcngettext F + GLIBC_2.2 dngettext F + GLIBC_2.2 fgetpos F +diff --git a/sysdeps/unix/sysv/linux/m68k/m680x0/librt.abilist b/sysdeps/unix/sysv/linux/m68k/m680x0/librt.abilist +index 595f1b712a4e8d70..bb03781dcc04d219 100644 +--- a/sysdeps/unix/sysv/linux/m68k/m680x0/librt.abilist ++++ b/sysdeps/unix/sysv/linux/m68k/m680x0/librt.abilist +@@ -15,11 +15,6 @@ GLIBC_2.1 aio_write F + GLIBC_2.1 aio_write64 F + GLIBC_2.1 lio_listio F + GLIBC_2.1 lio_listio64 F +-GLIBC_2.2 clock_getcpuclockid F +-GLIBC_2.2 clock_getres F +-GLIBC_2.2 clock_gettime F +-GLIBC_2.2 clock_nanosleep F +-GLIBC_2.2 clock_settime F + GLIBC_2.2 shm_open F + GLIBC_2.2 shm_unlink F + GLIBC_2.2 timer_create F +diff --git a/sysdeps/unix/sysv/linux/microblaze/librt.abilist b/sysdeps/unix/sysv/linux/microblaze/librt.abilist +index fb85d8729e1bc69d..889dfbc0eef5e75a 100644 +--- a/sysdeps/unix/sysv/linux/microblaze/librt.abilist ++++ b/sysdeps/unix/sysv/linux/microblaze/librt.abilist +@@ -14,11 +14,6 @@ GLIBC_2.18 aio_suspend F + GLIBC_2.18 aio_suspend64 F + GLIBC_2.18 aio_write F + GLIBC_2.18 aio_write64 F +-GLIBC_2.18 clock_getcpuclockid F +-GLIBC_2.18 clock_getres F +-GLIBC_2.18 clock_gettime F +-GLIBC_2.18 clock_nanosleep F +-GLIBC_2.18 clock_settime F + GLIBC_2.18 lio_listio F + GLIBC_2.18 lio_listio64 F + GLIBC_2.18 mq_close F +diff --git a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist +index dda9797e0ea736f6..34a24582ca7a4a08 100644 +--- a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist ++++ b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist +@@ -1612,6 +1612,11 @@ GLIBC_2.2 capget F + GLIBC_2.2 capset F + GLIBC_2.2 cbc_crypt F + GLIBC_2.2 clntunix_create F ++GLIBC_2.2 clock_getcpuclockid F ++GLIBC_2.2 clock_getres F ++GLIBC_2.2 clock_gettime F ++GLIBC_2.2 clock_nanosleep F ++GLIBC_2.2 clock_settime F + GLIBC_2.2 creat64 F + GLIBC_2.2 dcngettext F + GLIBC_2.2 des_setparity F +diff --git a/sysdeps/unix/sysv/linux/mips/mips32/librt.abilist b/sysdeps/unix/sysv/linux/mips/mips32/librt.abilist +index 84837c8a2ef02e1b..1539c1cef92bccfd 100644 +--- a/sysdeps/unix/sysv/linux/mips/mips32/librt.abilist ++++ b/sysdeps/unix/sysv/linux/mips/mips32/librt.abilist +@@ -13,11 +13,6 @@ GLIBC_2.2 aio_suspend F + GLIBC_2.2 aio_suspend64 F + GLIBC_2.2 aio_write F + GLIBC_2.2 aio_write64 F +-GLIBC_2.2 clock_getcpuclockid F +-GLIBC_2.2 clock_getres F +-GLIBC_2.2 clock_gettime F +-GLIBC_2.2 clock_nanosleep F +-GLIBC_2.2 clock_settime F + GLIBC_2.2 lio_listio F + GLIBC_2.2 lio_listio64 F + GLIBC_2.2 shm_open F +diff --git a/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist +index 42e930d56595083e..176a57298a45d492 100644 +--- a/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist ++++ b/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist +@@ -1610,6 +1610,11 @@ GLIBC_2.2 capget F + GLIBC_2.2 capset F + GLIBC_2.2 cbc_crypt F + GLIBC_2.2 clntunix_create F ++GLIBC_2.2 clock_getcpuclockid F ++GLIBC_2.2 clock_getres F ++GLIBC_2.2 clock_gettime F ++GLIBC_2.2 clock_nanosleep F ++GLIBC_2.2 clock_settime F + GLIBC_2.2 creat64 F + GLIBC_2.2 dcngettext F + GLIBC_2.2 des_setparity F +diff --git a/sysdeps/unix/sysv/linux/mips/mips64/librt.abilist b/sysdeps/unix/sysv/linux/mips/mips64/librt.abilist +index 84837c8a2ef02e1b..1539c1cef92bccfd 100644 +--- a/sysdeps/unix/sysv/linux/mips/mips64/librt.abilist ++++ b/sysdeps/unix/sysv/linux/mips/mips64/librt.abilist +@@ -13,11 +13,6 @@ GLIBC_2.2 aio_suspend F + GLIBC_2.2 aio_suspend64 F + GLIBC_2.2 aio_write F + GLIBC_2.2 aio_write64 F +-GLIBC_2.2 clock_getcpuclockid F +-GLIBC_2.2 clock_getres F +-GLIBC_2.2 clock_gettime F +-GLIBC_2.2 clock_nanosleep F +-GLIBC_2.2 clock_settime F + GLIBC_2.2 lio_listio F + GLIBC_2.2 lio_listio64 F + GLIBC_2.2 shm_open F +diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist +index f89b44f3a14d0f85..5a66ffd67e5cf364 100644 +--- a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist ++++ b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist +@@ -1611,6 +1611,11 @@ GLIBC_2.2 capget F + GLIBC_2.2 capset F + GLIBC_2.2 cbc_crypt F + GLIBC_2.2 clntunix_create F ++GLIBC_2.2 clock_getcpuclockid F ++GLIBC_2.2 clock_getres F ++GLIBC_2.2 clock_gettime F ++GLIBC_2.2 clock_nanosleep F ++GLIBC_2.2 clock_settime F + GLIBC_2.2 creat64 F + GLIBC_2.2 dcngettext F + GLIBC_2.2 des_setparity F +diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist +index 1486af11d755d37e..a817f33695a5230f 100644 +--- a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist ++++ b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist +@@ -1607,6 +1607,11 @@ GLIBC_2.2 capget F + GLIBC_2.2 capset F + GLIBC_2.2 cbc_crypt F + GLIBC_2.2 clntunix_create F ++GLIBC_2.2 clock_getcpuclockid F ++GLIBC_2.2 clock_getres F ++GLIBC_2.2 clock_gettime F ++GLIBC_2.2 clock_nanosleep F ++GLIBC_2.2 clock_settime F + GLIBC_2.2 creat64 F + GLIBC_2.2 dcngettext F + GLIBC_2.2 des_setparity F +diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist +index 45839ed25b0fde5f..d5e121b76e583f4c 100644 +--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist ++++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist +@@ -1830,6 +1830,11 @@ GLIBC_2.2 __xstat64 F + GLIBC_2.2 _flushlbf F + GLIBC_2.2 _res_hconf D 0x30 + GLIBC_2.2 bind_textdomain_codeset F ++GLIBC_2.2 clock_getcpuclockid F ++GLIBC_2.2 clock_getres F ++GLIBC_2.2 clock_gettime F ++GLIBC_2.2 clock_nanosleep F ++GLIBC_2.2 clock_settime F + GLIBC_2.2 dcngettext F + GLIBC_2.2 dngettext F + GLIBC_2.2 fgetpos F +diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/librt.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/librt.abilist +index 595f1b712a4e8d70..bb03781dcc04d219 100644 +--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/librt.abilist ++++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/librt.abilist +@@ -15,11 +15,6 @@ GLIBC_2.1 aio_write F + GLIBC_2.1 aio_write64 F + GLIBC_2.1 lio_listio F + GLIBC_2.1 lio_listio64 F +-GLIBC_2.2 clock_getcpuclockid F +-GLIBC_2.2 clock_getres F +-GLIBC_2.2 clock_gettime F +-GLIBC_2.2 clock_nanosleep F +-GLIBC_2.2 clock_settime F + GLIBC_2.2 shm_open F + GLIBC_2.2 shm_unlink F + GLIBC_2.2 timer_create F +diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist +index 344e5ae87c5d76b2..3dfddbddb3a11180 100644 +--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist ++++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist +@@ -1834,6 +1834,11 @@ GLIBC_2.2 __xstat64 F + GLIBC_2.2 _flushlbf F + GLIBC_2.2 _res_hconf D 0x30 + GLIBC_2.2 bind_textdomain_codeset F ++GLIBC_2.2 clock_getcpuclockid F ++GLIBC_2.2 clock_getres F ++GLIBC_2.2 clock_gettime F ++GLIBC_2.2 clock_nanosleep F ++GLIBC_2.2 clock_settime F + GLIBC_2.2 dcngettext F + GLIBC_2.2 dngettext F + GLIBC_2.2 fgetpos F +diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc.abilist +index 8c1781adf49a7432..06ce341194a37dd4 100644 +--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc.abilist ++++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc.abilist +@@ -670,6 +670,11 @@ GLIBC_2.3 clntudp_bufcreate F + GLIBC_2.3 clntudp_create F + GLIBC_2.3 clntunix_create F + GLIBC_2.3 clock F ++GLIBC_2.3 clock_getcpuclockid F ++GLIBC_2.3 clock_getres F ++GLIBC_2.3 clock_gettime F ++GLIBC_2.3 clock_nanosleep F ++GLIBC_2.3 clock_settime F + GLIBC_2.3 clone F + GLIBC_2.3 close F + GLIBC_2.3 closedir F +diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/librt.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/librt.abilist +index e76b7eb49566718b..6a5bd96963e67109 100644 +--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/librt.abilist ++++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/librt.abilist +@@ -13,11 +13,6 @@ GLIBC_2.3 aio_suspend F + GLIBC_2.3 aio_suspend64 F + GLIBC_2.3 aio_write F + GLIBC_2.3 aio_write64 F +-GLIBC_2.3 clock_getcpuclockid F +-GLIBC_2.3 clock_getres F +-GLIBC_2.3 clock_gettime F +-GLIBC_2.3 clock_nanosleep F +-GLIBC_2.3 clock_settime F + GLIBC_2.3 lio_listio F + GLIBC_2.3 lio_listio64 F + GLIBC_2.3 shm_open F +diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist +index 3a5ec2a1e47b5da5..02ff949c33197774 100644 +--- a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist ++++ b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist +@@ -1829,6 +1829,11 @@ GLIBC_2.2 _flushlbf F + GLIBC_2.2 _res_hconf D 0x30 + GLIBC_2.2 alphasort64 F + GLIBC_2.2 bind_textdomain_codeset F ++GLIBC_2.2 clock_getcpuclockid F ++GLIBC_2.2 clock_getres F ++GLIBC_2.2 clock_gettime F ++GLIBC_2.2 clock_nanosleep F ++GLIBC_2.2 clock_settime F + GLIBC_2.2 dcngettext F + GLIBC_2.2 dngettext F + GLIBC_2.2 fgetpos F +diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/librt.abilist b/sysdeps/unix/sysv/linux/s390/s390-32/librt.abilist +index 595f1b712a4e8d70..bb03781dcc04d219 100644 +--- a/sysdeps/unix/sysv/linux/s390/s390-32/librt.abilist ++++ b/sysdeps/unix/sysv/linux/s390/s390-32/librt.abilist +@@ -15,11 +15,6 @@ GLIBC_2.1 aio_write F + GLIBC_2.1 aio_write64 F + GLIBC_2.1 lio_listio F + GLIBC_2.1 lio_listio64 F +-GLIBC_2.2 clock_getcpuclockid F +-GLIBC_2.2 clock_getres F +-GLIBC_2.2 clock_gettime F +-GLIBC_2.2 clock_nanosleep F +-GLIBC_2.2 clock_settime F + GLIBC_2.2 shm_open F + GLIBC_2.2 shm_unlink F + GLIBC_2.2 timer_create F +diff --git a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist +index 3b5465558b72f166..96693d41df267e1b 100644 +--- a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist ++++ b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist +@@ -632,6 +632,11 @@ GLIBC_2.2 clntudp_bufcreate F + GLIBC_2.2 clntudp_create F + GLIBC_2.2 clntunix_create F + GLIBC_2.2 clock F ++GLIBC_2.2 clock_getcpuclockid F ++GLIBC_2.2 clock_getres F ++GLIBC_2.2 clock_gettime F ++GLIBC_2.2 clock_nanosleep F ++GLIBC_2.2 clock_settime F + GLIBC_2.2 clone F + GLIBC_2.2 close F + GLIBC_2.2 closedir F +diff --git a/sysdeps/unix/sysv/linux/s390/s390-64/librt.abilist b/sysdeps/unix/sysv/linux/s390/s390-64/librt.abilist +index 41be3bb84b6e4df0..5905498a488359d7 100644 +--- a/sysdeps/unix/sysv/linux/s390/s390-64/librt.abilist ++++ b/sysdeps/unix/sysv/linux/s390/s390-64/librt.abilist +@@ -13,11 +13,6 @@ GLIBC_2.2 aio_suspend F + GLIBC_2.2 aio_suspend64 F + GLIBC_2.2 aio_write F + GLIBC_2.2 aio_write64 F +-GLIBC_2.2 clock_getcpuclockid F +-GLIBC_2.2 clock_getres F +-GLIBC_2.2 clock_gettime F +-GLIBC_2.2 clock_nanosleep F +-GLIBC_2.2 clock_settime F + GLIBC_2.2 lio_listio F + GLIBC_2.2 lio_listio64 F + GLIBC_2.2 shm_open F +diff --git a/sysdeps/unix/sysv/linux/sh/libc.abilist b/sysdeps/unix/sysv/linux/sh/libc.abilist +index 1f4e648baade9c47..b126bda07a9cc58c 100644 +--- a/sysdeps/unix/sysv/linux/sh/libc.abilist ++++ b/sysdeps/unix/sysv/linux/sh/libc.abilist +@@ -618,6 +618,11 @@ GLIBC_2.2 clntudp_bufcreate F + GLIBC_2.2 clntudp_create F + GLIBC_2.2 clntunix_create F + GLIBC_2.2 clock F ++GLIBC_2.2 clock_getcpuclockid F ++GLIBC_2.2 clock_getres F ++GLIBC_2.2 clock_gettime F ++GLIBC_2.2 clock_nanosleep F ++GLIBC_2.2 clock_settime F + GLIBC_2.2 clone F + GLIBC_2.2 close F + GLIBC_2.2 closedir F +diff --git a/sysdeps/unix/sysv/linux/sh/librt.abilist b/sysdeps/unix/sysv/linux/sh/librt.abilist +index 595f1b712a4e8d70..bb03781dcc04d219 100644 +--- a/sysdeps/unix/sysv/linux/sh/librt.abilist ++++ b/sysdeps/unix/sysv/linux/sh/librt.abilist +@@ -15,11 +15,6 @@ GLIBC_2.1 aio_write F + GLIBC_2.1 aio_write64 F + GLIBC_2.1 lio_listio F + GLIBC_2.1 lio_listio64 F +-GLIBC_2.2 clock_getcpuclockid F +-GLIBC_2.2 clock_getres F +-GLIBC_2.2 clock_gettime F +-GLIBC_2.2 clock_nanosleep F +-GLIBC_2.2 clock_settime F + GLIBC_2.2 shm_open F + GLIBC_2.2 shm_unlink F + GLIBC_2.2 timer_create F +diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist +index d308ac8b0527cb3f..63b78d80b333d4b4 100644 +--- a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist ++++ b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist +@@ -1826,6 +1826,11 @@ GLIBC_2.2 __xstat64 F + GLIBC_2.2 _flushlbf F + GLIBC_2.2 _res_hconf D 0x30 + GLIBC_2.2 bind_textdomain_codeset F ++GLIBC_2.2 clock_getcpuclockid F ++GLIBC_2.2 clock_getres F ++GLIBC_2.2 clock_gettime F ++GLIBC_2.2 clock_nanosleep F ++GLIBC_2.2 clock_settime F + GLIBC_2.2 dcngettext F + GLIBC_2.2 dngettext F + GLIBC_2.2 fgetpos F +diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/librt.abilist b/sysdeps/unix/sysv/linux/sparc/sparc32/librt.abilist +index cb874f41477109c3..38f0aad791793010 100644 +--- a/sysdeps/unix/sysv/linux/sparc/sparc32/librt.abilist ++++ b/sysdeps/unix/sysv/linux/sparc/sparc32/librt.abilist +@@ -15,11 +15,6 @@ GLIBC_2.1 aio_write F + GLIBC_2.1 aio_write64 F + GLIBC_2.1 lio_listio F + GLIBC_2.1 lio_listio64 F +-GLIBC_2.2 clock_getcpuclockid F +-GLIBC_2.2 clock_getres F +-GLIBC_2.2 clock_gettime F +-GLIBC_2.2 clock_nanosleep F +-GLIBC_2.2 clock_settime F + GLIBC_2.2 shm_open F + GLIBC_2.2 shm_unlink F + GLIBC_2.2 timer_create F +diff --git a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist +index 6731ebfc2877c5c6..a899eb6a92215b47 100644 +--- a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist ++++ b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist +@@ -660,6 +660,11 @@ GLIBC_2.2 clntudp_bufcreate F + GLIBC_2.2 clntudp_create F + GLIBC_2.2 clntunix_create F + GLIBC_2.2 clock F ++GLIBC_2.2 clock_getcpuclockid F ++GLIBC_2.2 clock_getres F ++GLIBC_2.2 clock_gettime F ++GLIBC_2.2 clock_nanosleep F ++GLIBC_2.2 clock_settime F + GLIBC_2.2 clone F + GLIBC_2.2 close F + GLIBC_2.2 closedir F +diff --git a/sysdeps/unix/sysv/linux/sparc/sparc64/librt.abilist b/sysdeps/unix/sysv/linux/sparc/sparc64/librt.abilist +index d7a049cf600e2966..71f86e03ce67fd19 100644 +--- a/sysdeps/unix/sysv/linux/sparc/sparc64/librt.abilist ++++ b/sysdeps/unix/sysv/linux/sparc/sparc64/librt.abilist +@@ -15,11 +15,6 @@ GLIBC_2.1 aio_write F + GLIBC_2.1 aio_write64 F + GLIBC_2.1 lio_listio F + GLIBC_2.1 lio_listio64 F +-GLIBC_2.2 clock_getcpuclockid F +-GLIBC_2.2 clock_getres F +-GLIBC_2.2 clock_gettime F +-GLIBC_2.2 clock_nanosleep F +-GLIBC_2.2 clock_settime F + GLIBC_2.2 shm_open F + GLIBC_2.2 shm_unlink F + GLIBC_2.2 timer_create F +diff --git a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist +index 816e4a742632ad44..0ebb018e2089c70a 100644 +--- a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist ++++ b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist +@@ -621,6 +621,11 @@ GLIBC_2.2.5 clntudp_bufcreate F + GLIBC_2.2.5 clntudp_create F + GLIBC_2.2.5 clntunix_create F + GLIBC_2.2.5 clock F ++GLIBC_2.2.5 clock_getcpuclockid F ++GLIBC_2.2.5 clock_getres F ++GLIBC_2.2.5 clock_gettime F ++GLIBC_2.2.5 clock_nanosleep F ++GLIBC_2.2.5 clock_settime F + GLIBC_2.2.5 clone F + GLIBC_2.2.5 close F + GLIBC_2.2.5 closedir F +diff --git a/sysdeps/unix/sysv/linux/x86_64/64/librt.abilist b/sysdeps/unix/sysv/linux/x86_64/64/librt.abilist +index e2e8b60bf8e29f55..95e3f22daa06b237 100644 +--- a/sysdeps/unix/sysv/linux/x86_64/64/librt.abilist ++++ b/sysdeps/unix/sysv/linux/x86_64/64/librt.abilist +@@ -13,11 +13,6 @@ GLIBC_2.2.5 aio_suspend F + GLIBC_2.2.5 aio_suspend64 F + GLIBC_2.2.5 aio_write F + GLIBC_2.2.5 aio_write64 F +-GLIBC_2.2.5 clock_getcpuclockid F +-GLIBC_2.2.5 clock_getres F +-GLIBC_2.2.5 clock_gettime F +-GLIBC_2.2.5 clock_nanosleep F +-GLIBC_2.2.5 clock_settime F + GLIBC_2.2.5 lio_listio F + GLIBC_2.2.5 lio_listio64 F + GLIBC_2.2.5 shm_open F +diff --git a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist +index 6fee16a850adc7b8..0b6b3fa98183e5af 100644 +--- a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist ++++ b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist +@@ -660,6 +660,11 @@ GLIBC_2.16 clntudp_create F + GLIBC_2.16 clntunix_create F + GLIBC_2.16 clock F + GLIBC_2.16 clock_adjtime F ++GLIBC_2.16 clock_getcpuclockid F ++GLIBC_2.16 clock_getres F ++GLIBC_2.16 clock_gettime F ++GLIBC_2.16 clock_nanosleep F ++GLIBC_2.16 clock_settime F + GLIBC_2.16 clone F + GLIBC_2.16 close F + GLIBC_2.16 closedir F +diff --git a/sysdeps/unix/sysv/linux/x86_64/x32/librt.abilist b/sysdeps/unix/sysv/linux/x86_64/x32/librt.abilist +index 94e84e4dcfaa85dc..66969fb9ab887756 100644 +--- a/sysdeps/unix/sysv/linux/x86_64/x32/librt.abilist ++++ b/sysdeps/unix/sysv/linux/x86_64/x32/librt.abilist +@@ -14,11 +14,6 @@ GLIBC_2.16 aio_suspend F + GLIBC_2.16 aio_suspend64 F + GLIBC_2.16 aio_write F + GLIBC_2.16 aio_write64 F +-GLIBC_2.16 clock_getcpuclockid F +-GLIBC_2.16 clock_getres F +-GLIBC_2.16 clock_gettime F +-GLIBC_2.16 clock_nanosleep F +-GLIBC_2.16 clock_settime F + GLIBC_2.16 lio_listio F + GLIBC_2.16 lio_listio64 F + GLIBC_2.16 mq_close F +diff --git a/time/Makefile b/time/Makefile +index ec3e39dcea75ee51..6a68481a5de1b148 100644 +--- a/time/Makefile ++++ b/time/Makefile +@@ -36,14 +36,18 @@ routines := offtime asctime clock ctime ctime_r difftime \ + stime dysize timegm ftime \ + getdate strptime strptime_l \ + strftime wcsftime strftime_l wcsftime_l \ +- timespec_get ++ timespec_get \ ++ clock_getcpuclockid clock_getres \ ++ clock_gettime clock_settime clock_nanosleep ++ + aux := era alt_digit lc-time-cleanup + + tests := test_time clocktest tst-posixtz tst-strptime tst_wcsftime \ + tst-getdate tst-mktime tst-mktime2 tst-ftime_l tst-strftime \ + tst-mktime3 tst-strptime2 bug-asctime bug-asctime_r bug-mktime1 \ + tst-strptime3 bug-getdate1 tst-strptime-whitespace tst-ftime \ +- tst-tzname tst-y2039 ++ tst-tzname tst-y2039 \ ++ tst-clock tst-clock2 tst-clock_nanosleep tst-cpuclock1 + + include ../Rules + +diff --git a/time/Versions b/time/Versions +index fd838181e4f0969d..8788e192ce358d77 100644 +--- a/time/Versions ++++ b/time/Versions +@@ -49,6 +49,10 @@ libc { + GLIBC_2.2 { + # w* + wcsftime; ++ ++ # c*; actually in librt in version 2.2, moved to libc in 2.17 ++ clock_getres; clock_gettime; clock_settime; clock_getcpuclockid; ++ clock_nanosleep; + } + GLIBC_2.3 { + # these internal names are used by libstdc++ +@@ -65,4 +69,13 @@ libc { + GLIBC_2.16 { + timespec_get; + } ++ GLIBC_2.17 { ++ # c* ++ clock_getres; clock_gettime; clock_settime; clock_getcpuclockid; ++ clock_nanosleep; ++ } ++ GLIBC_PRIVATE { ++ # same as clock_gettime; used in other libraries ++ __clock_gettime; ++ } + } +diff --git a/rt/clock_getcpuclockid.c b/time/clock_getcpuclockid.c +similarity index 75% +rename from rt/clock_getcpuclockid.c +rename to time/clock_getcpuclockid.c +index 6bc42a0863d92d5a..81b86241f7adc6c9 100644 +--- a/rt/clock_getcpuclockid.c ++++ b/time/clock_getcpuclockid.c +@@ -19,6 +19,7 @@ + #include + #include + #include ++#include + + int + __clock_getcpuclockid (pid_t pid, clockid_t *clock_id) +@@ -37,4 +38,10 @@ __clock_getcpuclockid (pid_t pid, clockid_t *clock_id) + return ENOENT; + #endif + } +-weak_alias (__clock_getcpuclockid, clock_getcpuclockid) ++versioned_symbol (libc, __clock_getcpuclockid, clock_getcpuclockid, GLIBC_2_17); ++/* clock_getcpuclockid moved to libc in version 2.17; ++ old binaries may expect the symbol version it had in librt. */ ++#if SHLIB_COMPAT (libc, GLIBC_2_2, GLIBC_2_17) ++strong_alias (__clock_getcpuclockid, __clock_getcpuclockid_2); ++compat_symbol (libc, __clock_getcpuclockid_2, clock_getcpuclockid, GLIBC_2_2); ++#endif +diff --git a/rt/clock_getres.c b/time/clock_getres.c +similarity index 73% +rename from rt/clock_getres.c +rename to time/clock_getres.c +index 816f7b2a907e27ce..e8315393e560b186 100644 +--- a/rt/clock_getres.c ++++ b/time/clock_getres.c +@@ -18,6 +18,7 @@ + + #include + #include ++#include + + /* Get resolution of clock. */ + int +@@ -26,5 +27,13 @@ __clock_getres (clockid_t clock_id, struct timespec *res) + __set_errno (ENOSYS); + return -1; + } +-weak_alias (__clock_getres, clock_getres) ++ ++versioned_symbol (libc, __clock_getres, clock_getres, GLIBC_2_17); ++/* clock_getres moved to libc in version 2.17; ++ old binaries may expect the symbol version it had in librt. */ ++#if SHLIB_COMPAT (libc, GLIBC_2_2, GLIBC_2_17) ++strong_alias (__clock_getres, __clock_getres_2); ++compat_symbol (libc, __clock_getres_2, clock_getres, GLIBC_2_2); ++#endif ++ + stub_warning (clock_getres) +diff --git a/rt/clock_gettime.c b/time/clock_gettime.c +similarity index 74% +rename from rt/clock_gettime.c +rename to time/clock_gettime.c +index 30a012473f5bc821..4a5f808845351156 100644 +--- a/rt/clock_gettime.c ++++ b/time/clock_gettime.c +@@ -18,6 +18,7 @@ + + #include + #include ++#include + + /* Get current value of CLOCK and store it in TP. */ + int +@@ -26,6 +27,14 @@ __clock_gettime (clockid_t clock_id, struct timespec *tp) + __set_errno (ENOSYS); + return -1; + } +-weak_alias (__clock_gettime, clock_gettime) + libc_hidden_def (__clock_gettime) ++ ++versioned_symbol (libc, __clock_gettime, clock_gettime, GLIBC_2_17); ++/* clock_gettime moved to libc in version 2.17; ++ old binaries may expect the symbol version it had in librt. */ ++#if SHLIB_COMPAT (libc, GLIBC_2_2, GLIBC_2_17) ++strong_alias (__clock_gettime, __clock_gettime_2); ++compat_symbol (libc, __clock_gettime_2, clock_gettime, GLIBC_2_2); ++#endif ++ + stub_warning (clock_gettime) +diff --git a/rt/clock_nanosleep.c b/time/clock_nanosleep.c +similarity index 76% +rename from rt/clock_nanosleep.c +rename to time/clock_nanosleep.c +index 15aa6f7c4f22e197..a314b169a9455e0d 100644 +--- a/rt/clock_nanosleep.c ++++ b/time/clock_nanosleep.c +@@ -18,6 +18,7 @@ + + #include + #include ++#include + + int + __clock_nanosleep (clockid_t clock_id, int flags, const struct timespec *req, +@@ -33,5 +34,13 @@ __clock_nanosleep (clockid_t clock_id, int flags, const struct timespec *req, + /* Not implemented. */ + return ENOSYS; + } +-weak_alias (__clock_nanosleep, clock_nanosleep) ++ ++versioned_symbol (libc, __clock_nanosleep, clock_nanosleep, GLIBC_2_17); ++/* clock_nanosleep moved to libc in version 2.17; ++ old binaries may expect the symbol version it had in librt. */ ++#if SHLIB_COMPAT (libc, GLIBC_2_2, GLIBC_2_17) ++strong_alias (__clock_nanosleep, __clock_nanosleep_2); ++compat_symbol (libc, __clock_nanosleep_2, clock_nanosleep, GLIBC_2_2); ++#endif ++ + stub_warning (clock_nanosleep) +diff --git a/rt/clock_settime.c b/time/clock_settime.c +similarity index 71% +rename from rt/clock_settime.c +rename to time/clock_settime.c +index 0b6d4b2a2a0dc46c..2091239448e307f2 100644 +--- a/rt/clock_settime.c ++++ b/time/clock_settime.c +@@ -18,6 +18,7 @@ + + #include + #include ++#include + + /* Set CLOCK to value TP. */ + int +@@ -26,5 +27,14 @@ __clock_settime (clockid_t clock_id, const struct timespec *tp) + __set_errno (ENOSYS); + return -1; + } +-weak_alias (__clock_settime, clock_settime) ++libc_hidden_def (__clock_settime) ++ ++versioned_symbol (libc, __clock_settime, clock_settime, GLIBC_2_17); ++/* clock_settime moved to libc in version 2.17; ++ old binaries may expect the symbol version it had in librt. */ ++#if SHLIB_COMPAT (libc, GLIBC_2_2, GLIBC_2_17) ++strong_alias (__clock_settime, __clock_settime_2); ++compat_symbol (libc, __clock_settime_2, clock_settime, GLIBC_2_2); ++#endif ++ + stub_warning (clock_settime) +diff --git a/rt/tst-clock.c b/time/tst-clock.c +similarity index 100% +rename from rt/tst-clock.c +rename to time/tst-clock.c +diff --git a/rt/tst-clock2.c b/time/tst-clock2.c +similarity index 100% +rename from rt/tst-clock2.c +rename to time/tst-clock2.c +diff --git a/rt/tst-clock_nanosleep.c b/time/tst-clock_nanosleep.c +similarity index 100% +rename from rt/tst-clock_nanosleep.c +rename to time/tst-clock_nanosleep.c +diff --git a/rt/tst-cpuclock1.c b/time/tst-cpuclock1.c +similarity index 100% +rename from rt/tst-cpuclock1.c +rename to time/tst-cpuclock1.c diff --git a/SOURCES/glibc-rh1749439-1.patch b/SOURCES/glibc-rh1749439-1.patch new file mode 100644 index 0000000..18b7195 --- /dev/null +++ b/SOURCES/glibc-rh1749439-1.patch @@ -0,0 +1,512 @@ +commit 1a7fe2ebe52b3c8bf465d1756e69452d05c1c103 +Author: Florian Weimer +Date: Mon Aug 5 15:54:10 2019 +0200 + + login: Remove utmp backend jump tables [BZ #23518] + + There is just one file-based implementation, so this dispatch + mechanism is unnecessary. Instead of the vtable pointer + __libc_utmp_jump_table, use a non-negative file_fd as the indicator + that the backend is initialized. + +diff --git a/login/getutent_r.c b/login/getutent_r.c +index 6a244ba6e0b86da7..44239ecb81bacea4 100644 +--- a/login/getutent_r.c ++++ b/login/getutent_r.c +@@ -23,115 +23,16 @@ + + #include "utmp-private.h" + +- +-/* Functions defined here. */ +-static int setutent_unknown (void); +-static int getutent_r_unknown (struct utmp *buffer, struct utmp **result); +-static int getutid_r_unknown (const struct utmp *line, struct utmp *buffer, +- struct utmp **result); +-static int getutline_r_unknown (const struct utmp *id, struct utmp *buffer, +- struct utmp **result); +-static struct utmp *pututline_unknown (const struct utmp *data); +-static void endutent_unknown (void); +- +-/* Initial Jump table. */ +-const struct utfuncs __libc_utmp_unknown_functions = +-{ +- setutent_unknown, +- getutent_r_unknown, +- getutid_r_unknown, +- getutline_r_unknown, +- pututline_unknown, +- endutent_unknown, +- NULL +-}; +- +-/* Currently selected backend. */ +-const struct utfuncs *__libc_utmp_jump_table = &__libc_utmp_unknown_functions; +- + /* We need to protect the opening of the file. */ + __libc_lock_define_initialized (, __libc_utmp_lock attribute_hidden) + + +-static int +-setutent_unknown (void) +-{ +- int result; +- +- result = (*__libc_utmp_file_functions.setutent) (); +- if (result) +- __libc_utmp_jump_table = &__libc_utmp_file_functions; +- +- return result; +-} +- +- +-static int +-getutent_r_unknown (struct utmp *buffer, struct utmp **result) +-{ +- /* The backend was not yet initialized. */ +- if (setutent_unknown ()) +- return (*__libc_utmp_jump_table->getutent_r) (buffer, result); +- +- /* Not available. */ +- *result = NULL; +- return -1; +-} +- +- +-static int +-getutid_r_unknown (const struct utmp *id, struct utmp *buffer, +- struct utmp **result) +-{ +- /* The backend was not yet initialized. */ +- if (setutent_unknown ()) +- return (*__libc_utmp_jump_table->getutid_r) (id, buffer, result); +- +- /* Not available. */ +- *result = NULL; +- return -1; +-} +- +- +-static int +-getutline_r_unknown (const struct utmp *line, struct utmp *buffer, +- struct utmp **result) +-{ +- /* The backend was not yet initialized. */ +- if (setutent_unknown ()) +- return (*__libc_utmp_jump_table->getutline_r) (line, buffer, result); +- +- /* Not available. */ +- *result = NULL; +- return -1; +-} +- +- +-static struct utmp * +-pututline_unknown (const struct utmp *data) +-{ +- /* The backend was not yet initialized. */ +- if (setutent_unknown ()) +- return (*__libc_utmp_jump_table->pututline) (data); +- +- /* Not available. */ +- return NULL; +-} +- +- +-static void +-endutent_unknown (void) +-{ +- /* Nothing to do. */ +-} +- +- + void + __setutent (void) + { + __libc_lock_lock (__libc_utmp_lock); + +- (*__libc_utmp_jump_table->setutent) (); ++ __libc_setutent (); + + __libc_lock_unlock (__libc_utmp_lock); + } +@@ -145,7 +46,7 @@ __getutent_r (struct utmp *buffer, struct utmp **result) + + __libc_lock_lock (__libc_utmp_lock); + +- retval = (*__libc_utmp_jump_table->getutent_r) (buffer, result); ++ retval = __libc_getutent_r (buffer, result); + + __libc_lock_unlock (__libc_utmp_lock); + +@@ -162,7 +63,7 @@ __pututline (const struct utmp *data) + + __libc_lock_lock (__libc_utmp_lock); + +- buffer = (*__libc_utmp_jump_table->pututline) (data); ++ buffer = __libc_pututline (data); + + __libc_lock_unlock (__libc_utmp_lock); + +@@ -177,8 +78,7 @@ __endutent (void) + { + __libc_lock_lock (__libc_utmp_lock); + +- (*__libc_utmp_jump_table->endutent) (); +- __libc_utmp_jump_table = &__libc_utmp_unknown_functions; ++ __libc_endutent (); + + __libc_lock_unlock (__libc_utmp_lock); + } +diff --git a/login/getutid_r.c b/login/getutid_r.c +index b7d3dbac75774b0a..8cb6b16d735e8265 100644 +--- a/login/getutid_r.c ++++ b/login/getutid_r.c +@@ -49,7 +49,7 @@ __getutid_r (const struct utmp *id, struct utmp *buffer, struct utmp **result) + + __libc_lock_lock (__libc_utmp_lock); + +- retval = (*__libc_utmp_jump_table->getutid_r) (id, buffer, result); ++ retval = __libc_getutid_r (id, buffer, result); + + __libc_lock_unlock (__libc_utmp_lock); + +diff --git a/login/getutline_r.c b/login/getutline_r.c +index 6996887f76b28816..5607c19ed2e1ca66 100644 +--- a/login/getutline_r.c ++++ b/login/getutline_r.c +@@ -36,7 +36,7 @@ __getutline_r (const struct utmp *line, struct utmp *buffer, + + __libc_lock_lock (__libc_utmp_lock); + +- retval = (*__libc_utmp_jump_table->getutline_r) (line, buffer, result); ++ retval = __libc_getutline_r (line, buffer, result); + + __libc_lock_unlock (__libc_utmp_lock); + +diff --git a/login/updwtmp.c b/login/updwtmp.c +index 56fb41916a776c0a..7ae96224ca789b6d 100644 +--- a/login/updwtmp.c ++++ b/login/updwtmp.c +@@ -29,7 +29,7 @@ __updwtmp (const char *wtmp_file, const struct utmp *utmp) + { + const char *file_name = TRANSFORM_UTMP_FILE_NAME (wtmp_file); + +- (*__libc_utmp_file_functions.updwtmp) (file_name, utmp); ++ __libc_updwtmp (file_name, utmp); + } + libc_hidden_def (__updwtmp) + weak_alias (__updwtmp, updwtmp) +diff --git a/login/utmp-private.h b/login/utmp-private.h +index bd8773984cfc56de..5c2048ee52dc3cee 100644 +--- a/login/utmp-private.h ++++ b/login/utmp-private.h +@@ -24,24 +24,17 @@ + #include + #include + +-/* The structure describing the functions in a backend. */ +-struct utfuncs +-{ +- int (*setutent) (void); +- int (*getutent_r) (struct utmp *, struct utmp **); +- int (*getutid_r) (const struct utmp *, struct utmp *, struct utmp **); +- int (*getutline_r) (const struct utmp *, struct utmp *, struct utmp **); +- struct utmp *(*pututline) (const struct utmp *); +- void (*endutent) (void); +- int (*updwtmp) (const char *, const struct utmp *); +-}; +- +-/* The tables from the services. */ +-extern const struct utfuncs __libc_utmp_file_functions attribute_hidden; +-extern const struct utfuncs __libc_utmp_unknown_functions attribute_hidden; +- +-/* Currently selected backend. */ +-extern const struct utfuncs *__libc_utmp_jump_table attribute_hidden; ++/* These functions check for initialization, but not perform any ++ locking. */ ++int __libc_setutent (void) attribute_hidden; ++int __libc_getutent_r (struct utmp *, struct utmp **) attribute_hidden; ++int __libc_getutid_r (const struct utmp *, struct utmp *, struct utmp **) ++ attribute_hidden; ++int __libc_getutline_r (const struct utmp *, struct utmp *, struct utmp **) ++ attribute_hidden; ++struct utmp *__libc_pututline (const struct utmp *) attribute_hidden; ++void __libc_endutent (void) attribute_hidden; ++int __libc_updwtmp (const char *, const struct utmp *) attribute_hidden; + + /* Current file name. */ + extern const char *__libc_utmp_file_name attribute_hidden; +diff --git a/login/utmp_file.c b/login/utmp_file.c +index 040a5057116bb69d..069e6d0452e333ad 100644 +--- a/login/utmp_file.c ++++ b/login/utmp_file.c +@@ -105,37 +105,12 @@ static void timeout_handler (int signum) {}; + alarm (old_timeout); \ + } while (0) + +- +-/* Functions defined here. */ +-static int setutent_file (void); +-static int getutent_r_file (struct utmp *buffer, struct utmp **result); +-static int getutid_r_file (const struct utmp *key, struct utmp *buffer, +- struct utmp **result); +-static int getutline_r_file (const struct utmp *key, struct utmp *buffer, +- struct utmp **result); +-static struct utmp *pututline_file (const struct utmp *data); +-static void endutent_file (void); +-static int updwtmp_file (const char *file, const struct utmp *utmp); +- +-/* Jump table for file functions. */ +-const struct utfuncs __libc_utmp_file_functions = +-{ +- setutent_file, +- getutent_r_file, +- getutid_r_file, +- getutline_r_file, +- pututline_file, +- endutent_file, +- updwtmp_file +-}; +- +- + #ifndef TRANSFORM_UTMP_FILE_NAME + # define TRANSFORM_UTMP_FILE_NAME(file_name) (file_name) + #endif + +-static int +-setutent_file (void) ++int ++__libc_setutent (void) + { + if (file_fd < 0) + { +@@ -166,15 +141,19 @@ setutent_file (void) + return 1; + } + ++/* Preform initialization if necessary. */ ++static bool ++maybe_setutent (void) ++{ ++ return file_fd >= 0 || __libc_setutent (); ++} + +-static int +-getutent_r_file (struct utmp *buffer, struct utmp **result) ++int ++__libc_getutent_r (struct utmp *buffer, struct utmp **result) + { + ssize_t nbytes; + +- assert (file_fd >= 0); +- +- if (file_offset == -1l) ++ if (!maybe_setutent () || file_offset == -1l) + { + /* Not available. */ + *result = NULL; +@@ -279,13 +258,11 @@ unlock_return: + + /* For implementing this function we don't use the getutent_r function + because we can avoid the reposition on every new entry this way. */ +-static int +-getutid_r_file (const struct utmp *id, struct utmp *buffer, +- struct utmp **result) ++int ++__libc_getutid_r (const struct utmp *id, struct utmp *buffer, ++ struct utmp **result) + { +- assert (file_fd >= 0); +- +- if (file_offset == -1l) ++ if (!maybe_setutent () || file_offset == -1l) + { + *result = NULL; + return -1; +@@ -309,13 +286,11 @@ getutid_r_file (const struct utmp *id, struct utmp *buffer, + + /* For implementing this function we don't use the getutent_r function + because we can avoid the reposition on every new entry this way. */ +-static int +-getutline_r_file (const struct utmp *line, struct utmp *buffer, +- struct utmp **result) ++int ++__libc_getutline_r (const struct utmp *line, struct utmp *buffer, ++ struct utmp **result) + { +- assert (file_fd >= 0); +- +- if (file_offset == -1l) ++ if (!maybe_setutent () || file_offset == -1l) + { + *result = NULL; + return -1; +@@ -361,15 +336,16 @@ unlock_return: + } + + +-static struct utmp * +-pututline_file (const struct utmp *data) ++struct utmp * ++__libc_pututline (const struct utmp *data) + { ++ if (!maybe_setutent ()) ++ return NULL; ++ + struct utmp buffer; + struct utmp *pbuf; + int found; + +- assert (file_fd >= 0); +- + if (! file_writable) + { + /* We must make the file descriptor writable before going on. */ +@@ -467,18 +443,19 @@ pututline_file (const struct utmp *data) + } + + +-static void +-endutent_file (void) ++void ++__libc_endutent (void) + { +- assert (file_fd >= 0); +- +- __close_nocancel_nostatus (file_fd); +- file_fd = -1; ++ if (file_fd >= 0) ++ { ++ __close_nocancel_nostatus (file_fd); ++ file_fd = -1; ++ } + } + + +-static int +-updwtmp_file (const char *file, const struct utmp *utmp) ++int ++__libc_updwtmp (const char *file, const struct utmp *utmp) + { + int result = -1; + off64_t offset; +diff --git a/login/utmpname.c b/login/utmpname.c +index 21cb890a1a2fdc92..73b19c33ceab4dd7 100644 +--- a/login/utmpname.c ++++ b/login/utmpname.c +@@ -42,8 +42,7 @@ __utmpname (const char *file) + __libc_lock_lock (__libc_utmp_lock); + + /* Close the old file. */ +- (*__libc_utmp_jump_table->endutent) (); +- __libc_utmp_jump_table = &__libc_utmp_unknown_functions; ++ __libc_endutent (); + + if (strcmp (file, __libc_utmp_file_name) != 0) + { +diff --git a/manual/users.texi b/manual/users.texi +index 4ed79ba26fc8e9d0..a006bb58acfd0568 100644 +--- a/manual/users.texi ++++ b/manual/users.texi +@@ -894,9 +894,9 @@ The @code{getlogin} function is declared in @file{unistd.h}, while + @c ttyname_r dup @ascuheap @acsmem @acsfd + @c strncpy dup ok + @c libc_lock_lock dup @asulock @aculock +-@c *libc_utmp_jump_table->setutent dup @mtasurace:utent @acsfd +-@c *libc_utmp_jump_table->getutline_r dup @mtasurace:utent @mtascusig:ALRM @mtascutimer +-@c *libc_utmp_jump_table->endutent dup @mtasurace:utent @asulock @aculock ++@c __libc_setutent dup @mtasurace:utent @acsfd ++@c __libc_getutline_r dup @mtasurace:utent @mtascusig:ALRM @mtascutimer ++@c __libc_endutent dup @mtasurace:utent @asulock @aculock + @c libc_lock_unlock dup ok + @c strlen dup ok + @c memcpy dup ok +@@ -1111,7 +1111,7 @@ compatibility only, @file{utmp.h} defines @code{ut_time} as an alias for + + @c setutent @mtasurace:utent @asulock @aculock @acsfd + @c libc_lock_lock dup @asulock @aculock +-@c *libc_utmp_jump_table->setutent @mtasurace:utent @acsfd ++@c __libc_setutent @mtasurace:utent @acsfd + @c setutent_unknown @mtasurace:utent @acsfd + @c *libc_utmp_file_functions.setutent = setutent_file @mtasurace:utent @acsfd + @c open_not_cancel_2 dup @acsfd +@@ -1152,7 +1152,7 @@ A null pointer is returned in case no further entry is available. + @safety{@prelim{}@mtunsafe{@mtasurace{:utent}}@asunsafe{@asulock{}}@acunsafe{@aculock{} @acsfd{}}} + @c endutent @mtasurace:utent @asulock @aculock @acsfd + @c libc_lock_lock dup @asulock @aculock +-@c *libc_utmp_jump_table->endutent @mtasurace:utent @acsfd ++@c __libc_endutent @mtasurace:utent @acsfd + @c endutent_unknown ok + @c endutent_file @mtasurace:utent @acsfd + @c close_not_cancel_no_status dup @acsfd +@@ -1230,7 +1230,7 @@ over again. + @safety{@prelim{}@mtunsafe{@mtasurace{:utent} @mtascusig{:ALRM} @mtascutimer{}}@asunsafe{@asulock{}}@acunsafe{@aculock{} @acsfd{}}} + @c pututline @mtasurace:utent @mtascusig:ALRM @mtascutimer @asulock @aculock @acsfd + @c libc_lock_lock dup @asulock @aculock +-@c *libc_utmp_jump_table->pututline @mtasurace:utent @mtascusig:ALRM @mtascutimer @acsfd ++@c __libc_pututline @mtasurace:utent @mtascusig:ALRM @mtascutimer @acsfd + @c pututline_unknown @mtasurace:utent @acsfd + @c setutent_unknown dup @mtasurace:utent @acsfd + @c pututline_file @mtascusig:ALRM @mtascutimer @acsfd +@@ -1282,7 +1282,7 @@ user-provided buffer. + @safety{@prelim{}@mtunsafe{@mtasurace{:utent} @mtascusig{:ALRM} @mtascutimer{}}@asunsafe{@asulock{}}@acunsafe{@aculock{} @acsfd{}}} + @c getutent_r @mtasurace:utent @mtascusig:ALRM @mtascutimer @asulock @aculock @acsfd + @c libc_lock_lock dup @asulock @aculock +-@c *libc_utmp_jump_table->getutent_r @mtasurace:utent @mtascusig:ALRM @mtascutimer @acsfd ++@c __libc_getutent_r @mtasurace:utent @mtascusig:ALRM @mtascutimer @acsfd + @c getutent_r_unknown @mtasurace:utent @acsfd + @c setutent_unknown dup @mtasurace:utent @acsfd + @c getutent_r_file @mtasurace:utent @mtascusig:ALRM @mtascutimer +@@ -1319,7 +1319,7 @@ This function is a GNU extension. + @safety{@prelim{}@mtunsafe{@mtasurace{:utent} @mtascusig{:ALRM} @mtascutimer{}}@asunsafe{@asulock{}}@acunsafe{@aculock{} @acsfd{}}} + @c getutid_r @mtasurace:utent @mtascusig:ALRM @mtascutimer @asulock @aculock @acsfd + @c libc_lock_lock dup @asulock @aculock +-@c *libc_utmp_jump_table->getutid_r @mtasurace:utent @mtascusig:ALRM @mtascutimer @acsfd ++@c __libc_getutid_r @mtasurace:utent @mtascusig:ALRM @mtascutimer @acsfd + @c getutid_r_unknown @mtasurace:utent @acsfd + @c setutent_unknown dup @mtasurace:utent @acsfd + @c getutid_r_file @mtascusig:ALRM @mtascutimer +@@ -1349,7 +1349,7 @@ This function is a GNU extension. + @safety{@prelim{}@mtunsafe{@mtasurace{:utent} @mtascusig{:ALRM} @mtascutimer{}}@asunsafe{@asulock{}}@acunsafe{@aculock{} @acsfd{}}} + @c getutline_r @mtasurace:utent @mtascusig:ALRM @mtascutimer @asulock @aculock @acsfd + @c libc_lock_lock dup @asulock @aculock +-@c *libc_utmp_jump_table->getutline_r @mtasurace:utent @mtascusig:ALRM @mtascutimer @acsfd ++@c __libc_getutline_r @mtasurace:utent @mtascusig:ALRM @mtascutimer @acsfd + @c getutline_r_unknown @mtasurace:utent @acsfd + @c setutent_unknown dup @mtasurace:utent @acsfd + @c getutline_r_file @mtasurace:utent @mtascusig:ALRM @mtascutimer +@@ -1393,7 +1393,7 @@ be used. + @safety{@prelim{}@mtunsafe{@mtasurace{:utent}}@asunsafe{@asulock{} @ascuheap{}}@acunsafe{@aculock{} @acsmem{}}} + @c utmpname @mtasurace:utent @asulock @ascuheap @aculock @acsmem + @c libc_lock_lock dup @asulock @aculock +-@c *libc_utmp_jump_table->endutent dup @mtasurace:utent ++@c __libc_endutent dup @mtasurace:utent + @c strcmp dup ok + @c free dup @ascuheap @acsmem + @c strdup dup @ascuheap @acsmem +diff --git a/sysdeps/unix/getlogin_r.c b/sysdeps/unix/getlogin_r.c +index 444df7e4d3210cf6..180c0bbca13d0f87 100644 +--- a/sysdeps/unix/getlogin_r.c ++++ b/sysdeps/unix/getlogin_r.c +@@ -64,8 +64,8 @@ __getlogin_r (char *name, size_t name_len) + held so that our search is thread-safe. */ + + __libc_lock_lock (__libc_utmp_lock); +- (*__libc_utmp_jump_table->setutent) (); +- result = (*__libc_utmp_jump_table->getutline_r) (&line, &buffer, &ut); ++ __libc_setutent (); ++ result = __libc_getutline_r (&line, &buffer, &ut); + if (result < 0) + { + if (errno == ESRCH) +@@ -74,8 +74,7 @@ __getlogin_r (char *name, size_t name_len) + else + result = errno; + } +- (*__libc_utmp_jump_table->endutent) (); +- __libc_utmp_jump_table = &__libc_utmp_unknown_functions; ++ __libc_endutent (); + __libc_lock_unlock (__libc_utmp_lock); + + if (result == 0) diff --git a/SOURCES/glibc-rh1749439-10.patch b/SOURCES/glibc-rh1749439-10.patch new file mode 100644 index 0000000..92741c7 --- /dev/null +++ b/SOURCES/glibc-rh1749439-10.patch @@ -0,0 +1,389 @@ +commit be6b16d975683e6cca57852cd4cfe715b2a9d8b1 +Author: Florian Weimer +Date: Thu Nov 7 18:15:18 2019 +0100 + + login: Acquire write lock early in pututline [BZ #24882] + + It has been reported that due to lack of fairness in POSIX file + locking, the current reader-to-writer lock upgrade can result in + lack of forward progress. Acquiring the write lock directly + hopefully avoids this issue if there are only writers. + + This also fixes bug 24882 due to the cache revalidation in + __libc_pututline. + + Reviewed-by: Carlos O'Donell + Change-Id: I57e31ae30719e609a53505a0924dda101d46372e + +diff --git a/login/Makefile b/login/Makefile +index 82132c83fd799357..030cf489b2e037d4 100644 +--- a/login/Makefile ++++ b/login/Makefile +@@ -44,7 +44,7 @@ subdir-dirs = programs + vpath %.c programs + + tests := tst-utmp tst-utmpx tst-grantpt tst-ptsname tst-getlogin tst-updwtmpx \ +- tst-pututxline-lockfail ++ tst-pututxline-lockfail tst-pututxline-cache + + # Build the -lutil library with these extra functions. + extra-libs := libutil +@@ -74,3 +74,4 @@ $(inst_libexecdir)/pt_chown: $(objpfx)pt_chown $(+force) + -$(INSTALL_PROGRAM) -m 4755 -o root $< $@ + + $(objpfx)tst-pututxline-lockfail: $(shared-thread-library) ++$(objpfx)tst-pututxline-cache: $(shared-thread-library) +diff --git a/login/tst-pututxline-cache.c b/login/tst-pututxline-cache.c +new file mode 100644 +index 0000000000000000..3f30dd1776711769 +--- /dev/null ++++ b/login/tst-pututxline-cache.c +@@ -0,0 +1,193 @@ ++/* Test case for cache invalidation after concurrent write (bug 24882). ++ 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; see the file COPYING.LIB. If ++ not, see . */ ++ ++/* This test writes an entry to the utmpx file, reads it (so that it ++ is cached) in process1, and overwrites the same entry in process2 ++ with something that does not match the search criteria. At this ++ point, the cache of the first process is stale, and when process1 ++ attempts to write a new record which would have gone to the same ++ place (as indicated by the cache), it needs to realize that it has ++ to pick a different slot because the old slot is now used for ++ something else. */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* Set to the path of the utmp file. */ ++static char *utmp_file; ++ ++/* Used to synchronize the subprocesses. The barrier itself is ++ allocated in shared memory. */ ++static pthread_barrier_t *barrier; ++ ++/* setutxent with error checking. */ ++static void ++xsetutxent (void) ++{ ++ errno = 0; ++ setutxent (); ++ TEST_COMPARE (errno, 0); ++} ++ ++/* getutxent with error checking. */ ++static struct utmpx * ++xgetutxent (void) ++{ ++ errno = 0; ++ struct utmpx *result = getutxent (); ++ if (result == NULL) ++ FAIL_EXIT1 ("getutxent: %m"); ++ return result; ++} ++ ++static void ++put_entry (const char *id, pid_t pid, const char *user, const char *line) ++{ ++ struct utmpx ut = ++ { ++ .ut_type = LOGIN_PROCESS, ++ .ut_pid = pid, ++ .ut_host = "localhost", ++ }; ++ strcpy (ut.ut_id, id); ++ strncpy (ut.ut_user, user, sizeof (ut.ut_user)); ++ strncpy (ut.ut_line, line, sizeof (ut.ut_line)); ++ TEST_VERIFY (pututxline (&ut) != NULL); ++} ++ ++/* Use two cooperating subprocesses to avoid issues related to ++ unlock-on-close semantics of POSIX advisory locks. */ ++ ++static __attribute__ ((noreturn)) void ++process1 (void) ++{ ++ TEST_COMPARE (utmpname (utmp_file), 0); ++ ++ /* Create an entry. */ ++ xsetutxent (); ++ put_entry ("1", 101, "root", "process1"); ++ ++ /* Retrieve the entry. This will fill the internal cache. */ ++ { ++ errno = 0; ++ setutxent (); ++ TEST_COMPARE (errno, 0); ++ struct utmpx ut = ++ { ++ .ut_type = LOGIN_PROCESS, ++ .ut_line = "process1", ++ }; ++ struct utmpx *result = getutxline (&ut); ++ if (result == NULL) ++ FAIL_EXIT1 ("getutxline (\"process1\"): %m"); ++ TEST_COMPARE (result->ut_pid, 101); ++ } ++ ++ /* Signal the other process to overwrite the entry. */ ++ xpthread_barrier_wait (barrier); ++ ++ /* Wait for the other process to complete the write operation. */ ++ xpthread_barrier_wait (barrier); ++ ++ /* Add another entry. Note: This time, there is no setutxent call. */ ++ put_entry ("1", 103, "root", "process1"); ++ ++ _exit (0); ++} ++ ++static void ++process2 (void *closure) ++{ ++ /* Wait for the first process to write its entry. */ ++ xpthread_barrier_wait (barrier); ++ ++ /* Truncate the file. The glibc interface does not support ++ re-purposing records, but an external expiration mechanism may ++ trigger this. */ ++ TEST_COMPARE (truncate64 (utmp_file, 0), 0); ++ ++ /* Write the replacement entry. */ ++ TEST_COMPARE (utmpname (utmp_file), 0); ++ xsetutxent (); ++ put_entry ("2", 102, "user", "process2"); ++ ++ /* Signal the other process that the entry has been replaced. */ ++ xpthread_barrier_wait (barrier); ++} ++ ++static int ++do_test (void) ++{ ++ xclose (create_temp_file ("tst-tumpx-cache-write-", &utmp_file)); ++ { ++ pthread_barrierattr_t attr; ++ xpthread_barrierattr_init (&attr); ++ xpthread_barrierattr_setpshared (&attr, PTHREAD_SCOPE_PROCESS); ++ barrier = support_shared_allocate (sizeof (*barrier)); ++ xpthread_barrier_init (barrier, &attr, 2); ++ } ++ ++ /* Run both subprocesses in parallel. */ ++ { ++ pid_t pid1 = xfork (); ++ if (pid1 == 0) ++ process1 (); ++ support_isolate_in_subprocess (process2, NULL); ++ int status; ++ xwaitpid (pid1, &status, 0); ++ TEST_COMPARE (status, 0); ++ } ++ ++ /* Check that the utmpx database contains the expected records. */ ++ { ++ TEST_COMPARE (utmpname (utmp_file), 0); ++ xsetutxent (); ++ ++ struct utmpx *ut = xgetutxent (); ++ TEST_COMPARE_STRING (ut->ut_id, "2"); ++ TEST_COMPARE (ut->ut_pid, 102); ++ TEST_COMPARE_STRING (ut->ut_user, "user"); ++ TEST_COMPARE_STRING (ut->ut_line, "process2"); ++ ++ ut = xgetutxent (); ++ TEST_COMPARE_STRING (ut->ut_id, "1"); ++ TEST_COMPARE (ut->ut_pid, 103); ++ TEST_COMPARE_STRING (ut->ut_user, "root"); ++ TEST_COMPARE_STRING (ut->ut_line, "process1"); ++ ++ if (getutxent () != NULL) ++ FAIL_EXIT1 ("additional utmpx entry"); ++ } ++ ++ xpthread_barrier_destroy (barrier); ++ support_shared_free (barrier); ++ free (utmp_file); ++ ++ return 0; ++} ++ ++#include +diff --git a/login/utmp_file.c b/login/utmp_file.c +index 9ad80364682bae92..6bba120db9cc574e 100644 +--- a/login/utmp_file.c ++++ b/login/utmp_file.c +@@ -186,19 +186,11 @@ __libc_getutent_r (struct utmp *buffer, struct utmp **result) + + + /* Search for *ID, updating last_entry and file_offset. Return 0 on +- success and -1 on failure. If the locking operation failed, write +- true to *LOCK_FAILED. */ ++ success and -1 on failure. Does not perform locking; for that see ++ internal_getut_r below. */ + static int +-internal_getut_r (const struct utmp *id, bool *lock_failed) ++internal_getut_nolock (const struct utmp *id) + { +- int result = -1; +- +- if (try_file_lock (file_fd, F_RDLCK)) +- { +- *lock_failed = true; +- return -1; +- } +- + if (id->ut_type == RUN_LVL || id->ut_type == BOOT_TIME + || id->ut_type == OLD_TIME || id->ut_type == NEW_TIME) + { +@@ -213,7 +205,7 @@ internal_getut_r (const struct utmp *id, bool *lock_failed) + { + __set_errno (ESRCH); + file_offset = -1l; +- goto unlock_return; ++ return -1; + } + file_offset += sizeof (struct utmp); + +@@ -234,7 +226,7 @@ internal_getut_r (const struct utmp *id, bool *lock_failed) + { + __set_errno (ESRCH); + file_offset = -1l; +- goto unlock_return; ++ return -1; + } + file_offset += sizeof (struct utmp); + +@@ -243,15 +235,26 @@ internal_getut_r (const struct utmp *id, bool *lock_failed) + } + } + +- result = 0; ++ return 0; ++} + +-unlock_return: +- file_unlock (file_fd); ++/* Search for *ID, updating last_entry and file_offset. Return 0 on ++ success and -1 on failure. If the locking operation failed, write ++ true to *LOCK_FAILED. */ ++static int ++internal_getut_r (const struct utmp *id, bool *lock_failed) ++{ ++ if (try_file_lock (file_fd, F_RDLCK)) ++ { ++ *lock_failed = true; ++ return -1; ++ } + ++ int result = internal_getut_nolock (id); ++ file_unlock (file_fd); + return result; + } + +- + /* For implementing this function we don't use the getutent_r function + because we can avoid the reposition on every new entry this way. */ + int +@@ -279,7 +282,6 @@ __libc_getutid_r (const struct utmp *id, struct utmp *buffer, + return 0; + } + +- + /* For implementing this function we don't use the getutent_r function + because we can avoid the reposition on every new entry this way. */ + int +@@ -336,7 +338,6 @@ __libc_pututline (const struct utmp *data) + return NULL; + + struct utmp *pbuf; +- int found; + + if (! file_writable) + { +@@ -358,7 +359,12 @@ __libc_pututline (const struct utmp *data) + file_writable = true; + } + ++ /* Exclude other writers before validating the cache. */ ++ if (try_file_lock (file_fd, F_WRLCK)) ++ return NULL; ++ + /* Find the correct place to insert the data. */ ++ bool found = false; + if (file_offset > 0 + && ((last_entry.ut_type == data->ut_type + && (last_entry.ut_type == RUN_LVL +@@ -366,23 +372,30 @@ __libc_pututline (const struct utmp *data) + || last_entry.ut_type == OLD_TIME + || last_entry.ut_type == NEW_TIME)) + || __utmp_equal (&last_entry, data))) +- found = 1; +- else + { +- bool lock_failed = false; +- found = internal_getut_r (data, &lock_failed); +- +- if (__builtin_expect (lock_failed, false)) ++ if (__lseek64 (file_fd, file_offset, SEEK_SET) < 0) + { +- __set_errno (EAGAIN); ++ file_unlock (file_fd); + return NULL; + } ++ if (__read_nocancel (file_fd, &last_entry, sizeof (last_entry)) ++ != sizeof (last_entry)) ++ { ++ if (__lseek64 (file_fd, file_offset, SEEK_SET) < 0) ++ { ++ file_unlock (file_fd); ++ return NULL; ++ } ++ found = false; ++ } ++ else ++ found = __utmp_equal (&last_entry, data); + } + +- if (try_file_lock (file_fd, F_WRLCK)) +- return NULL; ++ if (!found) ++ found = internal_getut_nolock (data) >= 0; + +- if (found < 0) ++ if (!found) + { + /* We append the next entry. */ + file_offset = __lseek64 (file_fd, 0, SEEK_END); +@@ -411,7 +424,7 @@ __libc_pututline (const struct utmp *data) + { + /* If we appended a new record this is only partially written. + Remove it. */ +- if (found < 0) ++ if (!found) + (void) __ftruncate64 (file_fd, file_offset); + pbuf = NULL; + } diff --git a/SOURCES/glibc-rh1749439-11.patch b/SOURCES/glibc-rh1749439-11.patch new file mode 100644 index 0000000..d1289d6 --- /dev/null +++ b/SOURCES/glibc-rh1749439-11.patch @@ -0,0 +1,138 @@ +commit 76a7c103eb9060f9e3ba01d073ae4621a17d8b46 +Author: Florian Weimer +Date: Tue Nov 12 12:02:57 2019 +0100 + + login: Introduce matches_last_entry to utmp processing + + This simplifies internal_getut_nolock and fixes a regression, + introduced in commit be6b16d975683e6cca57852cd4cfe715b2a9d8b1 + ("login: Acquire write lock early in pututline [BZ #24882]") + in pututxline because __utmp_equal can only compare process-related + utmp entries. + + Fixes: be6b16d975683e6cca57852cd4cfe715b2a9d8b1 + Change-Id: Ib8a85002f7f87ee41590846d16d7e52bdb82f5a5 + +diff --git a/login/utmp_file.c b/login/utmp_file.c +index 6bba120db9cc574e..e653d14967c4fb7a 100644 +--- a/login/utmp_file.c ++++ b/login/utmp_file.c +@@ -43,6 +43,25 @@ static off64_t file_offset; + /* Cache for the last read entry. */ + static struct utmp last_entry; + ++/* Returns true if *ENTRY matches last_entry, based on ++ data->ut_type. */ ++static bool ++matches_last_entry (const struct utmp *data) ++{ ++ if (file_offset <= 0) ++ /* Nothing has been read. last_entry is stale and cannot match. */ ++ return false; ++ ++ if (data->ut_type == RUN_LVL ++ || data->ut_type == BOOT_TIME ++ || data->ut_type == OLD_TIME ++ || data->ut_type == NEW_TIME) ++ /* For some entry types, only a type match is required. */ ++ return data->ut_type == last_entry.ut_type; ++ else ++ /* For the process-related entries, a full match is needed. */ ++ return __utmp_equal (&last_entry, data); ++} + + /* Locking timeout. */ + #ifndef TIMEOUT +@@ -133,9 +152,6 @@ __libc_setutent (void) + __lseek64 (file_fd, 0, SEEK_SET); + file_offset = 0; + +- /* Make sure the entry won't match. */ +- last_entry.ut_type = -1; +- + return 1; + } + +@@ -191,48 +207,20 @@ __libc_getutent_r (struct utmp *buffer, struct utmp **result) + static int + internal_getut_nolock (const struct utmp *id) + { +- if (id->ut_type == RUN_LVL || id->ut_type == BOOT_TIME +- || id->ut_type == OLD_TIME || id->ut_type == NEW_TIME) ++ while (1) + { +- /* Search for next entry with type RUN_LVL, BOOT_TIME, +- OLD_TIME, or NEW_TIME. */ +- +- while (1) ++ /* Read the next entry. */ ++ if (__read_nocancel (file_fd, &last_entry, sizeof (struct utmp)) ++ != sizeof (struct utmp)) + { +- /* Read the next entry. */ +- if (__read_nocancel (file_fd, &last_entry, sizeof (struct utmp)) +- != sizeof (struct utmp)) +- { +- __set_errno (ESRCH); +- file_offset = -1l; +- return -1; +- } +- file_offset += sizeof (struct utmp); +- +- if (id->ut_type == last_entry.ut_type) +- break; ++ __set_errno (ESRCH); ++ file_offset = -1l; ++ return -1; + } +- } +- else +- { +- /* Search for the next entry with the specified ID and with type +- INIT_PROCESS, LOGIN_PROCESS, USER_PROCESS, or DEAD_PROCESS. */ +- +- while (1) +- { +- /* Read the next entry. */ +- if (__read_nocancel (file_fd, &last_entry, sizeof (struct utmp)) +- != sizeof (struct utmp)) +- { +- __set_errno (ESRCH); +- file_offset = -1l; +- return -1; +- } +- file_offset += sizeof (struct utmp); ++ file_offset += sizeof (struct utmp); + +- if (__utmp_equal (&last_entry, id)) +- break; +- } ++ if (matches_last_entry (id)) ++ break; + } + + return 0; +@@ -365,13 +353,7 @@ __libc_pututline (const struct utmp *data) + + /* Find the correct place to insert the data. */ + bool found = false; +- if (file_offset > 0 +- && ((last_entry.ut_type == data->ut_type +- && (last_entry.ut_type == RUN_LVL +- || last_entry.ut_type == BOOT_TIME +- || last_entry.ut_type == OLD_TIME +- || last_entry.ut_type == NEW_TIME)) +- || __utmp_equal (&last_entry, data))) ++ if (matches_last_entry (data)) + { + if (__lseek64 (file_fd, file_offset, SEEK_SET) < 0) + { +@@ -389,7 +371,7 @@ __libc_pututline (const struct utmp *data) + found = false; + } + else +- found = __utmp_equal (&last_entry, data); ++ found = matches_last_entry (data); + } + + if (!found) diff --git a/SOURCES/glibc-rh1749439-12.patch b/SOURCES/glibc-rh1749439-12.patch new file mode 100644 index 0000000..0308708 --- /dev/null +++ b/SOURCES/glibc-rh1749439-12.patch @@ -0,0 +1,114 @@ +commit fed33b0fb03d1942a6713286176d42869c0f1580 +Author: Leandro Pereira +Date: Wed Oct 2 12:42:28 2019 -0400 + + Add nocancel version of pread64() + + This is in preparation for changes in the dynamic linker so that + pread() is used instead of lseek()+read(). + + Reviewed-by: Carlos O'Donell + +Conflicts: + sysdeps/unix/sysv/linux/Makefile + (Textual conflict in routines list.) + +diff --git a/sysdeps/generic/not-cancel.h b/sysdeps/generic/not-cancel.h +index d9f8a75dbda85ed5..260e6e4081f5fe16 100644 +--- a/sysdeps/generic/not-cancel.h ++++ b/sysdeps/generic/not-cancel.h +@@ -41,6 +41,8 @@ + (void) __close (fd) + #define __read_nocancel(fd, buf, n) \ + __read (fd, buf, n) ++#define __pread64_nocancel(fd, buf, count, offset) \ ++ __pread64 (fd, buf, count, offset) + #define __write_nocancel(fd, buf, n) \ + __write (fd, buf, n) + #define __writev_nocancel_nostatus(fd, iov, n) \ +diff --git a/sysdeps/unix/sysv/linux/Makefile b/sysdeps/unix/sysv/linux/Makefile +index 773aaea0e980bdd6..fb4ccd63ddec7eca 100644 +--- a/sysdeps/unix/sysv/linux/Makefile ++++ b/sysdeps/unix/sysv/linux/Makefile +@@ -174,7 +174,8 @@ sysdep_routines += xstatconv internal_statvfs internal_statvfs64 \ + close_nocancel fcntl_nocancel nanosleep_nocancel \ + open_nocancel open64_nocancel \ + openat_nocancel openat64_nocancel \ +- pause_nocancel read_nocancel waitpid_nocancel write_nocancel ++ pause_nocancel read_nocancel pread64_nocancel \ ++ waitpid_nocancel write_nocancel + + sysdep_headers += bits/fcntl-linux.h + +diff --git a/sysdeps/unix/sysv/linux/Versions b/sysdeps/unix/sysv/linux/Versions +index 336c13b57dba727a..95759bead1b0b3ca 100644 +--- a/sysdeps/unix/sysv/linux/Versions ++++ b/sysdeps/unix/sysv/linux/Versions +@@ -176,6 +176,7 @@ libc { + __syscall_rt_sigqueueinfo; + __open_nocancel; + __read_nocancel; ++ __pread64_nocancel; + __close_nocancel; + __sigtimedwait; + # functions used by nscd +diff --git a/sysdeps/unix/sysv/linux/not-cancel.h b/sysdeps/unix/sysv/linux/not-cancel.h +index 09de92dee9437d98..e58db475682a8c6a 100644 +--- a/sysdeps/unix/sysv/linux/not-cancel.h ++++ b/sysdeps/unix/sysv/linux/not-cancel.h +@@ -43,6 +43,9 @@ __typeof (openat64) __openat64_nocancel; + /* Non cancellable read syscall. */ + __typeof (__read) __read_nocancel; + ++/* Non cancellable pread syscall (LFS version). */ ++__typeof (__pread64) __pread64_nocancel; ++ + /* Uncancelable write. */ + __typeof (__write) __write_nocancel; + +@@ -84,6 +87,7 @@ hidden_proto (__open64_nocancel) + hidden_proto (__openat_nocancel) + hidden_proto (__openat64_nocancel) + hidden_proto (__read_nocancel) ++hidden_proto (__pread64_nocancel) + hidden_proto (__write_nocancel) + hidden_proto (__close_nocancel) + hidden_proto (__waitpid_nocancel) +diff --git a/sysdeps/unix/sysv/linux/pread64_nocancel.c b/sysdeps/unix/sysv/linux/pread64_nocancel.c +new file mode 100644 +index 0000000000000000..dab61260e5db43b5 +--- /dev/null ++++ b/sysdeps/unix/sysv/linux/pread64_nocancel.c +@@ -0,0 +1,32 @@ ++/* Linux pread64() syscall implementation -- non-cancellable. ++ 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, see ++ . */ ++ ++#include ++#include ++#include ++ ++#ifndef __NR_pread64 ++# define __NR_pread64 __NR_pread ++#endif ++ ++ssize_t ++__pread64_nocancel (int fd, void *buf, size_t count, off64_t offset) ++{ ++ return INLINE_SYSCALL_CALL (pread64, fd, buf, count, SYSCALL_LL64_PRW (offset)); ++} ++hidden_def (__pread64_nocancel) diff --git a/SOURCES/glibc-rh1749439-13.patch b/SOURCES/glibc-rh1749439-13.patch new file mode 100644 index 0000000..333f1f6 --- /dev/null +++ b/SOURCES/glibc-rh1749439-13.patch @@ -0,0 +1,307 @@ +commit d4625a19fe64f664119a541b317fb83de01bb273 +Author: Florian Weimer +Date: Tue Nov 12 12:25:49 2019 +0100 + + login: Use pread64 in utmp implementation + + This reduces the possible error scenarios considerably because + no longer can file seek fail, leaving the file descriptor in an + inconsistent state and out of sync with the cache. + + As a result, it is possible to avoid setting file_offset to -1 + to make an error persistent. Instead, subsequent calls will retry + the operation and report any errors returned by the kernel. + + This change also avoids reading the file from the start if pututline + is called multiple times, to work around lock acquisition failures + due to timeouts. + + Change-Id: If21ea0c162c38830a89331ea93cddec14c0974de + +diff --git a/login/utmp_file.c b/login/utmp_file.c +index e653d14967c4fb7a..c828a28ac54c150e 100644 +--- a/login/utmp_file.c ++++ b/login/utmp_file.c +@@ -162,12 +162,35 @@ maybe_setutent (void) + return file_fd >= 0 || __libc_setutent (); + } + ++/* Reads the entry at file_offset, storing it in last_entry and ++ updating file_offset on success. Returns -1 for a read error, 0 ++ for EOF, and 1 for a successful read. last_entry and file_offset ++ are only updated on a successful and complete read. */ ++static ssize_t ++read_last_entry (void) ++{ ++ struct utmp buffer; ++ ssize_t nbytes = __pread64_nocancel (file_fd, &buffer, sizeof (buffer), ++ file_offset); ++ if (nbytes < 0) ++ return -1; ++ else if (nbytes != sizeof (buffer)) ++ /* Assume EOF. */ ++ return 0; ++ else ++ { ++ last_entry = buffer; ++ file_offset += sizeof (buffer); ++ return 1; ++ } ++} ++ + int + __libc_getutent_r (struct utmp *buffer, struct utmp **result) + { +- ssize_t nbytes; ++ int saved_errno = errno; + +- if (!maybe_setutent () || file_offset == -1l) ++ if (!maybe_setutent ()) + { + /* Not available. */ + *result = NULL; +@@ -175,25 +198,22 @@ __libc_getutent_r (struct utmp *buffer, struct utmp **result) + } + + if (try_file_lock (file_fd, F_RDLCK)) +- nbytes = 0; +- else +- { +- /* Read the next entry. */ +- nbytes = __read_nocancel (file_fd, &last_entry, sizeof (struct utmp)); +- file_unlock (file_fd); +- } ++ return -1; + +- if (nbytes != sizeof (struct utmp)) ++ ssize_t nbytes = read_last_entry (); ++ file_unlock (file_fd); ++ ++ if (nbytes <= 0) /* Read error or EOF. */ + { +- if (nbytes != 0) +- file_offset = -1l; ++ if (nbytes == 0) ++ /* errno should be unchanged to indicate success. A premature ++ EOF is treated like an EOF (missing complete record at the ++ end). */ ++ __set_errno (saved_errno); + *result = NULL; + return -1; + } + +- /* Update position pointer. */ +- file_offset += sizeof (struct utmp); +- + memcpy (buffer, &last_entry, sizeof (struct utmp)); + *result = buffer; + +@@ -209,15 +229,15 @@ internal_getut_nolock (const struct utmp *id) + { + while (1) + { +- /* Read the next entry. */ +- if (__read_nocancel (file_fd, &last_entry, sizeof (struct utmp)) +- != sizeof (struct utmp)) ++ ssize_t nbytes = read_last_entry (); ++ if (nbytes < 0) ++ return -1; ++ if (nbytes == 0) + { ++ /* End of file reached. */ + __set_errno (ESRCH); +- file_offset = -1l; + return -1; + } +- file_offset += sizeof (struct utmp); + + if (matches_last_entry (id)) + break; +@@ -249,7 +269,7 @@ int + __libc_getutid_r (const struct utmp *id, struct utmp *buffer, + struct utmp **result) + { +- if (!maybe_setutent () || file_offset == -1l) ++ if (!maybe_setutent ()) + { + *result = NULL; + return -1; +@@ -276,7 +296,7 @@ int + __libc_getutline_r (const struct utmp *line, struct utmp *buffer, + struct utmp **result) + { +- if (!maybe_setutent () || file_offset == -1l) ++ if (!maybe_setutent ()) + { + *result = NULL; + return -1; +@@ -290,16 +310,21 @@ __libc_getutline_r (const struct utmp *line, struct utmp *buffer, + + while (1) + { +- /* Read the next entry. */ +- if (__read_nocancel (file_fd, &last_entry, sizeof (struct utmp)) +- != sizeof (struct utmp)) ++ ssize_t nbytes = read_last_entry (); ++ if (nbytes < 0) + { ++ file_unlock (file_fd); ++ *result = NULL; ++ return -1; ++ } ++ if (nbytes == 0) ++ { ++ /* End of file reached. */ ++ file_unlock (file_fd); + __set_errno (ESRCH); +- file_offset = -1l; + *result = NULL; +- goto unlock_return; ++ return -1; + } +- file_offset += sizeof (struct utmp); + + /* Stop if we found a user or login entry. */ + if ((last_entry.ut_type == USER_PROCESS +@@ -309,20 +334,18 @@ __libc_getutline_r (const struct utmp *line, struct utmp *buffer, + break; + } + ++ file_unlock (file_fd); + memcpy (buffer, &last_entry, sizeof (struct utmp)); + *result = buffer; + +-unlock_return: +- file_unlock (file_fd); +- +- return ((*result == NULL) ? -1 : 0); ++ return 0; + } + + + struct utmp * + __libc_pututline (const struct utmp *data) + { +- if (!maybe_setutent () || file_offset == -1l) ++ if (!maybe_setutent ()) + return NULL; + + struct utmp *pbuf; +@@ -337,8 +360,7 @@ __libc_pututline (const struct utmp *data) + if (new_fd == -1) + return NULL; + +- if (__lseek64 (new_fd, __lseek64 (file_fd, 0, SEEK_CUR), SEEK_SET) == -1 +- || __dup2 (new_fd, file_fd) < 0) ++ if (__dup2 (new_fd, file_fd) < 0) + { + __close_nocancel_nostatus (new_fd); + return NULL; +@@ -355,69 +377,70 @@ __libc_pututline (const struct utmp *data) + bool found = false; + if (matches_last_entry (data)) + { +- if (__lseek64 (file_fd, file_offset, SEEK_SET) < 0) ++ /* Read back the entry under the write lock. */ ++ file_offset -= sizeof (last_entry); ++ ssize_t nbytes = read_last_entry (); ++ if (nbytes < 0) + { + file_unlock (file_fd); + return NULL; + } +- if (__read_nocancel (file_fd, &last_entry, sizeof (last_entry)) +- != sizeof (last_entry)) +- { +- if (__lseek64 (file_fd, file_offset, SEEK_SET) < 0) +- { +- file_unlock (file_fd); +- return NULL; +- } +- found = false; +- } ++ ++ if (nbytes == 0) ++ /* End of file reached. */ ++ found = false; + else + found = matches_last_entry (data); + } + + if (!found) ++ /* Search forward for the entry. */ + found = internal_getut_nolock (data) >= 0; + ++ off64_t write_offset; + if (!found) + { + /* We append the next entry. */ +- file_offset = __lseek64 (file_fd, 0, SEEK_END); +- if (file_offset % sizeof (struct utmp) != 0) +- { +- file_offset -= file_offset % sizeof (struct utmp); +- __ftruncate64 (file_fd, file_offset); +- +- if (__lseek64 (file_fd, 0, SEEK_END) < 0) +- { +- pbuf = NULL; +- goto unlock_return; +- } +- } ++ write_offset = __lseek64 (file_fd, 0, SEEK_END); ++ ++ /* Round down to the next multiple of the entry size. This ++ ensures any partially-written record is overwritten by the ++ new record. */ ++ write_offset = (write_offset / sizeof (struct utmp) ++ * sizeof (struct utmp)); + } + else ++ /* Overwrite last_entry. */ ++ write_offset = file_offset - sizeof (struct utmp); ++ ++ /* Write the new data. */ ++ ssize_t nbytes; ++ if (__lseek64 (file_fd, write_offset, SEEK_SET) < 0 ++ || (nbytes = __write_nocancel (file_fd, data, sizeof (struct utmp))) < 0) + { +- /* We replace the just read entry. */ +- file_offset -= sizeof (struct utmp); +- __lseek64 (file_fd, file_offset, SEEK_SET); ++ /* There is no need to recover the file position because all ++ reads use pread64, and any future write is preceded by ++ another seek. */ ++ file_unlock (file_fd); ++ return NULL; + } + +- /* Write the new data. */ +- if (__write_nocancel (file_fd, data, sizeof (struct utmp)) +- != sizeof (struct utmp)) ++ if (nbytes != sizeof (struct utmp)) + { + /* If we appended a new record this is only partially written. + Remove it. */ + if (!found) +- (void) __ftruncate64 (file_fd, file_offset); +- pbuf = NULL; +- } +- else +- { +- file_offset += sizeof (struct utmp); +- pbuf = (struct utmp *) data; ++ (void) __ftruncate64 (file_fd, write_offset); ++ file_unlock (file_fd); ++ /* Assume that the write failure was due to missing disk ++ space. */ ++ __set_errno (ENOSPC); ++ return NULL; + } + +- unlock_return: + file_unlock (file_fd); ++ file_offset = write_offset + sizeof (struct utmp); ++ pbuf = (struct utmp *) data; + + return pbuf; + } diff --git a/SOURCES/glibc-rh1749439-2.patch b/SOURCES/glibc-rh1749439-2.patch new file mode 100644 index 0000000..f00334c --- /dev/null +++ b/SOURCES/glibc-rh1749439-2.patch @@ -0,0 +1,676 @@ +commit a33b817f13170b5c24263b92e7e09880fe797d7e +Author: Florian Weimer +Date: Tue Aug 13 12:09:32 2019 +0200 + + login: Assume that _HAVE_UT_* constants are true + + Make the GNU version of bits/utmp.h the generic version because + all remaining ports use it (with a sysdeps override for + Linux s390/s390x). + +Conflicts: + bits/utmp.h + sysdeps/gnu/bits/utmp.h + (Upstream copyright year change.) + +diff --git a/bits/utmp.h b/bits/utmp.h +index 6e8695fbf072e5f1..3c02dd4f3fe4e99b 100644 +--- a/bits/utmp.h ++++ b/bits/utmp.h +@@ -1,5 +1,5 @@ +-/* The `struct utmp' type, describing entries in the utmp file. Generic/BSDish +- Copyright (C) 1993-2018 Free Software Foundation, Inc. ++/* The `struct utmp' type, describing entries in the utmp file. ++ Copyright (C) 1993-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 +@@ -21,29 +21,106 @@ + #endif + + #include +-#include ++#include ++#include ++#include + + +-#define UT_NAMESIZE 8 +-#define UT_LINESIZE 8 +-#define UT_HOSTSIZE 16 ++#define UT_LINESIZE 32 ++#define UT_NAMESIZE 32 ++#define UT_HOSTSIZE 256 + + ++/* The structure describing an entry in the database of ++ previous logins. */ + struct lastlog + { +- time_t ll_time; ++#if __WORDSIZE_TIME64_COMPAT32 ++ int32_t ll_time; ++#else ++ __time_t ll_time; ++#endif + char ll_line[UT_LINESIZE]; + char ll_host[UT_HOSTSIZE]; + }; + +-struct utmp ++ ++/* The structure describing the status of a terminated process. This ++ type is used in `struct utmp' below. */ ++struct exit_status + { +- char ut_line[UT_LINESIZE]; +- char ut_user[UT_NAMESIZE]; +-#define ut_name ut_user +- char ut_host[UT_HOSTSIZE]; +- long int ut_time; ++ short int e_termination; /* Process termination status. */ ++ short int e_exit; /* Process exit status. */ + }; + + +-#define _HAVE_UT_HOST 1 /* We have the ut_host field. */ ++/* The structure describing an entry in the user accounting database. */ ++struct utmp ++{ ++ short int ut_type; /* Type of login. */ ++ pid_t ut_pid; /* Process ID of login process. */ ++ char ut_line[UT_LINESIZE] ++ __attribute_nonstring__; /* Devicename. */ ++ char ut_id[4]; /* Inittab ID. */ ++ char ut_user[UT_NAMESIZE] ++ __attribute_nonstring__; /* Username. */ ++ char ut_host[UT_HOSTSIZE] ++ __attribute_nonstring__; /* Hostname for remote login. */ ++ struct exit_status ut_exit; /* Exit status of a process marked ++ as DEAD_PROCESS. */ ++/* The ut_session and ut_tv fields must be the same size when compiled ++ 32- and 64-bit. This allows data files and shared memory to be ++ shared between 32- and 64-bit applications. */ ++#if __WORDSIZE_TIME64_COMPAT32 ++ int32_t ut_session; /* Session ID, used for windowing. */ ++ struct ++ { ++ int32_t tv_sec; /* Seconds. */ ++ int32_t tv_usec; /* Microseconds. */ ++ } ut_tv; /* Time entry was made. */ ++#else ++ long int ut_session; /* Session ID, used for windowing. */ ++ struct timeval ut_tv; /* Time entry was made. */ ++#endif ++ ++ int32_t ut_addr_v6[4]; /* Internet address of remote host. */ ++ char __glibc_reserved[20]; /* Reserved for future use. */ ++}; ++ ++/* Backwards compatibility hacks. */ ++#define ut_name ut_user ++#ifndef _NO_UT_TIME ++/* We have a problem here: `ut_time' is also used otherwise. Define ++ _NO_UT_TIME if the compiler complains. */ ++# define ut_time ut_tv.tv_sec ++#endif ++#define ut_xtime ut_tv.tv_sec ++#define ut_addr ut_addr_v6[0] ++ ++ ++/* Values for the `ut_type' field of a `struct utmp'. */ ++#define EMPTY 0 /* No valid user accounting information. */ ++ ++#define RUN_LVL 1 /* The system's runlevel. */ ++#define BOOT_TIME 2 /* Time of system boot. */ ++#define NEW_TIME 3 /* Time after system clock changed. */ ++#define OLD_TIME 4 /* Time when system clock changed. */ ++ ++#define INIT_PROCESS 5 /* Process spawned by the init process. */ ++#define LOGIN_PROCESS 6 /* Session leader of a logged in user. */ ++#define USER_PROCESS 7 /* Normal process. */ ++#define DEAD_PROCESS 8 /* Terminated process. */ ++ ++#define ACCOUNTING 9 ++ ++/* Old Linux name for the EMPTY type. */ ++#define UT_UNKNOWN EMPTY ++ ++ ++/* Tell the user that we have a modern system with UT_HOST, UT_PID, ++ UT_TYPE, UT_ID and UT_TV fields. */ ++#define _HAVE_UT_TYPE 1 ++#define _HAVE_UT_PID 1 ++#define _HAVE_UT_ID 1 ++#define _HAVE_UT_TV 1 ++#define _HAVE_UT_HOST 1 +diff --git a/login/getutid_r.c b/login/getutid_r.c +index 8cb6b16d735e8265..11b288e99be6ee50 100644 +--- a/login/getutid_r.c ++++ b/login/getutid_r.c +@@ -32,7 +32,6 @@ __libc_lock_define (extern, __libc_utmp_lock attribute_hidden) + int + __getutid_r (const struct utmp *id, struct utmp *buffer, struct utmp **result) + { +-#if (_HAVE_UT_ID - 0) && (_HAVE_UT_TYPE - 0) + int retval; + + /* Test whether ID has any of the legal types. */ +@@ -54,10 +53,6 @@ __getutid_r (const struct utmp *id, struct utmp *buffer, struct utmp **result) + __libc_lock_unlock (__libc_utmp_lock); + + return retval; +-#else /* !_HAVE_UT_ID && !_HAVE_UT_TYPE */ +- __set_errno (ENOSYS); +- return -1; +-#endif + } + libc_hidden_def (__getutid_r) + weak_alias (__getutid_r, getutid_r) +diff --git a/login/getutmp.c b/login/getutmp.c +index 481150d5ef5a0bf0..32468ecae699fbf7 100644 +--- a/login/getutmp.c ++++ b/login/getutmp.c +@@ -23,23 +23,11 @@ + void + getutmp (const struct utmpx *utmpx, struct utmp *utmp) + { +-#if _HAVE_UT_TYPE - 0 + utmp->ut_type = utmpx->ut_type; +-#endif +-#if _HAVE_UT_PID - 0 + utmp->ut_pid = utmpx->ut_pid; +-#endif + memcpy (utmp->ut_line, utmpx->ut_line, sizeof (utmp->ut_line)); + memcpy (utmp->ut_user, utmpx->ut_user, sizeof (utmp->ut_user)); +-#if _HAVE_UT_ID - 0 + memcpy (utmp->ut_id, utmpx->ut_id, sizeof (utmp->ut_id)); +-#endif +-#if _HAVE_UT_HOST - 0 + memcpy (utmp->ut_host, utmpx->ut_host, sizeof (utmp->ut_host)); +-#endif +-#if _HAVE_UT_TV - 0 + utmp->ut_tv = utmpx->ut_tv; +-#else +- utmp->ut_time = utmpx->ut_time; +-#endif + } +diff --git a/login/getutmpx.c b/login/getutmpx.c +index 34145fe8db71faf0..92a182698e2be438 100644 +--- a/login/getutmpx.c ++++ b/login/getutmpx.c +@@ -24,24 +24,11 @@ void + getutmpx (const struct utmp *utmp, struct utmpx *utmpx) + { + memset (utmpx, 0, sizeof (struct utmpx)); +- +-#if _HAVE_UT_TYPE - 0 + utmpx->ut_type = utmp->ut_type; +-#endif +-#if _HAVE_UT_PID - 0 + utmpx->ut_pid = utmp->ut_pid; +-#endif + memcpy (utmpx->ut_line, utmp->ut_line, sizeof (utmp->ut_line)); + memcpy (utmpx->ut_user, utmp->ut_user, sizeof (utmp->ut_user)); +-#if _HAVE_UT_ID - 0 + memcpy (utmpx->ut_id, utmp->ut_id, sizeof (utmp->ut_id)); +-#endif +-#if _HAVE_UT_HOST - 0 + memcpy (utmpx->ut_host, utmp->ut_host, sizeof (utmp->ut_host)); +-#endif +-#if _HAVE_UT_TV - 0 + utmpx->ut_tv = utmp->ut_tv; +-#else +- utmpx->ut_time = utmp->ut_time; +-#endif + } +diff --git a/login/login.c b/login/login.c +index 5d48cd487f237ca0..1729fc070fcc1e4b 100644 +--- a/login/login.c ++++ b/login/login.c +@@ -91,12 +91,8 @@ login (const struct utmp *ut) + struct utmp copy = *ut; + + /* Fill in those fields we supply. */ +-#if _HAVE_UT_TYPE - 0 + copy.ut_type = USER_PROCESS; +-#endif +-#if _HAVE_UT_PID - 0 + copy.ut_pid = getpid (); +-#endif + + /* Seek tty. */ + found_tty = tty_name (STDIN_FILENO, &tty, sizeof (_tty)); +diff --git a/login/logout.c b/login/logout.c +index d49bc4ecac9a8379..4d76ecf1b40d306a 100644 +--- a/login/logout.c ++++ b/login/logout.c +@@ -36,9 +36,7 @@ logout (const char *line) + setutent (); + + /* Fill in search information. */ +-#if _HAVE_UT_TYPE - 0 + tmp.ut_type = USER_PROCESS; +-#endif + strncpy (tmp.ut_line, line, sizeof tmp.ut_line); + + /* Read the record. */ +@@ -46,20 +44,12 @@ logout (const char *line) + { + /* Clear information about who & from where. */ + memset (ut->ut_name, '\0', sizeof ut->ut_name); +-#if _HAVE_UT_HOST - 0 + memset (ut->ut_host, '\0', sizeof ut->ut_host); +-#endif +-#if _HAVE_UT_TV - 0 + struct timeval tv; + __gettimeofday (&tv, NULL); + ut->ut_tv.tv_sec = tv.tv_sec; + ut->ut_tv.tv_usec = tv.tv_usec; +-#else +- ut->ut_time = time (NULL); +-#endif +-#if _HAVE_UT_TYPE - 0 + ut->ut_type = DEAD_PROCESS; +-#endif + + if (pututline (ut) != NULL) + result = 1; +diff --git a/login/logwtmp.c b/login/logwtmp.c +index a19da4ab5ef7a624..e0b52b23e3603b7c 100644 +--- a/login/logwtmp.c ++++ b/login/logwtmp.c +@@ -30,26 +30,16 @@ logwtmp (const char *line, const char *name, const char *host) + + /* Set information in new entry. */ + memset (&ut, 0, sizeof (ut)); +-#if _HAVE_UT_PID - 0 + ut.ut_pid = getpid (); +-#endif +-#if _HAVE_UT_TYPE - 0 + ut.ut_type = name[0] ? USER_PROCESS : DEAD_PROCESS; +-#endif + strncpy (ut.ut_line, line, sizeof ut.ut_line); + strncpy (ut.ut_name, name, sizeof ut.ut_name); +-#if _HAVE_UT_HOST - 0 + strncpy (ut.ut_host, host, sizeof ut.ut_host); +-#endif + +-#if _HAVE_UT_TV - 0 + struct timeval tv; + __gettimeofday (&tv, NULL); + ut.ut_tv.tv_sec = tv.tv_sec; + ut.ut_tv.tv_usec = tv.tv_usec; +-#else +- ut.ut_time = time (NULL); +-#endif + + updwtmp (_PATH_WTMP, &ut); + } +diff --git a/login/programs/utmpdump.c b/login/programs/utmpdump.c +index dccdb669f5fb9c74..1763e55af2f03d8d 100644 +--- a/login/programs/utmpdump.c ++++ b/login/programs/utmpdump.c +@@ -37,47 +37,11 @@ print_entry (struct utmp *up) + temp_tv.tv_sec = up->ut_tv.tv_sec; + temp_tv.tv_usec = up->ut_tv.tv_usec; + +- (printf) ( +- /* The format string. */ +-#if _HAVE_UT_TYPE +- "[%d] " +-#endif +-#if _HAVE_UT_PID +- "[%05d] " +-#endif +-#if _HAVE_UT_ID +- "[%-4.4s] " +-#endif +- "[%-8.8s] [%-12.12s]" +-#if _HAVE_UT_HOST +- " [%-16.16s]" +-#endif +- " [%-15.15s]" +-#if _HAVE_UT_TV +- " [%ld]" +-#endif +- "\n" +- /* The arguments. */ +-#if _HAVE_UT_TYPE +- , up->ut_type +-#endif +-#if _HAVE_UT_PID +- , up->ut_pid +-#endif +-#if _HAVE_UT_ID +- , up->ut_id +-#endif +- , up->ut_user, up->ut_line +-#if _HAVE_UT_HOST +- , up->ut_host +-#endif +-#if _HAVE_UT_TV +- , 4 + ctime (&temp_tv.tv_sec) +- , (long int) temp_tv.tv_usec +-#else +- , 4 + ctime (&up->ut_time) +-#endif +- ); ++ printf ("[%d] [%05d] [%-4.4s] [%-8.8s] [%-12.12s] [%-16.16s] [%-15.15s]" ++ " [%ld]\n", ++ up->ut_type, up->ut_pid, up->ut_id, up->ut_user, up->ut_line, ++ up->ut_host, 4 + ctime (&temp_tv.tv_sec), ++ (long int) temp_tv.tv_usec); + } + + int +diff --git a/login/tst-utmp.c b/login/tst-utmp.c +index 8cc7aafa89c0ea8c..49b0cbda2a719643 100644 +--- a/login/tst-utmp.c ++++ b/login/tst-utmp.c +@@ -39,8 +39,6 @@ + #endif + + +-#if defined UTMPX || _HAVE_UT_TYPE +- + /* Prototype for our test function. */ + static int do_test (int argc, char *argv[]); + +@@ -75,11 +73,7 @@ do_prepare (int argc, char *argv[]) + + struct utmp entry[] = + { +-#if defined UTMPX || _HAVE_UT_TV + #define UT(a) .ut_tv = { .tv_sec = (a)} +-#else +-#define UT(a) .ut_time = (a) +-#endif + + { .ut_type = BOOT_TIME, .ut_pid = 1, UT(1000) }, + { .ut_type = RUN_LVL, .ut_pid = 1, UT(2000) }, +@@ -167,11 +161,7 @@ simulate_login (const char *line, const char *user) + entry[n].ut_pid = (entry_pid += 27); + entry[n].ut_type = USER_PROCESS; + strncpy (entry[n].ut_user, user, sizeof (entry[n].ut_user)); +-#if defined UTMPX || _HAVE_UT_TV - 0 + entry[n].ut_tv.tv_sec = (entry_time += 1000); +-#else +- entry[n].ut_time = (entry_time += 1000); +-#endif + setutent (); + + if (pututline (&entry[n]) == NULL) +@@ -201,11 +191,7 @@ simulate_logout (const char *line) + { + entry[n].ut_type = DEAD_PROCESS; + strncpy (entry[n].ut_user, "", sizeof (entry[n].ut_user)); +-#if defined UTMPX || _HAVE_UT_TV - 0 + entry[n].ut_tv.tv_sec = (entry_time += 1000); +-#else +- entry[n].ut_time = (entry_time += 1000); +-#endif + setutent (); + + if (pututline (&entry[n]) == NULL) +@@ -390,14 +376,3 @@ do_test (int argc, char *argv[]) + + return result; + } +- +-#else +- +-/* No field 'ut_type' in struct utmp. */ +-int +-main (void) +-{ +- return 0; +-} +- +-#endif +diff --git a/login/utmp_file.c b/login/utmp_file.c +index 069e6d0452e333ad..da1baa6948d0eb39 100644 +--- a/login/utmp_file.c ++++ b/login/utmp_file.c +@@ -129,14 +129,7 @@ __libc_setutent (void) + file_offset = 0; + + /* Make sure the entry won't match. */ +-#if _HAVE_UT_TYPE - 0 + last_entry.ut_type = -1; +-#else +- last_entry.ut_line[0] = '\177'; +-# if _HAVE_UT_ID - 0 +- last_entry.ut_id[0] = '\0'; +-# endif +-#endif + + return 1; + } +@@ -201,7 +194,6 @@ internal_getut_r (const struct utmp *id, struct utmp *buffer, + LOCKING_FAILED (); + } + +-#if _HAVE_UT_TYPE - 0 + if (id->ut_type == RUN_LVL || id->ut_type == BOOT_TIME + || id->ut_type == OLD_TIME || id->ut_type == NEW_TIME) + { +@@ -225,7 +217,6 @@ internal_getut_r (const struct utmp *id, struct utmp *buffer, + } + } + else +-#endif /* _HAVE_UT_TYPE */ + { + /* Search for the next entry with the specified ID and with type + INIT_PROCESS, LOGIN_PROCESS, USER_PROCESS, or DEAD_PROCESS. */ +@@ -316,13 +307,10 @@ __libc_getutline_r (const struct utmp *line, struct utmp *buffer, + file_offset += sizeof (struct utmp); + + /* Stop if we found a user or login entry. */ +- if ( +-#if _HAVE_UT_TYPE - 0 +- (last_entry.ut_type == USER_PROCESS ++ if ((last_entry.ut_type == USER_PROCESS + || last_entry.ut_type == LOGIN_PROCESS) +- && +-#endif +- !strncmp (line->ut_line, last_entry.ut_line, sizeof line->ut_line)) ++ && (strncmp (line->ut_line, last_entry.ut_line, sizeof line->ut_line) ++ == 0)) + break; + } + +@@ -368,16 +356,12 @@ __libc_pututline (const struct utmp *data) + + /* Find the correct place to insert the data. */ + if (file_offset > 0 +- && ( +-#if _HAVE_UT_TYPE - 0 +- (last_entry.ut_type == data->ut_type ++ && ((last_entry.ut_type == data->ut_type + && (last_entry.ut_type == RUN_LVL + || last_entry.ut_type == BOOT_TIME + || last_entry.ut_type == OLD_TIME + || last_entry.ut_type == NEW_TIME)) +- || +-#endif +- __utmp_equal (&last_entry, data))) ++ || __utmp_equal (&last_entry, data))) + found = 1; + else + { +diff --git a/sysdeps/generic/utmp-equal.h b/sysdeps/generic/utmp-equal.h +index 8b5c2e2cd2c4cf95..39993af192ab66ce 100644 +--- a/sysdeps/generic/utmp-equal.h ++++ b/sysdeps/generic/utmp-equal.h +@@ -27,26 +27,16 @@ + static int + __utmp_equal (const struct utmp *entry, const struct utmp *match) + { +- return +- ( +-#if _HAVE_UT_TYPE - 0 +- (entry->ut_type == INIT_PROCESS +- || entry->ut_type == LOGIN_PROCESS +- || entry->ut_type == USER_PROCESS +- || entry->ut_type == DEAD_PROCESS) +- && +- (match->ut_type == INIT_PROCESS +- || match->ut_type == LOGIN_PROCESS +- || match->ut_type == USER_PROCESS +- || match->ut_type == DEAD_PROCESS) +- && +-#endif +-#if _HAVE_UT_ID - 0 +- (entry->ut_id[0] && match->ut_id[0] +- ? strncmp (entry->ut_id, match->ut_id, sizeof match->ut_id) == 0 +- : strncmp (entry->ut_line, match->ut_line, sizeof match->ut_line) == 0) +-#else +- strncmp (entry->ut_line, match->ut_line, sizeof match->ut_line) == 0 +-#endif +- ); ++ return (entry->ut_type == INIT_PROCESS ++ || entry->ut_type == LOGIN_PROCESS ++ || entry->ut_type == USER_PROCESS ++ || entry->ut_type == DEAD_PROCESS) ++ && (match->ut_type == INIT_PROCESS ++ || match->ut_type == LOGIN_PROCESS ++ || match->ut_type == USER_PROCESS ++ || match->ut_type == DEAD_PROCESS) ++ && (entry->ut_id[0] && match->ut_id[0] ++ ? strncmp (entry->ut_id, match->ut_id, sizeof match->ut_id) == 0 ++ : (strncmp (entry->ut_line, match->ut_line, sizeof match->ut_line) ++ == 0)); + } +diff --git a/sysdeps/gnu/bits/utmp.h b/sysdeps/gnu/bits/utmp.h +deleted file mode 100644 +index 47a6082eacc56b4d..0000000000000000 +--- a/sysdeps/gnu/bits/utmp.h ++++ /dev/null +@@ -1,126 +0,0 @@ +-/* The `struct utmp' type, describing entries in the utmp file. GNU 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; if not, see +- . */ +- +-#ifndef _UTMP_H +-# error "Never include directly; use instead." +-#endif +- +-#include +-#include +-#include +-#include +- +- +-#define UT_LINESIZE 32 +-#define UT_NAMESIZE 32 +-#define UT_HOSTSIZE 256 +- +- +-/* The structure describing an entry in the database of +- previous logins. */ +-struct lastlog +- { +-#if __WORDSIZE_TIME64_COMPAT32 +- int32_t ll_time; +-#else +- __time_t ll_time; +-#endif +- char ll_line[UT_LINESIZE]; +- char ll_host[UT_HOSTSIZE]; +- }; +- +- +-/* The structure describing the status of a terminated process. This +- type is used in `struct utmp' below. */ +-struct exit_status +- { +- short int e_termination; /* Process termination status. */ +- short int e_exit; /* Process exit status. */ +- }; +- +- +-/* The structure describing an entry in the user accounting database. */ +-struct utmp +-{ +- short int ut_type; /* Type of login. */ +- pid_t ut_pid; /* Process ID of login process. */ +- char ut_line[UT_LINESIZE] +- __attribute_nonstring__; /* Devicename. */ +- char ut_id[4]; /* Inittab ID. */ +- char ut_user[UT_NAMESIZE] +- __attribute_nonstring__; /* Username. */ +- char ut_host[UT_HOSTSIZE] +- __attribute_nonstring__; /* Hostname for remote login. */ +- struct exit_status ut_exit; /* Exit status of a process marked +- as DEAD_PROCESS. */ +-/* The ut_session and ut_tv fields must be the same size when compiled +- 32- and 64-bit. This allows data files and shared memory to be +- shared between 32- and 64-bit applications. */ +-#if __WORDSIZE_TIME64_COMPAT32 +- int32_t ut_session; /* Session ID, used for windowing. */ +- struct +- { +- int32_t tv_sec; /* Seconds. */ +- int32_t tv_usec; /* Microseconds. */ +- } ut_tv; /* Time entry was made. */ +-#else +- long int ut_session; /* Session ID, used for windowing. */ +- struct timeval ut_tv; /* Time entry was made. */ +-#endif +- +- int32_t ut_addr_v6[4]; /* Internet address of remote host. */ +- char __glibc_reserved[20]; /* Reserved for future use. */ +-}; +- +-/* Backwards compatibility hacks. */ +-#define ut_name ut_user +-#ifndef _NO_UT_TIME +-/* We have a problem here: `ut_time' is also used otherwise. Define +- _NO_UT_TIME if the compiler complains. */ +-# define ut_time ut_tv.tv_sec +-#endif +-#define ut_xtime ut_tv.tv_sec +-#define ut_addr ut_addr_v6[0] +- +- +-/* Values for the `ut_type' field of a `struct utmp'. */ +-#define EMPTY 0 /* No valid user accounting information. */ +- +-#define RUN_LVL 1 /* The system's runlevel. */ +-#define BOOT_TIME 2 /* Time of system boot. */ +-#define NEW_TIME 3 /* Time after system clock changed. */ +-#define OLD_TIME 4 /* Time when system clock changed. */ +- +-#define INIT_PROCESS 5 /* Process spawned by the init process. */ +-#define LOGIN_PROCESS 6 /* Session leader of a logged in user. */ +-#define USER_PROCESS 7 /* Normal process. */ +-#define DEAD_PROCESS 8 /* Terminated process. */ +- +-#define ACCOUNTING 9 +- +-/* Old Linux name for the EMPTY type. */ +-#define UT_UNKNOWN EMPTY +- +- +-/* Tell the user that we have a modern system with UT_HOST, UT_PID, +- UT_TYPE, UT_ID and UT_TV fields. */ +-#define _HAVE_UT_TYPE 1 +-#define _HAVE_UT_PID 1 +-#define _HAVE_UT_ID 1 +-#define _HAVE_UT_TV 1 +-#define _HAVE_UT_HOST 1 diff --git a/SOURCES/glibc-rh1749439-3.patch b/SOURCES/glibc-rh1749439-3.patch new file mode 100644 index 0000000..7a18d19 --- /dev/null +++ b/SOURCES/glibc-rh1749439-3.patch @@ -0,0 +1,260 @@ +commit 5a3afa9738f3dbbaf8c0a35665318c1af782111b +Author: Florian Weimer +Date: Tue Aug 13 15:53:19 2019 +0200 + + login: Replace macro-based control flow with function calls in utmp + +diff --git a/login/utmp_file.c b/login/utmp_file.c +index da1baa6948d0eb39..812de8fd3d099ce9 100644 +--- a/login/utmp_file.c ++++ b/login/utmp_file.c +@@ -52,58 +52,71 @@ static struct utmp last_entry; + /* Do-nothing handler for locking timeout. */ + static void timeout_handler (int signum) {}; + +-/* LOCK_FILE(fd, type) failure_statement +- attempts to get a lock on the utmp file referenced by FD. If it fails, +- the failure_statement is executed, otherwise it is skipped. +- LOCKING_FAILED() +- jumps into the UNLOCK_FILE macro and ensures cleanup of LOCK_FILE. +- UNLOCK_FILE(fd) +- unlocks the utmp file referenced by FD and performs the cleanup of +- LOCK_FILE. +- */ +-#define LOCK_FILE(fd, type) \ +-{ \ +- struct flock fl; \ +- struct sigaction action, old_action; \ +- unsigned int old_timeout; \ +- \ +- /* Cancel any existing alarm. */ \ +- old_timeout = alarm (0); \ +- \ +- /* Establish signal handler. */ \ +- action.sa_handler = timeout_handler; \ +- __sigemptyset (&action.sa_mask); \ +- action.sa_flags = 0; \ +- __sigaction (SIGALRM, &action, &old_action); \ +- \ +- alarm (TIMEOUT); \ +- \ +- /* Try to get the lock. */ \ +- memset (&fl, '\0', sizeof (struct flock)); \ +- fl.l_type = (type); \ +- fl.l_whence = SEEK_SET; \ +- if (__fcntl64_nocancel ((fd), F_SETLKW, &fl) < 0) +- +-#define LOCKING_FAILED() \ +- goto unalarm_return +- +-#define UNLOCK_FILE(fd) \ +- /* Unlock the file. */ \ +- fl.l_type = F_UNLCK; \ +- __fcntl64_nocancel ((fd), F_SETLKW, &fl); \ +- \ +- unalarm_return: \ +- /* Reset the signal handler and alarm. We must reset the alarm \ +- before resetting the handler so our alarm does not generate a \ +- spurious SIGALRM seen by the user. However, we cannot just set \ +- the user's old alarm before restoring the handler, because then \ +- it's possible our handler could catch the user alarm's SIGARLM \ +- and then the user would never see the signal he expected. */ \ +- alarm (0); \ +- __sigaction (SIGALRM, &old_action, NULL); \ +- if (old_timeout != 0) \ +- alarm (old_timeout); \ +-} while (0) ++ ++/* try_file_lock (LOCKING, FD, TYPE) returns true if the locking ++ operation failed and recovery needs to be performed. ++ (file_lock_restore (LOCKING) still needs to be called.) ++ ++ file_unlock (FD) removes the lock (which must have been ++ acquired). ++ ++ file_lock_restore (LOCKING) is needed to clean up in both ++ cases. */ ++ ++struct file_locking ++{ ++ struct sigaction old_action; ++ unsigned int old_timeout; ++}; ++ ++static bool ++try_file_lock (struct file_locking *locking, int fd, int type) ++{ ++ /* Cancel any existing alarm. */ ++ locking->old_timeout = alarm (0); ++ ++ /* Establish signal handler. */ ++ struct sigaction action; ++ action.sa_handler = timeout_handler; ++ __sigemptyset (&action.sa_mask); ++ action.sa_flags = 0; ++ __sigaction (SIGALRM, &action, &locking->old_action); ++ ++ alarm (TIMEOUT); ++ ++ /* Try to get the lock. */ ++ struct flock fl = ++ { ++ .l_type = type, ++ fl.l_whence = SEEK_SET, ++ }; ++ return __fcntl64_nocancel (fd, F_SETLKW, &fl) < 0; ++} ++ ++static void ++file_unlock (int fd) ++{ ++ struct flock fl = ++ { ++ .l_type = F_UNLCK, ++ }; ++ __fcntl64_nocancel (fd, F_SETLKW, &fl); ++} ++ ++static void ++file_lock_restore (struct file_locking *locking) ++{ ++ /* Reset the signal handler and alarm. We must reset the alarm ++ before resetting the handler so our alarm does not generate a ++ spurious SIGALRM seen by the user. However, we cannot just set ++ the user's old alarm before restoring the handler, because then ++ it's possible our handler could catch the user alarm's SIGARLM ++ and then the user would never see the signal he expected. */ ++ alarm (0); ++ __sigaction (SIGALRM, &locking->old_action, NULL); ++ if (locking->old_timeout != 0) ++ alarm (locking->old_timeout); ++} + + #ifndef TRANSFORM_UTMP_FILE_NAME + # define TRANSFORM_UTMP_FILE_NAME(file_name) (file_name) +@@ -153,16 +166,16 @@ __libc_getutent_r (struct utmp *buffer, struct utmp **result) + return -1; + } + +- LOCK_FILE (file_fd, F_RDLCK) ++ struct file_locking fl; ++ if (try_file_lock (&fl, file_fd, F_RDLCK)) ++ nbytes = 0; ++ else + { +- nbytes = 0; +- LOCKING_FAILED (); ++ /* Read the next entry. */ ++ nbytes = __read_nocancel (file_fd, &last_entry, sizeof (struct utmp)); ++ file_unlock (file_fd); + } +- +- /* Read the next entry. */ +- nbytes = __read_nocancel (file_fd, &last_entry, sizeof (struct utmp)); +- +- UNLOCK_FILE (file_fd); ++ file_lock_restore (&fl); + + if (nbytes != sizeof (struct utmp)) + { +@@ -188,10 +201,12 @@ internal_getut_r (const struct utmp *id, struct utmp *buffer, + { + int result = -1; + +- LOCK_FILE (file_fd, F_RDLCK) ++ struct file_locking fl; ++ if (try_file_lock (&fl, file_fd, F_RDLCK)) + { + *lock_failed = true; +- LOCKING_FAILED (); ++ file_lock_restore (&fl); ++ return -1; + } + + if (id->ut_type == RUN_LVL || id->ut_type == BOOT_TIME +@@ -241,7 +256,8 @@ internal_getut_r (const struct utmp *id, struct utmp *buffer, + result = 0; + + unlock_return: +- UNLOCK_FILE (file_fd); ++ file_unlock (file_fd); ++ file_lock_restore (&fl); + + return result; + } +@@ -287,10 +303,12 @@ __libc_getutline_r (const struct utmp *line, struct utmp *buffer, + return -1; + } + +- LOCK_FILE (file_fd, F_RDLCK) ++ struct file_locking fl; ++ if (try_file_lock (&fl, file_fd, F_RDLCK)) + { + *result = NULL; +- LOCKING_FAILED (); ++ file_lock_restore (&fl); ++ return -1; + } + + while (1) +@@ -318,7 +336,8 @@ __libc_getutline_r (const struct utmp *line, struct utmp *buffer, + *result = buffer; + + unlock_return: +- UNLOCK_FILE (file_fd); ++ file_unlock (file_fd); ++ file_lock_restore (&fl); + + return ((*result == NULL) ? -1 : 0); + } +@@ -375,10 +394,11 @@ __libc_pututline (const struct utmp *data) + } + } + +- LOCK_FILE (file_fd, F_WRLCK) ++ struct file_locking fl; ++ if (try_file_lock (&fl, file_fd, F_WRLCK)) + { +- pbuf = NULL; +- LOCKING_FAILED (); ++ file_lock_restore (&fl); ++ return NULL; + } + + if (found < 0) +@@ -421,7 +441,8 @@ __libc_pututline (const struct utmp *data) + } + + unlock_return: +- UNLOCK_FILE (file_fd); ++ file_unlock (file_fd); ++ file_lock_restore (&fl); + + return pbuf; + } +@@ -450,8 +471,13 @@ __libc_updwtmp (const char *file, const struct utmp *utmp) + if (fd < 0) + return -1; + +- LOCK_FILE (fd, F_WRLCK) +- LOCKING_FAILED (); ++ struct file_locking fl; ++ if (try_file_lock (&fl, fd, F_WRLCK)) ++ { ++ file_lock_restore (&fl); ++ __close_nocancel_nostatus (fd); ++ return -1; ++ } + + /* Remember original size of log file. */ + offset = __lseek64 (fd, 0, SEEK_END); +@@ -477,7 +503,8 @@ __libc_updwtmp (const char *file, const struct utmp *utmp) + result = 0; + + unlock_return: +- UNLOCK_FILE (fd); ++ file_unlock (file_fd); ++ file_lock_restore (&fl); + + /* Close WTMP file. */ + __close_nocancel_nostatus (fd); diff --git a/SOURCES/glibc-rh1749439-4.patch b/SOURCES/glibc-rh1749439-4.patch new file mode 100644 index 0000000..b2c7972 --- /dev/null +++ b/SOURCES/glibc-rh1749439-4.patch @@ -0,0 +1,155 @@ +commit 341da5b4b6253de9a7581a066f33f89cacb44dec +Author: Florian Weimer +Date: Thu Aug 15 10:30:23 2019 +0200 + + login: Fix updwtmp, updwtmx unlocking + + Commit 5a3afa9738f3dbbaf8c0a35665318c1af782111b (login: Replace + macro-based control flow with function calls in utmp) introduced + a regression because after it, __libc_updwtmp attempts to unlock + the wrong file descriptor. + +diff --git a/login/Makefile b/login/Makefile +index 8b31991be835fa8e..81986ab6bd8560ea 100644 +--- a/login/Makefile ++++ b/login/Makefile +@@ -43,7 +43,7 @@ endif + subdir-dirs = programs + vpath %.c programs + +-tests := tst-utmp tst-utmpx tst-grantpt tst-ptsname tst-getlogin ++tests := tst-utmp tst-utmpx tst-grantpt tst-ptsname tst-getlogin tst-updwtmpx + + # Build the -lutil library with these extra functions. + extra-libs := libutil +diff --git a/login/tst-updwtmpx.c b/login/tst-updwtmpx.c +new file mode 100644 +index 0000000000000000..0a4a27daeb0440fd +--- /dev/null ++++ b/login/tst-updwtmpx.c +@@ -0,0 +1,112 @@ ++/* Basic test coverage for updwtmpx. ++ 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; see the file COPYING.LIB. If ++ not, see . */ ++ ++/* This program runs a series of tests. Each one calls updwtmpx ++ twice, to write two records, optionally with misalignment in the ++ file, and reads back the results. */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++static int ++do_test (void) ++{ ++ /* Two entries filled with an arbitrary bit pattern. */ ++ struct utmpx entries[2]; ++ unsigned char pad; ++ { ++ unsigned char *p = (unsigned char *) &entries[0]; ++ for (size_t i = 0; i < sizeof (entries); ++i) ++ { ++ p[i] = i; ++ } ++ /* Make sure that the first and second entry and the padding are ++ different. */ ++ p[sizeof (struct utmpx)] = p[0] + 1; ++ pad = p[0] + 2; ++ } ++ ++ char *path; ++ int fd = create_temp_file ("tst-updwtmpx-", &path); ++ ++ /* Used to check that updwtmpx does not leave an open file ++ descriptor around. */ ++ struct support_descriptors *descriptors = support_descriptors_list (); ++ ++ /* updwtmpx is expected to remove misalignment. Optionally insert ++ one byte of misalignment at the start and in the middle (after ++ the first entry). */ ++ for (int misaligned_start = 0; misaligned_start < 2; ++misaligned_start) ++ for (int misaligned_middle = 0; misaligned_middle < 2; ++misaligned_middle) ++ { ++ if (test_verbose > 0) ++ printf ("info: misaligned_start=%d misaligned_middle=%d\n", ++ misaligned_start, misaligned_middle); ++ ++ xftruncate (fd, 0); ++ TEST_COMPARE (pwrite64 (fd, &pad, misaligned_start, 0), ++ misaligned_start); ++ ++ /* Write first entry and check it. */ ++ errno = 0; ++ updwtmpx (path, &entries[0]); ++ TEST_COMPARE (errno, 0); ++ support_descriptors_check (descriptors); ++ TEST_COMPARE (xlseek (fd, 0, SEEK_END), sizeof (struct utmpx)); ++ struct utmpx buffer; ++ TEST_COMPARE (pread64 (fd, &buffer, sizeof (buffer), 0), ++ sizeof (buffer)); ++ TEST_COMPARE_BLOB (&entries[0], sizeof (entries[0]), ++ &buffer, sizeof (buffer)); ++ ++ /* Middle mis-alignmet. */ ++ TEST_COMPARE (pwrite64 (fd, &pad, misaligned_middle, ++ sizeof (struct utmpx)), misaligned_middle); ++ ++ /* Write second entry and check both entries. */ ++ errno = 0; ++ updwtmpx (path, &entries[1]); ++ TEST_COMPARE (errno, 0); ++ support_descriptors_check (descriptors); ++ TEST_COMPARE (xlseek (fd, 0, SEEK_END), 2 * sizeof (struct utmpx)); ++ TEST_COMPARE (pread64 (fd, &buffer, sizeof (buffer), 0), ++ sizeof (buffer)); ++ TEST_COMPARE_BLOB (&entries[0], sizeof (entries[0]), ++ &buffer, sizeof (buffer)); ++ TEST_COMPARE (pread64 (fd, &buffer, sizeof (buffer), sizeof (buffer)), ++ sizeof (buffer)); ++ TEST_COMPARE_BLOB (&entries[1], sizeof (entries[1]), ++ &buffer, sizeof (buffer)); ++ } ++ ++ support_descriptors_free (descriptors); ++ free (path); ++ xclose (fd); ++ ++ return 0; ++} ++ ++#include +diff --git a/login/utmp_file.c b/login/utmp_file.c +index 812de8fd3d099ce9..54f424fd6165bae7 100644 +--- a/login/utmp_file.c ++++ b/login/utmp_file.c +@@ -503,7 +503,7 @@ __libc_updwtmp (const char *file, const struct utmp *utmp) + result = 0; + + unlock_return: +- file_unlock (file_fd); ++ file_unlock (fd); + file_lock_restore (&fl); + + /* Close WTMP file. */ diff --git a/SOURCES/glibc-rh1749439-5.patch b/SOURCES/glibc-rh1749439-5.patch new file mode 100644 index 0000000..b9cfe31 --- /dev/null +++ b/SOURCES/glibc-rh1749439-5.patch @@ -0,0 +1,33 @@ +commit 0d5b2917530ccaf8ad312dfbb7bce69d569c23ad +Author: Florian Weimer +Date: Thu Aug 15 16:09:20 2019 +0200 + + login: Use struct flock64 in utmp [BZ #24880] + + Commit 06ab719d30b01da401150068054d3b8ea93dd12f ("Fix Linux fcntl OFD + locks for non-LFS architectures (BZ#20251)") introduced the use of + fcntl64 into the utmp implementation. However, the lock file + structure was not updated to struct flock64 at that point. + +diff --git a/login/utmp_file.c b/login/utmp_file.c +index 54f424fd6165bae7..8b6fee96b623fa90 100644 +--- a/login/utmp_file.c ++++ b/login/utmp_file.c +@@ -85,7 +85,7 @@ try_file_lock (struct file_locking *locking, int fd, int type) + alarm (TIMEOUT); + + /* Try to get the lock. */ +- struct flock fl = ++ struct flock64 fl = + { + .l_type = type, + fl.l_whence = SEEK_SET, +@@ -96,7 +96,7 @@ try_file_lock (struct file_locking *locking, int fd, int type) + static void + file_unlock (int fd) + { +- struct flock fl = ++ struct flock64 fl = + { + .l_type = F_UNLCK, + }; diff --git a/SOURCES/glibc-rh1749439-6.patch b/SOURCES/glibc-rh1749439-6.patch new file mode 100644 index 0000000..3a8ad22 --- /dev/null +++ b/SOURCES/glibc-rh1749439-6.patch @@ -0,0 +1,204 @@ +commit 628598be7e1bfaa04f34df71ef6678f2c5103dfd +Author: Florian Weimer +Date: Thu Aug 15 16:09:05 2019 +0200 + + login: Disarm timer after utmp lock acquisition [BZ #24879] + + If the file processing takes a long time for some reason, SIGALRM can + arrive while the file is still being processed. At that point, file + access will fail with EINTR. Disarming the timer after lock + acquisition avoids that. (If there was a previous alarm, it is the + responsibility of the caller to deal with the EINTR error.) + +diff --git a/login/utmp_file.c b/login/utmp_file.c +index 8b6fee96b623fa90..a736d3d25e005920 100644 +--- a/login/utmp_file.c ++++ b/login/utmp_file.c +@@ -55,32 +55,23 @@ static void timeout_handler (int signum) {}; + + /* try_file_lock (LOCKING, FD, TYPE) returns true if the locking + operation failed and recovery needs to be performed. +- (file_lock_restore (LOCKING) still needs to be called.) + + file_unlock (FD) removes the lock (which must have been +- acquired). +- +- file_lock_restore (LOCKING) is needed to clean up in both +- cases. */ +- +-struct file_locking +-{ +- struct sigaction old_action; +- unsigned int old_timeout; +-}; ++ successfully acquired). */ + + static bool +-try_file_lock (struct file_locking *locking, int fd, int type) ++try_file_lock (int fd, int type) + { + /* Cancel any existing alarm. */ +- locking->old_timeout = alarm (0); ++ int old_timeout = alarm (0); + + /* Establish signal handler. */ ++ struct sigaction old_action; + struct sigaction action; + action.sa_handler = timeout_handler; + __sigemptyset (&action.sa_mask); + action.sa_flags = 0; +- __sigaction (SIGALRM, &action, &locking->old_action); ++ __sigaction (SIGALRM, &action, &old_action); + + alarm (TIMEOUT); + +@@ -90,7 +81,23 @@ try_file_lock (struct file_locking *locking, int fd, int type) + .l_type = type, + fl.l_whence = SEEK_SET, + }; +- return __fcntl64_nocancel (fd, F_SETLKW, &fl) < 0; ++ ++ bool status = __fcntl64_nocancel (fd, F_SETLKW, &fl) < 0; ++ int saved_errno = errno; ++ ++ /* Reset the signal handler and alarm. We must reset the alarm ++ before resetting the handler so our alarm does not generate a ++ spurious SIGALRM seen by the user. However, we cannot just set ++ the user's old alarm before restoring the handler, because then ++ it's possible our handler could catch the user alarm's SIGARLM and ++ then the user would never see the signal he expected. */ ++ alarm (0); ++ __sigaction (SIGALRM, &old_action, NULL); ++ if (old_timeout != 0) ++ alarm (old_timeout); ++ ++ __set_errno (saved_errno); ++ return status; + } + + static void +@@ -103,21 +110,6 @@ file_unlock (int fd) + __fcntl64_nocancel (fd, F_SETLKW, &fl); + } + +-static void +-file_lock_restore (struct file_locking *locking) +-{ +- /* Reset the signal handler and alarm. We must reset the alarm +- before resetting the handler so our alarm does not generate a +- spurious SIGALRM seen by the user. However, we cannot just set +- the user's old alarm before restoring the handler, because then +- it's possible our handler could catch the user alarm's SIGARLM +- and then the user would never see the signal he expected. */ +- alarm (0); +- __sigaction (SIGALRM, &locking->old_action, NULL); +- if (locking->old_timeout != 0) +- alarm (locking->old_timeout); +-} +- + #ifndef TRANSFORM_UTMP_FILE_NAME + # define TRANSFORM_UTMP_FILE_NAME(file_name) (file_name) + #endif +@@ -166,8 +158,7 @@ __libc_getutent_r (struct utmp *buffer, struct utmp **result) + return -1; + } + +- struct file_locking fl; +- if (try_file_lock (&fl, file_fd, F_RDLCK)) ++ if (try_file_lock (file_fd, F_RDLCK)) + nbytes = 0; + else + { +@@ -175,7 +166,6 @@ __libc_getutent_r (struct utmp *buffer, struct utmp **result) + nbytes = __read_nocancel (file_fd, &last_entry, sizeof (struct utmp)); + file_unlock (file_fd); + } +- file_lock_restore (&fl); + + if (nbytes != sizeof (struct utmp)) + { +@@ -201,11 +191,9 @@ internal_getut_r (const struct utmp *id, struct utmp *buffer, + { + int result = -1; + +- struct file_locking fl; +- if (try_file_lock (&fl, file_fd, F_RDLCK)) ++ if (try_file_lock (file_fd, F_RDLCK)) + { + *lock_failed = true; +- file_lock_restore (&fl); + return -1; + } + +@@ -257,7 +245,6 @@ internal_getut_r (const struct utmp *id, struct utmp *buffer, + + unlock_return: + file_unlock (file_fd); +- file_lock_restore (&fl); + + return result; + } +@@ -303,11 +290,9 @@ __libc_getutline_r (const struct utmp *line, struct utmp *buffer, + return -1; + } + +- struct file_locking fl; +- if (try_file_lock (&fl, file_fd, F_RDLCK)) ++ if (try_file_lock (file_fd, F_RDLCK)) + { + *result = NULL; +- file_lock_restore (&fl); + return -1; + } + +@@ -337,7 +322,6 @@ __libc_getutline_r (const struct utmp *line, struct utmp *buffer, + + unlock_return: + file_unlock (file_fd); +- file_lock_restore (&fl); + + return ((*result == NULL) ? -1 : 0); + } +@@ -394,12 +378,8 @@ __libc_pututline (const struct utmp *data) + } + } + +- struct file_locking fl; +- if (try_file_lock (&fl, file_fd, F_WRLCK)) +- { +- file_lock_restore (&fl); +- return NULL; +- } ++ if (try_file_lock (file_fd, F_WRLCK)) ++ return NULL; + + if (found < 0) + { +@@ -442,7 +422,6 @@ __libc_pututline (const struct utmp *data) + + unlock_return: + file_unlock (file_fd); +- file_lock_restore (&fl); + + return pbuf; + } +@@ -471,10 +450,8 @@ __libc_updwtmp (const char *file, const struct utmp *utmp) + if (fd < 0) + return -1; + +- struct file_locking fl; +- if (try_file_lock (&fl, fd, F_WRLCK)) ++ if (try_file_lock (fd, F_WRLCK)) + { +- file_lock_restore (&fl); + __close_nocancel_nostatus (fd); + return -1; + } +@@ -504,7 +481,6 @@ __libc_updwtmp (const char *file, const struct utmp *utmp) + + unlock_return: + file_unlock (fd); +- file_lock_restore (&fl); + + /* Close WTMP file. */ + __close_nocancel_nostatus (fd); diff --git a/SOURCES/glibc-rh1749439-7.patch b/SOURCES/glibc-rh1749439-7.patch new file mode 100644 index 0000000..370dab2 --- /dev/null +++ b/SOURCES/glibc-rh1749439-7.patch @@ -0,0 +1,309 @@ +commit 61d3db428176d9d0822e4e680305fe34285edff2 +Author: Florian Weimer +Date: Wed Aug 28 11:59:45 2019 +0200 + + login: pututxline could fail to overwrite existing entries [BZ #24902] + + The internal_getut_r function updates the file_offset variable and + therefore must always update last_entry as well. + + Previously, if pututxline could not upgrade the read lock to a + write lock, internal_getut_r would update file_offset only, + without updating last_entry, and a subsequent call would not + overwrite the existing utmpx entry at file_offset, instead + creating a new entry. This has been observed to cause unbounded + file growth in high-load situations. + + This commit removes the buffer argument to internal_getut_r and + updates the last_entry variable directly, along with file_offset. + + Initially reported and fixed by Ondřej Lysoněk. + + Reviewed-by: Gabriel F. T. Gomes + +diff --git a/login/Makefile b/login/Makefile +index 81986ab6bd8560ea..82132c83fd799357 100644 +--- a/login/Makefile ++++ b/login/Makefile +@@ -43,7 +43,8 @@ endif + subdir-dirs = programs + vpath %.c programs + +-tests := tst-utmp tst-utmpx tst-grantpt tst-ptsname tst-getlogin tst-updwtmpx ++tests := tst-utmp tst-utmpx tst-grantpt tst-ptsname tst-getlogin tst-updwtmpx \ ++ tst-pututxline-lockfail + + # Build the -lutil library with these extra functions. + extra-libs := libutil +@@ -71,3 +72,5 @@ endif + $(inst_libexecdir)/pt_chown: $(objpfx)pt_chown $(+force) + $(make-target-directory) + -$(INSTALL_PROGRAM) -m 4755 -o root $< $@ ++ ++$(objpfx)tst-pututxline-lockfail: $(shared-thread-library) +diff --git a/login/tst-pututxline-lockfail.c b/login/tst-pututxline-lockfail.c +new file mode 100644 +index 0000000000000000..47c25dc0658d3c60 +--- /dev/null ++++ b/login/tst-pututxline-lockfail.c +@@ -0,0 +1,176 @@ ++/* Test the lock upgrade path in tst-pututxline. ++ 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; see the file COPYING.LIB. If ++ not, see . */ ++ ++/* pututxline upgrades the read lock on the file to a write lock. ++ This test verifies that if the lock upgrade fails, the utmp ++ subsystem remains in a consistent state, so that pututxline can be ++ called again. */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* Path to the temporary utmp file. */ ++static char *path; ++ ++/* Used to synchronize the subprocesses. The barrier itself is ++ allocated in shared memory. */ ++static pthread_barrier_t *barrier; ++ ++/* Use pututxline to write an entry for PID. */ ++static struct utmpx * ++write_entry (pid_t pid) ++{ ++ struct utmpx ut = ++ { ++ .ut_type = LOGIN_PROCESS, ++ .ut_id = "1", ++ .ut_user = "root", ++ .ut_pid = pid, ++ .ut_line = "entry", ++ .ut_host = "localhost", ++ }; ++ return pututxline (&ut); ++} ++ ++/* Create the initial entry in a subprocess, so that the utmp ++ subsystem in the original process is not disturbed. */ ++static void ++subprocess_create_entry (void *closure) ++{ ++ TEST_COMPARE (utmpname (path), 0); ++ TEST_VERIFY (write_entry (101) != NULL); ++} ++ ++/* Acquire an advisory read lock on PATH. */ ++__attribute__ ((noreturn)) static void ++subprocess_lock_file (void) ++{ ++ int fd = xopen (path, O_RDONLY, 0); ++ ++ struct flock64 fl = ++ { ++ .l_type = F_RDLCK, ++ fl.l_whence = SEEK_SET, ++ }; ++ TEST_COMPARE (fcntl64 (fd, F_SETLKW, &fl), 0); ++ ++ /* Signal to the main process that the lock has been acquired. */ ++ xpthread_barrier_wait (barrier); ++ ++ /* Wait for the unlock request from the main process. */ ++ xpthread_barrier_wait (barrier); ++ ++ /* Implicitly unlock the file. */ ++ xclose (fd); ++ ++ /* Overwrite the existing entry. */ ++ TEST_COMPARE (utmpname (path), 0); ++ errno = 0; ++ setutxent (); ++ TEST_COMPARE (errno, 0); ++ TEST_VERIFY (write_entry (102) != NULL); ++ errno = 0; ++ endutxent (); ++ TEST_COMPARE (errno, 0); ++ ++ _exit (0); ++} ++ ++static int ++do_test (void) ++{ ++ xclose (create_temp_file ("tst-pututxline-lockfail-", &path)); ++ ++ { ++ pthread_barrierattr_t attr; ++ xpthread_barrierattr_init (&attr); ++ xpthread_barrierattr_setpshared (&attr, PTHREAD_SCOPE_PROCESS); ++ barrier = support_shared_allocate (sizeof (*barrier)); ++ xpthread_barrier_init (barrier, &attr, 2); ++ xpthread_barrierattr_destroy (&attr); ++ } ++ ++ /* Write the initial entry. */ ++ support_isolate_in_subprocess (subprocess_create_entry, NULL); ++ ++ pid_t locker_pid = xfork (); ++ if (locker_pid == 0) ++ subprocess_lock_file (); ++ ++ /* Wait for the file locking to complete. */ ++ xpthread_barrier_wait (barrier); ++ ++ /* Try to add another entry. This attempt will fail, with EINTR or ++ EAGAIN. */ ++ TEST_COMPARE (utmpname (path), 0); ++ TEST_VERIFY (write_entry (102) == NULL); ++ if (errno != EINTR) ++ TEST_COMPARE (errno, EAGAIN); ++ ++ /* Signal the subprocess to overwrite the entry. */ ++ xpthread_barrier_wait (barrier); ++ ++ /* Wait for write and unlock to complete. */ ++ { ++ int status; ++ xwaitpid (locker_pid, &status, 0); ++ TEST_COMPARE (status, 0); ++ } ++ ++ /* The file is no longer locked, so this operation will succeed. */ ++ TEST_VERIFY (write_entry (103) != NULL); ++ errno = 0; ++ endutxent (); ++ TEST_COMPARE (errno, 0); ++ ++ /* Check that there is just one entry with the expected contents. ++ If pututxline becomes desynchronized internally, the entry is not ++ overwritten (bug 24902). */ ++ errno = 0; ++ setutxent (); ++ TEST_COMPARE (errno, 0); ++ struct utmpx *ut = getutxent (); ++ TEST_VERIFY_EXIT (ut != NULL); ++ TEST_COMPARE (ut->ut_type, LOGIN_PROCESS); ++ TEST_COMPARE_STRING (ut->ut_id, "1"); ++ TEST_COMPARE_STRING (ut->ut_user, "root"); ++ TEST_COMPARE (ut->ut_pid, 103); ++ TEST_COMPARE_STRING (ut->ut_line, "entry"); ++ TEST_COMPARE_STRING (ut->ut_host, "localhost"); ++ TEST_VERIFY (getutxent () == NULL); ++ errno = 0; ++ endutxent (); ++ TEST_COMPARE (errno, 0); ++ ++ xpthread_barrier_destroy (barrier); ++ support_shared_free (barrier); ++ free (path); ++ return 0; ++} ++ ++#include +diff --git a/login/utmp_file.c b/login/utmp_file.c +index a736d3d25e005920..cbc53d06de280af9 100644 +--- a/login/utmp_file.c ++++ b/login/utmp_file.c +@@ -185,9 +185,11 @@ __libc_getutent_r (struct utmp *buffer, struct utmp **result) + } + + ++/* Search for *ID, updating last_entry and file_offset. Return 0 on ++ success and -1 on failure. If the locking operation failed, write ++ true to *LOCK_FAILED. */ + static int +-internal_getut_r (const struct utmp *id, struct utmp *buffer, +- bool *lock_failed) ++internal_getut_r (const struct utmp *id, bool *lock_failed) + { + int result = -1; + +@@ -206,7 +208,7 @@ internal_getut_r (const struct utmp *id, struct utmp *buffer, + while (1) + { + /* Read the next entry. */ +- if (__read_nocancel (file_fd, buffer, sizeof (struct utmp)) ++ if (__read_nocancel (file_fd, &last_entry, sizeof (struct utmp)) + != sizeof (struct utmp)) + { + __set_errno (ESRCH); +@@ -215,7 +217,7 @@ internal_getut_r (const struct utmp *id, struct utmp *buffer, + } + file_offset += sizeof (struct utmp); + +- if (id->ut_type == buffer->ut_type) ++ if (id->ut_type == last_entry.ut_type) + break; + } + } +@@ -227,7 +229,7 @@ internal_getut_r (const struct utmp *id, struct utmp *buffer, + while (1) + { + /* Read the next entry. */ +- if (__read_nocancel (file_fd, buffer, sizeof (struct utmp)) ++ if (__read_nocancel (file_fd, &last_entry, sizeof (struct utmp)) + != sizeof (struct utmp)) + { + __set_errno (ESRCH); +@@ -236,7 +238,7 @@ internal_getut_r (const struct utmp *id, struct utmp *buffer, + } + file_offset += sizeof (struct utmp); + +- if (__utmp_equal (buffer, id)) ++ if (__utmp_equal (&last_entry, id)) + break; + } + } +@@ -265,7 +267,7 @@ __libc_getutid_r (const struct utmp *id, struct utmp *buffer, + /* We don't have to distinguish whether we can lock the file or + whether there is no entry. */ + bool lock_failed = false; +- if (internal_getut_r (id, &last_entry, &lock_failed) < 0) ++ if (internal_getut_r (id, &lock_failed) < 0) + { + *result = NULL; + return -1; +@@ -330,10 +332,9 @@ unlock_return: + struct utmp * + __libc_pututline (const struct utmp *data) + { +- if (!maybe_setutent ()) ++ if (!maybe_setutent () || file_offset == -1l) + return NULL; + +- struct utmp buffer; + struct utmp *pbuf; + int found; + +@@ -369,7 +370,7 @@ __libc_pututline (const struct utmp *data) + else + { + bool lock_failed = false; +- found = internal_getut_r (data, &buffer, &lock_failed); ++ found = internal_getut_r (data, &lock_failed); + + if (__builtin_expect (lock_failed, false)) + { diff --git a/SOURCES/glibc-rh1749439-8.patch b/SOURCES/glibc-rh1749439-8.patch new file mode 100644 index 0000000..3fc23cf --- /dev/null +++ b/SOURCES/glibc-rh1749439-8.patch @@ -0,0 +1,86 @@ +commit c2adefbafcdd2519ff43eca6891c77cd7b29ab62 +Author: Florian Weimer +Date: Thu Aug 15 16:09:43 2019 +0200 + + login: Add nonstring attributes to struct utmp, struct utmpx [BZ #24899] + + Commit 7532837d7b03b3ca5b9a63d77a5bd81dd23f3d9c ("The + -Wstringop-truncation option new in GCC 8 detects common misuses") + added __attribute_nonstring__ to bits/utmp.h, but it did not update + the parallel bits/utmpx.h header. In struct utmp, the nonstring + attribute for ut_id was missing. + +diff --git a/bits/utmp.h b/bits/utmp.h +index 3c02dd4f3fe4e99b..854b342164b785e0 100644 +--- a/bits/utmp.h ++++ b/bits/utmp.h +@@ -61,7 +61,8 @@ struct utmp + pid_t ut_pid; /* Process ID of login process. */ + char ut_line[UT_LINESIZE] + __attribute_nonstring__; /* Devicename. */ +- char ut_id[4]; /* Inittab ID. */ ++ char ut_id[4] ++ __attribute_nonstring__; /* Inittab ID. */ + char ut_user[UT_NAMESIZE] + __attribute_nonstring__; /* Username. */ + char ut_host[UT_HOSTSIZE] +diff --git a/sysdeps/gnu/bits/utmpx.h b/sysdeps/gnu/bits/utmpx.h +index 2a77efc607ae2ac0..71c743ebfcd41194 100644 +--- a/sysdeps/gnu/bits/utmpx.h ++++ b/sysdeps/gnu/bits/utmpx.h +@@ -56,10 +56,14 @@ struct utmpx + { + short int ut_type; /* Type of login. */ + __pid_t ut_pid; /* Process ID of login process. */ +- char ut_line[__UT_LINESIZE]; /* Devicename. */ +- char ut_id[4]; /* Inittab ID. */ +- char ut_user[__UT_NAMESIZE]; /* Username. */ +- char ut_host[__UT_HOSTSIZE]; /* Hostname for remote login. */ ++ char ut_line[__UT_LINESIZE] ++ __attribute_nonstring__; /* Devicename. */ ++ char ut_id[4] ++ __attribute_nonstring__; /* Inittab ID. */ ++ char ut_user[__UT_NAMESIZE] ++ __attribute_nonstring__; /* Username. */ ++ char ut_host[__UT_HOSTSIZE] ++ __attribute_nonstring__; /* Hostname for remote login. */ + struct __exit_status ut_exit; /* Exit status of a process marked + as DEAD_PROCESS. */ + +diff --git a/sysdeps/unix/sysv/linux/s390/bits/utmp.h b/sysdeps/unix/sysv/linux/s390/bits/utmp.h +index b3fa362f478ae6fe..82e8d17e2e8cc031 100644 +--- a/sysdeps/unix/sysv/linux/s390/bits/utmp.h ++++ b/sysdeps/unix/sysv/linux/s390/bits/utmp.h +@@ -61,7 +61,8 @@ struct utmp + pid_t ut_pid; /* Process ID of login process. */ + char ut_line[UT_LINESIZE] + __attribute_nonstring__; /* Devicename. */ +- char ut_id[4]; /* Inittab ID. */ ++ char ut_id[4] ++ __attribute_nonstring__; /* Inittab ID. */ + char ut_user[UT_NAMESIZE] + __attribute_nonstring__; /* Username. */ + char ut_host[UT_HOSTSIZE] +diff --git a/sysdeps/unix/sysv/linux/s390/bits/utmpx.h b/sysdeps/unix/sysv/linux/s390/bits/utmpx.h +index 3d3036c3b91e6f57..3818ed3aa4df1e65 100644 +--- a/sysdeps/unix/sysv/linux/s390/bits/utmpx.h ++++ b/sysdeps/unix/sysv/linux/s390/bits/utmpx.h +@@ -56,10 +56,14 @@ struct utmpx + { + short int ut_type; /* Type of login. */ + __pid_t ut_pid; /* Process ID of login process. */ +- char ut_line[__UT_LINESIZE]; /* Devicename. */ +- char ut_id[4]; /* Inittab ID. */ +- char ut_user[__UT_NAMESIZE]; /* Username. */ +- char ut_host[__UT_HOSTSIZE]; /* Hostname for remote login. */ ++ char ut_line[__UT_LINESIZE] ++ __attribute_nonstring__; /* Devicename. */ ++ char ut_id[4] ++ __attribute_nonstring__; /* Inittab ID. */ ++ char ut_user[__UT_NAMESIZE] ++ __attribute_nonstring__; /* Username. */ ++ char ut_host[__UT_HOSTSIZE] ++ __attribute_nonstring__; /* Hostname for remote login. */ + struct __exit_status ut_exit; /* Exit status of a process marked + as DEAD_PROCESS. */ + diff --git a/SOURCES/glibc-rh1749439-9.patch b/SOURCES/glibc-rh1749439-9.patch new file mode 100644 index 0000000..0a8470b --- /dev/null +++ b/SOURCES/glibc-rh1749439-9.patch @@ -0,0 +1,26 @@ +commit b0a83ae71b2588bd2a9e6b40f95191602940e01e +Author: Florian Weimer +Date: Thu Nov 7 09:53:41 2019 +0100 + + login: Remove double-assignment of fl.l_whence in try_file_lock + + Since l_whence is the second member of struct flock, it is written + twice. The double-assignment is technically undefined behavior due to + the lack of a sequence point. + + Reviewed-by: Carlos O'Donell + Change-Id: I2baf9e70690e723c61051b25ccbd510aec15976c + +diff --git a/login/utmp_file.c b/login/utmp_file.c +index cbc53d06de280af9..9ad80364682bae92 100644 +--- a/login/utmp_file.c ++++ b/login/utmp_file.c +@@ -79,7 +79,7 @@ try_file_lock (int fd, int type) + struct flock64 fl = + { + .l_type = type, +- fl.l_whence = SEEK_SET, ++ .l_whence = SEEK_SET, + }; + + bool status = __fcntl64_nocancel (fd, F_SETLKW, &fl) < 0; diff --git a/SOURCES/glibc-rh1757354.patch b/SOURCES/glibc-rh1757354.patch new file mode 100644 index 0000000..d159b26 --- /dev/null +++ b/SOURCES/glibc-rh1757354.patch @@ -0,0 +1,1163 @@ +commit 8e42fc6811ba94a01e194d46572c3cf803b3aae0 +Author: Mike FABIAN +Date: Tue Sep 17 17:20:32 2019 +0200 + + Sync "language", "lang_name", "territory", "country_name" with CLDR/langtable + + Sync these values with CLDR and langtable as much as possible. Add + missing values. + + If possible, take the values from CLDR, if CLDR does not have it, + take it from langtable. The values from langtable which are not from + CLDR are from Wikipedia or native speakers. + +diff --git a/localedata/locales/az_AZ b/localedata/locales/az_AZ +index 6fe8839f25cc7450..3c0db0be3de1e6d3 100644 +--- a/localedata/locales/az_AZ ++++ b/localedata/locales/az_AZ +@@ -243,7 +243,7 @@ country_ab3 "AZE" + country_num 031 + country_car "AZ" + % Azərbaycanca +-lang_name "azrbaycan dili" ++lang_name "azrbaycan" + lang_ab "az" + lang_term "aze" + lang_lib "aze" +diff --git a/localedata/locales/be_BY@latin b/localedata/locales/be_BY@latin +index 43b13cc27812aaa0..fef339f6247a0eb6 100644 +--- a/localedata/locales/be_BY@latin ++++ b/localedata/locales/be_BY@latin +@@ -156,7 +156,7 @@ country_ab2 "BY" + country_ab3 "BLR" + country_num 112 + country_car "BY" +-lang_name "biearuskaja mova" ++lang_name "biearuskaja" + lang_ab "be" + lang_term "bel" + lang_lib "bel" +diff --git a/localedata/locales/ber_DZ b/localedata/locales/ber_DZ +index 79f3d289b1ee771c..4fa1bdfff94b9efd 100644 +--- a/localedata/locales/ber_DZ ++++ b/localedata/locales/ber_DZ +@@ -8,7 +8,7 @@ escape_char / + % exempt you from the conditions of the license if your use would + % otherwise be governed by that license. + +-% Amazigh Language Locale for Algeria (latin) ++% Berber Language Locale for Algeria (latin) + % Source: + % Contact: Pablo Saratxaga + % Email: +@@ -20,14 +20,14 @@ escape_char / + % Users: general + + LC_IDENTIFICATION +-title "Amazigh language locale for Algeria (latin)" ++title "Berber language locale for Algeria (latin)" + source "" + address "" + contact "Pablo Saratxaga" + email "pablo@mandrakesoft.com" + tel "" + fax "" +-language "Amazigh" ++language "Berber" + territory "Algeria" + revision "0.1" + date "2002-04-16" +@@ -253,14 +253,15 @@ LC_ADDRESS + % This is the ISO_IEC TR14652 Locale definition for the + % LC_ADDRESS + postal_fmt "%z%c%T%s%b%e%r" ++country_name "Lezzayer" + %country_post "" + country_ab2 "DZ" + country_ab3 "DZA" + country_num 012 + %country_isbn "" + country_car "DZ" +-% ⵜⴰⵎⴰⵣⵉⵖⵜ +-lang_name "" ++% Tamaziɣt ++lang_name "Tamazit" + %lang_ab + lang_term "ber" + lang_lib "ber" +diff --git a/localedata/locales/ber_MA b/localedata/locales/ber_MA +index b9bd64868cda3412..5d19354ad65069eb 100644 +--- a/localedata/locales/ber_MA ++++ b/localedata/locales/ber_MA +@@ -8,7 +8,7 @@ escape_char / + % exempt you from the conditions of the license if your use would + % otherwise be governed by that license. + +-% Amazigh Language Locale for Morocco (tifinagh) ++% Berber Language Locale for Morocco (tifinagh) + % Source: + % Contact: Pablo Saratxaga + % Email: +@@ -20,14 +20,14 @@ escape_char / + % Users: general + + LC_IDENTIFICATION +-title "Amazigh language locale for Morocco (tifinagh)" ++title "Berber language locale for Morocco (tifinagh)" + source "" + address "" + contact "Pablo Saratxaga" + email "pablo@mandrakesoft.com" + tel "" + fax "" +-language "Amazigh" ++language "Berber" + territory "Morocco" + revision "0.1" + date "2002-06-26" +@@ -204,6 +204,8 @@ LC_ADDRESS + % This is the ISO_IEC TR14652 Locale definition for the + % LC_ADDRESS + postal_fmt "%z%c%T%s%b%e%r" ++% https://en.wikipedia.org/wiki/Morocco ⵜⴰⴳⵍⴷⵉⵜ ⵏ ⵍⵎⵖⵔⵉⴱ ++country_name " " + %country_post "" + country_ab2 "MA" + country_ab3 "MAR" +@@ -211,7 +213,7 @@ country_num 504 + %country_isbn "" + country_car "MA" + % ⵜⴰⵎⴰⵣⵉⵖⵜ +-lang_name "" ++lang_name "" + % lang_ab + lang_term "ber" + lang_lib "ber" +diff --git a/localedata/locales/bhb_IN b/localedata/locales/bhb_IN +index 549974de2cfd4843..80d590d068582de6 100644 +--- a/localedata/locales/bhb_IN ++++ b/localedata/locales/bhb_IN +@@ -145,11 +145,13 @@ LC_ADDRESS + % This is the ISO_IEC TR14652 Locale definition for the LC_ADDRESS category + % generated by IBM Basic CountryPack Transformer. + postal_fmt "%z%c%T%s%b%e%r" ++country_name "" + country_ab2 "IN" + country_ab3 "IND" + country_car "IND" + country_num 356 +-lang_name "bhili" ++% भीली ++lang_name "" + lang_ab "" + lang_term "bhb" + lang_lib "bhb" +diff --git a/localedata/locales/bho_IN b/localedata/locales/bho_IN +index 99a91c2553ecdeae..4a0f25d6aceaa023 100644 +--- a/localedata/locales/bho_IN ++++ b/localedata/locales/bho_IN +@@ -147,6 +147,7 @@ END LC_NAME + + LC_ADDRESS + postal_fmt "%z%c%T%s%b%e%r" ++country_name "" + country_ab2 "IN" + country_ab3 "IND" + country_num 356 +diff --git a/localedata/locales/chr_US b/localedata/locales/chr_US +index 290d1b24551dd3ba..86868c02e9ae2e1c 100644 +--- a/localedata/locales/chr_US ++++ b/localedata/locales/chr_US +@@ -113,7 +113,7 @@ END LC_NAME + + LC_ADDRESS + postal_fmt "%a%N%f%N%d%N%b%N%h %s %e %r%N%T, %S %z%N%c%N" +-country_name "" ++country_name "" + country_post "USA" + country_ab2 "US" + country_ab3 "USA" +diff --git a/localedata/locales/crh_UA b/localedata/locales/crh_UA +index b2ac8c66d78521b0..86281a27db1cc64d 100644 +--- a/localedata/locales/crh_UA ++++ b/localedata/locales/crh_UA +@@ -198,8 +198,8 @@ country_ab2 "UA" + country_ab3 "UKR" + country_num 804 + country_car "UA" +-% Qırımtatarca +-lang_name "Qrmtatarca" ++% qırımtatar tili ++lang_name "qrmtatar tili" + lang_term "crh" + lang_lib "crh" + END LC_ADDRESS +diff --git a/localedata/locales/csb_PL b/localedata/locales/csb_PL +index c8572f8fc54853b3..662dcefa15a2cae3 100644 +--- a/localedata/locales/csb_PL ++++ b/localedata/locales/csb_PL +@@ -210,6 +210,7 @@ END LC_NAME + + LC_ADDRESS + postal_fmt "%f%N%a%N%d%N%b%N%s %h %e %r%N%z %T%N%c%N" ++country_name "Plsk" + country_ab2 "PL" + country_ab3 "POL" + country_num 616 +diff --git a/localedata/locales/doi_IN b/localedata/locales/doi_IN +index 0428ae50a9bf60e8..df9dfc6e2a428abb 100644 +--- a/localedata/locales/doi_IN ++++ b/localedata/locales/doi_IN +@@ -156,6 +156,7 @@ END LC_NAME + + LC_ADDRESS + postal_fmt "%z%c%T%s%b%e%r" ++country_name "" + country_ab2 "IN" + country_ab3 "IND" + country_num 356 +diff --git a/localedata/locales/dv_MV b/localedata/locales/dv_MV +index 0d7842f39f7edf85..ab78fa5ce33cfe0e 100644 +--- a/localedata/locales/dv_MV ++++ b/localedata/locales/dv_MV +@@ -182,9 +182,8 @@ country_ab2 "MV" + country_ab3 "MDV" + country_num 462 + country_car "MV" +-% lang_name FIXME +-% Cannot represent Dhivehi in Thaana script +-% http://en.wikipedia.org/wiki/Maldivian_language ++% ދިވެހި ++lang_name "" + lang_ab "dv" + lang_term "div" + lang_lib "div" +diff --git a/localedata/locales/eo b/localedata/locales/eo +index 33a81033e23caadd..b2ad5758004b67d8 100644 +--- a/localedata/locales/eo ++++ b/localedata/locales/eo +@@ -206,7 +206,7 @@ END LC_NAME + + LC_ADDRESS + postal_fmt "%f%N%a%N%d%N%b%N%s %h %e %r%N%%z %T%N%c%N" +-lang_name "Esperanto" ++lang_name "esperanto" + lang_ab "eo" + lang_term "epo" + END LC_ADDRESS +diff --git a/localedata/locales/hak_TW b/localedata/locales/hak_TW +index f62937e91b634416..87f2a00489d1574e 100644 +--- a/localedata/locales/hak_TW ++++ b/localedata/locales/hak_TW +@@ -187,8 +187,8 @@ country_ab3 "TWN" + country_num 158 + country_car "RC" + country_isbn 957 +-% 漢語客家語 +-lang_name "" ++% 客家語 ++lang_name "" + lang_term "hak" + lang_lib "hak" + END LC_ADDRESS +diff --git a/localedata/locales/hif_FJ b/localedata/locales/hif_FJ +index 5433bb4a2a54636e..a6868b791025c8f4 100644 +--- a/localedata/locales/hif_FJ ++++ b/localedata/locales/hif_FJ +@@ -176,7 +176,8 @@ country_car "FJI" + country_num 242 + % https://en.wikipedia.org/wiki/ISO_3166-1_numeric + % https://en.wikipedia.org/wiki/Fiji_Hindi +-lang_name "Fiji Baat" ++% फ़िजी बात ++lang_name "" + % iso-639-1 + lang_ab "" + % iso-639-3 +diff --git a/localedata/locales/hne_IN b/localedata/locales/hne_IN +index 7abec636304b9e67..d8b83610165a6844 100644 +--- a/localedata/locales/hne_IN ++++ b/localedata/locales/hne_IN +@@ -154,6 +154,7 @@ END LC_NAME + + LC_ADDRESS + postal_fmt "%z%c%T%s%b%e%r" ++country_name "" + country_ab2 "IN" + country_ab3 "IND" + country_num 356 +diff --git a/localedata/locales/ia_FR b/localedata/locales/ia_FR +index f3fbf213a3f7f267..4ce7c7fe4a416541 100644 +--- a/localedata/locales/ia_FR ++++ b/localedata/locales/ia_FR +@@ -127,7 +127,7 @@ country_ab3 "FRA" + country_num 250 + country_isbn "979-10" + country_car "F" +-lang_name "Interlingua" ++lang_name "interlingua" + lang_ab "ia" + lang_term "ina" + lang_lib "ina" +diff --git a/localedata/locales/id_ID b/localedata/locales/id_ID +index 3ddd8d07daed6697..92ff81df23b059a0 100644 +--- a/localedata/locales/id_ID ++++ b/localedata/locales/id_ID +@@ -155,7 +155,7 @@ country_ab2 "ID" + country_ab3 "IDN" + country_num 360 + country_car "RI" +-lang_name "Bahasa Indonesia" ++lang_name "Indonesia" + lang_ab "id" + lang_term "ind" + lang_lib "ind" +diff --git a/localedata/locales/ig_NG b/localedata/locales/ig_NG +index bddd2ccde523dca8..113294a0f58ab576 100644 +--- a/localedata/locales/ig_NG ++++ b/localedata/locales/ig_NG +@@ -321,11 +321,11 @@ LC_ADDRESS + % "end of line + postal_fmt "%f%N%a%N%d%N%b%N%s %h %e %r%N%z %T%N%c%N" + +-% Country name in Igbo - "Nigeria" +-country_name "Nigeria" ++% Country name in Igbo - "Naịjịrịa" ++country_name "Najra" + +-% Language name in Igbo - "Igbo" +-lang_name "Igbo" ++% Language name in Igbo - "Asụsụ Igbo" ++lang_name "Ass Igbo" + + % CEPT MAILCODES are suggested + % Alternatively use the code found on your countries postal item tracking number +diff --git a/localedata/locales/kab_DZ b/localedata/locales/kab_DZ +index a165f53f01370c94..ef572357c22615f7 100644 +--- a/localedata/locales/kab_DZ ++++ b/localedata/locales/kab_DZ +@@ -154,7 +154,7 @@ END LC_NAME + + LC_ADDRESS + postal_fmt "%f%N%a%N%d%N%b%N%s %h %e %r%N%z %T%N%c%N" +-country_name "Zzayer" ++country_name "Lezzayer" + country_ab2 "DZ" + country_ab3 "DZA" + country_num 012 +diff --git a/localedata/locales/ks_IN b/localedata/locales/ks_IN +index 6992a5536887d9f6..e1efea342d4b55a0 100644 +--- a/localedata/locales/ks_IN ++++ b/localedata/locales/ks_IN +@@ -167,7 +167,7 @@ LC_ADDRESS + % This is the ISO_IEC TR14652 Locale definition for the LC_ADDRESS category + % generated by IBM Basic CountryPack Transformer. + postal_fmt "%z%c%T%s%b%e%r" +-country_name "" ++country_name "" + country_ab2 "IN" + country_ab3 "IND" + country_num 356 +diff --git a/localedata/locales/ku_TR b/localedata/locales/ku_TR +index 595cdb14bc9ef29d..f6a8925608ea046d 100644 +--- a/localedata/locales/ku_TR ++++ b/localedata/locales/ku_TR +@@ -182,14 +182,14 @@ END LC_NAME + LC_ADDRESS + postal_fmt "%f%N%a%N%d%N%b%N%s %h %e %r%N%z %T%N%c%N" + % TODO +-country_name "Turkey" ++country_name "Tirkiye" + country_post "TR" + country_ab2 "TR" + country_ab3 "TUR" + country_num 792 + country_isbn 975 + country_car "TR" +-lang_name "kurdi" ++lang_name "kurd" + lang_ab "ku" + lang_term "kur" + lang_lib "kur" +diff --git a/localedata/locales/mag_IN b/localedata/locales/mag_IN +index b8f65f70e26f4481..c86d9ba075ef2577 100644 +--- a/localedata/locales/mag_IN ++++ b/localedata/locales/mag_IN +@@ -152,6 +152,7 @@ END LC_NAME + LC_ADDRESS + + postal_fmt "%z%c%T%s%b%e%r" ++country_name "" + country_ab2 "IN" + country_ab3 "IND" + country_num 356 +diff --git a/localedata/locales/mfe_MU b/localedata/locales/mfe_MU +index 7415e9250fb78d50..7fabc5f80d9ae5e5 100644 +--- a/localedata/locales/mfe_MU ++++ b/localedata/locales/mfe_MU +@@ -170,7 +170,7 @@ END LC_NAME + + LC_ADDRESS + postal_fmt "%f%N%h%s%N%T" +-country_name "Mauritius" ++country_name "Moris" + country_ab2 "MU" + country_ab3 "MUS" + country_num 480 +diff --git a/localedata/locales/mhr_RU b/localedata/locales/mhr_RU +index 85ac21b35af25c87..02bec3e9aed6fddc 100644 +--- a/localedata/locales/mhr_RU ++++ b/localedata/locales/mhr_RU +@@ -159,6 +159,8 @@ country_ab2 "RU" + country_ab3 "RUS" + country_num 643 + country_car "RUS" ++% марий йылме ++lang_name " " + lang_term "mhr" + lang_lib "mhr" + END LC_ADDRESS +diff --git a/localedata/locales/mi_NZ b/localedata/locales/mi_NZ +index 782f02359cb096d4..d08bc249427581c2 100644 +--- a/localedata/locales/mi_NZ ++++ b/localedata/locales/mi_NZ +@@ -157,7 +157,7 @@ country_ab2 "NZ" + country_ab3 "NZL" + country_num 554 + country_car "NZ" +-lang_name "Te Reo" ++lang_name "Mori" + lang_ab "mi" + lang_term "mri" + lang_lib "mao" +diff --git a/localedata/locales/ms_MY b/localedata/locales/ms_MY +index 66b5dd98e99e5da3..8ffe9156b6e3d022 100644 +--- a/localedata/locales/ms_MY ++++ b/localedata/locales/ms_MY +@@ -184,7 +184,7 @@ country_ab3 "MYS" + country_num 458 + country_car "MAL" + % Bahasa Melayu +-lang_name "Bahasa Melayu" ++lang_name "Melayu" + lang_ab "ms" + lang_term "msa" + lang_lib "may" +diff --git a/localedata/locales/my_MM b/localedata/locales/my_MM +index d612e5305aff7e2b..846363223883723b 100644 +--- a/localedata/locales/my_MM ++++ b/localedata/locales/my_MM +@@ -309,7 +309,8 @@ country_ab2 "MM" + country_num 104 + country_car "MYA" + lang_ab "my" +-lang_name "" ++% မြန်မာ ++lang_name "" + lang_term "mya" + lang_lib "bur" + END LC_ADDRESS +diff --git a/localedata/locales/nan_TW b/localedata/locales/nan_TW +index f5bc5d1642c2ce9b..53884e02ffd16d2c 100644 +--- a/localedata/locales/nan_TW ++++ b/localedata/locales/nan_TW +@@ -188,8 +188,8 @@ country_ab3 "TWN" + country_num 158 + country_car "RC" + country_isbn 957 +-% 漢語閩南語 +-lang_name "" ++% 閩南語 ++lang_name "" + lang_term "nan" + lang_lib "nan" + END LC_ADDRESS +diff --git a/localedata/locales/nan_TW@latin b/localedata/locales/nan_TW@latin +index d4579a4cdf032d4c..104f4152a98b37ab 100644 +--- a/localedata/locales/nan_TW@latin ++++ b/localedata/locales/nan_TW@latin +@@ -165,8 +165,8 @@ country_ab3 "TWN" + country_num 158 + country_car "RC" + country_isbn 957 +-%lang_name "Bân-lâm-gú, Hō-ló-oē" +-lang_name "Bn-lm-g, H-l-o" ++%lang_name "Bân-lâm-gú" ++lang_name "Bn-lm-g" + lang_term "nan" + lang_lib "nan" + END LC_ADDRESS +diff --git a/localedata/locales/nds_DE b/localedata/locales/nds_DE +index 232f9e4455ca74cc..d6200b7972b6b820 100644 +--- a/localedata/locales/nds_DE ++++ b/localedata/locales/nds_DE +@@ -45,7 +45,7 @@ country_ab3 "DEU" + country_car "D" + country_num 276 + country_isbn "3" +-lang_name "Neddersassisch" ++lang_name "Neddersasssch" + %lang_ab + lang_term "nds" + lang_lib "nds" +diff --git a/localedata/locales/nds_NL b/localedata/locales/nds_NL +index 8c8bebd93530938f..9fd50fb6256d3823 100644 +--- a/localedata/locales/nds_NL ++++ b/localedata/locales/nds_NL +@@ -44,7 +44,7 @@ country_ab3 "NLD" + country_car "NL" + country_num 528 + country_isbn "3" +-lang_name "Neddersassisch" ++lang_name "Neddersasssch" + %lang_ab + lang_term "nds" + lang_lib "nds" +diff --git a/localedata/locales/nhn_MX b/localedata/locales/nhn_MX +index 88a89765e88f060b..2dbfcb3c6572cd0c 100644 +--- a/localedata/locales/nhn_MX ++++ b/localedata/locales/nhn_MX +@@ -133,11 +133,12 @@ END LC_NAME + + LC_ADDRESS + postal_fmt "%f%N%a%N%d%N%b%N%s %h %e %r%N%z %T%N%c%N" ++country_name "Mexihco" + country_ab2 "MX" + country_ab3 "MEX" + country_num 484 + country_car "MEX" +-lang_name "Tlaxcala-Puebla Nahuatl" ++lang_name "Tlahco nhuatlahtlli" + lang_term "nhn" + lang_lib "nhn" + END LC_ADDRESS +diff --git a/localedata/locales/niu_NU b/localedata/locales/niu_NU +index 553c5d9edcddfc86..387e109109fc0374 100644 +--- a/localedata/locales/niu_NU ++++ b/localedata/locales/niu_NU +@@ -163,10 +163,12 @@ END LC_NAME + + LC_ADDRESS + postal_fmt "%f%N%a%N%d%N%b%N%s %h %e %r%N%z %T%N%c%N" ++country_name "Niu" + country_post "NU" + country_ab2 "NU" + country_ab3 "NIU" + country_num 570 ++lang_name "ko e vagahau Niu" + lang_term "niu" + lang_lib "niu" + END LC_ADDRESS +diff --git a/localedata/locales/niu_NZ b/localedata/locales/niu_NZ +index 560101b447c22251..2eba7d2630f8a46d 100644 +--- a/localedata/locales/niu_NZ ++++ b/localedata/locales/niu_NZ +@@ -99,6 +99,7 @@ country_ab2 "NZ" + country_ab3 "NZL" + country_num 554 + country_car "NZ" ++lang_name "ko e vagahau Niu" + lang_term "niu" + lang_lib "niu" + END LC_ADDRESS +diff --git a/localedata/locales/nr_ZA b/localedata/locales/nr_ZA +index 7de6420a6b52977e..f64434fadbad4e69 100644 +--- a/localedata/locales/nr_ZA ++++ b/localedata/locales/nr_ZA +@@ -225,7 +225,7 @@ country_car "ZA" + country_num 710 + + % Language name in Southern Ndebele +-lang_name "IsiNdebele" ++lang_name "isiNdebele" + + % ISO 639 two and three letter language names + % see http://www.loc.gov/standards/iso639-2/englangn.html +diff --git a/localedata/locales/oc_FR b/localedata/locales/oc_FR +index 707927ee2662ac91..a106f8d1c1152959 100644 +--- a/localedata/locales/oc_FR ++++ b/localedata/locales/oc_FR +@@ -44,7 +44,7 @@ country_ab3 "FRA" + country_num 250 + country_isbn "979-10" + country_car "F" +-lang_name "Occitan" ++lang_name "occitan" + lang_ab "oc" + lang_term "oci" + lang_lib "oci" +diff --git a/localedata/locales/or_IN b/localedata/locales/or_IN +index ef28b58895c342b6..2e4975e7b710b592 100644 +--- a/localedata/locales/or_IN ++++ b/localedata/locales/or_IN +@@ -20,7 +20,7 @@ contact "" + email "bug-glibc@gnu.org" + tel "" + fax "" +-language "Oriya" ++language "Odia" + territory "India" + revision "1.0" + date "2006-05-25" +diff --git a/localedata/locales/pa_PK b/localedata/locales/pa_PK +index 1f49bdc90d7ce637..0a584114b8f06590 100644 +--- a/localedata/locales/pa_PK ++++ b/localedata/locales/pa_PK +@@ -173,7 +173,7 @@ END LC_NAME + LC_ADDRESS + % FIXME + postal_fmt "%a%N%f%N%d%N%b%N%h %s %e %r%N%T %z%N%c%N" +-country_name "" ++country_name "" + country_ab2 "PK" + country_ab3 "PAK" + country_num 586 +diff --git a/localedata/locales/ps_AF b/localedata/locales/ps_AF +index 66f560ef4406be61..23dc86dcf1c1453b 100644 +--- a/localedata/locales/ps_AF ++++ b/localedata/locales/ps_AF +@@ -308,8 +308,7 @@ END LC_NAME + + LC_ADDRESS + postal_fmt "%a%N%f%N%d%N%b%N%s %h %e %r%N%C-%z %T%N%c%N" +-country_name "/ +-" ++country_name "" + country_post "AF" + country_ab2 "AF" + country_ab3 "AFG" +diff --git a/localedata/locales/quz_PE b/localedata/locales/quz_PE +index f6b1956b937100df..9ed890cbb0e6c762 100644 +--- a/localedata/locales/quz_PE ++++ b/localedata/locales/quz_PE +@@ -10,7 +10,7 @@ escape_char / + + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + % +-% Quechua (Cusco-Collao) language locale for Peru ++% Cusco Quechua language locale for Peru + % + % Prepared and contributed to glibc by Chris Leonard + % and Amos Batto +@@ -25,14 +25,14 @@ escape_char / + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + LC_IDENTIFICATION +-title "Quechua (Cusco-Collao) locale for Peru" ++title "Cusco Quechua locale for Peru" + source "Sugar Labs // OLPC" + address "" + contact "sugarlabs.org" + email "libc-alpha@sourceware.org" + tel "" + fax "" +-language "Quechua (Cusco-Collao)" ++language "Cusco Quechua" + territory "Peru" + revision "1.0" + date "2013-08-24" +@@ -144,7 +144,7 @@ country_ab2 "PE" + country_ab3 "PER" + country_num 604 + country_car "PE" +-lang_name "Quechua (Cusco)" ++lang_name "Qusqu runasimi" + lang_term "quz" + lang_lib "quz" + END LC_ADDRESS +diff --git a/localedata/locales/raj_IN b/localedata/locales/raj_IN +index ece080223e8de94b..ce009e406ab5c332 100644 +--- a/localedata/locales/raj_IN ++++ b/localedata/locales/raj_IN +@@ -158,7 +158,16 @@ name_ms "" + END LC_NAME + + LC_ADDRESS +-copy "hi_IN" ++postal_fmt "%z%c%T%s%b%e%r" ++country_name "" ++country_ab2 "IN" ++country_ab3 "IND" ++country_num 356 ++country_car "IND" ++% राजस्थानी ++lang_name "" ++lang_term "raj" ++lang_lib "raj" + END LC_ADDRESS + + LC_TELEPHONE +diff --git a/localedata/locales/rw_RW b/localedata/locales/rw_RW +index e0bc763c5a484c15..31cb4673dfa4a3aa 100644 +--- a/localedata/locales/rw_RW ++++ b/localedata/locales/rw_RW +@@ -132,7 +132,7 @@ END LC_NAME + + LC_ADDRESS + postal_fmt "%f%N%a%N%d%N%b%N%s %h %e %r%N%z %T%N%c%N" +-country_name "Rwanda" ++country_name "U Rwanda" + country_ab2 "RW" + country_ab3 "RWA" + country_num 646 +diff --git a/localedata/locales/sah_RU b/localedata/locales/sah_RU +index 80f67219c39cceb2..2b5a4b7bd660fb6e 100644 +--- a/localedata/locales/sah_RU ++++ b/localedata/locales/sah_RU +@@ -1,7 +1,7 @@ + escape_char / + comment_char % + +-% Yakut (Sakha) locale for Russian Federation ++% Sakha (Yakut) locale for Russian Federation + % Source: Valery Timiriliyev + % Email: timiriliyev@gmail.com + % Tel: +@@ -13,14 +13,14 @@ comment_char % + % Users: general + + LC_IDENTIFICATION +-title "Yakut (Sakha) locale for Russian Federation" ++title "Sakha (Yakut) locale for Russian Federation" + source "Valery Timiriliyev" + address "" + contact "Valery Timiriliyev" + email "timiriliyev@gmail.com" + tel "" + fax "" +-language "Yakut" ++language "Sakha" + territory "Russian Federation" + revision "1.1.0" + date "2018-07-06" +@@ -264,11 +264,11 @@ END LC_NAME + LC_ADDRESS + postal_fmt "%f%N%a%N%d%N%b%N%s %h %e %r%N%z %T%N%c%N" + +-% Россия +-country_name "" ++% Арассыыйа ++country_name "" + +-% Саха тыла +-lang_name " " ++% саха тыла ++lang_name "" + + % UN Geneve 1949:68 Distinguishing signs of vehicles in international traffic + % RUS +diff --git a/localedata/locales/sat_IN b/localedata/locales/sat_IN +index 134eb8a572c836a7..e1775a4072ff7d9c 100644 +--- a/localedata/locales/sat_IN ++++ b/localedata/locales/sat_IN +@@ -158,12 +158,13 @@ END LC_NAME + LC_ADDRESS + + postal_fmt "%z%c%T%s%b%e%r" ++country_name "" + country_ab2 "IN" + country_ab3 "IND" + country_num 356 + country_car "IND" +-% Satār +-lang_name "Satr" ++% ᱥᱟᱱᱛᱟᱲᱤ ++lang_name "" + lang_term "sat" + lang_lib "sat" + END LC_ADDRESS +diff --git a/localedata/locales/sc_IT b/localedata/locales/sc_IT +index 1488744575dae32a..32626404d2956e8c 100644 +--- a/localedata/locales/sc_IT ++++ b/localedata/locales/sc_IT +@@ -144,7 +144,7 @@ country_ab3 "ITA" + country_num 380 + country_isbn "978-88,979-12" + country_car "I" +-lang_name "Sardu" ++lang_name "sardu" + lang_ab "sc" + lang_term "srd" + lang_lib "srd" +diff --git a/localedata/locales/sd_IN b/localedata/locales/sd_IN +index 66aa0e254cefe0d7..64c5366c31dcd818 100644 +--- a/localedata/locales/sd_IN ++++ b/localedata/locales/sd_IN +@@ -164,12 +164,14 @@ LC_ADDRESS + % This is the ISO_IEC TR14652 Locale definition for the LC_ADDRESS category + % generated by IBM Basic CountryPack Transformer. + postal_fmt "%z%c%T%s%b%e%r" +-% https://sd.wikipedia.org/wiki/%DA%80%D8%A7%D8%B1%D8%AA : "ڀارت" +-country_name "" ++% From cldr: انڊيا ++country_name "" + country_ab2 "IN" + country_ab3 "IND" + country_num 356 + country_car "IND" ++% سنڌي ++lang_name "" + lang_ab "sd" + lang_term "snd" + lang_lib "snd" +diff --git a/localedata/locales/sd_IN@devanagari b/localedata/locales/sd_IN@devanagari +index b1ce87df93f9c3d6..97357e08559ea64f 100644 +--- a/localedata/locales/sd_IN@devanagari ++++ b/localedata/locales/sd_IN@devanagari +@@ -167,6 +167,8 @@ country_ab2 "IN" + country_ab3 "IND" + country_num 356 + country_car "IND" ++% सिन्धी ++lang_name "" + lang_ab "sd" + lang_term "snd" + lang_lib "snd" +diff --git a/localedata/locales/shn_MM b/localedata/locales/shn_MM +index 4212c50ec5ae0066..a837f5fb394b1bb5 100644 +--- a/localedata/locales/shn_MM ++++ b/localedata/locales/shn_MM +@@ -281,7 +281,8 @@ END LC_NAME + + LC_ADDRESS + postal_fmt "%a%N%d%N%f%N%b%N%h%t%r%t%e%t%s%N%T%t%z%N%c%N" +-country_name "" ++% https://shn.wikipedia.org/wiki/%E1%80%99%E1%80%AD%E1%80%B0%E1%80%84%E1%80%BA%E1%80%B8%E1%80%99%E1%81%A2%E1%81%BC%E1%80%BA%E1%82%88 မိူင်းမၢၼ်ႈ ++country_name "" + country_post "Myanmar" + country_ab2 "MM" + country_num 104 +diff --git a/localedata/locales/shs_CA b/localedata/locales/shs_CA +index a5b675a316945608..ab48d600ef72ba75 100644 +--- a/localedata/locales/shs_CA ++++ b/localedata/locales/shs_CA +@@ -8,7 +8,7 @@ escape_char / + % exempt you from the conditions of the license if your use would + % otherwise be governed by that license. + +-% Secwepemctsin (Shuswap) language locale for Canada ++% Shuswap language locale for Canada + % sorting according to CAN/CSA-Z243.4.1-1992 + % Source: Neskie Manuel + % Address: 745 Ska-Hiish Dr +@@ -25,14 +25,14 @@ escape_char / + % Users: general + + LC_IDENTIFICATION +-title "Secwepemctsin locale for Canada" ++title "Shuswap locale for Canada" + source "Neskie Manuel" + address "745 Ska-Hiish Dr, Chase BC V0E 1M3" + contact "" + email "bug-glibc-locales@gnu.org" + tel "" + fax "" +-language "Secwepemctsin" ++language "Shuswap" + territory "Canada" + revision "1.0" + date "2008-01-15" +@@ -155,7 +155,7 @@ country_ab2 "CA" + country_ab3 "CAN" + country_num 124 + country_car "CDN" +-lang_name "Secwepemctsin" ++lang_name "Secwepemctsn" + lang_term "shs" + lang_lib "shs" + END LC_ADDRESS +diff --git a/localedata/locales/sm_WS b/localedata/locales/sm_WS +index 6058fbdc38283bb2..2823005c0635b6cf 100644 +--- a/localedata/locales/sm_WS ++++ b/localedata/locales/sm_WS +@@ -159,7 +159,7 @@ END LC_NAME + + LC_ADDRESS + postal_fmt "%a%N%f%N%d%N%b%N%h %s %e %r%N%T, %S %z%N%c%N" +-country_name "Samoa" ++country_name "Smoa" + country_post "%a %N %f %N %d %N %b %N %h %s %e %/ + r %N %T, %c %N" + % http://laendercode.net/en/2-letter-list.html +diff --git a/localedata/locales/ss_ZA b/localedata/locales/ss_ZA +index 7532a1940b3556f9..8e08a85f461aed9b 100644 +--- a/localedata/locales/ss_ZA ++++ b/localedata/locales/ss_ZA +@@ -228,7 +228,7 @@ country_car "ZA" + % country_isbn "" + + % Language name in Swati +-lang_name "SiSwati" ++lang_name "siSwati" + + % ISO 639 two and three letter language names + % see http://www.loc.gov/standards/iso639-2/englangn.html +diff --git a/localedata/locales/szl_PL b/localedata/locales/szl_PL +index 8d5de2112e54b7ad..88f1df4e905c5bdf 100644 +--- a/localedata/locales/szl_PL ++++ b/localedata/locales/szl_PL +@@ -188,6 +188,7 @@ END LC_NAME + + LC_ADDRESS + postal_fmt "%f%N%a%N%d%N%b%N%s %h %e %r%N%z %T%N%c%N" ++country_name "Polska" + country_ab2 "PL" + country_ab3 "POL" + country_num 616 +diff --git a/localedata/locales/te_IN b/localedata/locales/te_IN +index fb5bb21b09ae0647..cb1b1109690b20bb 100644 +--- a/localedata/locales/te_IN ++++ b/localedata/locales/te_IN +@@ -177,7 +177,7 @@ LC_ADDRESS + % generated by IBM Basic CountryPack Transformer. + + postal_fmt "%a%N%d%N%f%N%r%t%e%N%h%t%b%N%s%t%N%T%t%z%N%S%N%c" +-country_name " " ++country_name "" + country_ab2 "IN" + country_ab3 "IND" + country_num 356 +diff --git a/localedata/locales/tg_TJ b/localedata/locales/tg_TJ +index 35dfca4574d4b5b9..6d1e4d8ab339501f 100644 +--- a/localedata/locales/tg_TJ ++++ b/localedata/locales/tg_TJ +@@ -222,6 +222,8 @@ country_ab2 "TJ" + country_ab3 "TJK" + country_num 762 + country_car "TJ" ++% тоҷикӣ ++lang_name "" + lang_ab "tg" + lang_term "tgk" + lang_lib "tgk" +diff --git a/localedata/locales/the_NP b/localedata/locales/the_NP +index 993e62fbfc5cea64..296e9970885ee490 100644 +--- a/localedata/locales/the_NP ++++ b/localedata/locales/the_NP +@@ -162,10 +162,14 @@ LC_ADDRESS + postal_fmt "%z%c%T%s%b%e%r" + lang_term "the" + lang_lib "the" ++% नेपाल ++country_name "" + country_ab2 "NP" + country_ab3 "NPL" + country_num 524 + country_car "NEP" ++% थारु ++lang_name "" + END LC_ADDRESS + + +diff --git a/localedata/locales/tk_TM b/localedata/locales/tk_TM +index 410afaf6c76c920b..e29ae20408763196 100644 +--- a/localedata/locales/tk_TM ++++ b/localedata/locales/tk_TM +@@ -399,7 +399,7 @@ country_num 795 + country_ab2 "TM" + country_ab3 "TKM" + % Türkmençe +-lang_name "trkmene" ++lang_name "trkmen dili" + lang_term "tuk" + lang_lib "tuk" + lang_ab "tk" +diff --git a/localedata/locales/tl_PH b/localedata/locales/tl_PH +index 40fd71d96095be12..03b8350749ab2c0a 100644 +--- a/localedata/locales/tl_PH ++++ b/localedata/locales/tl_PH +@@ -138,6 +138,7 @@ country_ab2 "PH" + country_ab3 "PHL" + country_num 608 + country_car "RP" ++lang_name "Tagalog" + lang_ab "tl" + lang_term "tgl" + lang_lib "tgl" +diff --git a/localedata/locales/to_TO b/localedata/locales/to_TO +index 7abe8685df8488cf..403a1219126bb189 100644 +--- a/localedata/locales/to_TO ++++ b/localedata/locales/to_TO +@@ -169,7 +169,7 @@ country_ab3 "TON" + country_car "TON" + country_num 776 + % Tongan +-lang_name "Tonga" ++lang_name "lea fakatonga" + % https://en.wikipedia.org/wiki/Tongan_language + lang_ab "to" + lang_term "ton" +diff --git a/localedata/locales/tpi_PG b/localedata/locales/tpi_PG +index 3315c27633ba58c6..885481974c8b531b 100644 +--- a/localedata/locales/tpi_PG ++++ b/localedata/locales/tpi_PG +@@ -172,7 +172,8 @@ END LC_NAME + LC_ADDRESS + % http://www.addressexamples.com/papua-new-guinea-address-format/ + postal_fmt "%a%s%z%C" +-country_name "Papua New Guinea" ++% https://tpi.wikipedia.org/wiki/Papua_Niugini ++country_name "Papua Niugini" + country_post "" + country_ab2 "PG" + country_ab3 "PNG" +@@ -180,7 +181,7 @@ country_car "PNG" + % https://en.wikipedia.org/wiki/ISO_3166-1_numeric + country_num 598 + % Tok Pisin +-lang_name "Tok Pisin" ++lang_name "Tok Pisin" + % https://en.wikipedia.org/wiki/Tok_Pisin + lang_ab "" + lang_term "tpi" +diff --git a/localedata/locales/tt_RU@iqtelif b/localedata/locales/tt_RU@iqtelif +index d4737c888e41352b..b52b1299946f372f 100644 +--- a/localedata/locales/tt_RU@iqtelif ++++ b/localedata/locales/tt_RU@iqtelif +@@ -155,10 +155,12 @@ END LC_MEASUREMENT + + LC_ADDRESS + postal_fmt "%f%N%a%N%d%N%b%N%s %h %e %r%N%z %T%N%c%N" ++country_name "Urs Patahlq" + country_ab2 "RU" + country_ab3 "RUS" + country_num 643 + country_car "RUS" ++lang_name "tatar tele" + lang_ab "tt" + lang_term "tat" + lang_lib "tat" +diff --git a/localedata/locales/ug_CN b/localedata/locales/ug_CN +index 1ba583c588e074d2..acb8b68239c4a653 100644 +--- a/localedata/locales/ug_CN ++++ b/localedata/locales/ug_CN +@@ -195,6 +195,8 @@ country_ab3 "CHN" + country_num 156 + country_car "CHN" + country_isbn 7 ++% ئۇيغۇرچە ++lang_name "" + lang_ab "ug" + lang_term "uig" + lang_lib "uig" +diff --git a/localedata/locales/unm_US b/localedata/locales/unm_US +index 1e62c60443b83ec6..ef458e22dc195809 100644 +--- a/localedata/locales/unm_US ++++ b/localedata/locales/unm_US +@@ -139,7 +139,7 @@ country_ab3 "USA" + country_num 840 + country_car "USA" + country_isbn 0 +-% lang_name "" ++lang_name "Lenape" + % lang_ab "" + lang_term "unm" + lang_lib "unm" +diff --git a/localedata/locales/wa_BE b/localedata/locales/wa_BE +index e97493089eb287b0..afec10f41c8b1612 100644 +--- a/localedata/locales/wa_BE ++++ b/localedata/locales/wa_BE +@@ -44,7 +44,7 @@ country_ab3 "BEL" + country_num 056 + country_isbn "2" + country_car "B" +-lang_name "Walon" ++lang_name "walon" + lang_ab "wa" + lang_term "wln" + lang_lib "wln" +diff --git a/localedata/locales/wo_SN b/localedata/locales/wo_SN +index 47263d2eab6db94e..20190925034c9ab4 100644 +--- a/localedata/locales/wo_SN ++++ b/localedata/locales/wo_SN +@@ -161,6 +161,7 @@ country_ab2 "SN" + country_ab3 "SEN" + country_num 686 + country_car "SN" ++lang_name "Wolof" + lang_ab "wo" + lang_term "wol" + lang_lib "wol" +diff --git a/localedata/locales/xh_ZA b/localedata/locales/xh_ZA +index 4564137e851b0cda..327f7250987aaa57 100644 +--- a/localedata/locales/xh_ZA ++++ b/localedata/locales/xh_ZA +@@ -209,13 +209,13 @@ END LC_NAME + + LC_ADDRESS + % https://xh.wikipedia.org/wiki/UMzantsi_Afrika +-country_name "UMzantsi Afrika" ++country_name "uMzantsi Afrika" + % + % Abbreviated country postal name + country_post "ZA" + % + % Language name in Sotho +-lang_name "IsiXhosa" ++lang_name "isiXhosa" + + % UN Geneve 1949:68 Distinguishing signs of vehicles in international traffic + % http://www.unece.org/trans/conventn/disting-signs-5-2001.pdf +diff --git a/localedata/locales/yo_NG b/localedata/locales/yo_NG +index ec72d078bb7eab6d..a3102270bf0fd38b 100644 +--- a/localedata/locales/yo_NG ++++ b/localedata/locales/yo_NG +@@ -271,8 +271,8 @@ LC_ADDRESS + % "country designation for the keyword", + % "end of line + postal_fmt "%f%N%a%N%d%N%b%N%s %h %e %r%N%z %T%N%c%N" +- +-country_name "Orlde Njr" ++% https://yo.wikipedia.org/wiki/N%C3%A0%C3%ACj%C3%ADr%C3%AD%C3%A0 and CLDR: Orilẹ̀-èdè Nàìjíríà ++country_name "Orild Njr" + + % Language name in Yoruba - "Yorùbá" + lang_name "d Yorb" +diff --git a/localedata/locales/yuw_PG b/localedata/locales/yuw_PG +index 0cb3cadf4ae485a1..55e787a5cdfc559f 100644 +--- a/localedata/locales/yuw_PG ++++ b/localedata/locales/yuw_PG +@@ -16,7 +16,7 @@ contact "Hannah Sarvasy" + email "nungon.localization@gmail.com" + tel "" + fax "" +-language "Yau/Nungon" ++language "Yau" + territory "Papua New Guinea" + revision "1.0" + date "2016-12-07" +@@ -133,8 +133,8 @@ country_ab2 "PG" + country_ab3 "PNG" + % ISO 3166-1 numeric code for PNG + country_num 598 +-% Yau/Nungon +-lang_name "Yau/Nungon" ++% See: https://en.wikipedia.org/wiki/Yau_language, the endonym seems to be Uruwa ++lang_name "Uruwa" + country_car "PNG" + lang_ab "" + lang_term "yuw" +diff --git a/localedata/locales/zh_HK b/localedata/locales/zh_HK +index c130878f3d6e0ace..e8097d6ed0704670 100644 +--- a/localedata/locales/zh_HK ++++ b/localedata/locales/zh_HK +@@ -178,6 +178,7 @@ country_ab2 "HK" + country_ab3 "HKG" + country_num 344 + country_car "HK" ++lang_name "" + lang_ab "zh" + lang_term "zho" + lang_lib "chi" +diff --git a/localedata/locales/zh_SG b/localedata/locales/zh_SG +index 2427cd3ead3583dc..472843c7f77b8ed6 100644 +--- a/localedata/locales/zh_SG ++++ b/localedata/locales/zh_SG +@@ -175,6 +175,7 @@ country_ab3 "SGP" + country_num 702 + % SGP + country_car "SGP" ++lang_name "" + lang_ab "zh" + lang_term "zho" + lang_lib "chi" diff --git a/SOURCES/glibc-rh1764214.patch b/SOURCES/glibc-rh1764214.patch new file mode 100644 index 0000000..fb7703c --- /dev/null +++ b/SOURCES/glibc-rh1764214.patch @@ -0,0 +1,305 @@ +commit bc79db3fd487daea36e7c130f943cfb9826a41b4 +Author: Stefan Liebler +Date: Wed Feb 6 09:06:34 2019 +0100 + + Fix alignment of TLS variables for tls variant TLS_TCB_AT_TP [BZ #23403] + + The alignment of TLS variables is wrong if accessed from within a thread + for architectures with tls variant TLS_TCB_AT_TP. + For the main thread the static tls data is properly aligned. + For other threads the alignment depends on the alignment of the thread + pointer as the static tls data is located relative to this pointer. + + This patch adds this alignment for TLS_TCB_AT_TP variants in the same way + as it is already done for TLS_DTV_AT_TP. The thread pointer is also already + properly aligned if the user provides its own stack for the new thread. + + This patch extends the testcase nptl/tst-tls1.c in order to check the + alignment of the tls variables and it adds a pthread_create invocation + with a user provided stack. + The test itself is migrated from test-skeleton.c to test-driver.c + and the missing support functions xpthread_attr_setstack and xposix_memalign + are added. + + ChangeLog: + + [BZ #23403] + * nptl/allocatestack.c (allocate_stack): Align pointer pd for + TLS_TCB_AT_TP tls variant. + * nptl/tst-tls1.c: Migrate to support/test-driver.c. + Add alignment checks. + * support/Makefile (libsupport-routines): Add xposix_memalign and + xpthread_setstack. + * support/support.h: Add xposix_memalign. + * support/xthread.h: Add xpthread_attr_setstack. + * support/xposix_memalign.c: New File. + * support/xpthread_attr_setstack.c: Likewise. + +diff --git a/nptl/allocatestack.c b/nptl/allocatestack.c +index 670cb8ffe6..590350647b 100644 +--- a/nptl/allocatestack.c ++++ b/nptl/allocatestack.c +@@ -572,7 +572,9 @@ allocate_stack (const struct pthread_attr *attr, struct pthread **pdp, + + /* Place the thread descriptor at the end of the stack. */ + #if TLS_TCB_AT_TP +- pd = (struct pthread *) ((char *) mem + size) - 1; ++ pd = (struct pthread *) ((((uintptr_t) mem + size) ++ - TLS_TCB_SIZE) ++ & ~__static_tls_align_m1); + #elif TLS_DTV_AT_TP + pd = (struct pthread *) ((((uintptr_t) mem + size + - __static_tls_size) +diff --git a/nptl/tst-tls1.c b/nptl/tst-tls1.c +index 00489e23e9..1a915224a7 100644 +--- a/nptl/tst-tls1.c ++++ b/nptl/tst-tls1.c +@@ -19,12 +19,16 @@ + #include + #include + #include +- ++#include ++#include ++#include ++#include ++#include + + struct test_s + { +- int a; +- int b; ++ __attribute__ ((aligned(0x20))) int a; ++ __attribute__ ((aligned(0x200))) int b; + }; + + #define INIT_A 1 +@@ -36,15 +40,34 @@ __thread struct test_s s __attribute__ ((tls_model ("initial-exec"))) = + .b = INIT_B + }; + ++/* Use noinline in combination with not static to ensure that the ++ alignment check is really done. Otherwise it was optimized out! */ ++__attribute__ ((noinline)) void ++check_alignment (const char *thr_name, const char *ptr_name, ++ int *ptr, int alignment) ++{ ++ uintptr_t offset_aligment = ((uintptr_t) ptr) & (alignment - 1); ++ if (offset_aligment) ++ { ++ FAIL_EXIT1 ("%s (%p) is not 0x%x-byte aligned in %s thread\n", ++ ptr_name, ptr, alignment, thr_name); ++ } ++} ++ ++static void ++check_s (const char *thr_name) ++{ ++ if (s.a != INIT_A || s.b != INIT_B) ++ FAIL_EXIT1 ("initial value of s in %s thread wrong\n", thr_name); ++ ++ check_alignment (thr_name, "s.a", &s.a, 0x20); ++ check_alignment (thr_name, "s.b", &s.b, 0x200); ++} + + static void * + tf (void *arg) + { +- if (s.a != INIT_A || s.b != INIT_B) +- { +- puts ("initial value of s in child thread wrong"); +- exit (1); +- } ++ check_s ("child"); + + ++s.a; + +@@ -55,25 +78,14 @@ tf (void *arg) + int + do_test (void) + { +- if (s.a != INIT_A || s.b != INIT_B) +- { +- puts ("initial value of s in main thread wrong"); +- exit (1); +- } ++ check_s ("main"); + + pthread_attr_t a; + +- if (pthread_attr_init (&a) != 0) +- { +- puts ("attr_init failed"); +- exit (1); +- } ++ xpthread_attr_init (&a); + +- if (pthread_attr_setstacksize (&a, 1 * 1024 * 1024) != 0) +- { +- puts ("attr_setstacksize failed"); +- return 1; +- } ++#define STACK_SIZE (1 * 1024 * 1024) ++ xpthread_attr_setstacksize (&a, STACK_SIZE); + + #define N 10 + int i; +@@ -83,29 +95,25 @@ do_test (void) + pthread_t th[M]; + int j; + for (j = 0; j < M; ++j, ++s.a) +- if (pthread_create (&th[j], &a, tf, NULL) != 0) +- { +- puts ("pthread_create failed"); +- exit (1); +- } ++ th[j] = xpthread_create (&a, tf, NULL); + + for (j = 0; j < M; ++j) +- if (pthread_join (th[j], NULL) != 0) +- { +- puts ("pthread_join failed"); +- exit (1); +- } ++ xpthread_join (th[j]); + } + +- if (pthread_attr_destroy (&a) != 0) +- { +- puts ("attr_destroy failed"); +- exit (1); +- } ++ /* Also check the alignment of the tls variables if a misaligned stack is ++ specified. */ ++ pthread_t th; ++ void *thr_stack = NULL; ++ thr_stack = xposix_memalign (0x200, STACK_SIZE + 1); ++ xpthread_attr_setstack (&a, thr_stack + 1, STACK_SIZE); ++ th = xpthread_create (&a, tf, NULL); ++ xpthread_join (th); ++ free (thr_stack); ++ ++ xpthread_attr_destroy (&a); + + return 0; + } + +- +-#define TEST_FUNCTION do_test () +-#include "../test-skeleton.c" ++#include +diff --git a/support/Makefile b/support/Makefile +index c15b93647c..9ff0ec3fff 100644 +--- a/support/Makefile ++++ b/support/Makefile +@@ -99,10 +99,12 @@ libsupport-routines = \ + xopen \ + xpipe \ + xpoll \ ++ xposix_memalign \ + xpthread_attr_destroy \ + xpthread_attr_init \ + xpthread_attr_setdetachstate \ + xpthread_attr_setguardsize \ ++ xpthread_attr_setstack \ + xpthread_attr_setstacksize \ + xpthread_barrier_destroy \ + xpthread_barrier_init \ +diff --git a/support/support.h b/support/support.h +index 119495e5a9..97fef2cd23 100644 +--- a/support/support.h ++++ b/support/support.h +@@ -86,6 +86,7 @@ int support_descriptor_supports_holes (int fd); + void *xmalloc (size_t) __attribute__ ((malloc)); + void *xcalloc (size_t n, size_t s) __attribute__ ((malloc)); + void *xrealloc (void *p, size_t n); ++void *xposix_memalign (size_t alignment, size_t n); + char *xasprintf (const char *format, ...) + __attribute__ ((format (printf, 1, 2), malloc)); + char *xstrdup (const char *); +diff --git a/support/xposix_memalign.c b/support/xposix_memalign.c +new file mode 100644 +index 0000000000..5501a0846a +--- /dev/null ++++ b/support/xposix_memalign.c +@@ -0,0 +1,35 @@ ++/* Error-checking wrapper for posix_memalign. ++ 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, see ++ . */ ++ ++#include ++#include ++#include ++ ++void * ++xposix_memalign (size_t alignment, size_t n) ++{ ++ void *p = NULL; ++ ++ int ret = posix_memalign (&p, alignment, n); ++ if (ret) ++ { ++ errno = ret; ++ oom_error ("posix_memalign", n); ++ } ++ return p; ++} +diff --git a/support/xpthread_attr_setstack.c b/support/xpthread_attr_setstack.c +new file mode 100644 +index 0000000000..c3772e240b +--- /dev/null ++++ b/support/xpthread_attr_setstack.c +@@ -0,0 +1,26 @@ ++/* pthread_attr_setstack with error checking. ++ 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, see ++ . */ ++ ++#include ++ ++void ++xpthread_attr_setstack (pthread_attr_t *attr, void *stackaddr, size_t stacksize) ++{ ++ xpthread_check_return ("pthread_attr_setstack", ++ pthread_attr_setstack (attr, stackaddr, stacksize)); ++} +diff --git a/support/xthread.h b/support/xthread.h +index 9fe1f68b3b..5204f78ed2 100644 +--- a/support/xthread.h ++++ b/support/xthread.h +@@ -68,6 +68,8 @@ void xpthread_attr_destroy (pthread_attr_t *attr); + void xpthread_attr_init (pthread_attr_t *attr); + void xpthread_attr_setdetachstate (pthread_attr_t *attr, + int detachstate); ++void xpthread_attr_setstack (pthread_attr_t *attr, void *stackaddr, ++ size_t stacksize); + void xpthread_attr_setstacksize (pthread_attr_t *attr, + size_t stacksize); + void xpthread_attr_setguardsize (pthread_attr_t *attr, diff --git a/SOURCES/glibc-rh1764218-1.patch b/SOURCES/glibc-rh1764218-1.patch new file mode 100644 index 0000000..583f7a7 --- /dev/null +++ b/SOURCES/glibc-rh1764218-1.patch @@ -0,0 +1,192 @@ +commit cb89ba9c72f66327f5d66034681eb1d46eedf96f +Author: DJ Delorie +Date: Thu Aug 8 19:09:43 2019 -0400 + + Add glibc.malloc.mxfast tunable + + * elf/dl-tunables.list: Add glibc.malloc.mxfast. + * manual/tunables.texi: Document it. + * malloc/malloc.c (do_set_mxfast): New. + (__libc_mallopt): Call it. + * malloc/arena.c: Add mxfast tunable. + * malloc/tst-mxfast.c: New. + * malloc/Makefile: Add it. + + Reviewed-by: Carlos O'Donell + (cherry picked from commit c48d92b430c480de06762f80c104922239416826) + +diff --git a/elf/dl-tunables.list b/elf/dl-tunables.list +index 1f8ecb8437a0460f..1ff6fcb6f24f93a8 100644 +--- a/elf/dl-tunables.list ++++ b/elf/dl-tunables.list +@@ -85,6 +85,11 @@ glibc { + tcache_unsorted_limit { + type: SIZE_T + } ++ mxfast { ++ type: SIZE_T ++ minval: 0 ++ security_level: SXID_IGNORE ++ } + } + tune { + hwcap_mask { +diff --git a/malloc/Makefile b/malloc/Makefile +index 228a1279a5960d8c..bf9a53cb7c5ebacb 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-mxfast \ + + tests-static := \ + tst-interpose-static-nothread \ +@@ -196,6 +197,8 @@ tst-malloc-usable-static-ENV = $(tst-malloc-usable-ENV) + tst-malloc-usable-tunables-ENV = GLIBC_TUNABLES=glibc.malloc.check=3 + tst-malloc-usable-static-tunables-ENV = $(tst-malloc-usable-tunables-ENV) + ++tst-mxfast-ENV = GLIBC_TUNABLES=glibc.malloc.tcache_count=0:glibc.malloc.mxfast=0 ++ + ifeq ($(experimental-malloc),yes) + CPPFLAGS-malloc.c += -DUSE_TCACHE=1 + else +diff --git a/malloc/arena.c b/malloc/arena.c +index ff8fd5d2a7e51ac8..f5c7ad4570ad6186 100644 +--- a/malloc/arena.c ++++ b/malloc/arena.c +@@ -237,6 +237,7 @@ TUNABLE_CALLBACK_FNDECL (set_tcache_max, size_t) + TUNABLE_CALLBACK_FNDECL (set_tcache_count, size_t) + TUNABLE_CALLBACK_FNDECL (set_tcache_unsorted_limit, size_t) + #endif ++TUNABLE_CALLBACK_FNDECL (set_mxfast, size_t) + #else + /* Initialization routine. */ + #include +@@ -324,6 +325,7 @@ ptmalloc_init (void) + TUNABLE_GET (tcache_unsorted_limit, size_t, + TUNABLE_CALLBACK (set_tcache_unsorted_limit)); + # endif ++ TUNABLE_GET (mxfast, size_t, TUNABLE_CALLBACK (set_mxfast)); + #else + const char *s = NULL; + if (__glibc_likely (_environ != NULL)) +diff --git a/malloc/malloc.c b/malloc/malloc.c +index fcf480acdaea1b86..9756ed0a0d28c5f6 100644 +--- a/malloc/malloc.c ++++ b/malloc/malloc.c +@@ -5142,6 +5142,19 @@ do_set_tcache_unsorted_limit (size_t value) + } + #endif + ++static inline int ++__always_inline ++do_set_mxfast (size_t value) ++{ ++ if (value >= 0 && value <= MAX_FAST_SIZE) ++ { ++ LIBC_PROBE (memory_mallopt_mxfast, 2, value, get_max_fast ()); ++ set_max_fast (value); ++ return 1; ++ } ++ return 0; ++} ++ + int + __libc_mallopt (int param_number, int value) + { +@@ -5161,13 +5174,7 @@ __libc_mallopt (int param_number, int value) + switch (param_number) + { + case M_MXFAST: +- if (value >= 0 && value <= MAX_FAST_SIZE) +- { +- LIBC_PROBE (memory_mallopt_mxfast, 2, value, get_max_fast ()); +- set_max_fast (value); +- } +- else +- res = 0; ++ do_set_mxfast (value); + break; + + case M_TRIM_THRESHOLD: +diff --git a/malloc/tst-mxfast.c b/malloc/tst-mxfast.c +new file mode 100644 +index 0000000000000000..7a371d2f9d2f0005 +--- /dev/null ++++ b/malloc/tst-mxfast.c +@@ -0,0 +1,50 @@ ++/* Test that glibc.malloc.mxfast tunable works. ++ Copyright (C) 2018, 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, see ++ . */ ++ ++/* This test verifies that setting the glibc.malloc.mxfast tunable to ++ zero results in free'd blocks being returned to the small bins, not ++ the fast bins. */ ++ ++#include ++#include ++ ++int ++do_test(void) ++{ ++ struct mallinfo m; ++ char * volatile p1; ++ char * volatile p2; ++ ++ /* Arbitrary value; must be in default fastbin range. */ ++ p1 = malloc (3); ++ /* Something large so that p1 isn't a "top block" */ ++ p2 = malloc (512); ++ free (p1); ++ ++ m = mallinfo(); ++ ++ /* This will fail if there are any blocks in the fastbins. */ ++ assert (m.smblks == 0); ++ ++ /* To keep gcc happy. */ ++ free (p2); ++ ++ return 0; ++} ++ ++#include +diff --git a/manual/tunables.texi b/manual/tunables.texi +index f6c49250e3889ddd..3dc6f9a44592c030 100644 +--- a/manual/tunables.texi ++++ b/manual/tunables.texi +@@ -213,6 +213,18 @@ pre-fill the per-thread cache with. The default, or when set to zero, + is no limit. + @end deftp + ++@deftp Tunable glibc.malloc.mxfast ++One of the optimizations malloc uses is to maintain a series of ``fast ++bins'' that hold chunks up to a specific size. The default and ++maximum size which may be held this way is 80 bytes on 32-bit systems ++or 160 bytes on 64-bit systems. Applications which value size over ++speed may choose to reduce the size of requests which are serviced ++from fast bins with this tunable. Note that the value specified ++includes malloc's internal overhead, which is normally the size of one ++pointer, so add 4 on 32-bit systems or 8 on 64-bit systems to the size ++passed to @code{malloc} for the largest bin size to enable. ++@end deftp ++ + @node Elision Tunables + @section Elision Tunables + @cindex elision tunables diff --git a/SOURCES/glibc-rh1764218-2.patch b/SOURCES/glibc-rh1764218-2.patch new file mode 100644 index 0000000..8408975 --- /dev/null +++ b/SOURCES/glibc-rh1764218-2.patch @@ -0,0 +1,72 @@ +commit 5dab5eafb3dc2f72aaab911084d127d1af45a08c +Author: Florian Weimer +Date: Thu Aug 15 11:37:18 2019 +0200 + + malloc: Various cleanups for malloc/tst-mxfast + + (cherry picked from commit f9769a239784772453d595bc2f4bed8739810e06) + +diff --git a/malloc/Makefile b/malloc/Makefile +index bf9a53cb7c5ebacb..19c2a846ed8ce049 100644 +--- a/malloc/Makefile ++++ b/malloc/Makefile +@@ -39,7 +39,6 @@ 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-mxfast \ + + tests-static := \ + tst-interpose-static-nothread \ +@@ -55,7 +54,7 @@ tests-internal += \ + tst-dynarray-at-fail \ + + ifneq (no,$(have-tunables)) +-tests += tst-malloc-usable-tunables ++tests += tst-malloc-usable-tunables tst-mxfast + tests-static += tst-malloc-usable-static-tunables + endif + +diff --git a/malloc/tst-mxfast.c b/malloc/tst-mxfast.c +index 7a371d2f9d2f0005..7a7750bc71024bfb 100644 +--- a/malloc/tst-mxfast.c ++++ b/malloc/tst-mxfast.c +@@ -1,5 +1,5 @@ + /* Test that glibc.malloc.mxfast tunable works. +- Copyright (C) 2018, 2019 Free Software Foundation, Inc. ++ 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 +@@ -21,14 +21,14 @@ + the fast bins. */ + + #include +-#include ++#include + + int +-do_test(void) ++do_test (void) + { + struct mallinfo m; +- char * volatile p1; +- char * volatile p2; ++ char *volatile p1; ++ char *volatile p2; + + /* Arbitrary value; must be in default fastbin range. */ + p1 = malloc (3); +@@ -36,10 +36,10 @@ do_test(void) + p2 = malloc (512); + free (p1); + +- m = mallinfo(); ++ m = mallinfo (); + + /* This will fail if there are any blocks in the fastbins. */ +- assert (m.smblks == 0); ++ TEST_COMPARE (m.smblks, 0); + + /* To keep gcc happy. */ + free (p2); diff --git a/SOURCES/glibc-rh1764218-3.patch b/SOURCES/glibc-rh1764218-3.patch new file mode 100644 index 0000000..ba35b8e --- /dev/null +++ b/SOURCES/glibc-rh1764218-3.patch @@ -0,0 +1,31 @@ +commit f144981490bd2ab13189d85902ca74beecb307e4 +Author: DJ Delorie +Date: Wed Oct 30 18:03:14 2019 -0400 + + Base max_fast on alignment, not width, of bins (Bug 24903) + + set_max_fast sets the "impossibly small" value based on, + eventually, MALLOC_ALIGNMENT. The comparisons for the smallest + chunk used is, eventually, MIN_CHUNK_SIZE. Note that i386 + is the only platform where these are the same, so a smallest + chunk *would* be put in a no-fastbins fastbin. + + This change calculates the "impossibly small" value + based on MIN_CHUNK_SIZE instead, so that we can know it will + always be impossibly small. + + (cherry picked from commit ff12e0fb91b9072800f031cb21fb2651ee7b6251) + +diff --git a/malloc/malloc.c b/malloc/malloc.c +index 9756ed0a0d28c5f6..90825b2aaed53761 100644 +--- a/malloc/malloc.c ++++ b/malloc/malloc.c +@@ -1635,7 +1635,7 @@ static INTERNAL_SIZE_T global_max_fast; + + #define set_max_fast(s) \ + global_max_fast = (((s) == 0) \ +- ? SMALLBIN_WIDTH : ((s + SIZE_SZ) & ~MALLOC_ALIGN_MASK)) ++ ? MIN_CHUNK_SIZE / 2 : ((s + SIZE_SZ) & ~MALLOC_ALIGN_MASK)) + + static inline INTERNAL_SIZE_T + get_max_fast (void) diff --git a/SOURCES/glibc-rh1764223.patch b/SOURCES/glibc-rh1764223.patch new file mode 100644 index 0000000..372efaf --- /dev/null +++ b/SOURCES/glibc-rh1764223.patch @@ -0,0 +1,142 @@ +commit 2c75b545de6fe3c44138799c68217a94bc669a88 +Author: Florian Weimer +Date: Tue Jun 18 16:42:10 2019 +0200 + + elf: Refuse to dlopen PIE objects [BZ #24323] + + Another executable has already been mapped, so the dynamic linker + cannot perform relocations correctly for the second executable. + +diff --git a/elf/Makefile b/elf/Makefile +index 08e2f99..27a2fa8 100644 +--- a/elf/Makefile ++++ b/elf/Makefile +@@ -310,7 +310,7 @@ test-xfail-tst-protected1b = yes + endif + ifeq (yesyes,$(have-fpie)$(build-shared)) + modules-names += tst-piemod1 +-tests += tst-pie1 tst-pie2 ++tests += tst-pie1 tst-pie2 tst-dlopen-pie + tests-pie += tst-pie1 tst-pie2 + ifeq (yes,$(have-protected-data)) + tests += vismain +@@ -1084,6 +1084,8 @@ CFLAGS-tst-pie2.c += $(pie-ccflag) + + $(objpfx)tst-piemod1.so: $(libsupport) + $(objpfx)tst-pie1: $(objpfx)tst-piemod1.so ++$(objpfx)tst-dlopen-pie: $(libdl) ++$(objpfx)tst-dlopen-pie.out: $(objpfx)tst-pie1 + + ifeq (yes,$(build-shared)) + # NB: Please keep cet-built-dso in sysdeps/x86/Makefile in sync with +diff --git a/elf/dl-load.c b/elf/dl-load.c +index 2bbef81..5abeb86 100644 +--- a/elf/dl-load.c ++++ b/elf/dl-load.c +@@ -1158,6 +1158,10 @@ _dl_map_object_from_fd (const char *name, const char *origname, int fd, + goto call_lose; + } + ++ /* dlopen of an executable is not valid because it is not possible ++ to perform proper relocations, handle static TLS, or run the ++ ELF constructors. For PIE, the check needs the dynamic ++ section, so there is another check below. */ + if (__glibc_unlikely (type != ET_DYN) + && __glibc_unlikely ((mode & __RTLD_OPENEXEC) == 0)) + { +@@ -1194,9 +1198,11 @@ _dl_map_object_from_fd (const char *name, const char *origname, int fd, + elf_get_dynamic_info (l, NULL); + + /* Make sure we are not dlopen'ing an object that has the +- DF_1_NOOPEN flag set. */ +- if (__glibc_unlikely (l->l_flags_1 & DF_1_NOOPEN) +- && (mode & __RTLD_DLOPEN)) ++ DF_1_NOOPEN flag set, or a PIE object. */ ++ if ((__glibc_unlikely (l->l_flags_1 & DF_1_NOOPEN) ++ && (mode & __RTLD_DLOPEN)) ++ || (__glibc_unlikely (l->l_flags_1 & DF_1_PIE) ++ && __glibc_unlikely ((mode & __RTLD_OPENEXEC) == 0))) + { + /* We are not supposed to load this object. Free all resources. */ + _dl_unmap_segments (l); +@@ -1207,7 +1213,11 @@ _dl_map_object_from_fd (const char *name, const char *origname, int fd, + if (l->l_phdr_allocated) + free ((void *) l->l_phdr); + +- errstring = N_("shared object cannot be dlopen()ed"); ++ if (l->l_flags_1 & DF_1_PIE) ++ errstring ++ = N_("cannot dynamically load position-independent executable"); ++ else ++ errstring = N_("shared object cannot be dlopen()ed"); + goto call_lose; + } + +diff --git a/elf/tst-dlopen-pie.c b/elf/tst-dlopen-pie.c +new file mode 100644 +index 0000000..6a41c73 +--- /dev/null ++++ b/elf/tst-dlopen-pie.c +@@ -0,0 +1,49 @@ ++/* dlopen test for PIE objects. ++ 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, see ++ . */ ++ ++/* This test attempts to open the (otherwise unrelated) PIE test ++ program elf/tst-pie1 and expects the attempt to fail. */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++static void ++test_mode (int mode) ++{ ++ char *pie_path = xasprintf ("%s/elf/tst-pie1", support_objdir_root); ++ if (dlopen (pie_path, mode) != NULL) ++ FAIL_EXIT1 ("dlopen succeeded unexpectedly (%d)", mode); ++ const char *message = dlerror (); ++ const char *expected ++ = "cannot dynamically load position-independent executable"; ++ if (strstr (message, expected) == NULL) ++ FAIL_EXIT1 ("unexpected error message (mode %d): %s", mode, message); ++} ++ ++static int ++do_test (void) ++{ ++ test_mode (RTLD_LAZY); ++ test_mode (RTLD_NOW); ++ return 0; ++} ++ ++#include +diff --git a/include/elf.h b/include/elf.h +index ab76aaf..14ed67f 100644 +--- a/include/elf.h ++++ b/include/elf.h +@@ -23,7 +23,7 @@ + # endif + # define DT_1_SUPPORTED_MASK \ + (DF_1_NOW | DF_1_NODELETE | DF_1_INITFIRST | DF_1_NOOPEN \ +- | DF_1_ORIGIN | DF_1_NODEFLIB) ++ | DF_1_ORIGIN | DF_1_NODEFLIB | DF_1_PIE) + + #endif /* !_ISOMAC */ + #endif /* elf.h */ diff --git a/SOURCES/glibc-rh1764226-1.patch b/SOURCES/glibc-rh1764226-1.patch new file mode 100644 index 0000000..44035fe --- /dev/null +++ b/SOURCES/glibc-rh1764226-1.patch @@ -0,0 +1,82 @@ +commit 6c29942cbf059aca47fd4bbd852ea42c9d46b71f +Author: Stefan Liebler +Date: Mon Feb 18 16:12:01 2019 +0100 + + misc/tst-clone3: Fix waiting for exited thread. + + From time to time the test misc/tst-clone3 fails with a timeout. + Then futex_wait is blocking. Usually ctid should be set to zero + due to CLONE_CHILD_CLEARTID and the futex should be waken up. + But the fail occures if the thread has already exited before + ctid is set to the return value of clone(). Then futex_wait() will + block as there will be nobody who wakes the futex up again. + + This patch initializes ctid to a known value before calling clone + and the kernel is the only one who updates the value to zero after clone. + If futex_wait is called then it is either waked up due to the exited thread + or the futex syscall fails as *ctid_ptr is already zero instead of the + specified value 1. + + ChangeLog: + + * sysdeps/unix/sysv/linux/tst-clone3.c (do_test): + Initialize ctid with a known value and remove update of ctid + after clone. + (wait_tid): Adjust arguments and call futex_wait with ctid_val + as assumed current value of ctid_ptr. + +diff --git a/sysdeps/unix/sysv/linux/tst-clone3.c b/sysdeps/unix/sysv/linux/tst-clone3.c +index 784ce18f5343ec72..9f1ed6355e7acffd 100644 +--- a/sysdeps/unix/sysv/linux/tst-clone3.c ++++ b/sysdeps/unix/sysv/linux/tst-clone3.c +@@ -27,6 +27,7 @@ + + #include /* For _STACK_GROWS_{UP,DOWN}. */ + #include ++#include + + /* Test if clone call with CLONE_THREAD does not call exit_group. The 'f' + function returns '1', which will be used by clone thread to call the +@@ -42,11 +43,14 @@ f (void *a) + + /* Futex wait for TID argument, similar to pthread_join internal + implementation. */ +-#define wait_tid(tid) \ +- do { \ +- __typeof (tid) __tid; \ +- while ((__tid = (tid)) != 0) \ +- futex_wait (&(tid), __tid); \ ++#define wait_tid(ctid_ptr, ctid_val) \ ++ do { \ ++ __typeof (*(ctid_ptr)) __tid; \ ++ /* We need acquire MO here so that we synchronize with the \ ++ kernel's store to 0 when the clone terminates. */ \ ++ while ((__tid = atomic_load_explicit (ctid_ptr, \ ++ memory_order_acquire)) != 0) \ ++ futex_wait (ctid_ptr, ctid_val); \ + } while (0) + + static inline int +@@ -64,7 +68,11 @@ do_test (void) + clone_flags |= CLONE_VM | CLONE_SIGHAND; + /* We will used ctid to call on futex to wait for thread exit. */ + clone_flags |= CLONE_CHILD_CLEARTID; +- pid_t ctid, tid; ++ /* Initialize with a known value. ctid is set to zero by the kernel after the ++ cloned thread has exited. */ ++#define CTID_INIT_VAL 1 ++ pid_t ctid = CTID_INIT_VAL; ++ pid_t tid; + + #ifdef __ia64__ + extern int __clone2 (int (*__fn) (void *__arg), void *__child_stack_base, +@@ -86,8 +94,7 @@ do_test (void) + if (tid == -1) + FAIL_EXIT1 ("clone failed: %m"); + +- ctid = tid; +- wait_tid (ctid); ++ wait_tid (&ctid, CTID_INIT_VAL); + + return 2; + } diff --git a/SOURCES/glibc-rh1764226-2.patch b/SOURCES/glibc-rh1764226-2.patch new file mode 100644 index 0000000..69902cc --- /dev/null +++ b/SOURCES/glibc-rh1764226-2.patch @@ -0,0 +1,159 @@ +commit 481c30cb9573a280649fbf27251e6a0f4af1b2b1 +Author: Alexandra Hájková +Date: Thu May 9 13:51:40 2019 +0200 + + elf: Add tst-ldconfig-bad-aux-cache test [BZ #18093] + + This test corrupts /var/cache/ldconfig/aux-cache and executes ldconfig + to check it will not segfault using the corrupted aux_cache. The test + uses the test-in-container framework. Verified no regressions on + x86_64. + +diff --git a/elf/Makefile b/elf/Makefile +index 139d072e136284e1..8e907e69eb35e089 100644 +--- a/elf/Makefile ++++ b/elf/Makefile +@@ -156,6 +156,9 @@ tests-static-internal := tst-tls1-static tst-tls2-static \ + 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 ++ + tests := tst-tls9 tst-leaks1 \ + tst-array1 tst-array2 tst-array3 tst-array4 tst-array5 \ + tst-auxv +diff --git a/elf/tst-ldconfig-bad-aux-cache.c b/elf/tst-ldconfig-bad-aux-cache.c +new file mode 100644 +index 0000000000000000..68ce90a95648f6ab +--- /dev/null ++++ b/elf/tst-ldconfig-bad-aux-cache.c +@@ -0,0 +1,117 @@ ++/* Test ldconfig does not segfault when aux-cache is corrupted (Bug 18093). ++ 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; see the file COPYING.LIB. If ++ not, see . */ ++ ++/* This test does the following: ++ Run ldconfig to create the caches. ++ Corrupt the caches. ++ Run ldconfig again. ++ At each step we verify that ldconfig does not crash. */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++ ++#include ++ ++static int ++display_info (const char *fpath, const struct stat *sb, ++ int tflag, struct FTW *ftwbuf) ++{ ++ printf ("info: %-3s %2d %7jd %-40s %d %s\n", ++ (tflag == FTW_D) ? "d" : (tflag == FTW_DNR) ? "dnr" : ++ (tflag == FTW_DP) ? "dp" : (tflag == FTW_F) ? "f" : ++ (tflag == FTW_NS) ? "ns" : (tflag == FTW_SL) ? "sl" : ++ (tflag == FTW_SLN) ? "sln" : "???", ++ ftwbuf->level, (intmax_t) sb->st_size, ++ fpath, ftwbuf->base, fpath + ftwbuf->base); ++ /* To tell nftw to continue. */ ++ return 0; ++} ++ ++/* Run ldconfig with a corrupt aux-cache, in particular we test for size ++ truncation that might happen if a previous ldconfig run failed or if ++ there were storage or power issues while we were writing the file. ++ We want ldconfig not to crash, and it should be able to do so by ++ computing the expected size of the file (bug 18093). */ ++static int ++do_test (void) ++{ ++ char *prog = xasprintf ("%s/ldconfig", support_install_rootsbindir); ++ char *const args[] = { prog, NULL }; ++ const char *path = "/var/cache/ldconfig/aux-cache"; ++ struct stat64 fs; ++ long int size, new_size, i; ++ int status; ++ pid_t pid; ++ ++ /* Create the needed directories. */ ++ xmkdirp ("/var/cache/ldconfig", 0777); ++ ++ pid = xfork (); ++ /* Run ldconfig fist to generate the aux-cache. */ ++ if (pid == 0) ++ { ++ execv (args[0], args); ++ _exit (1); ++ } ++ else ++ { ++ xwaitpid (pid, &status, 0); ++ TEST_COMPARE(status, 0); ++ xstat (path, &fs); ++ ++ size = fs.st_size; ++ /* Run 3 tests, each truncating aux-cache shorter and shorter. */ ++ for (i = 3; i > 0; i--) ++ { ++ new_size = size * i / 4; ++ if (truncate (path, new_size)) ++ FAIL_EXIT1 ("truncation failed: %m"); ++ if (nftw (path, display_info, 1000, 0) == -1) ++ FAIL_EXIT1 ("nftw failed."); ++ ++ pid = xfork (); ++ /* Verify that ldconfig can run with a truncated ++ aux-cache and doesn't crash. */ ++ if (pid == 0) ++ { ++ execv (args[0], args); ++ _exit (1); ++ } ++ else ++ { ++ xwaitpid (pid, &status, 0); ++ TEST_COMPARE(status, 0); ++ } ++ } ++ } ++ ++ free (prog); ++ return 0; ++} ++ ++#include +diff --git a/elf/tst-ldconfig-bad-aux-cache.root/etc/ld.so.conf b/elf/tst-ldconfig-bad-aux-cache.root/etc/ld.so.conf +new file mode 100644 +index 0000000000000000..e1e74dbda2bf3dfa +--- /dev/null ++++ b/elf/tst-ldconfig-bad-aux-cache.root/etc/ld.so.conf +@@ -0,0 +1,2 @@ ++# This file was created to suppress a warning from ldconfig: ++# /sbin/ldconfig: Warning: ignoring configuration file that cannot be opened: /etc/ld.so.conf: No such file or directory +diff --git a/elf/tst-ldconfig-bad-aux-cache.root/postclean.req b/elf/tst-ldconfig-bad-aux-cache.root/postclean.req +new file mode 100644 +index 0000000000000000..e69de29bb2d1d643 diff --git a/SOURCES/glibc-rh1764226-3.patch b/SOURCES/glibc-rh1764226-3.patch new file mode 100644 index 0000000..cda312f --- /dev/null +++ b/SOURCES/glibc-rh1764226-3.patch @@ -0,0 +1,112 @@ +commit a6c1ce778e5c05a2e6925883b410157ef47654fd +Author: Alexandra Hájková +Date: Mon Aug 5 13:18:57 2019 +0200 + + elf: tst-ldconfig-bad-aux-cache: use support_capture_subprocess + +diff --git a/elf/tst-ldconfig-bad-aux-cache.c b/elf/tst-ldconfig-bad-aux-cache.c +index 68ce90a95648f6ab..6e22ff815eaaa817 100644 +--- a/elf/tst-ldconfig-bad-aux-cache.c ++++ b/elf/tst-ldconfig-bad-aux-cache.c +@@ -31,6 +31,7 @@ + #include + #include + ++#include + #include + #include + #include +@@ -52,6 +53,15 @@ display_info (const char *fpath, const struct stat *sb, + return 0; + } + ++static void ++execv_wrapper (void *args) ++{ ++ char **argv = args; ++ ++ execv (argv[0], argv); ++ FAIL_EXIT1 ("execv: %m"); ++} ++ + /* Run ldconfig with a corrupt aux-cache, in particular we test for size + truncation that might happen if a previous ldconfig run failed or if + there were storage or power issues while we were writing the file. +@@ -61,53 +71,38 @@ static int + do_test (void) + { + char *prog = xasprintf ("%s/ldconfig", support_install_rootsbindir); +- char *const args[] = { prog, NULL }; ++ char *args[] = { prog, NULL }; + const char *path = "/var/cache/ldconfig/aux-cache"; + struct stat64 fs; + long int size, new_size, i; +- int status; +- pid_t pid; + + /* Create the needed directories. */ + xmkdirp ("/var/cache/ldconfig", 0777); + +- pid = xfork (); +- /* Run ldconfig fist to generate the aux-cache. */ +- if (pid == 0) +- { +- execv (args[0], args); +- _exit (1); +- } +- else ++ /* Run ldconfig first to generate the aux-cache. */ ++ struct support_capture_subprocess result; ++ result = support_capture_subprocess (execv_wrapper, args); ++ support_capture_subprocess_check (&result, "execv", 0, sc_allow_none); ++ support_capture_subprocess_free (&result); ++ ++ xstat (path, &fs); ++ ++ size = fs.st_size; ++ /* Run 3 tests, each truncating aux-cache shorter and shorter. */ ++ for (i = 3; i > 0; i--) + { +- xwaitpid (pid, &status, 0); +- TEST_COMPARE(status, 0); +- xstat (path, &fs); +- +- size = fs.st_size; +- /* Run 3 tests, each truncating aux-cache shorter and shorter. */ +- for (i = 3; i > 0; i--) +- { +- new_size = size * i / 4; +- if (truncate (path, new_size)) +- FAIL_EXIT1 ("truncation failed: %m"); +- if (nftw (path, display_info, 1000, 0) == -1) +- FAIL_EXIT1 ("nftw failed."); +- +- pid = xfork (); +- /* Verify that ldconfig can run with a truncated +- aux-cache and doesn't crash. */ +- if (pid == 0) +- { +- execv (args[0], args); +- _exit (1); +- } +- else +- { +- xwaitpid (pid, &status, 0); +- TEST_COMPARE(status, 0); +- } +- } ++ new_size = size * i / 4; ++ if (truncate (path, new_size)) ++ FAIL_EXIT1 ("truncation failed: %m"); ++ if (nftw (path, display_info, 1000, 0) == -1) ++ FAIL_EXIT1 ("nftw failed."); ++ ++ /* Verify that ldconfig can run with a truncated ++ aux-cache and doesn't crash. */ ++ struct support_capture_subprocess result; ++ result = support_capture_subprocess (execv_wrapper, args); ++ support_capture_subprocess_check (&result, "execv", 0, sc_allow_none); ++ support_capture_subprocess_free (&result); + } + + free (prog); diff --git a/SOURCES/glibc-rh1764231-1.patch b/SOURCES/glibc-rh1764231-1.patch new file mode 100644 index 0000000..f879427 --- /dev/null +++ b/SOURCES/glibc-rh1764231-1.patch @@ -0,0 +1,49 @@ +commit 17432d7150bdab3bce2ea66c70ad6c920f54077a +Author: Florian Weimer +Date: Fri Jun 28 10:15:30 2019 +0200 + + support: Add xdlvsym function + +diff --git a/support/xdlfcn.c b/support/xdlfcn.c +index f34bb059c00f27f7..b4a6b85649d181c8 100644 +--- a/support/xdlfcn.c ++++ b/support/xdlfcn.c +@@ -48,6 +48,26 @@ xdlsym (void *handle, const char *symbol) + return sym; + } + ++void * ++xdlvsym (void *handle, const char *symbol, const char *version) ++{ ++ /* Clear any pending errors. */ ++ dlerror (); ++ ++ void *sym = dlvsym (handle, symbol, version); ++ ++ if (sym == NULL) ++ { ++ const char *error = dlerror (); ++ if (error != NULL) ++ FAIL_EXIT1 ("error: dlvsym: %s\n", error); ++ /* If there was no error, we found a NULL symbol. Return the ++ NULL value in this case. */ ++ } ++ ++ return sym; ++} ++ + void + xdlclose (void *handle) + { +diff --git a/support/xdlfcn.h b/support/xdlfcn.h +index 5ab7494e70924f52..ab1cbb3cb9bb1cc7 100644 +--- a/support/xdlfcn.h ++++ b/support/xdlfcn.h +@@ -26,6 +26,7 @@ __BEGIN_DECLS + /* Each of these terminates process on failure with relevant error message. */ + void *xdlopen (const char *filename, int flags); + void *xdlsym (void *handle, const char *symbol); ++void *xdlvsym (void *handle, const char *symbol, const char *version); + void xdlclose (void *handle); + + diff --git a/SOURCES/glibc-rh1764231-2.patch b/SOURCES/glibc-rh1764231-2.patch new file mode 100644 index 0000000..aaff767 --- /dev/null +++ b/SOURCES/glibc-rh1764231-2.patch @@ -0,0 +1,342 @@ +commit f0b2132b35248c1f4a80f62a2c38cddcc802aa8c +Author: Florian Weimer +Date: Fri Jun 28 10:12:50 2019 +0200 + + ld.so: Support moving versioned symbols between sonames [BZ #24741] + + This change should be fully backwards-compatible because the old + code aborted the load if a soname mismatch was encountered + (instead of searching further for a matching symbol). This means + that no different symbols are found. + + The soname check was explicitly disabled for the skip_map != NULL + case. However, this only happens with dl(v)sym and RTLD_NEXT, + and those lookups do not come with a verneed entry that could be used + for the check. + + The error check was already explicitly disabled for the skip_map != + NULL case, that is, when dl(v)sym was called with RTLD_NEXT. But + _dl_vsym always sets filename in the struct r_found_version argument + to NULL, so the check was not active anyway. This means that + symbol lookup results for the skip_map != NULL case do not change, + either. + +Conflicts: + elf/Makefile + (usual missing backports) + +diff --git a/elf/Makefile b/elf/Makefile +index 29aa3a96738e4176..73f9e25ea5efd63a 100644 +--- a/elf/Makefile ++++ b/elf/Makefile +@@ -187,7 +187,8 @@ tests += restest1 preloadtest loadfail multiload origtest resolvfail \ + 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-debug1 tst-main1 tst-absolute-sym tst-absolute-zero tst-big-note \ ++ tst-sonamemove-link tst-sonamemove-dlopen + # reldep9 + tests-internal += loadtest unload unload2 circleload1 \ + neededtest neededtest2 neededtest3 neededtest4 \ +@@ -275,7 +276,9 @@ modules-names = testobj1 testobj2 testobj3 testobj4 testobj5 testobj6 \ + tst-latepthreadmod $(tst-tls-many-dynamic-modules) \ + 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-absolute-zero-lib tst-big-note-lib \ ++ tst-sonamemove-linkmod1 \ ++ tst-sonamemove-runmod1 tst-sonamemove-runmod2 + + ifeq (yes,$(have-mtls-dialect-gnu2)) + tests += tst-gnu2-tls1 +@@ -1374,6 +1377,28 @@ tst-audit12-ENV = LD_AUDIT=$(objpfx)tst-auditmod12.so + $(objpfx)tst-audit12mod1.so: $(objpfx)tst-audit12mod2.so + LDFLAGS-tst-audit12mod2.so = -Wl,--version-script=tst-audit12mod2.map + ++# tst-sonamemove links against an older implementation of the library. ++LDFLAGS-tst-sonamemove-linkmod1.so = \ ++ -Wl,--version-script=tst-sonamemove-linkmod1.map \ ++ -Wl,-soname,tst-sonamemove-runmod1.so ++LDFLAGS-tst-sonamemove-runmod1.so = -Wl,--no-as-needed \ ++ -Wl,--version-script=tst-sonamemove-runmod1.map \ ++ -Wl,-soname,tst-sonamemove-runmod1.so ++LDFLAGS-tst-sonamemove-runmod2.so = \ ++ -Wl,--version-script=tst-sonamemove-runmod2.map \ ++ -Wl,-soname,tst-sonamemove-runmod2.so ++$(objpfx)tst-sonamemove-runmod1.so: $(objpfx)tst-sonamemove-runmod2.so ++# Link against the link module, but depend on the run-time modules ++# for execution. ++$(objpfx)tst-sonamemove-link: $(objpfx)tst-sonamemove-linkmod1.so ++$(objpfx)tst-sonamemove-link.out: \ ++ $(objpfx)tst-sonamemove-runmod1.so \ ++ $(objpfx)tst-sonamemove-runmod2.so ++$(objpfx)tst-sonamemove-dlopen: $(libdl) ++$(objpfx)tst-sonamemove-dlopen.out: \ ++ $(objpfx)tst-sonamemove-runmod1.so \ ++ $(objpfx)tst-sonamemove-runmod2.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-lookup.c b/elf/dl-lookup.c +index 68ecc6179f608547..1d046caf017b582b 100644 +--- a/elf/dl-lookup.c ++++ b/elf/dl-lookup.c +@@ -536,11 +536,7 @@ do_lookup_x (const char *undef_name, uint_fast32_t new_hash, + } + + skip: +- /* If this current map is the one mentioned in the verneed entry +- and we have not found a weak entry, it is a bug. */ +- if (symidx == STN_UNDEF && version != NULL && version->filename != NULL +- && __glibc_unlikely (_dl_name_match_p (version->filename, map))) +- return -1; ++ ; + } + while (++i < n); + +@@ -810,34 +806,10 @@ _dl_lookup_symbol_x (const char *undef_name, struct link_map *undef_map, + + /* Search the relevant loaded objects for a definition. */ + for (size_t start = i; *scope != NULL; start = 0, ++scope) +- { +- int res = do_lookup_x (undef_name, new_hash, &old_hash, *ref, +- ¤t_value, *scope, start, version, flags, +- skip_map, type_class, undef_map); +- if (res > 0) +- break; +- +- if (__glibc_unlikely (res < 0) && skip_map == NULL) +- { +- /* Oh, oh. The file named in the relocation entry does not +- contain the needed symbol. This code is never reached +- for unversioned lookups. */ +- assert (version != NULL); +- const char *reference_name = undef_map ? undef_map->l_name : ""; +- struct dl_exception exception; +- /* XXX We cannot translate the message. */ +- _dl_exception_create_format +- (&exception, DSO_FILENAME (reference_name), +- "symbol %s version %s not defined in file %s" +- " with link time reference%s", +- undef_name, version->name, version->filename, +- res == -2 ? " (no version symbols)" : ""); +- _dl_signal_cexception (0, &exception, N_("relocation error")); +- _dl_exception_free (&exception); +- *ref = NULL; +- return 0; +- } +- } ++ if (do_lookup_x (undef_name, new_hash, &old_hash, *ref, ++ ¤t_value, *scope, start, version, flags, ++ skip_map, type_class, undef_map) != 0) ++ break; + + if (__glibc_unlikely (current_value.s == NULL)) + { +diff --git a/elf/tst-sonamemove-dlopen.c b/elf/tst-sonamemove-dlopen.c +new file mode 100644 +index 0000000000000000..c496705044cdd53c +--- /dev/null ++++ b/elf/tst-sonamemove-dlopen.c +@@ -0,0 +1,35 @@ ++/* Check that a moved versioned symbol can be found using dlsym, dlvsym. ++ 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, see ++ . */ ++ ++#include ++#include ++#include ++ ++static int ++do_test (void) ++{ ++ /* tst-sonamemove-runmod1.so does not define moved_function, but it ++ depends on tst-sonamemove-runmod2.so, which does. */ ++ void *handle = xdlopen ("tst-sonamemove-runmod1.so", RTLD_NOW); ++ TEST_VERIFY (xdlsym (handle, "moved_function") != NULL); ++ TEST_VERIFY (xdlvsym (handle, "moved_function", "SONAME_MOVE") != NULL); ++ ++ return 0; ++} ++ ++#include +diff --git a/elf/tst-sonamemove-link.c b/elf/tst-sonamemove-link.c +new file mode 100644 +index 0000000000000000..4bc3bf32f88f97a9 +--- /dev/null ++++ b/elf/tst-sonamemove-link.c +@@ -0,0 +1,41 @@ ++/* Check that a versioned symbol can move from one library to another. ++ 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, see ++ . */ ++ ++/* At link time, moved_function is bound to the symbol version ++ SONAME_MOVE in tst-sonamemove-runmod1.so, using the ++ tst-sonamemove-linkmod1.so stub object. ++ ++ At run time, the process loads the real tst-sonamemove-runmod1.so, ++ which depends on tst-sonamemove-runmod2.so. ++ tst-sonamemove-runmod1.so does not define moved_function, but ++ tst-sonamemove-runmod2.so does. ++ ++ The net effect is that the versioned symbol ++ moved_function@SONAME_MOVE moved from the soname ++ tst-sonamemove-linkmod1.so at link time to the soname ++ tst-sonamemove-linkmod2.so at run time. */ ++void moved_function (void); ++ ++static int ++do_test (void) ++{ ++ moved_function (); ++ return 0; ++} ++ ++#include +diff --git a/elf/tst-sonamemove-linkmod1.c b/elf/tst-sonamemove-linkmod1.c +new file mode 100644 +index 0000000000000000..b8a354e5e394f566 +--- /dev/null ++++ b/elf/tst-sonamemove-linkmod1.c +@@ -0,0 +1,25 @@ ++/* Link interface for (lack of) soname matching in versioned symbol refs. ++ 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, see ++ . */ ++ ++/* This function moved from tst-sonamemove-runmod1.so. This module is ++ intended for linking only, to simulate an old application which was ++ linked against an older version of the library. */ ++void ++moved_function (void) ++{ ++} +diff --git a/elf/tst-sonamemove-linkmod1.map b/elf/tst-sonamemove-linkmod1.map +new file mode 100644 +index 0000000000000000..8fe5904018972009 +--- /dev/null ++++ b/elf/tst-sonamemove-linkmod1.map +@@ -0,0 +1,3 @@ ++SONAME_MOVE { ++ global: moved_function; ++}; +diff --git a/elf/tst-sonamemove-runmod1.c b/elf/tst-sonamemove-runmod1.c +new file mode 100644 +index 0000000000000000..5c409e22898bc836 +--- /dev/null ++++ b/elf/tst-sonamemove-runmod1.c +@@ -0,0 +1,23 @@ ++/* Run-time module whose moved_function moved to a library dependency. ++ 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, see ++ . */ ++ ++/* Dummy function to add the required symbol version. */ ++void ++other_function (void) ++{ ++} +diff --git a/elf/tst-sonamemove-runmod1.map b/elf/tst-sonamemove-runmod1.map +new file mode 100644 +index 0000000000000000..2ea81c6e6ffae2be +--- /dev/null ++++ b/elf/tst-sonamemove-runmod1.map +@@ -0,0 +1,3 @@ ++SONAME_MOVE { ++ global: other_function; ++}; +diff --git a/elf/tst-sonamemove-runmod2.c b/elf/tst-sonamemove-runmod2.c +new file mode 100644 +index 0000000000000000..b5e482eff57d7d83 +--- /dev/null ++++ b/elf/tst-sonamemove-runmod2.c +@@ -0,0 +1,24 @@ ++/* Run-time module with the actual implementation of moved_function. ++ 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, see ++ . */ ++ ++/* In the test scenario, this function was originally in ++ tst-sonamemove-runmod1.so. */ ++void ++moved_function (void) ++{ ++} +diff --git a/elf/tst-sonamemove-runmod2.map b/elf/tst-sonamemove-runmod2.map +new file mode 100644 +index 0000000000000000..8fe5904018972009 +--- /dev/null ++++ b/elf/tst-sonamemove-runmod2.map +@@ -0,0 +1,3 @@ ++SONAME_MOVE { ++ global: moved_function; ++}; diff --git a/SOURCES/glibc-rh1764234-1.patch b/SOURCES/glibc-rh1764234-1.patch new file mode 100644 index 0000000..0bbcf35 --- /dev/null +++ b/SOURCES/glibc-rh1764234-1.patch @@ -0,0 +1,40 @@ +commit 47ad5e1a2a3ab8eeda491454cbef3b1c5239dc02 +Author: Joseph Myers +Date: Tue Jan 1 02:01:02 2019 +0000 + + Update syscall-names.list for Linux 4.20. + + This patch updates sysdeps/unix/sysv/linux/syscall-names.list for + Linux 4.20. Although there are no new syscalls, the + riscv_flush_icache syscall has moved to asm/unistd.h (previously in + asm/syscalls.h) and so now needs to be added to the list. + + Tested with build-many-glibcs.py. + + * sysdeps/unix/sysv/linux/syscall-names.list: Update kernel + version to 4.20. + (riscv_flush_icache): New syscall. + +diff --git a/sysdeps/unix/sysv/linux/syscall-names.list b/sysdeps/unix/sysv/linux/syscall-names.list +index 698069a52d..b650dc07cc 100644 +--- a/sysdeps/unix/sysv/linux/syscall-names.list ++++ b/sysdeps/unix/sysv/linux/syscall-names.list +@@ -22,8 +22,8 @@ + # names are only used if the installed kernel headers also provide + # them. + +-# The list of system calls is current as of Linux 4.19. +-kernel 4.19 ++# The list of system calls is current as of Linux 4.20. ++kernel 4.20 + + FAST_atomic_update + FAST_cmpxchg +@@ -431,6 +431,7 @@ renameat + renameat2 + request_key + restart_syscall ++riscv_flush_icache + rmdir + rseq + rt_sigaction diff --git a/SOURCES/glibc-rh1764234-2.patch b/SOURCES/glibc-rh1764234-2.patch new file mode 100644 index 0000000..d8d5245 --- /dev/null +++ b/SOURCES/glibc-rh1764234-2.patch @@ -0,0 +1,43 @@ +commit 477e739b324349df854209117047779ac3142130 +Author: Joseph Myers +Date: Fri Mar 15 18:18:40 2019 +0000 + + Update syscall-names.list for Linux 5.0. + + This patch updates sysdeps/unix/sysv/linux/syscall-names.list for + Linux 5.0. Based on testing with build-many-glibcs.py, the only new + entry needed is for old_getpagesize (a newly added __NR_* name for an + old syscall on ia64). (Because 5.0 changes how syscall tables are + handled in the kernel, checking diffs wasn't a useful way of looking + for new syscalls in 5.0 as most of the syscall tables were moved to + the new representation without actually adding any syscalls to them.) + + Tested with build-many-glibcs.py. + + * sysdeps/unix/sysv/linux/syscall-names.list: Update kernel + version to 5.0. + (old_getpagesize): New syscall. + +diff --git a/sysdeps/unix/sysv/linux/syscall-names.list b/sysdeps/unix/sysv/linux/syscall-names.list +index b650dc07cc..0227e52a5f 100644 +--- a/sysdeps/unix/sysv/linux/syscall-names.list ++++ b/sysdeps/unix/sysv/linux/syscall-names.list +@@ -22,8 +22,8 @@ + # names are only used if the installed kernel headers also provide + # them. + +-# The list of system calls is current as of Linux 4.20. +-kernel 4.20 ++# The list of system calls is current as of Linux 5.0. ++kernel 5.0 + + FAST_atomic_update + FAST_cmpxchg +@@ -261,6 +261,7 @@ nfsservctl + ni_syscall + nice + old_adjtimex ++old_getpagesize + oldfstat + oldlstat + oldolduname diff --git a/SOURCES/glibc-rh1764234-3.patch b/SOURCES/glibc-rh1764234-3.patch new file mode 100644 index 0000000..a336060 --- /dev/null +++ b/SOURCES/glibc-rh1764234-3.patch @@ -0,0 +1,181 @@ +commit 7621676f7a5130c030f7fff1cab72dbf2993b837 +Author: Joseph Myers +Date: Tue May 7 23:57:26 2019 +0000 + + Update syscall-names.list for Linux 5.1. + + This patch updates syscall-names.list for Linux 5.1 (which has many + new syscalls, mainly but not entirely ones for 64-bit time). + + Tested with build-many-glibcs.py (before the revert of the move to + Linux 5.1 there; verified there were no tst-syscall-list failures). + + * sysdeps/unix/sysv/linux/syscall-names.list: Update kernel + version to 5.1. + (clock_adjtime64) New syscall. + (clock_getres_time64) Likewise. + (clock_gettime64) Likewise. + (clock_nanosleep_time64) Likewise. + (clock_settime64) Likewise. + (futex_time64) Likewise. + (io_pgetevents_time64) Likewise. + (io_uring_enter) Likewise. + (io_uring_register) Likewise. + (io_uring_setup) Likewise. + (mq_timedreceive_time64) Likewise. + (mq_timedsend_time64) Likewise. + (pidfd_send_signal) Likewise. + (ppoll_time64) Likewise. + (pselect6_time64) Likewise. + (recvmmsg_time64) Likewise. + (rt_sigtimedwait_time64) Likewise. + (sched_rr_get_interval_time64) Likewise. + (semtimedop_time64) Likewise. + (timer_gettime64) Likewise. + (timer_settime64) Likewise. + (timerfd_gettime64) Likewise. + (timerfd_settime64) Likewise. + (utimensat_time64) Likewise. + +diff --git a/sysdeps/unix/sysv/linux/syscall-names.list b/sysdeps/unix/sysv/linux/syscall-names.list +index 0227e52a5f..2d0354b8b3 100644 +--- a/sysdeps/unix/sysv/linux/syscall-names.list ++++ b/sysdeps/unix/sysv/linux/syscall-names.list +@@ -22,8 +22,8 @@ + # names are only used if the installed kernel headers also provide + # them. + +-# The list of system calls is current as of Linux 5.0. +-kernel 5.0 ++# The list of system calls is current as of Linux 5.1. ++kernel 5.1 + + FAST_atomic_update + FAST_cmpxchg +@@ -63,10 +63,15 @@ chown + chown32 + chroot + clock_adjtime ++clock_adjtime64 + clock_getres ++clock_getres_time64 + clock_gettime ++clock_gettime64 + clock_nanosleep ++clock_nanosleep_time64 + clock_settime ++clock_settime64 + clone + clone2 + close +@@ -128,6 +133,7 @@ ftime + ftruncate + ftruncate64 + futex ++futex_time64 + futimesat + get_kernel_syms + get_mempolicy +@@ -187,8 +193,12 @@ io_cancel + io_destroy + io_getevents + io_pgetevents ++io_pgetevents_time64 + io_setup + io_submit ++io_uring_enter ++io_uring_register ++io_uring_setup + ioctl + ioperm + iopl +@@ -242,7 +252,9 @@ mq_getsetattr + mq_notify + mq_open + mq_timedreceive ++mq_timedreceive_time64 + mq_timedsend ++mq_timedsend_time64 + mq_unlink + mremap + msgctl +@@ -389,6 +401,7 @@ perf_event_open + perfctr + perfmonctl + personality ++pidfd_send_signal + pipe + pipe2 + pivot_root +@@ -397,6 +410,7 @@ pkey_free + pkey_mprotect + poll + ppoll ++ppoll_time64 + prctl + pread64 + preadv +@@ -407,6 +421,7 @@ process_vm_writev + prof + profil + pselect6 ++pselect6_time64 + ptrace + putpmsg + pwrite64 +@@ -424,6 +439,7 @@ reboot + recv + recvfrom + recvmmsg ++recvmmsg_time64 + recvmsg + remap_file_pages + removexattr +@@ -442,6 +458,7 @@ rt_sigqueueinfo + rt_sigreturn + rt_sigsuspend + rt_sigtimedwait ++rt_sigtimedwait_time64 + rt_tgsigqueueinfo + rtas + s390_guarded_storage +@@ -457,6 +474,7 @@ sched_getattr + sched_getparam + sched_getscheduler + sched_rr_get_interval ++sched_rr_get_interval_time64 + sched_set_affinity + sched_setaffinity + sched_setattr +@@ -470,6 +488,7 @@ semctl + semget + semop + semtimedop ++semtimedop_time64 + send + sendfile + sendfile64 +@@ -567,11 +586,15 @@ timer_create + timer_delete + timer_getoverrun + timer_gettime ++timer_gettime64 + timer_settime ++timer_settime64 + timerfd + timerfd_create + timerfd_gettime ++timerfd_gettime64 + timerfd_settime ++timerfd_settime64 + times + tkill + truncate +@@ -591,6 +614,7 @@ userfaultfd + ustat + utime + utimensat ++utimensat_time64 + utimes + utrap_install + vfork diff --git a/SOURCES/glibc-rh1764234-4.patch b/SOURCES/glibc-rh1764234-4.patch new file mode 100644 index 0000000..5488fe1 --- /dev/null +++ b/SOURCES/glibc-rh1764234-4.patch @@ -0,0 +1,58 @@ +commit 0bb8f8c791862a4ff38a584af23bbb5bf3f90acd +Author: Florian Weimer +Date: Fri May 31 13:52:16 2019 +0200 + + Linux: Add oddly-named arm syscalls to syscall-names.list + + on arm defines the following macros: + + #define __ARM_NR_breakpoint (__ARM_NR_BASE+1) + #define __ARM_NR_cacheflush (__ARM_NR_BASE+2) + #define __ARM_NR_usr26 (__ARM_NR_BASE+3) + #define __ARM_NR_usr32 (__ARM_NR_BASE+4) + #define __ARM_NR_set_tls (__ARM_NR_BASE+5) + #define __ARM_NR_get_tls (__ARM_NR_BASE+6) + + These do not follow the regular __NR_* naming convention and + have so far been ignored by the syscall-names.list consistency + checks. This commit adds these names to the file, preparing + for the availability of these names in the regular __NR_* + namespace. + +diff --git a/sysdeps/unix/sysv/linux/syscall-names.list b/sysdeps/unix/sysv/linux/syscall-names.list +index 2d0354b8b3..ae8adabb70 100644 +--- a/sysdeps/unix/sysv/linux/syscall-names.list ++++ b/sysdeps/unix/sysv/linux/syscall-names.list +@@ -52,6 +52,7 @@ bdflush + bind + bpf + break ++breakpoint + brk + cachectl + cacheflush +@@ -139,6 +140,7 @@ get_kernel_syms + get_mempolicy + get_robust_list + get_thread_area ++get_tls + getcpu + getcwd + getdents +@@ -499,6 +501,7 @@ set_mempolicy + set_robust_list + set_thread_area + set_tid_address ++set_tls + setdomainname + setfsgid + setfsgid32 +@@ -611,6 +614,8 @@ unlinkat + unshare + uselib + userfaultfd ++usr26 ++usr32 + ustat + utime + utimensat diff --git a/SOURCES/glibc-rh1764234-5.patch b/SOURCES/glibc-rh1764234-5.patch new file mode 100644 index 0000000..53988c6 --- /dev/null +++ b/SOURCES/glibc-rh1764234-5.patch @@ -0,0 +1,30 @@ +commit a63b96fbddbf97feaa068a9efed3b5623a1a1e78 +Author: Vincent Chen +Date: Wed Jun 26 17:30:11 2019 +0800 + + Linux: Add nds32 specific syscalls to syscall-names.list + + The nds32 creates two specific syscalls, udftrap and fp_udfiex_crtl, in + kernel v5.0 and v5.2, respectively. Add these two syscalls to + syscall-names.list. + +diff --git a/sysdeps/unix/sysv/linux/syscall-names.list b/sysdeps/unix/sysv/linux/syscall-names.list +index ae8adabb70..95aa3ec7a5 100644 +--- a/sysdeps/unix/sysv/linux/syscall-names.list ++++ b/sysdeps/unix/sysv/linux/syscall-names.list +@@ -121,6 +121,7 @@ finit_module + flistxattr + flock + fork ++fp_udfiex_crtl + free_hugepages + fremovexattr + fsetxattr +@@ -603,6 +604,7 @@ tkill + truncate + truncate64 + tuxcall ++udftrap + ugetrlimit + ulimit + umask diff --git a/SOURCES/glibc-rh1764234-6.patch b/SOURCES/glibc-rh1764234-6.patch new file mode 100644 index 0000000..5f29118 --- /dev/null +++ b/SOURCES/glibc-rh1764234-6.patch @@ -0,0 +1,52 @@ +commit 1f7097d09ce628878107ed30341cfc1eb3649a81 +Author: Florian Weimer +Date: Fri Jul 19 08:53:04 2019 +0200 + + Linux: Update syscall-names.list to Linux 5.2 + + This adds the system call names fsconfig, fsmount, fsopen, fspick, + move_mount, open_tree. + + Tested with build-many-glibcs.py. + +diff --git a/sysdeps/unix/sysv/linux/syscall-names.list b/sysdeps/unix/sysv/linux/syscall-names.list +index 95aa3ec7a5..21bf37c627 100644 +--- a/sysdeps/unix/sysv/linux/syscall-names.list ++++ b/sysdeps/unix/sysv/linux/syscall-names.list +@@ -23,7 +23,7 @@ + # them. + + # The list of system calls is current as of Linux 5.1. +-kernel 5.1 ++kernel 5.2 + + FAST_atomic_update + FAST_cmpxchg +@@ -124,7 +124,11 @@ fork + fp_udfiex_crtl + free_hugepages + fremovexattr ++fsconfig + fsetxattr ++fsmount ++fsopen ++fspick + fstat + fstat64 + fstatat64 +@@ -248,6 +252,7 @@ mmap + mmap2 + modify_ldt + mount ++move_mount + move_pages + mprotect + mpx +@@ -285,6 +290,7 @@ oldumount + olduname + open + open_by_handle_at ++open_tree + openat + osf_adjtime + osf_afs_syscall diff --git a/SOURCES/glibc-rh1764234-7.patch b/SOURCES/glibc-rh1764234-7.patch new file mode 100644 index 0000000..9322a53 --- /dev/null +++ b/SOURCES/glibc-rh1764234-7.patch @@ -0,0 +1,24 @@ +commit 9c37bde5a2067e5b4dc878bac0291d6b207b8add +Author: Joseph Myers +Date: Fri Aug 2 15:08:02 2019 +0000 + + Update kernel version in comment in syscall-names.list. + + This patch updates the Linux kernel version in a comment in + syscall-names.list to agree with the following "kernel" line. + + * sysdeps/unix/sysv/linux/syscall-names.list: Update comment. + +diff --git a/sysdeps/unix/sysv/linux/syscall-names.list b/sysdeps/unix/sysv/linux/syscall-names.list +index 21bf37c627..9dcdd293d3 100644 +--- a/sysdeps/unix/sysv/linux/syscall-names.list ++++ b/sysdeps/unix/sysv/linux/syscall-names.list +@@ -22,7 +22,7 @@ + # names are only used if the installed kernel headers also provide + # them. + +-# The list of system calls is current as of Linux 5.1. ++# The list of system calls is current as of Linux 5.2. + kernel 5.2 + + FAST_atomic_update diff --git a/SOURCES/glibc-rh1764234-8.patch b/SOURCES/glibc-rh1764234-8.patch new file mode 100644 index 0000000..1728729 --- /dev/null +++ b/SOURCES/glibc-rh1764234-8.patch @@ -0,0 +1,47 @@ +commit 0f02b6cfc44af73d4d4363c46b3cbb18b8ff9171 +Author: Joseph Myers +Date: Wed Sep 18 22:57:46 2019 +0000 + + Update syscall-names.list for Linux 5.3. + + This patch updates syscall-names.list for Linux 5.3, adding two new + syscalls. + + Tested with build-many-glibcs.py. + + * sysdeps/unix/sysv/linux/syscall-names.list: Update kernel + version to 5.3. + (clone3): New syscall. + (pidfd_open): Likewise. + +diff --git a/sysdeps/unix/sysv/linux/syscall-names.list b/sysdeps/unix/sysv/linux/syscall-names.list +index e2382d3414..b55ffbc2a0 100644 +--- a/sysdeps/unix/sysv/linux/syscall-names.list ++++ b/sysdeps/unix/sysv/linux/syscall-names.list +@@ -22,8 +22,8 @@ + # names are only used if the installed kernel headers also provide + # them. + +-# The list of system calls is current as of Linux 5.2. +-kernel 5.2 ++# The list of system calls is current as of Linux 5.3. ++kernel 5.3 + + FAST_atomic_update + FAST_cmpxchg +@@ -75,6 +75,7 @@ clock_settime + clock_settime64 + clone + clone2 ++clone3 + close + cmpxchg_badaddr + connect +@@ -410,6 +411,7 @@ perf_event_open + perfctr + perfmonctl + personality ++pidfd_open + pidfd_send_signal + pipe + pipe2 diff --git a/SOURCES/glibc-rh1764235.patch b/SOURCES/glibc-rh1764235.patch new file mode 100644 index 0000000..1b783b9 --- /dev/null +++ b/SOURCES/glibc-rh1764235.patch @@ -0,0 +1,165 @@ +commit e621246ec6393ea08ae50310f9d5e72500f8c9bc +Author: Carlos O'Donell +Date: Mon Apr 8 17:35:05 2019 -0400 + + malloc: Set and reset all hooks for tracing (Bug 16573) + + If an error occurs during the tracing operation, particularly during a + call to lock_and_info() which calls _dl_addr, we may end up calling back + into the malloc-subsystem and relock the loader lock and deadlock. For + all intents and purposes the call to _dl_addr can call any of the malloc + family API functions and so we should disable all tracing before calling + such loader functions. This is similar to the strategy that the new + malloc tracer takes when calling the real malloc, namely that all + tracing ceases at the boundary to the real function and any faults at + that point are the purvue of the library (though the new tracer does + this on a per-thread basis in an MT-safe fashion). Since the new tracer + and the hook deprecation are not yet complete we must fix these issues + where we can. + + Tested on x86_64 with no regressions. + + Co-authored-by: Kwok Cheung Yeung + Reviewed-by: DJ Delorie + +diff --git a/malloc/mtrace.c b/malloc/mtrace.c +index 9064f209ec3b24c6..546d37a26018bf41 100644 +--- a/malloc/mtrace.c ++++ b/malloc/mtrace.c +@@ -121,6 +121,41 @@ lock_and_info (const void *caller, Dl_info *mem) + return res; + } + ++static void tr_freehook (void *, const void *); ++static void * tr_mallochook (size_t, const void *); ++static void * tr_reallochook (void *, size_t, const void *); ++static void * tr_memalignhook (size_t, size_t, const void *); ++ ++/* Set all the default non-trace hooks. */ ++static __always_inline void ++set_default_hooks (void) ++{ ++ __free_hook = tr_old_free_hook; ++ __malloc_hook = tr_old_malloc_hook; ++ __realloc_hook = tr_old_realloc_hook; ++ __memalign_hook = tr_old_memalign_hook; ++} ++ ++/* Set all of the tracing hooks used for mtrace. */ ++static __always_inline void ++set_trace_hooks (void) ++{ ++ __free_hook = tr_freehook; ++ __malloc_hook = tr_mallochook; ++ __realloc_hook = tr_reallochook; ++ __memalign_hook = tr_memalignhook; ++} ++ ++/* Save the current set of hooks as the default hooks. */ ++static __always_inline void ++save_default_hooks (void) ++{ ++ tr_old_free_hook = __free_hook; ++ tr_old_malloc_hook = __malloc_hook; ++ tr_old_realloc_hook = __realloc_hook; ++ tr_old_memalign_hook = __memalign_hook; ++} ++ + static void + tr_freehook (void *ptr, const void *caller) + { +@@ -138,12 +173,12 @@ tr_freehook (void *ptr, const void *caller) + tr_break (); + __libc_lock_lock (lock); + } +- __free_hook = tr_old_free_hook; ++ set_default_hooks (); + if (tr_old_free_hook != NULL) + (*tr_old_free_hook)(ptr, caller); + else + free (ptr); +- __free_hook = tr_freehook; ++ set_trace_hooks (); + __libc_lock_unlock (lock); + } + +@@ -155,12 +190,12 @@ tr_mallochook (size_t size, const void *caller) + Dl_info mem; + Dl_info *info = lock_and_info (caller, &mem); + +- __malloc_hook = tr_old_malloc_hook; ++ set_default_hooks (); + if (tr_old_malloc_hook != NULL) + hdr = (void *) (*tr_old_malloc_hook)(size, caller); + else + hdr = (void *) malloc (size); +- __malloc_hook = tr_mallochook; ++ set_trace_hooks (); + + tr_where (caller, info); + /* We could be printing a NULL here; that's OK. */ +@@ -185,16 +220,12 @@ tr_reallochook (void *ptr, size_t size, const void *caller) + Dl_info mem; + Dl_info *info = lock_and_info (caller, &mem); + +- __free_hook = tr_old_free_hook; +- __malloc_hook = tr_old_malloc_hook; +- __realloc_hook = tr_old_realloc_hook; ++ set_default_hooks (); + if (tr_old_realloc_hook != NULL) + hdr = (void *) (*tr_old_realloc_hook)(ptr, size, caller); + else + hdr = (void *) realloc (ptr, size); +- __free_hook = tr_freehook; +- __malloc_hook = tr_mallochook; +- __realloc_hook = tr_reallochook; ++ set_trace_hooks (); + + tr_where (caller, info); + if (hdr == NULL) +@@ -230,14 +261,12 @@ tr_memalignhook (size_t alignment, size_t size, const void *caller) + Dl_info mem; + Dl_info *info = lock_and_info (caller, &mem); + +- __memalign_hook = tr_old_memalign_hook; +- __malloc_hook = tr_old_malloc_hook; ++ set_default_hooks (); + if (tr_old_memalign_hook != NULL) + hdr = (void *) (*tr_old_memalign_hook)(alignment, size, caller); + else + hdr = (void *) memalign (alignment, size); +- __memalign_hook = tr_memalignhook; +- __malloc_hook = tr_mallochook; ++ set_trace_hooks (); + + tr_where (caller, info); + /* We could be printing a NULL here; that's OK. */ +@@ -305,14 +334,8 @@ mtrace (void) + malloc_trace_buffer = mtb; + setvbuf (mallstream, malloc_trace_buffer, _IOFBF, TRACE_BUFFER_SIZE); + fprintf (mallstream, "= Start\n"); +- tr_old_free_hook = __free_hook; +- __free_hook = tr_freehook; +- tr_old_malloc_hook = __malloc_hook; +- __malloc_hook = tr_mallochook; +- tr_old_realloc_hook = __realloc_hook; +- __realloc_hook = tr_reallochook; +- tr_old_memalign_hook = __memalign_hook; +- __memalign_hook = tr_memalignhook; ++ save_default_hooks (); ++ set_trace_hooks (); + #ifdef _LIBC + if (!added_atexit_handler) + { +@@ -338,10 +361,7 @@ muntrace (void) + file. */ + FILE *f = mallstream; + mallstream = NULL; +- __free_hook = tr_old_free_hook; +- __malloc_hook = tr_old_malloc_hook; +- __realloc_hook = tr_old_realloc_hook; +- __memalign_hook = tr_old_memalign_hook; ++ set_default_hooks (); + + fprintf (f, "= End\n"); + fclose (f); diff --git a/SOURCES/glibc-rh1764238-1.patch b/SOURCES/glibc-rh1764238-1.patch new file mode 100644 index 0000000..63fc994 --- /dev/null +++ b/SOURCES/glibc-rh1764238-1.patch @@ -0,0 +1,92 @@ +commit dc0afac3252d0c53716ccaf0b424f7769a66d695 +Author: marxin +Date: Wed Feb 20 14:54:35 2019 +0100 + + Add new Fortran vector math header file. + +diff --git a/bits/math-vector-fortran.h b/bits/math-vector-fortran.h +new file mode 100644 +index 0000000000000000..7c1e095094e24571 +--- /dev/null ++++ b/bits/math-vector-fortran.h +@@ -0,0 +1,19 @@ ++! Platform-specific declarations of SIMD math functions for Fortran. -*- f90 -*- ++! 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, see ++! . ++ ++! No SIMD math functions are available for this platform. +diff --git a/math/Makefile b/math/Makefile +index 90b3b68916e12d85..16e68754fc863ea2 100644 +--- a/math/Makefile ++++ b/math/Makefile +@@ -26,6 +26,7 @@ headers := math.h bits/mathcalls.h bits/mathinline.h \ + fpu_control.h complex.h bits/cmathcalls.h fenv.h \ + bits/fenv.h bits/fenvinline.h bits/mathdef.h tgmath.h \ + bits/math-finite.h bits/math-vector.h \ ++ bits/math-vector-fortran.h \ + bits/libm-simd-decl-stubs.h bits/iscanonical.h \ + bits/flt-eval-method.h bits/fp-fast.h bits/fp-logb.h \ + bits/long-double.h bits/mathcalls-helper-functions.h \ +diff --git a/sysdeps/x86/fpu/bits/math-vector-fortran.h b/sysdeps/x86/fpu/bits/math-vector-fortran.h +new file mode 100644 +index 0000000000000000..36051cc73ea03602 +--- /dev/null ++++ b/sysdeps/x86/fpu/bits/math-vector-fortran.h +@@ -0,0 +1,43 @@ ++! Platform-specific declarations of SIMD math functions for Fortran. -*- f90 -*- ++! 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, see ++! . ++ ++!GCC$ builtin (cos) attributes simd (notinbranch) if('x86_64') ++!GCC$ builtin (cosf) attributes simd (notinbranch) if('x86_64') ++!GCC$ builtin (sin) attributes simd (notinbranch) if('x86_64') ++!GCC$ builtin (sinf) attributes simd (notinbranch) if('x86_64') ++!GCC$ builtin (sincos) attributes simd (notinbranch) if('x86_64') ++!GCC$ builtin (sincosf) attributes simd (notinbranch) if('x86_64') ++!GCC$ builtin (log) attributes simd (notinbranch) if('x86_64') ++!GCC$ builtin (logf) attributes simd (notinbranch) if('x86_64') ++!GCC$ builtin (exp) attributes simd (notinbranch) if('x86_64') ++!GCC$ builtin (expf) attributes simd (notinbranch) if('x86_64') ++!GCC$ builtin (pow) attributes simd (notinbranch) if('x86_64') ++!GCC$ builtin (powf) attributes simd (notinbranch) if('x86_64') ++ ++!GCC$ builtin (cos) attributes simd (notinbranch) if('x32') ++!GCC$ builtin (cosf) attributes simd (notinbranch) if('x32') ++!GCC$ builtin (sin) attributes simd (notinbranch) if('x32') ++!GCC$ builtin (sinf) attributes simd (notinbranch) if('x32') ++!GCC$ builtin (sincos) attributes simd (notinbranch) if('x32') ++!GCC$ builtin (sincosf) attributes simd (notinbranch) if('x32') ++!GCC$ builtin (log) attributes simd (notinbranch) if('x32') ++!GCC$ builtin (logf) attributes simd (notinbranch) if('x32') ++!GCC$ builtin (exp) attributes simd (notinbranch) if('x32') ++!GCC$ builtin (expf) attributes simd (notinbranch) if('x32') ++!GCC$ builtin (pow) attributes simd (notinbranch) if('x32') ++!GCC$ builtin (powf) attributes simd (notinbranch) if('x32') diff --git a/SOURCES/glibc-rh1764238-2.patch b/SOURCES/glibc-rh1764238-2.patch new file mode 100644 index 0000000..5cafd01 --- /dev/null +++ b/SOURCES/glibc-rh1764238-2.patch @@ -0,0 +1,56 @@ +commit ae514971341dcc08ec7f8622493a65e7eb1ef9d2 +Author: marxin +Date: Thu Mar 7 09:39:55 2019 +0100 + + Fix location where math-vector-fortran.h is installed. + + 2019-03-07 Martin Liska + + * math/Makefile: Change location where math-vector-fortran.h is + installed. + * math/finclude/math-vector-fortran.h: Move from bits/math-vector-fortran.h. + * sysdeps/x86/fpu/finclude/math-vector-fortran.h: Move + from sysdeps/x86/fpu/bits/math-vector-fortran.h. + * scripts/check-installed-headers.sh: Skip Fortran header files. + * scripts/check-wrapper-headers.py: Likewise. + +Conflicts: + scripts/check-wrapper-headers.py + (Script does not exist downstream, change dropped.) + +diff --git a/math/Makefile b/math/Makefile +index 16e68754fc863ea2..df73d70840b61cd7 100644 +--- a/math/Makefile ++++ b/math/Makefile +@@ -26,7 +26,7 @@ headers := math.h bits/mathcalls.h bits/mathinline.h \ + fpu_control.h complex.h bits/cmathcalls.h fenv.h \ + bits/fenv.h bits/fenvinline.h bits/mathdef.h tgmath.h \ + bits/math-finite.h bits/math-vector.h \ +- bits/math-vector-fortran.h \ ++ finclude/math-vector-fortran.h \ + bits/libm-simd-decl-stubs.h bits/iscanonical.h \ + bits/flt-eval-method.h bits/fp-fast.h bits/fp-logb.h \ + bits/long-double.h bits/mathcalls-helper-functions.h \ +diff --git a/bits/math-vector-fortran.h b/math/finclude/math-vector-fortran.h +similarity index 100% +rename from bits/math-vector-fortran.h +rename to math/finclude/math-vector-fortran.h +diff --git a/scripts/check-installed-headers.sh b/scripts/check-installed-headers.sh +index 4a062e9cdaa57978..7a1969b43a144ebb 100644 +--- a/scripts/check-installed-headers.sh ++++ b/scripts/check-installed-headers.sh +@@ -84,6 +84,10 @@ for header in "$@"; do + (sys/elf.h) + continue;; + ++ # Skip Fortran headers. ++ (finclude/*) ++ continue;; ++ + # sys/sysctl.h is unsupported for x32. + (sys/sysctl.h) + case "$is_x32" in +diff --git a/sysdeps/x86/fpu/bits/math-vector-fortran.h b/sysdeps/x86/fpu/finclude/math-vector-fortran.h +similarity index 100% +rename from sysdeps/x86/fpu/bits/math-vector-fortran.h +rename to sysdeps/x86/fpu/finclude/math-vector-fortran.h diff --git a/SOURCES/glibc-rh1764241.patch b/SOURCES/glibc-rh1764241.patch new file mode 100644 index 0000000..9044857 --- /dev/null +++ b/SOURCES/glibc-rh1764241.patch @@ -0,0 +1,544 @@ +commit 09e1b0e3f6facc1af2dbcfef204f0aaa8718772b +Author: Florian Weimer +Date: Mon May 20 21:54:57 2019 +0200 + + libio: Remove codecvt vtable [BZ #24588] + + The codecvt vtable is not a real vtable because it also contains the + conversion state data. Furthermore, wide stream support was added to + GCC 3.0, after a C++ ABI bump, so there is no compatibility + requirement with libstdc++. + + This change removes several unmangled function pointers which could + be used with a corrupted FILE object to redirect execution. (libio + vtable verification did not cover the codecvt vtable.) + + Reviewed-by: Yann Droneaud + Reviewed-by: Adhemerval Zanella + +diff --git a/libio/fileops.c b/libio/fileops.c +index d2070a856e..daa5a05877 100644 +--- a/libio/fileops.c ++++ b/libio/fileops.c +@@ -331,9 +331,6 @@ _IO_new_file_fopen (FILE *fp, const char *filename, const char *mode, + + cc = fp->_codecvt = &fp->_wide_data->_codecvt; + +- /* The functions are always the same. */ +- *cc = __libio_codecvt; +- + cc->__cd_in.__cd.__nsteps = fcts.towc_nsteps; + cc->__cd_in.__cd.__steps = fcts.towc; + +diff --git a/libio/iofgetpos.c b/libio/iofgetpos.c +index 8032192440..388c4a0708 100644 +--- a/libio/iofgetpos.c ++++ b/libio/iofgetpos.c +@@ -70,8 +70,7 @@ _IO_new_fgetpos (FILE *fp, __fpos_t *posp) + else + { + posp->__pos = pos; +- if (fp->_mode > 0 +- && (*fp->_codecvt->__codecvt_do_encoding) (fp->_codecvt) < 0) ++ if (fp->_mode > 0 && __libio_codecvt_encoding (fp->_codecvt) < 0) + /* This is a stateful encoding, safe the state. */ + posp->__state = fp->_wide_data->_IO_state; + } +diff --git a/libio/iofgetpos64.c b/libio/iofgetpos64.c +index 54de6a8205..6a0ba50d29 100644 +--- a/libio/iofgetpos64.c ++++ b/libio/iofgetpos64.c +@@ -54,8 +54,7 @@ _IO_new_fgetpos64 (FILE *fp, __fpos64_t *posp) + else + { + posp->__pos = pos; +- if (fp->_mode > 0 +- && (*fp->_codecvt->__codecvt_do_encoding) (fp->_codecvt) < 0) ++ if (fp->_mode > 0 && __libio_codecvt_encoding (fp->_codecvt) < 0) + /* This is a stateful encoding, safe the state. */ + posp->__state = fp->_wide_data->_IO_state; + } +diff --git a/libio/iofsetpos.c b/libio/iofsetpos.c +index d7b1abbc61..4df1aae082 100644 +--- a/libio/iofsetpos.c ++++ b/libio/iofsetpos.c +@@ -58,8 +58,7 @@ _IO_new_fsetpos (FILE *fp, const __fpos_t *posp) + else + { + result = 0; +- if (fp->_mode > 0 +- && (*fp->_codecvt->__codecvt_do_encoding) (fp->_codecvt) < 0) ++ if (fp->_mode > 0 && __libio_codecvt_encoding (fp->_codecvt) < 0) + /* This is a stateful encoding, restore the state. */ + fp->_wide_data->_IO_state = posp->__state; + } +diff --git a/libio/iofsetpos64.c b/libio/iofsetpos64.c +index d1865b728e..f382ba0dc1 100644 +--- a/libio/iofsetpos64.c ++++ b/libio/iofsetpos64.c +@@ -48,8 +48,7 @@ _IO_new_fsetpos64 (FILE *fp, const fpos64_t *posp) + else + { + result = 0; +- if (fp->_mode > 0 +- && (*fp->_codecvt->__codecvt_do_encoding) (fp->_codecvt) < 0) ++ if (fp->_mode > 0 && __libio_codecvt_encoding (fp->_codecvt) < 0) + /* This is a stateful encoding, safe the state. */ + fp->_wide_data->_IO_state = posp->__state; + } +diff --git a/libio/iofwide.c b/libio/iofwide.c +index 247cfde3d0..80cb2d5074 100644 +--- a/libio/iofwide.c ++++ b/libio/iofwide.c +@@ -39,44 +39,6 @@ + #include + + +-/* Prototypes of libio's codecvt functions. */ +-static enum __codecvt_result do_out (struct _IO_codecvt *codecvt, +- __mbstate_t *statep, +- const wchar_t *from_start, +- const wchar_t *from_end, +- const wchar_t **from_stop, char *to_start, +- char *to_end, char **to_stop); +-static enum __codecvt_result do_unshift (struct _IO_codecvt *codecvt, +- __mbstate_t *statep, char *to_start, +- char *to_end, char **to_stop); +-static enum __codecvt_result do_in (struct _IO_codecvt *codecvt, +- __mbstate_t *statep, +- const char *from_start, +- const char *from_end, +- const char **from_stop, wchar_t *to_start, +- wchar_t *to_end, wchar_t **to_stop); +-static int do_encoding (struct _IO_codecvt *codecvt); +-static int do_length (struct _IO_codecvt *codecvt, __mbstate_t *statep, +- const char *from_start, +- const char *from_end, size_t max); +-static int do_max_length (struct _IO_codecvt *codecvt); +-static int do_always_noconv (struct _IO_codecvt *codecvt); +- +- +-/* The functions used in `codecvt' for libio are always the same. */ +-const struct _IO_codecvt __libio_codecvt = +-{ +- .__codecvt_destr = NULL, /* Destructor, never used. */ +- .__codecvt_do_out = do_out, +- .__codecvt_do_unshift = do_unshift, +- .__codecvt_do_in = do_in, +- .__codecvt_do_encoding = do_encoding, +- .__codecvt_do_always_noconv = do_always_noconv, +- .__codecvt_do_length = do_length, +- .__codecvt_do_max_length = do_max_length +-}; +- +- + /* Return orientation of stream. If mode is nonzero try to change + the orientation first. */ + #undef _IO_fwide +@@ -118,9 +80,6 @@ _IO_fwide (FILE *fp, int mode) + assert (fcts.towc_nsteps == 1); + assert (fcts.tomb_nsteps == 1); + +- /* The functions are always the same. */ +- *cc = __libio_codecvt; +- + cc->__cd_in.__cd.__nsteps = fcts.towc_nsteps; + cc->__cd_in.__cd.__steps = fcts.towc; + +@@ -150,11 +109,11 @@ _IO_fwide (FILE *fp, int mode) + } + + +-static enum __codecvt_result +-do_out (struct _IO_codecvt *codecvt, __mbstate_t *statep, +- const wchar_t *from_start, const wchar_t *from_end, +- const wchar_t **from_stop, char *to_start, char *to_end, +- char **to_stop) ++enum __codecvt_result ++__libio_codecvt_out (struct _IO_codecvt *codecvt, __mbstate_t *statep, ++ const wchar_t *from_start, const wchar_t *from_end, ++ const wchar_t **from_stop, char *to_start, char *to_end, ++ char **to_stop) + { + enum __codecvt_result result; + +@@ -202,57 +161,11 @@ do_out (struct _IO_codecvt *codecvt, __mbstate_t *statep, + } + + +-static enum __codecvt_result +-do_unshift (struct _IO_codecvt *codecvt, __mbstate_t *statep, +- char *to_start, char *to_end, char **to_stop) +-{ +- enum __codecvt_result result; +- +- struct __gconv_step *gs = codecvt->__cd_out.__cd.__steps; +- int status; +- size_t dummy; +- +- codecvt->__cd_out.__cd.__data[0].__outbuf = (unsigned char *) to_start; +- codecvt->__cd_out.__cd.__data[0].__outbufend = (unsigned char *) to_end; +- codecvt->__cd_out.__cd.__data[0].__statep = statep; +- +- __gconv_fct fct = gs->__fct; +-#ifdef PTR_DEMANGLE +- if (gs->__shlib_handle != NULL) +- PTR_DEMANGLE (fct); +-#endif +- +- status = DL_CALL_FCT (fct, +- (gs, codecvt->__cd_out.__cd.__data, NULL, NULL, +- NULL, &dummy, 1, 0)); +- +- *to_stop = (char *) codecvt->__cd_out.__cd.__data[0].__outbuf; +- +- switch (status) +- { +- case __GCONV_OK: +- case __GCONV_EMPTY_INPUT: +- result = __codecvt_ok; +- break; +- +- case __GCONV_FULL_OUTPUT: +- case __GCONV_INCOMPLETE_INPUT: +- result = __codecvt_partial; +- break; +- +- default: +- result = __codecvt_error; +- break; +- } +- +- return result; +-} +- +- +-static enum __codecvt_result +-do_in (struct _IO_codecvt *codecvt, __mbstate_t *statep, +- const char *from_start, const char *from_end, const char **from_stop, +- wchar_t *to_start, wchar_t *to_end, wchar_t **to_stop) ++enum __codecvt_result ++__libio_codecvt_in (struct _IO_codecvt *codecvt, __mbstate_t *statep, ++ const char *from_start, const char *from_end, ++ const char **from_stop, ++ wchar_t *to_start, wchar_t *to_end, wchar_t **to_stop) + { + enum __codecvt_result result; + +@@ -300,8 +213,8 @@ do_in (struct _IO_codecvt *codecvt, __mbstate_t *statep, + } + + +-static int +-do_encoding (struct _IO_codecvt *codecvt) ++int ++__libio_codecvt_encoding (struct _IO_codecvt *codecvt) + { + /* See whether the encoding is stateful. */ + if (codecvt->__cd_in.__cd.__steps[0].__stateful) +@@ -317,16 +230,10 @@ do_encoding (struct _IO_codecvt *codecvt) + } + + +-static int +-do_always_noconv (struct _IO_codecvt *codecvt) +-{ +- return 0; +-} +- +- +-static int +-do_length (struct _IO_codecvt *codecvt, __mbstate_t *statep, +- const char *from_start, const char *from_end, size_t max) ++int ++__libio_codecvt_length (struct _IO_codecvt *codecvt, __mbstate_t *statep, ++ const char *from_start, const char *from_end, ++ size_t max) + { + int result; + const unsigned char *cp = (const unsigned char *) from_start; +@@ -353,10 +260,3 @@ do_length (struct _IO_codecvt *codecvt, __mbstate_t *statep, + + return result; + } +- +- +-static int +-do_max_length (struct _IO_codecvt *codecvt) +-{ +- return codecvt->__cd_in.__cd.__steps[0].__max_needed_from; +-} +diff --git a/libio/libio.h b/libio/libio.h +index c38095ff77..b985c386a2 100644 +--- a/libio/libio.h ++++ b/libio/libio.h +@@ -116,40 +116,8 @@ struct _IO_marker { + int _pos; + }; + +-/* This is the structure from the libstdc++ codecvt class. */ +-enum __codecvt_result +-{ +- __codecvt_ok, +- __codecvt_partial, +- __codecvt_error, +- __codecvt_noconv +-}; +- +-/* The order of the elements in the following struct must match the order +- of the virtual functions in the libstdc++ codecvt class. */ + struct _IO_codecvt + { +- void (*__codecvt_destr) (struct _IO_codecvt *); +- enum __codecvt_result (*__codecvt_do_out) (struct _IO_codecvt *, +- __mbstate_t *, +- const wchar_t *, +- const wchar_t *, +- const wchar_t **, char *, +- char *, char **); +- enum __codecvt_result (*__codecvt_do_unshift) (struct _IO_codecvt *, +- __mbstate_t *, char *, +- char *, char **); +- enum __codecvt_result (*__codecvt_do_in) (struct _IO_codecvt *, +- __mbstate_t *, +- const char *, const char *, +- const char **, wchar_t *, +- wchar_t *, wchar_t **); +- int (*__codecvt_do_encoding) (struct _IO_codecvt *); +- int (*__codecvt_do_always_noconv) (struct _IO_codecvt *); +- int (*__codecvt_do_length) (struct _IO_codecvt *, __mbstate_t *, +- const char *, const char *, size_t); +- int (*__codecvt_do_max_length) (struct _IO_codecvt *); +- + _IO_iconv_t __cd_in; + _IO_iconv_t __cd_out; + }; +diff --git a/libio/libioP.h b/libio/libioP.h +index 7bdec86a62..66afaa8968 100644 +--- a/libio/libioP.h ++++ b/libio/libioP.h +@@ -476,7 +476,6 @@ extern const struct _IO_jump_t _IO_streambuf_jumps; + extern const struct _IO_jump_t _IO_old_proc_jumps attribute_hidden; + extern const struct _IO_jump_t _IO_str_jumps attribute_hidden; + extern const struct _IO_jump_t _IO_wstr_jumps attribute_hidden; +-extern const struct _IO_codecvt __libio_codecvt attribute_hidden; + extern int _IO_do_write (FILE *, const char *, size_t); + libc_hidden_proto (_IO_do_write) + extern int _IO_new_do_write (FILE *, const char *, size_t); +@@ -932,4 +931,32 @@ IO_validate_vtable (const struct _IO_jump_t *vtable) + return vtable; + } + ++/* Character set conversion. */ ++ ++enum __codecvt_result ++{ ++ __codecvt_ok, ++ __codecvt_partial, ++ __codecvt_error, ++ __codecvt_noconv ++}; ++ ++enum __codecvt_result __libio_codecvt_out (struct _IO_codecvt *, ++ __mbstate_t *, ++ const wchar_t *, ++ const wchar_t *, ++ const wchar_t **, char *, ++ char *, char **) ++ attribute_hidden; ++enum __codecvt_result __libio_codecvt_in (struct _IO_codecvt *, ++ __mbstate_t *, ++ const char *, const char *, ++ const char **, wchar_t *, ++ wchar_t *, wchar_t **) ++ attribute_hidden; ++int __libio_codecvt_encoding (struct _IO_codecvt *) attribute_hidden; ++int __libio_codecvt_length (struct _IO_codecvt *, __mbstate_t *, ++ const char *, const char *, size_t) ++ attribute_hidden; ++ + #endif /* libioP.h. */ +diff --git a/libio/wfileops.c b/libio/wfileops.c +index 69fbb62a02..f1863db638 100644 +--- a/libio/wfileops.c ++++ b/libio/wfileops.c +@@ -72,11 +72,11 @@ _IO_wdo_write (FILE *fp, const wchar_t *data, size_t to_do) + } + + /* Now convert from the internal format into the external buffer. */ +- result = (*cc->__codecvt_do_out) (cc, &fp->_wide_data->_IO_state, +- data, data + to_do, &new_data, +- write_ptr, +- buf_end, +- &write_ptr); ++ result = __libio_codecvt_out (cc, &fp->_wide_data->_IO_state, ++ data, data + to_do, &new_data, ++ write_ptr, ++ buf_end, ++ &write_ptr); + + /* Write out what we produced so far. */ + if (_IO_new_do_write (fp, write_base, write_ptr - write_base) == EOF) +@@ -140,12 +140,12 @@ _IO_wfile_underflow (FILE *fp) + fp->_wide_data->_IO_last_state = fp->_wide_data->_IO_state; + fp->_wide_data->_IO_read_base = fp->_wide_data->_IO_read_ptr = + fp->_wide_data->_IO_buf_base; +- status = (*cd->__codecvt_do_in) (cd, &fp->_wide_data->_IO_state, +- fp->_IO_read_ptr, fp->_IO_read_end, +- &read_stop, +- fp->_wide_data->_IO_read_ptr, +- fp->_wide_data->_IO_buf_end, +- &fp->_wide_data->_IO_read_end); ++ status = __libio_codecvt_in (cd, &fp->_wide_data->_IO_state, ++ fp->_IO_read_ptr, fp->_IO_read_end, ++ &read_stop, ++ fp->_wide_data->_IO_read_ptr, ++ fp->_wide_data->_IO_buf_end, ++ &fp->_wide_data->_IO_read_end); + + fp->_IO_read_base = fp->_IO_read_ptr; + fp->_IO_read_ptr = (char *) read_stop; +@@ -266,11 +266,11 @@ _IO_wfile_underflow (FILE *fp) + naccbuf += to_copy; + from = accbuf; + } +- status = (*cd->__codecvt_do_in) (cd, &fp->_wide_data->_IO_state, +- from, to, &read_ptr_copy, +- fp->_wide_data->_IO_read_end, +- fp->_wide_data->_IO_buf_end, +- &fp->_wide_data->_IO_read_end); ++ status = __libio_codecvt_in (cd, &fp->_wide_data->_IO_state, ++ from, to, &read_ptr_copy, ++ fp->_wide_data->_IO_read_end, ++ fp->_wide_data->_IO_buf_end, ++ &fp->_wide_data->_IO_read_end); + + if (__glibc_unlikely (naccbuf != 0)) + fp->_IO_read_ptr += MAX (0, read_ptr_copy - &accbuf[naccbuf - to_copy]); +@@ -372,12 +372,12 @@ _IO_wfile_underflow_mmap (FILE *fp) + fp->_wide_data->_IO_last_state = fp->_wide_data->_IO_state; + fp->_wide_data->_IO_read_base = fp->_wide_data->_IO_read_ptr = + fp->_wide_data->_IO_buf_base; +- (*cd->__codecvt_do_in) (cd, &fp->_wide_data->_IO_state, +- fp->_IO_read_ptr, fp->_IO_read_end, +- &read_stop, +- fp->_wide_data->_IO_read_ptr, +- fp->_wide_data->_IO_buf_end, +- &fp->_wide_data->_IO_read_end); ++ __libio_codecvt_in (cd, &fp->_wide_data->_IO_state, ++ fp->_IO_read_ptr, fp->_IO_read_end, ++ &read_stop, ++ fp->_wide_data->_IO_read_ptr, ++ fp->_wide_data->_IO_buf_end, ++ &fp->_wide_data->_IO_read_end); + + fp->_IO_read_ptr = (char *) read_stop; + +@@ -495,7 +495,7 @@ _IO_wfile_sync (FILE *fp) + struct _IO_codecvt *cv = fp->_codecvt; + off64_t new_pos; + +- int clen = (*cv->__codecvt_do_encoding) (cv); ++ int clen = __libio_codecvt_encoding (cv); + + if (clen > 0) + /* It is easy, a fixed number of input bytes are used for each +@@ -511,9 +511,9 @@ _IO_wfile_sync (FILE *fp) + size_t wnread = (fp->_wide_data->_IO_read_ptr + - fp->_wide_data->_IO_read_base); + fp->_wide_data->_IO_state = fp->_wide_data->_IO_last_state; +- nread = (*cv->__codecvt_do_length) (cv, &fp->_wide_data->_IO_state, +- fp->_IO_read_base, +- fp->_IO_read_end, wnread); ++ nread = __libio_codecvt_length (cv, &fp->_wide_data->_IO_state, ++ fp->_IO_read_base, ++ fp->_IO_read_end, wnread); + fp->_IO_read_ptr = fp->_IO_read_base + nread; + delta = -(fp->_IO_read_end - fp->_IO_read_base - nread); + } +@@ -548,7 +548,7 @@ adjust_wide_data (FILE *fp, bool do_convert) + { + struct _IO_codecvt *cv = fp->_codecvt; + +- int clen = (*cv->__codecvt_do_encoding) (cv); ++ int clen = __libio_codecvt_encoding (cv); + + /* Take the easy way out for constant length encodings if we don't need to + convert. */ +@@ -565,12 +565,12 @@ adjust_wide_data (FILE *fp, bool do_convert) + { + + fp->_wide_data->_IO_last_state = fp->_wide_data->_IO_state; +- status = (*cv->__codecvt_do_in) (cv, &fp->_wide_data->_IO_state, +- fp->_IO_read_base, fp->_IO_read_ptr, +- &read_stop, +- fp->_wide_data->_IO_read_base, +- fp->_wide_data->_IO_buf_end, +- &fp->_wide_data->_IO_read_end); ++ status = __libio_codecvt_in (cv, &fp->_wide_data->_IO_state, ++ fp->_IO_read_base, fp->_IO_read_ptr, ++ &read_stop, ++ fp->_wide_data->_IO_read_base, ++ fp->_wide_data->_IO_buf_end, ++ &fp->_wide_data->_IO_read_end); + + /* Should we return EILSEQ? */ + if (__glibc_unlikely (status == __codecvt_error)) +@@ -648,7 +648,7 @@ do_ftell_wide (FILE *fp) + } + + struct _IO_codecvt *cv = fp->_codecvt; +- int clen = (*cv->__codecvt_do_encoding) (cv); ++ int clen = __libio_codecvt_encoding (cv); + + if (!unflushed_writes) + { +@@ -663,9 +663,9 @@ do_ftell_wide (FILE *fp) + + size_t delta = wide_read_ptr - wide_read_base; + __mbstate_t state = fp->_wide_data->_IO_last_state; +- nread = (*cv->__codecvt_do_length) (cv, &state, +- fp->_IO_read_base, +- fp->_IO_read_end, delta); ++ nread = __libio_codecvt_length (cv, &state, ++ fp->_IO_read_base, ++ fp->_IO_read_end, delta); + offset -= fp->_IO_read_end - fp->_IO_read_base - nread; + } + } +@@ -688,9 +688,8 @@ do_ftell_wide (FILE *fp) + enum __codecvt_result status; + + __mbstate_t state = fp->_wide_data->_IO_last_state; +- status = (*cv->__codecvt_do_out) (cv, &state, +- in, in + delta, &in, +- out, out + outsize, &outstop); ++ status = __libio_codecvt_out (cv, &state, in, in + delta, &in, ++ out, out + outsize, &outstop); + + /* We don't check for __codecvt_partial because it can be + returned on one of two conditions: either the output +@@ -801,7 +800,7 @@ _IO_wfile_seekoff (FILE *fp, off64_t offset, int dir, int mode) + find out which position in the external buffer corresponds to + the current position in the internal buffer. */ + cv = fp->_codecvt; +- clen = (*cv->__codecvt_do_encoding) (cv); ++ clen = __libio_codecvt_encoding (cv); + + if (mode != 0 || !was_writing) + { +@@ -819,10 +818,10 @@ _IO_wfile_seekoff (FILE *fp, off64_t offset, int dir, int mode) + delta = (fp->_wide_data->_IO_read_ptr + - fp->_wide_data->_IO_read_base); + fp->_wide_data->_IO_state = fp->_wide_data->_IO_last_state; +- nread = (*cv->__codecvt_do_length) (cv, +- &fp->_wide_data->_IO_state, +- fp->_IO_read_base, +- fp->_IO_read_end, delta); ++ nread = __libio_codecvt_length (cv, ++ &fp->_wide_data->_IO_state, ++ fp->_IO_read_base, ++ fp->_IO_read_end, delta); + fp->_IO_read_ptr = fp->_IO_read_base + nread; + fp->_wide_data->_IO_read_end = fp->_wide_data->_IO_read_ptr; + offset -= fp->_IO_read_end - fp->_IO_read_base - nread; diff --git a/SOURCES/glibc-rh1764242.patch b/SOURCES/glibc-rh1764242.patch new file mode 100644 index 0000000..b8c9a2f --- /dev/null +++ b/SOURCES/glibc-rh1764242.patch @@ -0,0 +1,81 @@ +commit 4997e8f31e7415652c3dedec672c0e9bf8caa9ca +Author: Adhemerval Zanella +Date: Fri Feb 1 10:39:57 2019 -0200 + + math: Enable some math builtins for clang + + This patch enable the builtin usage for clang for the C99 functions + fpclassify, isfinite, isnormal, isnan, isinf, and sigbit. This allows + clang optimize the calls on frontend instead of call the appropriate + glibc symbols. + + Checked on aarch64-linux-gnu and x86_64-linux-gnu. I checked the supported + version for each builtin based on released version from clang/llvm. + + * math/math.h (fpclassify, isfinite, isnormal, isnan): Use builtin for + clang 2.8. + (signbit): Use builtin for clang 3.3. + (isinf): Use builtin for clang 3.7. + +diff --git a/math/math.h b/math/math.h +index ddee4e408389722f..b3b414f3678e91f7 100644 +--- a/math/math.h ++++ b/math/math.h +@@ -874,7 +874,8 @@ enum + the __SUPPORT_SNAN__ check may be skipped for those versions. */ + + /* Return number of classification appropriate for X. */ +-# if __GNUC_PREREQ (4,4) && !defined __SUPPORT_SNAN__ \ ++# if ((__GNUC_PREREQ (4,4) && !defined __SUPPORT_SNAN__) \ ++ || __glibc_clang_prereq (2,8)) \ + && (!defined __OPTIMIZE_SIZE__ || defined __cplusplus) + /* The check for __cplusplus allows the use of the builtin, even + when optimization for size is on. This is provided for +@@ -889,7 +890,7 @@ enum + # endif + + /* Return nonzero value if sign of X is negative. */ +-# if __GNUC_PREREQ (6,0) ++# if __GNUC_PREREQ (6,0) || __glibc_clang_prereq (3,3) + # define signbit(x) __builtin_signbit (x) + # elif defined __cplusplus + /* In C++ mode, __MATH_TG cannot be used, because it relies on +@@ -907,14 +908,16 @@ enum + # endif + + /* Return nonzero value if X is not +-Inf or NaN. */ +-# if __GNUC_PREREQ (4,4) && !defined __SUPPORT_SNAN__ ++# if (__GNUC_PREREQ (4,4) && !defined __SUPPORT_SNAN__) \ ++ || __glibc_clang_prereq (2,8) + # define isfinite(x) __builtin_isfinite (x) + # else + # define isfinite(x) __MATH_TG ((x), __finite, (x)) + # endif + + /* Return nonzero value if X is neither zero, subnormal, Inf, nor NaN. */ +-# if __GNUC_PREREQ (4,4) && !defined __SUPPORT_SNAN__ ++# if (__GNUC_PREREQ (4,4) && !defined __SUPPORT_SNAN__) \ ++ || __glibc_clang_prereq (2,8) + # define isnormal(x) __builtin_isnormal (x) + # else + # define isnormal(x) (fpclassify (x) == FP_NORMAL) +@@ -922,7 +925,8 @@ enum + + /* Return nonzero value if X is a NaN. We could use `fpclassify' but + we already have this functions `__isnan' and it is faster. */ +-# if __GNUC_PREREQ (4,4) && !defined __SUPPORT_SNAN__ ++# if (__GNUC_PREREQ (4,4) && !defined __SUPPORT_SNAN__) \ ++ || __glibc_clang_prereq (2,8) + # define isnan(x) __builtin_isnan (x) + # else + # define isnan(x) __MATH_TG ((x), __isnan, (x)) +@@ -939,7 +943,8 @@ enum + # define isinf(x) \ + (__builtin_types_compatible_p (__typeof (x), _Float128) \ + ? __isinff128 (x) : __builtin_isinf_sign (x)) +-# elif __GNUC_PREREQ (4,4) && !defined __SUPPORT_SNAN__ ++# elif (__GNUC_PREREQ (4,4) && !defined __SUPPORT_SNAN__) \ ++ || __glibc_clang_prereq (3,7) + # define isinf(x) __builtin_isinf_sign (x) + # else + # define isinf(x) __MATH_TG ((x), __isinf, (x)) diff --git a/SOURCES/glibc-rh1769304.patch b/SOURCES/glibc-rh1769304.patch new file mode 100644 index 0000000..e78c759 --- /dev/null +++ b/SOURCES/glibc-rh1769304.patch @@ -0,0 +1,740 @@ +commit 711a322a235d4c8177713f11aa59156603b94aeb +Author: Zack Weinberg +Date: Mon Mar 11 10:59:27 2019 -0400 + + Use a proper C tokenizer to implement the obsolete typedefs test. + + The test for obsolete typedefs in installed headers was implemented + using grep, and could therefore get false positives on e.g. “ulong” + in a comment. It was also scanning all of the headers included by + our headers, and therefore testing headers we don’t control, e.g. + Linux kernel headers. + + This patch splits the obsolete-typedef test from + scripts/check-installed-headers.sh to a separate program, + scripts/check-obsolete-constructs.py. Being implemented in Python, + it is feasible to make it tokenize C accurately enough to avoid false + positives on the contents of comments and strings. It also only + examines $(headers) in each subdirectory--all the headers we install, + but not any external dependencies of those headers. Headers whose + installed name starts with finclude/ are ignored, on the assumption + that they contain Fortran. + + It is also feasible to make the new test understand the difference + between _defining_ the obsolete typedefs and _using_ the obsolete + typedefs, which means posix/{bits,sys}/types.h no longer need to be + exempted. This uncovered an actual bug in bits/types.h: __quad_t and + __u_quad_t were being used to define __S64_TYPE, __U64_TYPE, + __SQUAD_TYPE and __UQUAD_TYPE. These are changed to __int64_t and + __uint64_t respectively. This is a safe change, despite the comments + in bits/types.h claiming a difference between __quad_t and __int64_t, + because those comments are incorrect. In all current ABIs, both + __quad_t and __int64_t are ‘long’ when ‘long’ is a 64-bit type, and + ‘long long’ when ‘long’ is a 32-bit type, and similarly for __u_quad_t + and __uint64_t. (Changing the types to be what the comments say they + are would be an ABI break, as it affects C++ name mangling.) This + patch includes a minimal change to make the comments not completely + wrong. + + sys/types.h was defining the legacy BSD u_intN_t typedefs using a + construct that was not necessarily consistent with how the C99 uintN_t + typedefs are defined, and is also too complicated for the new script to + understand (it lexes C relatively accurately, but it does not attempt + to expand preprocessor macros, nor does it do any actual parsing). + This patch cuts all of that out and uses bits/types.h's __uintN_t typedefs + to define u_intN_t instead. This is verified to not change the ABI on + any supported architecture, via the c++-types test, which means u_intN_t + and uintN_t were, in fact, consistent on all supported architectures. + + Reviewed-by: Carlos O'Donell + + * scripts/check-obsolete-constructs.py: New test script. + * scripts/check-installed-headers.sh: Remove tests for + obsolete typedefs, superseded by check-obsolete-constructs.py. + * Rules: Run scripts/check-obsolete-constructs.py over $(headers) + as a special test. Update commentary. + * posix/bits/types.h (__SQUAD_TYPE, __S64_TYPE): Define as __int64_t. + (__UQUAD_TYPE, __U64_TYPE): Define as __uint64_t. + Update commentary. + * posix/sys/types.h (__u_intN_t): Remove. + (u_int8_t): Typedef using __uint8_t. + (u_int16_t): Typedef using __uint16_t. + (u_int32_t): Typedef using __uint32_t. + (u_int64_t): Typedef using __uint64_t. + +Conflicts: + Rules + (textual conflicts due to lack of check-wrapper-headers test.) + +diff --git a/Rules b/Rules +index 5abb7270aa8e24aa..a07dbb8d978b5769 100644 +--- a/Rules ++++ b/Rules +@@ -82,7 +82,8 @@ $(common-objpfx)dummy.c: + common-generated += dummy.o dummy.c + + ifneq "$(headers)" "" +-# Special test of all the installed headers in this directory. ++# Test that all of the headers installed by this directory can be compiled ++# in isolation. + tests-special += $(objpfx)check-installed-headers-c.out + libof-check-installed-headers-c := testsuite + $(objpfx)check-installed-headers-c.out: \ +@@ -93,6 +94,8 @@ $(objpfx)check-installed-headers-c.out: \ + $(evaluate-test) + + ifneq "$(CXX)" "" ++# If a C++ compiler is available, also test that they can be compiled ++# in isolation as C++. + tests-special += $(objpfx)check-installed-headers-cxx.out + libof-check-installed-headers-cxx := testsuite + $(objpfx)check-installed-headers-cxx.out: \ +@@ -101,8 +104,19 @@ $(objpfx)check-installed-headers-cxx.out: \ + "$(CXX) $(filter-out -std=%,$(CXXFLAGS)) -D_ISOMAC $(+includes)" \ + $(headers) > $@; \ + $(evaluate-test) +-endif +-endif ++endif # $(CXX) ++ ++# Test that none of the headers installed by this directory use certain ++# obsolete constructs (e.g. legacy BSD typedefs superseded by stdint.h). ++# This script does not need $(py-env). ++tests-special += $(objpfx)check-obsolete-constructs.out ++libof-check-obsolete-constructs := testsuite ++$(objpfx)check-obsolete-constructs.out: \ ++ $(..)scripts/check-obsolete-constructs.py $(headers) ++ $(PYTHON) $^ > $@ 2>&1; \ ++ $(evaluate-test) ++ ++endif # $(headers) + + # This makes all the auxiliary and test programs. + +diff --git a/posix/bits/types.h b/posix/bits/types.h +index 5e22ce41bf4c29b3..64f344c6e7897491 100644 +--- a/posix/bits/types.h ++++ b/posix/bits/types.h +@@ -86,7 +86,7 @@ __extension__ typedef unsigned long long int __uintmax_t; + 32 -- "natural" 32-bit type (always int) + 64 -- "natural" 64-bit type (long or long long) + LONG32 -- 32-bit type, traditionally long +- QUAD -- 64-bit type, always long long ++ QUAD -- 64-bit type, traditionally long long + WORD -- natural type of __WORDSIZE bits (int or long) + LONGWORD -- type of __WORDSIZE bits, traditionally long + +@@ -112,14 +112,14 @@ __extension__ typedef unsigned long long int __uintmax_t; + #define __SLONGWORD_TYPE long int + #define __ULONGWORD_TYPE unsigned long int + #if __WORDSIZE == 32 +-# define __SQUAD_TYPE __quad_t +-# define __UQUAD_TYPE __u_quad_t ++# define __SQUAD_TYPE __int64_t ++# define __UQUAD_TYPE __uint64_t + # define __SWORD_TYPE int + # define __UWORD_TYPE unsigned int + # define __SLONG32_TYPE long int + # define __ULONG32_TYPE unsigned long int +-# define __S64_TYPE __quad_t +-# define __U64_TYPE __u_quad_t ++# define __S64_TYPE __int64_t ++# define __U64_TYPE __uint64_t + /* We want __extension__ before typedef's that use nonstandard base types + such as `long long' in C89 mode. */ + # define __STD_TYPE __extension__ typedef +diff --git a/posix/sys/types.h b/posix/sys/types.h +index db524d6cd13f0379..47eff1a7b1a91c81 100644 +--- a/posix/sys/types.h ++++ b/posix/sys/types.h +@@ -154,37 +154,20 @@ typedef unsigned int uint; + + #include + +-#if !__GNUC_PREREQ (2, 7) +- + /* These were defined by ISO C without the first `_'. */ +-typedef unsigned char u_int8_t; +-typedef unsigned short int u_int16_t; +-typedef unsigned int u_int32_t; +-# if __WORDSIZE == 64 +-typedef unsigned long int u_int64_t; +-# else +-__extension__ typedef unsigned long long int u_int64_t; +-# endif +- +-typedef int register_t; +- +-#else +- +-/* For GCC 2.7 and later, we can use specific type-size attributes. */ +-# define __u_intN_t(N, MODE) \ +- typedef unsigned int u_int##N##_t __attribute__ ((__mode__ (MODE))) +- +-__u_intN_t (8, __QI__); +-__u_intN_t (16, __HI__); +-__u_intN_t (32, __SI__); +-__u_intN_t (64, __DI__); ++typedef __uint8_t u_int8_t; ++typedef __uint16_t u_int16_t; ++typedef __uint32_t u_int32_t; ++typedef __uint64_t u_int64_t; + ++#if __GNUC_PREREQ (2, 7) + typedef int register_t __attribute__ ((__mode__ (__word__))); +- ++#else ++typedef int register_t; ++#endif + + /* Some code from BIND tests this macro to see if the types above are + defined. */ +-#endif + #define __BIT_TYPES_DEFINED__ 1 + + +diff --git a/scripts/check-installed-headers.sh b/scripts/check-installed-headers.sh +index 7a1969b43a144ebb..c2aeea5aabcc7ffd 100644 +--- a/scripts/check-installed-headers.sh ++++ b/scripts/check-installed-headers.sh +@@ -16,11 +16,9 @@ + # License along with the GNU C Library; if not, see + # . + +-# Check installed headers for cleanliness. For each header, confirm +-# that it's possible to compile a file that includes that header and +-# does nothing else, in several different compilation modes. Also, +-# scan the header for a set of obsolete typedefs that should no longer +-# appear. ++# For each installed header, confirm that it's possible to compile a ++# file that includes that header and does nothing else, in several ++# different compilation modes. + + # These compilation switches assume GCC or compatible, which is probably + # fine since we also assume that when _building_ glibc. +@@ -31,13 +29,6 @@ cxx_modes="-std=c++98 -std=gnu++98 -std=c++11 -std=gnu++11" + # These are probably the most commonly used three. + lib_modes="-D_DEFAULT_SOURCE=1 -D_GNU_SOURCE=1 -D_XOPEN_SOURCE=700" + +-# sys/types.h+bits/types.h have to define the obsolete types. +-# rpc(svc)/* have the obsolete types too deeply embedded in their API +-# to remove. +-skip_obsolete_type_check='*/sys/types.h|*/bits/types.h|*/rpc/*|*/rpcsvc/*' +-obsolete_type_re=\ +-'\<((__)?(quad_t|u(short|int|long|_(char|short|int([0-9]+_t)?|long|quad_t))))\>' +- + if [ $# -lt 3 ]; then + echo "usage: $0 c|c++ \"compile command\" header header header..." >&2 + exit 2 +@@ -46,14 +37,10 @@ case "$1" in + (c) + lang_modes="$c_modes" + cih_test_c=$(mktemp ${TMPDIR-/tmp}/cih_test_XXXXXX.c) +- already="$skip_obsolete_type_check" + ;; + (c++) + lang_modes="$cxx_modes" + cih_test_c=$(mktemp ${TMPDIR-/tmp}/cih_test_XXXXXX.cc) +- # The obsolete-type check can be skipped for C++; it is +- # sufficient to do it for C. +- already="*" + ;; + (*) + echo "usage: $0 c|c++ \"compile command\" header header header..." >&2 +@@ -155,22 +142,8 @@ $expanded_lib_mode + int avoid_empty_translation_unit; + EOF + if $cc_cmd -fsyntax-only $lang_mode "$cih_test_c" 2>&1 +- then +- includes=$($cc_cmd -fsyntax-only -H $lang_mode \ +- "$cih_test_c" 2>&1 | sed -ne 's/^[.][.]* //p') +- for h in $includes; do +- # Don't repeat work. +- eval 'case "$h" in ('"$already"') continue;; esac' +- +- if grep -qE "$obsolete_type_re" "$h"; then +- echo "*** Obsolete types detected:" +- grep -HE "$obsolete_type_re" "$h" +- failed=1 +- fi +- already="$already|$h" +- done +- else +- failed=1 ++ then : ++ else failed=1 + fi + done + done +diff --git a/scripts/check-obsolete-constructs.py b/scripts/check-obsolete-constructs.py +new file mode 100755 +index 0000000000000000..ce5c72251f4d7cc0 +--- /dev/null ++++ b/scripts/check-obsolete-constructs.py +@@ -0,0 +1,466 @@ ++#! /usr/bin/python3 ++# 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, see ++# . ++ ++"""Verifies that installed headers do not use any obsolete constructs: ++ * legacy BSD typedefs superseded by : ++ ushort uint ulong u_char u_short u_int u_long u_intNN_t quad_t u_quad_t ++ (sys/types.h is allowed to _define_ these types, but not to use them ++ to define anything else). ++""" ++ ++import argparse ++import collections ++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). ++ """ ++ ++ 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() ++ ++# ++# Base and generic classes for individual checks. ++# ++ ++class ConstructChecker: ++ """Scan a stream of C preprocessing tokens and possibly report ++ problems with them. The REPORTER object passed to __init__ has ++ one method, reporter.error(token, message), which should be ++ called to indicate a problem detected at the position of TOKEN. ++ If MESSAGE contains the four-character sequence '{!r}' then that ++ will be replaced with a textual representation of TOKEN. ++ """ ++ def __init__(self, reporter): ++ self.reporter = reporter ++ ++ def examine(self, tok): ++ """Called once for each token in a header file. ++ Call self.reporter.error if a problem is detected. ++ """ ++ raise NotImplementedError ++ ++ def eof(self): ++ """Called once at the end of the stream. Subclasses need only ++ override this if it might have something to do.""" ++ pass ++ ++class NoCheck(ConstructChecker): ++ """Generic checker class which doesn't do anything. Substitute this ++ class for a real checker when a particular check should be skipped ++ for some file.""" ++ ++ def examine(self, tok): ++ pass ++ ++# ++# Check for obsolete type names. ++# ++ ++# The obsolete type names we're looking for: ++OBSOLETE_TYPE_RE_ = re.compile(r"""\A ++ (__)? ++ ( quad_t ++ | u(?: short | int | long ++ | _(?: char | short | int(?:[0-9]+_t)? | long | quad_t ))) ++\Z""", re.VERBOSE) ++ ++class ObsoleteNotAllowed(ConstructChecker): ++ """Don't allow any use of the obsolete typedefs.""" ++ def examine(self, tok): ++ if OBSOLETE_TYPE_RE_.match(tok.text): ++ self.reporter.error(tok, "use of {!r}") ++ ++class ObsoletePrivateDefinitionsAllowed(ConstructChecker): ++ """Allow definitions of the private versions of the ++ obsolete typedefs; that is, 'typedef [anything] __obsolete;' ++ """ ++ def __init__(self, reporter): ++ super().__init__(reporter) ++ self.in_typedef = False ++ self.prev_token = None ++ ++ def examine(self, tok): ++ # bits/types.h hides 'typedef' in a macro sometimes. ++ if (tok.kind == "IDENT" ++ and tok.text in ("typedef", "__STD_TYPE") ++ and tok.context is None): ++ self.in_typedef = True ++ elif tok.kind == "PUNCTUATOR" and tok.text == ";" and self.in_typedef: ++ self.in_typedef = False ++ if self.prev_token.kind == "IDENT": ++ m = OBSOLETE_TYPE_RE_.match(self.prev_token.text) ++ if m and m.group(1) != "__": ++ self.reporter.error(self.prev_token, "use of {!r}") ++ self.prev_token = None ++ else: ++ self._check_prev() ++ ++ self.prev_token = tok ++ ++ def eof(self): ++ self._check_prev() ++ ++ def _check_prev(self): ++ if (self.prev_token is not None ++ and self.prev_token.kind == "IDENT" ++ and OBSOLETE_TYPE_RE_.match(self.prev_token.text)): ++ self.reporter.error(self.prev_token, "use of {!r}") ++ ++class ObsoletePublicDefinitionsAllowed(ConstructChecker): ++ """Allow definitions of the public versions of the obsolete ++ typedefs. Only specific forms of definition are allowed: ++ ++ typedef __obsolete obsolete; // identifiers must agree ++ typedef __uintN_t u_intN_t; // N must agree ++ typedef unsigned long int ulong; ++ typedef unsigned short int ushort; ++ typedef unsigned int uint; ++ """ ++ def __init__(self, reporter): ++ super().__init__(reporter) ++ self.typedef_tokens = [] ++ ++ def examine(self, tok): ++ if tok.kind in ("WHITESPACE", "BLOCK_COMMENT", ++ "LINE_COMMENT", "NL", "ESCNL"): ++ pass ++ ++ elif (tok.kind == "IDENT" and tok.text == "typedef" ++ and tok.context is None): ++ if self.typedef_tokens: ++ self.reporter.error(tok, "typedef inside typedef") ++ self._reset() ++ self.typedef_tokens.append(tok) ++ ++ elif tok.kind == "PUNCTUATOR" and tok.text == ";": ++ self._finish() ++ ++ elif self.typedef_tokens: ++ self.typedef_tokens.append(tok) ++ ++ def eof(self): ++ self._reset() ++ ++ def _reset(self): ++ while self.typedef_tokens: ++ tok = self.typedef_tokens.pop(0) ++ if tok.kind == "IDENT" and OBSOLETE_TYPE_RE_.match(tok.text): ++ self.reporter.error(tok, "use of {!r}") ++ ++ def _finish(self): ++ if not self.typedef_tokens: return ++ if self.typedef_tokens[-1].kind == "IDENT": ++ m = OBSOLETE_TYPE_RE_.match(self.typedef_tokens[-1].text) ++ if m: ++ if self._permissible_public_definition(m): ++ self.typedef_tokens.clear() ++ self._reset() ++ ++ def _permissible_public_definition(self, m): ++ if m.group(1) == "__": return False ++ name = m.group(2) ++ toks = self.typedef_tokens ++ ntok = len(toks) ++ if ntok == 3 and toks[1].kind == "IDENT": ++ defn = toks[1].text ++ n = OBSOLETE_TYPE_RE_.match(defn) ++ if n and n.group(1) == "__" and n.group(2) == name: ++ return True ++ ++ if (name[:5] == "u_int" and name[-2:] == "_t" ++ and defn[:6] == "__uint" and defn[-2:] == "_t" ++ and name[5:-2] == defn[6:-2]): ++ return True ++ ++ return False ++ ++ if (name == "ulong" and ntok == 5 ++ and toks[1].kind == "IDENT" and toks[1].text == "unsigned" ++ and toks[2].kind == "IDENT" and toks[2].text == "long" ++ and toks[3].kind == "IDENT" and toks[3].text == "int"): ++ return True ++ ++ if (name == "ushort" and ntok == 5 ++ and toks[1].kind == "IDENT" and toks[1].text == "unsigned" ++ and toks[2].kind == "IDENT" and toks[2].text == "short" ++ and toks[3].kind == "IDENT" and toks[3].text == "int"): ++ return True ++ ++ if (name == "uint" and ntok == 4 ++ and toks[1].kind == "IDENT" and toks[1].text == "unsigned" ++ and toks[2].kind == "IDENT" and toks[2].text == "int"): ++ return True ++ ++ return False ++ ++def ObsoleteTypedefChecker(reporter, fname): ++ """Factory: produce an instance of the appropriate ++ obsolete-typedef checker for FNAME.""" ++ ++ # The obsolete rpc/ and rpcsvc/ headers are allowed to use the ++ # obsolete types, because it would be more trouble than it's ++ # worth to remove them from headers that we intend to stop ++ # installing eventually anyway. ++ if (fname.startswith("rpc/") ++ or fname.startswith("rpcsvc/") ++ or "/rpc/" in fname ++ or "/rpcsvc/" in fname): ++ return NoCheck(reporter) ++ ++ # bits/types.h is allowed to define the __-versions of the ++ # obsolete types. ++ if (fname == "bits/types.h" ++ or fname.endswith("/bits/types.h")): ++ return ObsoletePrivateDefinitionsAllowed(reporter) ++ ++ # sys/types.h is allowed to use the __-versions of the ++ # obsolete types, but only to define the unprefixed versions. ++ if (fname == "sys/types.h" ++ or fname.endswith("/sys/types.h")): ++ return ObsoletePublicDefinitionsAllowed(reporter) ++ ++ return ObsoleteNotAllowed(reporter) ++ ++# ++# Master control ++# ++ ++class HeaderChecker: ++ """Perform all of the checks on each header. This is also the ++ "reporter" object expected by tokenize_c and ConstructChecker. ++ """ ++ def __init__(self): ++ self.fname = None ++ self.status = 0 ++ ++ def error(self, tok, message): ++ self.status = 1 ++ if '{!r}' in message: ++ message = message.format(tok.text) ++ sys.stderr.write("{}:{}:{}: error: {}\n".format( ++ self.fname, tok.line, tok.column, message)) ++ ++ def check(self, fname): ++ self.fname = fname ++ try: ++ with open(fname, "rt") as fp: ++ contents = fp.read() ++ except OSError as e: ++ sys.stderr.write("{}: {}\n".format(fname, e.strerror)) ++ self.status = 1 ++ return ++ ++ typedef_checker = ObsoleteTypedefChecker(self, self.fname) ++ ++ for tok in tokenize_c(contents, self): ++ typedef_checker.examine(tok) ++ ++def main(): ++ ap = argparse.ArgumentParser(description=__doc__) ++ ap.add_argument("headers", metavar="header", nargs="+", ++ help="one or more headers to scan for obsolete constructs") ++ args = ap.parse_args() ++ ++ checker = HeaderChecker() ++ for fname in args.headers: ++ # Headers whose installed name begins with "finclude/" contain ++ # Fortran, not C, and this program should completely ignore them. ++ if not (fname.startswith("finclude/") or "/finclude/" in fname): ++ checker.check(fname) ++ sys.exit(checker.status) ++ ++main() diff --git a/SOURCES/glibc-rh1774021.patch b/SOURCES/glibc-rh1774021.patch new file mode 100644 index 0000000..e298717 --- /dev/null +++ b/SOURCES/glibc-rh1774021.patch @@ -0,0 +1,24 @@ +commit d5dfad4326fc683c813df1e37bbf5cf920591c8e +Author: Marcin Kościelnicki +Date: Thu Nov 21 00:20:15 2019 +0100 + + rtld: Check __libc_enable_secure before honoring LD_PREFER_MAP_32BIT_EXEC (CVE-2019-19126) [BZ #25204] + + The problem was introduced in glibc 2.23, in commit + b9eb92ab05204df772eb4929eccd018637c9f3e9 + ("Add Prefer_MAP_32BIT_EXEC to map executable pages with MAP_32BIT"). + +diff --git a/sysdeps/unix/sysv/linux/x86_64/64/dl-librecon.h b/sysdeps/unix/sysv/linux/x86_64/64/dl-librecon.h +index 194369174df08946..ac694c032e7baf87 100644 +--- a/sysdeps/unix/sysv/linux/x86_64/64/dl-librecon.h ++++ b/sysdeps/unix/sysv/linux/x86_64/64/dl-librecon.h +@@ -31,7 +31,8 @@ + environment variable, LD_PREFER_MAP_32BIT_EXEC. */ + #define EXTRA_LD_ENVVARS \ + case 21: \ +- if (memcmp (envline, "PREFER_MAP_32BIT_EXEC", 21) == 0) \ ++ if (!__libc_enable_secure \ ++ && memcmp (envline, "PREFER_MAP_32BIT_EXEC", 21) == 0) \ + GLRO(dl_x86_cpu_features).feature[index_arch_Prefer_MAP_32BIT_EXEC] \ + |= bit_arch_Prefer_MAP_32BIT_EXEC; \ + break; diff --git a/SOURCES/glibc-rh1774114.patch b/SOURCES/glibc-rh1774114.patch new file mode 100644 index 0000000..bdee317 --- /dev/null +++ b/SOURCES/glibc-rh1774114.patch @@ -0,0 +1,85 @@ +commit 58e8f5fd2ba47b6dc47fd4d0a35e4175c7c87aaa +Author: Andreas Schwab +Date: Wed Oct 9 17:46:47 2019 +0200 + + ldconfig: handle .dynstr located in separate segment (bug 25087) + + To determine the load offset of the DT_STRTAB section search for the + segment containing it, instead of using the load offset of the first + segment. + +diff --git a/elf/readelflib.c b/elf/readelflib.c +index 5a1e2dc2dfa36599..8774e779f5abbfbb 100644 +--- a/elf/readelflib.c ++++ b/elf/readelflib.c +@@ -45,7 +45,6 @@ process_elf_file (const char *file_name, const char *lib, int *flag, + { + int i; + unsigned int j; +- ElfW(Addr) loadaddr; + unsigned int dynamic_addr; + size_t dynamic_size; + char *program_interpreter; +@@ -87,7 +86,6 @@ process_elf_file (const char *file_name, const char *lib, int *flag, + libc5/libc6. */ + *flag = FLAG_ELF; + +- loadaddr = -1; + dynamic_addr = 0; + dynamic_size = 0; + program_interpreter = NULL; +@@ -98,11 +96,6 @@ process_elf_file (const char *file_name, const char *lib, int *flag, + + switch (segment->p_type) + { +- case PT_LOAD: +- if (loadaddr == (ElfW(Addr)) -1) +- loadaddr = segment->p_vaddr - segment->p_offset; +- break; +- + case PT_DYNAMIC: + if (dynamic_addr) + error (0, 0, _("more than one dynamic segment\n")); +@@ -176,11 +169,6 @@ process_elf_file (const char *file_name, const char *lib, int *flag, + } + + } +- if (loadaddr == (ElfW(Addr)) -1) +- { +- /* Very strange. */ +- loadaddr = 0; +- } + + /* Now we can read the dynamic sections. */ + if (dynamic_size == 0) +@@ -197,7 +185,29 @@ process_elf_file (const char *file_name, const char *lib, int *flag, + check_ptr (dyn_entry); + if (dyn_entry->d_tag == DT_STRTAB) + { +- dynamic_strings = (char *) (file_contents + dyn_entry->d_un.d_val - loadaddr); ++ /* Find the file offset of the segment containing the dynamic ++ string table. */ ++ ElfW(Off) loadoff = -1; ++ for (i = 0, segment = elf_pheader; ++ i < elf_header->e_phnum; i++, segment++) ++ { ++ if (segment->p_type == PT_LOAD ++ && dyn_entry->d_un.d_val >= segment->p_vaddr ++ && (dyn_entry->d_un.d_val - segment->p_vaddr ++ < segment->p_filesz)) ++ { ++ loadoff = segment->p_vaddr - segment->p_offset; ++ break; ++ } ++ } ++ if (loadoff == (ElfW(Off)) -1) ++ { ++ /* Very strange. */ ++ loadoff = 0; ++ } ++ ++ dynamic_strings = (char *) (file_contents + dyn_entry->d_un.d_val ++ - loadoff); + check_ptr (dynamic_strings); + break; + } diff --git a/SOURCES/glibc-rh1774115.patch b/SOURCES/glibc-rh1774115.patch new file mode 100644 index 0000000..a660644 --- /dev/null +++ b/SOURCES/glibc-rh1774115.patch @@ -0,0 +1,103 @@ +Partial backport without the new tst-dlopen-aout-pie test. The test +fails because the a self-dlopen of a PIE binary succeeds, as commit +23d2e5faf0bca6d9b31bef4aa162b95ee64cbfc6 ("elf: Self-dlopen failure +with explict loader invocation [BZ #24900]") has not been backported. + +commit 77523d5e43cb5721c23855eb6045b0607a3b30a0 +Author: Florian Weimer +Date: Fri Oct 4 21:23:51 2019 +0200 + + elf: Assign TLS modid later during dlopen [BZ #24930] + + Commit a42faf59d6d9f82e5293a9ebcc26d9c9e562b12b ("Fix BZ #16634.") + attempted to fix a TLS modid consistency issue by adding additional + checks to the open_verify function. However, this is fragile + because open_verify cannot reliably predict whether + _dl_map_object_from_fd will later fail in the more complex cases + (such as memory allocation failures). Therefore, this commit + assigns the TLS modid as late as possible. At that point, the link + map pointer will eventually be passed to _dl_close, which will undo + the TLS modid assignment. + + Reviewed-by: Gabriel F. T. Gomes + +diff --git a/elf/dl-load.c b/elf/dl-load.c +index bb839ef70ff46f37..b190b28e32e47391 100644 +--- a/elf/dl-load.c ++++ b/elf/dl-load.c +@@ -1134,27 +1134,21 @@ _dl_map_object_from_fd (const char *name, const char *origname, int fd, + offset. We will adjust it later. */ + l->l_tls_initimage = (void *) ph->p_vaddr; + +- /* If not loading the initial set of shared libraries, +- check whether we should permit loading a TLS segment. */ +- if (__glibc_likely (l->l_type == lt_library) +- /* If GL(dl_tls_dtv_slotinfo_list) == NULL, then rtld.c did +- not set up TLS data structures, so don't use them now. */ +- || __glibc_likely (GL(dl_tls_dtv_slotinfo_list) != NULL)) +- { +- /* Assign the next available module ID. */ +- l->l_tls_modid = _dl_next_tls_modid (); +- break; +- } ++ /* l->l_tls_modid is assigned below, once there is no ++ possibility for failure. */ + ++ if (l->l_type != lt_library ++ && GL(dl_tls_dtv_slotinfo_list) == NULL) ++ { + #ifdef SHARED +- /* We are loading the executable itself when the dynamic +- linker was executed directly. The setup will happen +- later. Otherwise, the TLS data structures are already +- initialized, and we assigned a TLS modid above. */ +- assert (l->l_prev == NULL || (mode & __RTLD_AUDIT) != 0); ++ /* We are loading the executable itself when the dynamic ++ linker was executed directly. The setup will happen ++ later. */ ++ assert (l->l_prev == NULL || (mode & __RTLD_AUDIT) != 0); + #else +- assert (false && "TLS not initialized in static application"); ++ assert (false && "TLS not initialized in static application"); + #endif ++ } + break; + + case PT_GNU_STACK: +@@ -1395,6 +1389,18 @@ cannot enable executable stack as shared object requires"); + add_name_to_object (l, ((const char *) D_PTR (l, l_info[DT_STRTAB]) + + l->l_info[DT_SONAME]->d_un.d_val)); + ++ /* _dl_close can only eventually undo the module ID assignment (via ++ remove_slotinfo) if this function returns a pointer to a link ++ map. Therefore, delay this step until all possibilities for ++ failure have been excluded. */ ++ if (l->l_tls_blocksize > 0 ++ && (__glibc_likely (l->l_type == lt_library) ++ /* If GL(dl_tls_dtv_slotinfo_list) == NULL, then rtld.c did ++ not set up TLS data structures, so don't use them now. */ ++ || __glibc_likely (GL(dl_tls_dtv_slotinfo_list) != NULL))) ++ /* Assign the next available module ID. */ ++ l->l_tls_modid = _dl_next_tls_modid (); ++ + #ifdef DL_AFTER_LOAD + DL_AFTER_LOAD (l); + #endif +@@ -1662,17 +1668,6 @@ open_verify (const char *name, int fd, + errstring = N_("only ET_DYN and ET_EXEC can be loaded"); + goto call_lose; + } +- else if (__glibc_unlikely (ehdr->e_type == ET_EXEC +- && (mode & __RTLD_OPENEXEC) == 0)) +- { +- /* BZ #16634. It is an error to dlopen ET_EXEC (unless +- __RTLD_OPENEXEC is explicitly set). We return error here +- so that code in _dl_map_object_from_fd does not try to set +- l_tls_modid for this module. */ +- +- errstring = N_("cannot dynamically load executable"); +- goto call_lose; +- } + else if (__glibc_unlikely (ehdr->e_phentsize != sizeof (ElfW(Phdr)))) + { + errstring = N_("ELF file's phentsize not the expected size"); diff --git a/SOURCES/glibc-rh1775294.patch b/SOURCES/glibc-rh1775294.patch new file mode 100644 index 0000000..1805d6c --- /dev/null +++ b/SOURCES/glibc-rh1775294.patch @@ -0,0 +1,70 @@ +commit bfa864e1645e140da2e1aae3cf0d0ba0674f6eb5 +Author: Emilio Cobos Álvarez +Date: Tue Nov 12 19:18:32 2019 +0100 + + Don't use a custom wrapper macro around __has_include (bug 25189). + + This causes issues when using clang with -frewrite-includes to e.g., + submit the translation unit to a distributed compiler. + + In my case, I was building Firefox using sccache. + + See [1] for a reduced test-case since I initially thought this was a + clang bug, and [2] for more context. + + Apparently doing this is invalid C++ per [cpp.cond], which mentions [3]: + + > The #ifdef and #ifndef directives, and the defined conditional + > inclusion operator, shall treat __has_include and __has_cpp_attribute + > as if they were the names of defined macros. The identifiers + > __has_include and __has_cpp_attribute shall not appear in any context + > not mentioned in this subclause. + + [1]: https://bugs.llvm.org/show_bug.cgi?id=43982 + [2]: https://bugs.llvm.org/show_bug.cgi?id=37990 + [3]: http://eel.is/c++draft/cpp.cond#7.sentence-2 + + Change-Id: Id4b8ee19176a9e4624b533087ba870c418f27e60 + +diff --git a/misc/sys/cdefs.h b/misc/sys/cdefs.h +index 9e840e602f815d86..3f6fe3cc8563b493 100644 +--- a/misc/sys/cdefs.h ++++ b/misc/sys/cdefs.h +@@ -412,14 +412,6 @@ + # define __glibc_has_attribute(attr) 0 + #endif + +-#ifdef __has_include +-/* Do not use a function-like macro, so that __has_include can inhibit +- macro expansion. */ +-# define __glibc_has_include __has_include +-#else +-# define __glibc_has_include(header) 0 +-#endif +- + #if (!defined _Noreturn \ + && (defined __STDC_VERSION__ ? __STDC_VERSION__ : 0) < 201112 \ + && !__GNUC_PREREQ (4,7)) +diff --git a/sysdeps/unix/sysv/linux/bits/statx.h b/sysdeps/unix/sysv/linux/bits/statx.h +index 206878723fd37881..aaccfdc2dc03a1dc 100644 +--- a/sysdeps/unix/sysv/linux/bits/statx.h ++++ b/sysdeps/unix/sysv/linux/bits/statx.h +@@ -26,11 +26,13 @@ + + /* Use "" to work around incorrect macro expansion of the + __has_include argument (GCC PR 80005). */ +-#if __glibc_has_include ("linux/stat.h") +-# include "linux/stat.h" +-# ifdef STATX_TYPE +-# define __statx_timestamp_defined 1 +-# define __statx_defined 1 ++#ifdef __has_include ++# if __has_include ("linux/stat.h") ++# include "linux/stat.h" ++# ifdef STATX_TYPE ++# define __statx_timestamp_defined 1 ++# define __statx_defined 1 ++# endif + # endif + #endif + diff --git a/SOURCES/glibc-rh1775819.patch b/SOURCES/glibc-rh1775819.patch new file mode 100644 index 0000000..a9e6338 --- /dev/null +++ b/SOURCES/glibc-rh1775819.patch @@ -0,0 +1,33 @@ +commit f55e312bcd6582b5ff68fdcc1781c7017796dc91 +Author: Florian Weimer +Date: Thu Nov 28 14:42:11 2019 +0100 + + libio: Disable vtable validation for pre-2.1 interposed handles [BZ #25203] + + Commit c402355dfa7807b8e0adb27c009135a7e2b9f1b0 ("libio: Disable + vtable validation in case of interposition [BZ #23313]") only covered + the interposable glibc 2.1 handles, in libio/stdfiles.c. The + parallel code in libio/oldstdfiles.c needs similar detection logic. + + Fixes (again) commit db3476aff19b75c4fdefbe65fcd5f0a90588ba51 + ("libio: Implement vtable verification [BZ #20191]"). + + Change-Id: Ief6f9f17e91d1f7263421c56a7dc018f4f595c21 + (cherry picked from commit cb61630ed712d033f54295f776967532d3f4b46a) + +diff --git a/libio/oldstdfiles.c b/libio/oldstdfiles.c +index f3dda89004..9fe809bd68 100644 +--- a/libio/oldstdfiles.c ++++ b/libio/oldstdfiles.c +@@ -87,6 +87,11 @@ _IO_check_libio (void) + stdout->_vtable_offset = stderr->_vtable_offset = + ((int) sizeof (struct _IO_FILE) + - (int) sizeof (struct _IO_FILE_complete)); ++ ++ if (_IO_stdin_.vtable != &_IO_old_file_jumps ++ || _IO_stdout_.vtable != &_IO_old_file_jumps ++ || _IO_stderr_.vtable != &_IO_old_file_jumps) ++ IO_set_accept_foreign_vtables (&_IO_vtable_check); + } + } + diff --git a/SOURCES/glibc-rh1777241.patch b/SOURCES/glibc-rh1777241.patch new file mode 100644 index 0000000..e68afdd --- /dev/null +++ b/SOURCES/glibc-rh1777241.patch @@ -0,0 +1,88 @@ +commit bfdb731438206b0f70fe7afa890681155c30b419 +Author: Stefan Liebler +Date: Wed Nov 27 12:35:40 2019 +0100 + + S390: Fix handling of needles crossing a page in strstr z15 ifunc-variant. [BZ #25226] + + If the specified needle crosses a page-boundary, the s390-z15 ifunc variant of + strstr truncates the needle which results in invalid results. + + This is fixed by loading the needle beyond the page boundary to v18 instead of v16. + The bug is sometimes observable in test-strstr.c in check1 and check2 as the + haystack and needle is stored on stack. Thus the needle can be on a page boundary. + + check2 is now extended to test haystack / needles located on stack, at end of page + and on two pages. + + This bug was introduced with commit 6f47401bd5fc71209219779a0426170a9a7395b0 + ("S390: Add arch13 strstr ifunc variant.") and is already released in glibc 2.30. + +diff --git a/string/test-strstr.c b/string/test-strstr.c +index 5861b01b73e4c315..e9e14c1ee605516e 100644 +--- a/string/test-strstr.c ++++ b/string/test-strstr.c +@@ -138,16 +138,45 @@ check1 (void) + static void + check2 (void) + { +- const char s1[] = ", enable_static, \0, enable_shared, "; ++ const char s1_stack[] = ", enable_static, \0, enable_shared, "; ++ const size_t s1_byte_count = 18; ++ const char *s2_stack = &(s1_stack[s1_byte_count]); ++ const size_t s2_byte_count = 18; + char *exp_result; +- char *s2 = (void *) buf1 + page_size - 18; ++ const size_t page_size_real = getpagesize (); + +- strcpy (s2, s1); +- exp_result = stupid_strstr (s1, s1 + 18); ++ /* Haystack at end of page. The following page is protected. */ ++ char *s1_page_end = (void *) buf1 + page_size - s1_byte_count; ++ strcpy (s1_page_end, s1_stack); ++ ++ /* Haystack which crosses a page boundary. ++ Note: page_size is at least 2 * getpagesize. See test_init. */ ++ char *s1_page_cross = (void *) buf1 + page_size_real - 8; ++ strcpy (s1_page_cross, s1_stack); ++ ++ /* Needle at end of page. The following page is protected. */ ++ char *s2_page_end = (void *) buf2 + page_size - s2_byte_count; ++ strcpy (s2_page_end, s2_stack); ++ ++ /* Needle which crosses a page boundary. ++ Note: page_size is at least 2 * getpagesize. See test_init. */ ++ char *s2_page_cross = (void *) buf2 + page_size_real - 8; ++ strcpy (s2_page_cross, s2_stack); ++ ++ exp_result = stupid_strstr (s1_stack, s2_stack); + FOR_EACH_IMPL (impl, 0) + { +- check_result (impl, s1, s1 + 18, exp_result); +- check_result (impl, s2, s1 + 18, exp_result); ++ check_result (impl, s1_stack, s2_stack, exp_result); ++ check_result (impl, s1_stack, s2_page_end, exp_result); ++ check_result (impl, s1_stack, s2_page_cross, exp_result); ++ ++ check_result (impl, s1_page_end, s2_stack, exp_result); ++ check_result (impl, s1_page_end, s2_page_end, exp_result); ++ check_result (impl, s1_page_end, s2_page_cross, exp_result); ++ ++ check_result (impl, s1_page_cross, s2_stack, exp_result); ++ check_result (impl, s1_page_cross, s2_page_end, exp_result); ++ check_result (impl, s1_page_cross, s2_page_cross, exp_result); + } + } + +diff --git a/sysdeps/s390/strstr-arch13.S b/sysdeps/s390/strstr-arch13.S +index 929b026adfeba740..faa969849e09c2e1 100644 +--- a/sysdeps/s390/strstr-arch13.S ++++ b/sysdeps/s390/strstr-arch13.S +@@ -164,7 +164,7 @@ ENTRY(STRSTR_ARCH13) + vfenezb %v19,%v18,%v18 /* Search zero in loaded needle bytes. */ + veclb %v19,%v21 /* Zero index <= max loaded byte index? */ + jle .Lneedle_loaded /* -> v18 contains full needle. */ +- vl %v16,0(%r3) /* Load needle beyond page boundary. */ ++ vl %v18,0(%r3) /* Load needle beyond page boundary. */ + vfenezb %v19,%v18,%v18 + j .Lneedle_loaded + END(STRSTR_ARCH13) diff --git a/SOURCES/glibc-rh1780204-01.patch b/SOURCES/glibc-rh1780204-01.patch new file mode 100644 index 0000000..33a1752 --- /dev/null +++ b/SOURCES/glibc-rh1780204-01.patch @@ -0,0 +1,48 @@ +From 34e75eb497941f829115e6e8f34e899575f4e342 Mon Sep 17 00:00:00 2001 +From: Stefan Liebler +Date: Fri, 18 Oct 2019 14:57:14 +0200 +Subject: [PATCH 01/28] S390: Add new s390 platform z15. + +The new IBM z15 is added to platform string array. +The macro _DL_PLATFORMS_COUNT is incremented. + +(cherry picked from commit 2901743568452403849be7295c8732faa7732339) +--- + sysdeps/s390/dl-procinfo.c | 4 ++-- + sysdeps/s390/dl-procinfo.h | 2 +- + 2 files changed, 3 insertions(+), 3 deletions(-) + +diff --git a/sysdeps/s390/dl-procinfo.c b/sysdeps/s390/dl-procinfo.c +index 6ea220a171..6d76d7d008 100644 +--- a/sysdeps/s390/dl-procinfo.c ++++ b/sysdeps/s390/dl-procinfo.c +@@ -63,11 +63,11 @@ PROCINFO_CLASS const char _dl_s390_cap_flags[19][9] + #if !defined PROCINFO_DECL && defined SHARED + ._dl_s390_platforms + #else +-PROCINFO_CLASS const char _dl_s390_platforms[9][7] ++PROCINFO_CLASS const char _dl_s390_platforms[10][7] + #endif + #ifndef PROCINFO_DECL + = { +- "g5", "z900", "z990", "z9-109", "z10", "z196", "zEC12", "z13", "z14" ++ "g5", "z900", "z990", "z9-109", "z10", "z196", "zEC12", "z13", "z14", "z15" + } + #endif + #if !defined SHARED || defined PROCINFO_DECL +diff --git a/sysdeps/s390/dl-procinfo.h b/sysdeps/s390/dl-procinfo.h +index d03c69fffd..b367bbe8ce 100644 +--- a/sysdeps/s390/dl-procinfo.h ++++ b/sysdeps/s390/dl-procinfo.h +@@ -23,7 +23,7 @@ + + #define _DL_HWCAP_COUNT 19 + +-#define _DL_PLATFORMS_COUNT 9 ++#define _DL_PLATFORMS_COUNT 10 + + /* The kernel provides up to 32 capability bits with elf_hwcap. */ + #define _DL_FIRST_PLATFORM 32 +-- +2.18.2 + diff --git a/SOURCES/glibc-rh1780204-02.patch b/SOURCES/glibc-rh1780204-02.patch new file mode 100644 index 0000000..e9d2ea3 --- /dev/null +++ b/SOURCES/glibc-rh1780204-02.patch @@ -0,0 +1,159 @@ +From 73f98d03d2cde34255c0a39ef18902bffdce0185 Mon Sep 17 00:00:00 2001 +From: Stefan Liebler +Date: Wed, 11 Dec 2019 15:09:14 +0100 +Subject: [PATCH 02/28] Always use wordsize-64 version of s_rint.c. + +This patch replaces s_rint.c in sysdeps/dbl-64 with the one in +sysdeps/dbl-64/wordsize-64 and removes the latter one. +The code is not changed except changes in code style. + +Also adjusted the include path in x86_64 file. + +Reviewed-by: Adhemerval Zanella +(cherry picked from commit ab48bdd098a675dddb360faafc497a61c4bd4334) +--- + sysdeps/ieee754/dbl-64/s_rint.c | 32 ++++++------ + sysdeps/ieee754/dbl-64/wordsize-64/s_rint.c | 57 --------------------- + sysdeps/x86_64/fpu/multiarch/s_rint-c.c | 2 +- + 3 files changed, 17 insertions(+), 74 deletions(-) + delete mode 100644 sysdeps/ieee754/dbl-64/wordsize-64/s_rint.c + +diff --git a/sysdeps/ieee754/dbl-64/s_rint.c b/sysdeps/ieee754/dbl-64/s_rint.c +index cb0f5ca298..7f3dc87b96 100644 +--- a/sysdeps/ieee754/dbl-64/s_rint.c ++++ b/sysdeps/ieee754/dbl-64/s_rint.c +@@ -1,4 +1,3 @@ +-/* @(#)s_rint.c 5.1 93/09/24 */ + /* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. +@@ -25,38 +24,39 @@ + #include + + static const double +- TWO52[2] = { +- 4.50359962737049600000e+15, /* 0x43300000, 0x00000000 */ +- -4.50359962737049600000e+15, /* 0xC3300000, 0x00000000 */ ++TWO52[2] = { ++ 4.50359962737049600000e+15, /* 0x43300000, 0x00000000 */ ++ -4.50359962737049600000e+15, /* 0xC3300000, 0x00000000 */ + }; + + double + __rint (double x) + { +- int32_t i0, j0, sx; +- double w, t; +- GET_HIGH_WORD (i0, x); +- sx = (i0 >> 31) & 1; +- j0 = ((i0 >> 20) & 0x7ff) - 0x3ff; ++ int64_t i0, sx; ++ int32_t j0; ++ EXTRACT_WORDS64 (i0, x); ++ sx = (i0 >> 63) & 1; ++ j0 = ((i0 >> 52) & 0x7ff) - 0x3ff; + if (j0 < 52) + { + if (j0 < 0) + { +- w = TWO52[sx] + x; +- t = w - TWO52[sx]; +- GET_HIGH_WORD (i0, t); +- SET_HIGH_WORD (t, (i0 & 0x7fffffff) | (sx << 31)); ++ double w = TWO52[sx] + x; ++ double t = w - TWO52[sx]; ++ EXTRACT_WORDS64 (i0, t); ++ INSERT_WORDS64 (t, (i0 & UINT64_C (0x7fffffffffffffff)) ++ | (sx << 63)); + return t; + } + } + else + { + if (j0 == 0x400) +- return x + x; /* inf or NaN */ ++ return x + x; /* inf or NaN */ + else +- return x; /* x is integral */ ++ return x; /* x is integral */ + } +- w = TWO52[sx] + x; ++ double w = TWO52[sx] + x; + return w - TWO52[sx]; + } + #ifndef __rint +diff --git a/sysdeps/ieee754/dbl-64/wordsize-64/s_rint.c b/sysdeps/ieee754/dbl-64/wordsize-64/s_rint.c +deleted file mode 100644 +index 622e479c5f..0000000000 +--- a/sysdeps/ieee754/dbl-64/wordsize-64/s_rint.c ++++ /dev/null +@@ -1,57 +0,0 @@ +-/* +- * ==================================================== +- * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. +- * +- * Developed at SunPro, a Sun Microsystems, Inc. business. +- * Permission to use, copy, modify, and distribute this +- * software is freely granted, provided that this notice +- * is preserved. +- * ==================================================== +- */ +- +-/* +- * rint(x) +- * Return x rounded to integral value according to the prevailing +- * rounding mode. +- * Method: +- * Using floating addition. +- * Exception: +- * Inexact flag raised if x not equal to rint(x). +- */ +- +-#include +-#include +-#include +- +-static const double +-TWO52[2]={ +- 4.50359962737049600000e+15, /* 0x43300000, 0x00000000 */ +- -4.50359962737049600000e+15, /* 0xC3300000, 0x00000000 */ +-}; +- +-double +-__rint(double x) +-{ +- int64_t i0,sx; +- int32_t j0; +- EXTRACT_WORDS64(i0,x); +- sx = (i0>>63)&1; +- j0 = ((i0>>52)&0x7ff)-0x3ff; +- if(j0<52) { +- if(j0<0) { +- double w = TWO52[sx]+x; +- double t = w-TWO52[sx]; +- EXTRACT_WORDS64(i0,t); +- INSERT_WORDS64(t,(i0&UINT64_C(0x7fffffffffffffff))|(sx<<63)); +- return t; +- } +- } else { +- if(j0==0x400) return x+x; /* inf or NaN */ +- else return x; /* x is integral */ +- } +- double w = TWO52[sx]+x; +- return w-TWO52[sx]; +-} +-#ifndef __rint +-libm_alias_double (__rint, rint) +-#endif +diff --git a/sysdeps/x86_64/fpu/multiarch/s_rint-c.c b/sysdeps/x86_64/fpu/multiarch/s_rint-c.c +index 162a630ff9..b010150f52 100644 +--- a/sysdeps/x86_64/fpu/multiarch/s_rint-c.c ++++ b/sysdeps/x86_64/fpu/multiarch/s_rint-c.c +@@ -1,3 +1,3 @@ + #undef __rint + #define __rint __rint_c +-#include ++#include +-- +2.18.2 + diff --git a/SOURCES/glibc-rh1780204-03.patch b/SOURCES/glibc-rh1780204-03.patch new file mode 100644 index 0000000..1e5d46f --- /dev/null +++ b/SOURCES/glibc-rh1780204-03.patch @@ -0,0 +1,257 @@ +From 7741c9c7f566d09f57db45df9377ac497f6232a5 Mon Sep 17 00:00:00 2001 +From: Stefan Liebler +Date: Wed, 11 Dec 2019 15:09:15 +0100 +Subject: [PATCH 03/28] Always use wordsize-64 version of s_floor.c. + +This patch replaces s_floor.c in sysdeps/dbl-64 with the one in +sysdeps/dbl-64/wordsize-64 and removes the latter one. +The code is not changed except changes in code style. + +Also adjusted the include path in x86_64 and sparc64 files. + +Reviewed-by: Adhemerval Zanella +(cherry picked from commit 95b0c2c431510013eb2f7385fc078ee2498f83bf) +Note: glibc 2.28 had no NO_MATH_REDIRECT in wordsize-64 version. +--- + sysdeps/ieee754/dbl-64/s_floor.c | 92 +++++++++---------- + sysdeps/ieee754/dbl-64/wordsize-64/s_floor.c | 71 -------------- + .../sparc64/fpu/multiarch/s_floor-generic.c | 2 +- + .../sparc64/fpu/multiarch/s_floor-vis3.c | 2 +- + sysdeps/x86_64/fpu/multiarch/s_floor-c.c | 2 +- + 5 files changed, 45 insertions(+), 124 deletions(-) + delete mode 100644 sysdeps/ieee754/dbl-64/wordsize-64/s_floor.c + +diff --git a/sysdeps/ieee754/dbl-64/s_floor.c b/sysdeps/ieee754/dbl-64/s_floor.c +index f27c6f3ad2..b551a1aafa 100644 +--- a/sysdeps/ieee754/dbl-64/s_floor.c ++++ b/sysdeps/ieee754/dbl-64/s_floor.c +@@ -1,4 +1,24 @@ +-/* @(#)s_floor.c 5.1 93/09/24 */ ++/* Round double to integer away from zero. ++ Copyright (C) 2011-2019 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ Contributed by Ulrich Drepper , 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 ++ . */ ++ ++/* Based on a version which carries the following copyright: */ ++ + /* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. +@@ -10,6 +30,11 @@ + * ==================================================== + */ + ++#include ++#include ++#include ++#include ++ + /* + * floor(x) + * Return x rounded toward -inf to integral value +@@ -17,68 +42,35 @@ + * Bit twiddling. + */ + +-#include +-#include +-#include +- + double + __floor (double x) + { +- int32_t i0, i1, j0; +- uint32_t i, j; +- EXTRACT_WORDS (i0, i1, x); +- j0 = ((i0 >> 20) & 0x7ff) - 0x3ff; +- if (j0 < 20) ++ int64_t i0; ++ EXTRACT_WORDS64 (i0, x); ++ int32_t j0 = ((i0 >> 52) & 0x7ff) - 0x3ff; ++ if (__glibc_likely (j0 < 52)) + { + if (j0 < 0) + { +- /* return 0*sign(x) if |x|<1 */ ++ /* return 0 * sign (x) if |x| < 1 */ + if (i0 >= 0) +- { +- i0 = i1 = 0; +- } +- else if (((i0 & 0x7fffffff) | i1) != 0) +- { +- i0 = 0xbff00000; i1 = 0; +- } ++ i0 = 0; ++ else if ((i0 & 0x7fffffffffffffffl) != 0) ++ i0 = 0xbff0000000000000l; + } + else + { +- i = (0x000fffff) >> j0; +- if (((i0 & i) | i1) == 0) +- return x; /* x is integral */ ++ uint64_t i = 0x000fffffffffffffl >> j0; ++ if ((i0 & i) == 0) ++ return x; /* x is integral */ + if (i0 < 0) +- i0 += (0x00100000) >> j0; +- i0 &= (~i); i1 = 0; +- } +- } +- else if (j0 > 51) +- { +- if (j0 == 0x400) +- return x + x; /* inf or NaN */ +- else +- return x; /* x is integral */ +- } +- else +- { +- i = ((uint32_t) (0xffffffff)) >> (j0 - 20); +- if ((i1 & i) == 0) +- return x; /* x is integral */ +- if (i0 < 0) +- { +- if (j0 == 20) +- i0 += 1; +- else +- { +- j = i1 + (1 << (52 - j0)); +- if (j < i1) +- i0 += 1; /* got a carry */ +- i1 = j; +- } ++ i0 += 0x0010000000000000l >> j0; ++ i0 &= ~i; + } +- i1 &= (~i); ++ INSERT_WORDS64 (x, i0); + } +- INSERT_WORDS (x, i0, i1); ++ else if (j0 == 0x400) ++ return x + x; /* inf or NaN */ + return x; + } + #ifndef __floor +diff --git a/sysdeps/ieee754/dbl-64/wordsize-64/s_floor.c b/sysdeps/ieee754/dbl-64/wordsize-64/s_floor.c +deleted file mode 100644 +index f7e0a77ec3..0000000000 +--- a/sysdeps/ieee754/dbl-64/wordsize-64/s_floor.c ++++ /dev/null +@@ -1,71 +0,0 @@ +-/* Round double to integer away from zero. +- Copyright (C) 2011-2018 Free Software Foundation, Inc. +- This file is part of the GNU C Library. +- Contributed by Ulrich Drepper , 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 +- . */ +- +-/* Based on a version which carries the following copyright: */ +- +-/* +- * ==================================================== +- * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. +- * +- * Developed at SunPro, a Sun Microsystems, Inc. business. +- * Permission to use, copy, modify, and distribute this +- * software is freely granted, provided that this notice +- * is preserved. +- * ==================================================== +- */ +- +-#include +-#include +-#include +-#include +- +-/* +- * floor(x) +- * Return x rounded toward -inf to integral value +- * Method: +- * Bit twiddling. +- */ +- +- +-double +-__floor (double x) +-{ +- int64_t i0; +- EXTRACT_WORDS64(i0,x); +- int32_t j0 = ((i0>>52)&0x7ff)-0x3ff; +- if(__builtin_expect(j0<52, 1)) { +- if(j0<0) { +- /* return 0*sign(x) if |x|<1 */ +- if(i0>=0) {i0=0;} +- else if((i0&0x7fffffffffffffffl)!=0) +- { i0=0xbff0000000000000l;} +- } else { +- uint64_t i = (0x000fffffffffffffl)>>j0; +- if((i0&i)==0) return x; /* x is integral */ +- if(i0<0) i0 += (0x0010000000000000l)>>j0; +- i0 &= (~i); +- } +- INSERT_WORDS64(x,i0); +- } else if (j0==0x400) +- return x+x; /* inf or NaN */ +- return x; +-} +-#ifndef __floor +-libm_alias_double (__floor, floor) +-#endif +diff --git a/sysdeps/sparc/sparc64/fpu/multiarch/s_floor-generic.c b/sysdeps/sparc/sparc64/fpu/multiarch/s_floor-generic.c +index 0f3361a9fb..c92b600df1 100644 +--- a/sysdeps/sparc/sparc64/fpu/multiarch/s_floor-generic.c ++++ b/sysdeps/sparc/sparc64/fpu/multiarch/s_floor-generic.c +@@ -1,2 +1,2 @@ + #define __floor __floor_generic +-#include ++#include +diff --git a/sysdeps/sparc/sparc64/fpu/multiarch/s_floor-vis3.c b/sysdeps/sparc/sparc64/fpu/multiarch/s_floor-vis3.c +index d9974161b0..35564b9139 100644 +--- a/sysdeps/sparc/sparc64/fpu/multiarch/s_floor-vis3.c ++++ b/sysdeps/sparc/sparc64/fpu/multiarch/s_floor-vis3.c +@@ -20,4 +20,4 @@ + + #define __floor __floor_vis3 + +-#include ++#include +diff --git a/sysdeps/x86_64/fpu/multiarch/s_floor-c.c b/sysdeps/x86_64/fpu/multiarch/s_floor-c.c +index 68733b69ef..002d12247e 100644 +--- a/sysdeps/x86_64/fpu/multiarch/s_floor-c.c ++++ b/sysdeps/x86_64/fpu/multiarch/s_floor-c.c +@@ -1,3 +1,3 @@ + #undef __floor + #define __floor __floor_c +-#include ++#include +-- +2.18.2 + diff --git a/SOURCES/glibc-rh1780204-04.patch b/SOURCES/glibc-rh1780204-04.patch new file mode 100644 index 0000000..e447d66 --- /dev/null +++ b/SOURCES/glibc-rh1780204-04.patch @@ -0,0 +1,192 @@ +From d3833cb69c7ff42ac8df68ed7b646c98c3a32eb8 Mon Sep 17 00:00:00 2001 +From: Stefan Liebler +Date: Wed, 11 Dec 2019 15:09:16 +0100 +Subject: [PATCH 04/28] Always use wordsize-64 version of s_ceil.c. + +This patch replaces s_ceil.c in sysdeps/dbl-64 with the one in +sysdeps/dbl-64/wordsize-64 and removes the latter one. +The code is not changed except changes in code style. + +Also adjusted the include path in x86_64 and sparc64 files. + +Reviewed-by: Adhemerval Zanella +(cherry picked from commit 9f234eafe8698fd9a441ca2309a299d0bd771156) +--- + sysdeps/ieee754/dbl-64/s_ceil.c | 59 ++++++------------- + sysdeps/ieee754/dbl-64/wordsize-64/s_ceil.c | 51 ---------------- + .../sparc64/fpu/multiarch/s_ceil-generic.c | 2 +- + .../sparc/sparc64/fpu/multiarch/s_ceil-vis3.c | 2 +- + sysdeps/x86_64/fpu/multiarch/s_ceil-c.c | 2 +- + 5 files changed, 21 insertions(+), 95 deletions(-) + delete mode 100644 sysdeps/ieee754/dbl-64/wordsize-64/s_ceil.c + +diff --git a/sysdeps/ieee754/dbl-64/s_ceil.c b/sysdeps/ieee754/dbl-64/s_ceil.c +index 5a7434c737..3becdfc515 100644 +--- a/sysdeps/ieee754/dbl-64/s_ceil.c ++++ b/sysdeps/ieee754/dbl-64/s_ceil.c +@@ -24,61 +24,38 @@ + double + __ceil (double x) + { +- int32_t i0, i1, j0; +- uint32_t i, j; +- EXTRACT_WORDS (i0, i1, x); +- j0 = ((i0 >> 20) & 0x7ff) - 0x3ff; +- if (j0 < 20) ++ int64_t i0, i; ++ int32_t j0; ++ EXTRACT_WORDS64 (i0, x); ++ j0 = ((i0 >> 52) & 0x7ff) - 0x3ff; ++ if (j0 <= 51) + { + if (j0 < 0) + { +- /* return 0*sign(x) if |x|<1 */ ++ /* return 0 * sign(x) if |x| < 1 */ + if (i0 < 0) +- { +- i0 = 0x80000000; i1 = 0; +- } +- else if ((i0 | i1) != 0) +- { +- i0 = 0x3ff00000; i1 = 0; +- } ++ i0 = INT64_C (0x8000000000000000); ++ else if (i0 != 0) ++ i0 = INT64_C (0x3ff0000000000000); + } + else + { +- i = (0x000fffff) >> j0; +- if (((i0 & i) | i1) == 0) +- return x; /* x is integral */ ++ i = INT64_C (0x000fffffffffffff) >> j0; ++ if ((i0 & i) == 0) ++ return x; /* x is integral */ + if (i0 > 0) +- i0 += (0x00100000) >> j0; +- i0 &= (~i); i1 = 0; ++ i0 += UINT64_C (0x0010000000000000) >> j0; ++ i0 &= ~i; + } + } +- else if (j0 > 51) ++ else + { + if (j0 == 0x400) +- return x + x; /* inf or NaN */ ++ return x + x; /* inf or NaN */ + else +- return x; /* x is integral */ +- } +- else +- { +- i = ((uint32_t) (0xffffffff)) >> (j0 - 20); +- if ((i1 & i) == 0) +- return x; /* x is integral */ +- if (i0 > 0) +- { +- if (j0 == 20) +- i0 += 1; +- else +- { +- j = i1 + (1 << (52 - j0)); +- if (j < i1) +- i0 += 1; /* got a carry */ +- i1 = j; +- } +- } +- i1 &= (~i); ++ return x; /* x is integral */ + } +- INSERT_WORDS (x, i0, i1); ++ INSERT_WORDS64 (x, i0); + return x; + } + #ifndef __ceil +diff --git a/sysdeps/ieee754/dbl-64/wordsize-64/s_ceil.c b/sysdeps/ieee754/dbl-64/wordsize-64/s_ceil.c +deleted file mode 100644 +index b99829d2b0..0000000000 +--- a/sysdeps/ieee754/dbl-64/wordsize-64/s_ceil.c ++++ /dev/null +@@ -1,51 +0,0 @@ +-/* @(#)s_ceil.c 5.1 93/09/24 */ +-/* +- * ==================================================== +- * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. +- * +- * Developed at SunPro, a Sun Microsystems, Inc. business. +- * Permission to use, copy, modify, and distribute this +- * software is freely granted, provided that this notice +- * is preserved. +- * ==================================================== +- */ +- +-/* +- * ceil(x) +- * Return x rounded toward -inf to integral value +- * Method: +- * Bit twiddling. +- */ +- +-#include +-#include +-#include +- +-double +-__ceil(double x) +-{ +- int64_t i0,i; +- int32_t j0; +- EXTRACT_WORDS64(i0,x); +- j0 = ((i0>>52)&0x7ff)-0x3ff; +- if(j0<=51) { +- if(j0<0) { +- /* return 0*sign(x) if |x|<1 */ +- if(i0<0) {i0=INT64_C(0x8000000000000000);} +- else if(i0!=0) { i0=INT64_C(0x3ff0000000000000);} +- } else { +- i = INT64_C(0x000fffffffffffff)>>j0; +- if((i0&i)==0) return x; /* x is integral */ +- if(i0>0) i0 += UINT64_C(0x0010000000000000)>>j0; +- i0 &= (~i); +- } +- } else { +- if(j0==0x400) return x+x; /* inf or NaN */ +- else return x; /* x is integral */ +- } +- INSERT_WORDS64(x,i0); +- return x; +-} +-#ifndef __ceil +-libm_alias_double (__ceil, ceil) +-#endif +diff --git a/sysdeps/sparc/sparc64/fpu/multiarch/s_ceil-generic.c b/sysdeps/sparc/sparc64/fpu/multiarch/s_ceil-generic.c +index febea745e1..80f68b6766 100644 +--- a/sysdeps/sparc/sparc64/fpu/multiarch/s_ceil-generic.c ++++ b/sysdeps/sparc/sparc64/fpu/multiarch/s_ceil-generic.c +@@ -1,2 +1,2 @@ + #define __ceil __ceil_generic +-#include ++#include +diff --git a/sysdeps/sparc/sparc64/fpu/multiarch/s_ceil-vis3.c b/sysdeps/sparc/sparc64/fpu/multiarch/s_ceil-vis3.c +index a03a0090f0..59822e0f8c 100644 +--- a/sysdeps/sparc/sparc64/fpu/multiarch/s_ceil-vis3.c ++++ b/sysdeps/sparc/sparc64/fpu/multiarch/s_ceil-vis3.c +@@ -20,4 +20,4 @@ + + #define __ceil __ceil_vis3 + +-#include ++#include +diff --git a/sysdeps/x86_64/fpu/multiarch/s_ceil-c.c b/sysdeps/x86_64/fpu/multiarch/s_ceil-c.c +index 6a5ea3ff27..ada28baa1a 100644 +--- a/sysdeps/x86_64/fpu/multiarch/s_ceil-c.c ++++ b/sysdeps/x86_64/fpu/multiarch/s_ceil-c.c +@@ -1,2 +1,2 @@ + #define __ceil __ceil_c +-#include ++#include +-- +2.18.2 + diff --git a/SOURCES/glibc-rh1780204-05.patch b/SOURCES/glibc-rh1780204-05.patch new file mode 100644 index 0000000..3c139a2 --- /dev/null +++ b/SOURCES/glibc-rh1780204-05.patch @@ -0,0 +1,157 @@ +From e8f1c08a49d313b210ed4104c20646c105bab6a4 Mon Sep 17 00:00:00 2001 +From: Stefan Liebler +Date: Wed, 11 Dec 2019 15:09:17 +0100 +Subject: [PATCH 05/28] Always use wordsize-64 version of s_trunc.c. + +This patch replaces s_trunc.c in sysdeps/dbl-64 with the one in +sysdeps/dbl-64/wordsize-64 and removes the latter one. +The code is not changed except changes in code style. + +Also adjusted the include path in x86_64 and sparc64 files. + +Reviewed-by: Adhemerval Zanella +(cherry picked from commit 1c94bf0f0a50ce66c808e2ea9b7e417785798b73) +--- + sysdeps/ieee754/dbl-64/s_trunc.c | 25 ++++----- + sysdeps/ieee754/dbl-64/wordsize-64/s_trunc.c | 54 ------------------- + .../sparc64/fpu/multiarch/s_trunc-generic.c | 2 +- + .../sparc64/fpu/multiarch/s_trunc-vis3.c | 2 +- + sysdeps/x86_64/fpu/multiarch/s_trunc-c.c | 2 +- + 5 files changed, 13 insertions(+), 72 deletions(-) + delete mode 100644 sysdeps/ieee754/dbl-64/wordsize-64/s_trunc.c + +diff --git a/sysdeps/ieee754/dbl-64/s_trunc.c b/sysdeps/ieee754/dbl-64/s_trunc.c +index 6ffabb410a..38bb33d337 100644 +--- a/sysdeps/ieee754/dbl-64/s_trunc.c ++++ b/sysdeps/ieee754/dbl-64/s_trunc.c +@@ -26,31 +26,26 @@ + double + __trunc (double x) + { +- int32_t i0, j0; +- uint32_t i1; +- int sx; +- +- EXTRACT_WORDS (i0, i1, x); +- sx = i0 & 0x80000000; +- j0 = ((i0 >> 20) & 0x7ff) - 0x3ff; +- if (j0 < 20) ++ int64_t i0, j0; ++ int64_t sx; ++ ++ EXTRACT_WORDS64 (i0, x); ++ sx = i0 & UINT64_C (0x8000000000000000); ++ j0 = ((i0 >> 52) & 0x7ff) - 0x3ff; ++ if (j0 < 52) + { + if (j0 < 0) + /* The magnitude of the number is < 1 so the result is +-0. */ +- INSERT_WORDS (x, sx, 0); ++ INSERT_WORDS64 (x, sx); + else +- INSERT_WORDS (x, sx | (i0 & ~(0x000fffff >> j0)), 0); ++ INSERT_WORDS64 (x, sx | (i0 & ~(UINT64_C (0x000fffffffffffff) >> j0))); + } +- else if (j0 > 51) ++ else + { + if (j0 == 0x400) + /* x is inf or NaN. */ + return x + x; + } +- else +- { +- INSERT_WORDS (x, i0, i1 & ~(0xffffffffu >> (j0 - 20))); +- } + + return x; + } +diff --git a/sysdeps/ieee754/dbl-64/wordsize-64/s_trunc.c b/sysdeps/ieee754/dbl-64/wordsize-64/s_trunc.c +deleted file mode 100644 +index 19a09b894e..0000000000 +--- a/sysdeps/ieee754/dbl-64/wordsize-64/s_trunc.c ++++ /dev/null +@@ -1,54 +0,0 @@ +-/* Truncate argument to nearest integral value not larger than the argument. +- Copyright (C) 1997-2018 Free Software Foundation, Inc. +- This file is part of the GNU C Library. +- Contributed by Ulrich Drepper , 1997. +- +- The GNU C Library is free software; you can redistribute it and/or +- modify it under the terms of the GNU Lesser General Public +- License as published by the Free Software Foundation; either +- version 2.1 of the License, or (at your option) any later version. +- +- The GNU C Library is distributed in the hope that it will be useful, +- but WITHOUT ANY WARRANTY; without even the implied warranty of +- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +- Lesser General Public License for 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 +- +- +-double +-__trunc (double x) +-{ +- int64_t i0, j0; +- int64_t sx; +- +- EXTRACT_WORDS64 (i0, x); +- sx = i0 & UINT64_C(0x8000000000000000); +- j0 = ((i0 >> 52) & 0x7ff) - 0x3ff; +- if (j0 < 52) +- { +- if (j0 < 0) +- /* The magnitude of the number is < 1 so the result is +-0. */ +- INSERT_WORDS64 (x, sx); +- else +- INSERT_WORDS64 (x, sx | (i0 & ~(UINT64_C(0x000fffffffffffff) >> j0))); +- } +- else +- { +- if (j0 == 0x400) +- /* x is inf or NaN. */ +- return x + x; +- } +- +- return x; +-} +-#ifndef __trunc +-libm_alias_double (__trunc, trunc) +-#endif +diff --git a/sysdeps/sparc/sparc64/fpu/multiarch/s_trunc-generic.c b/sysdeps/sparc/sparc64/fpu/multiarch/s_trunc-generic.c +index 00abd2a643..c198ebb3d5 100644 +--- a/sysdeps/sparc/sparc64/fpu/multiarch/s_trunc-generic.c ++++ b/sysdeps/sparc/sparc64/fpu/multiarch/s_trunc-generic.c +@@ -1,2 +1,2 @@ + #define __trunc __trunc_generic +-#include ++#include +diff --git a/sysdeps/sparc/sparc64/fpu/multiarch/s_trunc-vis3.c b/sysdeps/sparc/sparc64/fpu/multiarch/s_trunc-vis3.c +index a89916ba89..766bb22629 100644 +--- a/sysdeps/sparc/sparc64/fpu/multiarch/s_trunc-vis3.c ++++ b/sysdeps/sparc/sparc64/fpu/multiarch/s_trunc-vis3.c +@@ -20,4 +20,4 @@ + + #define __trunc __trunc_vis3 + +-#include ++#include +diff --git a/sysdeps/x86_64/fpu/multiarch/s_trunc-c.c b/sysdeps/x86_64/fpu/multiarch/s_trunc-c.c +index 6204ae3c77..8aa499fbb8 100644 +--- a/sysdeps/x86_64/fpu/multiarch/s_trunc-c.c ++++ b/sysdeps/x86_64/fpu/multiarch/s_trunc-c.c +@@ -1,2 +1,2 @@ + #define __trunc __trunc_c +-#include ++#include +-- +2.18.2 + diff --git a/SOURCES/glibc-rh1780204-06.patch b/SOURCES/glibc-rh1780204-06.patch new file mode 100644 index 0000000..b0d1765 --- /dev/null +++ b/SOURCES/glibc-rh1780204-06.patch @@ -0,0 +1,167 @@ +From 577943dac79a5657bdfe51e06e289eb2473c3d2e Mon Sep 17 00:00:00 2001 +From: Stefan Liebler +Date: Wed, 11 Dec 2019 15:09:17 +0100 +Subject: [PATCH 06/28] Always use wordsize-64 version of s_round.c. + +This patch replaces s_round.c in sysdeps/dbl-64 with the one in +sysdeps/dbl-64/wordsize-64 and removes the latter one. + +Reviewed-by: Adhemerval Zanella +(cherry picked from commit 36e9acbd5cb2c330c0d53195db4a0ee31f2c3097) +--- + sysdeps/ieee754/dbl-64/s_round.c | 39 ++++-------- + sysdeps/ieee754/dbl-64/wordsize-64/s_round.c | 65 -------------------- + 2 files changed, 12 insertions(+), 92 deletions(-) + delete mode 100644 sysdeps/ieee754/dbl-64/wordsize-64/s_round.c + +diff --git a/sysdeps/ieee754/dbl-64/s_round.c b/sysdeps/ieee754/dbl-64/s_round.c +index fa9e83196e..bf9922edca 100644 +--- a/sysdeps/ieee754/dbl-64/s_round.c ++++ b/sysdeps/ieee754/dbl-64/s_round.c +@@ -21,38 +21,36 @@ + + #include + #include ++#include + + + double + __round (double x) + { +- int32_t i0, j0; +- uint32_t i1; ++ int64_t i0, j0; + +- EXTRACT_WORDS (i0, i1, x); +- j0 = ((i0 >> 20) & 0x7ff) - 0x3ff; +- if (j0 < 20) ++ EXTRACT_WORDS64 (i0, x); ++ j0 = ((i0 >> 52) & 0x7ff) - 0x3ff; ++ if (__glibc_likely (j0 < 52)) + { + if (j0 < 0) + { +- i0 &= 0x80000000; ++ i0 &= UINT64_C (0x8000000000000000); + if (j0 == -1) +- i0 |= 0x3ff00000; +- i1 = 0; ++ i0 |= UINT64_C (0x3ff0000000000000); + } + else + { +- uint32_t i = 0x000fffff >> j0; +- if (((i0 & i) | i1) == 0) ++ uint64_t i = UINT64_C (0x000fffffffffffff) >> j0; ++ if ((i0 & i) == 0) + /* X is integral. */ + return x; + +- i0 += 0x00080000 >> j0; ++ i0 += UINT64_C (0x0008000000000000) >> j0; + i0 &= ~i; +- i1 = 0; + } + } +- else if (j0 > 51) ++ else + { + if (j0 == 0x400) + /* Inf or NaN. */ +@@ -60,21 +58,8 @@ __round (double x) + else + return x; + } +- else +- { +- uint32_t i = 0xffffffff >> (j0 - 20); +- if ((i1 & i) == 0) +- /* X is integral. */ +- return x; +- +- uint32_t j = i1 + (1 << (51 - j0)); +- if (j < i1) +- i0 += 1; +- i1 = j; +- i1 &= ~i; +- } + +- INSERT_WORDS (x, i0, i1); ++ INSERT_WORDS64 (x, i0); + return x; + } + libm_alias_double (__round, round) +diff --git a/sysdeps/ieee754/dbl-64/wordsize-64/s_round.c b/sysdeps/ieee754/dbl-64/wordsize-64/s_round.c +deleted file mode 100644 +index 3323621ce3..0000000000 +--- a/sysdeps/ieee754/dbl-64/wordsize-64/s_round.c ++++ /dev/null +@@ -1,65 +0,0 @@ +-/* Round double to integer away from zero. +- Copyright (C) 1997-2018 Free Software Foundation, Inc. +- This file is part of the GNU C Library. +- Contributed by Ulrich Drepper , 1997. +- +- The GNU C Library is free software; you can redistribute it and/or +- modify it under the terms of the GNU Lesser General Public +- License as published by the Free Software Foundation; either +- version 2.1 of the License, or (at your option) any later version. +- +- The GNU C Library is distributed in the hope that it will be useful, +- but WITHOUT ANY WARRANTY; without even the implied warranty of +- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +- Lesser General Public License for 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 +- +- +-double +-__round (double x) +-{ +- int64_t i0, j0; +- +- EXTRACT_WORDS64 (i0, x); +- j0 = ((i0 >> 52) & 0x7ff) - 0x3ff; +- if (__glibc_likely (j0 < 52)) +- { +- if (j0 < 0) +- { +- i0 &= UINT64_C(0x8000000000000000); +- if (j0 == -1) +- i0 |= UINT64_C(0x3ff0000000000000); +- } +- else +- { +- uint64_t i = UINT64_C(0x000fffffffffffff) >> j0; +- if ((i0 & i) == 0) +- /* X is integral. */ +- return x; +- +- i0 += UINT64_C(0x0008000000000000) >> j0; +- i0 &= ~i; +- } +- } +- else +- { +- if (j0 == 0x400) +- /* Inf or NaN. */ +- return x + x; +- else +- return x; +- } +- +- INSERT_WORDS64 (x, i0); +- return x; +-} +-libm_alias_double (__round, round) +-- +2.18.2 + diff --git a/SOURCES/glibc-rh1780204-07.patch b/SOURCES/glibc-rh1780204-07.patch new file mode 100644 index 0000000..13b3c3e --- /dev/null +++ b/SOURCES/glibc-rh1780204-07.patch @@ -0,0 +1,255 @@ +From 735a36828f349419379f15e942bfdf0c532d58eb Mon Sep 17 00:00:00 2001 +From: Stefan Liebler +Date: Wed, 11 Dec 2019 15:09:18 +0100 +Subject: [PATCH 07/28] Use GCC builtins for nearbyint functions if desired. + +This patch is using the corresponding GCC builtin for nearbyintf, nearbyint, +nearbintl and nearbyintf128 if the USE_FUNCTION_BUILTIN macros are defined to one +in math-use-builtins.h. + +This is the case for s390 if build with at least --march=z196 --mzarch. +Otherwise the generic implementation is used. The code of the generic +implementation is not changed. + +Reviewed-by: Adhemerval Zanella +(cherry picked from commit ae3577f607b50bf3ce9b0877e43ad2508c9da61b) +Note: The TWO52 constants are now located in # ! USE_NEARBYINT_BUILTIN +--- + sysdeps/generic/math-use-builtins.h | 29 ++++++++++++ + sysdeps/ieee754/dbl-64/s_nearbyint.c | 17 ++++--- + sysdeps/ieee754/float128/float128_private.h | 4 ++ + sysdeps/ieee754/flt-32/s_nearbyintf.c | 17 ++++--- + sysdeps/ieee754/ldbl-128/s_nearbyintl.c | 17 ++++--- + sysdeps/s390/fpu/math-use-builtins.h | 49 +++++++++++++++++++++ + 6 files changed, 115 insertions(+), 18 deletions(-) + create mode 100644 sysdeps/generic/math-use-builtins.h + create mode 100644 sysdeps/s390/fpu/math-use-builtins.h + +diff --git a/sysdeps/generic/math-use-builtins.h b/sysdeps/generic/math-use-builtins.h +new file mode 100644 +index 0000000000..e12490ed41 +--- /dev/null ++++ b/sysdeps/generic/math-use-builtins.h +@@ -0,0 +1,29 @@ ++/* Using math gcc builtins instead of generic implementation. Generic 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, see ++ . */ ++ ++#ifndef MATH_USE_BUILTINS_H ++#define MATH_USE_BUILTINS_H 1 ++ ++/* Define these macros to 1 to use __builtin_xyz instead of the ++ generic implementation. */ ++#define USE_NEARBYINT_BUILTIN 0 ++#define USE_NEARBYINTF_BUILTIN 0 ++#define USE_NEARBYINTL_BUILTIN 0 ++#define USE_NEARBYINTF128_BUILTIN 0 ++ ++#endif /* math-use-builtins.h */ +diff --git a/sysdeps/ieee754/dbl-64/s_nearbyint.c b/sysdeps/ieee754/dbl-64/s_nearbyint.c +index 903121d456..6b9f44dc8d 100644 +--- a/sysdeps/ieee754/dbl-64/s_nearbyint.c ++++ b/sysdeps/ieee754/dbl-64/s_nearbyint.c +@@ -29,16 +29,20 @@ static char rcsid[] = "$NetBSD: s_rint.c,v 1.8 1995/05/10 20:48:04 jtc Exp $"; + #include + #include + #include +- +-static const double +- TWO52[2] = { +- 4.50359962737049600000e+15, /* 0x43300000, 0x00000000 */ +- -4.50359962737049600000e+15, /* 0xC3300000, 0x00000000 */ +-}; ++#include + + double + __nearbyint (double x) + { ++#if USE_NEARBYINT_BUILTIN ++ return __builtin_nearbyint (x); ++#else ++ /* Use generic implementation. */ ++ static const double ++ TWO52[2] = { ++ 4.50359962737049600000e+15, /* 0x43300000, 0x00000000 */ ++ -4.50359962737049600000e+15, /* 0xC3300000, 0x00000000 */ ++ }; + fenv_t env; + int32_t i0, j0, sx; + double w, t; +@@ -72,5 +76,6 @@ __nearbyint (double x) + math_force_eval (t); + libc_fesetenv (&env); + return t; ++#endif /* ! USE_NEARBYINT_BUILTIN */ + } + libm_alias_double (__nearbyint, nearbyint) +diff --git a/sysdeps/ieee754/float128/float128_private.h b/sysdeps/ieee754/float128/float128_private.h +index 9dd15601e6..0bf6e8dee2 100644 +--- a/sysdeps/ieee754/float128/float128_private.h ++++ b/sysdeps/ieee754/float128/float128_private.h +@@ -138,6 +138,9 @@ + #undef libm_alias_double_ldouble + #define libm_alias_double_ldouble(func) libm_alias_float64_float128 (func) + ++#include ++#undef USE_NEARBYINTL_BUILTIN ++#define USE_NEARBYINTL_BUILTIN USE_NEARBYINTF128_BUILTIN + + /* IEEE function renames. */ + #define __ieee754_acoshl __ieee754_acoshf128 +@@ -339,6 +342,7 @@ + /* Builtin renames. */ + #define __builtin_copysignl __builtin_copysignf128 + #define __builtin_signbitl __builtin_signbit ++#define __builtin_nearbyintl __builtin_nearbyintf128 + + /* Get the constant suffix from bits/floatn-compat.h. */ + #define L(x) __f128 (x) +diff --git a/sysdeps/ieee754/flt-32/s_nearbyintf.c b/sysdeps/ieee754/flt-32/s_nearbyintf.c +index 4dfe491f27..438dcae8cc 100644 +--- a/sysdeps/ieee754/flt-32/s_nearbyintf.c ++++ b/sysdeps/ieee754/flt-32/s_nearbyintf.c +@@ -20,16 +20,20 @@ + #include + #include + #include +- +-static const float +-TWO23[2]={ +- 8.3886080000e+06, /* 0x4b000000 */ +- -8.3886080000e+06, /* 0xcb000000 */ +-}; ++#include + + float + __nearbyintf(float x) + { ++#if USE_NEARBYINTF_BUILTIN ++ return __builtin_nearbyintf (x); ++#else ++ /* Use generic implementation. */ ++ static const float ++ TWO23[2] = { ++ 8.3886080000e+06, /* 0x4b000000 */ ++ -8.3886080000e+06, /* 0xcb000000 */ ++ }; + fenv_t env; + int32_t i0,j0,sx; + float w,t; +@@ -57,5 +61,6 @@ __nearbyintf(float x) + math_force_eval (t); + libc_fesetenvf (&env); + return t; ++#endif /* ! USE_NEARBYINT_BUILTIN */ + } + libm_alias_float (__nearbyint, nearbyint) +diff --git a/sysdeps/ieee754/ldbl-128/s_nearbyintl.c b/sysdeps/ieee754/ldbl-128/s_nearbyintl.c +index f044cb4334..a4ad8e82e5 100644 +--- a/sysdeps/ieee754/ldbl-128/s_nearbyintl.c ++++ b/sysdeps/ieee754/ldbl-128/s_nearbyintl.c +@@ -28,15 +28,19 @@ + #include + #include + #include +- +-static const _Float128 +-TWO112[2]={ +- L(5.19229685853482762853049632922009600E+33), /* 0x406F000000000000, 0 */ +- L(-5.19229685853482762853049632922009600E+33) /* 0xC06F000000000000, 0 */ +-}; ++#include + + _Float128 __nearbyintl(_Float128 x) + { ++#if USE_NEARBYINTL_BUILTIN ++ return __builtin_nearbyintl (x); ++#else ++ /* Use generic implementation. */ ++ static const _Float128 ++ TWO112[2] = { ++ L(5.19229685853482762853049632922009600E+33), /* 0x406F000000000000, 0 */ ++ L(-5.19229685853482762853049632922009600E+33) /* 0xC06F000000000000, 0 */ ++ }; + fenv_t env; + int64_t i0,j0,sx; + uint64_t i1 __attribute__ ((unused)); +@@ -65,5 +69,6 @@ _Float128 __nearbyintl(_Float128 x) + math_force_eval (t); + fesetenv (&env); + return t; ++#endif /* ! USE_NEARBYINTL_BUILTIN */ + } + libm_alias_ldouble (__nearbyint, nearbyint) +diff --git a/sysdeps/s390/fpu/math-use-builtins.h b/sysdeps/s390/fpu/math-use-builtins.h +new file mode 100644 +index 0000000000..7abbfb3b50 +--- /dev/null ++++ b/sysdeps/s390/fpu/math-use-builtins.h +@@ -0,0 +1,49 @@ ++/* Using math gcc builtins instead of generic implementation. s390/s390x 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, see ++ . */ ++ ++#ifndef MATH_USE_BUILTINS_S390_H ++#define MATH_USE_BUILTINS_S390_H 1 ++ ++#ifdef HAVE_S390_MIN_Z196_ZARCH_ASM_SUPPORT ++ ++# include /* For __GNUC_PREREQ. */ ++ ++/* GCC emits the z196 zarch "load fp integer" instructions for these ++ builtins if build with at least --march=z196 -mzarch. Otherwise a ++ function call to libc is emitted. */ ++# define USE_NEARBYINT_BUILTIN 1 ++# define USE_NEARBYINTF_BUILTIN 1 ++# define USE_NEARBYINTL_BUILTIN 1 ++ ++# if __GNUC_PREREQ (8, 0) ++# define USE_NEARBYINTF128_BUILTIN 1 ++# else ++# define USE_NEARBYINTF128_BUILTIN 0 ++# endif ++ ++#else ++ ++/* Disable the builtins if we do not have the z196 zarch instructions. */ ++# define USE_NEARBYINT_BUILTIN 0 ++# define USE_NEARBYINTF_BUILTIN 0 ++# define USE_NEARBYINTL_BUILTIN 0 ++# define USE_NEARBYINTF128_BUILTIN 0 ++ ++#endif /* ! HAVE_S390_MIN_Z196_ZARCH_ASM_SUPPORT */ ++ ++#endif /* math-use-builtins.h */ +-- +2.18.2 + diff --git a/SOURCES/glibc-rh1780204-08.patch b/SOURCES/glibc-rh1780204-08.patch new file mode 100644 index 0000000..9dd3a6c --- /dev/null +++ b/SOURCES/glibc-rh1780204-08.patch @@ -0,0 +1,210 @@ +From d37e99de7ab1cd8c3d427f74bf8ceb5774795fe5 Mon Sep 17 00:00:00 2001 +From: Stefan Liebler +Date: Wed, 11 Dec 2019 15:09:20 +0100 +Subject: [PATCH 08/28] Use GCC builtins for rint functions if desired. + +This patch is using the corresponding GCC builtin for rintf, rint, +rintl and rintf128 if the USE_FUNCTION_BUILTIN macros are defined to one +in math-use-builtins.h. + +This is the case for s390 if build with at least --march=z196 --mzarch. +Otherwise the generic implementation is used. The code of the generic +implementation is not changed. + +Reviewed-by: Adhemerval Zanella +(cherry picked from commit a2a9b004297b777758420c952cb6eea5985d37fe) +--- + sysdeps/generic/math-use-builtins.h | 5 +++++ + sysdeps/ieee754/dbl-64/s_rint.c | 17 +++++++++++------ + sysdeps/ieee754/float128/float128_private.h | 3 +++ + sysdeps/ieee754/flt-32/s_rintf.c | 17 +++++++++++------ + sysdeps/ieee754/ldbl-128/s_rintl.c | 17 +++++++++++------ + sysdeps/s390/fpu/math-use-builtins.h | 11 +++++++++++ + 6 files changed, 52 insertions(+), 18 deletions(-) + +diff --git a/sysdeps/generic/math-use-builtins.h b/sysdeps/generic/math-use-builtins.h +index e12490ed41..64b4a4bb5b 100644 +--- a/sysdeps/generic/math-use-builtins.h ++++ b/sysdeps/generic/math-use-builtins.h +@@ -26,4 +26,9 @@ + #define USE_NEARBYINTL_BUILTIN 0 + #define USE_NEARBYINTF128_BUILTIN 0 + ++#define USE_RINT_BUILTIN 0 ++#define USE_RINTF_BUILTIN 0 ++#define USE_RINTL_BUILTIN 0 ++#define USE_RINTF128_BUILTIN 0 ++ + #endif /* math-use-builtins.h */ +diff --git a/sysdeps/ieee754/dbl-64/s_rint.c b/sysdeps/ieee754/dbl-64/s_rint.c +index 7f3dc87b96..5f4ac7c1e3 100644 +--- a/sysdeps/ieee754/dbl-64/s_rint.c ++++ b/sysdeps/ieee754/dbl-64/s_rint.c +@@ -22,16 +22,20 @@ + #include + #include + #include +- +-static const double +-TWO52[2] = { +- 4.50359962737049600000e+15, /* 0x43300000, 0x00000000 */ +- -4.50359962737049600000e+15, /* 0xC3300000, 0x00000000 */ +-}; ++#include + + double + __rint (double x) + { ++#if USE_RINT_BUILTIN ++ return __builtin_rint (x); ++#else ++ /* Use generic implementation. */ ++ static const double ++ TWO52[2] = { ++ 4.50359962737049600000e+15, /* 0x43300000, 0x00000000 */ ++ -4.50359962737049600000e+15, /* 0xC3300000, 0x00000000 */ ++ }; + int64_t i0, sx; + int32_t j0; + EXTRACT_WORDS64 (i0, x); +@@ -58,6 +62,7 @@ __rint (double x) + } + double w = TWO52[sx] + x; + return w - TWO52[sx]; ++#endif /* ! USE_RINT_BUILTIN */ + } + #ifndef __rint + libm_alias_double (__rint, rint) +diff --git a/sysdeps/ieee754/float128/float128_private.h b/sysdeps/ieee754/float128/float128_private.h +index 0bf6e8dee2..b872aefbfd 100644 +--- a/sysdeps/ieee754/float128/float128_private.h ++++ b/sysdeps/ieee754/float128/float128_private.h +@@ -141,6 +141,8 @@ + #include + #undef USE_NEARBYINTL_BUILTIN + #define USE_NEARBYINTL_BUILTIN USE_NEARBYINTF128_BUILTIN ++#undef USE_RINTL_BUILTIN ++#define USE_RINTL_BUILTIN USE_RINTF128_BUILTIN + + /* IEEE function renames. */ + #define __ieee754_acoshl __ieee754_acoshf128 +@@ -343,6 +345,7 @@ + #define __builtin_copysignl __builtin_copysignf128 + #define __builtin_signbitl __builtin_signbit + #define __builtin_nearbyintl __builtin_nearbyintf128 ++#define __builtin_rintl __builtin_rintf128 + + /* Get the constant suffix from bits/floatn-compat.h. */ + #define L(x) __f128 (x) +diff --git a/sysdeps/ieee754/flt-32/s_rintf.c b/sysdeps/ieee754/flt-32/s_rintf.c +index db6f260a0b..a266b1999e 100644 +--- a/sysdeps/ieee754/flt-32/s_rintf.c ++++ b/sysdeps/ieee754/flt-32/s_rintf.c +@@ -16,16 +16,20 @@ + #include + #include + #include +- +-static const float +-TWO23[2]={ +- 8.3886080000e+06, /* 0x4b000000 */ +- -8.3886080000e+06, /* 0xcb000000 */ +-}; ++#include + + float + __rintf(float x) + { ++#if USE_RINTF_BUILTIN ++ return __builtin_rintf (x); ++#else ++ /* Use generic implementation. */ ++ static const float ++ TWO23[2] = { ++ 8.3886080000e+06, /* 0x4b000000 */ ++ -8.3886080000e+06, /* 0xcb000000 */ ++ }; + int32_t i0,j0,sx; + float w,t; + GET_FLOAT_WORD(i0,x); +@@ -45,6 +49,7 @@ __rintf(float x) + } + w = TWO23[sx]+x; + return w-TWO23[sx]; ++#endif /* ! USE_RINTF_BUILTIN */ + } + #ifndef __rintf + libm_alias_float (__rint, rint) +diff --git a/sysdeps/ieee754/ldbl-128/s_rintl.c b/sysdeps/ieee754/ldbl-128/s_rintl.c +index 9e6637a225..f060503066 100644 +--- a/sysdeps/ieee754/ldbl-128/s_rintl.c ++++ b/sysdeps/ieee754/ldbl-128/s_rintl.c +@@ -30,15 +30,19 @@ static char rcsid[] = "$NetBSD: $"; + #include + #include + #include +- +-static const _Float128 +-TWO112[2]={ +- 5.19229685853482762853049632922009600E+33L, /* 0x406F000000000000, 0 */ +- -5.19229685853482762853049632922009600E+33L /* 0xC06F000000000000, 0 */ +-}; ++#include + + _Float128 __rintl(_Float128 x) + { ++#if USE_RINTL_BUILTIN ++ return __builtin_rintl (x); ++#else ++ /* Use generic implementation. */ ++ static const _Float128 ++ TWO112[2] = { ++ 5.19229685853482762853049632922009600E+33L, /* 0x406F000000000000, 0 */ ++ -5.19229685853482762853049632922009600E+33L /* 0xC06F000000000000, 0 */ ++ }; + int64_t i0,j0,sx; + uint64_t i1 __attribute__ ((unused)); + _Float128 w,t; +@@ -59,5 +63,6 @@ _Float128 __rintl(_Float128 x) + } + w = TWO112[sx]+x; + return w-TWO112[sx]; ++#endif /* ! USE_RINTL_BUILTIN */ + } + libm_alias_ldouble (__rint, rint) +diff --git a/sysdeps/s390/fpu/math-use-builtins.h b/sysdeps/s390/fpu/math-use-builtins.h +index 7abbfb3b50..8b702a6a90 100644 +--- a/sysdeps/s390/fpu/math-use-builtins.h ++++ b/sysdeps/s390/fpu/math-use-builtins.h +@@ -30,10 +30,16 @@ + # define USE_NEARBYINTF_BUILTIN 1 + # define USE_NEARBYINTL_BUILTIN 1 + ++# define USE_RINT_BUILTIN 1 ++# define USE_RINTF_BUILTIN 1 ++# define USE_RINTL_BUILTIN 1 ++ + # if __GNUC_PREREQ (8, 0) + # define USE_NEARBYINTF128_BUILTIN 1 ++# define USE_RINTF128_BUILTIN 1 + # else + # define USE_NEARBYINTF128_BUILTIN 0 ++# define USE_RINTF128_BUILTIN 0 + # endif + + #else +@@ -44,6 +50,11 @@ + # define USE_NEARBYINTL_BUILTIN 0 + # define USE_NEARBYINTF128_BUILTIN 0 + ++# define USE_RINT_BUILTIN 0 ++# define USE_RINTF_BUILTIN 0 ++# define USE_RINTL_BUILTIN 0 ++# define USE_RINTF128_BUILTIN 0 ++ + #endif /* ! HAVE_S390_MIN_Z196_ZARCH_ASM_SUPPORT */ + + #endif /* math-use-builtins.h */ +-- +2.18.2 + diff --git a/SOURCES/glibc-rh1780204-09.patch b/SOURCES/glibc-rh1780204-09.patch new file mode 100644 index 0000000..fa6e2b6 --- /dev/null +++ b/SOURCES/glibc-rh1780204-09.patch @@ -0,0 +1,182 @@ +From 8353881ede286045dc5bdc00af6407560ca5d05b Mon Sep 17 00:00:00 2001 +From: Stefan Liebler +Date: Wed, 11 Dec 2019 15:09:20 +0100 +Subject: [PATCH 09/28] Use GCC builtins for floor functions if desired. + +This patch is using the corresponding GCC builtin for floorf, floor, +floorl and floorf128 if the USE_FUNCTION_BUILTIN macros are defined to one +in math-use-builtins.h. + +This is the case for s390 if build with at least --march=z196 --mzarch. +Otherwise the generic implementation is used. The code of the generic +implementation is not changed. + +Reviewed-by: Adhemerval Zanella +(cherry picked from commit 6c1b6a5e8cd91e0e1965509ad91e627e60eb00a3) +--- + sysdeps/generic/math-use-builtins.h | 5 +++++ + sysdeps/ieee754/dbl-64/s_floor.c | 6 ++++++ + sysdeps/ieee754/float128/float128_private.h | 3 +++ + sysdeps/ieee754/flt-32/s_floorf.c | 6 ++++++ + sysdeps/ieee754/ldbl-128/s_floorl.c | 6 ++++++ + sysdeps/s390/fpu/math-use-builtins.h | 11 +++++++++++ + 6 files changed, 37 insertions(+) + +diff --git a/sysdeps/generic/math-use-builtins.h b/sysdeps/generic/math-use-builtins.h +index 64b4a4bb5b..e1c5df62e4 100644 +--- a/sysdeps/generic/math-use-builtins.h ++++ b/sysdeps/generic/math-use-builtins.h +@@ -31,4 +31,9 @@ + #define USE_RINTL_BUILTIN 0 + #define USE_RINTF128_BUILTIN 0 + ++#define USE_FLOOR_BUILTIN 0 ++#define USE_FLOORF_BUILTIN 0 ++#define USE_FLOORL_BUILTIN 0 ++#define USE_FLOORF128_BUILTIN 0 ++ + #endif /* math-use-builtins.h */ +diff --git a/sysdeps/ieee754/dbl-64/s_floor.c b/sysdeps/ieee754/dbl-64/s_floor.c +index b551a1aafa..693938b708 100644 +--- a/sysdeps/ieee754/dbl-64/s_floor.c ++++ b/sysdeps/ieee754/dbl-64/s_floor.c +@@ -34,6 +34,7 @@ + #include + #include + #include ++#include + + /* + * floor(x) +@@ -45,6 +46,10 @@ + double + __floor (double x) + { ++#if USE_FLOOR_BUILTIN ++ return __builtin_floor (x); ++#else ++ /* Use generic implementation. */ + int64_t i0; + EXTRACT_WORDS64 (i0, x); + int32_t j0 = ((i0 >> 52) & 0x7ff) - 0x3ff; +@@ -72,6 +77,7 @@ __floor (double x) + else if (j0 == 0x400) + return x + x; /* inf or NaN */ + return x; ++#endif /* ! USE_FLOOR_BUILTIN */ + } + #ifndef __floor + libm_alias_double (__floor, floor) +diff --git a/sysdeps/ieee754/float128/float128_private.h b/sysdeps/ieee754/float128/float128_private.h +index b872aefbfd..667030ab06 100644 +--- a/sysdeps/ieee754/float128/float128_private.h ++++ b/sysdeps/ieee754/float128/float128_private.h +@@ -143,6 +143,8 @@ + #define USE_NEARBYINTL_BUILTIN USE_NEARBYINTF128_BUILTIN + #undef USE_RINTL_BUILTIN + #define USE_RINTL_BUILTIN USE_RINTF128_BUILTIN ++#undef USE_FLOORL_BUILTIN ++#define USE_FLOORL_BUILTIN USE_FLOORF128_BUILTIN + + /* IEEE function renames. */ + #define __ieee754_acoshl __ieee754_acoshf128 +@@ -346,6 +348,7 @@ + #define __builtin_signbitl __builtin_signbit + #define __builtin_nearbyintl __builtin_nearbyintf128 + #define __builtin_rintl __builtin_rintf128 ++#define __builtin_floorl __builtin_floorf128 + + /* Get the constant suffix from bits/floatn-compat.h. */ + #define L(x) __f128 (x) +diff --git a/sysdeps/ieee754/flt-32/s_floorf.c b/sysdeps/ieee754/flt-32/s_floorf.c +index 12aed343a0..6d37ab90a1 100644 +--- a/sysdeps/ieee754/flt-32/s_floorf.c ++++ b/sysdeps/ieee754/flt-32/s_floorf.c +@@ -23,10 +23,15 @@ + #include + #include + #include ++#include + + float + __floorf(float x) + { ++#if USE_FLOORF_BUILTIN ++ return __builtin_floorf (x); ++#else ++ /* Use generic implementation. */ + int32_t i0,j0; + uint32_t i; + GET_FLOAT_WORD(i0,x); +@@ -49,6 +54,7 @@ __floorf(float x) + } + SET_FLOAT_WORD(x,i0); + return x; ++#endif /* ! USE_FLOORF_BUILTIN */ + } + #ifndef __floorf + libm_alias_float (__floor, floor) +diff --git a/sysdeps/ieee754/ldbl-128/s_floorl.c b/sysdeps/ieee754/ldbl-128/s_floorl.c +index f9c5e014f9..6143fe6ec5 100644 +--- a/sysdeps/ieee754/ldbl-128/s_floorl.c ++++ b/sysdeps/ieee754/ldbl-128/s_floorl.c +@@ -27,9 +27,14 @@ static char rcsid[] = "$NetBSD: $"; + #include + #include + #include ++#include + + _Float128 __floorl(_Float128 x) + { ++#if USE_FLOORL_BUILTIN ++ return __builtin_floorl (x); ++#else ++ /* Use generic implementation. */ + int64_t i0,i1,j0; + uint64_t i,j; + GET_LDOUBLE_WORDS64(i0,i1,x); +@@ -64,5 +69,6 @@ _Float128 __floorl(_Float128 x) + } + SET_LDOUBLE_WORDS64(x,i0,i1); + return x; ++#endif /* ! USE_FLOORL_BUILTIN */ + } + libm_alias_ldouble (__floor, floor) +diff --git a/sysdeps/s390/fpu/math-use-builtins.h b/sysdeps/s390/fpu/math-use-builtins.h +index 8b702a6a90..c213c16c6f 100644 +--- a/sysdeps/s390/fpu/math-use-builtins.h ++++ b/sysdeps/s390/fpu/math-use-builtins.h +@@ -34,12 +34,18 @@ + # define USE_RINTF_BUILTIN 1 + # define USE_RINTL_BUILTIN 1 + ++# define USE_FLOOR_BUILTIN 1 ++# define USE_FLOORF_BUILTIN 1 ++# define USE_FLOORL_BUILTIN 1 ++ + # if __GNUC_PREREQ (8, 0) + # define USE_NEARBYINTF128_BUILTIN 1 + # define USE_RINTF128_BUILTIN 1 ++# define USE_FLOORF128_BUILTIN 1 + # else + # define USE_NEARBYINTF128_BUILTIN 0 + # define USE_RINTF128_BUILTIN 0 ++# define USE_FLOORF128_BUILTIN 0 + # endif + + #else +@@ -55,6 +61,11 @@ + # define USE_RINTL_BUILTIN 0 + # define USE_RINTF128_BUILTIN 0 + ++# define USE_FLOOR_BUILTIN 0 ++# define USE_FLOORF_BUILTIN 0 ++# define USE_FLOORL_BUILTIN 0 ++# define USE_FLOORF128_BUILTIN 0 ++ + #endif /* ! HAVE_S390_MIN_Z196_ZARCH_ASM_SUPPORT */ + + #endif /* math-use-builtins.h */ +-- +2.18.2 + diff --git a/SOURCES/glibc-rh1780204-10.patch b/SOURCES/glibc-rh1780204-10.patch new file mode 100644 index 0000000..3504976 --- /dev/null +++ b/SOURCES/glibc-rh1780204-10.patch @@ -0,0 +1,182 @@ +From 6c5e5f498cd004b3f42d97997898018df8f798a4 Mon Sep 17 00:00:00 2001 +From: Stefan Liebler +Date: Wed, 11 Dec 2019 15:09:21 +0100 +Subject: [PATCH 10/28] Use GCC builtins for ceil functions if desired. + +This patch is using the corresponding GCC builtin for ceilf, ceil, +ceill and ceilf128 if the USE_FUNCTION_BUILTIN macros are defined to one +in math-use-builtins.h. + +This is the case for s390 if build with at least --march=z196 --mzarch. +Otherwise the generic implementation is used. The code of the generic +implementation is not changed. + +Reviewed-by: Adhemerval Zanella +(cherry picked from commit 62560ee84095274bab1050817f42e782df226a17) +--- + sysdeps/generic/math-use-builtins.h | 5 +++++ + sysdeps/ieee754/dbl-64/s_ceil.c | 6 ++++++ + sysdeps/ieee754/float128/float128_private.h | 3 +++ + sysdeps/ieee754/flt-32/s_ceilf.c | 7 ++++++- + sysdeps/ieee754/ldbl-128/s_ceill.c | 6 ++++++ + sysdeps/s390/fpu/math-use-builtins.h | 11 +++++++++++ + 6 files changed, 37 insertions(+), 1 deletion(-) + +diff --git a/sysdeps/generic/math-use-builtins.h b/sysdeps/generic/math-use-builtins.h +index e1c5df62e4..076ec661b0 100644 +--- a/sysdeps/generic/math-use-builtins.h ++++ b/sysdeps/generic/math-use-builtins.h +@@ -36,4 +36,9 @@ + #define USE_FLOORL_BUILTIN 0 + #define USE_FLOORF128_BUILTIN 0 + ++#define USE_CEIL_BUILTIN 0 ++#define USE_CEILF_BUILTIN 0 ++#define USE_CEILL_BUILTIN 0 ++#define USE_CEILF128_BUILTIN 0 ++ + #endif /* math-use-builtins.h */ +diff --git a/sysdeps/ieee754/dbl-64/s_ceil.c b/sysdeps/ieee754/dbl-64/s_ceil.c +index 3becdfc515..ee4a3abc19 100644 +--- a/sysdeps/ieee754/dbl-64/s_ceil.c ++++ b/sysdeps/ieee754/dbl-64/s_ceil.c +@@ -20,10 +20,15 @@ + #include + #include + #include ++#include + + double + __ceil (double x) + { ++#if USE_CEIL_BUILTIN ++ return __builtin_ceil (x); ++#else ++ /* Use generic implementation. */ + int64_t i0, i; + int32_t j0; + EXTRACT_WORDS64 (i0, x); +@@ -57,6 +62,7 @@ __ceil (double x) + } + INSERT_WORDS64 (x, i0); + return x; ++#endif /* ! USE_CEIL_BUILTIN */ + } + #ifndef __ceil + libm_alias_double (__ceil, ceil) +diff --git a/sysdeps/ieee754/float128/float128_private.h b/sysdeps/ieee754/float128/float128_private.h +index 667030ab06..19352ca26c 100644 +--- a/sysdeps/ieee754/float128/float128_private.h ++++ b/sysdeps/ieee754/float128/float128_private.h +@@ -145,6 +145,8 @@ + #define USE_RINTL_BUILTIN USE_RINTF128_BUILTIN + #undef USE_FLOORL_BUILTIN + #define USE_FLOORL_BUILTIN USE_FLOORF128_BUILTIN ++#undef USE_CEILL_BUILTIN ++#define USE_CEILL_BUILTIN USE_CEILF128_BUILTIN + + /* IEEE function renames. */ + #define __ieee754_acoshl __ieee754_acoshf128 +@@ -349,6 +351,7 @@ + #define __builtin_nearbyintl __builtin_nearbyintf128 + #define __builtin_rintl __builtin_rintf128 + #define __builtin_floorl __builtin_floorf128 ++#define __builtin_ceill __builtin_ceilf128 + + /* Get the constant suffix from bits/floatn-compat.h. */ + #define L(x) __f128 (x) +diff --git a/sysdeps/ieee754/flt-32/s_ceilf.c b/sysdeps/ieee754/flt-32/s_ceilf.c +index f289ec2341..6cab7bdd62 100644 +--- a/sysdeps/ieee754/flt-32/s_ceilf.c ++++ b/sysdeps/ieee754/flt-32/s_ceilf.c +@@ -16,11 +16,15 @@ + #include + #include + #include +- ++#include + + float + __ceilf(float x) + { ++#if USE_CEILF_BUILTIN ++ return __builtin_ceilf (x); ++#else ++ /* Use generic implementation. */ + int32_t i0,j0; + uint32_t i; + +@@ -43,6 +47,7 @@ __ceilf(float x) + } + SET_FLOAT_WORD(x,i0); + return x; ++#endif /* ! USE_CEILF_BUILTIN */ + } + #ifndef __ceilf + libm_alias_float (__ceil, ceil) +diff --git a/sysdeps/ieee754/ldbl-128/s_ceill.c b/sysdeps/ieee754/ldbl-128/s_ceill.c +index e6aba5f2af..d212d86179 100644 +--- a/sysdeps/ieee754/ldbl-128/s_ceill.c ++++ b/sysdeps/ieee754/ldbl-128/s_ceill.c +@@ -27,9 +27,14 @@ static char rcsid[] = "$NetBSD: $"; + #include + #include + #include ++#include + + _Float128 __ceill(_Float128 x) + { ++#if USE_CEILL_BUILTIN ++ return __builtin_ceill (x); ++#else ++ /* Use generic implementation. */ + int64_t i0,i1,j0; + uint64_t i,j; + GET_LDOUBLE_WORDS64(i0,i1,x); +@@ -63,5 +68,6 @@ _Float128 __ceill(_Float128 x) + } + SET_LDOUBLE_WORDS64(x,i0,i1); + return x; ++#endif /* ! USE_CEILL_BUILTIN */ + } + libm_alias_ldouble (__ceil, ceil) +diff --git a/sysdeps/s390/fpu/math-use-builtins.h b/sysdeps/s390/fpu/math-use-builtins.h +index c213c16c6f..5435cbb65f 100644 +--- a/sysdeps/s390/fpu/math-use-builtins.h ++++ b/sysdeps/s390/fpu/math-use-builtins.h +@@ -38,14 +38,20 @@ + # define USE_FLOORF_BUILTIN 1 + # define USE_FLOORL_BUILTIN 1 + ++# define USE_CEIL_BUILTIN 1 ++# define USE_CEILF_BUILTIN 1 ++# define USE_CEILL_BUILTIN 1 ++ + # if __GNUC_PREREQ (8, 0) + # define USE_NEARBYINTF128_BUILTIN 1 + # define USE_RINTF128_BUILTIN 1 + # define USE_FLOORF128_BUILTIN 1 ++# define USE_CEILF128_BUILTIN 1 + # else + # define USE_NEARBYINTF128_BUILTIN 0 + # define USE_RINTF128_BUILTIN 0 + # define USE_FLOORF128_BUILTIN 0 ++# define USE_CEILF128_BUILTIN 0 + # endif + + #else +@@ -66,6 +72,11 @@ + # define USE_FLOORL_BUILTIN 0 + # define USE_FLOORF128_BUILTIN 0 + ++# define USE_CEIL_BUILTIN 0 ++# define USE_CEILF_BUILTIN 0 ++# define USE_CEILL_BUILTIN 0 ++# define USE_CEILF128_BUILTIN 0 ++ + #endif /* ! HAVE_S390_MIN_Z196_ZARCH_ASM_SUPPORT */ + + #endif /* math-use-builtins.h */ +-- +2.18.2 + diff --git a/SOURCES/glibc-rh1780204-11.patch b/SOURCES/glibc-rh1780204-11.patch new file mode 100644 index 0000000..533d478 --- /dev/null +++ b/SOURCES/glibc-rh1780204-11.patch @@ -0,0 +1,187 @@ +From abc72a0694c1c3d08354170da343eead8d9afcc1 Mon Sep 17 00:00:00 2001 +From: Stefan Liebler +Date: Wed, 11 Dec 2019 15:09:22 +0100 +Subject: [PATCH 11/28] Use GCC builtins for trunc functions if desired. + +This patch is using the corresponding GCC builtin for truncf, trunc, +truncl and truncf128 if the USE_FUNCTION_BUILTIN macros are defined to one +in math-use-builtins.h. + +This is the case for s390 if build with at least --march=z196 --mzarch. +Otherwise the generic implementation is used. The code of the generic +implementation is not changed. + +Reviewed-by: Adhemerval Zanella +(cherry picked from commit 1ac9c1cf87216bf9f8ac4f7c9754d025d9f2c4ae) +--- + sysdeps/generic/math-use-builtins.h | 5 +++++ + sysdeps/ieee754/dbl-64/s_trunc.c | 6 ++++++ + sysdeps/ieee754/float128/float128_private.h | 3 +++ + sysdeps/ieee754/flt-32/s_truncf.c | 6 ++++++ + sysdeps/ieee754/ldbl-128/s_truncl.c | 6 ++++++ + sysdeps/s390/fpu/math-use-builtins.h | 11 +++++++++++ + 6 files changed, 37 insertions(+) + +diff --git a/sysdeps/generic/math-use-builtins.h b/sysdeps/generic/math-use-builtins.h +index 076ec661b0..ab379f45ba 100644 +--- a/sysdeps/generic/math-use-builtins.h ++++ b/sysdeps/generic/math-use-builtins.h +@@ -41,4 +41,9 @@ + #define USE_CEILL_BUILTIN 0 + #define USE_CEILF128_BUILTIN 0 + ++#define USE_TRUNC_BUILTIN 0 ++#define USE_TRUNCF_BUILTIN 0 ++#define USE_TRUNCL_BUILTIN 0 ++#define USE_TRUNCF128_BUILTIN 0 ++ + #endif /* math-use-builtins.h */ +diff --git a/sysdeps/ieee754/dbl-64/s_trunc.c b/sysdeps/ieee754/dbl-64/s_trunc.c +index 38bb33d337..708169c727 100644 +--- a/sysdeps/ieee754/dbl-64/s_trunc.c ++++ b/sysdeps/ieee754/dbl-64/s_trunc.c +@@ -21,11 +21,16 @@ + + #include + #include ++#include + + + double + __trunc (double x) + { ++#if USE_TRUNC_BUILTIN ++ return __builtin_trunc (x); ++#else ++ /* Use generic implementation. */ + int64_t i0, j0; + int64_t sx; + +@@ -48,6 +53,7 @@ __trunc (double x) + } + + return x; ++#endif /* ! USE_TRUNC_BUILTIN */ + } + #ifndef __trunc + libm_alias_double (__trunc, trunc) +diff --git a/sysdeps/ieee754/float128/float128_private.h b/sysdeps/ieee754/float128/float128_private.h +index 19352ca26c..e248600ec2 100644 +--- a/sysdeps/ieee754/float128/float128_private.h ++++ b/sysdeps/ieee754/float128/float128_private.h +@@ -147,6 +147,8 @@ + #define USE_FLOORL_BUILTIN USE_FLOORF128_BUILTIN + #undef USE_CEILL_BUILTIN + #define USE_CEILL_BUILTIN USE_CEILF128_BUILTIN ++#undef USE_TRUNCL_BUILTIN ++#define USE_TRUNCL_BUILTIN USE_TRUNCF128_BUILTIN + + /* IEEE function renames. */ + #define __ieee754_acoshl __ieee754_acoshf128 +@@ -352,6 +354,7 @@ + #define __builtin_rintl __builtin_rintf128 + #define __builtin_floorl __builtin_floorf128 + #define __builtin_ceill __builtin_ceilf128 ++#define __builtin_truncl __builtin_truncf128 + + /* Get the constant suffix from bits/floatn-compat.h. */ + #define L(x) __f128 (x) +diff --git a/sysdeps/ieee754/flt-32/s_truncf.c b/sysdeps/ieee754/flt-32/s_truncf.c +index 2e1464aeac..71491e5175 100644 +--- a/sysdeps/ieee754/flt-32/s_truncf.c ++++ b/sysdeps/ieee754/flt-32/s_truncf.c +@@ -21,11 +21,16 @@ + + #include + #include ++#include + + + float + __truncf (float x) + { ++#if USE_TRUNCF_BUILTIN ++ return __builtin_truncf (x); ++#else ++ /* Use generic implementation. */ + int32_t i0, j0; + int sx; + +@@ -48,6 +53,7 @@ __truncf (float x) + } + + return x; ++#endif /* ! USE_TRUNCF_BUILTIN */ + } + #ifndef __truncf + libm_alias_float (__trunc, trunc) +diff --git a/sysdeps/ieee754/ldbl-128/s_truncl.c b/sysdeps/ieee754/ldbl-128/s_truncl.c +index f858ede3d2..aa49daaf85 100644 +--- a/sysdeps/ieee754/ldbl-128/s_truncl.c ++++ b/sysdeps/ieee754/ldbl-128/s_truncl.c +@@ -22,11 +22,16 @@ + + #include + #include ++#include + + + _Float128 + __truncl (_Float128 x) + { ++#if USE_TRUNCL_BUILTIN ++ return __builtin_truncl (x); ++#else ++ /* Use generic implementation. */ + int32_t j0; + uint64_t i0, i1, sx; + +@@ -53,5 +58,6 @@ __truncl (_Float128 x) + } + + return x; ++#endif /* ! USE_TRUNCL_BUILTIN */ + } + libm_alias_ldouble (__trunc, trunc) +diff --git a/sysdeps/s390/fpu/math-use-builtins.h b/sysdeps/s390/fpu/math-use-builtins.h +index 5435cbb65f..a39715c612 100644 +--- a/sysdeps/s390/fpu/math-use-builtins.h ++++ b/sysdeps/s390/fpu/math-use-builtins.h +@@ -42,16 +42,22 @@ + # define USE_CEILF_BUILTIN 1 + # define USE_CEILL_BUILTIN 1 + ++# define USE_TRUNC_BUILTIN 1 ++# define USE_TRUNCF_BUILTIN 1 ++# define USE_TRUNCL_BUILTIN 1 ++ + # if __GNUC_PREREQ (8, 0) + # define USE_NEARBYINTF128_BUILTIN 1 + # define USE_RINTF128_BUILTIN 1 + # define USE_FLOORF128_BUILTIN 1 + # define USE_CEILF128_BUILTIN 1 ++# define USE_TRUNCF128_BUILTIN 1 + # else + # define USE_NEARBYINTF128_BUILTIN 0 + # define USE_RINTF128_BUILTIN 0 + # define USE_FLOORF128_BUILTIN 0 + # define USE_CEILF128_BUILTIN 0 ++# define USE_TRUNCF128_BUILTIN 0 + # endif + + #else +@@ -77,6 +83,11 @@ + # define USE_CEILL_BUILTIN 0 + # define USE_CEILF128_BUILTIN 0 + ++# define USE_TRUNC_BUILTIN 0 ++# define USE_TRUNCF_BUILTIN 0 ++# define USE_TRUNCL_BUILTIN 0 ++# define USE_TRUNCF128_BUILTIN 0 ++ + #endif /* ! HAVE_S390_MIN_Z196_ZARCH_ASM_SUPPORT */ + + #endif /* math-use-builtins.h */ +-- +2.18.2 + diff --git a/SOURCES/glibc-rh1780204-12.patch b/SOURCES/glibc-rh1780204-12.patch new file mode 100644 index 0000000..3b95873 --- /dev/null +++ b/SOURCES/glibc-rh1780204-12.patch @@ -0,0 +1,187 @@ +From f49dd4cc4e295803e517190d1798bd84561d56f4 Mon Sep 17 00:00:00 2001 +From: Stefan Liebler +Date: Wed, 11 Dec 2019 15:09:24 +0100 +Subject: [PATCH 12/28] Use GCC builtins for round functions if desired. + +This patch is using the corresponding GCC builtin for roundf, round, +roundl and roundf128 if the USE_FUNCTION_BUILTIN macros are defined to one +in math-use-builtins.h. + +This is the case for s390 if build with at least --march=z196 --mzarch. +Otherwise the generic implementation is used. The code of the generic +implementation is not changed. + +Reviewed-by: Adhemerval Zanella +(cherry picked from commit f82996f8159981619ac7ed8a4c1838c2ad72ab61) +--- + sysdeps/generic/math-use-builtins.h | 5 +++++ + sysdeps/ieee754/dbl-64/s_round.c | 6 ++++++ + sysdeps/ieee754/float128/float128_private.h | 3 +++ + sysdeps/ieee754/flt-32/s_roundf.c | 6 ++++++ + sysdeps/ieee754/ldbl-128/s_roundl.c | 6 ++++++ + sysdeps/s390/fpu/math-use-builtins.h | 11 +++++++++++ + 6 files changed, 37 insertions(+) + +diff --git a/sysdeps/generic/math-use-builtins.h b/sysdeps/generic/math-use-builtins.h +index ab379f45ba..34ca438a8c 100644 +--- a/sysdeps/generic/math-use-builtins.h ++++ b/sysdeps/generic/math-use-builtins.h +@@ -46,4 +46,9 @@ + #define USE_TRUNCL_BUILTIN 0 + #define USE_TRUNCF128_BUILTIN 0 + ++#define USE_ROUND_BUILTIN 0 ++#define USE_ROUNDF_BUILTIN 0 ++#define USE_ROUNDL_BUILTIN 0 ++#define USE_ROUNDF128_BUILTIN 0 ++ + #endif /* math-use-builtins.h */ +diff --git a/sysdeps/ieee754/dbl-64/s_round.c b/sysdeps/ieee754/dbl-64/s_round.c +index bf9922edca..1f8482adf8 100644 +--- a/sysdeps/ieee754/dbl-64/s_round.c ++++ b/sysdeps/ieee754/dbl-64/s_round.c +@@ -22,11 +22,16 @@ + #include + #include + #include ++#include + + + double + __round (double x) + { ++#if USE_ROUND_BUILTIN ++ return __builtin_round (x); ++#else ++ /* Use generic implementation. */ + int64_t i0, j0; + + EXTRACT_WORDS64 (i0, x); +@@ -61,5 +66,6 @@ __round (double x) + + INSERT_WORDS64 (x, i0); + return x; ++#endif /* ! USE_ROUND_BUILTIN */ + } + libm_alias_double (__round, round) +diff --git a/sysdeps/ieee754/float128/float128_private.h b/sysdeps/ieee754/float128/float128_private.h +index e248600ec2..3297a71e44 100644 +--- a/sysdeps/ieee754/float128/float128_private.h ++++ b/sysdeps/ieee754/float128/float128_private.h +@@ -149,6 +149,8 @@ + #define USE_CEILL_BUILTIN USE_CEILF128_BUILTIN + #undef USE_TRUNCL_BUILTIN + #define USE_TRUNCL_BUILTIN USE_TRUNCF128_BUILTIN ++#undef USE_ROUNDL_BUILTIN ++#define USE_ROUNDL_BUILTIN USE_ROUNDF128_BUILTIN + + /* IEEE function renames. */ + #define __ieee754_acoshl __ieee754_acoshf128 +@@ -355,6 +357,7 @@ + #define __builtin_floorl __builtin_floorf128 + #define __builtin_ceill __builtin_ceilf128 + #define __builtin_truncl __builtin_truncf128 ++#define __builtin_roundl __builtin_roundf128 + + /* Get the constant suffix from bits/floatn-compat.h. */ + #define L(x) __f128 (x) +diff --git a/sysdeps/ieee754/flt-32/s_roundf.c b/sysdeps/ieee754/flt-32/s_roundf.c +index 7c95125d9c..6fdfbbbade 100644 +--- a/sysdeps/ieee754/flt-32/s_roundf.c ++++ b/sysdeps/ieee754/flt-32/s_roundf.c +@@ -21,11 +21,16 @@ + + #include + #include ++#include + + + float + __roundf (float x) + { ++#if USE_ROUNDF_BUILTIN ++ return __builtin_roundf (x); ++#else ++ /* Use generic implementation. */ + int32_t i0, j0; + + GET_FLOAT_WORD (i0, x); +@@ -60,5 +65,6 @@ __roundf (float x) + + SET_FLOAT_WORD (x, i0); + return x; ++#endif /* ! USE_ROUNDF_BUILTIN */ + } + libm_alias_float (__round, round) +diff --git a/sysdeps/ieee754/ldbl-128/s_roundl.c b/sysdeps/ieee754/ldbl-128/s_roundl.c +index 22789cedf3..564f8ac1b8 100644 +--- a/sysdeps/ieee754/ldbl-128/s_roundl.c ++++ b/sysdeps/ieee754/ldbl-128/s_roundl.c +@@ -22,11 +22,16 @@ + + #include + #include ++#include + + + _Float128 + __roundl (_Float128 x) + { ++#if USE_ROUNDL_BUILTIN ++ return __builtin_roundl (x); ++#else ++ /* Use generic implementation. */ + int32_t j0; + uint64_t i1, i0; + +@@ -77,5 +82,6 @@ __roundl (_Float128 x) + + SET_LDOUBLE_WORDS64 (x, i0, i1); + return x; ++#endif /* ! USE_ROUNDL_BUILTIN */ + } + libm_alias_ldouble (__round, round) +diff --git a/sysdeps/s390/fpu/math-use-builtins.h b/sysdeps/s390/fpu/math-use-builtins.h +index a39715c612..51cb9f91ab 100644 +--- a/sysdeps/s390/fpu/math-use-builtins.h ++++ b/sysdeps/s390/fpu/math-use-builtins.h +@@ -46,18 +46,24 @@ + # define USE_TRUNCF_BUILTIN 1 + # define USE_TRUNCL_BUILTIN 1 + ++# define USE_ROUND_BUILTIN 1 ++# define USE_ROUNDF_BUILTIN 1 ++# define USE_ROUNDL_BUILTIN 1 ++ + # if __GNUC_PREREQ (8, 0) + # define USE_NEARBYINTF128_BUILTIN 1 + # define USE_RINTF128_BUILTIN 1 + # define USE_FLOORF128_BUILTIN 1 + # define USE_CEILF128_BUILTIN 1 + # define USE_TRUNCF128_BUILTIN 1 ++# define USE_ROUNDF128_BUILTIN 1 + # else + # define USE_NEARBYINTF128_BUILTIN 0 + # define USE_RINTF128_BUILTIN 0 + # define USE_FLOORF128_BUILTIN 0 + # define USE_CEILF128_BUILTIN 0 + # define USE_TRUNCF128_BUILTIN 0 ++# define USE_ROUNDF128_BUILTIN 0 + # endif + + #else +@@ -88,6 +94,11 @@ + # define USE_TRUNCL_BUILTIN 0 + # define USE_TRUNCF128_BUILTIN 0 + ++# define USE_ROUND_BUILTIN 0 ++# define USE_ROUNDF_BUILTIN 0 ++# define USE_ROUNDL_BUILTIN 0 ++# define USE_ROUNDF128_BUILTIN 0 ++ + #endif /* ! HAVE_S390_MIN_Z196_ZARCH_ASM_SUPPORT */ + + #endif /* math-use-builtins.h */ +-- +2.18.2 + diff --git a/SOURCES/glibc-rh1780204-13.patch b/SOURCES/glibc-rh1780204-13.patch new file mode 100644 index 0000000..72ed332 --- /dev/null +++ b/SOURCES/glibc-rh1780204-13.patch @@ -0,0 +1,177 @@ +From e93b17fad37a61f7ae9a663c617926b0f510921a Mon Sep 17 00:00:00 2001 +From: Stefan Liebler +Date: Wed, 11 Dec 2019 15:09:24 +0100 +Subject: [PATCH 13/28] Use GCC builtins for copysign functions if desired. + +This patch is always using the corresponding GCC builtin for copysignf, copysign, +and is using the builtin for copysignl, copysignf128 if the USE_FUNCTION_BUILTIN +macros are defined to one in math-use-builtins.h. + +Altough the long double version is enabled by default we still need +the macro and the alternative implementation as the _Float128 version +of the builtin is not available with all supported GCC versions. + +Reviewed-by: Adhemerval Zanella +(cherry picked from commit f818afdd3b29d7eef2010448457c9f5c16e684cd) +--- + sysdeps/generic/math-use-builtins.h | 9 +++++++++ + sysdeps/ieee754/dbl-64/s_copysign.c | 9 ++------- + sysdeps/ieee754/float128/float128_private.h | 3 +++ + sysdeps/ieee754/flt-32/s_copysignf.c | 12 ++++-------- + sysdeps/ieee754/ldbl-128/s_copysignl.c | 6 ++++++ + sysdeps/s390/fpu/math-use-builtins.h | 7 +++++++ + 6 files changed, 31 insertions(+), 15 deletions(-) + +diff --git a/sysdeps/generic/math-use-builtins.h b/sysdeps/generic/math-use-builtins.h +index 34ca438a8c..770b54ce61 100644 +--- a/sysdeps/generic/math-use-builtins.h ++++ b/sysdeps/generic/math-use-builtins.h +@@ -19,6 +19,8 @@ + #ifndef MATH_USE_BUILTINS_H + #define MATH_USE_BUILTINS_H 1 + ++#include /* For __GNUC_PREREQ. */ ++ + /* Define these macros to 1 to use __builtin_xyz instead of the + generic implementation. */ + #define USE_NEARBYINT_BUILTIN 0 +@@ -51,4 +53,11 @@ + #define USE_ROUNDL_BUILTIN 0 + #define USE_ROUNDF128_BUILTIN 0 + ++#define USE_COPYSIGNL_BUILTIN 1 ++#if __GNUC_PREREQ (7, 0) ++# define USE_COPYSIGNF128_BUILTIN 1 ++#else ++# define USE_COPYSIGNF128_BUILTIN 0 ++#endif ++ + #endif /* math-use-builtins.h */ +diff --git a/sysdeps/ieee754/dbl-64/s_copysign.c b/sysdeps/ieee754/dbl-64/s_copysign.c +index ab81d732ab..b95f1575d9 100644 +--- a/sysdeps/ieee754/dbl-64/s_copysign.c ++++ b/sysdeps/ieee754/dbl-64/s_copysign.c +@@ -10,7 +10,7 @@ + * ==================================================== + */ + +-#if defined(LIBM_SCCS) && !defined(lint) ++#if defined (LIBM_SCCS) && ! defined (lint) + static char rcsid[] = "$NetBSD: s_copysign.c,v 1.8 1995/05/10 20:46:57 jtc Exp $"; + #endif + +@@ -21,16 +21,11 @@ static char rcsid[] = "$NetBSD: s_copysign.c,v 1.8 1995/05/10 20:46:57 jtc Exp $ + */ + + #include +-#include + #include + + double + __copysign (double x, double y) + { +- uint32_t hx, hy; +- GET_HIGH_WORD (hx, x); +- GET_HIGH_WORD (hy, y); +- SET_HIGH_WORD (x, (hx & 0x7fffffff) | (hy & 0x80000000)); +- return x; ++ return __builtin_copysign (x, y); + } + libm_alias_double (__copysign, copysign) +diff --git a/sysdeps/ieee754/float128/float128_private.h b/sysdeps/ieee754/float128/float128_private.h +index 3297a71e44..077df0e09f 100644 +--- a/sysdeps/ieee754/float128/float128_private.h ++++ b/sysdeps/ieee754/float128/float128_private.h +@@ -151,6 +151,8 @@ + #define USE_TRUNCL_BUILTIN USE_TRUNCF128_BUILTIN + #undef USE_ROUNDL_BUILTIN + #define USE_ROUNDL_BUILTIN USE_ROUNDF128_BUILTIN ++#undef USE_COPYSIGNL_BUILTIN ++#define USE_COPYSIGNL_BUILTIN USE_COPYSIGNF128_BUILTIN + + /* IEEE function renames. */ + #define __ieee754_acoshl __ieee754_acoshf128 +@@ -358,6 +360,7 @@ + #define __builtin_ceill __builtin_ceilf128 + #define __builtin_truncl __builtin_truncf128 + #define __builtin_roundl __builtin_roundf128 ++#define __builtin_copysignl __builtin_copysignf128 + + /* Get the constant suffix from bits/floatn-compat.h. */ + #define L(x) __f128 (x) +diff --git a/sysdeps/ieee754/flt-32/s_copysignf.c b/sysdeps/ieee754/flt-32/s_copysignf.c +index 3c4ac7ce68..0247abd152 100644 +--- a/sysdeps/ieee754/flt-32/s_copysignf.c ++++ b/sysdeps/ieee754/flt-32/s_copysignf.c +@@ -13,7 +13,7 @@ + * ==================================================== + */ + +-#if defined(LIBM_SCCS) && !defined(lint) ++#if defined (LIBM_SCCS) && ! defined (lint) + static char rcsid[] = "$NetBSD: s_copysignf.c,v 1.4 1995/05/10 20:46:59 jtc Exp $"; + #endif + +@@ -24,15 +24,11 @@ static char rcsid[] = "$NetBSD: s_copysignf.c,v 1.4 1995/05/10 20:46:59 jtc Exp + */ + + #include +-#include + #include + +-float __copysignf(float x, float y) ++float ++__copysignf (float x, float y) + { +- uint32_t ix,iy; +- GET_FLOAT_WORD(ix,x); +- GET_FLOAT_WORD(iy,y); +- SET_FLOAT_WORD(x,(ix&0x7fffffff)|(iy&0x80000000)); +- return x; ++ return __builtin_copysignf (x, y); + } + libm_alias_float (__copysign, copysign) +diff --git a/sysdeps/ieee754/ldbl-128/s_copysignl.c b/sysdeps/ieee754/ldbl-128/s_copysignl.c +index d23e0f72ea..4cae8612dc 100644 +--- a/sysdeps/ieee754/ldbl-128/s_copysignl.c ++++ b/sysdeps/ieee754/ldbl-128/s_copysignl.c +@@ -26,14 +26,20 @@ static char rcsid[] = "$NetBSD: $"; + #include + #include + #include ++#include + + _Float128 __copysignl(_Float128 x, _Float128 y) + { ++#if USE_COPYSIGNL_BUILTIN ++ return __builtin_copysignl (x, y); ++#else ++ /* Use generic implementation. */ + uint64_t hx,hy; + GET_LDOUBLE_MSW64(hx,x); + GET_LDOUBLE_MSW64(hy,y); + SET_LDOUBLE_MSW64(x,(hx&0x7fffffffffffffffULL) + |(hy&0x8000000000000000ULL)); + return x; ++#endif /* ! USE_COPYSIGNL_BUILTIN */ + } + libm_alias_ldouble (__copysign, copysign) +diff --git a/sysdeps/s390/fpu/math-use-builtins.h b/sysdeps/s390/fpu/math-use-builtins.h +index 51cb9f91ab..4c4aad2ab5 100644 +--- a/sysdeps/s390/fpu/math-use-builtins.h ++++ b/sysdeps/s390/fpu/math-use-builtins.h +@@ -101,4 +101,11 @@ + + #endif /* ! HAVE_S390_MIN_Z196_ZARCH_ASM_SUPPORT */ + ++#define USE_COPYSIGNL_BUILTIN 1 ++#if __GNUC_PREREQ (7, 0) ++# define USE_COPYSIGNF128_BUILTIN 1 ++#else ++# define USE_COPYSIGNF128_BUILTIN 0 ++#endif ++ + #endif /* math-use-builtins.h */ +-- +2.18.2 + diff --git a/SOURCES/glibc-rh1780204-14.patch b/SOURCES/glibc-rh1780204-14.patch new file mode 100644 index 0000000..6e58c11 --- /dev/null +++ b/SOURCES/glibc-rh1780204-14.patch @@ -0,0 +1,180 @@ +From bd7c710d3b234a8d3bd77aae358bd7f7a6ce576d Mon Sep 17 00:00:00 2001 +From: Stefan Liebler +Date: Wed, 11 Dec 2019 15:09:25 +0100 +Subject: [PATCH 14/28] Adjust s_nearbyintf.c and s_nearbyintl.c regarding code + style. + +This patch just adjusts the generic implementation regarding code style. +No functional change. + +Reviewed-by: Adhemerval Zanella +(cherry picked from commit 6a3866dae98cccc8cd7a0a4c1fb409dba9192a83) +--- + sysdeps/ieee754/flt-32/s_nearbyintf.c | 60 ++++++++++++----------- + sysdeps/ieee754/ldbl-128/s_nearbyintl.c | 63 ++++++++++++++----------- + 2 files changed, 68 insertions(+), 55 deletions(-) + +diff --git a/sysdeps/ieee754/flt-32/s_nearbyintf.c b/sysdeps/ieee754/flt-32/s_nearbyintf.c +index 438dcae8cc..5969e3e5b8 100644 +--- a/sysdeps/ieee754/flt-32/s_nearbyintf.c ++++ b/sysdeps/ieee754/flt-32/s_nearbyintf.c +@@ -23,7 +23,7 @@ + #include + + float +-__nearbyintf(float x) ++__nearbyintf (float x) + { + #if USE_NEARBYINTF_BUILTIN + return __builtin_nearbyintf (x); +@@ -34,33 +34,39 @@ __nearbyintf(float x) + 8.3886080000e+06, /* 0x4b000000 */ + -8.3886080000e+06, /* 0xcb000000 */ + }; +- fenv_t env; +- int32_t i0,j0,sx; +- float w,t; +- GET_FLOAT_WORD(i0,x); +- sx = (i0>>31)&1; +- j0 = ((i0>>23)&0xff)-0x7f; +- if(j0<23) { +- if(j0<0) { +- libc_feholdexceptf (&env); +- w = TWO23[sx] + math_opt_barrier (x); +- t = w-TWO23[sx]; +- math_force_eval (t); +- libc_fesetenvf (&env); +- GET_FLOAT_WORD(i0,t); +- SET_FLOAT_WORD(t,(i0&0x7fffffff)|(sx<<31)); +- return t; +- } +- } else { +- if(__builtin_expect(j0==0x80, 0)) return x+x; /* inf or NaN */ +- else return x; /* x is integral */ ++ fenv_t env; ++ int32_t i0, j0, sx; ++ float w, t; ++ GET_FLOAT_WORD (i0, x); ++ sx = (i0 >> 31) & 1; ++ j0 = ((i0 >> 23) & 0xff) - 0x7f; ++ if (j0 < 23) ++ { ++ if (j0 < 0) ++ { ++ libc_feholdexceptf (&env); ++ w = TWO23[sx] + math_opt_barrier (x); ++ t = w - TWO23[sx]; ++ math_force_eval (t); ++ libc_fesetenvf (&env); ++ GET_FLOAT_WORD (i0, t); ++ SET_FLOAT_WORD (t, (i0 & 0x7fffffff) | (sx << 31)); ++ return t; + } +- libc_feholdexceptf (&env); +- w = TWO23[sx] + math_opt_barrier (x); +- t = w-TWO23[sx]; +- math_force_eval (t); +- libc_fesetenvf (&env); +- return t; ++ } ++ else ++ { ++ if (__glibc_unlikely (j0 == 0x80)) ++ return x + x; /* inf or NaN */ ++ else ++ return x; /* x is integral */ ++ } ++ libc_feholdexceptf (&env); ++ w = TWO23[sx] + math_opt_barrier (x); ++ t = w - TWO23[sx]; ++ math_force_eval (t); ++ libc_fesetenvf (&env); ++ return t; + #endif /* ! USE_NEARBYINT_BUILTIN */ + } + libm_alias_float (__nearbyint, nearbyint) +diff --git a/sysdeps/ieee754/ldbl-128/s_nearbyintl.c b/sysdeps/ieee754/ldbl-128/s_nearbyintl.c +index a4ad8e82e5..8d26786f78 100644 +--- a/sysdeps/ieee754/ldbl-128/s_nearbyintl.c ++++ b/sysdeps/ieee754/ldbl-128/s_nearbyintl.c +@@ -30,7 +30,8 @@ + #include + #include + +-_Float128 __nearbyintl(_Float128 x) ++_Float128 ++__nearbyintl (_Float128 x) + { + #if USE_NEARBYINTL_BUILTIN + return __builtin_nearbyintl (x); +@@ -41,34 +42,40 @@ _Float128 __nearbyintl(_Float128 x) + L(5.19229685853482762853049632922009600E+33), /* 0x406F000000000000, 0 */ + L(-5.19229685853482762853049632922009600E+33) /* 0xC06F000000000000, 0 */ + }; +- fenv_t env; +- int64_t i0,j0,sx; +- uint64_t i1 __attribute__ ((unused)); +- _Float128 w,t; +- GET_LDOUBLE_WORDS64(i0,i1,x); +- sx = (((uint64_t)i0)>>63); +- j0 = ((i0>>48)&0x7fff)-0x3fff; +- if(j0<112) { +- if(j0<0) { +- feholdexcept (&env); +- w = TWO112[sx] + math_opt_barrier (x); +- t = w-TWO112[sx]; +- math_force_eval (t); +- fesetenv (&env); +- GET_LDOUBLE_MSW64(i0,t); +- SET_LDOUBLE_MSW64(t,(i0&0x7fffffffffffffffLL)|(sx<<63)); +- return t; +- } +- } else { +- if(j0==0x4000) return x+x; /* inf or NaN */ +- else return x; /* x is integral */ ++ fenv_t env; ++ int64_t i0, j0, sx; ++ uint64_t i1 __attribute__ ((unused)); ++ _Float128 w, t; ++ GET_LDOUBLE_WORDS64 (i0, i1, x); ++ sx = (((uint64_t) i0) >> 63); ++ j0 = ((i0 >> 48) & 0x7fff) - 0x3fff; ++ if (j0 < 112) ++ { ++ if (j0 < 0) ++ { ++ feholdexcept (&env); ++ w = TWO112[sx] + math_opt_barrier (x); ++ t = w - TWO112[sx]; ++ math_force_eval (t); ++ fesetenv (&env); ++ GET_LDOUBLE_MSW64 (i0, t); ++ SET_LDOUBLE_MSW64 (t, (i0 & 0x7fffffffffffffffLL) | (sx << 63)); ++ return t; + } +- feholdexcept (&env); +- w = TWO112[sx] + math_opt_barrier (x); +- t = w-TWO112[sx]; +- math_force_eval (t); +- fesetenv (&env); +- return t; ++ } ++ else ++ { ++ if (j0 == 0x4000) ++ return x + x; /* inf or NaN */ ++ else ++ return x; /* x is integral */ ++ } ++ feholdexcept (&env); ++ w = TWO112[sx] + math_opt_barrier (x); ++ t = w - TWO112[sx]; ++ math_force_eval (t); ++ fesetenv (&env); ++ return t; + #endif /* ! USE_NEARBYINTL_BUILTIN */ + } + libm_alias_ldouble (__nearbyint, nearbyint) +-- +2.18.2 + diff --git a/SOURCES/glibc-rh1780204-15.patch b/SOURCES/glibc-rh1780204-15.patch new file mode 100644 index 0000000..47a5661 --- /dev/null +++ b/SOURCES/glibc-rh1780204-15.patch @@ -0,0 +1,156 @@ +From ce4f299c02be0a06130b70a62aa79b77385f4326 Mon Sep 17 00:00:00 2001 +From: Stefan Liebler +Date: Wed, 11 Dec 2019 15:09:26 +0100 +Subject: [PATCH 15/28] Adjust s_rintf.c and s_rintl.c regarding code style. + +This patch just adjusts the generic implementation regarding code style. +No functional change. + +Reviewed-by: Adhemerval Zanella +(cherry picked from commit 99b39a83e72f4b58e2f284fd844622df26b3b5fe) +--- + sysdeps/ieee754/flt-32/s_rintf.c | 44 +++++++++++++++------------ + sysdeps/ieee754/ldbl-128/s_rintl.c | 49 +++++++++++++++++------------- + 2 files changed, 53 insertions(+), 40 deletions(-) + +diff --git a/sysdeps/ieee754/flt-32/s_rintf.c b/sysdeps/ieee754/flt-32/s_rintf.c +index a266b1999e..3463a044e1 100644 +--- a/sysdeps/ieee754/flt-32/s_rintf.c ++++ b/sysdeps/ieee754/flt-32/s_rintf.c +@@ -19,7 +19,7 @@ + #include + + float +-__rintf(float x) ++__rintf (float x) + { + #if USE_RINTF_BUILTIN + return __builtin_rintf (x); +@@ -30,25 +30,31 @@ __rintf(float x) + 8.3886080000e+06, /* 0x4b000000 */ + -8.3886080000e+06, /* 0xcb000000 */ + }; +- int32_t i0,j0,sx; +- float w,t; +- GET_FLOAT_WORD(i0,x); +- sx = (i0>>31)&1; +- j0 = ((i0>>23)&0xff)-0x7f; +- if(j0<23) { +- if(j0<0) { +- w = TWO23[sx]+x; +- t = w-TWO23[sx]; +- GET_FLOAT_WORD(i0,t); +- SET_FLOAT_WORD(t,(i0&0x7fffffff)|(sx<<31)); +- return t; +- } +- } else { +- if(j0==0x80) return x+x; /* inf or NaN */ +- else return x; /* x is integral */ ++ int32_t i0, j0, sx; ++ float w, t; ++ GET_FLOAT_WORD (i0, x); ++ sx = (i0 >> 31) & 1; ++ j0 = ((i0 >> 23) & 0xff) - 0x7f; ++ if (j0 < 23) ++ { ++ if(j0 < 0) ++ { ++ w = TWO23[sx] + x; ++ t = w - TWO23[sx]; ++ GET_FLOAT_WORD (i0, t); ++ SET_FLOAT_WORD (t, (i0 & 0x7fffffff) | (sx << 31)); ++ return t; + } +- w = TWO23[sx]+x; +- return w-TWO23[sx]; ++ } ++ else ++ { ++ if (j0 == 0x80) ++ return x + x; /* inf or NaN */ ++ else ++ return x; /* x is integral */ ++ } ++ w = TWO23[sx] + x; ++ return w - TWO23[sx]; + #endif /* ! USE_RINTF_BUILTIN */ + } + #ifndef __rintf +diff --git a/sysdeps/ieee754/ldbl-128/s_rintl.c b/sysdeps/ieee754/ldbl-128/s_rintl.c +index f060503066..260f3aa9b9 100644 +--- a/sysdeps/ieee754/ldbl-128/s_rintl.c ++++ b/sysdeps/ieee754/ldbl-128/s_rintl.c +@@ -13,7 +13,7 @@ + * ==================================================== + */ + +-#if defined(LIBM_SCCS) && !defined(lint) ++#if defined (LIBM_SCCS) && ! defined (lint) + static char rcsid[] = "$NetBSD: $"; + #endif + +@@ -32,7 +32,8 @@ static char rcsid[] = "$NetBSD: $"; + #include + #include + +-_Float128 __rintl(_Float128 x) ++_Float128 ++__rintl (_Float128 x) + { + #if USE_RINTL_BUILTIN + return __builtin_rintl (x); +@@ -43,26 +44,32 @@ _Float128 __rintl(_Float128 x) + 5.19229685853482762853049632922009600E+33L, /* 0x406F000000000000, 0 */ + -5.19229685853482762853049632922009600E+33L /* 0xC06F000000000000, 0 */ + }; +- int64_t i0,j0,sx; +- uint64_t i1 __attribute__ ((unused)); +- _Float128 w,t; +- GET_LDOUBLE_WORDS64(i0,i1,x); +- sx = (((uint64_t)i0)>>63); +- j0 = ((i0>>48)&0x7fff)-0x3fff; +- if(j0<112) { +- if(j0<0) { +- w = TWO112[sx]+x; +- t = w-TWO112[sx]; +- GET_LDOUBLE_MSW64(i0,t); +- SET_LDOUBLE_MSW64(t,(i0&0x7fffffffffffffffLL)|(sx<<63)); +- return t; +- } +- } else { +- if(j0==0x4000) return x+x; /* inf or NaN */ +- else return x; /* x is integral */ ++ int64_t i0, j0, sx; ++ uint64_t i1 __attribute__ ((unused)); ++ _Float128 w, t; ++ GET_LDOUBLE_WORDS64 (i0, i1, x); ++ sx = (((uint64_t) i0) >> 63); ++ j0 = ((i0 >> 48) & 0x7fff) - 0x3fff; ++ if (j0 < 112) ++ { ++ if (j0 < 0) ++ { ++ w = TWO112[sx] + x; ++ t = w - TWO112[sx]; ++ GET_LDOUBLE_MSW64 (i0, t); ++ SET_LDOUBLE_MSW64 (t, (i0 & 0x7fffffffffffffffLL) | (sx << 63)); ++ return t; + } +- w = TWO112[sx]+x; +- return w-TWO112[sx]; ++ } ++ else ++ { ++ if (j0 == 0x4000) ++ return x + x; /* inf or NaN */ ++ else ++ return x; /* x is integral */ ++ } ++ w = TWO112[sx] + x; ++ return w - TWO112[sx]; + #endif /* ! USE_RINTL_BUILTIN */ + } + libm_alias_ldouble (__rint, rint) +-- +2.18.2 + diff --git a/SOURCES/glibc-rh1780204-16.patch b/SOURCES/glibc-rh1780204-16.patch new file mode 100644 index 0000000..47d84fd --- /dev/null +++ b/SOURCES/glibc-rh1780204-16.patch @@ -0,0 +1,198 @@ +From e96879644e4a9f4304725d1da9cc76b0c685b0b8 Mon Sep 17 00:00:00 2001 +From: Stefan Liebler +Date: Wed, 11 Dec 2019 15:09:26 +0100 +Subject: [PATCH 16/28] Adjust s_floorf.c and s_floorl.c regarding code style. + +This patch just adjusts the generic implementation regarding code style. +No functional change. + +Reviewed-by: Adhemerval Zanella +(cherry picked from commit d3a0409ab615e133ff3ea27b492de75a607cff4a) +--- + sysdeps/ieee754/flt-32/s_floorf.c | 55 +++++++++++------- + sysdeps/ieee754/ldbl-128/s_floorl.c | 89 ++++++++++++++++++----------- + 2 files changed, 90 insertions(+), 54 deletions(-) + +diff --git a/sysdeps/ieee754/flt-32/s_floorf.c b/sysdeps/ieee754/flt-32/s_floorf.c +index 6d37ab90a1..c45816e3bd 100644 +--- a/sysdeps/ieee754/flt-32/s_floorf.c ++++ b/sysdeps/ieee754/flt-32/s_floorf.c +@@ -26,34 +26,45 @@ + #include + + float +-__floorf(float x) ++__floorf (float x) + { + #if USE_FLOORF_BUILTIN + return __builtin_floorf (x); + #else + /* Use generic implementation. */ +- int32_t i0,j0; +- uint32_t i; +- GET_FLOAT_WORD(i0,x); +- j0 = ((i0>>23)&0xff)-0x7f; +- if(j0<23) { +- if(j0<0) { +- /* return 0*sign(x) if |x|<1 */ +- if(i0>=0) {i0=0;} +- else if((i0&0x7fffffff)!=0) +- { i0=0xbf800000;} +- } else { +- i = (0x007fffff)>>j0; +- if((i0&i)==0) return x; /* x is integral */ +- if(i0<0) i0 += (0x00800000)>>j0; +- i0 &= (~i); +- } +- } else { +- if(__builtin_expect(j0==0x80, 0)) return x+x; /* inf or NaN */ +- else return x; /* x is integral */ ++ int32_t i0, j0; ++ uint32_t i; ++ GET_FLOAT_WORD (i0, x); ++ j0 = ((i0 >> 23) & 0xff) - 0x7f; ++ if (j0 < 23) ++ { ++ if (j0 < 0) ++ { ++ /* return 0 * sign (x) if |x| < 1 */ ++ if (i0 >= 0) ++ i0 = 0; ++ else if ((i0 & 0x7fffffff) != 0) ++ i0 = 0xbf800000; + } +- SET_FLOAT_WORD(x,i0); +- return x; ++ else ++ { ++ i = (0x007fffff) >> j0; ++ if ((i0 & i) == 0) ++ return x; /* x is integral */ ++ if (i0 < 0) ++ i0 += (0x00800000) >> j0; ++ i0 &= (~i); ++ } ++ } ++ else ++ { ++ if (__glibc_unlikely (j0 == 0x80)) ++ return x + x; /* inf or NaN */ ++ else ++ return x; /* x is integral */ ++ } ++ SET_FLOAT_WORD (x, i0); ++ return x; + #endif /* ! USE_FLOORF_BUILTIN */ + } + #ifndef __floorf +diff --git a/sysdeps/ieee754/ldbl-128/s_floorl.c b/sysdeps/ieee754/ldbl-128/s_floorl.c +index 6143fe6ec5..4fc10992c2 100644 +--- a/sysdeps/ieee754/ldbl-128/s_floorl.c ++++ b/sysdeps/ieee754/ldbl-128/s_floorl.c +@@ -29,46 +29,71 @@ static char rcsid[] = "$NetBSD: $"; + #include + #include + +-_Float128 __floorl(_Float128 x) ++_Float128 ++__floorl (_Float128 x) + { + #if USE_FLOORL_BUILTIN + return __builtin_floorl (x); + #else + /* Use generic implementation. */ +- int64_t i0,i1,j0; +- uint64_t i,j; +- GET_LDOUBLE_WORDS64(i0,i1,x); +- j0 = ((i0>>48)&0x7fff)-0x3fff; +- if(j0<48) { +- if(j0<0) { +- /* return 0*sign(x) if |x|<1 */ +- if(i0>=0) {i0=i1=0;} +- else if(((i0&0x7fffffffffffffffLL)|i1)!=0) +- { i0=0xbfff000000000000ULL;i1=0;} +- } else { +- i = (0x0000ffffffffffffULL)>>j0; +- if(((i0&i)|i1)==0) return x; /* x is integral */ +- if(i0<0) i0 += (0x0001000000000000LL)>>j0; +- i0 &= (~i); i1=0; ++ int64_t i0, i1, j0; ++ uint64_t i, j; ++ GET_LDOUBLE_WORDS64 (i0, i1, x); ++ j0 = ((i0 >> 48) & 0x7fff) - 0x3fff; ++ if (j0 < 48) ++ { ++ if (j0 < 0) ++ { ++ /* return 0 * sign (x) if |x| < 1 */ ++ if (i0 >= 0) ++ { ++ i0 = i1 = 0; + } +- } else if (j0>111) { +- if(j0==0x4000) return x+x; /* inf or NaN */ +- else return x; /* x is integral */ +- } else { +- i = -1ULL>>(j0-48); +- if((i1&i)==0) return x; /* x is integral */ +- if(i0<0) { +- if(j0==48) i0+=1; +- else { +- j = i1+(1LL<<(112-j0)); +- if(j> j0; ++ if (((i0 & i) | i1) == 0) ++ return x; /* x is integral */ ++ if (i0 < 0) ++ i0 += (0x0001000000000000LL) >> j0; ++ i0 &= (~i); ++ i1 = 0; ++ } ++ } ++ else if (j0 > 111) ++ { ++ if (j0 == 0x4000) ++ return x + x; /* inf or NaN */ ++ else ++ return x; /* x is integral */ ++ } ++ else ++ { ++ i = -1ULL >> (j0 - 48); ++ if ((i1 & i) == 0) ++ return x; /* x is integral */ ++ if (i0 < 0) ++ { ++ if (j0 == 48) ++ i0 += 1; ++ else ++ { ++ j = i1 + (1LL << (112 - j0)); ++ if (j < i1) ++ i0 += 1 ; /* got a carry */ ++ i1 = j; ++ } ++ } ++ i1 &= (~i); ++ } ++ SET_LDOUBLE_WORDS64 (x, i0, i1); ++ return x; + #endif /* ! USE_FLOORL_BUILTIN */ + } + libm_alias_ldouble (__floor, floor) +-- +2.18.2 + diff --git a/SOURCES/glibc-rh1780204-17.patch b/SOURCES/glibc-rh1780204-17.patch new file mode 100644 index 0000000..c8e447c --- /dev/null +++ b/SOURCES/glibc-rh1780204-17.patch @@ -0,0 +1,207 @@ +From 77b9cf86bba41d44e084337a11bfbf5ee7c98a38 Mon Sep 17 00:00:00 2001 +From: Stefan Liebler +Date: Wed, 11 Dec 2019 15:09:27 +0100 +Subject: [PATCH 17/28] Adjust s_ceilf.c and s_ceill.c regarding code style. + +This patch just adjusts the generic implementation regarding code style. +No functional change. + +Reviewed-by: Adhemerval Zanella +(cherry picked from commit 171d23d7cbce7b6f175a6690e625ccf80b647d23) +--- + sysdeps/ieee754/flt-32/s_ceilf.c | 54 +++++++++++------- + sysdeps/ieee754/ldbl-128/s_ceill.c | 91 +++++++++++++++++++----------- + 2 files changed, 92 insertions(+), 53 deletions(-) + +diff --git a/sysdeps/ieee754/flt-32/s_ceilf.c b/sysdeps/ieee754/flt-32/s_ceilf.c +index 6cab7bdd62..f60d0ac1f5 100644 +--- a/sysdeps/ieee754/flt-32/s_ceilf.c ++++ b/sysdeps/ieee754/flt-32/s_ceilf.c +@@ -19,34 +19,46 @@ + #include + + float +-__ceilf(float x) ++__ceilf (float x) + { + #if USE_CEILF_BUILTIN + return __builtin_ceilf (x); + #else + /* Use generic implementation. */ +- int32_t i0,j0; +- uint32_t i; ++ int32_t i0, j0; ++ uint32_t i; + +- GET_FLOAT_WORD(i0,x); +- j0 = ((i0>>23)&0xff)-0x7f; +- if(j0<23) { +- if(j0<0) { +- /* return 0*sign(x) if |x|<1 */ +- if(i0<0) {i0=0x80000000;} +- else if(i0!=0) { i0=0x3f800000;} +- } else { +- i = (0x007fffff)>>j0; +- if((i0&i)==0) return x; /* x is integral */ +- if(i0>0) i0 += (0x00800000)>>j0; +- i0 &= (~i); +- } +- } else { +- if(__builtin_expect(j0==0x80, 0)) return x+x; /* inf or NaN */ +- else return x; /* x is integral */ ++ GET_FLOAT_WORD (i0, x); ++ j0 = ((i0 >> 23) & 0xff) - 0x7f; ++ if (j0 < 23) ++ { ++ if (j0 < 0) ++ { ++ /* return 0 * sign (x) if |x| < 1 */ ++ if (i0 < 0) ++ i0 = 0x80000000; ++ else if (i0 != 0) ++ i0 = 0x3f800000; + } +- SET_FLOAT_WORD(x,i0); +- return x; ++ else ++ { ++ i = (0x007fffff) >> j0; ++ if ((i0 & i) == 0) ++ return x; /* x is integral */ ++ if (i0 > 0) ++ i0 += (0x00800000) >> j0; ++ i0 &= (~i); ++ } ++ } ++ else ++ { ++ if (__glibc_unlikely (j0 == 0x80)) ++ return x + x; /* inf or NaN */ ++ else ++ return x; /* x is integral */ ++ } ++ SET_FLOAT_WORD (x, i0); ++ return x; + #endif /* ! USE_CEILF_BUILTIN */ + } + #ifndef __ceilf +diff --git a/sysdeps/ieee754/ldbl-128/s_ceill.c b/sysdeps/ieee754/ldbl-128/s_ceill.c +index d212d86179..df75dc3008 100644 +--- a/sysdeps/ieee754/ldbl-128/s_ceill.c ++++ b/sysdeps/ieee754/ldbl-128/s_ceill.c +@@ -13,7 +13,7 @@ + * ==================================================== + */ + +-#if defined(LIBM_SCCS) && !defined(lint) ++#if defined (LIBM_SCCS) && ! defined (lint) + static char rcsid[] = "$NetBSD: $"; + #endif + +@@ -29,45 +29,72 @@ static char rcsid[] = "$NetBSD: $"; + #include + #include + +-_Float128 __ceill(_Float128 x) ++_Float128 ++__ceill (_Float128 x) + { + #if USE_CEILL_BUILTIN + return __builtin_ceill (x); + #else + /* Use generic implementation. */ +- int64_t i0,i1,j0; +- uint64_t i,j; +- GET_LDOUBLE_WORDS64(i0,i1,x); +- j0 = ((i0>>48)&0x7fff)-0x3fff; +- if(j0<48) { +- if(j0<0) { +- /* return 0*sign(x) if |x|<1 */ +- if(i0<0) {i0=0x8000000000000000ULL;i1=0;} +- else if((i0|i1)!=0) { i0=0x3fff000000000000ULL;i1=0;} +- } else { +- i = (0x0000ffffffffffffULL)>>j0; +- if(((i0&i)|i1)==0) return x; /* x is integral */ +- if(i0>0) i0 += (0x0001000000000000LL)>>j0; +- i0 &= (~i); i1=0; ++ int64_t i0, i1, j0; ++ uint64_t i, j; ++ GET_LDOUBLE_WORDS64 (i0, i1, x); ++ j0 = ((i0 >> 48) & 0x7fff) - 0x3fff; ++ if (j0 < 48) ++ { ++ if (j0 < 0) ++ { ++ /* return 0 * sign (x) if |x| < 1 */ ++ if (i0 < 0) ++ { ++ i0 = 0x8000000000000000ULL; ++ i1 = 0; + } +- } else if (j0>111) { +- if(j0==0x4000) return x+x; /* inf or NaN */ +- else return x; /* x is integral */ +- } else { +- i = -1ULL>>(j0-48); +- if((i1&i)==0) return x; /* x is integral */ +- if(i0>0) { +- if(j0==48) i0+=1; +- else { +- j = i1+(1LL<<(112-j0)); +- if(j> j0; ++ if (((i0 & i) | i1) == 0) ++ return x; /* x is integral */ ++ if (i0 > 0) ++ i0 += (0x0001000000000000LL) >> j0; ++ i0 &= (~i); ++ i1 = 0; ++ } ++ } ++ else if (j0 > 111) ++ { ++ if (j0 == 0x4000) ++ return x + x; /* inf or NaN */ ++ else ++ return x; /* x is integral */ ++ } ++ else ++ { ++ i = -1ULL >> (j0 - 48); ++ if ((i1 & i) == 0) ++ return x; /* x is integral */ ++ if (i0 > 0) ++ { ++ if (j0 == 48) ++ i0 += 1; ++ else ++ { ++ j = i1 + (1LL << (112 - j0)); ++ if (j < i1) ++ i0 += 1; /* got a carry */ ++ i1 = j; ++ } ++ } ++ i1 &= (~i); ++ } ++ SET_LDOUBLE_WORDS64 (x, i0, i1); ++ return x; + #endif /* ! USE_CEILL_BUILTIN */ + } + libm_alias_ldouble (__ceil, ceil) +-- +2.18.2 + diff --git a/SOURCES/glibc-rh1780204-18.patch b/SOURCES/glibc-rh1780204-18.patch new file mode 100644 index 0000000..feb6f36 --- /dev/null +++ b/SOURCES/glibc-rh1780204-18.patch @@ -0,0 +1,57 @@ +From f6e3f49613f4a31bce8c5f52ae440f9c7b3646fb Mon Sep 17 00:00:00 2001 +From: Stefan Liebler +Date: Wed, 11 Dec 2019 15:09:28 +0100 +Subject: [PATCH 18/28] Adjust s_copysignl.c regarding code style. + +This patch just adjusts the generic implementation regarding code style. +No functional change. + +Reviewed-by: Adhemerval Zanella +(cherry picked from commit 1902d5d5ff04771f16b67648789c75a18af06222) +--- + sysdeps/ieee754/ldbl-128/s_copysignl.c | 17 +++++++++-------- + 1 file changed, 9 insertions(+), 8 deletions(-) + +diff --git a/sysdeps/ieee754/ldbl-128/s_copysignl.c b/sysdeps/ieee754/ldbl-128/s_copysignl.c +index 4cae8612dc..9b0e44cf1d 100644 +--- a/sysdeps/ieee754/ldbl-128/s_copysignl.c ++++ b/sysdeps/ieee754/ldbl-128/s_copysignl.c +@@ -13,7 +13,7 @@ + * ==================================================== + */ + +-#if defined(LIBM_SCCS) && !defined(lint) ++#if defined (LIBM_SCCS) && ! defined (lint) + static char rcsid[] = "$NetBSD: $"; + #endif + +@@ -28,18 +28,19 @@ static char rcsid[] = "$NetBSD: $"; + #include + #include + +-_Float128 __copysignl(_Float128 x, _Float128 y) ++_Float128 ++__copysignl (_Float128 x, _Float128 y) + { + #if USE_COPYSIGNL_BUILTIN + return __builtin_copysignl (x, y); + #else + /* Use generic implementation. */ +- uint64_t hx,hy; +- GET_LDOUBLE_MSW64(hx,x); +- GET_LDOUBLE_MSW64(hy,y); +- SET_LDOUBLE_MSW64(x,(hx&0x7fffffffffffffffULL) +- |(hy&0x8000000000000000ULL)); +- return x; ++ uint64_t hx, hy; ++ GET_LDOUBLE_MSW64 (hx, x); ++ GET_LDOUBLE_MSW64 (hy, y); ++ SET_LDOUBLE_MSW64 (x, (hx & 0x7fffffffffffffffULL) ++ | (hy & 0x8000000000000000ULL)); ++ return x; + #endif /* ! USE_COPYSIGNL_BUILTIN */ + } + libm_alias_ldouble (__copysign, copysign) +-- +2.18.2 + diff --git a/SOURCES/glibc-rh1780204-19.patch b/SOURCES/glibc-rh1780204-19.patch new file mode 100644 index 0000000..bda184c --- /dev/null +++ b/SOURCES/glibc-rh1780204-19.patch @@ -0,0 +1,157 @@ +From 855d045bc26175195dadafc28abf84e7b6613aac Mon Sep 17 00:00:00 2001 +From: Stefan Liebler +Date: Wed, 11 Dec 2019 15:09:28 +0100 +Subject: [PATCH 19/28] S390: Use load-fp-integer instruction for roundeven + functions. + +If compiled with z196 zarch support, the load-fp-integer instruction +is used to implement roundeven, roundevenf, roundevenl. +Otherwise the common-code implementation is used. + +(cherry picked from commit 4399b163376b331773e43917dcf56ce68e43e6a0) +--- + sysdeps/s390/fpu/s_roundeven.c | 39 +++++++++++++++++++++++++++++++++ + sysdeps/s390/fpu/s_roundevenf.c | 38 ++++++++++++++++++++++++++++++++ + sysdeps/s390/fpu/s_roundevenl.c | 39 +++++++++++++++++++++++++++++++++ + 3 files changed, 116 insertions(+) + create mode 100644 sysdeps/s390/fpu/s_roundeven.c + create mode 100644 sysdeps/s390/fpu/s_roundevenf.c + create mode 100644 sysdeps/s390/fpu/s_roundevenl.c + +diff --git a/sysdeps/s390/fpu/s_roundeven.c b/sysdeps/s390/fpu/s_roundeven.c +new file mode 100644 +index 0000000000..95a83a70e8 +--- /dev/null ++++ b/sysdeps/s390/fpu/s_roundeven.c +@@ -0,0 +1,39 @@ ++/* roundeven() - S390 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, see ++ . */ ++ ++#ifdef HAVE_S390_MIN_Z196_ZARCH_ASM_SUPPORT ++# include ++# include ++ ++double ++__roundeven (double x) ++{ ++ double y; ++ /* The z196 zarch "load fp integer" (fidbra) instruction is rounding ++ x to the nearest integer with "ties to even" rounding mode ++ (M3-field: 4) where inexact exceptions are suppressed (M4-field: 4). */ ++ __asm__ ("fidbra %0,4,%1,4" : "=f" (y) : "f" (x)); ++ return y; ++} ++hidden_def (__roundeven) ++libm_alias_double (__roundeven, roundeven) ++ ++#else ++# include ++#endif +diff --git a/sysdeps/s390/fpu/s_roundevenf.c b/sysdeps/s390/fpu/s_roundevenf.c +new file mode 100644 +index 0000000000..c620a0189c +--- /dev/null ++++ b/sysdeps/s390/fpu/s_roundevenf.c +@@ -0,0 +1,38 @@ ++/* roundevenf() - S390 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, see ++ . */ ++ ++#ifdef HAVE_S390_MIN_Z196_ZARCH_ASM_SUPPORT ++# include ++# include ++ ++float ++__roundevenf (float x) ++{ ++ float y; ++ /* The z196 zarch "load fp integer" (fiebra) instruction is rounding ++ x to the nearest integer with "ties to even" rounding mode ++ (M3-field: 4) where inexact exceptions are suppressed (M4-field: 4). */ ++ __asm__ ("fiebra %0,4,%1,4" : "=f" (y) : "f" (x)); ++ return y; ++} ++libm_alias_float (__roundeven, roundeven) ++ ++#else ++# include ++#endif +diff --git a/sysdeps/s390/fpu/s_roundevenl.c b/sysdeps/s390/fpu/s_roundevenl.c +new file mode 100644 +index 0000000000..3481af2665 +--- /dev/null ++++ b/sysdeps/s390/fpu/s_roundevenl.c +@@ -0,0 +1,39 @@ ++/* roundevenl() - S390 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, see ++ . */ ++ ++#ifdef HAVE_S390_MIN_Z196_ZARCH_ASM_SUPPORT ++# include ++# include ++# include ++ ++_Float128 ++__roundevenl (_Float128 x) ++{ ++ _Float128 y; ++ /* The z196 zarch "load fp integer" (fixbra) instruction is rounding ++ x to the nearest integer with "ties to even" rounding mode ++ (M3-field: 4) where inexact exceptions are suppressed (M4-field: 4). */ ++ __asm__ ("fixbra %0,4,%1,4" : "=f" (y) : "f" (x)); ++ return y; ++} ++libm_alias_ldouble (__roundeven, roundeven) ++ ++#else ++# include ++#endif +-- +2.18.2 + diff --git a/SOURCES/glibc-rh1780204-20.patch b/SOURCES/glibc-rh1780204-20.patch new file mode 100644 index 0000000..4967ce3 --- /dev/null +++ b/SOURCES/glibc-rh1780204-20.patch @@ -0,0 +1,207 @@ +From 90e84ac5ac8e774ce0cfd3abc5f7d8834efd2c9b Mon Sep 17 00:00:00 2001 +From: Stefan Liebler +Date: Wed, 11 Dec 2019 15:09:29 +0100 +Subject: [PATCH 20/28] S390: Use convert-to-fixed instruction for lrint + functions. + +If compiled with z196 zarch support, the convert-to-fixed instruction +is used to implement lrint, lrintf, lrintl. +Otherwise the common-code implementation is used. + +(cherry picked from commit e3f07622209c1b4436ef364b134dfd2cd4ca9976) +--- + sysdeps/s390/fpu/s_lrint.c | 55 ++++++++++++++++++++++++++++++++++++ + sysdeps/s390/fpu/s_lrintf.c | 55 ++++++++++++++++++++++++++++++++++++ + sysdeps/s390/fpu/s_lrintl.c | 56 +++++++++++++++++++++++++++++++++++++ + 3 files changed, 166 insertions(+) + create mode 100644 sysdeps/s390/fpu/s_lrint.c + create mode 100644 sysdeps/s390/fpu/s_lrintf.c + create mode 100644 sysdeps/s390/fpu/s_lrintl.c + +diff --git a/sysdeps/s390/fpu/s_lrint.c b/sysdeps/s390/fpu/s_lrint.c +new file mode 100644 +index 0000000000..7be60665b5 +--- /dev/null ++++ b/sysdeps/s390/fpu/s_lrint.c +@@ -0,0 +1,55 @@ ++/* lrint() - S390 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, see ++ . */ ++ ++#ifdef HAVE_S390_MIN_Z196_ZARCH_ASM_SUPPORT ++# include ++# include ++ ++/* The sizeof (long int) differs between s390x (8byte) and s390 (4byte). ++ Thus we need different instructions as the target size is encoded there. ++ Note: On s390 this instruction is only used if build with -mzarch. */ ++# ifdef __s390x__ ++# define INSN "cgdbra" ++# else ++# define INSN "cfdbra" ++# endif ++ ++long int ++__lrint (double x) ++{ ++ long int y; ++ /* The z196 zarch "convert to fixed" (cgdbra) instruction is rounding ++ according to current rounding mode (M3-field: 0). ++ First convert x with suppressed inexact exception and check if the ++ resulting value is beyond the target limits (indicated by cc=3; ++ Note: a nan is also indicated by cc=3). ++ If the resulting value is within the target limits, redo ++ without suppressing the inexact exception. */ ++ __asm__ (INSN " %0,0,%1,4 \n\t" ++ "jo 1f \n\t" ++ INSN " %0,0,%1,0 \n\t" ++ "1:" ++ : "=&d" (y) : "f" (x) : "cc"); ++ return y; ++} ++libm_alias_double (__lrint, lrint) ++ ++#else ++# include ++#endif +diff --git a/sysdeps/s390/fpu/s_lrintf.c b/sysdeps/s390/fpu/s_lrintf.c +new file mode 100644 +index 0000000000..d6a2a4081a +--- /dev/null ++++ b/sysdeps/s390/fpu/s_lrintf.c +@@ -0,0 +1,55 @@ ++/* lrintf() - S390 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, see ++ . */ ++ ++#ifdef HAVE_S390_MIN_Z196_ZARCH_ASM_SUPPORT ++# include ++# include ++ ++/* The sizeof (long int) differs between s390x (8byte) and s390 (4byte). ++ Thus we need different instructions as the target size is encoded there. ++ Note: On s390 this instruction is only used if build with -mzarch. */ ++# ifdef __s390x__ ++# define INSN "cgebra" ++# else ++# define INSN "cfebra" ++# endif ++ ++long int ++__lrintf (float x) ++{ ++ long int y; ++ /* The z196 zarch "convert to fixed" (cgebra) instruction is rounding ++ according to current rounding mode (M3-field: 0). ++ First convert x with suppressed inexact exception and check if the ++ resulting value is beyond the target limits (indicated by cc=3; ++ Note: a nan is also indicated by cc=3). ++ If the resulting value is within the target limits, redo ++ without suppressing the inexact exception. */ ++ __asm__ (INSN " %0,0,%1,4 \n\t" ++ "jo 1f \n\t" ++ INSN " %0,0,%1,0 \n\t" ++ "1:" ++ : "=&d" (y) : "f" (x) : "cc"); ++ return y; ++} ++libm_alias_float (__lrint, lrint) ++ ++#else ++# include ++#endif +diff --git a/sysdeps/s390/fpu/s_lrintl.c b/sysdeps/s390/fpu/s_lrintl.c +new file mode 100644 +index 0000000000..2d386ecff9 +--- /dev/null ++++ b/sysdeps/s390/fpu/s_lrintl.c +@@ -0,0 +1,56 @@ ++/* lrintl() - S390 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, see ++ . */ ++ ++#ifdef HAVE_S390_MIN_Z196_ZARCH_ASM_SUPPORT ++# include ++# include ++# include ++ ++/* The sizeof (long int) differs between s390x (8byte) and s390 (4byte). ++ Thus we need different instructions as the target size is encoded there. ++ Note: On s390 this instruction is only used if build with -mzarch. */ ++# ifdef __s390x__ ++# define INSN "cgxbra" ++# else ++# define INSN "cfxbra" ++# endif ++ ++long int ++__lrintl (_Float128 x) ++{ ++ long int y; ++ /* The z196 zarch "convert to fixed" (cgxbra) instruction is rounding ++ according to current rounding mode (M3-field: 0). ++ First convert x with suppressed inexact exception and check if the ++ resulting value is beyond the target limits (indicated by cc=3; ++ Note: a nan is also indicated by cc=3). ++ If the resulting value is within the target limits, redo ++ without suppressing the inexact exception. */ ++ __asm__ (INSN " %0,0,%1,4 \n\t" ++ "jo 1f \n\t" ++ INSN " %0,0,%1,0 \n\t" ++ "1:" ++ : "=&d" (y) : "f" (x) : "cc"); ++ return y; ++} ++libm_alias_ldouble (__lrint, lrint) ++ ++#else ++# include ++#endif +-- +2.18.2 + diff --git a/SOURCES/glibc-rh1780204-21.patch b/SOURCES/glibc-rh1780204-21.patch new file mode 100644 index 0000000..743e16c --- /dev/null +++ b/SOURCES/glibc-rh1780204-21.patch @@ -0,0 +1,192 @@ +From 429eff12541cc0779c381f84257c8860ece25b12 Mon Sep 17 00:00:00 2001 +From: Stefan Liebler +Date: Wed, 11 Dec 2019 15:09:29 +0100 +Subject: [PATCH 21/28] S390: Use convert-to-fixed instruction for llrint + functions. + +If compiled with z196 zarch support, the convert-to-fixed instruction +is used to implement llrint, llrintf, llrintl. +Otherwise the common-code implementation is used. + +(cherry picked from commit f10c1654fe13d797d2fd347dc47f72f93c58cf62) +--- + sysdeps/s390/fpu/s_llrint.c | 50 +++++++++++++++++++++++++++++++++++ + sysdeps/s390/fpu/s_llrintf.c | 50 +++++++++++++++++++++++++++++++++++ + sysdeps/s390/fpu/s_llrintl.c | 51 ++++++++++++++++++++++++++++++++++++ + 3 files changed, 151 insertions(+) + create mode 100644 sysdeps/s390/fpu/s_llrint.c + create mode 100644 sysdeps/s390/fpu/s_llrintf.c + create mode 100644 sysdeps/s390/fpu/s_llrintl.c + +diff --git a/sysdeps/s390/fpu/s_llrint.c b/sysdeps/s390/fpu/s_llrint.c +new file mode 100644 +index 0000000000..edd796ae8c +--- /dev/null ++++ b/sysdeps/s390/fpu/s_llrint.c +@@ -0,0 +1,50 @@ ++/* llrint() - S390 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, see ++ . */ ++ ++#if defined __s390x__ && defined HAVE_S390_MIN_Z196_ZARCH_ASM_SUPPORT ++/* We only support s390x as on s390 a long long int refers to a register pair ++ of two 4byte registers instead of a 8byte register which is produced by the ++ instruction. ++ Note: On s390 this instruction would only be used if build with -mzarch. */ ++# include ++# include ++ ++long long int ++__llrint (double x) ++{ ++ long long int y; ++ /* The z196 zarch "convert to fixed" (cgdbra) instruction is rounding ++ according to current rounding mode (M3-field: 0). ++ First convert x with suppressed inexact exception and check if the ++ resulting value is beyond the target limits (indicated by cc=3; ++ Note: a nan is also indicated by cc=3). ++ If the resulting value is within the target limits, redo ++ without suppressing the inexact exception. */ ++ __asm__ ("cgdbra %0,0,%1,4 \n\t" ++ "jo 1f \n\t" ++ "cgdbra %0,0,%1,0 \n\t" ++ "1:" ++ : "=&d" (y) : "f" (x) : "cc"); ++ return y; ++} ++libm_alias_double (__llrint, llrint) ++ ++#else ++# include ++#endif +diff --git a/sysdeps/s390/fpu/s_llrintf.c b/sysdeps/s390/fpu/s_llrintf.c +new file mode 100644 +index 0000000000..3cbe7c581a +--- /dev/null ++++ b/sysdeps/s390/fpu/s_llrintf.c +@@ -0,0 +1,50 @@ ++/* llrintf() - S390 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, see ++ . */ ++ ++#if defined __s390x__ && defined HAVE_S390_MIN_Z196_ZARCH_ASM_SUPPORT ++/* We only support s390x as on s390 a long long int refers to a register pair ++ of two 4byte registers instead of a 8byte register which is produced by the ++ instruction. ++ Note: On s390 this instruction would only be used if build with -mzarch. */ ++# include ++# include ++ ++long long int ++__llrintf (float x) ++{ ++ long long int y; ++ /* The z196 zarch "convert to fixed" (cgebra) instruction is rounding ++ according to current rounding mode (M3-field: 0). ++ First convert x with suppressed inexact exception and check if the ++ resulting value is beyond the target limits (indicated by cc=3; ++ Note: a nan is also indicated by cc=3). ++ If the resulting value is within the target limits, redo ++ without suppressing the inexact exception. */ ++ __asm__ ("cgebra %0,0,%1,4 \n\t" ++ "jo 1f \n\t" ++ "cgebra %0,0,%1,0 \n\t" ++ "1:" ++ : "=&d" (y) : "f" (x) : "cc"); ++ return y; ++} ++libm_alias_float (__llrint, llrint) ++ ++#else ++# include ++#endif +diff --git a/sysdeps/s390/fpu/s_llrintl.c b/sysdeps/s390/fpu/s_llrintl.c +new file mode 100644 +index 0000000000..37eea5914f +--- /dev/null ++++ b/sysdeps/s390/fpu/s_llrintl.c +@@ -0,0 +1,51 @@ ++/* llrintl() - S390 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, see ++ . */ ++ ++#if defined __s390x__ && defined HAVE_S390_MIN_Z196_ZARCH_ASM_SUPPORT ++/* We only support s390x as on s390 a long long int refers to a register pair ++ of two 4byte registers instead of a 8byte register which is produced by the ++ instruction. ++ Note: On s390 this instruction would only be used if build with -mzarch. */ ++# include ++# include ++# include ++ ++long long int ++__llrintl (_Float128 x) ++{ ++ long long int y; ++ /* The z196 zarch "convert to fixed" (cgxbra) instruction is rounding ++ according to current rounding mode (M3-field: 0). ++ First convert x with suppressed inexact exception and check if the ++ resulting value is beyond the target limits (indicated by cc=3; ++ Note: a nan is also indicated by cc=3). ++ If the resulting value is within the target limits, redo ++ without suppressing the inexact exception. */ ++ __asm__ ("cgxbra %0,0,%1,4 \n\t" ++ "jo 1f \n\t" ++ "cgxbra %0,0,%1,0 \n\t" ++ "1:" ++ : "=&d" (y) : "f" (x) : "cc"); ++ return y; ++} ++libm_alias_ldouble (__llrint, llrint) ++ ++#else ++# include ++#endif +-- +2.18.2 + diff --git a/SOURCES/glibc-rh1780204-22.patch b/SOURCES/glibc-rh1780204-22.patch new file mode 100644 index 0000000..db29fa3 --- /dev/null +++ b/SOURCES/glibc-rh1780204-22.patch @@ -0,0 +1,183 @@ +From 9f3ee7825b1eae00431ea6477fce8210aaced7db Mon Sep 17 00:00:00 2001 +From: Stefan Liebler +Date: Wed, 11 Dec 2019 15:09:30 +0100 +Subject: [PATCH 22/28] S390: Use convert-to-fixed instruction for lround + functions. + +If compiled with z196 zarch support, the convert-to-fixed instruction +is used to implement lround, lroundf, lroundl. +Otherwise the common-code implementation is used. + +(cherry picked from commit 9d9f3527daf65fdca0eb46eaa324b81b8f94d88c) +--- + sysdeps/s390/fpu/s_lround.c | 47 +++++++++++++++++++++++++++++++++++ + sysdeps/s390/fpu/s_lroundf.c | 47 +++++++++++++++++++++++++++++++++++ + sysdeps/s390/fpu/s_lroundl.c | 48 ++++++++++++++++++++++++++++++++++++ + 3 files changed, 142 insertions(+) + create mode 100644 sysdeps/s390/fpu/s_lround.c + create mode 100644 sysdeps/s390/fpu/s_lroundf.c + create mode 100644 sysdeps/s390/fpu/s_lroundl.c + +diff --git a/sysdeps/s390/fpu/s_lround.c b/sysdeps/s390/fpu/s_lround.c +new file mode 100644 +index 0000000000..9290ec32cd +--- /dev/null ++++ b/sysdeps/s390/fpu/s_lround.c +@@ -0,0 +1,47 @@ ++/* lround() - S390 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, see ++ . */ ++ ++#ifdef HAVE_S390_MIN_Z196_ZARCH_ASM_SUPPORT ++# include ++# include ++ ++/* The sizeof (long int) differs between s390x (8byte) and s390 (4byte). ++ Thus we need different instructions as the target size is encoded there. ++ Note: On s390 this instruction is only used if build with -mzarch. */ ++# ifdef __s390x__ ++# define INSN "cgdbra" ++# else ++# define INSN "cfdbra" ++# endif ++ ++long int ++__lround (double x) ++{ ++ long int y; ++ /* The z196 zarch "convert to fixed" (cgdbra) instruction is rounding ++ x to the nearest integer with "ties away from 0" rounding mode ++ (M3-field: 1) where inexact exceptions are suppressed (M4-field: 4). */ ++ __asm__ (INSN " %0,1,%1,4" : "=d" (y) : "f" (x) : "cc"); ++ return y; ++} ++libm_alias_double (__lround, lround) ++ ++#else ++# include ++#endif +diff --git a/sysdeps/s390/fpu/s_lroundf.c b/sysdeps/s390/fpu/s_lroundf.c +new file mode 100644 +index 0000000000..097b924c91 +--- /dev/null ++++ b/sysdeps/s390/fpu/s_lroundf.c +@@ -0,0 +1,47 @@ ++/* lroundf() - S390 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, see ++ . */ ++ ++#ifdef HAVE_S390_MIN_Z196_ZARCH_ASM_SUPPORT ++# include ++# include ++ ++/* The sizeof (long int) differs between s390x (8byte) and s390 (4byte). ++ Thus we need different instructions as the target size is encoded there. ++ Note: On s390 this instruction is only used if build with -mzarch. */ ++# ifdef __s390x__ ++# define INSN "cgebra" ++# else ++# define INSN "cfebra" ++# endif ++ ++long int ++__lroundf (float x) ++{ ++ long int y; ++ /* The z196 zarch "convert to fixed" (cgebra) instruction is rounding ++ x to the nearest integer with "ties away from 0" rounding mode ++ (M3-field: 1) where inexact exceptions are suppressed (M4-field: 4). */ ++ __asm__ (INSN " %0,1,%1,4" : "=d" (y) : "f" (x) : "cc"); ++ return y; ++} ++libm_alias_float (__lround, lround) ++ ++#else ++# include ++#endif +diff --git a/sysdeps/s390/fpu/s_lroundl.c b/sysdeps/s390/fpu/s_lroundl.c +new file mode 100644 +index 0000000000..0ef77dc667 +--- /dev/null ++++ b/sysdeps/s390/fpu/s_lroundl.c +@@ -0,0 +1,48 @@ ++/* lroundl() - S390 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, see ++ . */ ++ ++#ifdef HAVE_S390_MIN_Z196_ZARCH_ASM_SUPPORT ++# include ++# include ++# include ++ ++/* The sizeof (long int) differs between s390x (8byte) and s390 (4byte). ++ Thus we need different instructions as the target size is encoded there. ++ Note: On s390 this instruction is only used if build with -mzarch. */ ++# ifdef __s390x__ ++# define INSN "cgxbra" ++# else ++# define INSN "cfxbra" ++# endif ++ ++long int ++__lroundl (_Float128 x) ++{ ++ long int y; ++ /* The z196 zarch "convert to fixed" (cgxbra) instruction is rounding ++ x to the nearest integer with "ties away from 0" rounding mode ++ (M3-field: 1) where inexact exceptions are suppressed (M4-field: 4). */ ++ __asm__ (INSN " %0,1,%1,4" : "=d" (y) : "f" (x) : "cc"); ++ return y; ++} ++libm_alias_ldouble (__lround, lround) ++ ++#else ++# include ++#endif +-- +2.18.2 + diff --git a/SOURCES/glibc-rh1780204-23.patch b/SOURCES/glibc-rh1780204-23.patch new file mode 100644 index 0000000..bcd8965 --- /dev/null +++ b/SOURCES/glibc-rh1780204-23.patch @@ -0,0 +1,168 @@ +From dd8bfb911e89f3ad1da5cfa5618a8c52c62bb095 Mon Sep 17 00:00:00 2001 +From: Stefan Liebler +Date: Wed, 11 Dec 2019 15:09:31 +0100 +Subject: [PATCH 23/28] S390: Use convert-to-fixed instruction for llround + functions. + +If compiled with z196 zarch support, the convert-to-fixed instruction +is used to implement llround, llroundf, llroundl. +Otherwise the common-code implementation is used. + +(cherry picked from commit 7d42d614fdc2c9d9f6ad46111bd6130501d50460) +--- + sysdeps/s390/fpu/s_llround.c | 42 ++++++++++++++++++++++++++++++++++ + sysdeps/s390/fpu/s_llroundf.c | 42 ++++++++++++++++++++++++++++++++++ + sysdeps/s390/fpu/s_llroundl.c | 43 +++++++++++++++++++++++++++++++++++ + 3 files changed, 127 insertions(+) + create mode 100644 sysdeps/s390/fpu/s_llround.c + create mode 100644 sysdeps/s390/fpu/s_llroundf.c + create mode 100644 sysdeps/s390/fpu/s_llroundl.c + +diff --git a/sysdeps/s390/fpu/s_llround.c b/sysdeps/s390/fpu/s_llround.c +new file mode 100644 +index 0000000000..f4a1b21637 +--- /dev/null ++++ b/sysdeps/s390/fpu/s_llround.c +@@ -0,0 +1,42 @@ ++/* llround() - S390 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, see ++ . */ ++ ++#if defined __s390x__ && defined HAVE_S390_MIN_Z196_ZARCH_ASM_SUPPORT ++/* We only support s390x as on s390 a long long int refers to a register pair ++ of two 4byte registers instead of a 8byte register which is produced by the ++ instruction. ++ Note: On s390 this instruction would only be used if build with -mzarch. */ ++# include ++# include ++ ++long long int ++__llround (double x) ++{ ++ long long int y; ++ /* The z196 zarch "convert to fixed" (cgdbra) instruction is rounding ++ x to the nearest integer with "ties away from 0" rounding mode ++ (M3-field: 1) where inexact exceptions are suppressed (M4-field: 4). */ ++ __asm__ ("cgdbra %0,1,%1,4" : "=d" (y) : "f" (x) : "cc"); ++ return y; ++} ++libm_alias_double (__llround, llround) ++ ++#else ++# include ++#endif +diff --git a/sysdeps/s390/fpu/s_llroundf.c b/sysdeps/s390/fpu/s_llroundf.c +new file mode 100644 +index 0000000000..d202f4be8c +--- /dev/null ++++ b/sysdeps/s390/fpu/s_llroundf.c +@@ -0,0 +1,42 @@ ++/* llroundf() - S390 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, see ++ . */ ++ ++#if defined __s390x__ && defined HAVE_S390_MIN_Z196_ZARCH_ASM_SUPPORT ++/* We only support s390x as on s390 a long long int refers to a register pair ++ of two 4byte registers instead of a 8byte register which is produced by the ++ instruction. ++ Note: On s390 this instruction would only be used if build with -mzarch. */ ++# include ++# include ++ ++long long int ++__llroundf (float x) ++{ ++ long long int y; ++ /* The z196 zarch "convert to fixed" (cgebra) instruction is rounding ++ x to the nearest integer with "ties away from 0" rounding mode ++ (M3-field: 1) where inexact exceptions are suppressed (M4-field: 4). */ ++ __asm__ ("cgebra %0,1,%1,4" : "=d" (y) : "f" (x) : "cc"); ++ return y; ++} ++libm_alias_float (__llround, llround) ++ ++#else ++# include ++#endif +diff --git a/sysdeps/s390/fpu/s_llroundl.c b/sysdeps/s390/fpu/s_llroundl.c +new file mode 100644 +index 0000000000..58976cd5c5 +--- /dev/null ++++ b/sysdeps/s390/fpu/s_llroundl.c +@@ -0,0 +1,43 @@ ++/* llroundl() - S390 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, see ++ . */ ++ ++#if defined __s390x__ && defined HAVE_S390_MIN_Z196_ZARCH_ASM_SUPPORT ++/* We only support s390x as on s390 a long long int refers to a register pair ++ of two 4byte registers instead of a 8byte register which is produced by the ++ instruction. ++ Note: On s390 this instruction would only be used if build with -mzarch. */ ++# include ++# include ++# include ++ ++long long int ++__llroundl (_Float128 x) ++{ ++ long long int y; ++ /* The z196 zarch "convert to fixed" (cgxbra) instruction is rounding ++ x to the nearest integer with "ties away from 0" rounding mode ++ (M3-field: 1) where inexact exceptions are suppressed (M4-field: 4). */ ++ __asm__ ("cgxbra %0,1,%1,4" : "=d" (y) : "f" (x) : "cc"); ++ return y; ++} ++libm_alias_ldouble (__llround, llround) ++ ++#else ++# include ++#endif +-- +2.18.2 + diff --git a/SOURCES/glibc-rh1780204-24.patch b/SOURCES/glibc-rh1780204-24.patch new file mode 100644 index 0000000..21bfd24 --- /dev/null +++ b/SOURCES/glibc-rh1780204-24.patch @@ -0,0 +1,70 @@ +From 33f3c934e3023b85c3774ee0482ec4da2a10a3b5 Mon Sep 17 00:00:00 2001 +From: Stefan Liebler +Date: Wed, 11 Dec 2019 15:09:32 +0100 +Subject: [PATCH 24/28] S390: Implement math-barriers math_opt_barrier and + math_force_eval. + +This patch implements the s390 specific math barriers in order +to omit the store and load from stack if possible. + +(cherry picked from commit 433a2ba68cd91842546e0f0d43d65835634d570d) +--- + sysdeps/s390/fpu/math-barriers.h | 46 ++++++++++++++++++++++++++++++++ + 1 file changed, 46 insertions(+) + create mode 100644 sysdeps/s390/fpu/math-barriers.h + +diff --git a/sysdeps/s390/fpu/math-barriers.h b/sysdeps/s390/fpu/math-barriers.h +new file mode 100644 +index 0000000000..7c3e6b15e0 +--- /dev/null ++++ b/sysdeps/s390/fpu/math-barriers.h +@@ -0,0 +1,46 @@ ++/* Control when floating-point expressions are evaluated. s390 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, see ++ . */ ++ ++#ifndef S390_MATH_BARRIERS_H ++#define S390_MATH_BARRIERS_H 1 ++ ++#ifdef HAVE_S390_VX_GCC_SUPPORT ++# define ASM_CONSTRAINT_VR "v" ++#else ++# define ASM_CONSTRAINT_VR ++#endif ++ ++#define math_opt_barrier(x) \ ++ ({ __typeof (x) __x = (x); \ ++ if (__builtin_types_compatible_p (__typeof (x), _Float128)) \ ++ __asm__ ("# math_opt_barrier_f128 %0" : "+fm" (__x)); \ ++ else \ ++ __asm__ ("# math_opt_barrier %0" \ ++ : "+f" ASM_CONSTRAINT_VR "m" (__x)); \ ++ __x; }) ++#define math_force_eval(x) \ ++ ({ __typeof (x) __x = (x); \ ++ if (__builtin_types_compatible_p (__typeof (x), _Float128)) \ ++ __asm__ __volatile__ ("# math_force_eval_f128 %0" \ ++ : : "fm" (__x)); \ ++ else \ ++ __asm__ __volatile__ ("# math_force_eval %0" \ ++ : : "f" ASM_CONSTRAINT_VR "m" (__x)); \ ++ }) ++ ++#endif +-- +2.18.2 + diff --git a/SOURCES/glibc-rh1780204-25.patch b/SOURCES/glibc-rh1780204-25.patch new file mode 100644 index 0000000..34353ff --- /dev/null +++ b/SOURCES/glibc-rh1780204-25.patch @@ -0,0 +1,79 @@ +From cf5397eb5b33bab37c16bcb2d1bbddbce1a27de2 Mon Sep 17 00:00:00 2001 +From: Stefan Liebler +Date: Wed, 11 Dec 2019 15:09:33 +0100 +Subject: [PATCH 25/28] S390: Implement roundtoint and converttoint and define + TOINT_INTRINSICS. + +This patch implements roundtoint and convertoint for s390 +by using the load-fp-integer and convert-to-fixed instructions. +Both functions are using "round to nearest with ties away from zero" +rounding mode and do not raise inexact exceptions. + +(cherry picked from commit 2763d3145a326aa9afa613fe9e1b444cf912a883) +--- + sysdeps/s390/fpu/math_private.h | 53 +++++++++++++++++++++++++++++++++ + 1 file changed, 53 insertions(+) + create mode 100644 sysdeps/s390/fpu/math_private.h + +diff --git a/sysdeps/s390/fpu/math_private.h b/sysdeps/s390/fpu/math_private.h +new file mode 100644 +index 0000000000..a1ae91a87c +--- /dev/null ++++ b/sysdeps/s390/fpu/math_private.h +@@ -0,0 +1,53 @@ ++/* Configure optimized libm functions. S390 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, see ++ . */ ++ ++#ifndef S390_MATH_PRIVATE_H ++#define S390_MATH_PRIVATE_H 1 ++ ++#include ++#include ++ ++#ifdef HAVE_S390_MIN_Z196_ZARCH_ASM_SUPPORT ++# define TOINT_INTRINSICS 1 ++ ++static inline double_t ++roundtoint (double_t x) ++{ ++ double_t y; ++ /* The z196 zarch "load fp integer" (fidbra) instruction is rounding ++ x to the nearest integer with ties away from zero (M3-field: 1) ++ where inexact exceptions are suppressed (M4-field: 4). */ ++ __asm__ ("fidbra %0,1,%1,4" : "=f" (y) : "f" (x)); ++ return y; ++} ++ ++static inline int32_t ++converttoint (double_t x) ++{ ++ int32_t y; ++ /* The z196 zarch "convert to fixed" (cfdbra) instruction is rounding ++ x to the nearest integer with ties away from zero (M3-field: 1) ++ where inexact exceptions are suppressed (M4-field: 4). */ ++ __asm__ ("cfdbra %0,1,%1,4" : "=d" (y) : "f" (x) : "cc"); ++ return y; ++} ++#endif ++ ++#include_next ++ ++#endif +-- +2.18.2 + diff --git a/SOURCES/glibc-rh1780204-26.patch b/SOURCES/glibc-rh1780204-26.patch new file mode 100644 index 0000000..0f5a6bc --- /dev/null +++ b/SOURCES/glibc-rh1780204-26.patch @@ -0,0 +1,23 @@ +From 363f9d7a6be5a3b400e3ea3daab583bccfcfa152 Mon Sep 17 00:00:00 2001 +From: Stefan Liebler +Date: Wed, 11 Dec 2019 15:09:34 +0100 +Subject: [PATCH 26/28] S390: Use sysdeps/ieee754/dbl-64/wordsize-64 on s390x. + +This patch enables the usage of implementations in +sysdeps/ieee754/dbl-64/wordsize-64 on 64bit s390x. + +(cherry picked from commit fcee34cc373daee6aa5320a6e1897cdf2005ab53) +--- + sysdeps/s390/s390-64/Implies | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/sysdeps/s390/s390-64/Implies b/sysdeps/s390/s390-64/Implies +index a8cae95f9d..7603c9859c 100644 +--- a/sysdeps/s390/s390-64/Implies ++++ b/sysdeps/s390/s390-64/Implies +@@ -1 +1,2 @@ + wordsize-64 ++ieee754/dbl-64/wordsize-64 +-- +2.18.2 + diff --git a/SOURCES/glibc-rh1780204-27.patch b/SOURCES/glibc-rh1780204-27.patch new file mode 100644 index 0000000..a90ba6f --- /dev/null +++ b/SOURCES/glibc-rh1780204-27.patch @@ -0,0 +1,294 @@ +From 8e5e36d7ba097b8e110ab45794659156af182f54 Mon Sep 17 00:00:00 2001 +From: Stefan Liebler +Date: Wed, 11 Dec 2019 15:09:31 +0100 +Subject: [PATCH 27/28] S390: Implement libc_fe* macros. + +This patch provides the s390 specific implementation for +libc_feholdexcept, libc_fesetround, libc_feholdexcept_setround, +libc_fetestexcept, libc_fesetenv, libc_feupdateenv_test, +libc_feupdateenv, libc_feholdsetround_ctx, libc_feresetround_ctx, +libc_feholdsetround_noex_ctx and libc_feresetround_noex_ctx. + +(cherry picked from commit 7c94d036c17dfd352d11e9bf98e5d84122c1f95e) +Note: glibc-2.28 does not have a generic fenv_private.h. +Therefore include_next does not work. Instead fenv_private.h needs to +be included in the s390 specific mathp_private.h just before including +the generic math_private.h. +As the s390 specific math_private.h is introduced with the backport of +commit "S390: Implement roundtoint and converttoint and define TOINT_INTRINSICS.", +the order of cherry-picking was changed compared to upstream! +--- + sysdeps/s390/fpu/fenv_private.h | 248 ++++++++++++++++++++++++++++++++ + sysdeps/s390/fpu/math_private.h | 1 + + 2 files changed, 249 insertions(+) + create mode 100644 sysdeps/s390/fpu/fenv_private.h + +diff --git a/sysdeps/s390/fpu/fenv_private.h b/sysdeps/s390/fpu/fenv_private.h +new file mode 100644 +index 0000000000..8899f8f434 +--- /dev/null ++++ b/sysdeps/s390/fpu/fenv_private.h +@@ -0,0 +1,248 @@ ++/* Private floating point rounding and exceptions handling. 390/s390x 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, see ++ . */ ++ ++#ifndef S390_FENV_PRIVATE_H ++#define S390_FENV_PRIVATE_H 1 ++ ++#include ++#include ++#include ++ ++static __always_inline void ++libc_feholdexcept_s390 (fenv_t *envp) ++{ ++ fpu_control_t fpc, fpc_new; ++ ++ /* Store the environment. */ ++ _FPU_GETCW (fpc); ++ envp->__fpc = fpc; ++ ++ /* Clear the current exception flags and dxc field. ++ Hold from generating fpu exceptions temporarily. */ ++ fpc_new = fpc & ~(FPC_FLAGS_MASK | FPC_DXC_MASK | FPC_EXCEPTION_MASK); ++ ++ /* Only set new environment if it has changed. */ ++ if (fpc_new != fpc) ++ _FPU_SETCW (fpc_new); ++} ++ ++#define libc_feholdexcept libc_feholdexcept_s390 ++#define libc_feholdexceptf libc_feholdexcept_s390 ++#define libc_feholdexceptl libc_feholdexcept_s390 ++ ++static __always_inline void ++libc_fesetround_s390 (int round) ++{ ++ __asm__ __volatile__ ("srnm 0(%0)" : : "a" (round)); ++} ++ ++#define libc_fesetround libc_fesetround_s390 ++#define libc_fesetroundf libc_fesetround_s390 ++#define libc_fesetroundl libc_fesetround_s390 ++ ++static __always_inline void ++libc_feholdexcept_setround_s390 (fenv_t *envp, int r) ++{ ++ fpu_control_t fpc, fpc_new; ++ ++ _FPU_GETCW (fpc); ++ envp->__fpc = fpc; ++ ++ /* Clear the current exception flags and dxc field. ++ Hold from generating fpu exceptions temporarily. ++ Reset rounding mode bits. */ ++ fpc_new = fpc & ~(FPC_FLAGS_MASK | FPC_DXC_MASK | FPC_EXCEPTION_MASK ++ | FPC_RM_MASK); ++ ++ /* Set new rounding mode. */ ++ fpc_new |= (r & FPC_RM_MASK); ++ ++ /* Only set new environment if it has changed. */ ++ if (fpc_new != fpc) ++ _FPU_SETCW (fpc_new); ++} ++ ++#define libc_feholdexcept_setround libc_feholdexcept_setround_s390 ++#define libc_feholdexcept_setroundf libc_feholdexcept_setround_s390 ++#define libc_feholdexcept_setroundl libc_feholdexcept_setround_s390 ++ ++static __always_inline int ++libc_fetestexcept_s390 (int excepts) ++{ ++ int res; ++ fexcept_t fpc; ++ ++ _FPU_GETCW (fpc); ++ ++ /* Get current exceptions. */ ++ res = (fpc >> FPC_FLAGS_SHIFT) & FE_ALL_EXCEPT; ++ if ((fpc & FPC_NOT_FPU_EXCEPTION) == 0) ++ /* Bits 6, 7 of dxc-byte are zero, ++ thus bits 0-5 of dxc-byte correspond to the flag-bits. ++ Evaluate flags and last dxc-exception-code. */ ++ res |= (fpc >> FPC_DXC_SHIFT) & FE_ALL_EXCEPT; ++ ++ return res & excepts; ++} ++ ++#define libc_fetestexcept libc_fetestexcept_s390 ++#define libc_fetestexceptf libc_fetestexcept_s390 ++#define libc_fetestexceptl libc_fetestexcept_s390 ++ ++static __always_inline void ++libc_fesetenv_s390 (const fenv_t *envp) ++{ ++ _FPU_SETCW (envp->__fpc); ++} ++ ++#define libc_fesetenv libc_fesetenv_s390 ++#define libc_fesetenvf libc_fesetenv_s390 ++#define libc_fesetenvl libc_fesetenv_s390 ++ ++static __always_inline int ++libc_feupdateenv_test_s390 (const fenv_t *envp, int ex) ++{ ++ /* Get the currently raised exceptions. */ ++ int excepts; ++ fexcept_t fpc_old; ++ ++ _FPU_GETCW (fpc_old); ++ ++ /* Get current exceptions. */ ++ excepts = (fpc_old >> FPC_FLAGS_SHIFT) & FE_ALL_EXCEPT; ++ if ((fpc_old & FPC_NOT_FPU_EXCEPTION) == 0) ++ /* Bits 6, 7 of dxc-byte are zero, ++ thus bits 0-5 of dxc-byte correspond to the flag-bits. ++ Evaluate flags and last dxc-exception-code. */ ++ excepts |= (fpc_old >> FPC_DXC_SHIFT) & FE_ALL_EXCEPT; ++ ++ /* Merge the currently raised exceptions with those in envp. */ ++ fpu_control_t fpc_new = envp->__fpc; ++ fpc_new |= excepts << FPC_FLAGS_SHIFT; ++ ++ /* Install the new fpc from envp. */ ++ if (fpc_new != fpc_old) ++ _FPU_SETCW (fpc_new); ++ ++ /* Raise the exceptions if enabled in new fpc. */ ++ if (__glibc_unlikely ((fpc_new >> FPC_EXCEPTION_MASK_SHIFT) & excepts)) ++ __feraiseexcept (excepts); ++ ++ return excepts & ex; ++} ++ ++#define libc_feupdateenv_test libc_feupdateenv_test_s390 ++#define libc_feupdateenv_testf libc_feupdateenv_test_s390 ++#define libc_feupdateenv_testl libc_feupdateenv_test_s390 ++ ++static __always_inline void ++libc_feupdateenv_s390 (const fenv_t *envp) ++{ ++ libc_feupdateenv_test_s390 (envp, 0); ++} ++ ++#define libc_feupdateenv libc_feupdateenv_s390 ++#define libc_feupdateenvf libc_feupdateenv_s390 ++#define libc_feupdateenvl libc_feupdateenv_s390 ++ ++static __always_inline fenv_t ++libc_handle_user_fenv_s390 (const fenv_t *envp) ++{ ++ fenv_t env; ++ if (envp == FE_DFL_ENV) ++ { ++ env.__fpc = _FPU_DEFAULT; ++ } ++ else if (envp == FE_NOMASK_ENV) ++ { ++ env.__fpc = FPC_EXCEPTION_MASK; ++ } ++ else ++ env = (*envp); ++ ++ return env; ++} ++ ++/* We have support for rounding mode context. */ ++#define HAVE_RM_CTX 1 ++ ++static __always_inline void ++libc_feholdsetround_s390_ctx (struct rm_ctx *ctx, int r) ++{ ++ fpu_control_t fpc; ++ int round; ++ ++ _FPU_GETCW (fpc); ++ ctx->env.__fpc = fpc; ++ ++ /* Check whether rounding modes are different. */ ++ round = fpc & FPC_RM_MASK; ++ ++ /* Set the rounding mode if changed. */ ++ if (__glibc_unlikely (round != r)) ++ { ++ ctx->updated_status = true; ++ libc_fesetround_s390 (r); ++ } ++ else ++ ctx->updated_status = false; ++} ++ ++#define libc_feholdsetround_ctx libc_feholdsetround_s390_ctx ++#define libc_feholdsetroundf_ctx libc_feholdsetround_s390_ctx ++#define libc_feholdsetroundl_ctx libc_feholdsetround_s390_ctx ++ ++static __always_inline void ++libc_feresetround_s390_ctx (struct rm_ctx *ctx) ++{ ++ /* Restore the rounding mode if updated. */ ++ if (__glibc_unlikely (ctx->updated_status)) ++ { ++ fpu_control_t fpc; ++ _FPU_GETCW (fpc); ++ fpc = ctx->env.__fpc | (fpc & FPC_FLAGS_MASK); ++ _FPU_SETCW (fpc); ++ } ++} ++ ++#define libc_feresetround_ctx libc_feresetround_s390_ctx ++#define libc_feresetroundf_ctx libc_feresetround_s390_ctx ++#define libc_feresetroundl_ctx libc_feresetround_s390_ctx ++ ++static __always_inline void ++libc_feholdsetround_noex_s390_ctx (struct rm_ctx *ctx, int r) ++{ ++ libc_feholdexcept_setround_s390 (&ctx->env, r); ++} ++ ++#define libc_feholdsetround_noex_ctx libc_feholdsetround_noex_s390_ctx ++#define libc_feholdsetround_noexf_ctx libc_feholdsetround_noex_s390_ctx ++#define libc_feholdsetround_noexl_ctx libc_feholdsetround_noex_s390_ctx ++ ++static __always_inline void ++libc_feresetround_noex_s390_ctx (struct rm_ctx *ctx) ++{ ++ /* Restore exception flags and rounding mode. */ ++ libc_fesetenv_s390 (&ctx->env); ++} ++ ++#define libc_feresetround_noex_ctx libc_feresetround_noex_s390_ctx ++#define libc_feresetround_noexf_ctx libc_feresetround_noex_s390_ctx ++#define libc_feresetround_noexl_ctx libc_feresetround_noex_s390_ctx ++ ++#endif +diff --git a/sysdeps/s390/fpu/math_private.h b/sysdeps/s390/fpu/math_private.h +index a1ae91a87c..f3c770d59a 100644 +--- a/sysdeps/s390/fpu/math_private.h ++++ b/sysdeps/s390/fpu/math_private.h +@@ -48,6 +48,7 @@ converttoint (double_t x) + } + #endif + ++#include + #include_next + + #endif +-- +2.18.2 + diff --git a/SOURCES/glibc-rh1780204-28.patch b/SOURCES/glibc-rh1780204-28.patch new file mode 100644 index 0000000..d2b165a --- /dev/null +++ b/SOURCES/glibc-rh1780204-28.patch @@ -0,0 +1,317 @@ +From 2ab6ce8252a14e6ef0cfb33046dd565ae15085c2 Mon Sep 17 00:00:00 2001 +From: Stefan Liebler +Date: Wed, 11 Dec 2019 15:09:32 +0100 +Subject: [PATCH 28/28] S390: Use libc_fe* macros in fe* functions. + +This patch updates the s390 specific functions fegetround, +fesetround, feholdexcept, fesetenv, feupdateenv, fegetexceptflag, +fetestexcept, fesetexceptflag, fetestexceptflag. +Now those functions are using the libc_fe* macros if possible. + +Furthermore fegetexceptflag is now returning the exception from +dxc field shifted to the usual exception-flags. +Thus a special fetestexceptflag implementation is not needed anymore. + +(cherry picked from commit 238adf59db85646ebae47876819bd896dae597bc) +--- + sysdeps/s390/fpu/fegetround.c | 9 ++------- + sysdeps/s390/fpu/feholdexcpt.c | 12 ++--------- + sysdeps/s390/fpu/fesetenv.c | 21 +++---------------- + sysdeps/s390/fpu/fesetround.c | 9 +++------ + sysdeps/s390/fpu/fetestexceptflag.c | 31 ----------------------------- + sysdeps/s390/fpu/feupdateenv.c | 14 +++---------- + sysdeps/s390/fpu/fgetexcptflg.c | 16 ++------------- + sysdeps/s390/fpu/fsetexcptflg.c | 23 ++++++++++----------- + sysdeps/s390/fpu/ftestexcept.c | 16 ++------------- + 9 files changed, 27 insertions(+), 124 deletions(-) + delete mode 100644 sysdeps/s390/fpu/fetestexceptflag.c + +diff --git a/sysdeps/s390/fpu/fegetround.c b/sysdeps/s390/fpu/fegetround.c +index 3c38bc9189..f1be1d12e1 100644 +--- a/sysdeps/s390/fpu/fegetround.c ++++ b/sysdeps/s390/fpu/fegetround.c +@@ -17,17 +17,12 @@ + License along with the GNU C Library; if not, see + . */ + +-#include +-#include ++#include + + int + __fegetround (void) + { +- fexcept_t cw; +- +- _FPU_GETCW (cw); +- +- return cw & FPC_RM_MASK; ++ return get_rounding_mode (); + } + libm_hidden_def (__fegetround) + weak_alias (__fegetround, fegetround) +diff --git a/sysdeps/s390/fpu/feholdexcpt.c b/sysdeps/s390/fpu/feholdexcpt.c +index 5daee5675d..48af7ff51b 100644 +--- a/sysdeps/s390/fpu/feholdexcpt.c ++++ b/sysdeps/s390/fpu/feholdexcpt.c +@@ -17,19 +17,11 @@ + License along with the GNU C Library; if not, see + . */ + +-#include +-#include ++#include + + int __feholdexcept (fenv_t *envp) + { +- fexcept_t fpc; +- /* Store the environment. */ +- __fegetenv (envp); +- /* Clear the current sticky bits as more than one exception +- may be generated. */ +- fpc = envp->__fpc & ~(FPC_FLAGS_MASK | FPC_DXC_MASK); +- /* Hold from generating fpu exceptions temporarily. */ +- _FPU_SETCW ((fpc & ~(FE_ALL_EXCEPT << FPC_EXCEPTION_MASK_SHIFT))); ++ libc_feholdexcept_s390 (envp); + return 0; + } + libm_hidden_def (__feholdexcept) +diff --git a/sysdeps/s390/fpu/fesetenv.c b/sysdeps/s390/fpu/fesetenv.c +index c6c275d79d..54ba2aa94a 100644 +--- a/sysdeps/s390/fpu/fesetenv.c ++++ b/sysdeps/s390/fpu/fesetenv.c +@@ -17,28 +17,13 @@ + License along with the GNU C Library; if not, see + . */ + +-#include +-#include +-#include +-#include ++#include + + int + __fesetenv (const fenv_t *envp) + { +- fenv_t env; +- +- if (envp == FE_DFL_ENV) +- { +- env.__fpc = _FPU_DEFAULT; +- } +- else if (envp == FE_NOMASK_ENV) +- { +- env.__fpc = FPC_EXCEPTION_MASK; +- } +- else +- env = (*envp); +- +- _FPU_SETCW (env.__fpc); ++ fenv_t env = libc_handle_user_fenv_s390 (envp); ++ libc_fesetenv_s390 (&env); + + /* Success. */ + return 0; +diff --git a/sysdeps/s390/fpu/fesetround.c b/sysdeps/s390/fpu/fesetround.c +index d8a84d2c96..0a7fe2635b 100644 +--- a/sysdeps/s390/fpu/fesetround.c ++++ b/sysdeps/s390/fpu/fesetround.c +@@ -17,21 +17,18 @@ + License along with the GNU C Library; if not, see + . */ + +-#include +-#include ++#include + + int + __fesetround (int round) + { +- if ((round|FPC_RM_MASK) != FPC_RM_MASK) ++ if ((round | FPC_RM_MASK) != FPC_RM_MASK) + { + /* ROUND is not a valid rounding mode. */ + return 1; + } +- __asm__ __volatile__ ("srnm 0(%0)" +- : +- : "a" (round)); + ++ libc_fesetround_s390 (round); + return 0; + } + libm_hidden_def (__fesetround) +diff --git a/sysdeps/s390/fpu/fetestexceptflag.c b/sysdeps/s390/fpu/fetestexceptflag.c +deleted file mode 100644 +index 784d356f7b..0000000000 +--- a/sysdeps/s390/fpu/fetestexceptflag.c ++++ /dev/null +@@ -1,31 +0,0 @@ +-/* Test exception in saved exception state. S/390 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 +-fetestexceptflag (const fexcept_t *flagp, int excepts) +-{ +- /* As *flagp is obtained by an earlier call of fegetexceptflag the +- bits 0-5 of dxc-byte are either zero or correspond to the +- flag-bits. Evaluate flags and last dxc-exception-code. */ +- return (((*flagp >> FPC_FLAGS_SHIFT) | (*flagp >> FPC_DXC_SHIFT)) +- & excepts +- & FE_ALL_EXCEPT); +-} +diff --git a/sysdeps/s390/fpu/feupdateenv.c b/sysdeps/s390/fpu/feupdateenv.c +index 4888e1a864..f6b3d7d2de 100644 +--- a/sysdeps/s390/fpu/feupdateenv.c ++++ b/sysdeps/s390/fpu/feupdateenv.c +@@ -18,21 +18,13 @@ + . */ + + +-#include +-#include ++#include + + int + __feupdateenv (const fenv_t *envp) + { +- fexcept_t temp; +- +- _FPU_GETCW (temp); +- temp = (temp & FPC_FLAGS_MASK) >> FPC_FLAGS_SHIFT; +- +- /* Raise the exceptions since the last call to feholdenv */ +- /* re install saved environment. */ +- __fesetenv (envp); +- __feraiseexcept ((int) temp); ++ fenv_t env = libc_handle_user_fenv_s390 (envp); ++ libc_feupdateenv_s390 (&env); + + /* Success. */ + return 0; +diff --git a/sysdeps/s390/fpu/fgetexcptflg.c b/sysdeps/s390/fpu/fgetexcptflg.c +index 2a0f6dc77c..1985b396c9 100644 +--- a/sysdeps/s390/fpu/fgetexcptflg.c ++++ b/sysdeps/s390/fpu/fgetexcptflg.c +@@ -17,24 +17,12 @@ + License along with the GNU C Library; if not, see + . */ + +-#include +-#include ++#include + + int + fegetexceptflag (fexcept_t *flagp, int excepts) + { +- fexcept_t temp, newexcepts; +- +- /* Get the current exceptions. */ +- _FPU_GETCW (temp); +- newexcepts = excepts << FPC_FLAGS_SHIFT; +- if ((temp & FPC_NOT_FPU_EXCEPTION) == 0) +- /* Bits 6, 7 of dxc-byte are zero, +- thus bits 0-5 of dxc-byte correspond to the flag-bits. +- Evaluate flags and last dxc-exception-code. */ +- newexcepts |= excepts << FPC_DXC_SHIFT; +- +- *flagp = temp & newexcepts; ++ *flagp = libc_fetestexcept_s390 (excepts); + + /* Success. */ + return 0; +diff --git a/sysdeps/s390/fpu/fsetexcptflg.c b/sysdeps/s390/fpu/fsetexcptflg.c +index e50684c574..51d258cf17 100644 +--- a/sysdeps/s390/fpu/fsetexcptflg.c ++++ b/sysdeps/s390/fpu/fsetexcptflg.c +@@ -24,29 +24,26 @@ + int + fesetexceptflag (const fexcept_t *flagp, int excepts) + { +- fexcept_t temp, newexcepts; ++ fexcept_t fpc, fpc_new; + + /* Get the current environment. We have to do this since we cannot + separately set the status word. */ +- _FPU_GETCW (temp); +- /* Install the new exception bits in the Accrued Exception Byte. */ +- excepts = excepts & FE_ALL_EXCEPT; +- newexcepts = excepts << FPC_FLAGS_SHIFT; +- temp &= ~newexcepts; +- if ((temp & FPC_NOT_FPU_EXCEPTION) == 0) ++ _FPU_GETCW (fpc); ++ ++ /* Clear the current exception bits. */ ++ fpc_new = fpc & ~((excepts & FE_ALL_EXCEPT) << FPC_FLAGS_SHIFT); ++ if ((fpc & FPC_NOT_FPU_EXCEPTION) == 0) + /* Bits 6, 7 of dxc-byte are zero, + thus bits 0-5 of dxc-byte correspond to the flag-bits. + Clear given exceptions in dxc-field. */ +- temp &= ~(excepts << FPC_DXC_SHIFT); ++ fpc_new &= ~((excepts & FE_ALL_EXCEPT) << FPC_DXC_SHIFT); + +- /* Integrate dxc-byte of flagp into flags. The dxc-byte of flagp contains +- either an ieee-exception or 0 (see fegetexceptflag). */ +- temp |= (*flagp | ((*flagp >> FPC_DXC_SHIFT) << FPC_FLAGS_SHIFT)) +- & newexcepts; ++ /* Set exceptions from flagp in flags-field. */ ++ fpc_new |= (*flagp & excepts & FE_ALL_EXCEPT) << FPC_FLAGS_SHIFT; + + /* Store the new status word (along with the rest of the environment. + Possibly new exceptions are set but they won't get executed. */ +- _FPU_SETCW (temp); ++ _FPU_SETCW (fpc_new); + + /* Success. */ + return 0; +diff --git a/sysdeps/s390/fpu/ftestexcept.c b/sysdeps/s390/fpu/ftestexcept.c +index 727b9b342d..f2acecc1af 100644 +--- a/sysdeps/s390/fpu/ftestexcept.c ++++ b/sysdeps/s390/fpu/ftestexcept.c +@@ -17,23 +17,11 @@ + License along with the GNU C Library; if not, see + . */ + +-#include +-#include ++#include + + int + fetestexcept (int excepts) + { +- fexcept_t temp, res; +- +- /* Get current exceptions. */ +- _FPU_GETCW (temp); +- res = temp >> FPC_FLAGS_SHIFT; +- if ((temp & FPC_NOT_FPU_EXCEPTION) == 0) +- /* Bits 6, 7 of dxc-byte are zero, +- thus bits 0-5 of dxc-byte correspond to the flag-bits. +- Evaluate flags and last dxc-exception-code. */ +- res |= temp >> FPC_DXC_SHIFT; +- +- return res & excepts & FE_ALL_EXCEPT; ++ return libc_fetestexcept_s390 (excepts); + } + libm_hidden_def (fetestexcept) +-- +2.18.2 + diff --git a/SOURCES/glibc-rh1780204-29.patch b/SOURCES/glibc-rh1780204-29.patch new file mode 100644 index 0000000..cf88bee --- /dev/null +++ b/SOURCES/glibc-rh1780204-29.patch @@ -0,0 +1,160 @@ +From af123aa95091d3d2d1b4ff027cf806ca1721d29d Mon Sep 17 00:00:00 2001 +From: Stefan Liebler +Date: Wed, 11 Dec 2019 15:09:14 +0100 +Subject: [PATCH 01/28] Always use wordsize-64 version of s_nearbyint.c. + +This patch replaces s_nearbyint.c in sysdeps/dbl-64 with the one in +sysdeps/dbl-64/wordsize-64 and removes the latter one. +The code is not changed except changes in code style. + +Also adjusted the include path in x86_64 file. + +Reviewed-by: Adhemerval Zanella +--- + sysdeps/ieee754/dbl-64/s_nearbyint.c | 38 ++++++-------- + sysdeps/ieee754/dbl-64/wordsize-64/s_nearbyint.c | 65 ------------------------ + sysdeps/x86_64/fpu/multiarch/s_nearbyint-c.c | 2 +- + 3 files changed, 17 insertions(+), 88 deletions(-) + delete mode 100644 sysdeps/ieee754/dbl-64/wordsize-64/s_nearbyint.c + +Note: tweaked by DJ for backport; some portions handled by glibc-rh1780204-07.patch + +diff -rupN a/sysdeps/ieee754/dbl-64/s_nearbyint.c b/sysdeps/ieee754/dbl-64/s_nearbyint.c +--- a/sysdeps/ieee754/dbl-64/s_nearbyint.c 2020-04-09 21:17:04.281854809 -0400 ++++ b/sysdeps/ieee754/dbl-64/s_nearbyint.c 2020-04-09 21:28:13.380741798 -0400 +@@ -10,10 +10,6 @@ + * ==================================================== + */ + +-#if defined(LIBM_SCCS) && !defined(lint) +-static char rcsid[] = "$NetBSD: s_rint.c,v 1.8 1995/05/10 20:48:04 jtc Exp $"; +-#endif +- + /* + * rint(x) + * Return x rounded to integral value according to the prevailing +@@ -44,35 +40,33 @@ __nearbyint (double x) + -4.50359962737049600000e+15, /* 0xC3300000, 0x00000000 */ + }; + fenv_t env; +- int32_t i0, j0, sx; +- double w, t; +- GET_HIGH_WORD (i0, x); +- sx = (i0 >> 31) & 1; +- j0 = ((i0 >> 20) & 0x7ff) - 0x3ff; +- if (j0 < 52) ++ int64_t i0, sx; ++ int32_t j0; ++ EXTRACT_WORDS64 (i0, x); ++ sx = (i0 >> 63) & 1; ++ j0 = ((i0 >> 52) & 0x7ff) - 0x3ff; ++ if (__glibc_likely (j0 < 52)) + { + if (j0 < 0) + { + libc_feholdexcept (&env); +- w = TWO52[sx] + math_opt_barrier (x); +- t = w - TWO52[sx]; ++ double w = TWO52[sx] + math_opt_barrier (x); ++ double t = w - TWO52[sx]; + math_force_eval (t); + libc_fesetenv (&env); +- GET_HIGH_WORD (i0, t); +- SET_HIGH_WORD (t, (i0 & 0x7fffffff) | (sx << 31)); +- return t; ++ return copysign (t, x); + } + } + else + { + if (j0 == 0x400) +- return x + x; /* inf or NaN */ ++ return x + x; /* inf or NaN */ + else +- return x; /* x is integral */ ++ return x; /* x is integral */ + } + libc_feholdexcept (&env); +- w = TWO52[sx] + math_opt_barrier (x); +- t = w - TWO52[sx]; ++ double w = TWO52[sx] + math_opt_barrier (x); ++ double t = w - TWO52[sx]; + math_force_eval (t); + libc_fesetenv (&env); + return t; +diff -rupN a/sysdeps/ieee754/dbl-64/wordsize-64/s_nearbyint.c b/sysdeps/ieee754/dbl-64/wordsize-64/s_nearbyint.c +--- a/sysdeps/ieee754/dbl-64/wordsize-64/s_nearbyint.c 2018-08-01 01:10:47.000000000 -0400 ++++ b/sysdeps/ieee754/dbl-64/wordsize-64/s_nearbyint.c 1969-12-31 19:00:00.000000000 -0500 +@@ -1,64 +0,0 @@ +-/* Adapted for use as nearbyint by Ulrich Drepper . */ +-/* +- * ==================================================== +- * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. +- * +- * Developed at SunPro, a Sun Microsystems, Inc. business. +- * Permission to use, copy, modify, and distribute this +- * software is freely granted, provided that this notice +- * is preserved. +- * ==================================================== +- */ +- +-/* +- * rint(x) +- * Return x rounded to integral value according to the prevailing +- * rounding mode. +- * Method: +- * Using floating addition. +- * Exception: +- * Inexact flag raised if x not equal to rint(x). +- */ +- +-#include +-#include +-#include +-#include +-#include +- +-static const double +-TWO52[2]={ +- 4.50359962737049600000e+15, /* 0x43300000, 0x00000000 */ +- -4.50359962737049600000e+15, /* 0xC3300000, 0x00000000 */ +-}; +- +-double +-__nearbyint(double x) +-{ +- fenv_t env; +- int64_t i0,sx; +- int32_t j0; +- EXTRACT_WORDS64(i0,x); +- sx = (i0>>63)&1; +- j0 = ((i0>>52)&0x7ff)-0x3ff; +- if(__builtin_expect(j0<52, 1)) { +- if(j0<0) { +- libc_feholdexcept (&env); +- double w = TWO52[sx] + math_opt_barrier (x); +- double t = w-TWO52[sx]; +- math_force_eval (t); +- libc_fesetenv (&env); +- return __copysign (t, x); +- } +- } else { +- if(j0==0x400) return x+x; /* inf or NaN */ +- else return x; /* x is integral */ +- } +- libc_feholdexcept (&env); +- double w = TWO52[sx] + math_opt_barrier (x); +- double t = w-TWO52[sx]; +- math_force_eval (t); +- libc_fesetenv (&env); +- return t; +-} +-libm_alias_double (__nearbyint, nearbyint) +diff -rupN a/sysdeps/x86_64/fpu/multiarch/s_nearbyint-c.c b/sysdeps/x86_64/fpu/multiarch/s_nearbyint-c.c +--- a/sysdeps/x86_64/fpu/multiarch/s_nearbyint-c.c 2018-08-01 01:10:47.000000000 -0400 ++++ b/sysdeps/x86_64/fpu/multiarch/s_nearbyint-c.c 2020-04-09 21:28:13.205735274 -0400 +@@ -1,3 +1,3 @@ + #undef __nearbyint + #define __nearbyint __nearbyint_c +-#include ++#include diff --git a/SOURCES/glibc-rh1783303-1.patch b/SOURCES/glibc-rh1783303-1.patch new file mode 100644 index 0000000..89fe806 --- /dev/null +++ b/SOURCES/glibc-rh1783303-1.patch @@ -0,0 +1,1188 @@ +commit 6cac323c8dd78668e65aaa29f044cbd33c1a66a5 +Author: Adhemerval Zanella +Date: Fri Mar 15 18:42:00 2019 +0000 + + powerpc: ceil/ceilf refactor + + This patches consolidates all the powerpc ceil{f} implementations on + the generic sysdeps/powerpc/fpu/s_ceil{f}. The generic implementation + uses either the compiler builts for ISA 2.03+ (which generates the frip + instruction) or a generic implementation which uses FP only operations. + + It adds a generic implementation (round_to_integer.h) which is shared + with other rounding to integer routines. The resulting code should be + similar in term os performance to previous assembly one. + + The IFUNC organization for powerpc64 is also change to be enabled only + for powerpc64 and not for powerpc64le (since minium ISA of 2.08 does not + require the fallback generic implementation). + + Checked on powerpc-linux-gnu (built without --with-cpu, with + --with-cpu=power4 and with --with-cpu=power5+ and --disable-multi-arch), + powerpc64-linux-gnu (built without --with-cp and with --with-cpu=power5+ + and --disable-multi-arch). + + * sysdeps/powerpc/fpu/fenv_libc.h (__fesetround_inline_nocheck): New + function. + * sysdeps/powerpc/fpu/round_to_integer.h: New file. + * sysdeps/powerpc/fpu/s_ceil.c: Likewise. + * sysdeps/powerpc/fpu/s_ceilf.c: Likewise. + * sysdeps/powerpc/powerpc32/fpu/s_ceil.S: Remove file. + * sysdeps/powerpc/powerpc32/fpu/s_ceilf.S: Likewise. + * sysdeps/powerpc/powerpc32/power4/fpu/multiarch/Makefile + (CFLAGS-s_ceil-power5+.c, CFLAGS-s_ceilf-power5+.c): New rule. + * sysdeps/powerpc/powerpc32/power4/fpu/multiarch/s_ceil-power5+.S: + Remove file. + * sysdeps/powerpc/powerpc32/power4/fpu/multiarch/s_ceil-ppc32.S: + Likewise. + * sysdeps/powerpc/powerpc32/power4/fpu/multiarch/s_ceilf-power5+.S: + Likewise. + * sysdeps/powerpc/powerpc32/power4/fpu/multiarch/s_ceilf-ppc32.S: + Likewise. + * sysdeps/powerpc/powerpc32/power4/fpu/multiarch/s_ceil-power5+.c: + New file. + * sysdeps/powerpc/powerpc32/power4/fpu/multiarch/s_ceil-ppc32.c: + Likewise. + * sysdeps/powerpc/powerpc32/power4/fpu/multiarch/s_ceilf-power5+.c: + Likewise. + * sysdeps/powerpc/powerpc32/power4/fpu/multiarch/s_ceilf-ppc32.c: + Likewise. + * sysdeps/powerpc/powerpc32/power5+/fpu/s_ceil.S: Remove file. + * sysdeps/powerpc/powerpc32/power5+/fpu/s_ceilf.S: Likewise. + * sysdeps/powerpc/powerpc64/be/fpu/multiarch/Makefile: New file. + * sysdeps/powerpc/powerpc64/be/fpu/multiarch/s_ceil-power5+.c: + Likewise. + * sysdeps/powerpc/powerpc64/be/fpu/multiarch/s_ceil-ppc64.c: + Likewise. + * sysdeps/powerpc/powerpc64/fpu/multiarch/s_ceil.c: Move to ... + * sysdeps/powerpc/powerpc64/be/fpu/multiarch/s_ceil.c: ... here. + * sysdeps/powerpc/powerpc64/be/fpu/multiarch/s_ceilf-power5+.c: New + file. + * sysdeps/powerpc/powerpc64/be/fpu/multiarch/s_ceilf-ppc64.c: + Likewise. + * sysdeps/powerpc/powerpc64/fpu/multiarch/s_ceilf.c: Move to ... + * sysdeps/powerpc/powerpc64/be/fpu/multiarch/s_ceilf.c: ... + * here. + * sysdeps/powerpc/powerpc64/fpu/multiarch/Makefile + (libm-sysdep_routines): Remove s_ceil-power5+, s_ceil-ppc64, + s_ceilf-power5+, and s_ceilf-ppc64. + * sysdeps/powerpc/powerpc64/fpu/multiarch/s_ceil-power5+.S: Remove + file. + * sysdeps/powerpc/powerpc64/fpu/multiarch/s_ceil-ppc64.S: Likewise. + * sysdeps/powerpc/powerpc64/fpu/multiarch/s_ceilf-power5+.S: Likewise. + * sysdeps/powerpc/powerpc64/fpu/multiarch/s_ceilf-ppc64.S: Likewise. + * sysdeps/powerpc/powerpc64/fpu/s_ceil.S: Likewise. + * sysdeps/powerpc/powerpc64/fpu/s_ceilf.S: Likewise. + * sysdeps/powerpc/powerpc64/power5+/fpu/s_ceil.S: Likewise. + * sysdeps/powerpc/powerpc64/power5+/fpu/s_ceilf.S: Likewise. + + Reviewed-by: Gabriel F. T. Gomes + +Conflicts: + sysdeps/powerpc/powerpc32/fpu/s_ceil.S + sysdeps/powerpc/powerpc32/fpu/s_ceilf.S + sysdeps/powerpc/powerpc32/power4/fpu/multiarch/s_ceil-power5+.S + sysdeps/powerpc/powerpc32/power4/fpu/multiarch/s_ceil-ppc32.S + sysdeps/powerpc/powerpc32/power4/fpu/multiarch/s_ceilf-power5+.S + sysdeps/powerpc/powerpc32/power4/fpu/multiarch/s_ceilf-ppc32.S + sysdeps/powerpc/powerpc32/power5+/fpu/s_ceil.S + sysdeps/powerpc/powerpc32/power5+/fpu/s_ceilf.S + sysdeps/powerpc/powerpc64/fpu/multiarch/s_ceil-power5+.S + sysdeps/powerpc/powerpc64/fpu/multiarch/s_ceil-ppc64.S + sysdeps/powerpc/powerpc64/fpu/multiarch/s_ceilf-power5+.S + sysdeps/powerpc/powerpc64/fpu/multiarch/s_ceilf-ppc64.S + sysdeps/powerpc/powerpc64/fpu/s_ceil.S + sysdeps/powerpc/powerpc64/fpu/s_ceilf.S + sysdeps/powerpc/powerpc64/power5+/fpu/s_ceil.S + sysdeps/powerpc/powerpc64/power5+/fpu/s_ceilf.S + (Removal after the copyright year header change upstream.) + +diff --git a/sysdeps/powerpc/fpu/fenv_libc.h b/sysdeps/powerpc/fpu/fenv_libc.h +index 4c19d12b0b31c1f9..a0128c66444a3e46 100644 +--- a/sysdeps/powerpc/fpu/fenv_libc.h ++++ b/sysdeps/powerpc/fpu/fenv_libc.h +@@ -98,6 +98,14 @@ __fesetround_inline (int round) + return 0; + } + ++/* Same as __fesetround_inline, however without runtime check to use DFP ++ mtfsfi syntax (as relax_fenv_state) or if round value is valid. */ ++static inline void ++__fesetround_inline_nocheck (const int round) ++{ ++ asm volatile ("mtfsfi 7,%0" : : "i" (round)); ++} ++ + /* Definitions of all the FPSCR bit numbers */ + enum { + FPSCR_FX = 0, /* exception summary */ +diff --git a/sysdeps/powerpc/fpu/round_to_integer.h b/sysdeps/powerpc/fpu/round_to_integer.h +new file mode 100644 +index 0000000000000000..c70afbb10f600d81 +--- /dev/null ++++ b/sysdeps/powerpc/fpu/round_to_integer.h +@@ -0,0 +1,105 @@ ++/* Round to integer generic implementation. ++ 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 Library General Public License as ++ published by the Free Software Foundation; either version 2 of the ++ License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Library General Public License for more details. ++ ++ You should have received a copy of the GNU Library General Public ++ License along with the GNU C Library; see the file COPYING.LIB. If ++ not, see . */ ++ ++#ifndef _ROUND_TO_INTEGER_H ++#define _ROUND_TO_INTEGER_H ++ ++#include ++ ++enum round_mode ++{ ++ CEIL ++}; ++ ++static inline void ++set_fenv_mode (enum round_mode mode) ++{ ++ int rmode; ++ switch (mode) ++ { ++ case CEIL: rmode = FE_UPWARD; break; ++ default: rmode = FE_TONEAREST; break; ++ } ++ __fesetround_inline_nocheck (rmode); ++} ++ ++static inline float ++round_to_integer_float (enum round_mode mode, float x) ++{ ++ /* Ensure sNaN input is converted to qNaN. */ ++ if (__glibc_unlikely (isnan (x))) ++ return x + x; ++ ++ if (fabs (x) > 0x1p+23) ++ return x; ++ ++ float r = x; ++ ++ /* Save current FPU rounding mode and inexact state. */ ++ fenv_t fe = fegetenv_register (); ++ set_fenv_mode (mode); ++ if (x > 0.0) ++ { ++ r += 0x1p+23; ++ r -= 0x1p+23; ++ r = fabs (r); ++ } ++ else if (x < 0.0) ++ { ++ r -= 0x1p+23; ++ r += 0x1p+23; ++ r = -fabs (r); ++ } ++ __builtin_mtfsf (0xff, fe); ++ ++ return r; ++} ++ ++static inline double ++round_to_integer_double (enum round_mode mode, double x) ++{ ++ /* Ensure sNaN input is converted to qNaN. */ ++ if (__glibc_unlikely (isnan (x))) ++ return x + x; ++ ++ if (fabs (x) > 0x1p+52) ++ return x; ++ ++ double r = x; ++ ++ /* Save current FPU rounding mode and inexact state. */ ++ fenv_t fe = fegetenv_register (); ++ set_fenv_mode (mode); ++ if (x > 0.0) ++ { ++ r += 0x1p+52; ++ r -= 0x1p+52; ++ r = fabs (r); ++ } ++ else if (x < 0.0) ++ { ++ r -= 0x1p+52; ++ r += 0x1p+52; ++ r = -fabs (r); ++ } ++ __builtin_mtfsf (0xff, fe); ++ ++ return r; ++} ++ ++#endif +diff --git a/sysdeps/powerpc/fpu/s_ceil.c b/sysdeps/powerpc/fpu/s_ceil.c +new file mode 100644 +index 0000000000000000..49008c7af87d6d55 +--- /dev/null ++++ b/sysdeps/powerpc/fpu/s_ceil.c +@@ -0,0 +1,35 @@ ++/* Smallest integral value not less than argument. PowerPC 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 Library General Public License as ++ published by the Free Software Foundation; either version 2 of the ++ License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Library General Public License for more details. ++ ++ You should have received a copy of the GNU Library General Public ++ License along with the GNU C Library; see the file COPYING.LIB. If ++ not, see . */ ++ ++#define NO_MATH_REDIRECT ++#include ++#include ++#include ++ ++double ++__ceil (double x) ++{ ++#ifdef _ARCH_PWR5X ++ return __builtin_ceil (x); ++#else ++ return round_to_integer_double (CEIL, x); ++#endif ++} ++#ifndef __ceil ++libm_alias_double (__ceil, ceil) ++#endif +diff --git a/sysdeps/powerpc/fpu/s_ceilf.c b/sysdeps/powerpc/fpu/s_ceilf.c +new file mode 100644 +index 0000000000000000..8c86bf30a34df4cf +--- /dev/null ++++ b/sysdeps/powerpc/fpu/s_ceilf.c +@@ -0,0 +1,35 @@ ++/* Smallest integral value not less than argument. PowerPC 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 Library General Public License as ++ published by the Free Software Foundation; either version 2 of the ++ License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Library General Public License for more details. ++ ++ You should have received a copy of the GNU Library General Public ++ License along with the GNU C Library; see the file COPYING.LIB. If ++ not, see . */ ++ ++#define NO_MATH_REDIRECT ++#include ++#include ++#include ++ ++float ++__ceilf (float x) ++{ ++#ifdef _ARCH_PWR5X ++ return __builtin_ceilf (x); ++#else ++ return round_to_integer_float (CEIL, x); ++#endif ++} ++#ifndef __ceilf ++libm_alias_float (__ceil, ceil) ++#endif +diff --git a/sysdeps/powerpc/powerpc32/fpu/s_ceil.S b/sysdeps/powerpc/powerpc32/fpu/s_ceil.S +deleted file mode 100644 +index 7f2f97ada1a14a52..0000000000000000 +--- a/sysdeps/powerpc/powerpc32/fpu/s_ceil.S ++++ /dev/null +@@ -1,76 +0,0 @@ +-/* ceil function. PowerPC32 version. +- 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 +-#include +- +- .section .rodata.cst4,"aM",@progbits,4 +- .align 2 +-.LC0: /* 2**52 */ +- .long 0x59800000 +- +- .section ".text" +-ENTRY (__ceil) +-#ifdef SHARED +- mflr r11 +- cfi_register(lr,r11) +- SETUP_GOT_ACCESS(r9,got_label) +- addis r9,r9,.LC0-got_label@ha +- lfs fp13,.LC0-got_label@l(r9) +- mtlr r11 +- cfi_same_value (lr) +-#else +- lis r9,.LC0@ha +- lfs fp13,.LC0@l(r9) +-#endif +- fabs fp0,fp1 +- fsub fp12,fp13,fp13 /* generate 0.0 */ +- fcmpu cr7,fp0,fp13 /* if (fabs(x) > TWO52) */ +- mffs fp11 /* Save current FPU rounding mode and +- "inexact" state. */ +- fcmpu cr6,fp1,fp12 /* if (x > 0.0) */ +- bnl- cr7,.L10 +- mtfsfi 7,2 /* Set rounding mode toward +inf. */ +- ble- cr6,.L4 +- fadd fp1,fp1,fp13 /* x+= TWO52; */ +- fsub fp1,fp1,fp13 /* x-= TWO52; */ +- fabs fp1,fp1 /* if (x == 0.0) */ +- /* x = 0.0; */ +- mtfsf 0xff,fp11 /* Restore previous rounding mode and +- "inexact" state. */ +- blr +-.L4: +- bge- cr6,.L9 /* if (x < 0.0) */ +- fsub fp1,fp1,fp13 /* x-= TWO52; */ +- fadd fp1,fp1,fp13 /* x+= TWO52; */ +- fnabs fp1,fp1 /* if (x == 0.0) */ +- /* x = -0.0; */ +-.L9: +- mtfsf 0xff,fp11 /* Restore previous rounding mode and +- "inexact" state. */ +- blr +-.L10: +- /* Ensure sNaN input is converted to qNaN. */ +- fcmpu cr7,fp1,fp1 +- beqlr cr7 +- fadd fp1,fp1,fp1 +- blr +- END (__ceil) +- +-libm_alias_double (__ceil, ceil) +diff --git a/sysdeps/powerpc/powerpc32/fpu/s_ceilf.S b/sysdeps/powerpc/powerpc32/fpu/s_ceilf.S +deleted file mode 100644 +index 3f5949004fa51baf..0000000000000000 +--- a/sysdeps/powerpc/powerpc32/fpu/s_ceilf.S ++++ /dev/null +@@ -1,76 +0,0 @@ +-/* float ceil function. PowerPC32 version. +- 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 +- +- .section .rodata.cst4,"aM",@progbits,4 +- .align 2 +-.LC0: /* 2**23 */ +- .long 0x4b000000 +- +- .section ".text" +-ENTRY (__ceilf) +-#ifdef SHARED +- mflr r11 +- cfi_register(lr,r11) +- SETUP_GOT_ACCESS(r9,got_label) +- addis r9,r9,.LC0-got_label@ha +- lfs fp13,.LC0-got_label@l(r9) +- mtlr r11 +- cfi_same_value (lr) +-#else +- lis r9,.LC0@ha +- lfs fp13,.LC0@l(r9) +-#endif +- fabs fp0,fp1 +- fsubs fp12,fp13,fp13 /* generate 0.0 */ +- fcmpu cr7,fp0,fp13 /* if (fabs(x) > TWO23) */ +- mffs fp11 /* Save current FPU rounding mode and +- "inexact" state. */ +- fcmpu cr6,fp1,fp12 /* if (x > 0.0) */ +- bnl- cr7,.L10 +- mtfsfi 7,2 /* Set rounding mode toward +inf. */ +- ble- cr6,.L4 +- fadds fp1,fp1,fp13 /* x+= TWO23; */ +- fsubs fp1,fp1,fp13 /* x-= TWO23; */ +- fabs fp1,fp1 /* if (x == 0.0) */ +- /* x = 0.0; */ +- mtfsf 0xff,fp11 /* Restore previous rounding mode and +- "inexact" state. */ +- blr +-.L4: +- bge- cr6,.L9 /* if (x < 0.0) */ +- fsubs fp1,fp1,fp13 /* x-= TWO23; */ +- fadds fp1,fp1,fp13 /* x+= TWO23; */ +- fnabs fp1,fp1 /* if (x == 0.0) */ +- /* x = -0.0; */ +-.L9: +- mtfsf 0xff,fp11 /* Restore previous rounding mode and +- "inexact" state. */ +- blr +-.L10: +- /* Ensure sNaN input is converted to qNaN. */ +- fcmpu cr7,fp1,fp1 +- beqlr cr7 +- fadds fp1,fp1,fp1 +- blr +- END (__ceilf) +- +-libm_alias_float (__ceil, ceil) +- +diff --git a/sysdeps/powerpc/powerpc32/power4/fpu/multiarch/Makefile b/sysdeps/powerpc/powerpc32/power4/fpu/multiarch/Makefile +index 4e85021d50831eb6..cf38e347f2da74e9 100644 +--- a/sysdeps/powerpc/powerpc32/power4/fpu/multiarch/Makefile ++++ b/sysdeps/powerpc/powerpc32/power4/fpu/multiarch/Makefile +@@ -26,6 +26,8 @@ libm-sysdep_routines += s_llrintf-power6 s_llrintf-ppc32 s_llrint-power6 \ + s_logbf-power7 s_logbf-ppc32 e_hypot-power7 \ + e_hypot-ppc32 e_hypotf-power7 e_hypotf-ppc32 + ++CFLAGS-s_ceil-power5+.c = -mcpu=power5+ ++CFLAGS-s_ceilf-power5+.c = -mcpu=power5+ + CFLAGS-s_modf-power5+.c = -mcpu=power5+ + CFLAGS-s_modff-power5+.c = -mcpu=power5+ + CFLAGS-s_logbl-power7.c = -mcpu=power7 +diff --git a/sysdeps/powerpc/powerpc32/power4/fpu/multiarch/s_ceil-power5+.S b/sysdeps/powerpc/powerpc32/power4/fpu/multiarch/s_ceil-power5+.S +deleted file mode 100644 +index b8181585a869bd8a..0000000000000000 +--- a/sysdeps/powerpc/powerpc32/power4/fpu/multiarch/s_ceil-power5+.S ++++ /dev/null +@@ -1,33 +0,0 @@ +-/* ceil function. PowerPC32/power5+ 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 +- . */ +- +-#include +-#include +- +-#undef hidden_def +-#define hidden_def(name) +-#undef weak_alias +-#define weak_alias(name, alias) +-#undef strong_alias +-#define strong_alias(name, alias) +-#undef compat_symbol +-#define compat_symbol(lib, name, alias, ver) +- +-#define __ceil __ceil_power5plus +- +-#include +diff --git a/sysdeps/powerpc/powerpc32/power4/fpu/multiarch/s_ceil-power5+.c b/sysdeps/powerpc/powerpc32/power4/fpu/multiarch/s_ceil-power5+.c +new file mode 100644 +index 0000000000000000..87bc66cdb0322c59 +--- /dev/null ++++ b/sysdeps/powerpc/powerpc32/power4/fpu/multiarch/s_ceil-power5+.c +@@ -0,0 +1,3 @@ ++#include ++#define __ceil __ceil_power5plus ++#include +diff --git a/sysdeps/powerpc/powerpc32/power4/fpu/multiarch/s_ceil-ppc32.S b/sysdeps/powerpc/powerpc32/power4/fpu/multiarch/s_ceil-ppc32.S +deleted file mode 100644 +index cd2bc69b677e76db..0000000000000000 +--- a/sysdeps/powerpc/powerpc32/power4/fpu/multiarch/s_ceil-ppc32.S ++++ /dev/null +@@ -1,31 +0,0 @@ +-/* ceil function. PowerPC32 default 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 +- . */ +- +-#include +-#include +- +-#undef weak_alias +-#define weak_alias(a,b) +-#undef strong_alias +-#define strong_alias(a,b) +-#undef compat_symbol +-#define compat_symbol(a,b,c,d) +- +-#define __ceil __ceil_ppc32 +- +-#include +diff --git a/sysdeps/powerpc/powerpc32/power4/fpu/multiarch/s_ceil-ppc32.c b/sysdeps/powerpc/powerpc32/power4/fpu/multiarch/s_ceil-ppc32.c +new file mode 100644 +index 0000000000000000..93c098476b915f9d +--- /dev/null ++++ b/sysdeps/powerpc/powerpc32/power4/fpu/multiarch/s_ceil-ppc32.c +@@ -0,0 +1,3 @@ ++#include ++#define __ceil __ceil_ppc32 ++#include +diff --git a/sysdeps/powerpc/powerpc32/power4/fpu/multiarch/s_ceilf-power5+.S b/sysdeps/powerpc/powerpc32/power4/fpu/multiarch/s_ceilf-power5+.S +deleted file mode 100644 +index d01aa6e7db3d0b9d..0000000000000000 +--- a/sysdeps/powerpc/powerpc32/power4/fpu/multiarch/s_ceilf-power5+.S ++++ /dev/null +@@ -1,26 +0,0 @@ +-/* ceilf function. PowerPC32/power5+ 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 +- . */ +- +-#include +- +-#undef weak_alias +-#define weak_alias(name, alias) +- +-#define __ceilf __ceilf_power5plus +- +-#include +diff --git a/sysdeps/powerpc/powerpc32/power4/fpu/multiarch/s_ceilf-power5+.c b/sysdeps/powerpc/powerpc32/power4/fpu/multiarch/s_ceilf-power5+.c +new file mode 100644 +index 0000000000000000..a5bfa98535c088a0 +--- /dev/null ++++ b/sysdeps/powerpc/powerpc32/power4/fpu/multiarch/s_ceilf-power5+.c +@@ -0,0 +1,3 @@ ++#include ++#define __ceilf __ceilf_power5plus ++#include +diff --git a/sysdeps/powerpc/powerpc32/power4/fpu/multiarch/s_ceilf-ppc32.S b/sysdeps/powerpc/powerpc32/power4/fpu/multiarch/s_ceilf-ppc32.S +deleted file mode 100644 +index 264e032b3b27f9b3..0000000000000000 +--- a/sysdeps/powerpc/powerpc32/power4/fpu/multiarch/s_ceilf-ppc32.S ++++ /dev/null +@@ -1,27 +0,0 @@ +-/* ceilf function. PowerPC32 default 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 +- . */ +- +-#include +-#include +- +-#undef weak_alias +-#define weak_alias(a,b) +- +-#define __ceilf __ceilf_ppc32 +- +-#include +diff --git a/sysdeps/powerpc/powerpc32/power4/fpu/multiarch/s_ceilf-ppc32.c b/sysdeps/powerpc/powerpc32/power4/fpu/multiarch/s_ceilf-ppc32.c +new file mode 100644 +index 0000000000000000..a4dcdcb4069289d6 +--- /dev/null ++++ b/sysdeps/powerpc/powerpc32/power4/fpu/multiarch/s_ceilf-ppc32.c +@@ -0,0 +1,3 @@ ++#include ++#define __ceilf __ceilf_ppc32 ++#include +diff --git a/sysdeps/powerpc/powerpc32/power5+/fpu/s_ceil.S b/sysdeps/powerpc/powerpc32/power5+/fpu/s_ceil.S +deleted file mode 100644 +index 356c7a79edf79940..0000000000000000 +--- a/sysdeps/powerpc/powerpc32/power5+/fpu/s_ceil.S ++++ /dev/null +@@ -1,29 +0,0 @@ +-/* ceil function. PowerPC32/power5+ version. +- Copyright (C) 2006-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 +- +- .machine "power5" +-EALIGN (__ceil, 4, 0) +- frip fp1, fp1 +- blr +- END (__ceil) +- +-libm_alias_double (__ceil, ceil) +diff --git a/sysdeps/powerpc/powerpc32/power5+/fpu/s_ceilf.S b/sysdeps/powerpc/powerpc32/power5+/fpu/s_ceilf.S +deleted file mode 100644 +index a0bcda17fde0c0f6..0000000000000000 +--- a/sysdeps/powerpc/powerpc32/power5+/fpu/s_ceilf.S ++++ /dev/null +@@ -1,30 +0,0 @@ +-/* ceilf function. PowerPC32/power5+ version. +- Copyright (C) 2006-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 +- +- .machine "power5" +-EALIGN (__ceilf, 4, 0) +- frip fp1, fp1 /* The rounding instructions are double. */ +- frsp fp1, fp1 /* But we need to set ooverflow for float. */ +- blr +- END (__ceilf) +- +-libm_alias_float (__ceil, ceil) +- +diff --git a/sysdeps/powerpc/powerpc64/be/fpu/multiarch/Makefile b/sysdeps/powerpc/powerpc64/be/fpu/multiarch/Makefile +new file mode 100644 +index 0000000000000000..932c3c7e6c6ad27e +--- /dev/null ++++ b/sysdeps/powerpc/powerpc64/be/fpu/multiarch/Makefile +@@ -0,0 +1,9 @@ ++ifeq ($(subdir),math) ++libm-sysdep_routines += s_ceil-power5+ \ ++ s_ceil-ppc64 \ ++ s_ceilf-power5+ \ ++ s_ceilf-ppc64 ++ ++CFLAGS-s_ceil-power5+.c = -mcpu=power5+ ++CFLAGS-s_ceilf-power5+.c = -mcpu=power5+ ++endif +diff --git a/sysdeps/powerpc/powerpc64/be/fpu/multiarch/s_ceil-power5+.c b/sysdeps/powerpc/powerpc64/be/fpu/multiarch/s_ceil-power5+.c +new file mode 100644 +index 0000000000000000..87bc66cdb0322c59 +--- /dev/null ++++ b/sysdeps/powerpc/powerpc64/be/fpu/multiarch/s_ceil-power5+.c +@@ -0,0 +1,3 @@ ++#include ++#define __ceil __ceil_power5plus ++#include +diff --git a/sysdeps/powerpc/powerpc64/be/fpu/multiarch/s_ceil-ppc64.c b/sysdeps/powerpc/powerpc64/be/fpu/multiarch/s_ceil-ppc64.c +new file mode 100644 +index 0000000000000000..8711ff3229467026 +--- /dev/null ++++ b/sysdeps/powerpc/powerpc64/be/fpu/multiarch/s_ceil-ppc64.c +@@ -0,0 +1,3 @@ ++#include ++#define __ceil __ceil_ppc64 ++#include +diff --git a/sysdeps/powerpc/powerpc64/fpu/multiarch/s_ceil.c b/sysdeps/powerpc/powerpc64/be/fpu/multiarch/s_ceil.c +similarity index 95% +rename from sysdeps/powerpc/powerpc64/fpu/multiarch/s_ceil.c +rename to sysdeps/powerpc/powerpc64/be/fpu/multiarch/s_ceil.c +index 5cde4eb46f26ec82..1abca7ef63d6a852 100644 +--- a/sysdeps/powerpc/powerpc64/fpu/multiarch/s_ceil.c ++++ b/sysdeps/powerpc/powerpc64/be/fpu/multiarch/s_ceil.c +@@ -17,10 +17,8 @@ + . */ + + #include +-#include +-#include +-#include "init-arch.h" + #include ++#include "init-arch.h" + + extern __typeof (__ceil) __ceil_ppc64 attribute_hidden; + extern __typeof (__ceil) __ceil_power5plus attribute_hidden; +diff --git a/sysdeps/powerpc/powerpc64/be/fpu/multiarch/s_ceilf-power5+.c b/sysdeps/powerpc/powerpc64/be/fpu/multiarch/s_ceilf-power5+.c +new file mode 100644 +index 0000000000000000..a5bfa98535c088a0 +--- /dev/null ++++ b/sysdeps/powerpc/powerpc64/be/fpu/multiarch/s_ceilf-power5+.c +@@ -0,0 +1,3 @@ ++#include ++#define __ceilf __ceilf_power5plus ++#include +diff --git a/sysdeps/powerpc/powerpc64/be/fpu/multiarch/s_ceilf-ppc64.c b/sysdeps/powerpc/powerpc64/be/fpu/multiarch/s_ceilf-ppc64.c +new file mode 100644 +index 0000000000000000..086251dc0937acfa +--- /dev/null ++++ b/sysdeps/powerpc/powerpc64/be/fpu/multiarch/s_ceilf-ppc64.c +@@ -0,0 +1,3 @@ ++#include ++#define __ceilf __ceilf_ppc64 ++#include +diff --git a/sysdeps/powerpc/powerpc64/fpu/multiarch/s_ceilf.c b/sysdeps/powerpc/powerpc64/be/fpu/multiarch/s_ceilf.c +similarity index 95% +rename from sysdeps/powerpc/powerpc64/fpu/multiarch/s_ceilf.c +rename to sysdeps/powerpc/powerpc64/be/fpu/multiarch/s_ceilf.c +index 18697e52b3ac1616..33245968a86ddcf5 100644 +--- a/sysdeps/powerpc/powerpc64/fpu/multiarch/s_ceilf.c ++++ b/sysdeps/powerpc/powerpc64/be/fpu/multiarch/s_ceilf.c +@@ -17,10 +17,8 @@ + . */ + + #include +-#include +-#include +-#include "init-arch.h" + #include ++#include "init-arch.h" + + extern __typeof (__ceilf) __ceilf_ppc64 attribute_hidden; + extern __typeof (__ceilf) __ceilf_power5plus attribute_hidden; +diff --git a/sysdeps/powerpc/powerpc64/fpu/multiarch/Makefile b/sysdeps/powerpc/powerpc64/fpu/multiarch/Makefile +index 73f2f693771027a9..2805e4e0d66f3175 100644 +--- a/sysdeps/powerpc/powerpc64/fpu/multiarch/Makefile ++++ b/sysdeps/powerpc/powerpc64/fpu/multiarch/Makefile +@@ -14,8 +14,7 @@ sysdep_calls := s_copysign-power6 s_copysign-ppc64 \ + + sysdep_routines += $(sysdep_calls) + libm-sysdep_routines += s_llround-power6x \ +- s_llround-power5+ s_llround-ppc64 s_ceil-power5+ \ +- s_ceil-ppc64 s_ceilf-power5+ s_ceilf-ppc64 \ ++ s_llround-power5+ s_llround-ppc64 \ + s_floor-power5+ s_floor-ppc64 s_floorf-power5+ \ + s_floorf-ppc64 s_round-power5+ s_round-ppc64 \ + s_roundf-power5+ s_roundf-ppc64 s_trunc-power5+ \ +diff --git a/sysdeps/powerpc/powerpc64/fpu/multiarch/s_ceil-power5+.S b/sysdeps/powerpc/powerpc64/fpu/multiarch/s_ceil-power5+.S +deleted file mode 100644 +index 76651b694c251bb4..0000000000000000 +--- a/sysdeps/powerpc/powerpc64/fpu/multiarch/s_ceil-power5+.S ++++ /dev/null +@@ -1,30 +0,0 @@ +-/* ceil function. PowerPC64/power5+ 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 +- . */ +- +-#include +- +-#undef weak_alias +-#define weak_alias(a,b) +-#undef strong_alias +-#define strong_alias(a,b) +-#undef compat_symbol +-#define compat_symbol(a,b,c,d) +- +-#define __ceil __ceil_power5plus +- +-#include +diff --git a/sysdeps/powerpc/powerpc64/fpu/multiarch/s_ceil-ppc64.S b/sysdeps/powerpc/powerpc64/fpu/multiarch/s_ceil-ppc64.S +deleted file mode 100644 +index c75c66ba3bbf49c8..0000000000000000 +--- a/sysdeps/powerpc/powerpc64/fpu/multiarch/s_ceil-ppc64.S ++++ /dev/null +@@ -1,30 +0,0 @@ +-/* ceil function. PowerPC64 default 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 +- . */ +- +-#include +- +-#undef weak_alias +-#define weak_alias(a,b) +-#undef strong_alias +-#define strong_alias(a,b) +-#undef compat_symbol +-#define compat_symbol(a,b,c,d) +- +-#define __ceil __ceil_ppc64 +- +-#include +diff --git a/sysdeps/powerpc/powerpc64/fpu/multiarch/s_ceilf-power5+.S b/sysdeps/powerpc/powerpc64/fpu/multiarch/s_ceilf-power5+.S +deleted file mode 100644 +index b9c9e14fba6ee134..0000000000000000 +--- a/sysdeps/powerpc/powerpc64/fpu/multiarch/s_ceilf-power5+.S ++++ /dev/null +@@ -1,24 +0,0 @@ +-/* ceilf function. PowerPC64/power5+ 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 +- . */ +- +-#undef weak_alias +-#define weak_alias(a,b) +- +-#define __ceilf __ceilf_power5plus +- +-#include +diff --git a/sysdeps/powerpc/powerpc64/fpu/multiarch/s_ceilf-ppc64.S b/sysdeps/powerpc/powerpc64/fpu/multiarch/s_ceilf-ppc64.S +deleted file mode 100644 +index ce5cc49770fdfdee..0000000000000000 +--- a/sysdeps/powerpc/powerpc64/fpu/multiarch/s_ceilf-ppc64.S ++++ /dev/null +@@ -1,24 +0,0 @@ +-/* ceilf function. PowerPC64 default 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 +- . */ +- +-#undef weak_alias +-#define weak_alias(a,b) +- +-#define __ceilf __ceilf_ppc64 +- +-#include +diff --git a/sysdeps/powerpc/powerpc64/fpu/s_ceil.S b/sysdeps/powerpc/powerpc64/fpu/s_ceil.S +deleted file mode 100644 +index 252d94f51ea1a167..0000000000000000 +--- a/sysdeps/powerpc/powerpc64/fpu/s_ceil.S ++++ /dev/null +@@ -1,65 +0,0 @@ +-/* ceil function. PowerPC64 version. +- 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 +-#include +- +- .section ".toc","aw" +-.LC0: /* 2**52 */ +- .tc FD_43300000_0[TC],0x4330000000000000 +- .section ".text" +- +-ENTRY (__ceil, 4) +- CALL_MCOUNT 0 +- lfd fp13,.LC0@toc(2) +- fabs fp0,fp1 +- fsub fp12,fp13,fp13 /* generate 0.0 */ +- fcmpu cr7,fp0,fp13 /* if (fabs(x) > TWO52) */ +- mffs fp11 /* Save current FPU rounding mode and +- "inexact" state. */ +- fcmpu cr6,fp1,fp12 /* if (x > 0.0) */ +- bnl- cr7,.L10 +- mtfsfi 7,2 /* Set rounding mode toward +inf. */ +- ble- cr6,.L4 +- fadd fp1,fp1,fp13 /* x+= TWO52; */ +- fsub fp1,fp1,fp13 /* x-= TWO52; */ +- fabs fp1,fp1 /* if (x == 0.0) */ +- /* x = 0.0; */ +- mtfsf 0xff,fp11 /* Restore previous rounding mode and +- "inexact" state. */ +- blr +-.L4: +- bge- cr6,.L9 /* if (x < 0.0) */ +- fsub fp1,fp1,fp13 /* x-= TWO52; */ +- fadd fp1,fp1,fp13 /* x+= TWO52; */ +- fnabs fp1,fp1 /* if (x == 0.0) */ +- /* x = -0.0; */ +-.L9: +- mtfsf 0xff,fp11 /* Restore previous rounding mode and +- "inexact" state. */ +- blr +-.L10: +- /* Ensure sNaN input is converted to qNaN. */ +- fcmpu cr7,fp1,fp1 +- beqlr cr7 +- fadd fp1,fp1,fp1 +- blr +- END (__ceil) +- +-libm_alias_double (__ceil, ceil) +diff --git a/sysdeps/powerpc/powerpc64/fpu/s_ceilf.S b/sysdeps/powerpc/powerpc64/fpu/s_ceilf.S +deleted file mode 100644 +index 3c62077c143eeced..0000000000000000 +--- a/sysdeps/powerpc/powerpc64/fpu/s_ceilf.S ++++ /dev/null +@@ -1,67 +0,0 @@ +-/* float ceil function. PowerPC64 version. +- 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 +- +- .section ".toc","aw" +- .p2align 3 +-.LC0: /* 2**23 */ +- .long 0x4b000000 +- .long 0x0 +- .section ".text" +- +-ENTRY (__ceilf, 4) +- CALL_MCOUNT 0 +- lfs fp13,.LC0@toc(2) +- fabs fp0,fp1 +- fsubs fp12,fp13,fp13 /* generate 0.0 */ +- fcmpu cr7,fp0,fp13 /* if (fabs(x) > TWO23) */ +- mffs fp11 /* Save current FPU rounding mode and +- "inexact" state. */ +- fcmpu cr6,fp1,fp12 /* if (x > 0.0) */ +- bnl- cr7,.L10 +- mtfsfi 7,2 /* Set rounding mode toward +inf. */ +- ble- cr6,.L4 +- fadds fp1,fp1,fp13 /* x+= TWO23; */ +- fsubs fp1,fp1,fp13 /* x-= TWO23; */ +- fabs fp1,fp1 /* if (x == 0.0) */ +- /* x = 0.0; */ +- mtfsf 0xff,fp11 /* Restore previous rounding mode and +- "inexact" state. */ +- blr +-.L4: +- bge- cr6,.L9 /* if (x < 0.0) */ +- fsubs fp1,fp1,fp13 /* x-= TWO23; */ +- fadds fp1,fp1,fp13 /* x+= TWO23; */ +- fnabs fp1,fp1 /* if (x == 0.0) */ +- /* x = -0.0; */ +-.L9: +- mtfsf 0xff,fp11 /* Restore previous rounding mode and +- "inexact" state. */ +- blr +-.L10: +- /* Ensure sNaN input is converted to qNaN. */ +- fcmpu cr7,fp1,fp1 +- beqlr cr7 +- fadds fp1,fp1,fp1 +- blr +- END (__ceilf) +- +-libm_alias_float (__ceil, ceil) +- +diff --git a/sysdeps/powerpc/powerpc64/power5+/fpu/s_ceil.S b/sysdeps/powerpc/powerpc64/power5+/fpu/s_ceil.S +deleted file mode 100644 +index e500932573c07503..0000000000000000 +--- a/sysdeps/powerpc/powerpc64/power5+/fpu/s_ceil.S ++++ /dev/null +@@ -1,30 +0,0 @@ +-/* ceil function. PowerPC64/power5+ version. +- Copyright (C) 2006-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 +- +- .machine "power5" +-ENTRY_TOCLESS (__ceil, 4) +- CALL_MCOUNT 0 +- frip fp1, fp1 +- blr +- END (__ceil) +- +-libm_alias_double (__ceil, ceil) +diff --git a/sysdeps/powerpc/powerpc64/power5+/fpu/s_ceilf.S b/sysdeps/powerpc/powerpc64/power5+/fpu/s_ceilf.S +deleted file mode 100644 +index d0b2118c2a3f81be..0000000000000000 +--- a/sysdeps/powerpc/powerpc64/power5+/fpu/s_ceilf.S ++++ /dev/null +@@ -1,31 +0,0 @@ +-/* ceilf function. PowerPC64/power5+ version. +- Copyright (C) 2006-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 +- +- .machine "power5" +-ENTRY_TOCLESS (__ceilf, 4) +- CALL_MCOUNT 0 +- frip fp1, fp1 /* The rounding instructions are double. */ +- frsp fp1, fp1 /* But we need to set ooverflow for float. */ +- blr +- END (__ceilf) +- +-libm_alias_float (__ceil, ceil) +- diff --git a/SOURCES/glibc-rh1783303-10.patch b/SOURCES/glibc-rh1783303-10.patch new file mode 100644 index 0000000..33663f6 --- /dev/null +++ b/SOURCES/glibc-rh1783303-10.patch @@ -0,0 +1,57 @@ +commit 0b3c9e57a41d9f7c26fb6aa45b99f671bef9c7e0 +Author: Paul A. Clarke +Date: Tue Aug 20 15:57:35 2019 -0500 + + [powerpc] fegetenv_status: simplify instruction generation + + fegetenv_status() wants to use the lighter weight instruction 'mffsl' + for reading the Floating-Point Status and Control Register (FPSCR). + It currently will use it directly if compiled '-mcpu=power9', and will + perform a runtime check (cpu_supports("arch_3_00")) otherwise. + + Nicely, it turns out that the 'mffsl' instruction will decode to + 'mffs' on architectures older than "arch_3_00" because the additional + bits set for 'mffsl' are "don't care" for 'mffs'. 'mffs' is a superset + of 'mffsl'. + + So, just generate 'mffsl'. + +diff --git a/sysdeps/powerpc/fpu/fenv_libc.h b/sysdeps/powerpc/fpu/fenv_libc.h +index b244770d115ea7bb..e8d40ea256b6c5bc 100644 +--- a/sysdeps/powerpc/fpu/fenv_libc.h ++++ b/sysdeps/powerpc/fpu/fenv_libc.h +@@ -36,9 +36,12 @@ extern const fenv_t *__fe_mask_env (void) attribute_hidden; + ({ fenv_t env; asm volatile ("mffs %0" : "=f" (env)); env; }) + + /* Equivalent to fegetenv_register, but only returns bits for +- status, exception enables, and mode. */ +- +-#define fegetenv_status_ISA300() \ ++ status, exception enables, and mode. ++ Nicely, it turns out that the 'mffsl' instruction will decode to ++ 'mffs' on architectures older than "power9" because the additional ++ bits set for 'mffsl' are "don't care" for 'mffs'. 'mffs' is a superset ++ of 'mffsl'. */ ++#define fegetenv_status() \ + ({register double __fr; \ + __asm__ __volatile__ ( \ + ".machine push; .machine \"power9\"; mffsl %0; .machine pop" \ +@@ -46,18 +49,6 @@ extern const fenv_t *__fe_mask_env (void) attribute_hidden; + __fr; \ + }) + +-#ifdef _ARCH_PWR9 +-# define fegetenv_status() fegetenv_status_ISA300() +-#elif defined __BUILTIN_CPU_SUPPORTS__ +-# define fegetenv_status() \ +- (__glibc_likely (__builtin_cpu_supports ("arch_3_00")) \ +- ? fegetenv_status_ISA300() \ +- : fegetenv_register() \ +- ) +-#else +-# define fegetenv_status() fegetenv_register () +-#endif +- + /* Equivalent to fesetenv, but takes a fenv_t instead of a pointer. */ + #define fesetenv_register(env) \ + do { \ diff --git a/SOURCES/glibc-rh1783303-11.patch b/SOURCES/glibc-rh1783303-11.patch new file mode 100644 index 0000000..2af4f13 --- /dev/null +++ b/SOURCES/glibc-rh1783303-11.patch @@ -0,0 +1,128 @@ +commit f1c56cdff09f650ad721fae026eb6a3651631f3d +Author: Paul A. Clarke +Date: Thu Sep 19 08:35:16 2019 -0500 + + [powerpc] SET_RESTORE_ROUND optimizations and bug fix + + SET_RESTORE_ROUND brackets a block of code, temporarily setting and + restoring the rounding mode and letting everything else, including + exceptions generated within the block, pass through. + + On powerpc, the current code clears the exception enables, which will hide + exceptions generated within the block. This issue was introduced by me + in commit e905212627350d54b58426214b5a54ddc852b0c9. + + Fix this by not clearing exception enable bits in the prologue. + + Also, since we are no longer changing the enable bits in either the + prologue or the epilogue, there is no need to test for entering/exiting + non-stop mode. + + Also, optimize the prologue get/save/set rounding mode operations for + POWER9 and later by using 'mffscrn' when possible. + + Suggested-by: Paul E. Murphy + Reviewed-by: Paul E. Murphy + Fixes: e905212627350d54b58426214b5a54ddc852b0c9 + + 2019-09-19 Paul A. Clarke + + * sysdeps/powerpc/fpu/fenv_libc.h (fegetenv_and_set_rn): New. + (__fe_mffscrn): New. + * sysdeps/powerpc/fpu/fenv_private.h (libc_feholdsetround_ppc_ctx): + Do not clear enable bits, remove obsolete code, use + fegetenv_and_set_rn. + (libc_feresetround_ppc): Remove obsolete code, use + fegetenv_and_set_rn. + +diff --git a/sysdeps/powerpc/fpu/fenv_libc.h b/sysdeps/powerpc/fpu/fenv_libc.h +index e8d40ea256b6c5bc..b10b6a141ded4bfd 100644 +--- a/sysdeps/powerpc/fpu/fenv_libc.h ++++ b/sysdeps/powerpc/fpu/fenv_libc.h +@@ -49,6 +49,38 @@ extern const fenv_t *__fe_mask_env (void) attribute_hidden; + __fr; \ + }) + ++#define __fe_mffscrn(rn) \ ++ ({register fenv_union_t __fr; \ ++ if (__builtin_constant_p (rn)) \ ++ __asm__ __volatile__ ( \ ++ ".machine push; .machine \"power9\"; mffscrni %0,%1; .machine pop" \ ++ : "=f" (__fr.fenv) : "i" (rn)); \ ++ else \ ++ { \ ++ __fr.l = (rn); \ ++ __asm__ __volatile__ ( \ ++ ".machine push; .machine \"power9\"; mffscrn %0,%1; .machine pop" \ ++ : "=f" (__fr.fenv) : "f" (__fr.fenv)); \ ++ } \ ++ __fr.fenv; \ ++ }) ++ ++/* Like fegetenv_status, but also sets the rounding mode. */ ++#ifdef _ARCH_PWR9 ++#define fegetenv_and_set_rn(rn) __fe_mffscrn (rn) ++#else ++/* 'mffscrn' will decode to 'mffs' on ARCH < 3_00, which is still necessary ++ but not sufficient, because it does not set the rounding mode. ++ Explicitly set the rounding mode when 'mffscrn' actually doesn't. */ ++#define fegetenv_and_set_rn(rn) \ ++ ({register fenv_union_t __fr; \ ++ __fr.fenv = __fe_mffscrn (rn); \ ++ if (__glibc_unlikely (!(GLRO(dl_hwcap2) & PPC_FEATURE2_ARCH_3_00))) \ ++ __fesetround_inline (rn); \ ++ __fr.fenv; \ ++ }) ++#endif ++ + /* Equivalent to fesetenv, but takes a fenv_t instead of a pointer. */ + #define fesetenv_register(env) \ + do { \ +diff --git a/sysdeps/powerpc/fpu/fenv_private.h b/sysdeps/powerpc/fpu/fenv_private.h +index b0149aa243e69f5a..30df92c9a4700dee 100644 +--- a/sysdeps/powerpc/fpu/fenv_private.h ++++ b/sysdeps/powerpc/fpu/fenv_private.h +@@ -133,16 +133,7 @@ static __always_inline void + libc_feresetround_ppc (fenv_t *envp) + { + fenv_union_t new = { .fenv = *envp }; +- +- /* If the old env has no enabled exceptions and the new env has any enabled +- exceptions, then unmask SIGFPE in the MSR FE0/FE1 bits. This will put the +- hardware into "precise mode" and may cause the FPU to run slower on some +- hardware. */ +- if ((new.l & _FPU_ALL_TRAPS) != 0) +- (void) __fe_nomask_env_priv (); +- +- /* Atomically enable and raise (if appropriate) exceptions set in `new'. */ +- fesetenv_mode (new.fenv); ++ fegetenv_and_set_rn (new.l & FPSCR_RN_MASK); + } + + static __always_inline int +@@ -184,22 +175,10 @@ libc_feupdateenv_ppc (fenv_t *e) + static __always_inline void + libc_feholdsetround_ppc_ctx (struct rm_ctx *ctx, int r) + { +- fenv_union_t old, new; ++ fenv_union_t old; + +- old.fenv = fegetenv_status (); +- +- new.l = (old.l & ~(FPSCR_ENABLES_MASK|FPSCR_RN_MASK)) | r; +- +- ctx->env = old.fenv; +- if (__glibc_unlikely (new.l != old.l)) +- { +- if ((old.l & _FPU_ALL_TRAPS) != 0) +- (void) __fe_mask_env (); +- fesetenv_mode (new.fenv); +- ctx->updated_status = true; +- } +- else +- ctx->updated_status = false; ++ ctx->env = old.fenv = fegetenv_and_set_rn (r); ++ ctx->updated_status = (r != (old.l & FPSCR_RN_MASK)); + } + + static __always_inline void diff --git a/SOURCES/glibc-rh1783303-12.patch b/SOURCES/glibc-rh1783303-12.patch new file mode 100644 index 0000000..5113469 --- /dev/null +++ b/SOURCES/glibc-rh1783303-12.patch @@ -0,0 +1,303 @@ +commit e3d85df50b083c9ba68a40f5d45b201cbec4e68b +Author: Paul A. Clarke +Date: Thu Sep 19 09:13:14 2019 -0500 + + [powerpc] fenv_private.h clean up + + fenv_private.h includes unused functions, magic macro constants, and + some replicated common code fragments. + + Remove unused functions, replace magic constants with constants from + fenv_libc.h, and refactor replicated code. + + Suggested-by: Paul E. Murphy + Reviewed-By: Paul E Murphy + +diff --git a/sysdeps/powerpc/fpu/fedisblxcpt.c b/sysdeps/powerpc/fpu/fedisblxcpt.c +index 2a776c72fb5a2b70..bdf55ac62f1ffe4f 100644 +--- a/sysdeps/powerpc/fpu/fedisblxcpt.c ++++ b/sysdeps/powerpc/fpu/fedisblxcpt.c +@@ -43,8 +43,7 @@ fedisableexcept (int excepts) + if (fe.l != curr.l) + fesetenv_mode (fe.fenv); + +- if (new == 0 && result != 0) +- (void)__fe_mask_env (); ++ __TEST_AND_ENTER_NON_STOP (-1ULL, fe.l); + + return result; + } +diff --git a/sysdeps/powerpc/fpu/feenablxcpt.c b/sysdeps/powerpc/fpu/feenablxcpt.c +index 6f5a828e80965bfa..78ebabed9232c0ad 100644 +--- a/sysdeps/powerpc/fpu/feenablxcpt.c ++++ b/sysdeps/powerpc/fpu/feenablxcpt.c +@@ -43,8 +43,7 @@ feenableexcept (int excepts) + if (fe.l != curr.l) + fesetenv_mode (fe.fenv); + +- if (new != 0 && result == 0) +- (void) __fe_nomask_env_priv (); ++ __TEST_AND_EXIT_NON_STOP (0ULL, fe.l); + + return result; + } +diff --git a/sysdeps/powerpc/fpu/feholdexcpt.c b/sysdeps/powerpc/fpu/feholdexcpt.c +index 8ec3fbff82b22f51..9636ecaa0b600b0d 100644 +--- a/sysdeps/powerpc/fpu/feholdexcpt.c ++++ b/sysdeps/powerpc/fpu/feholdexcpt.c +@@ -18,7 +18,6 @@ + + #include + #include +-#define _FPU_MASK_ALL (_FPU_MASK_ZM | _FPU_MASK_OM | _FPU_MASK_UM | _FPU_MASK_XM | _FPU_MASK_IM) + + int + __feholdexcept (fenv_t *envp) +@@ -35,11 +34,7 @@ __feholdexcept (fenv_t *envp) + if (new.l == old.l) + return 0; + +- /* If the old env had any enabled exceptions, then mask SIGFPE in the +- MSR FE0/FE1 bits. This may allow the FPU to run faster because it +- always takes the default action and can not generate SIGFPE. */ +- if ((old.l & _FPU_MASK_ALL) != 0) +- (void)__fe_mask_env (); ++ __TEST_AND_ENTER_NON_STOP (old.l, 0ULL); + + /* Put the new state in effect. */ + fesetenv_register (new.fenv); +diff --git a/sysdeps/powerpc/fpu/fenv_libc.h b/sysdeps/powerpc/fpu/fenv_libc.h +index b10b6a141ded4bfd..36b639c3939586f6 100644 +--- a/sysdeps/powerpc/fpu/fenv_libc.h ++++ b/sysdeps/powerpc/fpu/fenv_libc.h +@@ -27,6 +27,26 @@ extern const fenv_t *__fe_nomask_env_priv (void); + + extern const fenv_t *__fe_mask_env (void) attribute_hidden; + ++/* If the old env had any enabled exceptions and the new env has no enabled ++ exceptions, then mask SIGFPE in the MSR FE0/FE1 bits. This may allow the ++ FPU to run faster because it always takes the default action and can not ++ generate SIGFPE. */ ++#define __TEST_AND_ENTER_NON_STOP(old, new) \ ++ do { \ ++ if (((old) & FPSCR_ENABLES_MASK) != 0 && ((new) & FPSCR_ENABLES_MASK) == 0) \ ++ (void) __fe_mask_env (); \ ++ } while (0) ++ ++/* If the old env has no enabled exceptions and the new env has any enabled ++ exceptions, then unmask SIGFPE in the MSR FE0/FE1 bits. This will put the ++ hardware into "precise mode" and may cause the FPU to run slower on some ++ hardware. */ ++#define __TEST_AND_EXIT_NON_STOP(old, new) \ ++ do { \ ++ if (((old) & FPSCR_ENABLES_MASK) == 0 && ((new) & FPSCR_ENABLES_MASK) != 0) \ ++ (void) __fe_nomask_env_priv (); \ ++ } while (0) ++ + /* The sticky bits in the FPSCR indicating exceptions have occurred. */ + #define FPSCR_STICKY_BITS ((FE_ALL_EXCEPT | FE_ALL_INVALID) & ~FE_INVALID) + +diff --git a/sysdeps/powerpc/fpu/fenv_private.h b/sysdeps/powerpc/fpu/fenv_private.h +index 30df92c9a4700dee..c236d45db2f399a4 100644 +--- a/sysdeps/powerpc/fpu/fenv_private.h ++++ b/sysdeps/powerpc/fpu/fenv_private.h +@@ -23,73 +23,20 @@ + #include + #include + +-/* Mask for the exception enable bits. */ +-#define _FPU_ALL_TRAPS (_FPU_MASK_ZM | _FPU_MASK_OM | _FPU_MASK_UM \ +- | _FPU_MASK_XM | _FPU_MASK_IM) +- +-/* Mask the rounding mode bits. */ +-#define _FPU_MASK_RN 0xfffffffffffffffcLL +- +-/* Mask everything but the rounding modes and non-IEEE arithmetic flags. */ +-#define _FPU_MASK_NOT_RN_NI 0xffffffff00000807LL +- +-/* Mask restore rounding mode and exception enabled. */ +-#define _FPU_MASK_TRAPS_RN 0xffffffffffffff00LL +- +-/* Mask FP result flags, preserve fraction rounded/inexact bits. */ +-#define _FPU_MASK_FRAC_INEX_RET_CC 0xfffffffffff80fffLL +- + static __always_inline void +-__libc_feholdbits_ppc (fenv_t *envp, unsigned long long mask, +- unsigned long long bits) ++libc_feholdexcept_setround_ppc (fenv_t *envp, int r) + { + fenv_union_t old, new; + + old.fenv = *envp = fegetenv_register (); + +- new.l = (old.l & mask) | bits; +- +- /* If the old env had any enabled exceptions, then mask SIGFPE in the +- MSR FE0/FE1 bits. This may allow the FPU to run faster because it +- always takes the default action and can not generate SIGFPE. */ +- if ((old.l & _FPU_ALL_TRAPS) != 0) +- (void) __fe_mask_env (); ++ __TEST_AND_ENTER_NON_STOP (old.l, 0ULL); + ++ /* Clear everything and set the rounding mode. */ ++ new.l = r; + fesetenv_register (new.fenv); + } + +-static __always_inline void +-libc_feholdexcept_ppc (fenv_t *envp) +-{ +- __libc_feholdbits_ppc (envp, _FPU_MASK_NOT_RN_NI, 0LL); +-} +- +-static __always_inline void +-libc_feholdexcept_setround_ppc (fenv_t *envp, int r) +-{ +- __libc_feholdbits_ppc (envp, _FPU_MASK_NOT_RN_NI & _FPU_MASK_RN, r); +-} +- +-static __always_inline void +-libc_fesetround_ppc (int r) +-{ +- __fesetround_inline (r); +-} +- +-static __always_inline int +-libc_fetestexcept_ppc (int e) +-{ +- fenv_union_t u; +- u.fenv = fegetenv_register (); +- return u.l & e; +-} +- +-static __always_inline void +-libc_feholdsetround_ppc (fenv_t *e, int r) +-{ +- __libc_feholdbits_ppc (e, _FPU_MASK_TRAPS_RN, r); +-} +- + static __always_inline unsigned long long + __libc_femergeenv_ppc (const fenv_t *envp, unsigned long long old_mask, + unsigned long long new_mask) +@@ -102,19 +49,8 @@ __libc_femergeenv_ppc (const fenv_t *envp, unsigned long long old_mask, + /* Merge bits while masking unwanted bits from new and old env. */ + new.l = (old.l & old_mask) | (new.l & new_mask); + +- /* If the old env has no enabled exceptions and the new env has any enabled +- exceptions, then unmask SIGFPE in the MSR FE0/FE1 bits. This will put the +- hardware into "precise mode" and may cause the FPU to run slower on some +- hardware. */ +- if ((old.l & _FPU_ALL_TRAPS) == 0 && (new.l & _FPU_ALL_TRAPS) != 0) +- (void) __fe_nomask_env_priv (); +- +- /* If the old env had any enabled exceptions and the new env has no enabled +- exceptions, then mask SIGFPE in the MSR FE0/FE1 bits. This may allow the +- FPU to run faster because it always takes the default action and can not +- generate SIGFPE. */ +- if ((old.l & _FPU_ALL_TRAPS) != 0 && (new.l & _FPU_ALL_TRAPS) == 0) +- (void) __fe_mask_env (); ++ __TEST_AND_EXIT_NON_STOP (old.l, new.l); ++ __TEST_AND_ENTER_NON_STOP (old.l, new.l); + + /* Atomically enable and raise (if appropriate) exceptions set in `new'. */ + fesetenv_register (new.fenv); +@@ -139,8 +75,8 @@ libc_feresetround_ppc (fenv_t *envp) + static __always_inline int + libc_feupdateenv_test_ppc (fenv_t *envp, int ex) + { +- return __libc_femergeenv_ppc (envp, _FPU_MASK_TRAPS_RN, +- _FPU_MASK_FRAC_INEX_RET_CC) & ex; ++ return __libc_femergeenv_ppc (envp, ~FPSCR_CONTROL_MASK, ++ ~FPSCR_STATUS_MASK) & ex; + } + + static __always_inline void +@@ -193,8 +129,7 @@ libc_feholdsetround_noex_ppc_ctx (struct rm_ctx *ctx, int r) + ctx->env = old.fenv; + if (__glibc_unlikely (new.l != old.l)) + { +- if ((old.l & _FPU_ALL_TRAPS) != 0) +- (void) __fe_mask_env (); ++ __TEST_AND_ENTER_NON_STOP (old.l, 0ULL); + fesetenv_register (new.fenv); + ctx->updated_status = true; + } +diff --git a/sysdeps/powerpc/fpu/fesetenv.c b/sysdeps/powerpc/fpu/fesetenv.c +index ac927c8f3ada40b4..4eab5045c48105e3 100644 +--- a/sysdeps/powerpc/fpu/fesetenv.c ++++ b/sysdeps/powerpc/fpu/fesetenv.c +@@ -28,19 +28,8 @@ __fesetenv (const fenv_t *envp) + new.fenv = *envp; + old.fenv = fegetenv_status (); + +- /* If the old env has no enabled exceptions and the new env has any enabled +- exceptions, then unmask SIGFPE in the MSR FE0/FE1 bits. This will put the +- hardware into "precise mode" and may cause the FPU to run slower on some +- hardware. */ +- if ((old.l & FPSCR_ENABLES_MASK) == 0 && (new.l & FPSCR_ENABLES_MASK) != 0) +- (void) __fe_nomask_env_priv (); +- +- /* If the old env had any enabled exceptions and the new env has no enabled +- exceptions, then mask SIGFPE in the MSR FE0/FE1 bits. This may allow the +- FPU to run faster because it always takes the default action and can not +- generate SIGFPE. */ +- if ((old.l & FPSCR_ENABLES_MASK) != 0 && (new.l & FPSCR_ENABLES_MASK) == 0) +- (void)__fe_mask_env (); ++ __TEST_AND_EXIT_NON_STOP (old.l, new.l); ++ __TEST_AND_ENTER_NON_STOP (old.l, new.l); + + fesetenv_register (new.fenv); + +diff --git a/sysdeps/powerpc/fpu/fesetmode.c b/sysdeps/powerpc/fpu/fesetmode.c +index 29e088d5ab1c0d93..58ba02c0a1e64c27 100644 +--- a/sysdeps/powerpc/fpu/fesetmode.c ++++ b/sysdeps/powerpc/fpu/fesetmode.c +@@ -33,11 +33,8 @@ fesetmode (const femode_t *modep) + if (old.l == new.l) + return 0; + +- if ((old.l & FPSCR_ENABLES_MASK) == 0 && (new.l & FPSCR_ENABLES_MASK) != 0) +- (void) __fe_nomask_env_priv (); +- +- if ((old.l & FPSCR_ENABLES_MASK) != 0 && (new.l & FPSCR_ENABLES_MASK) == 0) +- (void) __fe_mask_env (); ++ __TEST_AND_EXIT_NON_STOP (old.l, new.l); ++ __TEST_AND_ENTER_NON_STOP (old.l, new.l); + + fesetenv_mode (new.fenv); + return 0; +diff --git a/sysdeps/powerpc/fpu/feupdateenv.c b/sysdeps/powerpc/fpu/feupdateenv.c +index 2dbd1c4e9ec65ed0..fdd15651e0101f9e 100644 +--- a/sysdeps/powerpc/fpu/feupdateenv.c ++++ b/sysdeps/powerpc/fpu/feupdateenv.c +@@ -20,8 +20,6 @@ + #include + #include + +-#define _FPU_MASK_ALL (_FPU_MASK_ZM | _FPU_MASK_OM | _FPU_MASK_UM | _FPU_MASK_XM | _FPU_MASK_IM) +- + int + __feupdateenv (const fenv_t *envp) + { +@@ -36,19 +34,8 @@ __feupdateenv (const fenv_t *envp) + unchanged. */ + new.l = (old.l & 0xffffffff1fffff00LL) | (new.l & 0x1ff80fff); + +- /* If the old env has no enabled exceptions and the new env has any enabled +- exceptions, then unmask SIGFPE in the MSR FE0/FE1 bits. This will put +- the hardware into "precise mode" and may cause the FPU to run slower on +- some hardware. */ +- if ((old.l & _FPU_MASK_ALL) == 0 && (new.l & _FPU_MASK_ALL) != 0) +- (void) __fe_nomask_env_priv (); +- +- /* If the old env had any enabled exceptions and the new env has no enabled +- exceptions, then mask SIGFPE in the MSR FE0/FE1 bits. This may allow the +- FPU to run faster because it always takes the default action and can not +- generate SIGFPE. */ +- if ((old.l & _FPU_MASK_ALL) != 0 && (new.l & _FPU_MASK_ALL) == 0) +- (void)__fe_mask_env (); ++ __TEST_AND_EXIT_NON_STOP (old.l, new.l); ++ __TEST_AND_ENTER_NON_STOP (old.l, new.l); + + /* Atomically enable and raise (if appropriate) exceptions set in `new'. */ + fesetenv_register (new.fenv); diff --git a/SOURCES/glibc-rh1783303-13.patch b/SOURCES/glibc-rh1783303-13.patch new file mode 100644 index 0000000..73d2018 --- /dev/null +++ b/SOURCES/glibc-rh1783303-13.patch @@ -0,0 +1,58 @@ +commit 7413c188c77adb26a15cf0e98e0a991d09d73c65 +Author: Paul A. Clarke +Date: Thu Sep 19 11:18:33 2019 -0500 + + [powerpc] libc_feupdateenv_test: optimize FPSCR access + + ROUND_TO_ODD and a couple of other places use libc_feupdateenv_test to + restore the rounding mode and exception enables, preserve exception flags, + and test whether given exception(s) were generated. + + If the exception flags haven't changed, then it is sufficient and a bit + more efficient to just restore the rounding mode and enables, rather than + writing the full Floating-Point Status and Control Register (FPSCR). + + Reviewed-by: Paul E. Murphy + +diff --git a/sysdeps/powerpc/fpu/fenv_libc.h b/sysdeps/powerpc/fpu/fenv_libc.h +index 36b639c3939586f6..86ae7fda016abd8b 100644 +--- a/sysdeps/powerpc/fpu/fenv_libc.h ++++ b/sysdeps/powerpc/fpu/fenv_libc.h +@@ -257,6 +257,10 @@ enum { + (FPSCR_VE_MASK|FPSCR_OE_MASK|FPSCR_UE_MASK|FPSCR_ZE_MASK|FPSCR_XE_MASK) + #define FPSCR_BASIC_EXCEPTIONS_MASK \ + (FPSCR_VX_MASK|FPSCR_OX_MASK|FPSCR_UX_MASK|FPSCR_ZX_MASK|FPSCR_XX_MASK) ++#define FPSCR_EXCEPTIONS_MASK (FPSCR_BASIC_EXCEPTIONS_MASK| \ ++ FPSCR_VXSNAN_MASK|FPSCR_VXISI_MASK|FPSCR_VXIDI_MASK|FPSCR_VXZDZ_MASK| \ ++ FPSCR_VXIMZ_MASK|FPSCR_VXVC_MASK|FPSCR_VXSOFT_MASK|FPSCR_VXSQRT_MASK| \ ++ FPSCR_VXCVI_MASK) + #define FPSCR_FPRF_MASK \ + (FPSCR_FPRF_C_MASK|FPSCR_FPRF_FL_MASK|FPSCR_FPRF_FG_MASK| \ + FPSCR_FPRF_FE_MASK|FPSCR_FPRF_FU_MASK) +diff --git a/sysdeps/powerpc/fpu/fenv_private.h b/sysdeps/powerpc/fpu/fenv_private.h +index c236d45db2f399a4..86a3611b3ef41759 100644 +--- a/sysdeps/powerpc/fpu/fenv_private.h ++++ b/sysdeps/powerpc/fpu/fenv_private.h +@@ -52,8 +52,20 @@ __libc_femergeenv_ppc (const fenv_t *envp, unsigned long long old_mask, + __TEST_AND_EXIT_NON_STOP (old.l, new.l); + __TEST_AND_ENTER_NON_STOP (old.l, new.l); + +- /* Atomically enable and raise (if appropriate) exceptions set in `new'. */ +- fesetenv_register (new.fenv); ++ /* If requesting to keep status, replace control, and merge exceptions, ++ and exceptions haven't changed, we can just set new control instead ++ of the whole FPSCR. */ ++ if ((old_mask & (FPSCR_CONTROL_MASK|FPSCR_STATUS_MASK|FPSCR_EXCEPTIONS_MASK)) ++ == (FPSCR_STATUS_MASK|FPSCR_EXCEPTIONS_MASK) && ++ (new_mask & (FPSCR_CONTROL_MASK|FPSCR_STATUS_MASK|FPSCR_EXCEPTIONS_MASK)) ++ == (FPSCR_CONTROL_MASK|FPSCR_EXCEPTIONS_MASK) && ++ (old.l & FPSCR_EXCEPTIONS_MASK) == (new.l & FPSCR_EXCEPTIONS_MASK)) ++ { ++ fesetenv_mode (new.fenv); ++ } ++ else ++ /* Atomically enable and raise (if appropriate) exceptions set in `new'. */ ++ fesetenv_register (new.fenv); + + return old.l; + } diff --git a/SOURCES/glibc-rh1783303-14.patch b/SOURCES/glibc-rh1783303-14.patch new file mode 100644 index 0000000..b0c5e66 --- /dev/null +++ b/SOURCES/glibc-rh1783303-14.patch @@ -0,0 +1,56 @@ +commit e68b1151f7460d5fa88c3a567c13f66052da79a7 +Author: Paul A. Clarke +Date: Thu Sep 19 11:39:44 2019 -0500 + + [powerpc] __fesetround_inline optimizations + + On POWER9, use more efficient means to update the 2-bit rounding mode + via the 'mffscrn' instruction (instead of two 'mtfsb0/1' instructions + or one 'mtfsfi' instruction that modifies 4 bits). + + Suggested-by: Paul E. Murphy + Reviewed-By: Paul E Murphy + +diff --git a/sysdeps/powerpc/fpu/fenv_libc.h b/sysdeps/powerpc/fpu/fenv_libc.h +index 86ae7fda016abd8b..c3f541c08440b20e 100644 +--- a/sysdeps/powerpc/fpu/fenv_libc.h ++++ b/sysdeps/powerpc/fpu/fenv_libc.h +@@ -149,7 +149,12 @@ typedef union + static inline int + __fesetround_inline (int round) + { +- if ((unsigned int) round < 2) ++#ifdef _ARCH_PWR9 ++ __fe_mffscrn (round); ++#else ++ if (__glibc_likely (GLRO(dl_hwcap2) & PPC_FEATURE2_ARCH_3_00)) ++ __fe_mffscrn (round); ++ else if ((unsigned int) round < 2) + { + asm volatile ("mtfsb0 30"); + if ((unsigned int) round == 0) +@@ -165,7 +170,7 @@ __fesetround_inline (int round) + else + asm volatile ("mtfsb1 31"); + } +- ++#endif + return 0; + } + +@@ -174,7 +179,14 @@ __fesetround_inline (int round) + static inline void + __fesetround_inline_nocheck (const int round) + { +- asm volatile ("mtfsfi 7,%0" : : "i" (round)); ++#ifdef _ARCH_PWR9 ++ __fe_mffscrn (round); ++#else ++ if (__glibc_likely (GLRO(dl_hwcap2) & PPC_FEATURE2_ARCH_3_00)) ++ __fe_mffscrn (round); ++ else ++ asm volatile ("mtfsfi 7,%0" : : "i" (round)); ++#endif + } + + #define FPSCR_MASK(bit) (1 << (31 - (bit))) diff --git a/SOURCES/glibc-rh1783303-15.patch b/SOURCES/glibc-rh1783303-15.patch new file mode 100644 index 0000000..47f85db --- /dev/null +++ b/SOURCES/glibc-rh1783303-15.patch @@ -0,0 +1,123 @@ +commit 81ecb0ee4970865cbe5d1da733c4879b999c528f +Author: Paul A. Clarke +Date: Thu Sep 19 11:58:46 2019 -0500 + + [powerpc] Rename fegetenv_status to fegetenv_control + + fegetenv_status is used variously to retrieve the FPSCR exception enable + bits, rounding mode bits, or both. These are referred to as the control + bits in the POWER ISA. FPSCR status bits are also returned by the + 'mffs' and 'mffsl' instructions, but they are uniformly ignored by all + uses of fegetenv_status. Change the name to be reflective of its + current and expected use. + + Reviewed-By: Paul E Murphy + +diff --git a/sysdeps/powerpc/fpu/fedisblxcpt.c b/sysdeps/powerpc/fpu/fedisblxcpt.c +index bdf55ac62f1ffe4f..1273987459655585 100644 +--- a/sysdeps/powerpc/fpu/fedisblxcpt.c ++++ b/sysdeps/powerpc/fpu/fedisblxcpt.c +@@ -26,7 +26,7 @@ fedisableexcept (int excepts) + int result, new; + + /* Get current exception mask to return. */ +- fe.fenv = curr.fenv = fegetenv_status (); ++ fe.fenv = curr.fenv = fegetenv_control (); + result = fenv_reg_to_exceptions (fe.l); + + if ((excepts & FE_ALL_INVALID) == FE_ALL_INVALID) +diff --git a/sysdeps/powerpc/fpu/feenablxcpt.c b/sysdeps/powerpc/fpu/feenablxcpt.c +index 78ebabed9232c0ad..fa233c305aedd5f6 100644 +--- a/sysdeps/powerpc/fpu/feenablxcpt.c ++++ b/sysdeps/powerpc/fpu/feenablxcpt.c +@@ -26,7 +26,7 @@ feenableexcept (int excepts) + int result, new; + + /* Get current exception mask to return. */ +- fe.fenv = curr.fenv = fegetenv_status (); ++ fe.fenv = curr.fenv = fegetenv_control (); + result = fenv_reg_to_exceptions (fe.l); + + if ((excepts & FE_ALL_INVALID) == FE_ALL_INVALID) +diff --git a/sysdeps/powerpc/fpu/fegetexcept.c b/sysdeps/powerpc/fpu/fegetexcept.c +index 9d77adea59939ece..6bbf11d9d5df61e5 100644 +--- a/sysdeps/powerpc/fpu/fegetexcept.c ++++ b/sysdeps/powerpc/fpu/fegetexcept.c +@@ -25,7 +25,7 @@ __fegetexcept (void) + fenv_union_t fe; + int result = 0; + +- fe.fenv = fegetenv_status (); ++ fe.fenv = fegetenv_control (); + + if (fe.l & (1 << (31 - FPSCR_XE))) + result |= FE_INEXACT; +diff --git a/sysdeps/powerpc/fpu/fegetmode.c b/sysdeps/powerpc/fpu/fegetmode.c +index 75493e5f24c8b05b..57d6d5275485ebdc 100644 +--- a/sysdeps/powerpc/fpu/fegetmode.c ++++ b/sysdeps/powerpc/fpu/fegetmode.c +@@ -21,6 +21,6 @@ + int + fegetmode (femode_t *modep) + { +- *modep = fegetenv_status (); ++ *modep = fegetenv_control (); + return 0; + } +diff --git a/sysdeps/powerpc/fpu/fenv_libc.h b/sysdeps/powerpc/fpu/fenv_libc.h +index c3f541c08440b20e..b5c8da1adefe93cb 100644 +--- a/sysdeps/powerpc/fpu/fenv_libc.h ++++ b/sysdeps/powerpc/fpu/fenv_libc.h +@@ -61,7 +61,7 @@ extern const fenv_t *__fe_mask_env (void) attribute_hidden; + 'mffs' on architectures older than "power9" because the additional + bits set for 'mffsl' are "don't care" for 'mffs'. 'mffs' is a superset + of 'mffsl'. */ +-#define fegetenv_status() \ ++#define fegetenv_control() \ + ({register double __fr; \ + __asm__ __volatile__ ( \ + ".machine push; .machine \"power9\"; mffsl %0; .machine pop" \ +@@ -85,7 +85,7 @@ extern const fenv_t *__fe_mask_env (void) attribute_hidden; + __fr.fenv; \ + }) + +-/* Like fegetenv_status, but also sets the rounding mode. */ ++/* Like fegetenv_control, but also sets the rounding mode. */ + #ifdef _ARCH_PWR9 + #define fegetenv_and_set_rn(rn) __fe_mffscrn (rn) + #else +@@ -116,7 +116,7 @@ extern const fenv_t *__fe_mask_env (void) attribute_hidden; + + /* Set the last 2 nibbles of the FPSCR, which contain the + exception enables and the rounding mode. +- 'fegetenv_status' retrieves these bits by reading the FPSCR. */ ++ 'fegetenv_control' retrieves these bits by reading the FPSCR. */ + #define fesetenv_mode(env) __builtin_mtfsf (0b00000011, (env)); + + /* This very handy macro: +diff --git a/sysdeps/powerpc/fpu/fesetenv.c b/sysdeps/powerpc/fpu/fesetenv.c +index 4eab5045c48105e3..252114141cd87f8d 100644 +--- a/sysdeps/powerpc/fpu/fesetenv.c ++++ b/sysdeps/powerpc/fpu/fesetenv.c +@@ -26,7 +26,7 @@ __fesetenv (const fenv_t *envp) + + /* get the currently set exceptions. */ + new.fenv = *envp; +- old.fenv = fegetenv_status (); ++ old.fenv = fegetenv_control (); + + __TEST_AND_EXIT_NON_STOP (old.l, new.l); + __TEST_AND_ENTER_NON_STOP (old.l, new.l); +diff --git a/sysdeps/powerpc/fpu/fesetmode.c b/sysdeps/powerpc/fpu/fesetmode.c +index 58ba02c0a1e64c27..e5938af04cb71ca1 100644 +--- a/sysdeps/powerpc/fpu/fesetmode.c ++++ b/sysdeps/powerpc/fpu/fesetmode.c +@@ -27,7 +27,7 @@ fesetmode (const femode_t *modep) + /* Logic regarding enabled exceptions as in fesetenv. */ + + new.fenv = *modep; +- old.fenv = fegetenv_status (); ++ old.fenv = fegetenv_control (); + new.l = (new.l & ~FPSCR_STATUS_MASK) | (old.l & FPSCR_STATUS_MASK); + + if (old.l == new.l) diff --git a/SOURCES/glibc-rh1783303-16.patch b/SOURCES/glibc-rh1783303-16.patch new file mode 100644 index 0000000..c60fb39 --- /dev/null +++ b/SOURCES/glibc-rh1783303-16.patch @@ -0,0 +1,29 @@ +commit 36c17c7079a5243a890ba43affff326a041775a9 +Author: Paul A. Clarke +Date: Thu Sep 19 11:31:31 2019 -0500 + + [powerpc] libc_feholdsetround_noex_ppc_ctx: optimize FPSCR write + + libc_feholdsetround_noex_ppc_ctx currently performs: + 1. Read FPSCR, save to context. + 2. Create new FPSCR value: clear enables and set new rounding mode. + 3. Write new value to FPSCR. + + Since other bits just pass through, there is no need to write them. + + Instead, write just the changed values (enables and rounding mode), + which can be a bit more efficient. + +diff --git a/sysdeps/powerpc/fpu/fenv_private.h b/sysdeps/powerpc/fpu/fenv_private.h +index 86a3611b3ef41759..c88142fe3053580f 100644 +--- a/sysdeps/powerpc/fpu/fenv_private.h ++++ b/sysdeps/powerpc/fpu/fenv_private.h +@@ -142,7 +142,7 @@ libc_feholdsetround_noex_ppc_ctx (struct rm_ctx *ctx, int r) + if (__glibc_unlikely (new.l != old.l)) + { + __TEST_AND_ENTER_NON_STOP (old.l, 0ULL); +- fesetenv_register (new.fenv); ++ fesetenv_mode (new.fenv); + ctx->updated_status = true; + } + else diff --git a/SOURCES/glibc-rh1783303-17.patch b/SOURCES/glibc-rh1783303-17.patch new file mode 100644 index 0000000..2c521cc --- /dev/null +++ b/SOURCES/glibc-rh1783303-17.patch @@ -0,0 +1,84 @@ +commit d7a568af5546e0313abbc04060c8e9b0d3f750b4 +Author: Paul A. Clarke +Date: Thu Sep 19 14:04:45 2019 -0500 + + [powerpc] Rename fesetenv_mode to fesetenv_control + + fesetenv_mode is used variously to write the FPSCR exception enable + bits and rounding mode bits. These are referred to as the control + bits in the POWER ISA. Change the name to be reflective of its + current and expected use, and match up well with fegetenv_control. + +diff --git a/sysdeps/powerpc/fpu/fedisblxcpt.c b/sysdeps/powerpc/fpu/fedisblxcpt.c +index 1273987459655585..efa9c422fe54f5d8 100644 +--- a/sysdeps/powerpc/fpu/fedisblxcpt.c ++++ b/sysdeps/powerpc/fpu/fedisblxcpt.c +@@ -41,7 +41,7 @@ fedisableexcept (int excepts) + fe.l &= ~new; + + if (fe.l != curr.l) +- fesetenv_mode (fe.fenv); ++ fesetenv_control (fe.fenv); + + __TEST_AND_ENTER_NON_STOP (-1ULL, fe.l); + +diff --git a/sysdeps/powerpc/fpu/feenablxcpt.c b/sysdeps/powerpc/fpu/feenablxcpt.c +index fa233c305aedd5f6..dfcc6fb7bd24b8db 100644 +--- a/sysdeps/powerpc/fpu/feenablxcpt.c ++++ b/sysdeps/powerpc/fpu/feenablxcpt.c +@@ -41,7 +41,7 @@ feenableexcept (int excepts) + fe.l |= new; + + if (fe.l != curr.l) +- fesetenv_mode (fe.fenv); ++ fesetenv_control (fe.fenv); + + __TEST_AND_EXIT_NON_STOP (0ULL, fe.l); + +diff --git a/sysdeps/powerpc/fpu/fenv_libc.h b/sysdeps/powerpc/fpu/fenv_libc.h +index b5c8da1adefe93cb..287fc9f8f70e051c 100644 +--- a/sysdeps/powerpc/fpu/fenv_libc.h ++++ b/sysdeps/powerpc/fpu/fenv_libc.h +@@ -117,7 +117,7 @@ extern const fenv_t *__fe_mask_env (void) attribute_hidden; + /* Set the last 2 nibbles of the FPSCR, which contain the + exception enables and the rounding mode. + 'fegetenv_control' retrieves these bits by reading the FPSCR. */ +-#define fesetenv_mode(env) __builtin_mtfsf (0b00000011, (env)); ++#define fesetenv_control(env) __builtin_mtfsf (0b00000011, (env)); + + /* This very handy macro: + - Sets the rounding mode to 'round to nearest'; +diff --git a/sysdeps/powerpc/fpu/fenv_private.h b/sysdeps/powerpc/fpu/fenv_private.h +index c88142fe3053580f..666fbfdd9fef7759 100644 +--- a/sysdeps/powerpc/fpu/fenv_private.h ++++ b/sysdeps/powerpc/fpu/fenv_private.h +@@ -61,7 +61,7 @@ __libc_femergeenv_ppc (const fenv_t *envp, unsigned long long old_mask, + == (FPSCR_CONTROL_MASK|FPSCR_EXCEPTIONS_MASK) && + (old.l & FPSCR_EXCEPTIONS_MASK) == (new.l & FPSCR_EXCEPTIONS_MASK)) + { +- fesetenv_mode (new.fenv); ++ fesetenv_control (new.fenv); + } + else + /* Atomically enable and raise (if appropriate) exceptions set in `new'. */ +@@ -142,7 +142,7 @@ libc_feholdsetround_noex_ppc_ctx (struct rm_ctx *ctx, int r) + if (__glibc_unlikely (new.l != old.l)) + { + __TEST_AND_ENTER_NON_STOP (old.l, 0ULL); +- fesetenv_mode (new.fenv); ++ fesetenv_control (new.fenv); + ctx->updated_status = true; + } + else +diff --git a/sysdeps/powerpc/fpu/fesetmode.c b/sysdeps/powerpc/fpu/fesetmode.c +index e5938af04cb71ca1..fdaecb1a6a25a820 100644 +--- a/sysdeps/powerpc/fpu/fesetmode.c ++++ b/sysdeps/powerpc/fpu/fesetmode.c +@@ -36,6 +36,6 @@ fesetmode (const femode_t *modep) + __TEST_AND_EXIT_NON_STOP (old.l, new.l); + __TEST_AND_ENTER_NON_STOP (old.l, new.l); + +- fesetenv_mode (new.fenv); ++ fesetenv_control (new.fenv); + return 0; + } diff --git a/SOURCES/glibc-rh1783303-18.patch b/SOURCES/glibc-rh1783303-18.patch new file mode 100644 index 0000000..60b6d9d --- /dev/null +++ b/SOURCES/glibc-rh1783303-18.patch @@ -0,0 +1,64 @@ +commit 7b8481b330720d28c019a2e5994492a1923d5daa +Author: Paul A. Clarke +Date: Thu Sep 19 11:11:04 2019 -0500 + + [powerpc] No need to enter "Ignore Exceptions Mode" + + Since at least POWER8, there is no performance advantage to entering + "Ignore Exceptions Mode", and doing so conditionally requires + - the conditional logic, and + - a system call. + + Make it a no-op for uses within glibc. + +diff --git a/sysdeps/powerpc/fpu/fenv_private.h b/sysdeps/powerpc/fpu/fenv_private.h +index 666fbfdd9fef7759..e09137e892a8e3f3 100644 +--- a/sysdeps/powerpc/fpu/fenv_private.h ++++ b/sysdeps/powerpc/fpu/fenv_private.h +@@ -23,6 +23,17 @@ + #include + #include + ++#ifdef _ARCH_PWR8 ++/* There is no performance advantage to non-stop mode. */ ++/* The odd syntax here is to innocuously reference the given variables ++ to prevent warnings about unused variables. */ ++#define __TEST_AND_BEGIN_NON_STOP(old, new) do {} while ((old) * (new) * 0 != 0) ++#define __TEST_AND_END_NON_STOP(old, new) do {} while ((old) * (new) * 0 != 0) ++#else ++#define __TEST_AND_BEGIN_NON_STOP __TEST_AND_ENTER_NON_STOP ++#define __TEST_AND_END_NON_STOP __TEST_AND_EXIT_NON_STOP ++#endif ++ + static __always_inline void + libc_feholdexcept_setround_ppc (fenv_t *envp, int r) + { +@@ -30,7 +41,7 @@ libc_feholdexcept_setround_ppc (fenv_t *envp, int r) + + old.fenv = *envp = fegetenv_register (); + +- __TEST_AND_ENTER_NON_STOP (old.l, 0ULL); ++ __TEST_AND_BEGIN_NON_STOP (old.l, 0ULL); + + /* Clear everything and set the rounding mode. */ + new.l = r; +@@ -49,8 +60,8 @@ __libc_femergeenv_ppc (const fenv_t *envp, unsigned long long old_mask, + /* Merge bits while masking unwanted bits from new and old env. */ + new.l = (old.l & old_mask) | (new.l & new_mask); + +- __TEST_AND_EXIT_NON_STOP (old.l, new.l); +- __TEST_AND_ENTER_NON_STOP (old.l, new.l); ++ __TEST_AND_END_NON_STOP (old.l, new.l); ++ __TEST_AND_BEGIN_NON_STOP (old.l, new.l); + + /* If requesting to keep status, replace control, and merge exceptions, + and exceptions haven't changed, we can just set new control instead +@@ -141,7 +152,7 @@ libc_feholdsetround_noex_ppc_ctx (struct rm_ctx *ctx, int r) + ctx->env = old.fenv; + if (__glibc_unlikely (new.l != old.l)) + { +- __TEST_AND_ENTER_NON_STOP (old.l, 0ULL); ++ __TEST_AND_BEGIN_NON_STOP (old.l, 0ULL); + fesetenv_control (new.fenv); + ctx->updated_status = true; + } diff --git a/SOURCES/glibc-rh1783303-2.patch b/SOURCES/glibc-rh1783303-2.patch new file mode 100644 index 0000000..616af07 --- /dev/null +++ b/SOURCES/glibc-rh1783303-2.patch @@ -0,0 +1,105 @@ +commit de751ebc9efa97ce0115e42bd55fa1beeb614380 +Author: Paul A. Clarke +Date: Fri Mar 15 19:04:24 2019 -0400 + + [powerpc] get_rounding_mode: utilize faster method to get rounding mode + + Add support to use 'mffsl' instruction if compiled for POWER9 (or later). + + Also, mask the result to avoid bleeding unrelated bits into the result of + _FPU_GET_RC(). + + Reviewed-by: Tulio Magno Quites Machado Filho + +diff --git a/sysdeps/powerpc/fpu/get-rounding-mode.h b/sysdeps/powerpc/fpu/get-rounding-mode.h +new file mode 100644 +index 0000000000000000..e2fdbbbcce72bd66 +--- /dev/null ++++ b/sysdeps/powerpc/fpu/get-rounding-mode.h +@@ -0,0 +1,33 @@ ++/* Determine floating-point rounding mode within libc. powerpc64 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, see ++ . */ ++ ++#ifndef _POWERPC64_GET_ROUNDING_MODE_H ++#define _POWERPC64_GET_ROUNDING_MODE_H 1 ++ ++#include ++#include ++ ++/* Return the floating-point rounding mode. */ ++ ++static inline int ++get_rounding_mode (void) ++{ ++ return _FPU_GET_RC (); ++} ++ ++#endif /* get-rounding-mode.h */ +diff --git a/sysdeps/powerpc/fpu_control.h b/sysdeps/powerpc/fpu_control.h +index 9d0698b4fc3eb595..62c478d72ae660cb 100644 +--- a/sysdeps/powerpc/fpu_control.h ++++ b/sysdeps/powerpc/fpu_control.h +@@ -71,6 +71,8 @@ extern fpu_control_t __fpu_control; + # define _FPU_RC_UP 0x02 + # define _FPU_RC_ZERO 0x01 + ++# define _FPU_MASK_RC (_FPU_RC_NEAREST|_FPU_RC_DOWN|_FPU_RC_UP|_FPU_RC_ZERO) ++ + # define _FPU_MASK_NI 0x04 /* non-ieee mode */ + + /* masking of interrupts */ +@@ -94,15 +96,36 @@ extern fpu_control_t __fpu_control; + typedef unsigned int fpu_control_t; + + /* Macros for accessing the hardware control word. */ ++# define __FPU_MFFS() \ ++ ({register double __fr; \ ++ __asm__ ("mffs %0" : "=f" (__fr)); \ ++ __fr; \ ++ }) ++ + # define _FPU_GETCW(cw) \ + ({union { double __d; unsigned long long __ll; } __u; \ +- register double __fr; \ +- __asm__ ("mffs %0" : "=f" (__fr)); \ +- __u.__d = __fr; \ ++ __u.__d = __FPU_MFFS(); \ + (cw) = (fpu_control_t) __u.__ll; \ + (fpu_control_t) __u.__ll; \ + }) + ++#ifdef _ARCH_PWR9 ++# define __FPU_MFFSL() \ ++ ({register double __fr; \ ++ __asm__ ("mffsl %0" : "=f" (__fr)); \ ++ __fr; \ ++ }) ++#else ++# define __FPU_MFFSL() __FPU_MFFS() ++#endif ++ ++# define _FPU_GET_RC() \ ++ ({union { double __d; unsigned long long __ll; } __u; \ ++ __u.__d = __FPU_MFFSL(); \ ++ __u.__ll &= _FPU_MASK_RC; \ ++ (fpu_control_t) __u.__ll; \ ++ }) ++ + # define _FPU_SETCW(cw) \ + { union { double __d; unsigned long long __ll; } __u; \ + register double __fr; \ diff --git a/SOURCES/glibc-rh1783303-3.patch b/SOURCES/glibc-rh1783303-3.patch new file mode 100644 index 0000000..b653b49 --- /dev/null +++ b/SOURCES/glibc-rh1783303-3.patch @@ -0,0 +1,65 @@ +commit 49bc41b64239c4726f31fa35a1af4f22fb41d51f +Author: Paul A. Clarke +Date: Tue Jun 11 14:37:37 2019 -0500 + + [powerpc] add 'volatile' to asm + + Add 'volatile' keyword to a few asm statements, to force the compiler + to generate the instructions therein. + + Some instances were implicitly volatile, but adding keyword for consistency. + + 2019-06-19 Paul A. Clarke + + * sysdeps/powerpc/fpu/fenv_libc.h (relax_fenv_state): Add 'volatile'. + * sysdeps/powerpc/fpu/fpu_control.h (__FPU_MFFS): Likewise. + (__FPU_MFFSL): Likewise. + (_FPU_SETCW): Likewise. + +diff --git a/sysdeps/powerpc/fpu/fenv_libc.h b/sysdeps/powerpc/fpu/fenv_libc.h +index a0128c66444a3e46..d6945903b525748e 100644 +--- a/sysdeps/powerpc/fpu/fenv_libc.h ++++ b/sysdeps/powerpc/fpu/fenv_libc.h +@@ -57,9 +57,9 @@ extern const fenv_t *__fe_mask_env (void) attribute_hidden; + #define relax_fenv_state() \ + do { \ + if (GLRO(dl_hwcap) & PPC_FEATURE_HAS_DFP) \ +- asm (".machine push; .machine \"power6\"; " \ ++ asm volatile (".machine push; .machine \"power6\"; " \ + "mtfsfi 7,0,1; .machine pop"); \ +- asm ("mtfsfi 7,0"); \ ++ asm volatile ("mtfsfi 7,0"); \ + } while(0) + + /* Set/clear a particular FPSCR bit (for instance, +diff --git a/sysdeps/powerpc/fpu_control.h b/sysdeps/powerpc/fpu_control.h +index 62c478d72ae660cb..90063d77bbbf794f 100644 +--- a/sysdeps/powerpc/fpu_control.h ++++ b/sysdeps/powerpc/fpu_control.h +@@ -98,7 +98,7 @@ typedef unsigned int fpu_control_t; + /* Macros for accessing the hardware control word. */ + # define __FPU_MFFS() \ + ({register double __fr; \ +- __asm__ ("mffs %0" : "=f" (__fr)); \ ++ __asm__ __volatile__("mffs %0" : "=f" (__fr)); \ + __fr; \ + }) + +@@ -112,7 +112,7 @@ typedef unsigned int fpu_control_t; + #ifdef _ARCH_PWR9 + # define __FPU_MFFSL() \ + ({register double __fr; \ +- __asm__ ("mffsl %0" : "=f" (__fr)); \ ++ __asm__ __volatile__("mffsl %0" : "=f" (__fr)); \ + __fr; \ + }) + #else +@@ -132,7 +132,7 @@ typedef unsigned int fpu_control_t; + __u.__ll = 0xfff80000LL << 32; /* This is a QNaN. */ \ + __u.__ll |= (cw) & 0xffffffffLL; \ + __fr = __u.__d; \ +- __asm__ ("mtfsf 255,%0" : : "f" (__fr)); \ ++ __asm__ __volatile__("mtfsf 255,%0" : : "f" (__fr)); \ + } + + /* Default control word set at startup. */ diff --git a/SOURCES/glibc-rh1783303-4.patch b/SOURCES/glibc-rh1783303-4.patch new file mode 100644 index 0000000..5475305 --- /dev/null +++ b/SOURCES/glibc-rh1783303-4.patch @@ -0,0 +1,200 @@ +commit 3db85a9814784a74536a1f0e7b7ddbfef7dc84bb +Author: Paul A. Clarke +Date: Thu Jun 20 11:57:18 2019 -0500 + + powerpc: Use faster means to access FPSCR when possible in some cases + + Using 'mffs' instruction to read the Floating Point Status Control Register + (FPSCR) can force a processor flush in some cases, with undesirable + performance impact. If the values of the bits in the FPSCR which force the + flush are not needed, an instruction that is new to POWER9 (ISA version 3.0), + 'mffsl' can be used instead. + + Cases included: get_rounding_mode, fegetround, fegetmode, fegetexcept. + + * sysdeps/powerpc/bits/fenvinline.h (__fegetround): Use + __fegetround_ISA300() or __fegetround_ISA2() as appropriate. + (__fegetround_ISA300) New. + (__fegetround_ISA2) New. + * sysdeps/powerpc/fpu_control.h (IS_ISA300): New. + (_FPU_MFFS): Move implementation... + (_FPU_GETCW): Here. + (_FPU_MFFSL): Move implementation.... + (_FPU_GET_RC_ISA300): Here. New. + (_FPU_GET_RC): Use _FPU_GET_RC_ISA300() or _FPU_GETCW() as appropriate. + * sysdeps/powerpc/fpu/fenv_libc.h (fegetenv_status_ISA300): New. + (fegetenv_status): New. + * sysdeps/powerpc/fpu/fegetmode.c (fegetmode): Use fegetenv_status() + instead of fegetenv_register(). + * sysdeps/powerpc/fpu/fegetexcept.c (__fegetexcept): Likewise. + + Reviewed-by: Tulio Magno Quites Machado Filho + +diff --git a/sysdeps/powerpc/bits/fenvinline.h b/sysdeps/powerpc/bits/fenvinline.h +index 41316386ba75e903..caec8ead6e17219d 100644 +--- a/sysdeps/powerpc/bits/fenvinline.h ++++ b/sysdeps/powerpc/bits/fenvinline.h +@@ -18,13 +18,36 @@ + + #if defined __GNUC__ && !defined _SOFT_FLOAT && !defined __NO_FPRS__ + +-/* Inline definition for fegetround. */ +-# define __fegetround() \ +- (__extension__ ({ int __fegetround_result; \ +- __asm__ __volatile__ \ +- ("mcrfs 7,7 ; mfcr %0" \ +- : "=r"(__fegetround_result) : : "cr7"); \ +- __fegetround_result & 3; })) ++/* Inline definitions for fegetround. */ ++# define __fegetround_ISA300() \ ++ (__extension__ ({ \ ++ union { double __d; unsigned long long __ll; } __u; \ ++ __asm__ __volatile__ ( \ ++ ".machine push; .machine \"power9\"; mffsl %0; .machine pop" \ ++ : "=f" (__u.__d)); \ ++ __u.__ll & 0x0000000000000003LL; \ ++ })) ++ ++# define __fegetround_ISA2() \ ++ (__extension__ ({ \ ++ int __fegetround_result; \ ++ __asm__ __volatile__ ("mcrfs 7,7 ; mfcr %0" \ ++ : "=r"(__fegetround_result) : : "cr7"); \ ++ __fegetround_result & 3; \ ++ })) ++ ++# ifdef _ARCH_PWR9 ++# define __fegetround() __fegetround_ISA300() ++# elif defined __BUILTIN_CPU_SUPPORTS__ ++# define __fegetround() \ ++ (__glibc_likely (__builtin_cpu_supports ("arch_3_00")) \ ++ ? __fegetround_ISA300() \ ++ : __fegetround_ISA2() \ ++ ) ++# else ++# define __fegetround() __fegetround_ISA2() ++# endif ++ + # define fegetround() __fegetround () + + # ifndef __NO_MATH_INLINES +diff --git a/sysdeps/powerpc/fpu/fegetexcept.c b/sysdeps/powerpc/fpu/fegetexcept.c +index a053a32bfe11c0d4..9d77adea59939ece 100644 +--- a/sysdeps/powerpc/fpu/fegetexcept.c ++++ b/sysdeps/powerpc/fpu/fegetexcept.c +@@ -25,7 +25,7 @@ __fegetexcept (void) + fenv_union_t fe; + int result = 0; + +- fe.fenv = fegetenv_register (); ++ fe.fenv = fegetenv_status (); + + if (fe.l & (1 << (31 - FPSCR_XE))) + result |= FE_INEXACT; +diff --git a/sysdeps/powerpc/fpu/fegetmode.c b/sysdeps/powerpc/fpu/fegetmode.c +index b83dc9f625d2248a..75493e5f24c8b05b 100644 +--- a/sysdeps/powerpc/fpu/fegetmode.c ++++ b/sysdeps/powerpc/fpu/fegetmode.c +@@ -21,6 +21,6 @@ + int + fegetmode (femode_t *modep) + { +- *modep = fegetenv_register (); ++ *modep = fegetenv_status (); + return 0; + } +diff --git a/sysdeps/powerpc/fpu/fenv_libc.h b/sysdeps/powerpc/fpu/fenv_libc.h +index d6945903b525748e..cc00df033da47c1a 100644 +--- a/sysdeps/powerpc/fpu/fenv_libc.h ++++ b/sysdeps/powerpc/fpu/fenv_libc.h +@@ -35,6 +35,27 @@ extern const fenv_t *__fe_mask_env (void) attribute_hidden; + #define fegetenv_register() \ + ({ fenv_t env; asm volatile ("mffs %0" : "=f" (env)); env; }) + ++/* Equivalent to fegetenv_register, but only returns bits for ++ status, exception enables, and mode. */ ++ ++#define fegetenv_status_ISA300() \ ++ ({register double __fr; \ ++ __asm__ __volatile__ ( \ ++ ".machine push; .machine \"power9\"; mffsl %0; .machine pop" \ ++ : "=f" (__fr)); \ ++ __fr; \ ++ }) ++ ++#ifdef _ARCH_PWR9 ++# define fegetenv_status() fegetenv_status_ISA300() ++#else ++# define fegetenv_status() \ ++ (__glibc_likely (__builtin_cpu_supports ("arch_3_00")) \ ++ ? fegetenv_status_ISA300() \ ++ : fegetenv_register() \ ++ ) ++#endif ++ + /* Equivalent to fesetenv, but takes a fenv_t instead of a pointer. */ + #define fesetenv_register(env) \ + do { \ +diff --git a/sysdeps/powerpc/fpu_control.h b/sysdeps/powerpc/fpu_control.h +index 90063d77bbbf794f..e0ee622e246c0d61 100644 +--- a/sysdeps/powerpc/fpu_control.h ++++ b/sysdeps/powerpc/fpu_control.h +@@ -96,35 +96,37 @@ extern fpu_control_t __fpu_control; + typedef unsigned int fpu_control_t; + + /* Macros for accessing the hardware control word. */ +-# define __FPU_MFFS() \ +- ({register double __fr; \ +- __asm__ __volatile__("mffs %0" : "=f" (__fr)); \ +- __fr; \ +- }) +- + # define _FPU_GETCW(cw) \ + ({union { double __d; unsigned long long __ll; } __u; \ +- __u.__d = __FPU_MFFS(); \ ++ __asm__ __volatile__("mffs %0" : "=f" (__u.__d)); \ + (cw) = (fpu_control_t) __u.__ll; \ + (fpu_control_t) __u.__ll; \ + }) + +-#ifdef _ARCH_PWR9 +-# define __FPU_MFFSL() \ +- ({register double __fr; \ +- __asm__ __volatile__("mffsl %0" : "=f" (__fr)); \ +- __fr; \ ++# define _FPU_GET_RC_ISA300() \ ++ ({union { double __d; unsigned long long __ll; } __u; \ ++ __asm__ __volatile__( \ ++ ".machine push; .machine \"power9\"; mffsl %0; .machine pop" \ ++ : "=f" (__u.__d)); \ ++ (fpu_control_t) (__u.__ll & _FPU_MASK_RC); \ + }) +-#else +-# define __FPU_MFFSL() __FPU_MFFS() +-#endif +- +-# define _FPU_GET_RC() \ +- ({union { double __d; unsigned long long __ll; } __u; \ +- __u.__d = __FPU_MFFSL(); \ +- __u.__ll &= _FPU_MASK_RC; \ +- (fpu_control_t) __u.__ll; \ ++ ++# ifdef _ARCH_PWR9 ++# define _FPU_GET_RC() _FPU_GET_RC_ISA300() ++# elif defined __BUILTIN_CPU_SUPPORTS__ ++# define _FPU_GET_RC() \ ++ ({fpu_control_t __rc; \ ++ __rc = __glibc_likely (__builtin_cpu_supports ("arch_3_00")) \ ++ ? _FPU_GET_RC_ISA300 () \ ++ : _FPU_GETCW (__rc) & _FPU_MASK_RC; \ ++ __rc; \ ++ }) ++# else ++# define _FPU_GET_RC() \ ++ ({fpu_control_t __rc = _FPU_GETCW (__rc) & _FPU_MASK_RC; \ ++ __rc; \ + }) ++# endif + + # define _FPU_SETCW(cw) \ + { union { double __d; unsigned long long __ll; } __u; \ diff --git a/SOURCES/glibc-rh1783303-5.patch b/SOURCES/glibc-rh1783303-5.patch new file mode 100644 index 0000000..e8c439e --- /dev/null +++ b/SOURCES/glibc-rh1783303-5.patch @@ -0,0 +1,37 @@ +commit b5232c9f9e6048b8f780d3cbfadbc8e59bb90ce4 +Author: Paul A. Clarke +Date: Mon Jul 8 17:06:19 2019 -0500 + + [powerpc] fenv_libc.h: protect use of __builtin_cpu_supports + + Using __builtin_cpu_supports() requires support in GCC and Glibc. + My recent patch to fenv_libc.h added an unprotected use of + __builtin_cpu_supports(). Compilation of Glibc itself will fail + with a sufficiently new GCC and sufficiently old Glibc: + + ../sysdeps/powerpc/fpu/fegetexcept.c: In function ‘__fegetexcept’: + ../sysdeps/powerpc/fpu/fenv_libc.h:52:20: error: builtin ‘__builtin_cpu_supports’ needs GLIBC (2.23 and newer) that exports hardware capability bits [-Werror] + + Reviewed-by: Florian Weimer + Fixes 3db85a9814784a74536a1f0e7b7ddbfef7dc84bb. + +diff --git a/sysdeps/powerpc/fpu/fenv_libc.h b/sysdeps/powerpc/fpu/fenv_libc.h +index cc00df033da47c1a..9dca6e760cc51946 100644 +--- a/sysdeps/powerpc/fpu/fenv_libc.h ++++ b/sysdeps/powerpc/fpu/fenv_libc.h +@@ -48,12 +48,14 @@ extern const fenv_t *__fe_mask_env (void) attribute_hidden; + + #ifdef _ARCH_PWR9 + # define fegetenv_status() fegetenv_status_ISA300() +-#else ++#elif defined __BUILTIN_CPU_SUPPORTS__ + # define fegetenv_status() \ + (__glibc_likely (__builtin_cpu_supports ("arch_3_00")) \ + ? fegetenv_status_ISA300() \ + : fegetenv_register() \ + ) ++#else ++# define fegetenv_status() fegetenv_register () + #endif + + /* Equivalent to fesetenv, but takes a fenv_t instead of a pointer. */ diff --git a/SOURCES/glibc-rh1783303-6.patch b/SOURCES/glibc-rh1783303-6.patch new file mode 100644 index 0000000..7313bd6 --- /dev/null +++ b/SOURCES/glibc-rh1783303-6.patch @@ -0,0 +1,185 @@ +commit cd7ce12a027656ad3cda774454088de5a2c7fbfa +Author: Paul A. Clarke +Date: Fri Jul 12 20:13:58 2019 -0500 + + [powerpc] fe{en,dis}ableexcept optimize bit translations + + The exceptions passed to fe{en,dis}ableexcept() are defined in the ABI + as a bitmask, a combination of FE_INVALID, FE_OVERFLOW, etc. + Within the functions, these bits must be translated to/from the corresponding + enable bits in the Floating Point Status Control Register (FPSCR). + This translation is currently done bit-by-bit. The compiler generates + a series of conditional bit operations. Nicely, the "FE" exception + bits are all a uniform offset from the FPSCR enable bits, so the bit-by-bit + operation can instead be performed by a shift with appropriate masking. + +diff --git a/sysdeps/powerpc/fpu/fedisblxcpt.c b/sysdeps/powerpc/fpu/fedisblxcpt.c +index 2daed44a419301e8..90bc3d12c6d8558c 100644 +--- a/sysdeps/powerpc/fpu/fedisblxcpt.c ++++ b/sysdeps/powerpc/fpu/fedisblxcpt.c +@@ -33,16 +33,7 @@ fedisableexcept (int excepts) + excepts = (excepts | FE_INVALID) & ~ FE_ALL_INVALID; + + /* Sets the new exception mask. */ +- if (excepts & FE_INEXACT) +- fe.l &= ~(1 << (31 - FPSCR_XE)); +- if (excepts & FE_DIVBYZERO) +- fe.l &= ~(1 << (31 - FPSCR_ZE)); +- if (excepts & FE_UNDERFLOW) +- fe.l &= ~(1 << (31 - FPSCR_UE)); +- if (excepts & FE_OVERFLOW) +- fe.l &= ~(1 << (31 - FPSCR_OE)); +- if (excepts & FE_INVALID) +- fe.l &= ~(1 << (31 - FPSCR_VE)); ++ fe.l &= ~ fenv_exceptions_to_reg (excepts); + + if (fe.l != curr.l) + fesetenv_register (fe.fenv); +diff --git a/sysdeps/powerpc/fpu/feenablxcpt.c b/sysdeps/powerpc/fpu/feenablxcpt.c +index 19cfe28e7aa307d4..e029971b9a460c28 100644 +--- a/sysdeps/powerpc/fpu/feenablxcpt.c ++++ b/sysdeps/powerpc/fpu/feenablxcpt.c +@@ -33,16 +33,7 @@ feenableexcept (int excepts) + excepts = (excepts | FE_INVALID) & ~ FE_ALL_INVALID; + + /* Sets the new exception mask. */ +- if (excepts & FE_INEXACT) +- fe.l |= (1 << (31 - FPSCR_XE)); +- if (excepts & FE_DIVBYZERO) +- fe.l |= (1 << (31 - FPSCR_ZE)); +- if (excepts & FE_UNDERFLOW) +- fe.l |= (1 << (31 - FPSCR_UE)); +- if (excepts & FE_OVERFLOW) +- fe.l |= (1 << (31 - FPSCR_OE)); +- if (excepts & FE_INVALID) +- fe.l |= (1 << (31 - FPSCR_VE)); ++ fe.l |= fenv_exceptions_to_reg (excepts); + + if (fe.l != curr.l) + fesetenv_register (fe.fenv); +diff --git a/sysdeps/powerpc/fpu/fenv_libc.h b/sysdeps/powerpc/fpu/fenv_libc.h +index 9dca6e760cc51946..f9634a64d186c076 100644 +--- a/sysdeps/powerpc/fpu/fenv_libc.h ++++ b/sysdeps/powerpc/fpu/fenv_libc.h +@@ -129,60 +129,108 @@ __fesetround_inline_nocheck (const int round) + asm volatile ("mtfsfi 7,%0" : : "i" (round)); + } + ++#define FPSCR_MASK(bit) (1 << (31 - (bit))) ++ + /* Definitions of all the FPSCR bit numbers */ + enum { + FPSCR_FX = 0, /* exception summary */ ++#define FPSCR_FX_MASK (FPSCR_MASK (FPSCR_FX)) + FPSCR_FEX, /* enabled exception summary */ ++#define FPSCR_FEX_MASK (FPSCR_MASK FPSCR_FEX)) + FPSCR_VX, /* invalid operation summary */ ++#define FPSCR_VX_MASK (FPSCR_MASK (FPSCR_VX)) + FPSCR_OX, /* overflow */ ++#define FPSCR_OX_MASK (FPSCR_MASK (FPSCR_OX)) + FPSCR_UX, /* underflow */ ++#define FPSCR_UX_MASK (FPSCR_MASK (FPSCR_UX)) + FPSCR_ZX, /* zero divide */ ++#define FPSCR_ZX_MASK (FPSCR_MASK (FPSCR_ZX)) + FPSCR_XX, /* inexact */ ++#define FPSCR_XX_MASK (FPSCR_MASK (FPSCR_XX)) + FPSCR_VXSNAN, /* invalid operation for sNaN */ ++#define FPSCR_VXSNAN_MASK (FPSCR_MASK (FPSCR_VXSNAN)) + FPSCR_VXISI, /* invalid operation for Inf-Inf */ ++#define FPSCR_VXISI_MASK (FPSCR_MASK (FPSCR_VXISI)) + FPSCR_VXIDI, /* invalid operation for Inf/Inf */ ++#define FPSCR_VXIDI_MASK (FPSCR_MASK (FPSCR_VXIDI)) + FPSCR_VXZDZ, /* invalid operation for 0/0 */ ++#define FPSCR_VXZDZ_MASK (FPSCR_MASK (FPSCR_VXZDZ)) + FPSCR_VXIMZ, /* invalid operation for Inf*0 */ ++#define FPSCR_VXIMZ_MASK (FPSCR_MASK (FPSCR_VXIMZ)) + FPSCR_VXVC, /* invalid operation for invalid compare */ ++#define FPSCR_VXVC_MASK (FPSCR_MASK (FPSCR_VXVC)) + FPSCR_FR, /* fraction rounded [fraction was incremented by round] */ ++#define FPSCR_FR_MASK (FPSCR_MASK (FPSCR_FR)) + FPSCR_FI, /* fraction inexact */ ++#define FPSCR_FI_MASK (FPSCR_MASK (FPSCR_FI)) + FPSCR_FPRF_C, /* result class descriptor */ ++#define FPSCR_FPRF_C_MASK (FPSCR_MASK (FPSCR_FPRF_C)) + FPSCR_FPRF_FL, /* result less than (usually, less than 0) */ ++#define FPSCR_FPRF_FL_MASK (FPSCR_MASK (FPSCR_FPRF_FL)) + FPSCR_FPRF_FG, /* result greater than */ ++#define FPSCR_FPRF_FG_MASK (FPSCR_MASK (FPSCR_FPRF_FG)) + FPSCR_FPRF_FE, /* result equal to */ ++#define FPSCR_FPRF_FE_MASK (FPSCR_MASK (FPSCR_FPRF_FE)) + FPSCR_FPRF_FU, /* result unordered */ ++#define FPSCR_FPRF_FU_MASK (FPSCR_MASK (FPSCR_FPRF_FU)) + FPSCR_20, /* reserved */ + FPSCR_VXSOFT, /* invalid operation set by software */ ++#define FPSCR_VXSOFT_MASK (FPSCR_MASK (FPSCR_VXSOFT)) + FPSCR_VXSQRT, /* invalid operation for square root */ ++#define FPSCR_VXSQRT_MASK (FPSCR_MASK (FPSCR_VXSQRT)) + FPSCR_VXCVI, /* invalid operation for invalid integer convert */ ++#define FPSCR_VXCVI_MASK (FPSCR_MASK (FPSCR_VXCVI)) + FPSCR_VE, /* invalid operation exception enable */ ++#define FPSCR_VE_MASK (FPSCR_MASK (FPSCR_VE)) + FPSCR_OE, /* overflow exception enable */ ++#define FPSCR_OE_MASK (FPSCR_MASK (FPSCR_OE)) + FPSCR_UE, /* underflow exception enable */ ++#define FPSCR_UE_MASK (FPSCR_MASK (FPSCR_UE)) + FPSCR_ZE, /* zero divide exception enable */ ++#define FPSCR_ZE_MASK (FPSCR_MASK (FPSCR_ZE)) + FPSCR_XE, /* inexact exception enable */ ++#define FPSCR_XE_MASK (FPSCR_MASK (FPSCR_XE)) + #ifdef _ARCH_PWR6 + FPSCR_29, /* Reserved in ISA 2.05 */ ++#define FPSCR_NI_MASK (FPSCR_MASK (FPSCR_29)) + #else +- FPSCR_NI /* non-IEEE mode (typically, no denormalised numbers) */ ++ FPSCR_NI, /* non-IEEE mode (typically, no denormalised numbers) */ ++#define FPSCR_NI_MASK (FPSCR_MASK (FPSCR_NI)) + #endif /* _ARCH_PWR6 */ + /* the remaining two least-significant bits keep the rounding mode */ ++ FPSCR_RN_hi, ++#define FPSCR_RN_hi_MASK (FPSCR_MASK (FPSCR_RN_hi)) ++ FPSCR_RN_lo ++#define FPSCR_RN_lo_MASK (FPSCR_MASK (FPSCR_RN_lo)) + }; + ++#define FPSCR_RN_MASK (FPSCR_RN_hi_MASK|FPSCR_RN_lo_MASK) ++#define FPSCR_ENABLES_MASK \ ++ (FPSCR_VE_MASK|FPSCR_OE_MASK|FPSCR_UE_MASK|FPSCR_ZE_MASK|FPSCR_XE_MASK) ++#define FPSCR_BASIC_EXCEPTIONS_MASK \ ++ (FPSCR_VX_MASK|FPSCR_OX_MASK|FPSCR_UX_MASK|FPSCR_ZX_MASK|FPSCR_XX_MASK) ++ ++#define FPSCR_CONTROL_MASK (FPSCR_ENABLES_MASK|FPSCR_NI_MASK|FPSCR_RN_MASK) ++ ++/* The bits in the FENV(1) ABI for exceptions correspond one-to-one with bits ++ in the FPSCR, albeit shifted to different but corresponding locations. ++ Similarly, the exception indicator bits in the FPSCR correspond one-to-one ++ with the exception enable bits. It is thus possible to map the FENV(1) ++ exceptions directly to the FPSCR enables with a simple mask and shift, ++ and vice versa. */ ++#define FPSCR_EXCEPT_TO_ENABLE_SHIFT 22 ++ + static inline int + fenv_reg_to_exceptions (unsigned long long l) + { +- int result = 0; +- if (l & (1 << (31 - FPSCR_XE))) +- result |= FE_INEXACT; +- if (l & (1 << (31 - FPSCR_ZE))) +- result |= FE_DIVBYZERO; +- if (l & (1 << (31 - FPSCR_UE))) +- result |= FE_UNDERFLOW; +- if (l & (1 << (31 - FPSCR_OE))) +- result |= FE_OVERFLOW; +- if (l & (1 << (31 - FPSCR_VE))) +- result |= FE_INVALID; +- return result; ++ return (((int)l) & FPSCR_ENABLES_MASK) << FPSCR_EXCEPT_TO_ENABLE_SHIFT; ++} ++ ++static inline unsigned long long ++fenv_exceptions_to_reg (int excepts) ++{ ++ return (unsigned long long) ++ (excepts & FE_ALL_EXCEPT) >> FPSCR_EXCEPT_TO_ENABLE_SHIFT; + } + + #ifdef _ARCH_PWR6 diff --git a/SOURCES/glibc-rh1783303-7.patch b/SOURCES/glibc-rh1783303-7.patch new file mode 100644 index 0000000..a74f2eb --- /dev/null +++ b/SOURCES/glibc-rh1783303-7.patch @@ -0,0 +1,174 @@ +commit 3c1766ea10043f2e9625f3cba3bda37c84b32cf0 +Author: Paul A. Clarke +Date: Thu Jul 18 19:37:13 2019 -0500 + + [powerpc] fe{en,dis}ableexcept, fesetmode: optimize FPSCR accesses + + Since fe{en,dis}ableexcept() and fesetmode() read-modify-write just the + "mode" (exception enable and rounding mode) bits of the Floating Point Status + Control Register (FPSCR), the lighter weight 'mffsl' instruction can be used + to read the FPSCR (enables and rounding mode), and 'mtfsf 0b00000011' can be + used to write just those bits back to the FPSCR. The net is better performance. + + In addition, fe{en,dis}ableexcept() read the FPSCR again after writing it, or + they determine that it doesn't need to be written because it is not changing. + In either case, the local variable holds the current values of the enable + bits in the FPSCR. This local variable can be used instead of again reading + the FPSCR. + + Also, that value of the FPSCR which is read the second time is validated + against the requested enables. Since the write can't fail, this validation + step is unnecessary, and can be removed. Instead, the exceptions to be + enabled (or disabled) are transformed into available bits in the FPSCR, + then validated after being transformed back, to ensure that all requested + bits are actually being set. For example, FE_INVALID_SQRT can be + requested, but cannot actually be set. This bit is not mapped during the + transformations, so a test for that bit being set before and after + transformations will show the bit would not be set, and the function will + return -1 for failure. + + Finally, convert the local macros in fesetmode.c to more generally useful + macros in fenv_libc.h. + +diff --git a/sysdeps/powerpc/fpu/fedisblxcpt.c b/sysdeps/powerpc/fpu/fedisblxcpt.c +index 90bc3d12c6d8558c..2a776c72fb5a2b70 100644 +--- a/sysdeps/powerpc/fpu/fedisblxcpt.c ++++ b/sysdeps/powerpc/fpu/fedisblxcpt.c +@@ -26,23 +26,25 @@ fedisableexcept (int excepts) + int result, new; + + /* Get current exception mask to return. */ +- fe.fenv = curr.fenv = fegetenv_register (); ++ fe.fenv = curr.fenv = fegetenv_status (); + result = fenv_reg_to_exceptions (fe.l); + + if ((excepts & FE_ALL_INVALID) == FE_ALL_INVALID) + excepts = (excepts | FE_INVALID) & ~ FE_ALL_INVALID; + ++ new = fenv_exceptions_to_reg (excepts); ++ ++ if (fenv_reg_to_exceptions (new) != excepts) ++ return -1; ++ + /* Sets the new exception mask. */ +- fe.l &= ~ fenv_exceptions_to_reg (excepts); ++ fe.l &= ~new; + + if (fe.l != curr.l) +- fesetenv_register (fe.fenv); ++ fesetenv_mode (fe.fenv); + +- new = __fegetexcept (); + if (new == 0 && result != 0) + (void)__fe_mask_env (); + +- if ((new & excepts) != 0) +- result = -1; + return result; + } +diff --git a/sysdeps/powerpc/fpu/feenablxcpt.c b/sysdeps/powerpc/fpu/feenablxcpt.c +index e029971b9a460c28..6f5a828e80965bfa 100644 +--- a/sysdeps/powerpc/fpu/feenablxcpt.c ++++ b/sysdeps/powerpc/fpu/feenablxcpt.c +@@ -26,24 +26,25 @@ feenableexcept (int excepts) + int result, new; + + /* Get current exception mask to return. */ +- fe.fenv = curr.fenv = fegetenv_register (); ++ fe.fenv = curr.fenv = fegetenv_status (); + result = fenv_reg_to_exceptions (fe.l); + + if ((excepts & FE_ALL_INVALID) == FE_ALL_INVALID) + excepts = (excepts | FE_INVALID) & ~ FE_ALL_INVALID; + ++ new = fenv_exceptions_to_reg (excepts); ++ ++ if (fenv_reg_to_exceptions (new) != excepts) ++ return -1; ++ + /* Sets the new exception mask. */ +- fe.l |= fenv_exceptions_to_reg (excepts); ++ fe.l |= new; + + if (fe.l != curr.l) +- fesetenv_register (fe.fenv); ++ fesetenv_mode (fe.fenv); + +- new = __fegetexcept (); + if (new != 0 && result == 0) + (void) __fe_nomask_env_priv (); + +- if ((new & excepts) != excepts) +- result = -1; +- + return result; + } +diff --git a/sysdeps/powerpc/fpu/fenv_libc.h b/sysdeps/powerpc/fpu/fenv_libc.h +index f9634a64d186c076..b244770d115ea7bb 100644 +--- a/sysdeps/powerpc/fpu/fenv_libc.h ++++ b/sysdeps/powerpc/fpu/fenv_libc.h +@@ -71,6 +71,11 @@ extern const fenv_t *__fe_mask_env (void) attribute_hidden; + asm volatile ("mtfsf 0xff,%0" : : "f" (d)); \ + } while(0) + ++/* Set the last 2 nibbles of the FPSCR, which contain the ++ exception enables and the rounding mode. ++ 'fegetenv_status' retrieves these bits by reading the FPSCR. */ ++#define fesetenv_mode(env) __builtin_mtfsf (0b00000011, (env)); ++ + /* This very handy macro: + - Sets the rounding mode to 'round to nearest'; + - Sets the processor into IEEE mode; and +@@ -209,8 +214,11 @@ enum { + (FPSCR_VE_MASK|FPSCR_OE_MASK|FPSCR_UE_MASK|FPSCR_ZE_MASK|FPSCR_XE_MASK) + #define FPSCR_BASIC_EXCEPTIONS_MASK \ + (FPSCR_VX_MASK|FPSCR_OX_MASK|FPSCR_UX_MASK|FPSCR_ZX_MASK|FPSCR_XX_MASK) +- ++#define FPSCR_FPRF_MASK \ ++ (FPSCR_FPRF_C_MASK|FPSCR_FPRF_FL_MASK|FPSCR_FPRF_FG_MASK| \ ++ FPSCR_FPRF_FE_MASK|FPSCR_FPRF_FU_MASK) + #define FPSCR_CONTROL_MASK (FPSCR_ENABLES_MASK|FPSCR_NI_MASK|FPSCR_RN_MASK) ++#define FPSCR_STATUS_MASK (FPSCR_FR_MASK|FPSCR_FI_MASK|FPSCR_FPRF_MASK) + + /* The bits in the FENV(1) ABI for exceptions correspond one-to-one with bits + in the FPSCR, albeit shifted to different but corresponding locations. +diff --git a/sysdeps/powerpc/fpu/fesetmode.c b/sysdeps/powerpc/fpu/fesetmode.c +index 32203a24ff434a32..29e088d5ab1c0d93 100644 +--- a/sysdeps/powerpc/fpu/fesetmode.c ++++ b/sysdeps/powerpc/fpu/fesetmode.c +@@ -19,11 +19,6 @@ + #include + #include + +-#define _FPU_MASK_ALL (_FPU_MASK_ZM | _FPU_MASK_OM | _FPU_MASK_UM \ +- | _FPU_MASK_XM | _FPU_MASK_IM) +- +-#define FPU_STATUS 0xbffff700ULL +- + int + fesetmode (const femode_t *modep) + { +@@ -32,18 +27,18 @@ fesetmode (const femode_t *modep) + /* Logic regarding enabled exceptions as in fesetenv. */ + + new.fenv = *modep; +- old.fenv = fegetenv_register (); +- new.l = (new.l & ~FPU_STATUS) | (old.l & FPU_STATUS); ++ old.fenv = fegetenv_status (); ++ new.l = (new.l & ~FPSCR_STATUS_MASK) | (old.l & FPSCR_STATUS_MASK); + + if (old.l == new.l) + return 0; + +- if ((old.l & _FPU_MASK_ALL) == 0 && (new.l & _FPU_MASK_ALL) != 0) ++ if ((old.l & FPSCR_ENABLES_MASK) == 0 && (new.l & FPSCR_ENABLES_MASK) != 0) + (void) __fe_nomask_env_priv (); + +- if ((old.l & _FPU_MASK_ALL) != 0 && (new.l & _FPU_MASK_ALL) == 0) ++ if ((old.l & FPSCR_ENABLES_MASK) != 0 && (new.l & FPSCR_ENABLES_MASK) == 0) + (void) __fe_mask_env (); + +- fesetenv_register (new.fenv); ++ fesetenv_mode (new.fenv); + return 0; + } diff --git a/SOURCES/glibc-rh1783303-8.patch b/SOURCES/glibc-rh1783303-8.patch new file mode 100644 index 0000000..142e3bb --- /dev/null +++ b/SOURCES/glibc-rh1783303-8.patch @@ -0,0 +1,124 @@ +commit e905212627350d54b58426214b5a54ddc852b0c9 +Author: Paul A. Clarke +Date: Fri Aug 2 22:47:57 2019 -0400 + + [powerpc] SET_RESTORE_ROUND improvements + + SET_RESTORE_ROUND uses libc_feholdsetround_ppc_ctx and + libc_feresetround_ppc_ctx to bracket a block of code where the floating point + rounding mode must be set to a certain value. + + For the *prologue*, libc_feholdsetround_ppc_ctx is used and performs: + 1. Read/save FPSCR. + 2. Create new value for FPSCR with new rounding mode and enables cleared. + 3. If new value is different than current value, + a. If transitioning from a state where some exceptions enabled, + enter "ignore exceptions / non-stop" mode. + b. Write new value to FPSCR. + c. Put a mark on the wall indicating the FPSCR was changed. + + (1) uses the 'mffs' instruction. On POWER9, the lighter weight 'mffsl' + instruction can be used, but it doesn't return all of the bits in the FPSCR. + fegetenv_status uses 'mffsl' on POWER9, 'mffs' otherwise, and can thus be + used instead of fegetenv_register. + (3b) uses 'mtfsf 0b11111111' to write the entire FPSCR, so it must + instead use 'mtfsf 0b00000011' to write just the enables and the mode, + because some of the rest of the bits are not valid if 'mffsl' was used. + fesetenv_mode uses 'mtfsf 0b00000011' on POWER9, 'mtfsf 0b11111111' + otherwise. + + For the *epilogue*, libc_feresetround_ppc_ctx checks the mark on the wall, then + calls libc_feresetround_ppc, which just calls __libc_femergeenv_ppc with + parameters such that it performs: + 1. Retreive saved value of FPSCR, saved in prologue above. + 2. Read FPSCR. + 3. Create new value of FPSCR where: + - Summary bits and exception indicators = current OR saved. + - Rounding mode and enables = saved. + - Status bits = current. + 4. If transitioning from some exceptions enabled to none, + enter "ignore exceptions / non-stop" mode. + 5. If transitioning from no exceptions enabled to some, + enter "catch exceptions" mode. + 6. Write new value to FPSCR. + + The summary bits are hardwired to the exception indicators, so there is no + need to restore any saved summary bits. + The exception indicator bits, which are sticky and remain set unless + explicitly cleared, would only need to be restored if the code block + might explicitly clear any of them. This is certainly not expected. + + So, the only bits that need to be restored are the enables and the mode. + If it is the case that only those bits are to be restored, there is no need to + read the FPSCR. Steps (2) and (3) are unnecessary, and step (6) only needs to + write the bits being restored. + + We know we are transitioning out of "ignore exceptions" mode, so step (4) is + unnecessary, and in step (6), we only need to check the state we are + entering. + +diff --git a/sysdeps/powerpc/fpu/fenv_private.h b/sysdeps/powerpc/fpu/fenv_private.h +index 945ab98018450092..b0149aa243e69f5a 100644 +--- a/sysdeps/powerpc/fpu/fenv_private.h ++++ b/sysdeps/powerpc/fpu/fenv_private.h +@@ -132,7 +132,17 @@ libc_fesetenv_ppc (const fenv_t *envp) + static __always_inline void + libc_feresetround_ppc (fenv_t *envp) + { +- __libc_femergeenv_ppc (envp, _FPU_MASK_TRAPS_RN, _FPU_MASK_FRAC_INEX_RET_CC); ++ fenv_union_t new = { .fenv = *envp }; ++ ++ /* If the old env has no enabled exceptions and the new env has any enabled ++ exceptions, then unmask SIGFPE in the MSR FE0/FE1 bits. This will put the ++ hardware into "precise mode" and may cause the FPU to run slower on some ++ hardware. */ ++ if ((new.l & _FPU_ALL_TRAPS) != 0) ++ (void) __fe_nomask_env_priv (); ++ ++ /* Atomically enable and raise (if appropriate) exceptions set in `new'. */ ++ fesetenv_mode (new.fenv); + } + + static __always_inline int +@@ -176,9 +186,30 @@ libc_feholdsetround_ppc_ctx (struct rm_ctx *ctx, int r) + { + fenv_union_t old, new; + ++ old.fenv = fegetenv_status (); ++ ++ new.l = (old.l & ~(FPSCR_ENABLES_MASK|FPSCR_RN_MASK)) | r; ++ ++ ctx->env = old.fenv; ++ if (__glibc_unlikely (new.l != old.l)) ++ { ++ if ((old.l & _FPU_ALL_TRAPS) != 0) ++ (void) __fe_mask_env (); ++ fesetenv_mode (new.fenv); ++ ctx->updated_status = true; ++ } ++ else ++ ctx->updated_status = false; ++} ++ ++static __always_inline void ++libc_feholdsetround_noex_ppc_ctx (struct rm_ctx *ctx, int r) ++{ ++ fenv_union_t old, new; ++ + old.fenv = fegetenv_register (); + +- new.l = (old.l & _FPU_MASK_TRAPS_RN) | r; ++ new.l = (old.l & ~(FPSCR_ENABLES_MASK|FPSCR_RN_MASK)) | r; + + ctx->env = old.fenv; + if (__glibc_unlikely (new.l != old.l)) +@@ -218,6 +249,9 @@ libc_feresetround_ppc_ctx (struct rm_ctx *ctx) + #define libc_feholdsetround_ctx libc_feholdsetround_ppc_ctx + #define libc_feholdsetroundf_ctx libc_feholdsetround_ppc_ctx + #define libc_feholdsetroundl_ctx libc_feholdsetround_ppc_ctx ++#define libc_feholdsetround_noex_ctx libc_feholdsetround_noex_ppc_ctx ++#define libc_feholdsetround_noexf_ctx libc_feholdsetround_noex_ppc_ctx ++#define libc_feholdsetround_noexl_ctx libc_feholdsetround_noex_ppc_ctx + #define libc_feresetround_ctx libc_feresetround_ppc_ctx + #define libc_feresetroundf_ctx libc_feresetround_ppc_ctx + #define libc_feresetroundl_ctx libc_feresetround_ppc_ctx diff --git a/SOURCES/glibc-rh1783303-9.patch b/SOURCES/glibc-rh1783303-9.patch new file mode 100644 index 0000000..e151082 --- /dev/null +++ b/SOURCES/glibc-rh1783303-9.patch @@ -0,0 +1,61 @@ +commit fec2bd2c2d31bc731cf61623e150d047746954bd +Author: Paul A. Clarke +Date: Tue Aug 6 00:13:45 2019 -0400 + + [powerpc] fesetenv: optimize FPSCR access + + fesetenv() reads the current value of the Floating-Point Status and Control + Register (FPSCR) to determine the difference between the current state of + exception enables and the newly requested state. All of these bits are also + returned by the lighter weight 'mffsl' instruction used by fegetenv_status(). + Use that instead. + + Also, remove a local macro _FPU_MASK_ALL in favor of a common macro, + FPU_ENABLES_MASK from fenv_libc.h. + + Finally, use a local variable ('new') in favor of a pointer dereference + ('*envp'). + +diff --git a/sysdeps/powerpc/fpu/fesetenv.c b/sysdeps/powerpc/fpu/fesetenv.c +index ad9fda15b12f15e3..ac927c8f3ada40b4 100644 +--- a/sysdeps/powerpc/fpu/fesetenv.c ++++ b/sysdeps/powerpc/fpu/fesetenv.c +@@ -19,8 +19,6 @@ + #include + #include + +-#define _FPU_MASK_ALL (_FPU_MASK_ZM | _FPU_MASK_OM | _FPU_MASK_UM | _FPU_MASK_XM | _FPU_MASK_IM) +- + int + __fesetenv (const fenv_t *envp) + { +@@ -28,25 +26,23 @@ __fesetenv (const fenv_t *envp) + + /* get the currently set exceptions. */ + new.fenv = *envp; +- old.fenv = fegetenv_register (); +- if (old.l == new.l) +- return 0; ++ old.fenv = fegetenv_status (); + + /* If the old env has no enabled exceptions and the new env has any enabled + exceptions, then unmask SIGFPE in the MSR FE0/FE1 bits. This will put the + hardware into "precise mode" and may cause the FPU to run slower on some + hardware. */ +- if ((old.l & _FPU_MASK_ALL) == 0 && (new.l & _FPU_MASK_ALL) != 0) ++ if ((old.l & FPSCR_ENABLES_MASK) == 0 && (new.l & FPSCR_ENABLES_MASK) != 0) + (void) __fe_nomask_env_priv (); + + /* If the old env had any enabled exceptions and the new env has no enabled + exceptions, then mask SIGFPE in the MSR FE0/FE1 bits. This may allow the + FPU to run faster because it always takes the default action and can not + generate SIGFPE. */ +- if ((old.l & _FPU_MASK_ALL) != 0 && (new.l & _FPU_MASK_ALL) == 0) ++ if ((old.l & FPSCR_ENABLES_MASK) != 0 && (new.l & FPSCR_ENABLES_MASK) == 0) + (void)__fe_mask_env (); + +- fesetenv_register (*envp); ++ fesetenv_register (new.fenv); + + /* Success. */ + return 0; diff --git a/SOURCES/glibc-rh1784519.patch b/SOURCES/glibc-rh1784519.patch new file mode 100644 index 0000000..c9779d1 --- /dev/null +++ b/SOURCES/glibc-rh1784519.patch @@ -0,0 +1,29 @@ +commit 953ceff17a4a15b10cfdd5edc3c8cae4884c8ec3 +Author: Kamlesh Kumar +Date: Thu Dec 5 16:49:00 2019 +0100 + + : Define __CORRECT_ISO_CPP_STRING_H_PROTO for Clang [BZ #25232] + + Without the asm redirects, strchr et al. are not const-correct. + + libc++ has a wrapper header that works with and without + __CORRECT_ISO_CPP_STRING_H_PROTO (using a Clang extension). But when + Clang is used with libstdc++ or just C headers, the overloaded functions + with the correct types are not declared. + + This change does not impact current GCC (with libstdc++ or libc++). + +diff --git a/string/string.h b/string/string.h +index 73c22a535a..faf997b972 100644 +--- a/string/string.h ++++ b/string/string.h +@@ -33,7 +33,8 @@ __BEGIN_DECLS + #include + + /* Tell the caller that we provide correct C++ prototypes. */ +-#if defined __cplusplus && __GNUC_PREREQ (4, 4) ++#if defined __cplusplus && (__GNUC_PREREQ (4, 4) \ ++ || __glibc_clang_prereq (3, 5)) + # define __CORRECT_ISO_CPP_STRING_H_PROTO + #endif + diff --git a/SOURCES/glibc-rh1784520.patch b/SOURCES/glibc-rh1784520.patch new file mode 100644 index 0000000..90e9d77 --- /dev/null +++ b/SOURCES/glibc-rh1784520.patch @@ -0,0 +1,121 @@ +commit 16554464bcd9d77b07c6ff419dc54f00e394fa50 +Author: DJ Delorie +Date: Tue Dec 3 17:44:36 2019 -0500 + + Correct range checking in mallopt/mxfast/tcache [BZ #25194] + + do_set_tcache_max, do_set_mxfast: + Fix two instances of comparing "size_t < 0" + Both cases have upper limit, so the "negative value" case + is already handled via overflow semantics. + + do_set_tcache_max, do_set_tcache_count: + Fix return value on error. Note: currently not used. + + mallopt: + pass return value of helper functions to user. Behavior should + only be actually changed for mxfast, where we restore the old + (pre-tunables) behavior. + + Reviewed-by: Carlos O'Donell + +diff --git a/malloc/malloc.c b/malloc/malloc.c +index 90825b2aaed53761..00a37f218c0ab3b2 100644 +--- a/malloc/malloc.c ++++ b/malloc/malloc.c +@@ -5111,13 +5111,14 @@ static inline int + __always_inline + do_set_tcache_max (size_t value) + { +- if (value >= 0 && value <= MAX_TCACHE_SIZE) ++ if (value <= MAX_TCACHE_SIZE) + { + LIBC_PROBE (memory_tunable_tcache_max_bytes, 2, value, mp_.tcache_max_bytes); + mp_.tcache_max_bytes = value; + mp_.tcache_bins = csize2tidx (request2size(value)) + 1; ++ return 1; + } +- return 1; ++ return 0; + } + + static inline int +@@ -5128,8 +5129,9 @@ do_set_tcache_count (size_t value) + { + LIBC_PROBE (memory_tunable_tcache_count, 2, value, mp_.tcache_count); + mp_.tcache_count = value; ++ return 1; + } +- return 1; ++ return 0; + } + + static inline int +@@ -5146,7 +5148,7 @@ static inline int + __always_inline + do_set_mxfast (size_t value) + { +- if (value >= 0 && value <= MAX_FAST_SIZE) ++ if (value <= MAX_FAST_SIZE) + { + LIBC_PROBE (memory_mallopt_mxfast, 2, value, get_max_fast ()); + set_max_fast (value); +@@ -5171,18 +5173,24 @@ __libc_mallopt (int param_number, int value) + (see definition of set_max_fast). */ + malloc_consolidate (av); + ++ /* Many of these helper functions take a size_t. We do not worry ++ about overflow here, because negative int values will wrap to ++ very large size_t values and the helpers have sufficient range ++ checking for such conversions. Many of these helpers are also ++ used by the tunables macros in arena.c. */ ++ + switch (param_number) + { + case M_MXFAST: +- do_set_mxfast (value); ++ res = do_set_mxfast (value); + break; + + case M_TRIM_THRESHOLD: +- do_set_trim_threshold (value); ++ res = do_set_trim_threshold (value); + break; + + case M_TOP_PAD: +- do_set_top_pad (value); ++ res = do_set_top_pad (value); + break; + + case M_MMAP_THRESHOLD: +@@ -5190,25 +5198,25 @@ __libc_mallopt (int param_number, int value) + break; + + case M_MMAP_MAX: +- do_set_mmaps_max (value); ++ res = do_set_mmaps_max (value); + break; + + case M_CHECK_ACTION: +- do_set_mallopt_check (value); ++ res = do_set_mallopt_check (value); + break; + + case M_PERTURB: +- do_set_perturb_byte (value); ++ res = do_set_perturb_byte (value); + break; + + case M_ARENA_TEST: + if (value > 0) +- do_set_arena_test (value); ++ res = do_set_arena_test (value); + break; + + case M_ARENA_MAX: + if (value > 0) +- do_set_arena_max (value); ++ res = do_set_arena_max (value); + break; + } + __libc_lock_unlock (av->mutex); diff --git a/SOURCES/glibc-rh1784525.patch b/SOURCES/glibc-rh1784525.patch new file mode 100644 index 0000000..3a5f000 --- /dev/null +++ b/SOURCES/glibc-rh1784525.patch @@ -0,0 +1,29 @@ +commit ef21bd2d8c6805c0c186a01f7c5039189f51b8c4 +Author: DJ Delorie +Date: Fri Oct 18 17:15:52 2019 -0400 + + loadarchive: guard against locale-archive corruption (Bug #25115) + + _nl_load_locale_from_archive() checks for a zero size, but + divides by both (size) and (size-2). Extend the check to + guard against a size of two or less. + + Tested by manually corrupting locale-archive and running a program + that calls setlocale() with LOCPATH unset (size is typically very + large). + + Reviewed-by: Carlos O'Donell + +diff --git a/locale/loadarchive.c b/locale/loadarchive.c +index 516d30d8d16bd578..b308fd886f44e1fd 100644 +--- a/locale/loadarchive.c ++++ b/locale/loadarchive.c +@@ -274,7 +274,7 @@ _nl_load_locale_from_archive (int category, const char **namep) + + head->namehash_offset); + + /* Avoid division by 0 if the file is corrupted. */ +- if (__glibc_unlikely (head->namehash_size == 0)) ++ if (__glibc_unlikely (head->namehash_size <= 2)) + goto close_and_out; + + idx = hval % head->namehash_size; diff --git a/SOURCES/glibc-rh1810142-1.patch b/SOURCES/glibc-rh1810142-1.patch new file mode 100644 index 0000000..4a6d2e9 --- /dev/null +++ b/SOURCES/glibc-rh1810142-1.patch @@ -0,0 +1,382 @@ +From: Florian Weimer +Date: Tue, 11 Feb 2020 12:52:06 +0000 (+0100) +Subject: Add internal header file +X-Git-Url: https://sourceware.org/git/?p=glibc.git;a=commitdiff_plain;h=6c80c6e8767b860a5e18e136d04a80be2a8dce15 + +Add internal header file + +The code started out with bits form resolv/resolv_conf.c, but it +was enhanced to deal with directories and FIFOs in a more predictable +manner. A test case is included as well. + +This will be used to implement the /etc/resolv.conf change detection. + +This currently lives in a header file only. Once there are multiple +users, the implementations should be moved into C files. +--- + +diff -rupN a/include/file_change_detection.h b/include/file_change_detection.h +--- a/include/file_change_detection.h 1969-12-31 19:00:00.000000000 -0500 ++++ b/include/file_change_detection.h 2020-03-25 16:57:24.227929816 -0400 +@@ -0,0 +1,140 @@ ++/* Detecting file changes using modification times. ++ Copyright (C) 2017-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 ++ ++/* Items for identifying a particular file version. Excerpt from ++ struct stat64. */ ++struct file_change_detection ++{ ++ /* Special values: 0 if file does not exist. -1 to force mismatch ++ with the next comparison. */ ++ off64_t size; ++ ++ ino64_t ino; ++ struct timespec mtime; ++ struct timespec ctime; ++}; ++ ++/* Returns true if *LEFT and *RIGHT describe the same version of the ++ same file. */ ++static bool __attribute__ ((unused)) ++file_is_unchanged (const struct file_change_detection *left, ++ const struct file_change_detection *right) ++{ ++ if (left->size < 0 || right->size < 0) ++ /* Negative sizes are used as markers and never match. */ ++ return false; ++ else if (left->size == 0 && right->size == 0) ++ /* Both files are empty or do not exist, so they have the same ++ content, no matter what the other fields indicate. */ ++ return true; ++ else ++ return left->size == right->size ++ && left->ino == right->ino ++ && left->mtime.tv_sec == right->mtime.tv_sec ++ && left->mtime.tv_nsec == right->mtime.tv_nsec ++ && left->ctime.tv_sec == right->ctime.tv_sec ++ && left->ctime.tv_nsec == right->ctime.tv_nsec; ++} ++ ++/* Extract file change information to *FILE from the stat buffer ++ *ST. */ ++static void __attribute__ ((unused)) ++file_change_detection_for_stat (struct file_change_detection *file, ++ const struct stat64 *st) ++{ ++ if (S_ISDIR (st->st_mode)) ++ /* Treat as empty file. */ ++ file->size = 0; ++ else if (!S_ISREG (st->st_mode)) ++ /* Non-regular files cannot be cached. */ ++ file->size = -1; ++ else ++ { ++ file->size = st->st_size; ++ file->ino = st->st_ino; ++ file->mtime = st->st_mtim; ++ file->ctime = st->st_ctim; ++ } ++} ++ ++/* Writes file change information for PATH to *FILE. Returns true on ++ success. For benign errors, *FILE is cleared, and true is ++ returned. For errors indicating resource outages and the like, ++ false is returned. */ ++static bool __attribute__ ((unused)) ++file_change_detection_for_path (struct file_change_detection *file, ++ const char *path) ++{ ++ struct stat64 st; ++ if (stat64 (path, &st) != 0) ++ switch (errno) ++ { ++ case EACCES: ++ case EISDIR: ++ case ELOOP: ++ case ENOENT: ++ case ENOTDIR: ++ case EPERM: ++ /* Ignore errors due to file system contents. Instead, treat ++ the file as empty. */ ++ file->size = 0; ++ return true; ++ default: ++ /* Other errors are fatal. */ ++ return false; ++ } ++ else /* stat64 was successfull. */ ++ { ++ file_change_detection_for_stat (file, &st); ++ return true; ++ } ++} ++ ++/* Writes file change information for the stream FP to *FILE. Returns ++ ture on success, false on failure. If FP is NULL, treat the file ++ as non-existing. */ ++static bool __attribute__ ((unused)) ++file_change_detection_for_fp (struct file_change_detection *file, ++ FILE *fp) ++{ ++ if (fp == NULL) ++ { ++ /* The file does not exist. */ ++ file->size = 0; ++ return true; ++ } ++ else ++ { ++ struct stat64 st; ++ if (fstat64 (__fileno (fp), &st) != 0) ++ /* If we already have a file descriptor, all errors are fatal. */ ++ return false; ++ else ++ { ++ file_change_detection_for_stat (file, &st); ++ return true; ++ } ++ } ++} +diff -rupN a/io/Makefile b/io/Makefile +--- a/io/Makefile 2020-03-25 16:55:42.442195992 -0400 ++++ b/io/Makefile 2020-03-25 16:58:48.571023810 -0400 +@@ -74,6 +74,7 @@ tests := test-utime test-stat test-stat + tst-posix_fallocate tst-posix_fallocate64 \ + tst-fts tst-fts-lfs tst-open-tmpfile \ + tst-copy_file_range tst-getcwd-abspath \ ++ tst-file_change_detection + + # Likewise for statx, but we do not need static linking here. + tests-internal += tst-statx +diff -rupN a/io/tst-file_change_detection.c b/io/tst-file_change_detection.c +--- a/io/tst-file_change_detection.c 1969-12-31 19:00:00.000000000 -0500 ++++ b/io/tst-file_change_detection.c 2020-03-25 16:57:24.242930366 -0400 +@@ -0,0 +1,206 @@ ++/* Test for . ++ 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 ++ . */ ++ ++/* The header uses the internal __fileno symbol, which is not ++ available outside of libc (even to internal tests). */ ++#define __fileno(fp) fileno (fp) ++ ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++static void ++all_same (struct file_change_detection *array, size_t length) ++{ ++ for (size_t i = 0; i < length; ++i) ++ for (size_t j = 0; j < length; ++j) ++ { ++ if (test_verbose > 0) ++ printf ("info: comparing %zu and %zu\n", i, j); ++ TEST_VERIFY (file_is_unchanged (array + i, array + j)); ++ } ++} ++ ++static void ++all_different (struct file_change_detection *array, size_t length) ++{ ++ for (size_t i = 0; i < length; ++i) ++ for (size_t j = 0; j < length; ++j) ++ { ++ if (i == j) ++ continue; ++ if (test_verbose > 0) ++ printf ("info: comparing %zu and %zu\n", i, j); ++ TEST_VERIFY (!file_is_unchanged (array + i, array + j)); ++ } ++} ++ ++static int ++do_test (void) ++{ ++ /* Use a temporary directory with various paths. */ ++ char *tempdir = support_create_temp_directory ("tst-file_change_detection-"); ++ ++ char *path_dangling = xasprintf ("%s/dangling", tempdir); ++ char *path_does_not_exist = xasprintf ("%s/does-not-exist", tempdir); ++ char *path_empty1 = xasprintf ("%s/empty1", tempdir); ++ char *path_empty2 = xasprintf ("%s/empty2", tempdir); ++ char *path_fifo = xasprintf ("%s/fifo", tempdir); ++ char *path_file1 = xasprintf ("%s/file1", tempdir); ++ char *path_file2 = xasprintf ("%s/file2", tempdir); ++ char *path_loop = xasprintf ("%s/loop", tempdir); ++ char *path_to_empty1 = xasprintf ("%s/to-empty1", tempdir); ++ char *path_to_file1 = xasprintf ("%s/to-file1", tempdir); ++ ++ add_temp_file (path_dangling); ++ add_temp_file (path_empty1); ++ add_temp_file (path_empty2); ++ add_temp_file (path_fifo); ++ add_temp_file (path_file1); ++ add_temp_file (path_file2); ++ add_temp_file (path_loop); ++ add_temp_file (path_to_empty1); ++ add_temp_file (path_to_file1); ++ ++ xsymlink ("target-does-not-exist", path_dangling); ++ support_write_file_string (path_empty1, ""); ++ support_write_file_string (path_empty2, ""); ++ TEST_COMPARE (mknod (path_fifo, 0777 | S_IFIFO, 0), 0); ++ support_write_file_string (path_file1, "line\n"); ++ support_write_file_string (path_file2, "line\n"); ++ xsymlink ("loop", path_loop); ++ xsymlink ("empty1", path_to_empty1); ++ xsymlink ("file1", path_to_file1); ++ ++ FILE *fp_file1 = xfopen (path_file1, "r"); ++ FILE *fp_file2 = xfopen (path_file2, "r"); ++ FILE *fp_empty1 = xfopen (path_empty1, "r"); ++ FILE *fp_empty2 = xfopen (path_empty2, "r"); ++ ++ /* Test for the same (empty) files. */ ++ { ++ struct file_change_detection fcd[10]; ++ int i = 0; ++ /* Two empty files always have the same contents. */ ++ TEST_VERIFY (file_change_detection_for_path (&fcd[i++], path_empty1)); ++ TEST_VERIFY (file_change_detection_for_path (&fcd[i++], path_empty2)); ++ /* So does a missing file (which is treated as empty). */ ++ TEST_VERIFY (file_change_detection_for_path (&fcd[i++], ++ path_does_not_exist)); ++ /* And a symbolic link loop. */ ++ TEST_VERIFY (file_change_detection_for_path (&fcd[i++], path_loop)); ++ /* And a dangling symbolic link. */ ++ TEST_VERIFY (file_change_detection_for_path (&fcd[i++], path_dangling)); ++ /* And a directory. */ ++ TEST_VERIFY (file_change_detection_for_path (&fcd[i++], tempdir)); ++ /* And a symbolic link to an empty file. */ ++ TEST_VERIFY (file_change_detection_for_path (&fcd[i++], path_to_empty1)); ++ /* Likewise for access the file via a FILE *. */ ++ TEST_VERIFY (file_change_detection_for_fp (&fcd[i++], fp_empty1)); ++ TEST_VERIFY (file_change_detection_for_fp (&fcd[i++], fp_empty2)); ++ /* And a NULL FILE * (missing file). */ ++ TEST_VERIFY (file_change_detection_for_fp (&fcd[i++], NULL)); ++ TEST_COMPARE (i, array_length (fcd)); ++ ++ all_same (fcd, array_length (fcd)); ++ } ++ ++ /* Symbolic links are resolved. */ ++ { ++ struct file_change_detection fcd[3]; ++ int i = 0; ++ TEST_VERIFY (file_change_detection_for_path (&fcd[i++], path_file1)); ++ TEST_VERIFY (file_change_detection_for_path (&fcd[i++], path_to_file1)); ++ TEST_VERIFY (file_change_detection_for_fp (&fcd[i++], fp_file1)); ++ TEST_COMPARE (i, array_length (fcd)); ++ all_same (fcd, array_length (fcd)); ++ } ++ ++ /* Test for different files. */ ++ { ++ struct file_change_detection fcd[5]; ++ int i = 0; ++ /* The other files are not empty. */ ++ TEST_VERIFY (file_change_detection_for_path (&fcd[i++], path_empty1)); ++ /* These two files have the same contents, but have different file ++ identity. */ ++ TEST_VERIFY (file_change_detection_for_path (&fcd[i++], path_file1)); ++ TEST_VERIFY (file_change_detection_for_path (&fcd[i++], path_file2)); ++ /* FIFOs are always different, even with themselves. */ ++ TEST_VERIFY (file_change_detection_for_path (&fcd[i++], path_fifo)); ++ TEST_VERIFY (file_change_detection_for_path (&fcd[i++], path_fifo)); ++ TEST_COMPARE (i, array_length (fcd)); ++ all_different (fcd, array_length (fcd)); ++ ++ /* Replacing the file with its symbolic link does not make a ++ difference. */ ++ TEST_VERIFY (file_change_detection_for_path (&fcd[1], path_to_file1)); ++ all_different (fcd, array_length (fcd)); ++ } ++ ++ /* Wait for a file change. Depending on file system time stamp ++ resolution, this subtest blocks for a while. */ ++ for (int use_stdio = 0; use_stdio < 2; ++use_stdio) ++ { ++ struct file_change_detection initial; ++ TEST_VERIFY (file_change_detection_for_path (&initial, path_file1)); ++ while (true) ++ { ++ support_write_file_string (path_file1, "line\n"); ++ struct file_change_detection current; ++ if (use_stdio) ++ TEST_VERIFY (file_change_detection_for_fp (¤t, fp_file1)); ++ else ++ TEST_VERIFY (file_change_detection_for_path (¤t, path_file1)); ++ if (!file_is_unchanged (&initial, ¤t)) ++ break; ++ /* Wait for a bit to reduce system load. */ ++ usleep (100 * 1000); ++ } ++ } ++ ++ fclose (fp_empty1); ++ fclose (fp_empty2); ++ fclose (fp_file1); ++ fclose (fp_file2); ++ ++ free (path_dangling); ++ free (path_does_not_exist); ++ free (path_empty1); ++ free (path_empty2); ++ free (path_fifo); ++ free (path_file1); ++ free (path_file2); ++ free (path_loop); ++ free (path_to_empty1); ++ free (path_to_file1); ++ ++ free (tempdir); ++ ++ return 0; ++} ++ ++#include diff --git a/SOURCES/glibc-rh1810142-2.patch b/SOURCES/glibc-rh1810142-2.patch new file mode 100644 index 0000000..cd7b4e4 --- /dev/null +++ b/SOURCES/glibc-rh1810142-2.patch @@ -0,0 +1,94 @@ +From: Florian Weimer +Date: Tue, 21 Jan 2020 15:52:33 +0000 (+0100) +Subject: resolv: Use in __resolv_conf_get_current +X-Git-Url: https://sourceware.org/git/?p=glibc.git;a=commitdiff_plain;h=9642b85fd0dfa5731020a3271c08e33e1dc05c85 + +resolv: Use in __resolv_conf_get_current + +Only minor functional changes (i.e., regarding the handling of +directories, which are now treated as empty files). + +Reviewed-by: Adhemerval Zanella +--- + +diff --git a/resolv/resolv_conf.c b/resolv/resolv_conf.c +index 08c50ef19e..d954ba9a5a 100644 +--- a/resolv/resolv_conf.c ++++ b/resolv/resolv_conf.c +@@ -24,6 +24,7 @@ + #include + #include + #include ++#include + + /* _res._u._ext.__glibc_extension_index is used as an index into a + struct resolv_conf_array object. The intent of this construction +@@ -68,12 +69,8 @@ struct resolv_conf_global + /* Cached current configuration object for /etc/resolv.conf. */ + struct resolv_conf *conf_current; + +- /* These properties of /etc/resolv.conf are used to check if the +- configuration needs reloading. */ +- struct timespec conf_mtime; +- struct timespec conf_ctime; +- off64_t conf_size; +- ino64_t conf_ino; ++ /* File system identification for /etc/resolv.conf. */ ++ struct file_change_detection file_resolve_conf; + }; + + /* Lazily allocated storage for struct resolv_conf_global. */ +@@ -123,37 +120,16 @@ conf_decrement (struct resolv_conf *conf) + struct resolv_conf * + __resolv_conf_get_current (void) + { +- struct stat64 st; +- if (stat64 (_PATH_RESCONF, &st) != 0) +- { +- switch (errno) +- { +- case EACCES: +- case EISDIR: +- case ELOOP: +- case ENOENT: +- case ENOTDIR: +- case EPERM: +- /* Ignore errors due to file system contents. */ +- memset (&st, 0, sizeof (st)); +- break; +- default: +- /* Other errors are fatal. */ +- return NULL; +- } +- } ++ struct file_change_detection initial; ++ if (!file_change_detection_for_path (&initial, _PATH_RESCONF)) ++ return NULL; + + struct resolv_conf_global *global_copy = get_locked_global (); + if (global_copy == NULL) + return NULL; + struct resolv_conf *conf; + if (global_copy->conf_current != NULL +- && (global_copy->conf_mtime.tv_sec == st.st_mtim.tv_sec +- && global_copy->conf_mtime.tv_nsec == st.st_mtim.tv_nsec +- && global_copy->conf_ctime.tv_sec == st.st_ctim.tv_sec +- && global_copy->conf_ctime.tv_nsec == st.st_ctim.tv_nsec +- && global_copy->conf_ino == st.st_ino +- && global_copy->conf_size == st.st_size)) ++ && file_is_unchanged (&initial, &global_copy->file_resolve_conf)) + /* We can reuse the cached configuration object. */ + conf = global_copy->conf_current; + else +@@ -171,10 +147,7 @@ __resolv_conf_get_current (void) + read could be a newer version of the file, but this does + not matter because this will lead to an extraneous reload + later. */ +- global_copy->conf_mtime = st.st_mtim; +- global_copy->conf_ctime = st.st_ctim; +- global_copy->conf_ino = st.st_ino; +- global_copy->conf_size = st.st_size; ++ global_copy->file_resolve_conf = initial; + } + } + diff --git a/SOURCES/glibc-rh1810142-3.patch b/SOURCES/glibc-rh1810142-3.patch new file mode 100644 index 0000000..e13f74d --- /dev/null +++ b/SOURCES/glibc-rh1810142-3.patch @@ -0,0 +1,46 @@ +From: Florian Weimer +Date: Tue, 21 Jan 2020 16:11:01 +0000 (+0100) +Subject: resolv: Fix file handle leak in __resolv_conf_load [BZ #25429] +X-Git-Url: https://sourceware.org/git/?p=glibc.git;a=commitdiff_plain;h=a1a20f029299dc27170912bb9233070c8403444d + +resolv: Fix file handle leak in __resolv_conf_load [BZ #25429] + +res_vinit_1 did not close the stream on errors, only on success. +This change moves closing the stream to __resolv_conf_load, for both +the success and error cases. + +Fixes commit 89f187a40fc0ad4e22838526bfe34d73f758b776 ("resolv: Use +getline for configuration file reading in res_vinit_1") and commit +3f853f22c87f0b671c0366eb290919719fa56c0e ("resolv: Lift domain search +list limits [BZ #19569] [BZ #21475]"), where memory allocation was +introduced into res_vinit_1. + +Reviewed-by: Adhemerval Zanella +--- + +diff --git a/resolv/res_init.c b/resolv/res_init.c +index 95dce098aa..09345718cd 100644 +--- a/resolv/res_init.c ++++ b/resolv/res_init.c +@@ -508,7 +508,6 @@ res_vinit_1 (FILE *fp, struct resolv_conf_parser *parser) + continue; + } + } +- fclose (fp); + } + if (__glibc_unlikely (nameserver_list_size (&parser->nameserver_list) == 0)) + { +@@ -593,6 +592,13 @@ __resolv_conf_load (struct __res_state *preinit) + } + resolv_conf_parser_free (&parser); + ++ if (fp != NULL) ++ { ++ int saved_errno = errno; ++ fclose (fp); ++ __set_errno (saved_errno); ++ } ++ + return conf; + } + diff --git a/SOURCES/glibc-rh1810142-4.patch b/SOURCES/glibc-rh1810142-4.patch new file mode 100644 index 0000000..3d4ff39 --- /dev/null +++ b/SOURCES/glibc-rh1810142-4.patch @@ -0,0 +1,96 @@ +From: Florian Weimer +Date: Tue, 21 Jan 2020 16:25:39 +0000 (+0100) +Subject: resolv: Enhance __resolv_conf_load to capture file change data +X-Git-Url: https://sourceware.org/git/?p=glibc.git;a=commitdiff_plain;h=dd0b4df329ff7ff2a656404db271c8ee8379ff9d + +resolv: Enhance __resolv_conf_load to capture file change data + +The data is captured after reading the file. This allows callers +to check the change data against an earlier measurement. + +Reviewed-by: Adhemerval Zanella +--- + +diff --git a/resolv/res_init.c b/resolv/res_init.c +index 09345718cd..98d84f264d 100644 +--- a/resolv/res_init.c ++++ b/resolv/res_init.c +@@ -103,6 +103,7 @@ + #include + #include + #include ++#include + + static uint32_t net_mask (struct in_addr); + +@@ -549,7 +550,8 @@ res_vinit_1 (FILE *fp, struct resolv_conf_parser *parser) + } + + struct resolv_conf * +-__resolv_conf_load (struct __res_state *preinit) ++__resolv_conf_load (struct __res_state *preinit, ++ struct file_change_detection *change) + { + /* Ensure that /etc/hosts.conf has been loaded (once). */ + _res_hconf_init (); +@@ -577,7 +579,13 @@ __resolv_conf_load (struct __res_state *preinit) + resolv_conf_parser_init (&parser, preinit); + + struct resolv_conf *conf = NULL; +- if (res_vinit_1 (fp, &parser)) ++ bool ok = res_vinit_1 (fp, &parser); ++ if (ok && change != NULL) ++ /* Update the file change information if the configuration was ++ loaded successfully. */ ++ ok = file_change_detection_for_fp (change, fp); ++ ++ if (ok) + { + parser.template.nameserver_list + = nameserver_list_begin (&parser.nameserver_list); +@@ -615,7 +623,7 @@ __res_vinit (res_state statp, int preinit) + if (preinit && has_preinit_values (statp)) + /* For the preinit case, we cannot use the cached configuration + because some settings could be different. */ +- conf = __resolv_conf_load (statp); ++ conf = __resolv_conf_load (statp, NULL); + else + conf = __resolv_conf_get_current (); + if (conf == NULL) +diff --git a/resolv/resolv_conf.c b/resolv/resolv_conf.c +index d954ba9a5a..bdd2ebb909 100644 +--- a/resolv/resolv_conf.c ++++ b/resolv/resolv_conf.c +@@ -136,7 +136,7 @@ __resolv_conf_get_current (void) + { + /* Parse configuration while holding the lock. This avoids + duplicate work. */ +- conf = __resolv_conf_load (NULL); ++ conf = __resolv_conf_load (NULL, NULL); + if (conf != NULL) + { + if (global_copy->conf_current != NULL) +diff --git a/resolv/resolv_conf.h b/resolv/resolv_conf.h +index 01cbff9111..101e14bfe5 100644 +--- a/resolv/resolv_conf.h ++++ b/resolv/resolv_conf.h +@@ -63,12 +63,16 @@ struct resolv_conf + and the struct resolv_context facility. */ + + struct __res_state; ++struct file_change_detection; + + /* Read /etc/resolv.conf and return a configuration object, or NULL if + /etc/resolv.conf cannot be read due to memory allocation errors. +- If PREINIT is not NULL, some configuration values are taken from the +- struct __res_state object. */ +-struct resolv_conf *__resolv_conf_load (struct __res_state *preinit) ++ If PREINIT is not NULL, some configuration values are taken from ++ the struct __res_state object. If CHANGE is not null, file change ++ detection data is written to *CHANGE, based on the state of the ++ file after reading it. */ ++struct resolv_conf *__resolv_conf_load (struct __res_state *preinit, ++ struct file_change_detection *change) + attribute_hidden __attribute__ ((warn_unused_result)); + + /* Return a configuration object for the current /etc/resolv.conf diff --git a/SOURCES/glibc-rh1810142-5.patch b/SOURCES/glibc-rh1810142-5.patch new file mode 100644 index 0000000..be991b0 --- /dev/null +++ b/SOURCES/glibc-rh1810142-5.patch @@ -0,0 +1,52 @@ +From: Florian Weimer +Date: Tue, 21 Jan 2020 16:38:15 +0000 (+0100) +Subject: resolv: Fix ABA race in /etc/resolv.conf change detection [BZ #25420] +X-Git-Url: https://sourceware.org/git/?p=glibc.git;a=commitdiff_plain;h=fa00db0a6eb755837ae5d413515e0da582b304f3 + +resolv: Fix ABA race in /etc/resolv.conf change detection [BZ #25420] + +__resolv_conf_get_current should only record the initial file +change data if after verifying that file just read matches the +original measurement. Fixes commit aef16cc8a4c670036d45590877 +("resolv: Automatically reload a changed /etc/resolv.conf file +[BZ #984]"). + +Reviewed-by: Adhemerval Zanella +--- + +diff --git a/resolv/resolv_conf.c b/resolv/resolv_conf.c +index bdd2ebb909..29a1f4fb94 100644 +--- a/resolv/resolv_conf.c ++++ b/resolv/resolv_conf.c +@@ -136,18 +136,25 @@ __resolv_conf_get_current (void) + { + /* Parse configuration while holding the lock. This avoids + duplicate work. */ +- conf = __resolv_conf_load (NULL, NULL); ++ struct file_change_detection after_load; ++ conf = __resolv_conf_load (NULL, &after_load); + if (conf != NULL) + { + if (global_copy->conf_current != NULL) + conf_decrement (global_copy->conf_current); + global_copy->conf_current = conf; /* Takes ownership. */ + +- /* Update file modification stamps. The configuration we +- read could be a newer version of the file, but this does +- not matter because this will lead to an extraneous reload +- later. */ +- global_copy->file_resolve_conf = initial; ++ /* Update file change detection data, but only if it matches ++ the initial measurement. This avoids an ABA race in case ++ /etc/resolv.conf is temporarily replaced while the file ++ is read (after the initial measurement), and restored to ++ the initial version later. */ ++ if (file_is_unchanged (&initial, &after_load)) ++ global_copy->file_resolve_conf = after_load; ++ else ++ /* If there is a discrepancy, trigger a reload during the ++ next use. */ ++ global_copy->file_resolve_conf.size = -1; + } + } + diff --git a/SOURCES/glibc-rh1810142-6.patch b/SOURCES/glibc-rh1810142-6.patch new file mode 100644 index 0000000..8d96880 --- /dev/null +++ b/SOURCES/glibc-rh1810142-6.patch @@ -0,0 +1,481 @@ +From: Florian Weimer +Date: Tue, 18 Feb 2020 12:44:48 +0000 (+0100) +Subject: Move implementation of into a C file +X-Git-Url: https://sourceware.org/git/?p=glibc.git;a=commitdiff_plain;h=631cf64bc1d8306e011ef39f60b8cb6de91bd271 + +Move implementation of into a C file + +file_change_detection_for_stat partially initialize +struct file_change_detection in some cases, when the size member +alone determines the outcome of all comparisons. This results +in maybe-uninitialized compiler warnings in case of sufficiently +aggressive inlining. + +Once the implementation is moved into a separate C file, this kind +of inlining is no longer possible, so the compiler warnings are gone. +--- + +diff --git a/include/file_change_detection.h b/include/file_change_detection.h +index aaed0a9b6d..767e578555 100644 +--- a/include/file_change_detection.h ++++ b/include/file_change_detection.h +@@ -16,9 +16,10 @@ + License along with the GNU C Library; if not, see + . */ + +-#include ++#ifndef _FILE_CHANGE_DETECTION_H ++#define _FILE_CHANGE_DETECTION_H ++ + #include +-#include + #include + #include + #include +@@ -38,103 +39,32 @@ struct file_change_detection + + /* Returns true if *LEFT and *RIGHT describe the same version of the + same file. */ +-static bool __attribute__ ((unused)) +-file_is_unchanged (const struct file_change_detection *left, +- const struct file_change_detection *right) +-{ +- if (left->size < 0 || right->size < 0) +- /* Negative sizes are used as markers and never match. */ +- return false; +- else if (left->size == 0 && right->size == 0) +- /* Both files are empty or do not exist, so they have the same +- content, no matter what the other fields indicate. */ +- return true; +- else +- return left->size == right->size +- && left->ino == right->ino +- && left->mtime.tv_sec == right->mtime.tv_sec +- && left->mtime.tv_nsec == right->mtime.tv_nsec +- && left->ctime.tv_sec == right->ctime.tv_sec +- && left->ctime.tv_nsec == right->ctime.tv_nsec; +-} ++bool __file_is_unchanged (const struct file_change_detection *left, ++ const struct file_change_detection *right); + + /* Extract file change information to *FILE from the stat buffer + *ST. */ +-static void __attribute__ ((unused)) +-file_change_detection_for_stat (struct file_change_detection *file, +- const struct stat64 *st) +-{ +- if (S_ISDIR (st->st_mode)) +- /* Treat as empty file. */ +- file->size = 0; +- else if (!S_ISREG (st->st_mode)) +- /* Non-regular files cannot be cached. */ +- file->size = -1; +- else +- { +- file->size = st->st_size; +- file->ino = st->st_ino; +- file->mtime = st->st_mtim; +- file->ctime = st->st_ctim; +- } +-} ++void __file_change_detection_for_stat (struct file_change_detection *file, ++ const struct stat64 *st); + + /* Writes file change information for PATH to *FILE. Returns true on + success. For benign errors, *FILE is cleared, and true is + returned. For errors indicating resource outages and the like, + false is returned. */ +-static bool __attribute__ ((unused)) +-file_change_detection_for_path (struct file_change_detection *file, +- const char *path) +-{ +- struct stat64 st; +- if (stat64 (path, &st) != 0) +- switch (errno) +- { +- case EACCES: +- case EISDIR: +- case ELOOP: +- case ENOENT: +- case ENOTDIR: +- case EPERM: +- /* Ignore errors due to file system contents. Instead, treat +- the file as empty. */ +- file->size = 0; +- return true; +- default: +- /* Other errors are fatal. */ +- return false; +- } +- else /* stat64 was successfull. */ +- { +- file_change_detection_for_stat (file, &st); +- return true; +- } +-} ++bool __file_change_detection_for_path (struct file_change_detection *file, ++ const char *path); + + /* Writes file change information for the stream FP to *FILE. Returns + ture on success, false on failure. If FP is NULL, treat the file + as non-existing. */ +-static bool __attribute__ ((unused)) +-file_change_detection_for_fp (struct file_change_detection *file, +- FILE *fp) +-{ +- if (fp == NULL) +- { +- /* The file does not exist. */ +- file->size = 0; +- return true; +- } +- else +- { +- struct stat64 st; +- if (fstat64 (__fileno (fp), &st) != 0) +- /* If we already have a file descriptor, all errors are fatal. */ +- return false; +- else +- { +- file_change_detection_for_stat (file, &st); +- return true; +- } +- } +-} ++bool __file_change_detection_for_fp (struct file_change_detection *file, ++ FILE *fp); ++ ++#ifndef _ISOMAC ++libc_hidden_proto (__file_is_unchanged) ++libc_hidden_proto (__file_change_detection_for_stat) ++libc_hidden_proto (__file_change_detection_for_path) ++libc_hidden_proto (__file_change_detection_for_fp) ++#endif ++ ++#endif /* _FILE_CHANGE_DETECTION_H */ +diff --git a/io/Makefile b/io/Makefile +index 04c4647dc0..cf380f3516 100644 +--- a/io/Makefile ++++ b/io/Makefile +@@ -55,7 +55,7 @@ routines := \ + posix_fadvise posix_fadvise64 \ + posix_fallocate posix_fallocate64 \ + sendfile sendfile64 copy_file_range \ +- utimensat futimens ++ utimensat futimens file_change_detection + + # These routines will be omitted from the libc shared object. + # Instead the static object files will be included in a special archive +diff --git a/io/Versions b/io/Versions +index f7e5dbe49e..ee468055ff 100644 +--- a/io/Versions ++++ b/io/Versions +@@ -137,5 +137,9 @@ libc { + __fcntl_nocancel; + __open64_nocancel; + __write_nocancel; ++ __file_is_unchanged; ++ __file_change_detection_for_stat; ++ __file_change_detection_for_path; ++ __file_change_detection_for_fp; + } + } +diff --git a/io/file_change_detection.c b/io/file_change_detection.c +new file mode 100644 +index 0000000000..c6d700ed05 +--- /dev/null ++++ b/io/file_change_detection.c +@@ -0,0 +1,118 @@ ++/* Detecting file changes using modification times. ++ Copyright (C) 2017-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 ++ ++bool ++__file_is_unchanged (const struct file_change_detection *left, ++ const struct file_change_detection *right) ++{ ++ if (left->size < 0 || right->size < 0) ++ /* Negative sizes are used as markers and never match. */ ++ return false; ++ else if (left->size == 0 && right->size == 0) ++ /* Both files are empty or do not exist, so they have the same ++ content, no matter what the other fields indicate. */ ++ return true; ++ else ++ return left->size == right->size ++ && left->ino == right->ino ++ && left->mtime.tv_sec == right->mtime.tv_sec ++ && left->mtime.tv_nsec == right->mtime.tv_nsec ++ && left->ctime.tv_sec == right->ctime.tv_sec ++ && left->ctime.tv_nsec == right->ctime.tv_nsec; ++} ++libc_hidden_def (__file_is_unchanged) ++ ++void ++__file_change_detection_for_stat (struct file_change_detection *file, ++ const struct stat64 *st) ++{ ++ if (S_ISDIR (st->st_mode)) ++ /* Treat as empty file. */ ++ file->size = 0; ++ else if (!S_ISREG (st->st_mode)) ++ /* Non-regular files cannot be cached. */ ++ file->size = -1; ++ else ++ { ++ file->size = st->st_size; ++ file->ino = st->st_ino; ++ file->mtime = st->st_mtim; ++ file->ctime = st->st_ctim; ++ } ++} ++libc_hidden_def (__file_change_detection_for_stat) ++ ++bool ++__file_change_detection_for_path (struct file_change_detection *file, ++ const char *path) ++{ ++ struct stat64 st; ++ if (stat64 (path, &st) != 0) ++ switch (errno) ++ { ++ case EACCES: ++ case EISDIR: ++ case ELOOP: ++ case ENOENT: ++ case ENOTDIR: ++ case EPERM: ++ /* Ignore errors due to file system contents. Instead, treat ++ the file as empty. */ ++ file->size = 0; ++ return true; ++ default: ++ /* Other errors are fatal. */ ++ return false; ++ } ++ else /* stat64 was successfull. */ ++ { ++ __file_change_detection_for_stat (file, &st); ++ return true; ++ } ++} ++libc_hidden_def (__file_change_detection_for_path) ++ ++bool ++__file_change_detection_for_fp (struct file_change_detection *file, ++ FILE *fp) ++{ ++ if (fp == NULL) ++ { ++ /* The file does not exist. */ ++ file->size = 0; ++ return true; ++ } ++ else ++ { ++ struct stat64 st; ++ if (fstat64 (__fileno (fp), &st) != 0) ++ /* If we already have a file descriptor, all errors are fatal. */ ++ return false; ++ else ++ { ++ __file_change_detection_for_stat (file, &st); ++ return true; ++ } ++ } ++} ++libc_hidden_def (__file_change_detection_for_fp) +diff --git a/io/tst-file_change_detection.c b/io/tst-file_change_detection.c +index 035dd39c4d..6e00e787b1 100644 +--- a/io/tst-file_change_detection.c ++++ b/io/tst-file_change_detection.c +@@ -16,10 +16,6 @@ + License along with the GNU C Library; if not, see + . */ + +-/* The header uses the internal __fileno symbol, which is not +- available outside of libc (even to internal tests). */ +-#define __fileno(fp) fileno (fp) +- + #include + + #include +@@ -40,7 +36,7 @@ all_same (struct file_change_detection *array, size_t length) + { + if (test_verbose > 0) + printf ("info: comparing %zu and %zu\n", i, j); +- TEST_VERIFY (file_is_unchanged (array + i, array + j)); ++ TEST_VERIFY (__file_is_unchanged (array + i, array + j)); + } + } + +@@ -54,7 +50,7 @@ all_different (struct file_change_detection *array, size_t length) + continue; + if (test_verbose > 0) + printf ("info: comparing %zu and %zu\n", i, j); +- TEST_VERIFY (!file_is_unchanged (array + i, array + j)); ++ TEST_VERIFY (!__file_is_unchanged (array + i, array + j)); + } + } + +@@ -105,24 +101,24 @@ do_test (void) + struct file_change_detection fcd[10]; + int i = 0; + /* Two empty files always have the same contents. */ +- TEST_VERIFY (file_change_detection_for_path (&fcd[i++], path_empty1)); +- TEST_VERIFY (file_change_detection_for_path (&fcd[i++], path_empty2)); ++ TEST_VERIFY (__file_change_detection_for_path (&fcd[i++], path_empty1)); ++ TEST_VERIFY (__file_change_detection_for_path (&fcd[i++], path_empty2)); + /* So does a missing file (which is treated as empty). */ +- TEST_VERIFY (file_change_detection_for_path (&fcd[i++], +- path_does_not_exist)); ++ TEST_VERIFY (__file_change_detection_for_path (&fcd[i++], ++ path_does_not_exist)); + /* And a symbolic link loop. */ +- TEST_VERIFY (file_change_detection_for_path (&fcd[i++], path_loop)); ++ TEST_VERIFY (__file_change_detection_for_path (&fcd[i++], path_loop)); + /* And a dangling symbolic link. */ +- TEST_VERIFY (file_change_detection_for_path (&fcd[i++], path_dangling)); ++ TEST_VERIFY (__file_change_detection_for_path (&fcd[i++], path_dangling)); + /* And a directory. */ +- TEST_VERIFY (file_change_detection_for_path (&fcd[i++], tempdir)); ++ TEST_VERIFY (__file_change_detection_for_path (&fcd[i++], tempdir)); + /* And a symbolic link to an empty file. */ +- TEST_VERIFY (file_change_detection_for_path (&fcd[i++], path_to_empty1)); ++ TEST_VERIFY (__file_change_detection_for_path (&fcd[i++], path_to_empty1)); + /* Likewise for access the file via a FILE *. */ +- TEST_VERIFY (file_change_detection_for_fp (&fcd[i++], fp_empty1)); +- TEST_VERIFY (file_change_detection_for_fp (&fcd[i++], fp_empty2)); ++ TEST_VERIFY (__file_change_detection_for_fp (&fcd[i++], fp_empty1)); ++ TEST_VERIFY (__file_change_detection_for_fp (&fcd[i++], fp_empty2)); + /* And a NULL FILE * (missing file). */ +- TEST_VERIFY (file_change_detection_for_fp (&fcd[i++], NULL)); ++ TEST_VERIFY (__file_change_detection_for_fp (&fcd[i++], NULL)); + TEST_COMPARE (i, array_length (fcd)); + + all_same (fcd, array_length (fcd)); +@@ -132,9 +128,9 @@ do_test (void) + { + struct file_change_detection fcd[3]; + int i = 0; +- TEST_VERIFY (file_change_detection_for_path (&fcd[i++], path_file1)); +- TEST_VERIFY (file_change_detection_for_path (&fcd[i++], path_to_file1)); +- TEST_VERIFY (file_change_detection_for_fp (&fcd[i++], fp_file1)); ++ TEST_VERIFY (__file_change_detection_for_path (&fcd[i++], path_file1)); ++ TEST_VERIFY (__file_change_detection_for_path (&fcd[i++], path_to_file1)); ++ TEST_VERIFY (__file_change_detection_for_fp (&fcd[i++], fp_file1)); + TEST_COMPARE (i, array_length (fcd)); + all_same (fcd, array_length (fcd)); + } +@@ -144,20 +140,20 @@ do_test (void) + struct file_change_detection fcd[5]; + int i = 0; + /* The other files are not empty. */ +- TEST_VERIFY (file_change_detection_for_path (&fcd[i++], path_empty1)); ++ TEST_VERIFY (__file_change_detection_for_path (&fcd[i++], path_empty1)); + /* These two files have the same contents, but have different file + identity. */ +- TEST_VERIFY (file_change_detection_for_path (&fcd[i++], path_file1)); +- TEST_VERIFY (file_change_detection_for_path (&fcd[i++], path_file2)); ++ TEST_VERIFY (__file_change_detection_for_path (&fcd[i++], path_file1)); ++ TEST_VERIFY (__file_change_detection_for_path (&fcd[i++], path_file2)); + /* FIFOs are always different, even with themselves. */ +- TEST_VERIFY (file_change_detection_for_path (&fcd[i++], path_fifo)); +- TEST_VERIFY (file_change_detection_for_path (&fcd[i++], path_fifo)); ++ TEST_VERIFY (__file_change_detection_for_path (&fcd[i++], path_fifo)); ++ TEST_VERIFY (__file_change_detection_for_path (&fcd[i++], path_fifo)); + TEST_COMPARE (i, array_length (fcd)); + all_different (fcd, array_length (fcd)); + + /* Replacing the file with its symbolic link does not make a + difference. */ +- TEST_VERIFY (file_change_detection_for_path (&fcd[1], path_to_file1)); ++ TEST_VERIFY (__file_change_detection_for_path (&fcd[1], path_to_file1)); + all_different (fcd, array_length (fcd)); + } + +@@ -166,16 +162,17 @@ do_test (void) + for (int use_stdio = 0; use_stdio < 2; ++use_stdio) + { + struct file_change_detection initial; +- TEST_VERIFY (file_change_detection_for_path (&initial, path_file1)); ++ TEST_VERIFY (__file_change_detection_for_path (&initial, path_file1)); + while (true) + { + support_write_file_string (path_file1, "line\n"); + struct file_change_detection current; + if (use_stdio) +- TEST_VERIFY (file_change_detection_for_fp (¤t, fp_file1)); ++ TEST_VERIFY (__file_change_detection_for_fp (¤t, fp_file1)); + else +- TEST_VERIFY (file_change_detection_for_path (¤t, path_file1)); +- if (!file_is_unchanged (&initial, ¤t)) ++ TEST_VERIFY (__file_change_detection_for_path ++ (¤t, path_file1)); ++ if (!__file_is_unchanged (&initial, ¤t)) + break; + /* Wait for a bit to reduce system load. */ + usleep (100 * 1000); +diff --git a/resolv/res_init.c b/resolv/res_init.c +index 98d84f264d..ee5dfdd391 100644 +--- a/resolv/res_init.c ++++ b/resolv/res_init.c +@@ -583,7 +583,7 @@ __resolv_conf_load (struct __res_state *preinit, + if (ok && change != NULL) + /* Update the file change information if the configuration was + loaded successfully. */ +- ok = file_change_detection_for_fp (change, fp); ++ ok = __file_change_detection_for_fp (change, fp); + + if (ok) + { +diff --git a/resolv/resolv_conf.c b/resolv/resolv_conf.c +index 29a1f4fb94..286149ffad 100644 +--- a/resolv/resolv_conf.c ++++ b/resolv/resolv_conf.c +@@ -121,7 +121,7 @@ struct resolv_conf * + __resolv_conf_get_current (void) + { + struct file_change_detection initial; +- if (!file_change_detection_for_path (&initial, _PATH_RESCONF)) ++ if (!__file_change_detection_for_path (&initial, _PATH_RESCONF)) + return NULL; + + struct resolv_conf_global *global_copy = get_locked_global (); +@@ -129,7 +129,7 @@ __resolv_conf_get_current (void) + return NULL; + struct resolv_conf *conf; + if (global_copy->conf_current != NULL +- && file_is_unchanged (&initial, &global_copy->file_resolve_conf)) ++ && __file_is_unchanged (&initial, &global_copy->file_resolve_conf)) + /* We can reuse the cached configuration object. */ + conf = global_copy->conf_current; + else +@@ -149,7 +149,7 @@ __resolv_conf_get_current (void) + /etc/resolv.conf is temporarily replaced while the file + is read (after the initial measurement), and restored to + the initial version later. */ +- if (file_is_unchanged (&initial, &after_load)) ++ if (__file_is_unchanged (&initial, &after_load)) + global_copy->file_resolve_conf = after_load; + else + /* If there is a discrepancy, trigger a reload during the diff --git a/SOURCES/glibc-rh1810146.patch b/SOURCES/glibc-rh1810146.patch new file mode 100644 index 0000000..da0d6b3 --- /dev/null +++ b/SOURCES/glibc-rh1810146.patch @@ -0,0 +1,28 @@ +commit 8b222fa38700422b4da6731806835f0bbf40920d +Author: Florian Weimer +Date: Mon Jan 20 18:37:13 2020 +0100 + + getaddrinfo: Fix resource leak after strdup failure in gethosts [BZ #25425] + + Filip Ochnik spotted that one of the error jumps in gethosts fails to + call __resolv_context_put to release the resolver context. + + Fixes commit 352f4ff9a268b81ef5d4b2413f582565806e4790 ("resolv: + Introduce struct resolv_context [BZ #21668]") and commit + 964263bb8d650f1681665c55704fb01a8e725621 ("getaddrinfo: Release + resolver context on error in gethosts [BZ #21885]"). + + Reviewed-by: Siddhesh Poyarekar + +diff --git a/sysdeps/posix/getaddrinfo.c b/sysdeps/posix/getaddrinfo.c +index 6a5805c9e63a257c..fae3dea81f19dba6 100644 +--- a/sysdeps/posix/getaddrinfo.c ++++ b/sysdeps/posix/getaddrinfo.c +@@ -292,6 +292,7 @@ convert_hostent_to_gaih_addrtuple (const struct addrinfo *req, + canonbuf = __strdup (localcanon); \ + if (canonbuf == NULL) \ + { \ ++ __resolv_context_put (res_ctx); \ + result = -EAI_SYSTEM; \ + goto free_and_return; \ + } \ diff --git a/SOURCES/glibc-rh1810223-1.patch b/SOURCES/glibc-rh1810223-1.patch new file mode 100644 index 0000000..6771e16 --- /dev/null +++ b/SOURCES/glibc-rh1810223-1.patch @@ -0,0 +1,170 @@ +commit 0499a353a6e196f468e7ec554cb13c82011f0e36 +Author: Florian Weimer +Date: Mon Mar 2 14:24:27 2020 +0100 + + elf: Add elf/check-wx-segment, a test for the presence of WX segments + + Writable, executable segments defeat security hardening. The + existing check for DT_TEXTREL does not catch this. + + hppa and SPARC currently keep the PLT in an RWX load segment. + +# Conflicts: +# sysdeps/sparc/Makefile + +diff --git a/elf/Makefile b/elf/Makefile +index f1a16fe8ca594c57..a52d9b1f6a4364a7 100644 +--- a/elf/Makefile ++++ b/elf/Makefile +@@ -378,6 +378,7 @@ tests-special += $(objpfx)tst-pathopt.out $(objpfx)tst-rtld-load-self.out \ + $(objpfx)tst-rtld-preload.out + endif + tests-special += $(objpfx)check-textrel.out $(objpfx)check-execstack.out \ ++ $(objpfx)check-wx-segment.out \ + $(objpfx)check-localplt.out $(objpfx)check-initfini.out + endif + +@@ -1148,6 +1149,12 @@ $(objpfx)check-execstack.out: $(..)scripts/check-execstack.awk \ + $(evaluate-test) + generated += check-execstack.out + ++$(objpfx)check-wx-segment.out: $(..)scripts/check-wx-segment.py \ ++ $(all-built-dso:=.phdr) ++ $(PYTHON) $^ --xfail="$(check-wx-segment-xfail)" > $@; \ ++ $(evaluate-test) ++generated += check-wx-segment.out ++ + $(objpfx)tst-dlmodcount: $(libdl) + $(objpfx)tst-dlmodcount.out: $(test-modules) + +diff --git a/scripts/check-wx-segment.py b/scripts/check-wx-segment.py +new file mode 100644 +index 0000000000000000..e1fa79387ce22c4b +--- /dev/null ++++ b/scripts/check-wx-segment.py +@@ -0,0 +1,85 @@ ++#!/usr/bin/python3 ++# Check ELF program headers for WX segments. ++# 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 ++# . ++ ++"""Check that the program headers do not contain write-exec segments.""" ++ ++import argparse ++import os.path ++import re ++import sys ++ ++# Regular expression to extract the RWE flags field. The ++# address/offset columns have varying width. ++RE_LOAD = re.compile( ++ r'^ LOAD +(?:0x[0-9a-fA-F]+ +){5}([R ][W ][ E]) +0x[0-9a-fA-F]+\n\Z') ++ ++def process_file(path, inp, xfail): ++ """Analyze one input file.""" ++ ++ errors = 0 ++ for line in inp: ++ error = None ++ if line.startswith(' LOAD '): ++ match = RE_LOAD.match(line) ++ if match is None: ++ error = 'Invalid LOAD line' ++ else: ++ flags, = match.groups() ++ if 'W' in flags and 'E' in flags: ++ if xfail: ++ print('{}: warning: WX segment (as expected)'.format( ++ path)) ++ else: ++ error = 'WX segment' ++ ++ if error is not None: ++ print('{}: error: {}: {!r}'.format(path, error, line.strip())) ++ errors += 1 ++ ++ if xfail and errors == 0: ++ print('{}: warning: missing expected WX segment'.format(path)) ++ return errors ++ ++ ++def main(): ++ """The main entry point.""" ++ parser = argparse.ArgumentParser(description=__doc__) ++ parser.add_argument('--xfail', ++ help='Mark input files as XFAILed ("*" for all)', ++ type=str, default='') ++ parser.add_argument('phdrs', ++ help='Files containing readelf -Wl output', ++ nargs='*') ++ opts = parser.parse_args(sys.argv) ++ ++ xfails = set(opts.xfail.split(' ')) ++ xfails_all = opts.xfail.strip() == '*' ++ ++ errors = 0 ++ for path in opts.phdrs: ++ xfail = ((os.path.basename(path) + '.phdrs') in xfails ++ or xfails_all) ++ with open(path) as inp: ++ errors += process_file(path, inp, xfail) ++ if errors > 0: ++ sys.exit(1) ++ ++ ++if __name__ == '__main__': ++ main() +diff --git a/sysdeps/sparc/Makefile b/sysdeps/sparc/Makefile +index 3f0c0964002560f0..a1004e819c9b0c38 100644 +--- a/sysdeps/sparc/Makefile ++++ b/sysdeps/sparc/Makefile +@@ -16,5 +16,14 @@ CPPFLAGS-crti.S += -fPIC + CPPFLAGS-crtn.S += -fPIC + endif + ++ifeq ($(subdir),elf) ++ ++# Lazy binding on SPARC rewrites the PLT sequence. See the Solaris ++# Linker and Libraries Guide, section SPARC: Procedure Linkage Table. ++# ++test-xfail-check-wx-segment = * ++ ++endif # $(subdir) == elf ++ + # The assembler on SPARC needs the -fPIC flag even when it's assembler code. + ASFLAGS-.os += -fPIC +diff --git a/sysdeps/unix/sysv/linux/hppa/Makefile b/sysdeps/unix/sysv/linux/hppa/Makefile +index e1637f54f508c007..c89ec8318208205d 100644 +--- a/sysdeps/unix/sysv/linux/hppa/Makefile ++++ b/sysdeps/unix/sysv/linux/hppa/Makefile +@@ -3,9 +3,14 @@ ifeq ($(subdir),stdlib) + gen-as-const-headers += ucontext_i.sym + endif + ++ifeq ($(subdir),elf) + # Supporting non-executable stacks on HPPA requires changes to both + # the Linux kernel and glibc. The kernel currently needs an executable + # stack for syscall restarts and signal returns. +-ifeq ($(subdir),elf) + test-xfail-check-execstack = yes +-endif ++ ++# On hppa, the PLT is executable because it contains an executable ++# trampoline used during lazy binding. ++test-xfail-check-wx-segment = * ++ ++endif # $(subdir) == elf diff --git a/SOURCES/glibc-rh1810223-2.patch b/SOURCES/glibc-rh1810223-2.patch new file mode 100644 index 0000000..4bee60f --- /dev/null +++ b/SOURCES/glibc-rh1810223-2.patch @@ -0,0 +1,49 @@ +commit 279c68ce1336d84d82ce491a4b77086e574ba380 +Author: DJ Delorie +Date: Mon Feb 3 14:57:23 2020 -0500 + + Run nptl/tst-pthread-getattr in a container + + See https://bugzilla.redhat.com/show_bug.cgi?id=1653942 + + This test depends on the kernel's assignment of memory regions, but + running under ld.so explicitly changes those assignments, sometimes + sufficiently to cause the test to fail (esp with address space + randomization). + + The easiest way to "fix" the test, is to run it the way the user would + - without ld.so. Running it in a container does that. + + Reviewed-by: Carlos O'Donell + +diff --git a/nptl/Makefile b/nptl/Makefile +index b1003cf56b31ddfa..071c53866d14d2fe 100644 +--- a/nptl/Makefile ++++ b/nptl/Makefile +@@ -293,7 +293,7 @@ tests = tst-attr1 tst-attr2 tst-attr3 tst-default-attr \ + tst-exec1 tst-exec2 tst-exec3 tst-exec4 tst-exec5 \ + tst-exit1 tst-exit2 tst-exit3 \ + tst-stdio1 tst-stdio2 \ +- tst-stack1 tst-stack2 tst-stack3 tst-stack4 tst-pthread-getattr \ ++ tst-stack1 tst-stack2 tst-stack3 tst-stack4 \ + tst-pthread-attr-affinity tst-pthread-mutexattr \ + tst-unload \ + tst-dlsym1 \ +@@ -322,6 +322,8 @@ tests = tst-attr1 tst-attr2 tst-attr3 tst-default-attr \ + tst-rwlock-pwn \ + tst-rwlock-tryrdlock-stall tst-rwlock-trywrlock-stall + ++tests-container = tst-pthread-getattr ++ + tests-internal := tst-rwlock19 tst-rwlock20 \ + tst-sem11 tst-sem12 tst-sem13 \ + tst-barrier5 tst-signal7 tst-mutex8 tst-mutex8-static \ +@@ -633,7 +635,7 @@ ifeq ($(build-shared),yes) + $(addprefix $(objpfx), \ + $(filter-out $(tests-static) $(xtests-static) $(tests-reverse) \ + $(tests-nolibpthread), \ +- $(tests) $(tests-internal) $(xtests) $(test-srcs))): \ ++ $(tests) $(tests-internal) $(xtests) $(test-srcs) $(tests-container))): \ + $(objpfx)libpthread.so + $(objpfx)tst-unload: $(libdl) + # $(objpfx)../libc.so is used instead of $(common-objpfx)libc.so, diff --git a/SOURCES/glibc-rh1810224-1.patch b/SOURCES/glibc-rh1810224-1.patch new file mode 100644 index 0000000..a4b671a --- /dev/null +++ b/SOURCES/glibc-rh1810224-1.patch @@ -0,0 +1,28 @@ +commit a331150af65477fc3fa72ab341eed5e0b2daf7f3 +Author: Joseph Myers +Date: Thu Nov 28 20:32:09 2019 +0000 + + Update syscall-names.list for Linux 5.4. + + This patch updates syscall-names.list for Linux 5.4. There are no new + syscalls, so this is just a matter of updating the version number + listed in the file. + + Tested with build-many-glibcs.py. + +Reworked for RHEL 8.3.0. + +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 2020-04-05 20:20:41.471686371 -0400 ++++ b/sysdeps/unix/sysv/linux/syscall-names.list 2020-04-05 20:21:56.871912297 -0400 +@@ -22,8 +22,8 @@ + # names are only used if the installed kernel headers also provide + # them. + +-# The list of system calls is current as of Linux 5.3. +-kernel 5.3 ++# The list of system calls is current as of Linux 5.4. ++kernel 5.4 + + FAST_atomic_update + FAST_cmpxchg diff --git a/SOURCES/glibc-rh1810224-2.patch b/SOURCES/glibc-rh1810224-2.patch new file mode 100644 index 0000000..df51b1d --- /dev/null +++ b/SOURCES/glibc-rh1810224-2.patch @@ -0,0 +1,29 @@ +commit 5828bc4523230685ac29a4a882967913255f5666 +Author: Joseph Myers +Date: Fri Feb 7 13:54:58 2020 +0000 + + Update syscall lists for Linux 5.5. + + Linux 5.5 has no new syscalls to add to syscall-names.list, but it + does newly enable the clone3 syscall for AArch64. This patch updates + the kernel version listed in syscall-names.list and regenerates the + AArch64 arch-syscall.h. + + Tested with build-many-glibcs.py. + +Modified to only update syscall-names.list for RHEL 8.3.0. + +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 2020-04-06 12:10:47.683272882 -0400 ++++ b/sysdeps/unix/sysv/linux/syscall-names.list 2020-04-06 12:12:41.769598687 -0400 +@@ -22,8 +22,8 @@ + # names are only used if the installed kernel headers also provide + # them. + +-# The list of system calls is current as of Linux 5.4. +-kernel 5.4 ++# The list of system calls is current as of Linux 5.5. ++kernel 5.5 + + FAST_atomic_update + FAST_cmpxchg diff --git a/SOURCES/glibc-rh1810224-3.patch b/SOURCES/glibc-rh1810224-3.patch new file mode 100644 index 0000000..2293e42 --- /dev/null +++ b/SOURCES/glibc-rh1810224-3.patch @@ -0,0 +1,26 @@ +commit 6cf6a91d05d626698f158078961b3bffcb39ff8c +Author: Joseph Myers +Date: Wed Feb 12 13:37:16 2020 +0000 + + Rename RWF_WRITE_LIFE_NOT_SET to RWH_WRITE_LIFE_NOT_SET following Linux 5.5. + + Linux 5.5 renames RWF_WRITE_LIFE_NOT_SET to RWH_WRITE_LIFE_NOT_SET, + with the old name kept as an alias. This patch makes the + corresponding change in glibc. + + Tested for x86_64. + +diff --git a/sysdeps/unix/sysv/linux/bits/fcntl-linux.h b/sysdeps/unix/sysv/linux/bits/fcntl-linux.h +index 07a889d683..b06488a847 100644 +--- a/sysdeps/unix/sysv/linux/bits/fcntl-linux.h ++++ b/sysdeps/unix/sysv/linux/bits/fcntl-linux.h +@@ -290,7 +290,8 @@ struct f_owner_ex + + #ifdef __USE_GNU + /* Hint values for F_{GET,SET}_RW_HINT. */ +-# define RWF_WRITE_LIFE_NOT_SET 0 ++# define RWH_WRITE_LIFE_NOT_SET 0 ++# define RWF_WRITE_LIFE_NOT_SET RWH_WRITE_LIFE_NOT_SET + # define RWH_WRITE_LIFE_NONE 1 + # define RWH_WRITE_LIFE_SHORT 2 + # define RWH_WRITE_LIFE_MEDIUM 3 diff --git a/SOURCES/glibc-rh1810224-4.patch b/SOURCES/glibc-rh1810224-4.patch new file mode 100644 index 0000000..c1205a1 --- /dev/null +++ b/SOURCES/glibc-rh1810224-4.patch @@ -0,0 +1,54 @@ +commit e788beaf093bfafecd6b4456b984bd927c18987a +Author: Joseph Myers +Date: Fri Apr 3 18:07:55 2020 +0000 + + Update syscall lists for Linux 5.6. + + Linux 5.6 has new openat2 and pidfd_getfd syscalls. This patch adds + them to syscall-names.list and regenerates the arch-syscall.h files. + + Tested with build-many-glibcs.py. + +Modified to only update syscall-names.list for RHEL 8.3.0. +Also cleaned up typos in the comments. + +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 2020-04-06 12:27:10.519027866 -0400 ++++ b/sysdeps/unix/sysv/linux/syscall-names.list 2020-04-06 12:31:53.665812810 -0400 +@@ -16,14 +16,13 @@ + # License along with the GNU C Library; if not, see + # . + +-# This file contains the list of system call names names. It has to +-# remain in alphabetica order. Lines which start with # are treated +-# as comments. This file can list all potential system calls. The +-# names are only used if the installed kernel headers also provide +-# them. ++# This file contains the list of system call names. It has to remain in ++# alphabetical order. Lines which start with # are treated as comments. ++# 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.5. +-kernel 5.5 ++# The list of system calls is current as of Linux 5.6. ++kernel 5.6 + + FAST_atomic_update + FAST_cmpxchg +@@ -293,6 +292,7 @@ open + open_by_handle_at + open_tree + openat ++openat2 + osf_adjtime + osf_afs_syscall + osf_alt_plock +@@ -411,6 +411,7 @@ perf_event_open + perfctr + perfmonctl + personality ++pidfd_getfd + pidfd_open + pidfd_send_signal + pipe diff --git a/SOURCES/glibc-rh1811796-1.patch b/SOURCES/glibc-rh1811796-1.patch new file mode 100644 index 0000000..a7b711d --- /dev/null +++ b/SOURCES/glibc-rh1811796-1.patch @@ -0,0 +1,113 @@ +commit 9333498794cde1d5cca518badf79533a24114b6f +Author: Joseph Myers +Date: Wed Feb 12 23:31:56 2020 +0000 + + Avoid ldbl-96 stack corruption from range reduction of pseudo-zero (bug 25487). + + Bug 25487 reports stack corruption in ldbl-96 sinl on a pseudo-zero + argument (an representation where all the significand bits, including + the explicit high bit, are zero, but the exponent is not zero, which + is not a valid representation for the long double type). + + Although this is not a valid long double representation, existing + practice in this area (see bug 4586, originally marked invalid but + subsequently fixed) is that we still seek to avoid invalid memory + accesses as a result, in case of programs that treat arbitrary binary + data as long double representations, although the invalid + representations of the ldbl-96 format do not need to be consistently + handled the same as any particular valid representation. + + This patch makes the range reduction detect pseudo-zero and unnormal + representations that would otherwise go to __kernel_rem_pio2, and + returns a NaN for them instead of continuing with the range reduction + process. (Pseudo-zero and unnormal representations whose unbiased + exponent is less than -1 have already been safely returned from the + function before this point without going through the rest of range + reduction.) Pseudo-zero representations would previously result in + the value passed to __kernel_rem_pio2 being all-zero, which is + definitely unsafe; unnormal representations would previously result in + a value passed whose high bit is zero, which might well be unsafe + since that is not a form of input expected by __kernel_rem_pio2. + + Tested for x86_64. + +Revised for RHEL 8.3.0. + +diff -Nrup a/sysdeps/ieee754/ldbl-96/e_rem_pio2l.c b/sysdeps/ieee754/ldbl-96/e_rem_pio2l.c +--- a/sysdeps/ieee754/ldbl-96/e_rem_pio2l.c 2018-08-01 01:10:47.000000000 -0400 ++++ b/sysdeps/ieee754/ldbl-96/e_rem_pio2l.c 2020-04-03 13:05:02.609844427 -0400 +@@ -209,6 +209,18 @@ __ieee754_rem_pio2l (long double x, long + y[1] = y[0]; + return 0; + } ++ ++ if ((i0 & 0x80000000) == 0) ++ { ++ /* Pseudo-zero and unnormal representations are not valid ++ representations of long double. We need to avoid stack ++ corruption in __kernel_rem_pio2, which expects input in a ++ particular normal form, but those representations do not need ++ to be consistently handled like any particular floating-point ++ value. */ ++ y[1] = y[0] = __builtin_nanl (""); ++ return 0; ++ } + + /* Split the 64 bits of the mantissa into three 24-bit integers + stored in a double array. */ +diff -Nrup a/sysdeps/ieee754/ldbl-96/Makefile b/sysdeps/ieee754/ldbl-96/Makefile +--- a/sysdeps/ieee754/ldbl-96/Makefile 2018-08-01 01:10:47.000000000 -0400 ++++ b/sysdeps/ieee754/ldbl-96/Makefile 2020-04-03 13:03:20.233546734 -0400 +@@ -17,5 +17,6 @@ + # . + + ifeq ($(subdir),math) +-tests += test-canonical-ldbl-96 test-totalorderl-ldbl-96 ++tests += test-canonical-ldbl-96 test-totalorderl-ldbl-96 test-sinl-pseudo ++CFLAGS-test-sinl-pseudo.c += -fstack-protector-all + endif +diff -Nrup a/sysdeps/ieee754/ldbl-96/test-sinl-pseudo.c b/sysdeps/ieee754/ldbl-96/test-sinl-pseudo.c +--- a/sysdeps/ieee754/ldbl-96/test-sinl-pseudo.c 1969-12-31 19:00:00.000000000 -0500 ++++ b/sysdeps/ieee754/ldbl-96/test-sinl-pseudo.c 2020-04-03 13:05:37.857952212 -0400 +@@ -0,0 +1,41 @@ ++/* Test sinl for pseudo-zeros and unnormals for ldbl-96 (bug 25487). ++ 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 ++ ++static int ++do_test (void) ++{ ++ for (int i = 0; i < 64; i++) ++ { ++ uint64_t sig = i == 63 ? 0 : 1ULL << i; ++ long double ld; ++ SET_LDOUBLE_WORDS (ld, 0x4141, ++ sig >> 32, sig & 0xffffffffULL); ++ /* The requirement is that no stack overflow occurs when the ++ pseudo-zero or unnormal goes through range reduction. */ ++ volatile long double ldr; ++ ldr = sinl (ld); ++ (void) ldr; ++ } ++ return 0; ++} ++ ++#include diff --git a/SOURCES/glibc-rh1811796-2.patch b/SOURCES/glibc-rh1811796-2.patch new file mode 100644 index 0000000..eae8269 --- /dev/null +++ b/SOURCES/glibc-rh1811796-2.patch @@ -0,0 +1,21 @@ +commit c10acd40262486dac597001aecc20ad9d3bd0e4a +Author: Florian Weimer +Date: Thu Feb 13 17:01:15 2020 +0100 + + math/test-sinl-pseudo: Use stack protector only if available + + This fixes commit 9333498794cde1d5cca518bad ("Avoid ldbl-96 stack + corruption from range reduction of pseudo-zero (bug 25487)."). + +diff --git a/sysdeps/ieee754/ldbl-96/Makefile b/sysdeps/ieee754/ldbl-96/Makefile +index 318628aed6..6030adf7e7 100644 +--- a/sysdeps/ieee754/ldbl-96/Makefile ++++ b/sysdeps/ieee754/ldbl-96/Makefile +@@ -18,5 +18,7 @@ + + ifeq ($(subdir),math) + tests += test-canonical-ldbl-96 test-totalorderl-ldbl-96 test-sinl-pseudo ++ifeq ($(have-ssp),yes) + CFLAGS-test-sinl-pseudo.c += -fstack-protector-all + endif ++endif # $(subdir) == math diff --git a/SOURCES/glibc-rh1812756-1.patch b/SOURCES/glibc-rh1812756-1.patch new file mode 100644 index 0000000..7675c1c --- /dev/null +++ b/SOURCES/glibc-rh1812756-1.patch @@ -0,0 +1,517 @@ +commit eb447b7b4bd6177f876ba9420ad9e048c27bae91 +Author: David Kilroy +Date: Wed Feb 12 14:28:15 2020 -0300 + + elf: Allow dlopen of filter object to work [BZ #16272] + + There are two fixes that are needed to be able to dlopen filter + objects. First _dl_map_object_deps cannot assume that map will be at + the beginning of l_searchlist.r_list[], as filtees are inserted before + map. Secondly dl_open_worker needs to ensure that filtees get + relocated. + + In _dl_map_object_deps: + + * avoiding removing relocation dependencies of map by setting + l_reserved to 0 and otherwise processing the rest of the search + list. + + * ensure that map remains at the beginning of l_initfini - the list + of things that need initialisation (and destruction). Do this by + splitting the copy up. This may not be required, but matches the + initialization order without dlopen. + + Modify dl_open_worker to relocate the objects in new->l_inifini. + new->l_initfini is constructed in _dl_map_object_deps, and lists the + objects that need initialization and destruction. Originally the list + of objects in new->l_next are relocated. All of these objects should + also be included in new->l_initfini (both lists are populated with + dependencies in _dl_map_object_deps). We can't use new->l_prev to pick + up filtees, as during a recursive dlopen from an interposed malloc + call, l->prev can contain objects that are not ready for relocation. + + Add tests to verify that symbols resolve to the filtee implementation + when auxiliary and filter objects are used, both as a normal link and + when dlopen'd. + + Tested by running the testsuite on x86_64. + +# Conflicts: +# elf/Makefile + +diff --git a/elf/Makefile b/elf/Makefile +index a52d9b1f6a4364a7..b4b618ce62a9e6df 100644 +--- a/elf/Makefile ++++ b/elf/Makefile +@@ -192,7 +192,8 @@ tests += restest1 preloadtest loadfail multiload origtest resolvfail \ + tst-latepthread tst-tls-manydynamic tst-nodelete-dlclose \ + tst-debug1 tst-main1 tst-absolute-sym tst-absolute-zero tst-big-note \ + tst-sonamemove-link tst-sonamemove-dlopen tst-initfinilazyfail \ +- tst-dlopenfail tst-dlopenfail-2 ++ tst-dlopenfail tst-dlopenfail-2 \ ++ tst-filterobj tst-filterobj-dlopen tst-auxobj tst-auxobj-dlopen + # reldep9 + tests-internal += loadtest unload unload2 circleload1 \ + neededtest neededtest2 neededtest3 neededtest4 \ +@@ -302,7 +303,8 @@ modules-names = testobj1 testobj2 testobj3 testobj4 testobj5 testobj6 \ + tst-sonamemove-runmod1 tst-sonamemove-runmod2 \ + tst-initlazyfailmod tst-finilazyfailmod \ + tst-dlopenfailmod1 tst-dlopenfaillinkmod tst-dlopenfailmod2 \ +- tst-dlopenfailmod3 ++ tst-dlopenfailmod3 \ ++ tst-filterobj-flt tst-filterobj-aux tst-filterobj-filtee + + ifeq (yes,$(have-mtls-dialect-gnu2)) + tests += tst-gnu2-tls1 +@@ -1626,3 +1628,15 @@ $(objpfx)tst-dlopen-nodelete-reloc-mod17.so: \ + $(objpfx)tst-dlopen-nodelete-reloc-mod15.so \ + $(objpfx)tst-dlopen-nodelete-reloc-mod16.so + LDFLAGS-tst-dlopen-nodelete-reloc-mod17.so = -Wl,--no-as-needed ++ ++LDFLAGS-tst-filterobj-flt.so = -Wl,--filter=$(objpfx)tst-filterobj-filtee.so ++$(objpfx)tst-filterobj: $(objpfx)tst-filterobj-flt.so ++$(objpfx)tst-filterobj-dlopen: $(libdl) ++$(objpfx)tst-filterobj.out: $(objpfx)tst-filterobj-filtee.so ++$(objpfx)tst-filterobj-dlopen.out: $(objpfx)tst-filterobj-filtee.so ++ ++LDFLAGS-tst-filterobj-aux.so = -Wl,--auxiliary=$(objpfx)tst-filterobj-filtee.so ++$(objpfx)tst-auxobj: $(objpfx)tst-filterobj-aux.so ++$(objpfx)tst-auxobj-dlopen: $(libdl) ++$(objpfx)tst-auxobj.out: $(objpfx)tst-filterobj-filtee.so ++$(objpfx)tst-auxobj-dlopen.out: $(objpfx)tst-filterobj-filtee.so +diff --git a/elf/dl-deps.c b/elf/dl-deps.c +index 9d9b1ba7f244348a..50f053a1586efdc3 100644 +--- a/elf/dl-deps.c ++++ b/elf/dl-deps.c +@@ -485,14 +485,18 @@ _dl_map_object_deps (struct link_map *map, + + map->l_searchlist.r_list = &l_initfini[nlist + 1]; + map->l_searchlist.r_nlist = nlist; ++ unsigned int map_index = UINT_MAX; + + for (nlist = 0, runp = known; runp; runp = runp->next) + { + if (__builtin_expect (trace_mode, 0) && runp->map->l_faked) + /* This can happen when we trace the loading. */ + --map->l_searchlist.r_nlist; +- else ++ else { ++ if (runp->map == map) ++ map_index = nlist; + map->l_searchlist.r_list[nlist++] = runp->map; ++ } + + /* Now clear all the mark bits we set in the objects on the search list + to avoid duplicates, so the next call starts fresh. */ +@@ -550,13 +554,14 @@ Filters not supported with LD_TRACE_PRELINKING")); + } + + /* Maybe we can remove some relocation dependencies now. */ +- assert (map->l_searchlist.r_list[0] == map); + struct link_map_reldeps *l_reldeps = NULL; + if (map->l_reldeps != NULL) + { +- for (i = 1; i < nlist; ++i) ++ for (i = 0; i < nlist; ++i) + map->l_searchlist.r_list[i]->l_reserved = 1; + ++ /* Avoid removing relocation dependencies of the main binary. */ ++ map->l_reserved = 0; + struct link_map **list = &map->l_reldeps->list[0]; + for (i = 0; i < map->l_reldeps->act; ++i) + if (list[i]->l_reserved) +@@ -581,16 +586,30 @@ Filters not supported with LD_TRACE_PRELINKING")); + } + } + +- for (i = 1; i < nlist; ++i) ++ for (i = 0; i < nlist; ++i) + map->l_searchlist.r_list[i]->l_reserved = 0; + } + +- /* Sort the initializer list to take dependencies into account. The binary +- itself will always be initialize last. */ +- memcpy (l_initfini, map->l_searchlist.r_list, +- nlist * sizeof (struct link_map *)); +- /* We can skip looking for the binary itself which is at the front of +- the search list. */ ++ /* Sort the initializer list to take dependencies into account. Always ++ initialize the binary itself last. */ ++ assert (map_index < nlist); ++ if (map_index > 0) ++ { ++ /* Copy the binary into position 0. */ ++ l_initfini[0] = map->l_searchlist.r_list[map_index]; ++ ++ /* Copy the filtees. */ ++ for (i = 0; i < map_index; ++i) ++ l_initfini[i+1] = map->l_searchlist.r_list[i]; ++ ++ /* Copy the remainder. */ ++ for (i = map_index + 1; i < nlist; ++i) ++ l_initfini[i] = map->l_searchlist.r_list[i]; ++ } ++ else ++ memcpy (l_initfini, map->l_searchlist.r_list, ++ nlist * sizeof (struct link_map *)); ++ + _dl_sort_maps (&l_initfini[1], nlist - 1, NULL, false); + + /* Terminate the list of dependencies. */ +diff --git a/elf/dl-open.c b/elf/dl-open.c +index d834b89754d2b073..d31356f7e17dfb14 100644 +--- a/elf/dl-open.c ++++ b/elf/dl-open.c +@@ -618,22 +618,25 @@ dl_open_worker (void *a) + allows IFUNC relocations to work and it also means copy + relocation of dependencies are if necessary overwritten. */ + unsigned int nmaps = 0; +- struct link_map *l = new; ++ unsigned int j = 0; ++ struct link_map *l = new->l_initfini[0]; + do + { + if (! l->l_real->l_relocated) + ++nmaps; +- l = l->l_next; ++ l = new->l_initfini[++j]; + } + while (l != NULL); ++ /* Stack allocation is limited by the number of loaded objects. */ + struct link_map *maps[nmaps]; + nmaps = 0; +- l = new; ++ j = 0; ++ l = new->l_initfini[0]; + do + { + if (! l->l_real->l_relocated) + maps[nmaps++] = l; +- l = l->l_next; ++ l = new->l_initfini[++j]; + } + while (l != NULL); + _dl_sort_maps (maps, nmaps, NULL, false); +diff --git a/elf/tst-auxobj-dlopen.c b/elf/tst-auxobj-dlopen.c +new file mode 100644 +index 0000000000000000..cb54aba19470a1fe +--- /dev/null ++++ b/elf/tst-auxobj-dlopen.c +@@ -0,0 +1,47 @@ ++/* Test for BZ#16272, dlopen'ing an auxiliary filter object. ++ Ensure that symbols from the resolve correctly. ++ ++ 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 ++ ++static int do_test (void) ++{ ++ void *lib = xdlopen ("tst-filterobj-aux.so", RTLD_LAZY); ++ char *(*fn)(void) = xdlsym (lib, "get_text"); ++ const char* text = fn (); ++ ++ printf ("%s\n", text); ++ ++ /* Verify the text matches what we expect from the filtee */ ++ TEST_COMPARE_STRING (text, "Hello from filtee (PASS)"); ++ ++ fn = xdlsym (lib, "get_text2"); ++ text = fn (); ++ ++ printf ("%s\n", text); ++ ++ /* Verify the text matches what we expect from the auxiliary object */ ++ TEST_COMPARE_STRING (text, "Hello from auxiliary filter object (PASS)"); ++ ++ return 0; ++} ++ ++#include +diff --git a/elf/tst-auxobj.c b/elf/tst-auxobj.c +new file mode 100644 +index 0000000000000000..bdc7713b04b4a79b +--- /dev/null ++++ b/elf/tst-auxobj.c +@@ -0,0 +1,42 @@ ++/* Test that symbols from auxiliary filter objects are resolved to the ++ filtee. ++ ++ 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 "tst-filterobj-filtee.h" ++ ++static int do_test (void) ++{ ++ const char* text = get_text (); ++ printf ("%s\n", text); ++ ++ /* Verify the text matches what we expect from the filtee */ ++ TEST_COMPARE_STRING (text, "Hello from filtee (PASS)"); ++ ++ text = get_text2 (); ++ printf ("%s\n", text); ++ ++ /* Verify the text matches what we expect from the auxiliary object */ ++ TEST_COMPARE_STRING (text, "Hello from auxiliary filter object (PASS)"); ++ ++ return 0; ++} ++ ++#include +diff --git a/elf/tst-filterobj-aux.c b/elf/tst-filterobj-aux.c +new file mode 100644 +index 0000000000000000..0b732f2fb3a69a7f +--- /dev/null ++++ b/elf/tst-filterobj-aux.c +@@ -0,0 +1,33 @@ ++/* Auxiliary filter object. ++ Contains symbols to be resolved in filtee, and one which doesn't. ++ ++ 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 "tst-filterobj-filtee.h" ++ ++/* We never want to see the output of the auxiliary object. */ ++const char *get_text (void) ++{ ++ return "Hello from auxiliary filter object (FAIL)"; ++} ++ ++/* The filtee doesn't implement this symbol, so this should resolve. */ ++const char *get_text2 (void) ++{ ++ return "Hello from auxiliary filter object (PASS)"; ++} +diff --git a/elf/tst-filterobj-dlopen.c b/elf/tst-filterobj-dlopen.c +new file mode 100644 +index 0000000000000000..c5b5072979802b98 +--- /dev/null ++++ b/elf/tst-filterobj-dlopen.c +@@ -0,0 +1,39 @@ ++/* Test for BZ#16272, dlopen'ing a filter object. ++ Ensure that symbols from the filter object resolve to the filtee. ++ ++ 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 ++ ++static int do_test (void) ++{ ++ void *lib = xdlopen ("tst-filterobj-flt.so", RTLD_LAZY); ++ char *(*fn)(void) = xdlsym (lib, "get_text"); ++ const char* text = fn (); ++ ++ printf ("%s\n", text); ++ ++ /* Verify the text matches what we expect from the filtee */ ++ TEST_COMPARE_STRING (text, "Hello from filtee (PASS)"); ++ ++ return 0; ++} ++ ++#include +diff --git a/elf/tst-filterobj-filtee.c b/elf/tst-filterobj-filtee.c +new file mode 100644 +index 0000000000000000..8fa557cbd251f53c +--- /dev/null ++++ b/elf/tst-filterobj-filtee.c +@@ -0,0 +1,27 @@ ++/* Filtee for BZ#16272 test. ++ Contains desired symbol implementations. ++ ++ 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 "tst-filterobj-filtee.h" ++ ++/* This is the real implementation that wants to be called */ ++const char *get_text (void) ++{ ++ return "Hello from filtee (PASS)"; ++} +diff --git a/elf/tst-filterobj-filtee.h b/elf/tst-filterobj-filtee.h +new file mode 100644 +index 0000000000000000..46aee28178b88a77 +--- /dev/null ++++ b/elf/tst-filterobj-filtee.h +@@ -0,0 +1,24 @@ ++/* Filtee header for BZ#16272 test. ++ Contains prototypes for symbols implemented in the filtee. ++ ++ 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 ++ . */ ++ ++const char *get_text (void); ++ ++/* For testing auxiliary filter object. */ ++const char *get_text2 (void); +diff --git a/elf/tst-filterobj-flt.c b/elf/tst-filterobj-flt.c +new file mode 100644 +index 0000000000000000..5062654be6f14a80 +--- /dev/null ++++ b/elf/tst-filterobj-flt.c +@@ -0,0 +1,27 @@ ++/* Filter object for BZ#16272 test. ++ Contains symbols to be resolved in filtee. ++ ++ 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 "tst-filterobj-filtee.h" ++ ++/* We never want to see the output of the filter object */ ++const char *get_text (void) ++{ ++ return "Hello from filter object (FAIL)"; ++} +diff --git a/elf/tst-filterobj.c b/elf/tst-filterobj.c +new file mode 100644 +index 0000000000000000..96bfae019ea670bc +--- /dev/null ++++ b/elf/tst-filterobj.c +@@ -0,0 +1,36 @@ ++/* Test that symbols from filter objects are resolved to the filtee. ++ ++ 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 "tst-filterobj-filtee.h" ++ ++static int do_test (void) ++{ ++ const char* text = get_text (); ++ ++ printf ("%s\n", text); ++ ++ /* Verify the text matches what we expect from the filtee */ ++ TEST_COMPARE_STRING (text, "Hello from filtee (PASS)"); ++ ++ return 0; ++} ++ ++#include diff --git a/SOURCES/glibc-rh1812756-2.patch b/SOURCES/glibc-rh1812756-2.patch new file mode 100644 index 0000000..e2df4e4 --- /dev/null +++ b/SOURCES/glibc-rh1812756-2.patch @@ -0,0 +1,37 @@ +commit 71bcfa62451dfaa015326d3524f2a0e2d09d80ed +Author: David Kilroy +Date: Wed Feb 12 14:30:31 2020 -0300 + + elf: avoid redundant sort in dlopen + + l_initfini is already sorted by dependency in _dl_map_object_deps(), + so avoid sorting again in dl_open_worker(). + + Tested by running the testsuite on x86_64. + +diff --git a/elf/dl-open.c b/elf/dl-open.c +index d31356f7e17dfb14..980a28c836ca9a7a 100644 +--- a/elf/dl-open.c ++++ b/elf/dl-open.c +@@ -614,9 +614,10 @@ dl_open_worker (void *a) + if (GLRO(dl_lazy)) + reloc_mode |= mode & RTLD_LAZY; + +- /* Sort the objects by dependency for the relocation process. This +- allows IFUNC relocations to work and it also means copy +- relocation of dependencies are if necessary overwritten. */ ++ /* Objects must be sorted by dependency for the relocation process. ++ This allows IFUNC relocations to work and it also means copy ++ relocation of dependencies are if necessary overwritten. ++ __dl_map_object_deps has already sorted l_initfini for us. */ + unsigned int nmaps = 0; + unsigned int j = 0; + struct link_map *l = new->l_initfini[0]; +@@ -639,7 +640,6 @@ dl_open_worker (void *a) + l = new->l_initfini[++j]; + } + while (l != NULL); +- _dl_sort_maps (maps, nmaps, NULL, false); + + int relocation_in_progress = 0; + diff --git a/SOURCES/glibc-rh1812756-3.patch b/SOURCES/glibc-rh1812756-3.patch new file mode 100644 index 0000000..93e54e2 --- /dev/null +++ b/SOURCES/glibc-rh1812756-3.patch @@ -0,0 +1,68 @@ +commit 0a8ce6a0966283b17f373f430929bcadef1ae205 +Author: David Kilroy +Date: Wed Feb 12 14:31:17 2020 -0300 + + elf: avoid stack allocation in dl_open_worker + + As the sort was removed, there's no need to keep a separate map of + links. Instead, when relocating objects iterate over l_initfini + directly. + + This allows us to remove the loop copying l_initfini elements into + map. We still need a loop to identify the first and last elements that + need relocation. + + Tested by running the testsuite on x86_64. + +diff --git a/elf/dl-open.c b/elf/dl-open.c +index 980a28c836ca9a7a..46a4c1e5a3f8d2dd 100644 +--- a/elf/dl-open.c ++++ b/elf/dl-open.c +@@ -618,25 +618,18 @@ dl_open_worker (void *a) + This allows IFUNC relocations to work and it also means copy + relocation of dependencies are if necessary overwritten. + __dl_map_object_deps has already sorted l_initfini for us. */ +- unsigned int nmaps = 0; ++ unsigned int first = UINT_MAX; ++ unsigned int last = 0; + unsigned int j = 0; + struct link_map *l = new->l_initfini[0]; + do + { + if (! l->l_real->l_relocated) +- ++nmaps; +- l = new->l_initfini[++j]; +- } +- while (l != NULL); +- /* Stack allocation is limited by the number of loaded objects. */ +- struct link_map *maps[nmaps]; +- nmaps = 0; +- j = 0; +- l = new->l_initfini[0]; +- do +- { +- if (! l->l_real->l_relocated) +- maps[nmaps++] = l; ++ { ++ if (first == UINT_MAX) ++ first = j; ++ last = j + 1; ++ } + l = new->l_initfini[++j]; + } + while (l != NULL); +@@ -651,9 +644,12 @@ dl_open_worker (void *a) + them. However, such relocation dependencies in IFUNC resolvers + are undefined anyway, so this is not a problem. */ + +- for (unsigned int i = nmaps; i-- > 0; ) ++ for (unsigned int i = last; i-- > first; ) + { +- l = maps[i]; ++ l = new->l_initfini[i]; ++ ++ if (l->l_real->l_relocated) ++ continue; + + if (! relocation_in_progress) + { diff --git a/SOURCES/glibc-rh1813398.patch b/SOURCES/glibc-rh1813398.patch new file mode 100644 index 0000000..1355dfa --- /dev/null +++ b/SOURCES/glibc-rh1813398.patch @@ -0,0 +1,58 @@ +commit ddc650e9b3dc916eab417ce9f79e67337b05035c +Author: Andreas Schwab +Date: Wed Feb 19 17:21:46 2020 +0100 + + Fix use-after-free in glob when expanding ~user (bug 25414) + + The value of `end_name' points into the value of `dirname', thus don't + deallocate the latter before the last use of the former. + +diff --git a/posix/glob.c b/posix/glob.c +index cba9cd1819..4580cefb9f 100644 +--- a/posix/glob.c ++++ b/posix/glob.c +@@ -827,31 +827,32 @@ __glob (const char *pattern, int flags, int (*errfunc) (const char *, int), + { + size_t home_len = strlen (p->pw_dir); + size_t rest_len = end_name == NULL ? 0 : strlen (end_name); +- char *d; ++ char *d, *newp; ++ bool use_alloca = glob_use_alloca (alloca_used, ++ home_len + rest_len + 1); + +- if (__glibc_unlikely (malloc_dirname)) +- free (dirname); +- malloc_dirname = 0; +- +- if (glob_use_alloca (alloca_used, home_len + rest_len + 1)) +- dirname = alloca_account (home_len + rest_len + 1, +- alloca_used); ++ if (use_alloca) ++ newp = alloca_account (home_len + rest_len + 1, alloca_used); + else + { +- dirname = malloc (home_len + rest_len + 1); +- if (dirname == NULL) ++ newp = malloc (home_len + rest_len + 1); ++ if (newp == NULL) + { + scratch_buffer_free (&pwtmpbuf); + retval = GLOB_NOSPACE; + goto out; + } +- malloc_dirname = 1; + } +- d = mempcpy (dirname, p->pw_dir, home_len); ++ 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; + } diff --git a/SOURCES/glibc-rh1813399.patch b/SOURCES/glibc-rh1813399.patch new file mode 100644 index 0000000..16ef72d --- /dev/null +++ b/SOURCES/glibc-rh1813399.patch @@ -0,0 +1,59 @@ +commit d93769405996dfc11d216ddbe415946617b5a494 +Author: Andreas Schwab +Date: Mon Jan 20 17:01:50 2020 +0100 + + Fix array overflow in backtrace on PowerPC (bug 25423) + + When unwinding through a signal frame the backtrace function on PowerPC + didn't check array bounds when storing the frame address. Fixes commit + d400dcac5e ("PowerPC: fix backtrace to handle signal trampolines"). + +diff --git a/debug/tst-backtrace5.c b/debug/tst-backtrace5.c +index e7ce410845..b2f46160e7 100644 +--- a/debug/tst-backtrace5.c ++++ b/debug/tst-backtrace5.c +@@ -89,6 +89,18 @@ handle_signal (int signum) + } + /* Symbol names are not available for static functions, so we do not + check do_test. */ ++ ++ /* Check that backtrace does not return more than what fits in the array ++ (bug 25423). */ ++ for (int j = 0; j < NUM_FUNCTIONS; j++) ++ { ++ n = backtrace (addresses, j); ++ if (n > j) ++ { ++ FAIL (); ++ return; ++ } ++ } + } + + NO_INLINE int +diff --git a/sysdeps/powerpc/powerpc32/backtrace.c b/sysdeps/powerpc/powerpc32/backtrace.c +index 7c2d4726f8..d1456c8ae4 100644 +--- a/sysdeps/powerpc/powerpc32/backtrace.c ++++ b/sysdeps/powerpc/powerpc32/backtrace.c +@@ -114,6 +114,8 @@ __backtrace (void **array, int size) + } + if (gregset) + { ++ if (count + 1 == size) ++ break; + array[++count] = (void*)((*gregset)[PT_NIP]); + current = (void*)((*gregset)[PT_R1]); + } +diff --git a/sysdeps/powerpc/powerpc64/backtrace.c b/sysdeps/powerpc/powerpc64/backtrace.c +index 65c260ab76..8a53a1088f 100644 +--- a/sysdeps/powerpc/powerpc64/backtrace.c ++++ b/sysdeps/powerpc/powerpc64/backtrace.c +@@ -87,6 +87,8 @@ __backtrace (void **array, int size) + if (is_sigtramp_address (current->return_address)) + { + struct signal_frame_64 *sigframe = (struct signal_frame_64*) current; ++ if (count + 1 == size) ++ break; + array[++count] = (void*) sigframe->uc.uc_mcontext.gp_regs[PT_NIP]; + current = (void*) sigframe->uc.uc_mcontext.gp_regs[PT_R1]; + } diff --git a/SOURCES/glibc-rh1817513-1.patch b/SOURCES/glibc-rh1817513-1.patch new file mode 100644 index 0000000..5bfd84c --- /dev/null +++ b/SOURCES/glibc-rh1817513-1.patch @@ -0,0 +1,53 @@ +commit 82c80ac2ebf9acc81ec460adfd951d4884836c7c +Author: H.J. Lu +Date: Wed Aug 1 04:57:34 2018 -0700 + + x86: Rename get_common_indeces to get_common_indices + + Reviewed-by: Carlos O'Donell + + * sysdeps/x86/cpu-features.c (get_common_indeces): Renamed to + ... + (get_common_indices): This. + (init_cpu_features): Updated. + +diff --git a/sysdeps/x86/cpu-features.c b/sysdeps/x86/cpu-features.c +index ac74f408343191b0..41f2d15fa5c8a756 100644 +--- a/sysdeps/x86/cpu-features.c ++++ b/sysdeps/x86/cpu-features.c +@@ -56,7 +56,7 @@ get_extended_indices (struct cpu_features *cpu_features) + } + + static void +-get_common_indeces (struct cpu_features *cpu_features, ++get_common_indices (struct cpu_features *cpu_features, + unsigned int *family, unsigned int *model, + unsigned int *extended_model, unsigned int *stepping) + { +@@ -234,7 +234,7 @@ init_cpu_features (struct cpu_features *cpu_features) + + kind = arch_kind_intel; + +- get_common_indeces (cpu_features, &family, &model, &extended_model, ++ get_common_indices (cpu_features, &family, &model, &extended_model, + &stepping); + + get_extended_indices (cpu_features); +@@ -356,7 +356,7 @@ init_cpu_features (struct cpu_features *cpu_features) + + kind = arch_kind_amd; + +- get_common_indeces (cpu_features, &family, &model, &extended_model, ++ get_common_indices (cpu_features, &family, &model, &extended_model, + &stepping); + + get_extended_indices (cpu_features); +@@ -393,7 +393,7 @@ init_cpu_features (struct cpu_features *cpu_features) + else + { + kind = arch_kind_other; +- get_common_indeces (cpu_features, NULL, NULL, NULL, NULL); ++ get_common_indices (cpu_features, NULL, NULL, NULL, NULL); + } + + /* Support i586 if CX8 is available. */ diff --git a/SOURCES/glibc-rh1817513-10.patch b/SOURCES/glibc-rh1817513-10.patch new file mode 100644 index 0000000..fe934ce --- /dev/null +++ b/SOURCES/glibc-rh1817513-10.patch @@ -0,0 +1,41 @@ +commit 2dd8e58cc533ee840d37725b11bc0dc0308a5dc0 +Author: H.J. Lu +Date: Sun Oct 21 00:37:11 2018 -0700 + + x86: Don't include + + Use __builtin_ia32_rdtsc directly since including makes + building glibc very slow. On Intel Core i5-6260U, this patch reduces + x86-64 build time from 8 minutes 33 seconds to 3 minutes 48 seconds + with "make -j4" and GCC 8.2.1. + + * sysdeps/x86/hp-timing.h: Don't include . + (HP_TIMING_NOW): Replace _rdtsc with __builtin_ia32_rdtsc. + +diff --git a/sysdeps/x86/hp-timing.h b/sysdeps/x86/hp-timing.h +index 1c20e9d8289cc15b..77a1360748ca4535 100644 +--- a/sysdeps/x86/hp-timing.h ++++ b/sysdeps/x86/hp-timing.h +@@ -22,8 +22,6 @@ + #include + + #if MINIMUM_ISA == 686 || MINIMUM_ISA == 8664 +-# include +- + /* We always assume having the timestamp register. */ + # define HP_TIMING_AVAIL (1) + # define HP_SMALL_TIMING_AVAIL (1) +@@ -38,8 +36,11 @@ typedef unsigned long long int hp_timing_t; + might not be 100% accurate since there might be some more instructions + running in this moment. This could be changed by using a barrier like + 'cpuid' right before the `rdtsc' instruciton. But we are not interested +- in accurate clock cycles here so we don't do this. */ +-# define HP_TIMING_NOW(Var) ((Var) = _rdtsc ()) ++ in accurate clock cycles here so we don't do this. ++ ++ NB: Use __builtin_ia32_rdtsc directly since including ++ makes building glibc very slow. */ ++# define HP_TIMING_NOW(Var) ((Var) = __builtin_ia32_rdtsc ()) + + # include + #else diff --git a/SOURCES/glibc-rh1817513-100.patch b/SOURCES/glibc-rh1817513-100.patch new file mode 100644 index 0000000..9917f06 --- /dev/null +++ b/SOURCES/glibc-rh1817513-100.patch @@ -0,0 +1,82 @@ +commit bb5fd5ce64b598085bdb8a05cb53777480fe093c +Author: Florian Weimer +Date: Fri Oct 9 10:13:14 2020 +0200 + + elf: Do not pass GLRO(dl_platform), GLRO(dl_platformlen) to _dl_important_hwcaps + + In the current code, the function can easily obtain the information + on its own. + + Reviewed-by: Adhemerval Zanella + +diff --git a/elf/dl-hwcaps.c b/elf/dl-hwcaps.c +index ae2e4ca7fe91d407..82ee89c36a1eb4ab 100644 +--- a/elf/dl-hwcaps.c ++++ b/elf/dl-hwcaps.c +@@ -28,13 +28,12 @@ + + /* Return an array of useful/necessary hardware capability names. */ + const struct r_strlenpair * +-_dl_important_hwcaps (const char *platform, size_t platform_len, size_t *sz, +- size_t *max_capstrlen) ++_dl_important_hwcaps (size_t *sz, size_t *max_capstrlen) + { + uint64_t hwcap_mask = GET_HWCAP_MASK(); + /* Determine how many important bits are set. */ + uint64_t masked = GLRO(dl_hwcap) & hwcap_mask; +- size_t cnt = platform != NULL; ++ size_t cnt = GLRO (dl_platform) != NULL; + size_t n, m; + size_t total; + struct r_strlenpair *result; +@@ -60,10 +59,10 @@ _dl_important_hwcaps (const char *platform, size_t platform_len, size_t *sz, + masked ^= 1ULL << n; + ++m; + } +- if (platform != NULL) ++ if (GLRO (dl_platform) != NULL) + { +- temp[m].str = platform; +- temp[m].len = platform_len; ++ temp[m].str = GLRO (dl_platform); ++ temp[m].len = GLRO (dl_platformlen); + ++m; + } + +diff --git a/elf/dl-load.c b/elf/dl-load.c +index 2eb4f35b2467f7d8..d2be21ea7d1545fe 100644 +--- a/elf/dl-load.c ++++ b/elf/dl-load.c +@@ -697,8 +697,7 @@ _dl_init_paths (const char *llp, const char *source) + + #ifdef SHARED + /* Get the capabilities. */ +- capstr = _dl_important_hwcaps (GLRO(dl_platform), GLRO(dl_platformlen), +- &ncapstr, &max_capstrlen); ++ capstr = _dl_important_hwcaps (&ncapstr, &max_capstrlen); + #endif + + /* First set up the rest of the default search directory entries. */ +diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h +index aa006afafaf46dee..2c9fdeb286bdaadf 100644 +--- a/sysdeps/generic/ldsodefs.h ++++ b/sysdeps/generic/ldsodefs.h +@@ -1069,12 +1069,12 @@ extern void _dl_show_auxv (void) attribute_hidden; + other. */ + extern char *_dl_next_ld_env_entry (char ***position) attribute_hidden; + +-/* Return an array with the names of the important hardware capabilities. */ +-extern const struct r_strlenpair *_dl_important_hwcaps (const char *platform, +- size_t paltform_len, +- size_t *sz, +- size_t *max_capstrlen) +- attribute_hidden; ++/* Return an array with the names of the important hardware ++ capabilities. The length of the array is written to *SZ, and the ++ maximum of all strings length is written to *MAX_CAPSTRLEN. */ ++const struct r_strlenpair *_dl_important_hwcaps (size_t *sz, ++ size_t *max_capstrlen) ++ attribute_hidden; + + /* Look up NAME in ld.so.cache and return the file name stored there, + or null if none is found. Caller must free returned string. */ diff --git a/SOURCES/glibc-rh1817513-101.patch b/SOURCES/glibc-rh1817513-101.patch new file mode 100644 index 0000000..bcf0aae --- /dev/null +++ b/SOURCES/glibc-rh1817513-101.patch @@ -0,0 +1,65 @@ +commit 7674695cf7e28528be7243ceb30c9a600bbaa7b5 +Author: H.J. Lu +Date: Thu Oct 8 08:19:15 2020 -0700 + + : Add Intel UINTR support + + Add Intel UINTR support to . + +diff --git a/manual/platform.texi b/manual/platform.texi +index 95b0ed0642c9f8a9..0dd12a4353a93bf2 100644 +--- a/manual/platform.texi ++++ b/manual/platform.texi +@@ -583,6 +583,9 @@ using a TSC deadline value. + @item + @code{TSXLDTRK} -- TSXLDTRK instructions. + ++@item ++@code{UINTR} -- User interrupts. ++ + @item + @code{UMIP} -- User-mode instruction prevention. + +diff --git a/sysdeps/x86/sys/platform/x86.h b/sysdeps/x86/sys/platform/x86.h +index bcc81ab5f8ac8265..2760b81a56e6c7d7 100644 +--- a/sysdeps/x86/sys/platform/x86.h ++++ b/sysdeps/x86/sys/platform/x86.h +@@ -241,7 +241,7 @@ extern const struct cpu_features *__x86_get_cpu_features (unsigned int) + #define bit_cpu_AVX512_4VNNIW (1u << 2) + #define bit_cpu_AVX512_4FMAPS (1u << 3) + #define bit_cpu_FSRM (1u << 4) +-#define bit_cpu_INDEX_7_EDX_5 (1u << 5) ++#define bit_cpu_UINTR (1u << 5) + #define bit_cpu_INDEX_7_EDX_6 (1u << 6) + #define bit_cpu_INDEX_7_EDX_7 (1u << 7) + #define bit_cpu_AVX512_VP2INTERSECT (1u << 8) +@@ -460,7 +460,7 @@ extern const struct cpu_features *__x86_get_cpu_features (unsigned int) + #define index_cpu_AVX512_4VNNIW COMMON_CPUID_INDEX_7 + #define index_cpu_AVX512_4FMAPS COMMON_CPUID_INDEX_7 + #define index_cpu_FSRM COMMON_CPUID_INDEX_7 +-#define index_cpu_INDEX_7_EDX_5 COMMON_CPUID_INDEX_7 ++#define index_cpu_UINTR COMMON_CPUID_INDEX_7 + #define index_cpu_INDEX_7_EDX_6 COMMON_CPUID_INDEX_7 + #define index_cpu_INDEX_7_EDX_7 COMMON_CPUID_INDEX_7 + #define index_cpu_AVX512_VP2INTERSECT COMMON_CPUID_INDEX_7 +@@ -679,7 +679,7 @@ extern const struct cpu_features *__x86_get_cpu_features (unsigned int) + #define reg_AVX512_4VNNIW edx + #define reg_AVX512_4FMAPS edx + #define reg_FSRM edx +-#define reg_INDEX_7_EDX_5 edx ++#define reg_UINTR edx + #define reg_INDEX_7_EDX_6 edx + #define reg_INDEX_7_EDX_7 edx + #define reg_AVX512_VP2INTERSECT edx +diff --git a/sysdeps/x86/tst-get-cpu-features.c b/sysdeps/x86/tst-get-cpu-features.c +index 3ec94e0c9a191f36..6fa092a8c10486a0 100644 +--- a/sysdeps/x86/tst-get-cpu-features.c ++++ b/sysdeps/x86/tst-get-cpu-features.c +@@ -180,6 +180,7 @@ do_test (void) + CHECK_CPU_FEATURE (AVX512_4VNNIW); + CHECK_CPU_FEATURE (AVX512_4FMAPS); + CHECK_CPU_FEATURE (FSRM); ++ CHECK_CPU_FEATURE (UINTR); + CHECK_CPU_FEATURE (AVX512_VP2INTERSECT); + CHECK_CPU_FEATURE (MD_CLEAR); + CHECK_CPU_FEATURE (SERIALIZE); diff --git a/SOURCES/glibc-rh1817513-102.patch b/SOURCES/glibc-rh1817513-102.patch new file mode 100644 index 0000000..73fa041 --- /dev/null +++ b/SOURCES/glibc-rh1817513-102.patch @@ -0,0 +1,86 @@ +commit ebe454bcca6a5421512ad228595a5391506e990a +Author: H.J. Lu +Date: Thu Oct 8 08:24:47 2020 -0700 + + : Add AVX512_FP16 support + + Add AVX512_FP16 support to . + +diff --git a/manual/platform.texi b/manual/platform.texi +index 0dd12a4353a93bf2..4f5fdff9d9ef16fd 100644 +--- a/manual/platform.texi ++++ b/manual/platform.texi +@@ -210,6 +210,9 @@ The supported processor features are: + @item + @code{AVX512_BITALG} -- The AVX512_BITALG instruction extensions. + ++@item ++@code{AVX512_FP16} -- The AVX512_FP16 instruction extensions. ++ + @item + @code{AVX512_IFMA} -- The AVX512_IFMA instruction extensions. + +diff --git a/sysdeps/x86/cpu-features.c b/sysdeps/x86/cpu-features.c +index 7f2ff00f2b4b45f2..67f137259fccf4ad 100644 +--- a/sysdeps/x86/cpu-features.c ++++ b/sysdeps/x86/cpu-features.c +@@ -175,6 +175,8 @@ update_usable (struct cpu_features *cpu_features) + AVX512_VP2INTERSECT); + /* Determine if AVX512_BF16 is usable. */ + CPU_FEATURE_SET_USABLE (cpu_features, AVX512_BF16); ++ /* Determine if AVX512_FP16 is usable. */ ++ CPU_FEATURE_SET_USABLE (cpu_features, AVX512_FP16); + } + } + } +diff --git a/sysdeps/x86/sys/platform/x86.h b/sysdeps/x86/sys/platform/x86.h +index 2760b81a56e6c7d7..0b18257e20105ea4 100644 +--- a/sysdeps/x86/sys/platform/x86.h ++++ b/sysdeps/x86/sys/platform/x86.h +@@ -259,7 +259,7 @@ extern const struct cpu_features *__x86_get_cpu_features (unsigned int) + #define bit_cpu_IBT (1u << 20) + #define bit_cpu_INDEX_7_EDX_21 (1u << 21) + #define bit_cpu_AMX_BF16 (1u << 22) +-#define bit_cpu_INDEX_7_EDX_23 (1u << 23) ++#define bit_cpu_AVX512_FP16 (1u << 23) + #define bit_cpu_AMX_TILE (1u << 24) + #define bit_cpu_AMX_INT8 (1u << 25) + #define bit_cpu_IBRS_IBPB (1u << 26) +@@ -478,7 +478,7 @@ extern const struct cpu_features *__x86_get_cpu_features (unsigned int) + #define index_cpu_IBT COMMON_CPUID_INDEX_7 + #define index_cpu_INDEX_7_EDX_21 COMMON_CPUID_INDEX_7 + #define index_cpu_AMX_BF16 COMMON_CPUID_INDEX_7 +-#define index_cpu_INDEX_7_EDX_23 COMMON_CPUID_INDEX_7 ++#define index_cpu_AVX512_FP16 COMMON_CPUID_INDEX_7 + #define index_cpu_AMX_TILE COMMON_CPUID_INDEX_7 + #define index_cpu_AMX_INT8 COMMON_CPUID_INDEX_7 + #define index_cpu_IBRS_IBPB COMMON_CPUID_INDEX_7 +@@ -697,7 +697,7 @@ extern const struct cpu_features *__x86_get_cpu_features (unsigned int) + #define reg_IBT edx + #define reg_INDEX_7_EDX_21 edx + #define reg_AMX_BF16 edx +-#define reg_INDEX_7_EDX_23 edx ++#define reg_AVX512_FP16 edx + #define reg_AMX_TILE edx + #define reg_AMX_INT8 edx + #define reg_IBRS_IBPB edx +diff --git a/sysdeps/x86/tst-get-cpu-features.c b/sysdeps/x86/tst-get-cpu-features.c +index 6fa092a8c10486a0..bcdeb243a82c4adc 100644 +--- a/sysdeps/x86/tst-get-cpu-features.c ++++ b/sysdeps/x86/tst-get-cpu-features.c +@@ -189,6 +189,7 @@ do_test (void) + CHECK_CPU_FEATURE (PCONFIG); + CHECK_CPU_FEATURE (IBT); + CHECK_CPU_FEATURE (AMX_BF16); ++ CHECK_CPU_FEATURE (AVX512_FP16); + CHECK_CPU_FEATURE (AMX_TILE); + CHECK_CPU_FEATURE (AMX_INT8); + CHECK_CPU_FEATURE (IBRS_IBPB); +@@ -343,6 +344,7 @@ do_test (void) + CHECK_CPU_FEATURE_USABLE (TSXLDTRK); + CHECK_CPU_FEATURE_USABLE (PCONFIG); + CHECK_CPU_FEATURE_USABLE (AMX_BF16); ++ CHECK_CPU_FEATURE_USABLE (AVX512_FP16); + CHECK_CPU_FEATURE_USABLE (AMX_TILE); + CHECK_CPU_FEATURE_USABLE (AMX_INT8); + CHECK_CPU_FEATURE_USABLE (IBRS_IBPB); diff --git a/SOURCES/glibc-rh1817513-103.patch b/SOURCES/glibc-rh1817513-103.patch new file mode 100644 index 0000000..0c4db8f --- /dev/null +++ b/SOURCES/glibc-rh1817513-103.patch @@ -0,0 +1,83 @@ +commit 875a50ff63b2c86af770949d563ee851d08eb46e +Author: H.J. Lu +Date: Thu Oct 8 08:33:45 2020 -0700 + + : Add AVX-VNNI support + + Add AVX-VNNI support to . + +diff --git a/manual/platform.texi b/manual/platform.texi +index 4f5fdff9d9ef16fd..283f255679643d3e 100644 +--- a/manual/platform.texi ++++ b/manual/platform.texi +@@ -198,6 +198,9 @@ The supported processor features are: + @item + @code{AVX2} -- The AVX2 instruction extensions. + ++@item ++@code{AVX_VNNI} -- The AVX-VNNI instruction extensions. ++ + @item + @code{AVX512_4FMAPS} -- The AVX512_4FMAPS instruction extensions. + +diff --git a/sysdeps/x86/cpu-features.c b/sysdeps/x86/cpu-features.c +index 67f137259fccf4ad..3e5b9341c9756009 100644 +--- a/sysdeps/x86/cpu-features.c ++++ b/sysdeps/x86/cpu-features.c +@@ -119,6 +119,8 @@ update_usable (struct cpu_features *cpu_features) + cpu_features->preferred[index_arch_AVX_Fast_Unaligned_Load] + |= bit_arch_AVX_Fast_Unaligned_Load; + } ++ /* Determine if AVX-VNNI is usable. */ ++ CPU_FEATURE_SET_USABLE (cpu_features, AVX_VNNI); + /* Determine if FMA is usable. */ + CPU_FEATURE_SET_USABLE (cpu_features, FMA); + /* Determine if VAES is usable. */ +diff --git a/sysdeps/x86/sys/platform/x86.h b/sysdeps/x86/sys/platform/x86.h +index 0b18257e20105ea4..0942ad7a7f7d4ce2 100644 +--- a/sysdeps/x86/sys/platform/x86.h ++++ b/sysdeps/x86/sys/platform/x86.h +@@ -311,6 +311,7 @@ extern const struct cpu_features *__x86_get_cpu_features (unsigned int) + /* COMMON_CPUID_INDEX_7_ECX_1. */ + + /* EAX. */ ++#define bit_cpu_AVX_VNNI (1u << 4) + #define bit_cpu_AVX512_BF16 (1u << 5) + + /* COMMON_CPUID_INDEX_19. */ +@@ -530,6 +531,7 @@ extern const struct cpu_features *__x86_get_cpu_features (unsigned int) + /* COMMON_CPUID_INDEX_7_ECX_1. */ + + /* EAX. */ ++#define index_cpu_AVX_VNNI COMMON_CPUID_INDEX_7_ECX_1 + #define index_cpu_AVX512_BF16 COMMON_CPUID_INDEX_7_ECX_1 + + /* COMMON_CPUID_INDEX_19. */ +@@ -749,6 +751,7 @@ extern const struct cpu_features *__x86_get_cpu_features (unsigned int) + /* COMMON_CPUID_INDEX_7_ECX_1. */ + + /* EAX. */ ++#define reg_AVX_VNNI eax + #define reg_AVX512_BF16 eax + + /* COMMON_CPUID_INDEX_19. */ +diff --git a/sysdeps/x86/tst-get-cpu-features.c b/sysdeps/x86/tst-get-cpu-features.c +index bcdeb243a82c4adc..8894d9f08ac36633 100644 +--- a/sysdeps/x86/tst-get-cpu-features.c ++++ b/sysdeps/x86/tst-get-cpu-features.c +@@ -219,6 +219,7 @@ do_test (void) + CHECK_CPU_FEATURE (XFD); + CHECK_CPU_FEATURE (INVARIANT_TSC); + CHECK_CPU_FEATURE (WBNOINVD); ++ CHECK_CPU_FEATURE (AVX_VNNI); + CHECK_CPU_FEATURE (AVX512_BF16); + CHECK_CPU_FEATURE (AESKLE); + CHECK_CPU_FEATURE (WIDE_KL); +@@ -374,6 +375,7 @@ do_test (void) + CHECK_CPU_FEATURE_USABLE (XFD); + CHECK_CPU_FEATURE_USABLE (INVARIANT_TSC); + CHECK_CPU_FEATURE_USABLE (WBNOINVD); ++ CHECK_CPU_FEATURE_USABLE (AVX_VNNI); + CHECK_CPU_FEATURE_USABLE (AVX512_BF16); + CHECK_CPU_FEATURE_USABLE (AESKLE); + CHECK_CPU_FEATURE_USABLE (WIDE_KL); diff --git a/SOURCES/glibc-rh1817513-104.patch b/SOURCES/glibc-rh1817513-104.patch new file mode 100644 index 0000000..8e0f358 --- /dev/null +++ b/SOURCES/glibc-rh1817513-104.patch @@ -0,0 +1,62 @@ +commit c712401bc641b66d9bd558884751d8979e2e0e96 +Author: H.J. Lu +Date: Thu Oct 8 08:38:03 2020 -0700 + + : Add Intel HRESET support + + Add Intel HRESET support to . + +diff --git a/manual/platform.texi b/manual/platform.texi +index 283f255679643d3e..1e44525552f5bda5 100644 +--- a/manual/platform.texi ++++ b/manual/platform.texi +@@ -346,6 +346,9 @@ extensions. + @item + @code{HTT} -- Max APIC IDs reserved field is Valid. + ++@item ++@code{HRESET} -- History reset. ++ + @item + @code{HYBRID} -- Hybrid processor. + +diff --git a/sysdeps/x86/sys/platform/x86.h b/sysdeps/x86/sys/platform/x86.h +index 0942ad7a7f7d4ce2..357c6f1c5605d82d 100644 +--- a/sysdeps/x86/sys/platform/x86.h ++++ b/sysdeps/x86/sys/platform/x86.h +@@ -313,6 +313,7 @@ extern const struct cpu_features *__x86_get_cpu_features (unsigned int) + /* EAX. */ + #define bit_cpu_AVX_VNNI (1u << 4) + #define bit_cpu_AVX512_BF16 (1u << 5) ++#define bit_cpu_HRESET (1u << 22) + + /* COMMON_CPUID_INDEX_19. */ + +@@ -533,6 +534,7 @@ extern const struct cpu_features *__x86_get_cpu_features (unsigned int) + /* EAX. */ + #define index_cpu_AVX_VNNI COMMON_CPUID_INDEX_7_ECX_1 + #define index_cpu_AVX512_BF16 COMMON_CPUID_INDEX_7_ECX_1 ++#define index_cpu_HRESET COMMON_CPUID_INDEX_7_ECX_1 + + /* COMMON_CPUID_INDEX_19. */ + +@@ -753,6 +755,7 @@ extern const struct cpu_features *__x86_get_cpu_features (unsigned int) + /* EAX. */ + #define reg_AVX_VNNI eax + #define reg_AVX512_BF16 eax ++#define reg_HRESET eax + + /* COMMON_CPUID_INDEX_19. */ + +diff --git a/sysdeps/x86/tst-get-cpu-features.c b/sysdeps/x86/tst-get-cpu-features.c +index 8894d9f08ac36633..1516af1d461a801b 100644 +--- a/sysdeps/x86/tst-get-cpu-features.c ++++ b/sysdeps/x86/tst-get-cpu-features.c +@@ -221,6 +221,7 @@ do_test (void) + CHECK_CPU_FEATURE (WBNOINVD); + CHECK_CPU_FEATURE (AVX_VNNI); + CHECK_CPU_FEATURE (AVX512_BF16); ++ CHECK_CPU_FEATURE (HRESET); + CHECK_CPU_FEATURE (AESKLE); + CHECK_CPU_FEATURE (WIDE_KL); + diff --git a/SOURCES/glibc-rh1817513-105.patch b/SOURCES/glibc-rh1817513-105.patch new file mode 100644 index 0000000..5767dbc --- /dev/null +++ b/SOURCES/glibc-rh1817513-105.patch @@ -0,0 +1,107 @@ +commit 428985c436f442e91e27173bccaf28f547233586 +Author: H.J. Lu +Date: Thu Oct 8 08:50:44 2020 -0700 + + : Add FSRCS/FSRS/FZLRM support + + Add Fast Short REP CMP and SCA (FSRCS), Fast Short REP STO (FSRS) and + Fast Zero-Length REP MOV (FZLRM) support to . + +diff --git a/manual/platform.texi b/manual/platform.texi +index 1e44525552f5bda5..8fec2933d6442823 100644 +--- a/manual/platform.texi ++++ b/manual/platform.texi +@@ -331,12 +331,21 @@ extensions. + @item + @code{FSGSBASE} -- RDFSBASE/RDGSBASE/WRFSBASE/WRGSBASE instructions. + ++@item ++@code{FSRCS} -- Fast Short REP CMP and SCA. ++ + @item + @code{FSRM} -- Fast Short REP MOV. + ++@item ++@code{FSRS} -- Fast Short REP STO. ++ + @item + @code{FXSR} -- FXSAVE and FXRSTOR instructions. + ++@item ++@code{FZLRM} -- Fast Zero-Length REP MOV. ++ + @item + @code{GFNI} -- GFNI instruction extensions. + +diff --git a/sysdeps/x86/cpu-features.c b/sysdeps/x86/cpu-features.c +index 3e5b9341c9756009..5f0548fe08134236 100644 +--- a/sysdeps/x86/cpu-features.c ++++ b/sysdeps/x86/cpu-features.c +@@ -93,6 +93,9 @@ update_usable (struct cpu_features *cpu_features) + CPU_FEATURE_SET_USABLE (cpu_features, TBM); + CPU_FEATURE_SET_USABLE (cpu_features, RDTSCP); + CPU_FEATURE_SET_USABLE (cpu_features, WBNOINVD); ++ CPU_FEATURE_SET_USABLE (cpu_features, FZLRM); ++ CPU_FEATURE_SET_USABLE (cpu_features, FSRS); ++ CPU_FEATURE_SET_USABLE (cpu_features, FSRCS); + + /* Can we call xgetbv? */ + if (CPU_FEATURES_CPU_P (cpu_features, OSXSAVE)) +diff --git a/sysdeps/x86/sys/platform/x86.h b/sysdeps/x86/sys/platform/x86.h +index 357c6f1c5605d82d..e5cc7c683a20b5a0 100644 +--- a/sysdeps/x86/sys/platform/x86.h ++++ b/sysdeps/x86/sys/platform/x86.h +@@ -313,6 +313,9 @@ extern const struct cpu_features *__x86_get_cpu_features (unsigned int) + /* EAX. */ + #define bit_cpu_AVX_VNNI (1u << 4) + #define bit_cpu_AVX512_BF16 (1u << 5) ++#define bit_cpu_FZLRM (1u << 10) ++#define bit_cpu_FSRS (1u << 11) ++#define bit_cpu_FSRCS (1u << 12) + #define bit_cpu_HRESET (1u << 22) + + /* COMMON_CPUID_INDEX_19. */ +@@ -534,6 +537,9 @@ extern const struct cpu_features *__x86_get_cpu_features (unsigned int) + /* EAX. */ + #define index_cpu_AVX_VNNI COMMON_CPUID_INDEX_7_ECX_1 + #define index_cpu_AVX512_BF16 COMMON_CPUID_INDEX_7_ECX_1 ++#define index_cpu_FZLRM COMMON_CPUID_INDEX_7_ECX_1 ++#define index_cpu_FSRS COMMON_CPUID_INDEX_7_ECX_1 ++#define index_cpu_FSRCS COMMON_CPUID_INDEX_7_ECX_1 + #define index_cpu_HRESET COMMON_CPUID_INDEX_7_ECX_1 + + /* COMMON_CPUID_INDEX_19. */ +@@ -755,6 +761,9 @@ extern const struct cpu_features *__x86_get_cpu_features (unsigned int) + /* EAX. */ + #define reg_AVX_VNNI eax + #define reg_AVX512_BF16 eax ++#define reg_FZLRM eax ++#define reg_FSRS eax ++#define reg_FSRCS eax + #define reg_HRESET eax + + /* COMMON_CPUID_INDEX_19. */ +diff --git a/sysdeps/x86/tst-get-cpu-features.c b/sysdeps/x86/tst-get-cpu-features.c +index 1516af1d461a801b..2763deb6d008597f 100644 +--- a/sysdeps/x86/tst-get-cpu-features.c ++++ b/sysdeps/x86/tst-get-cpu-features.c +@@ -221,6 +221,9 @@ do_test (void) + CHECK_CPU_FEATURE (WBNOINVD); + CHECK_CPU_FEATURE (AVX_VNNI); + CHECK_CPU_FEATURE (AVX512_BF16); ++ CHECK_CPU_FEATURE (FZLRM); ++ CHECK_CPU_FEATURE (FSRS); ++ CHECK_CPU_FEATURE (FSRCS); + CHECK_CPU_FEATURE (HRESET); + CHECK_CPU_FEATURE (AESKLE); + CHECK_CPU_FEATURE (WIDE_KL); +@@ -378,6 +381,9 @@ do_test (void) + CHECK_CPU_FEATURE_USABLE (WBNOINVD); + CHECK_CPU_FEATURE_USABLE (AVX_VNNI); + CHECK_CPU_FEATURE_USABLE (AVX512_BF16); ++ CHECK_CPU_FEATURE_USABLE (FZLRM); ++ CHECK_CPU_FEATURE_USABLE (FSRS); ++ CHECK_CPU_FEATURE_USABLE (FSRCS); + CHECK_CPU_FEATURE_USABLE (AESKLE); + CHECK_CPU_FEATURE_USABLE (WIDE_KL); + diff --git a/SOURCES/glibc-rh1817513-106.patch b/SOURCES/glibc-rh1817513-106.patch new file mode 100644 index 0000000..9e30fb5 --- /dev/null +++ b/SOURCES/glibc-rh1817513-106.patch @@ -0,0 +1,18 @@ +commit 21181d1c7b181c4bb71e587c7944e100d923b393 +Author: Matheus Castanho +Date: Mon Oct 12 11:28:18 2020 +0200 + + elf: Add missing header to elf/dl-usage.c + +diff --git a/elf/dl-usage.c b/elf/dl-usage.c +index c07f43835bd771cf..796ad38b43c2211b 100644 +--- a/elf/dl-usage.c ++++ b/elf/dl-usage.c +@@ -22,6 +22,7 @@ + #include + #include "version.h" + ++#include + #include + + void diff --git a/SOURCES/glibc-rh1817513-107.patch b/SOURCES/glibc-rh1817513-107.patch new file mode 100644 index 0000000..ac33688 --- /dev/null +++ b/SOURCES/glibc-rh1817513-107.patch @@ -0,0 +1,2017 @@ +commit 0f09154c64005e78b61484ae87b5ea2028051ea0 +Author: H.J. Lu +Date: Sat Jul 4 06:35:49 2020 -0700 + + x86: Initialize CPU info via IFUNC relocation [BZ 26203] + + X86 CPU features in ld.so are initialized by init_cpu_features, which is + invoked by DL_PLATFORM_INIT from _dl_sysdep_start. But when ld.so is + loaded by static executable, DL_PLATFORM_INIT is never called. Also + x86 cache info in libc.o and libc.a is initialized by a constructor + which may be called too late. Since some fields in _rtld_global_ro + in ld.so are initialized by dynamic relocation, we can also initialize + x86 CPU features in _rtld_global_ro in ld.so and cache info in libc.so + by initializing dummy function pointers in ld.so and libc.so via IFUNC + relocation. + + Key points: + + 1. IFUNC is always supported, independent of --enable-multi-arch or + --disable-multi-arch. Linker generates IFUNC relocations from input + IFUNC objects and ld.so performs IFUNC relocations. + 2. There are no IFUNC dependencies in ld.so before dynamic relocation + have been performed, + 3. The x86 CPU features in ld.so is initialized by DL_PLATFORM_INIT + in dynamic executable and by IFUNC relocation in dlopen in static + executable. + 4. The x86 cache info in libc.o is initialized by IFUNC relocation. + 5. In libc.a, both x86 CPU features and cache info are initialized from + ARCH_INIT_CPU_FEATURES, not by IFUNC relocation, before __libc_early_init + is called. + + Note: _dl_x86_init_cpu_features can be called more than once from + DL_PLATFORM_INIT and during relocation in ld.so. + +Conflicts: + sysdeps/x86/cacheinfo.c + (Copyright year difference, and AMD Zen cache computation + backports downstream. These changes were reapplied to + sysdeps/x86/cacheinfo.h, mirroring the upstream refactoring + in the backported commit.) + sysdeps/x86/dl-get-cpu-features.c + (Copyright year difference.) + +diff --git a/sysdeps/i386/dl-machine.h b/sysdeps/i386/dl-machine.h +index 8c959e39457c8c41..e5776ef7bc8ad749 100644 +--- a/sysdeps/i386/dl-machine.h ++++ b/sysdeps/i386/dl-machine.h +@@ -25,7 +25,6 @@ + #include + #include + #include +-#include + + /* Return nonzero iff ELF header is compatible with the running host. */ + static inline int __attribute__ ((unused)) +@@ -248,9 +247,9 @@ static inline void __attribute__ ((unused)) + dl_platform_init (void) + { + #if IS_IN (rtld) +- /* init_cpu_features has been called early from __libc_start_main in +- static executable. */ +- init_cpu_features (&GLRO(dl_x86_cpu_features)); ++ /* _dl_x86_init_cpu_features is a wrapper for init_cpu_features which ++ has been called early from __libc_start_main in static executable. */ ++ _dl_x86_init_cpu_features (); + #else + if (GLRO(dl_platform) != NULL && *GLRO(dl_platform) == '\0') + /* Avoid an empty string which would disturb us. */ +diff --git a/sysdeps/x86/cacheinfo.c b/sysdeps/x86/cacheinfo.c +index fdfe2684759d968c..84b10f6dd8d23a51 100644 +--- a/sysdeps/x86/cacheinfo.c ++++ b/sysdeps/x86/cacheinfo.c +@@ -1,5 +1,5 @@ +-/* x86_64 cache info. +- Copyright (C) 2003-2018 Free Software Foundation, Inc. ++/* x86 cache info. ++ Copyright (C) 2003-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 +@@ -19,473 +19,10 @@ + #if IS_IN (libc) + + #include +-#include +-#include + #include + #include +-#include +- +-static const struct intel_02_cache_info +-{ +- unsigned char idx; +- unsigned char assoc; +- unsigned char linesize; +- unsigned char rel_name; +- unsigned int size; +-} intel_02_known [] = +- { +-#define M(sc) ((sc) - _SC_LEVEL1_ICACHE_SIZE) +- { 0x06, 4, 32, M(_SC_LEVEL1_ICACHE_SIZE), 8192 }, +- { 0x08, 4, 32, M(_SC_LEVEL1_ICACHE_SIZE), 16384 }, +- { 0x09, 4, 32, M(_SC_LEVEL1_ICACHE_SIZE), 32768 }, +- { 0x0a, 2, 32, M(_SC_LEVEL1_DCACHE_SIZE), 8192 }, +- { 0x0c, 4, 32, M(_SC_LEVEL1_DCACHE_SIZE), 16384 }, +- { 0x0d, 4, 64, M(_SC_LEVEL1_DCACHE_SIZE), 16384 }, +- { 0x0e, 6, 64, M(_SC_LEVEL1_DCACHE_SIZE), 24576 }, +- { 0x21, 8, 64, M(_SC_LEVEL2_CACHE_SIZE), 262144 }, +- { 0x22, 4, 64, M(_SC_LEVEL3_CACHE_SIZE), 524288 }, +- { 0x23, 8, 64, M(_SC_LEVEL3_CACHE_SIZE), 1048576 }, +- { 0x25, 8, 64, M(_SC_LEVEL3_CACHE_SIZE), 2097152 }, +- { 0x29, 8, 64, M(_SC_LEVEL3_CACHE_SIZE), 4194304 }, +- { 0x2c, 8, 64, M(_SC_LEVEL1_DCACHE_SIZE), 32768 }, +- { 0x30, 8, 64, M(_SC_LEVEL1_ICACHE_SIZE), 32768 }, +- { 0x39, 4, 64, M(_SC_LEVEL2_CACHE_SIZE), 131072 }, +- { 0x3a, 6, 64, M(_SC_LEVEL2_CACHE_SIZE), 196608 }, +- { 0x3b, 2, 64, M(_SC_LEVEL2_CACHE_SIZE), 131072 }, +- { 0x3c, 4, 64, M(_SC_LEVEL2_CACHE_SIZE), 262144 }, +- { 0x3d, 6, 64, M(_SC_LEVEL2_CACHE_SIZE), 393216 }, +- { 0x3e, 4, 64, M(_SC_LEVEL2_CACHE_SIZE), 524288 }, +- { 0x3f, 2, 64, M(_SC_LEVEL2_CACHE_SIZE), 262144 }, +- { 0x41, 4, 32, M(_SC_LEVEL2_CACHE_SIZE), 131072 }, +- { 0x42, 4, 32, M(_SC_LEVEL2_CACHE_SIZE), 262144 }, +- { 0x43, 4, 32, M(_SC_LEVEL2_CACHE_SIZE), 524288 }, +- { 0x44, 4, 32, M(_SC_LEVEL2_CACHE_SIZE), 1048576 }, +- { 0x45, 4, 32, M(_SC_LEVEL2_CACHE_SIZE), 2097152 }, +- { 0x46, 4, 64, M(_SC_LEVEL3_CACHE_SIZE), 4194304 }, +- { 0x47, 8, 64, M(_SC_LEVEL3_CACHE_SIZE), 8388608 }, +- { 0x48, 12, 64, M(_SC_LEVEL2_CACHE_SIZE), 3145728 }, +- { 0x49, 16, 64, M(_SC_LEVEL2_CACHE_SIZE), 4194304 }, +- { 0x4a, 12, 64, M(_SC_LEVEL3_CACHE_SIZE), 6291456 }, +- { 0x4b, 16, 64, M(_SC_LEVEL3_CACHE_SIZE), 8388608 }, +- { 0x4c, 12, 64, M(_SC_LEVEL3_CACHE_SIZE), 12582912 }, +- { 0x4d, 16, 64, M(_SC_LEVEL3_CACHE_SIZE), 16777216 }, +- { 0x4e, 24, 64, M(_SC_LEVEL2_CACHE_SIZE), 6291456 }, +- { 0x60, 8, 64, M(_SC_LEVEL1_DCACHE_SIZE), 16384 }, +- { 0x66, 4, 64, M(_SC_LEVEL1_DCACHE_SIZE), 8192 }, +- { 0x67, 4, 64, M(_SC_LEVEL1_DCACHE_SIZE), 16384 }, +- { 0x68, 4, 64, M(_SC_LEVEL1_DCACHE_SIZE), 32768 }, +- { 0x78, 8, 64, M(_SC_LEVEL2_CACHE_SIZE), 1048576 }, +- { 0x79, 8, 64, M(_SC_LEVEL2_CACHE_SIZE), 131072 }, +- { 0x7a, 8, 64, M(_SC_LEVEL2_CACHE_SIZE), 262144 }, +- { 0x7b, 8, 64, M(_SC_LEVEL2_CACHE_SIZE), 524288 }, +- { 0x7c, 8, 64, M(_SC_LEVEL2_CACHE_SIZE), 1048576 }, +- { 0x7d, 8, 64, M(_SC_LEVEL2_CACHE_SIZE), 2097152 }, +- { 0x7f, 2, 64, M(_SC_LEVEL2_CACHE_SIZE), 524288 }, +- { 0x80, 8, 64, M(_SC_LEVEL2_CACHE_SIZE), 524288 }, +- { 0x82, 8, 32, M(_SC_LEVEL2_CACHE_SIZE), 262144 }, +- { 0x83, 8, 32, M(_SC_LEVEL2_CACHE_SIZE), 524288 }, +- { 0x84, 8, 32, M(_SC_LEVEL2_CACHE_SIZE), 1048576 }, +- { 0x85, 8, 32, M(_SC_LEVEL2_CACHE_SIZE), 2097152 }, +- { 0x86, 4, 64, M(_SC_LEVEL2_CACHE_SIZE), 524288 }, +- { 0x87, 8, 64, M(_SC_LEVEL2_CACHE_SIZE), 1048576 }, +- { 0xd0, 4, 64, M(_SC_LEVEL3_CACHE_SIZE), 524288 }, +- { 0xd1, 4, 64, M(_SC_LEVEL3_CACHE_SIZE), 1048576 }, +- { 0xd2, 4, 64, M(_SC_LEVEL3_CACHE_SIZE), 2097152 }, +- { 0xd6, 8, 64, M(_SC_LEVEL3_CACHE_SIZE), 1048576 }, +- { 0xd7, 8, 64, M(_SC_LEVEL3_CACHE_SIZE), 2097152 }, +- { 0xd8, 8, 64, M(_SC_LEVEL3_CACHE_SIZE), 4194304 }, +- { 0xdc, 12, 64, M(_SC_LEVEL3_CACHE_SIZE), 2097152 }, +- { 0xdd, 12, 64, M(_SC_LEVEL3_CACHE_SIZE), 4194304 }, +- { 0xde, 12, 64, M(_SC_LEVEL3_CACHE_SIZE), 8388608 }, +- { 0xe2, 16, 64, M(_SC_LEVEL3_CACHE_SIZE), 2097152 }, +- { 0xe3, 16, 64, M(_SC_LEVEL3_CACHE_SIZE), 4194304 }, +- { 0xe4, 16, 64, M(_SC_LEVEL3_CACHE_SIZE), 8388608 }, +- { 0xea, 24, 64, M(_SC_LEVEL3_CACHE_SIZE), 12582912 }, +- { 0xeb, 24, 64, M(_SC_LEVEL3_CACHE_SIZE), 18874368 }, +- { 0xec, 24, 64, M(_SC_LEVEL3_CACHE_SIZE), 25165824 }, +- }; +- +-#define nintel_02_known (sizeof (intel_02_known) / sizeof (intel_02_known [0])) +- +-static int +-intel_02_known_compare (const void *p1, const void *p2) +-{ +- const struct intel_02_cache_info *i1; +- const struct intel_02_cache_info *i2; +- +- i1 = (const struct intel_02_cache_info *) p1; +- i2 = (const struct intel_02_cache_info *) p2; +- +- if (i1->idx == i2->idx) +- return 0; +- +- return i1->idx < i2->idx ? -1 : 1; +-} +- +- +-static long int +-__attribute__ ((noinline)) +-intel_check_word (int name, unsigned int value, bool *has_level_2, +- bool *no_level_2_or_3, +- const struct cpu_features *cpu_features) +-{ +- if ((value & 0x80000000) != 0) +- /* The register value is reserved. */ +- return 0; +- +- /* Fold the name. The _SC_ constants are always in the order SIZE, +- ASSOC, LINESIZE. */ +- int folded_rel_name = (M(name) / 3) * 3; +- +- while (value != 0) +- { +- unsigned int byte = value & 0xff; +- +- if (byte == 0x40) +- { +- *no_level_2_or_3 = true; +- +- if (folded_rel_name == M(_SC_LEVEL3_CACHE_SIZE)) +- /* No need to look further. */ +- break; +- } +- else if (byte == 0xff) +- { +- /* CPUID leaf 0x4 contains all the information. We need to +- iterate over it. */ +- unsigned int eax; +- unsigned int ebx; +- unsigned int ecx; +- unsigned int edx; +- +- unsigned int round = 0; +- while (1) +- { +- __cpuid_count (4, round, eax, ebx, ecx, edx); +- +- enum { null = 0, data = 1, inst = 2, uni = 3 } type = eax & 0x1f; +- if (type == null) +- /* That was the end. */ +- break; +- +- unsigned int level = (eax >> 5) & 0x7; +- +- if ((level == 1 && type == data +- && folded_rel_name == M(_SC_LEVEL1_DCACHE_SIZE)) +- || (level == 1 && type == inst +- && folded_rel_name == M(_SC_LEVEL1_ICACHE_SIZE)) +- || (level == 2 && folded_rel_name == M(_SC_LEVEL2_CACHE_SIZE)) +- || (level == 3 && folded_rel_name == M(_SC_LEVEL3_CACHE_SIZE)) +- || (level == 4 && folded_rel_name == M(_SC_LEVEL4_CACHE_SIZE))) +- { +- unsigned int offset = M(name) - folded_rel_name; +- +- if (offset == 0) +- /* Cache size. */ +- return (((ebx >> 22) + 1) +- * (((ebx >> 12) & 0x3ff) + 1) +- * ((ebx & 0xfff) + 1) +- * (ecx + 1)); +- if (offset == 1) +- return (ebx >> 22) + 1; +- +- assert (offset == 2); +- return (ebx & 0xfff) + 1; +- } +- +- ++round; +- } +- /* There is no other cache information anywhere else. */ +- break; +- } +- else +- { +- if (byte == 0x49 && folded_rel_name == M(_SC_LEVEL3_CACHE_SIZE)) +- { +- /* Intel reused this value. For family 15, model 6 it +- specifies the 3rd level cache. Otherwise the 2nd +- level cache. */ +- unsigned int family = cpu_features->basic.family; +- unsigned int model = cpu_features->basic.model; +- +- if (family == 15 && model == 6) +- { +- /* The level 3 cache is encoded for this model like +- the level 2 cache is for other models. Pretend +- the caller asked for the level 2 cache. */ +- name = (_SC_LEVEL2_CACHE_SIZE +- + (name - _SC_LEVEL3_CACHE_SIZE)); +- folded_rel_name = M(_SC_LEVEL2_CACHE_SIZE); +- } +- } +- +- struct intel_02_cache_info *found; +- struct intel_02_cache_info search; +- +- search.idx = byte; +- found = bsearch (&search, intel_02_known, nintel_02_known, +- sizeof (intel_02_known[0]), intel_02_known_compare); +- if (found != NULL) +- { +- if (found->rel_name == folded_rel_name) +- { +- unsigned int offset = M(name) - folded_rel_name; +- +- if (offset == 0) +- /* Cache size. */ +- return found->size; +- if (offset == 1) +- return found->assoc; +- +- assert (offset == 2); +- return found->linesize; +- } +- +- if (found->rel_name == M(_SC_LEVEL2_CACHE_SIZE)) +- *has_level_2 = true; +- } +- } +- +- /* Next byte for the next round. */ +- value >>= 8; +- } +- +- /* Nothing found. */ +- return 0; +-} +- +- +-static long int __attribute__ ((noinline)) +-handle_intel (int name, const struct cpu_features *cpu_features) +-{ +- unsigned int maxidx = cpu_features->basic.max_cpuid; +- +- /* Return -1 for older CPUs. */ +- if (maxidx < 2) +- return -1; +- +- /* OK, we can use the CPUID instruction to get all info about the +- caches. */ +- unsigned int cnt = 0; +- unsigned int max = 1; +- long int result = 0; +- bool no_level_2_or_3 = false; +- bool has_level_2 = false; +- +- while (cnt++ < max) +- { +- unsigned int eax; +- unsigned int ebx; +- unsigned int ecx; +- unsigned int edx; +- __cpuid (2, eax, ebx, ecx, edx); +- +- /* The low byte of EAX in the first round contain the number of +- rounds we have to make. At least one, the one we are already +- doing. */ +- if (cnt == 1) +- { +- max = eax & 0xff; +- eax &= 0xffffff00; +- } +- +- /* Process the individual registers' value. */ +- result = intel_check_word (name, eax, &has_level_2, +- &no_level_2_or_3, cpu_features); +- if (result != 0) +- return result; +- +- result = intel_check_word (name, ebx, &has_level_2, +- &no_level_2_or_3, cpu_features); +- if (result != 0) +- return result; +- +- result = intel_check_word (name, ecx, &has_level_2, +- &no_level_2_or_3, cpu_features); +- if (result != 0) +- return result; +- +- result = intel_check_word (name, edx, &has_level_2, +- &no_level_2_or_3, cpu_features); +- if (result != 0) +- return result; +- } +- +- if (name >= _SC_LEVEL2_CACHE_SIZE && name <= _SC_LEVEL3_CACHE_LINESIZE +- && no_level_2_or_3) +- return -1; +- +- return 0; +-} +- +- +-static long int __attribute__ ((noinline)) +-handle_amd (int name) +-{ +- unsigned int eax; +- unsigned int ebx; +- unsigned int ecx; +- unsigned int edx; +- __cpuid (0x80000000, eax, ebx, ecx, edx); +- +- /* No level 4 cache (yet). */ +- if (name > _SC_LEVEL3_CACHE_LINESIZE) +- return 0; +- +- unsigned int fn = 0x80000005 + (name >= _SC_LEVEL2_CACHE_SIZE); +- if (eax < fn) +- return 0; +- +- __cpuid (fn, eax, ebx, ecx, edx); +- +- if (name < _SC_LEVEL1_DCACHE_SIZE) +- { +- name += _SC_LEVEL1_DCACHE_SIZE - _SC_LEVEL1_ICACHE_SIZE; +- ecx = edx; +- } +- +- switch (name) +- { +- case _SC_LEVEL1_DCACHE_SIZE: +- return (ecx >> 14) & 0x3fc00; +- +- case _SC_LEVEL1_DCACHE_ASSOC: +- ecx >>= 16; +- if ((ecx & 0xff) == 0xff) +- /* Fully associative. */ +- return (ecx << 2) & 0x3fc00; +- return ecx & 0xff; +- +- case _SC_LEVEL1_DCACHE_LINESIZE: +- return ecx & 0xff; +- +- case _SC_LEVEL2_CACHE_SIZE: +- return (ecx & 0xf000) == 0 ? 0 : (ecx >> 6) & 0x3fffc00; +- +- case _SC_LEVEL2_CACHE_ASSOC: +- switch ((ecx >> 12) & 0xf) +- { +- case 0: +- case 1: +- case 2: +- case 4: +- return (ecx >> 12) & 0xf; +- case 6: +- return 8; +- case 8: +- return 16; +- case 10: +- return 32; +- case 11: +- return 48; +- case 12: +- return 64; +- case 13: +- return 96; +- case 14: +- return 128; +- case 15: +- return ((ecx >> 6) & 0x3fffc00) / (ecx & 0xff); +- default: +- return 0; +- } +- /* NOTREACHED */ +- +- case _SC_LEVEL2_CACHE_LINESIZE: +- return (ecx & 0xf000) == 0 ? 0 : ecx & 0xff; +- +- case _SC_LEVEL3_CACHE_SIZE: +- return (edx & 0xf000) == 0 ? 0 : (edx & 0x3ffc0000) << 1; +- +- case _SC_LEVEL3_CACHE_ASSOC: +- switch ((edx >> 12) & 0xf) +- { +- case 0: +- case 1: +- case 2: +- case 4: +- return (edx >> 12) & 0xf; +- case 6: +- return 8; +- case 8: +- return 16; +- case 10: +- return 32; +- case 11: +- return 48; +- case 12: +- return 64; +- case 13: +- return 96; +- case 14: +- return 128; +- case 15: +- return ((edx & 0x3ffc0000) << 1) / (edx & 0xff); +- default: +- return 0; +- } +- /* NOTREACHED */ +- +- case _SC_LEVEL3_CACHE_LINESIZE: +- return (edx & 0xf000) == 0 ? 0 : edx & 0xff; +- +- default: +- assert (! "cannot happen"); +- } +- return -1; +-} +- +- +-static long int __attribute__ ((noinline)) +-handle_zhaoxin (int name) +-{ +- unsigned int eax; +- unsigned int ebx; +- unsigned int ecx; +- unsigned int edx; +- +- int folded_rel_name = (M(name) / 3) * 3; +- +- unsigned int round = 0; +- while (1) +- { +- __cpuid_count (4, round, eax, ebx, ecx, edx); +- +- enum { null = 0, data = 1, inst = 2, uni = 3 } type = eax & 0x1f; +- if (type == null) +- break; +- +- unsigned int level = (eax >> 5) & 0x7; +- +- if ((level == 1 && type == data +- && folded_rel_name == M(_SC_LEVEL1_DCACHE_SIZE)) +- || (level == 1 && type == inst +- && folded_rel_name == M(_SC_LEVEL1_ICACHE_SIZE)) +- || (level == 2 && folded_rel_name == M(_SC_LEVEL2_CACHE_SIZE)) +- || (level == 3 && folded_rel_name == M(_SC_LEVEL3_CACHE_SIZE))) +- { +- unsigned int offset = M(name) - folded_rel_name; +- +- if (offset == 0) +- /* Cache size. */ +- return (((ebx >> 22) + 1) +- * (((ebx >> 12) & 0x3ff) + 1) +- * ((ebx & 0xfff) + 1) +- * (ecx + 1)); +- if (offset == 1) +- return (ebx >> 22) + 1; +- +- assert (offset == 2); +- return (ebx & 0xfff) + 1; +- } +- +- ++round; +- } +- +- /* Nothing found. */ +- return 0; +-} +- ++#include ++#include + + /* Get the value of the system variable NAME. */ + long int +@@ -509,409 +46,18 @@ __cache_sysconf (int name) + return 0; + } + ++# ifdef SHARED ++/* NB: In libc.a, cacheinfo.h is included in libc-start.c. In libc.so, ++ cacheinfo.h is included here and call init_cacheinfo by initializing ++ a dummy function pointer via IFUNC relocation after CPU features in ++ ld.so have been initialized by DL_PLATFORM_INIT or IFUNC relocation. */ ++# include ++# include + +-/* Data cache size for use in memory and string routines, typically +- L1 size, rounded to multiple of 256 bytes. */ +-long int __x86_data_cache_size_half attribute_hidden = 32 * 1024 / 2; +-long int __x86_data_cache_size attribute_hidden = 32 * 1024; +-/* Similar to __x86_data_cache_size_half, but not rounded. */ +-long int __x86_raw_data_cache_size_half attribute_hidden = 32 * 1024 / 2; +-/* Similar to __x86_data_cache_size, but not rounded. */ +-long int __x86_raw_data_cache_size attribute_hidden = 32 * 1024; +-/* Shared cache size for use in memory and string routines, typically +- L2 or L3 size, rounded to multiple of 256 bytes. */ +-long int __x86_shared_cache_size_half attribute_hidden = 1024 * 1024 / 2; +-long int __x86_shared_cache_size attribute_hidden = 1024 * 1024; +-/* Similar to __x86_shared_cache_size_half, but not rounded. */ +-long int __x86_raw_shared_cache_size_half attribute_hidden = 1024 * 1024 / 2; +-/* Similar to __x86_shared_cache_size, but not rounded. */ +-long int __x86_raw_shared_cache_size attribute_hidden = 1024 * 1024; +- +-/* Threshold to use non temporal store. */ +-long int __x86_shared_non_temporal_threshold attribute_hidden; +- +-/* Threshold to use Enhanced REP MOVSB. */ +-long int __x86_rep_movsb_threshold attribute_hidden = 2048; +- +-/* Threshold to use Enhanced REP STOSB. */ +-long int __x86_rep_stosb_threshold attribute_hidden = 2048; +- +- +-static void +-get_common_cache_info (long int *shared_ptr, unsigned int *threads_ptr, +- long int core) +-{ +- unsigned int eax; +- unsigned int ebx; +- unsigned int ecx; +- unsigned int edx; +- +- /* Number of logical processors sharing L2 cache. */ +- int threads_l2; +- +- /* Number of logical processors sharing L3 cache. */ +- int threads_l3; +- +- const struct cpu_features *cpu_features = __get_cpu_features (); +- int max_cpuid = cpu_features->basic.max_cpuid; +- unsigned int family = cpu_features->basic.family; +- unsigned int model = cpu_features->basic.model; +- long int shared = *shared_ptr; +- unsigned int threads = *threads_ptr; +- bool inclusive_cache = true; +- bool support_count_mask = true; +- +- /* Try L3 first. */ +- unsigned int level = 3; +- +- if (cpu_features->basic.kind == arch_kind_zhaoxin && family == 6) +- support_count_mask = false; +- +- if (shared <= 0) +- { +- /* Try L2 otherwise. */ +- level = 2; +- shared = core; +- threads_l2 = 0; +- threads_l3 = -1; +- } +- else +- { +- threads_l2 = 0; +- threads_l3 = 0; +- } +- +- /* A value of 0 for the HTT bit indicates there is only a single +- logical processor. */ +- if (CPU_FEATURE_USABLE (HTT)) +- { +- /* Figure out the number of logical threads that share the +- highest cache level. */ +- if (max_cpuid >= 4) +- { +- int i = 0; +- +- /* Query until cache level 2 and 3 are enumerated. */ +- int check = 0x1 | (threads_l3 == 0) << 1; +- do +- { +- __cpuid_count (4, i++, eax, ebx, ecx, edx); +- +- /* There seems to be a bug in at least some Pentium Ds +- which sometimes fail to iterate all cache parameters. +- Do not loop indefinitely here, stop in this case and +- assume there is no such information. */ +- if (cpu_features->basic.kind == arch_kind_intel +- && (eax & 0x1f) == 0 ) +- goto intel_bug_no_cache_info; +- +- switch ((eax >> 5) & 0x7) +- { +- default: +- break; +- case 2: +- if ((check & 0x1)) +- { +- /* Get maximum number of logical processors +- sharing L2 cache. */ +- threads_l2 = (eax >> 14) & 0x3ff; +- check &= ~0x1; +- } +- break; +- case 3: +- if ((check & (0x1 << 1))) +- { +- /* Get maximum number of logical processors +- sharing L3 cache. */ +- threads_l3 = (eax >> 14) & 0x3ff; +- +- /* Check if L2 and L3 caches are inclusive. */ +- inclusive_cache = (edx & 0x2) != 0; +- check &= ~(0x1 << 1); +- } +- break; +- } +- } +- while (check); +- +- /* If max_cpuid >= 11, THREADS_L2/THREADS_L3 are the maximum +- numbers of addressable IDs for logical processors sharing +- the cache, instead of the maximum number of threads +- sharing the cache. */ +- if (max_cpuid >= 11 && support_count_mask) +- { +- /* Find the number of logical processors shipped in +- one core and apply count mask. */ +- i = 0; +- +- /* Count SMT only if there is L3 cache. Always count +- core if there is no L3 cache. */ +- int count = ((threads_l2 > 0 && level == 3) +- | ((threads_l3 > 0 +- || (threads_l2 > 0 && level == 2)) << 1)); +- +- while (count) +- { +- __cpuid_count (11, i++, eax, ebx, ecx, edx); +- +- int shipped = ebx & 0xff; +- int type = ecx & 0xff00; +- if (shipped == 0 || type == 0) +- break; +- else if (type == 0x100) +- { +- /* Count SMT. */ +- if ((count & 0x1)) +- { +- int count_mask; +- +- /* Compute count mask. */ +- asm ("bsr %1, %0" +- : "=r" (count_mask) : "g" (threads_l2)); +- count_mask = ~(-1 << (count_mask + 1)); +- threads_l2 = (shipped - 1) & count_mask; +- count &= ~0x1; +- } +- } +- else if (type == 0x200) +- { +- /* Count core. */ +- if ((count & (0x1 << 1))) +- { +- int count_mask; +- int threads_core +- = (level == 2 ? threads_l2 : threads_l3); +- +- /* Compute count mask. */ +- asm ("bsr %1, %0" +- : "=r" (count_mask) : "g" (threads_core)); +- count_mask = ~(-1 << (count_mask + 1)); +- threads_core = (shipped - 1) & count_mask; +- if (level == 2) +- threads_l2 = threads_core; +- else +- threads_l3 = threads_core; +- count &= ~(0x1 << 1); +- } +- } +- } +- } +- if (threads_l2 > 0) +- threads_l2 += 1; +- if (threads_l3 > 0) +- threads_l3 += 1; +- if (level == 2) +- { +- if (threads_l2) +- { +- threads = threads_l2; +- if (cpu_features->basic.kind == arch_kind_intel +- && threads > 2 +- && family == 6) +- switch (model) +- { +- case 0x37: +- case 0x4a: +- case 0x4d: +- case 0x5a: +- case 0x5d: +- /* Silvermont has L2 cache shared by 2 cores. */ +- threads = 2; +- break; +- default: +- break; +- } +- } +- } +- else if (threads_l3) +- threads = threads_l3; +- } +- else +- { +-intel_bug_no_cache_info: +- /* Assume that all logical threads share the highest cache +- level. */ +- threads +- = ((cpu_features->features[COMMON_CPUID_INDEX_1].cpuid.ebx +- >> 16) & 0xff); +- } +- +- /* Cap usage of highest cache level to the number of supported +- threads. */ +- if (shared > 0 && threads > 0) +- shared /= threads; +- } +- +- /* Account for non-inclusive L2 and L3 caches. */ +- if (!inclusive_cache) +- { +- if (threads_l2 > 0) +- core /= threads_l2; +- shared += core; +- } +- +- *shared_ptr = shared; +- *threads_ptr = threads; +-} +- +- +-static void +-__attribute__((constructor)) +-init_cacheinfo (void) +-{ +- /* Find out what brand of processor. */ +- unsigned int ebx; +- unsigned int ecx; +- unsigned int edx; +- int max_cpuid_ex; +- long int data = -1; +- long int shared = -1; +- long int core; +- unsigned int threads = 0; +- const struct cpu_features *cpu_features = __get_cpu_features (); +- +- if (cpu_features->basic.kind == arch_kind_intel) +- { +- data = handle_intel (_SC_LEVEL1_DCACHE_SIZE, cpu_features); +- core = handle_intel (_SC_LEVEL2_CACHE_SIZE, cpu_features); +- shared = handle_intel (_SC_LEVEL3_CACHE_SIZE, cpu_features); +- +- get_common_cache_info (&shared, &threads, core); +- } +- else if (cpu_features->basic.kind == arch_kind_zhaoxin) +- { +- data = handle_zhaoxin (_SC_LEVEL1_DCACHE_SIZE); +- core = handle_zhaoxin (_SC_LEVEL2_CACHE_SIZE); +- shared = handle_zhaoxin (_SC_LEVEL3_CACHE_SIZE); +- +- get_common_cache_info (&shared, &threads, core); +- } +- else if (cpu_features->basic.kind == arch_kind_amd) +- { +- data = handle_amd (_SC_LEVEL1_DCACHE_SIZE); +- long int core = handle_amd (_SC_LEVEL2_CACHE_SIZE); +- shared = handle_amd (_SC_LEVEL3_CACHE_SIZE); ++extern void __x86_cacheinfo (void) attribute_hidden; ++const void (*__x86_cacheinfo_p) (void) attribute_hidden ++ = __x86_cacheinfo; + +- /* Get maximum extended function. */ +- __cpuid (0x80000000, max_cpuid_ex, ebx, ecx, edx); +- +- if (shared <= 0) +- /* No shared L3 cache. All we have is the L2 cache. */ +- shared = core; +- else +- { +- /* Figure out the number of logical threads that share L3. */ +- if (max_cpuid_ex >= 0x80000008) +- { +- /* Get width of APIC ID. */ +- __cpuid (0x80000008, max_cpuid_ex, ebx, ecx, edx); +- threads = 1 << ((ecx >> 12) & 0x0f); +- } +- +- if (threads == 0 || cpu_features->basic.family >= 0x17) +- { +- /* If APIC ID width is not available, use logical +- processor count. */ +- __cpuid (0x00000001, max_cpuid_ex, ebx, ecx, edx); +- +- if ((edx & (1 << 28)) != 0) +- threads = (ebx >> 16) & 0xff; +- } +- +- /* Cap usage of highest cache level to the number of +- supported threads. */ +- if (threads > 0) +- shared /= threads; +- +- /* Get shared cache per ccx for Zen architectures. */ +- if (cpu_features->basic.family >= 0x17) +- { +- unsigned int eax; +- +- /* Get number of threads share the L3 cache in CCX. */ +- __cpuid_count (0x8000001D, 0x3, eax, ebx, ecx, edx); +- +- unsigned int threads_per_ccx = ((eax >> 14) & 0xfff) + 1; +- shared *= threads_per_ccx; +- } +- else +- { +- /* Account for exclusive L2 and L3 caches. */ +- shared += core; +- } +- } +- } +- +- if (cpu_features->data_cache_size != 0) +- data = cpu_features->data_cache_size; +- +- if (data > 0) +- { +- __x86_raw_data_cache_size_half = data / 2; +- __x86_raw_data_cache_size = data; +- /* Round data cache size to multiple of 256 bytes. */ +- data = data & ~255L; +- __x86_data_cache_size_half = data / 2; +- __x86_data_cache_size = data; +- } +- +- if (cpu_features->shared_cache_size != 0) +- shared = cpu_features->shared_cache_size; +- +- if (shared > 0) +- { +- __x86_raw_shared_cache_size_half = shared / 2; +- __x86_raw_shared_cache_size = shared; +- /* Round shared cache size to multiple of 256 bytes. */ +- shared = shared & ~255L; +- __x86_shared_cache_size_half = shared / 2; +- __x86_shared_cache_size = shared; +- } +- +- /* The default setting for the non_temporal threshold is 3/4 of one +- thread's share of the chip's cache. For most Intel and AMD processors +- with an initial release date between 2017 and 2020, a thread's typical +- share of the cache is from 500 KBytes to 2 MBytes. Using the 3/4 +- threshold leaves 125 KBytes to 500 KBytes of the thread's data +- in cache after a maximum temporal copy, which will maintain +- in cache a reasonable portion of the thread's stack and other +- active data. If the threshold is set higher than one thread's +- share of the cache, it has a substantial risk of negatively +- impacting the performance of other threads running on the chip. */ +- __x86_shared_non_temporal_threshold +- = (cpu_features->non_temporal_threshold != 0 +- ? cpu_features->non_temporal_threshold +- : __x86_shared_cache_size * 3 / 4); +- +- /* NB: The REP MOVSB threshold must be greater than VEC_SIZE * 8. */ +- unsigned int minimum_rep_movsb_threshold; +- /* NB: The default REP MOVSB threshold is 2048 * (VEC_SIZE / 16). */ +- unsigned int rep_movsb_threshold; +- if (CPU_FEATURE_USABLE_P (cpu_features, AVX512F) +- && !CPU_FEATURE_PREFERRED_P (cpu_features, Prefer_No_AVX512)) +- { +- rep_movsb_threshold = 2048 * (64 / 16); +- minimum_rep_movsb_threshold = 64 * 8; +- } +- else if (CPU_FEATURE_PREFERRED_P (cpu_features, +- AVX_Fast_Unaligned_Load)) +- { +- rep_movsb_threshold = 2048 * (32 / 16); +- minimum_rep_movsb_threshold = 32 * 8; +- } +- else +- { +- rep_movsb_threshold = 2048 * (16 / 16); +- minimum_rep_movsb_threshold = 16 * 8; +- } +- if (cpu_features->rep_movsb_threshold > minimum_rep_movsb_threshold) +- __x86_rep_movsb_threshold = cpu_features->rep_movsb_threshold; +- else +- __x86_rep_movsb_threshold = rep_movsb_threshold; +- +-# if HAVE_TUNABLES +- __x86_rep_stosb_threshold = cpu_features->rep_stosb_threshold; ++__ifunc (__x86_cacheinfo, __x86_cacheinfo, NULL, void, init_cacheinfo); + # endif +-} +- + #endif +diff --git a/sysdeps/x86/cacheinfo.h b/sysdeps/x86/cacheinfo.h +new file mode 100644 +index 0000000000000000..0255696163b7b8ff +--- /dev/null ++++ b/sysdeps/x86/cacheinfo.h +@@ -0,0 +1,427 @@ ++/* x86 cache info. ++ 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 ++ ++/* Data cache size for use in memory and string routines, typically ++ L1 size, rounded to multiple of 256 bytes. */ ++long int __x86_data_cache_size_half attribute_hidden = 32 * 1024 / 2; ++long int __x86_data_cache_size attribute_hidden = 32 * 1024; ++/* Similar to __x86_data_cache_size_half, but not rounded. */ ++long int __x86_raw_data_cache_size_half attribute_hidden = 32 * 1024 / 2; ++/* Similar to __x86_data_cache_size, but not rounded. */ ++long int __x86_raw_data_cache_size attribute_hidden = 32 * 1024; ++/* Shared cache size for use in memory and string routines, typically ++ L2 or L3 size, rounded to multiple of 256 bytes. */ ++long int __x86_shared_cache_size_half attribute_hidden = 1024 * 1024 / 2; ++long int __x86_shared_cache_size attribute_hidden = 1024 * 1024; ++/* Similar to __x86_shared_cache_size_half, but not rounded. */ ++long int __x86_raw_shared_cache_size_half attribute_hidden = 1024 * 1024 / 2; ++/* Similar to __x86_shared_cache_size, but not rounded. */ ++long int __x86_raw_shared_cache_size attribute_hidden = 1024 * 1024; ++ ++/* Threshold to use non temporal store. */ ++long int __x86_shared_non_temporal_threshold attribute_hidden; ++ ++/* Threshold to use Enhanced REP MOVSB. */ ++long int __x86_rep_movsb_threshold attribute_hidden = 2048; ++ ++/* Threshold to use Enhanced REP STOSB. */ ++long int __x86_rep_stosb_threshold attribute_hidden = 2048; ++ ++static void ++get_common_cache_info (long int *shared_ptr, unsigned int *threads_ptr, ++ long int core) ++{ ++ unsigned int eax; ++ unsigned int ebx; ++ unsigned int ecx; ++ unsigned int edx; ++ ++ /* Number of logical processors sharing L2 cache. */ ++ int threads_l2; ++ ++ /* Number of logical processors sharing L3 cache. */ ++ int threads_l3; ++ ++ const struct cpu_features *cpu_features = __get_cpu_features (); ++ int max_cpuid = cpu_features->basic.max_cpuid; ++ unsigned int family = cpu_features->basic.family; ++ unsigned int model = cpu_features->basic.model; ++ long int shared = *shared_ptr; ++ unsigned int threads = *threads_ptr; ++ bool inclusive_cache = true; ++ bool support_count_mask = true; ++ ++ /* Try L3 first. */ ++ unsigned int level = 3; ++ ++ if (cpu_features->basic.kind == arch_kind_zhaoxin && family == 6) ++ support_count_mask = false; ++ ++ if (shared <= 0) ++ { ++ /* Try L2 otherwise. */ ++ level = 2; ++ shared = core; ++ threads_l2 = 0; ++ threads_l3 = -1; ++ } ++ else ++ { ++ threads_l2 = 0; ++ threads_l3 = 0; ++ } ++ ++ /* A value of 0 for the HTT bit indicates there is only a single ++ logical processor. */ ++ if (HAS_CPU_FEATURE (HTT)) ++ { ++ /* Figure out the number of logical threads that share the ++ highest cache level. */ ++ if (max_cpuid >= 4) ++ { ++ int i = 0; ++ ++ /* Query until cache level 2 and 3 are enumerated. */ ++ int check = 0x1 | (threads_l3 == 0) << 1; ++ do ++ { ++ __cpuid_count (4, i++, eax, ebx, ecx, edx); ++ ++ /* There seems to be a bug in at least some Pentium Ds ++ which sometimes fail to iterate all cache parameters. ++ Do not loop indefinitely here, stop in this case and ++ assume there is no such information. */ ++ if (cpu_features->basic.kind == arch_kind_intel ++ && (eax & 0x1f) == 0 ) ++ goto intel_bug_no_cache_info; ++ ++ switch ((eax >> 5) & 0x7) ++ { ++ default: ++ break; ++ case 2: ++ if ((check & 0x1)) ++ { ++ /* Get maximum number of logical processors ++ sharing L2 cache. */ ++ threads_l2 = (eax >> 14) & 0x3ff; ++ check &= ~0x1; ++ } ++ break; ++ case 3: ++ if ((check & (0x1 << 1))) ++ { ++ /* Get maximum number of logical processors ++ sharing L3 cache. */ ++ threads_l3 = (eax >> 14) & 0x3ff; ++ ++ /* Check if L2 and L3 caches are inclusive. */ ++ inclusive_cache = (edx & 0x2) != 0; ++ check &= ~(0x1 << 1); ++ } ++ break; ++ } ++ } ++ while (check); ++ ++ /* If max_cpuid >= 11, THREADS_L2/THREADS_L3 are the maximum ++ numbers of addressable IDs for logical processors sharing ++ the cache, instead of the maximum number of threads ++ sharing the cache. */ ++ if (max_cpuid >= 11 && support_count_mask) ++ { ++ /* Find the number of logical processors shipped in ++ one core and apply count mask. */ ++ i = 0; ++ ++ /* Count SMT only if there is L3 cache. Always count ++ core if there is no L3 cache. */ ++ int count = ((threads_l2 > 0 && level == 3) ++ | ((threads_l3 > 0 ++ || (threads_l2 > 0 && level == 2)) << 1)); ++ ++ while (count) ++ { ++ __cpuid_count (11, i++, eax, ebx, ecx, edx); ++ ++ int shipped = ebx & 0xff; ++ int type = ecx & 0xff00; ++ if (shipped == 0 || type == 0) ++ break; ++ else if (type == 0x100) ++ { ++ /* Count SMT. */ ++ if ((count & 0x1)) ++ { ++ int count_mask; ++ ++ /* Compute count mask. */ ++ asm ("bsr %1, %0" ++ : "=r" (count_mask) : "g" (threads_l2)); ++ count_mask = ~(-1 << (count_mask + 1)); ++ threads_l2 = (shipped - 1) & count_mask; ++ count &= ~0x1; ++ } ++ } ++ else if (type == 0x200) ++ { ++ /* Count core. */ ++ if ((count & (0x1 << 1))) ++ { ++ int count_mask; ++ int threads_core ++ = (level == 2 ? threads_l2 : threads_l3); ++ ++ /* Compute count mask. */ ++ asm ("bsr %1, %0" ++ : "=r" (count_mask) : "g" (threads_core)); ++ count_mask = ~(-1 << (count_mask + 1)); ++ threads_core = (shipped - 1) & count_mask; ++ if (level == 2) ++ threads_l2 = threads_core; ++ else ++ threads_l3 = threads_core; ++ count &= ~(0x1 << 1); ++ } ++ } ++ } ++ } ++ if (threads_l2 > 0) ++ threads_l2 += 1; ++ if (threads_l3 > 0) ++ threads_l3 += 1; ++ if (level == 2) ++ { ++ if (threads_l2) ++ { ++ threads = threads_l2; ++ if (cpu_features->basic.kind == arch_kind_intel ++ && threads > 2 ++ && family == 6) ++ switch (model) ++ { ++ case 0x37: ++ case 0x4a: ++ case 0x4d: ++ case 0x5a: ++ case 0x5d: ++ /* Silvermont has L2 cache shared by 2 cores. */ ++ threads = 2; ++ break; ++ default: ++ break; ++ } ++ } ++ } ++ else if (threads_l3) ++ threads = threads_l3; ++ } ++ else ++ { ++intel_bug_no_cache_info: ++ /* Assume that all logical threads share the highest cache ++ level. */ ++ threads ++ = ((cpu_features->features[COMMON_CPUID_INDEX_1].cpuid.ebx ++ >> 16) & 0xff); ++ } ++ ++ /* Cap usage of highest cache level to the number of supported ++ threads. */ ++ if (shared > 0 && threads > 0) ++ shared /= threads; ++ } ++ ++ /* Account for non-inclusive L2 and L3 caches. */ ++ if (!inclusive_cache) ++ { ++ if (threads_l2 > 0) ++ core /= threads_l2; ++ shared += core; ++ } ++ ++ *shared_ptr = shared; ++ *threads_ptr = threads; ++} ++ ++static void ++init_cacheinfo (void) ++{ ++ /* Find out what brand of processor. */ ++ unsigned int ebx; ++ unsigned int ecx; ++ unsigned int edx; ++ int max_cpuid_ex; ++ long int data = -1; ++ long int shared = -1; ++ long int core; ++ unsigned int threads = 0; ++ const struct cpu_features *cpu_features = __get_cpu_features (); ++ ++ /* NB: In libc.so, cpu_features is defined in ld.so and is initialized ++ by DL_PLATFORM_INIT or IFUNC relocation before init_cacheinfo is ++ called by IFUNC relocation. In libc.a, init_cacheinfo is called ++ from init_cpu_features by ARCH_INIT_CPU_FEATURES. */ ++ assert (cpu_features->basic.kind != arch_kind_unknown); ++ ++ if (cpu_features->basic.kind == arch_kind_intel) ++ { ++ data = handle_intel (_SC_LEVEL1_DCACHE_SIZE, cpu_features); ++ core = handle_intel (_SC_LEVEL2_CACHE_SIZE, cpu_features); ++ shared = handle_intel (_SC_LEVEL3_CACHE_SIZE, cpu_features); ++ ++ get_common_cache_info (&shared, &threads, core); ++ } ++ else if (cpu_features->basic.kind == arch_kind_zhaoxin) ++ { ++ data = handle_zhaoxin (_SC_LEVEL1_DCACHE_SIZE); ++ core = handle_zhaoxin (_SC_LEVEL2_CACHE_SIZE); ++ shared = handle_zhaoxin (_SC_LEVEL3_CACHE_SIZE); ++ ++ get_common_cache_info (&shared, &threads, core); ++ } ++ else if (cpu_features->basic.kind == arch_kind_amd) ++ { ++ data = handle_amd (_SC_LEVEL1_DCACHE_SIZE); ++ long int core = handle_amd (_SC_LEVEL2_CACHE_SIZE); ++ shared = handle_amd (_SC_LEVEL3_CACHE_SIZE); ++ ++ /* Get maximum extended function. */ ++ __cpuid (0x80000000, max_cpuid_ex, ebx, ecx, edx); ++ ++ if (shared <= 0) ++ /* No shared L3 cache. All we have is the L2 cache. */ ++ shared = core; ++ else ++ { ++ /* Figure out the number of logical threads that share L3. */ ++ if (max_cpuid_ex >= 0x80000008) ++ { ++ /* Get width of APIC ID. */ ++ __cpuid (0x80000008, max_cpuid_ex, ebx, ecx, edx); ++ threads = 1 << ((ecx >> 12) & 0x0f); ++ } ++ ++ if (threads == 0 || cpu_features->basic.family >= 0x17) ++ { ++ /* If APIC ID width is not available, use logical ++ processor count. */ ++ __cpuid (0x00000001, max_cpuid_ex, ebx, ecx, edx); ++ ++ if ((edx & (1 << 28)) != 0) ++ threads = (ebx >> 16) & 0xff; ++ } ++ ++ /* Cap usage of highest cache level to the number of ++ supported threads. */ ++ if (threads > 0) ++ shared /= threads; ++ ++ /* Get shared cache per ccx for Zen architectures. */ ++ if (cpu_features->basic.family >= 0x17) ++ { ++ unsigned int eax; ++ ++ /* Get number of threads share the L3 cache in CCX. */ ++ __cpuid_count (0x8000001D, 0x3, eax, ebx, ecx, edx); ++ ++ unsigned int threads_per_ccx = ((eax >> 14) & 0xfff) + 1; ++ shared *= threads_per_ccx; ++ } ++ else ++ { ++ /* Account for exclusive L2 and L3 caches. */ ++ shared += core; ++ } ++ } ++ } ++ ++ if (cpu_features->data_cache_size != 0) ++ data = cpu_features->data_cache_size; ++ ++ if (data > 0) ++ { ++ __x86_raw_data_cache_size_half = data / 2; ++ __x86_raw_data_cache_size = data; ++ /* Round data cache size to multiple of 256 bytes. */ ++ data = data & ~255L; ++ __x86_data_cache_size_half = data / 2; ++ __x86_data_cache_size = data; ++ } ++ ++ if (cpu_features->shared_cache_size != 0) ++ shared = cpu_features->shared_cache_size; ++ ++ if (shared > 0) ++ { ++ __x86_raw_shared_cache_size_half = shared / 2; ++ __x86_raw_shared_cache_size = shared; ++ /* Round shared cache size to multiple of 256 bytes. */ ++ shared = shared & ~255L; ++ __x86_shared_cache_size_half = shared / 2; ++ __x86_shared_cache_size = shared; ++ } ++ ++ /* The default setting for the non_temporal threshold is 3/4 of one ++ thread's share of the chip's cache. For most Intel and AMD processors ++ with an initial release date between 2017 and 2020, a thread's typical ++ share of the cache is from 500 KBytes to 2 MBytes. Using the 3/4 ++ threshold leaves 125 KBytes to 500 KBytes of the thread's data ++ in cache after a maximum temporal copy, which will maintain ++ in cache a reasonable portion of the thread's stack and other ++ active data. If the threshold is set higher than one thread's ++ share of the cache, it has a substantial risk of negatively ++ impacting the performance of other threads running on the chip. */ ++ __x86_shared_non_temporal_threshold ++ = (cpu_features->non_temporal_threshold != 0 ++ ? cpu_features->non_temporal_threshold ++ : __x86_shared_cache_size * 3 / 4); ++ ++ /* NB: The REP MOVSB threshold must be greater than VEC_SIZE * 8. */ ++ unsigned int minimum_rep_movsb_threshold; ++ /* NB: The default REP MOVSB threshold is 2048 * (VEC_SIZE / 16). */ ++ unsigned int rep_movsb_threshold; ++ if (CPU_FEATURE_USABLE_P (cpu_features, AVX512F) ++ && !CPU_FEATURE_PREFERRED_P (cpu_features, Prefer_No_AVX512)) ++ { ++ rep_movsb_threshold = 2048 * (64 / 16); ++ minimum_rep_movsb_threshold = 64 * 8; ++ } ++ else if (CPU_FEATURE_PREFERRED_P (cpu_features, ++ AVX_Fast_Unaligned_Load)) ++ { ++ rep_movsb_threshold = 2048 * (32 / 16); ++ minimum_rep_movsb_threshold = 32 * 8; ++ } ++ else ++ { ++ rep_movsb_threshold = 2048 * (16 / 16); ++ minimum_rep_movsb_threshold = 16 * 8; ++ } ++ if (cpu_features->rep_movsb_threshold > minimum_rep_movsb_threshold) ++ __x86_rep_movsb_threshold = cpu_features->rep_movsb_threshold; ++ else ++ __x86_rep_movsb_threshold = rep_movsb_threshold; ++ ++# if HAVE_TUNABLES ++ __x86_rep_stosb_threshold = cpu_features->rep_stosb_threshold; ++# endif ++} +diff --git a/sysdeps/x86/cpu-features.c b/sysdeps/x86/cpu-features.c +index 5f0548fe08134236..4c9c15a44b618fed 100644 +--- a/sysdeps/x86/cpu-features.c ++++ b/sysdeps/x86/cpu-features.c +@@ -17,9 +17,14 @@ + . */ + + #include +-#include + #include + #include ++#if IS_IN (libc) && !defined SHARED ++# include ++# include ++# include ++# include ++#endif + + #if HAVE_TUNABLES + # define TUNABLE_NAMESPACE cpu +@@ -752,4 +757,9 @@ no_cpuid: + # endif + } + #endif ++ ++#ifndef SHARED ++ /* NB: In libc.a, call init_cacheinfo. */ ++ init_cacheinfo (); ++#endif + } +diff --git a/sysdeps/x86/dl-cacheinfo.h b/sysdeps/x86/dl-cacheinfo.h +new file mode 100644 +index 0000000000000000..b2b90074b0e98a60 +--- /dev/null ++++ b/sysdeps/x86/dl-cacheinfo.h +@@ -0,0 +1,478 @@ ++/* Initialize x86 cache info. ++ 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 ++ . */ ++ ++static const struct intel_02_cache_info ++{ ++ unsigned char idx; ++ unsigned char assoc; ++ unsigned char linesize; ++ unsigned char rel_name; ++ unsigned int size; ++} intel_02_known [] = ++ { ++#define M(sc) ((sc) - _SC_LEVEL1_ICACHE_SIZE) ++ { 0x06, 4, 32, M(_SC_LEVEL1_ICACHE_SIZE), 8192 }, ++ { 0x08, 4, 32, M(_SC_LEVEL1_ICACHE_SIZE), 16384 }, ++ { 0x09, 4, 32, M(_SC_LEVEL1_ICACHE_SIZE), 32768 }, ++ { 0x0a, 2, 32, M(_SC_LEVEL1_DCACHE_SIZE), 8192 }, ++ { 0x0c, 4, 32, M(_SC_LEVEL1_DCACHE_SIZE), 16384 }, ++ { 0x0d, 4, 64, M(_SC_LEVEL1_DCACHE_SIZE), 16384 }, ++ { 0x0e, 6, 64, M(_SC_LEVEL1_DCACHE_SIZE), 24576 }, ++ { 0x21, 8, 64, M(_SC_LEVEL2_CACHE_SIZE), 262144 }, ++ { 0x22, 4, 64, M(_SC_LEVEL3_CACHE_SIZE), 524288 }, ++ { 0x23, 8, 64, M(_SC_LEVEL3_CACHE_SIZE), 1048576 }, ++ { 0x25, 8, 64, M(_SC_LEVEL3_CACHE_SIZE), 2097152 }, ++ { 0x29, 8, 64, M(_SC_LEVEL3_CACHE_SIZE), 4194304 }, ++ { 0x2c, 8, 64, M(_SC_LEVEL1_DCACHE_SIZE), 32768 }, ++ { 0x30, 8, 64, M(_SC_LEVEL1_ICACHE_SIZE), 32768 }, ++ { 0x39, 4, 64, M(_SC_LEVEL2_CACHE_SIZE), 131072 }, ++ { 0x3a, 6, 64, M(_SC_LEVEL2_CACHE_SIZE), 196608 }, ++ { 0x3b, 2, 64, M(_SC_LEVEL2_CACHE_SIZE), 131072 }, ++ { 0x3c, 4, 64, M(_SC_LEVEL2_CACHE_SIZE), 262144 }, ++ { 0x3d, 6, 64, M(_SC_LEVEL2_CACHE_SIZE), 393216 }, ++ { 0x3e, 4, 64, M(_SC_LEVEL2_CACHE_SIZE), 524288 }, ++ { 0x3f, 2, 64, M(_SC_LEVEL2_CACHE_SIZE), 262144 }, ++ { 0x41, 4, 32, M(_SC_LEVEL2_CACHE_SIZE), 131072 }, ++ { 0x42, 4, 32, M(_SC_LEVEL2_CACHE_SIZE), 262144 }, ++ { 0x43, 4, 32, M(_SC_LEVEL2_CACHE_SIZE), 524288 }, ++ { 0x44, 4, 32, M(_SC_LEVEL2_CACHE_SIZE), 1048576 }, ++ { 0x45, 4, 32, M(_SC_LEVEL2_CACHE_SIZE), 2097152 }, ++ { 0x46, 4, 64, M(_SC_LEVEL3_CACHE_SIZE), 4194304 }, ++ { 0x47, 8, 64, M(_SC_LEVEL3_CACHE_SIZE), 8388608 }, ++ { 0x48, 12, 64, M(_SC_LEVEL2_CACHE_SIZE), 3145728 }, ++ { 0x49, 16, 64, M(_SC_LEVEL2_CACHE_SIZE), 4194304 }, ++ { 0x4a, 12, 64, M(_SC_LEVEL3_CACHE_SIZE), 6291456 }, ++ { 0x4b, 16, 64, M(_SC_LEVEL3_CACHE_SIZE), 8388608 }, ++ { 0x4c, 12, 64, M(_SC_LEVEL3_CACHE_SIZE), 12582912 }, ++ { 0x4d, 16, 64, M(_SC_LEVEL3_CACHE_SIZE), 16777216 }, ++ { 0x4e, 24, 64, M(_SC_LEVEL2_CACHE_SIZE), 6291456 }, ++ { 0x60, 8, 64, M(_SC_LEVEL1_DCACHE_SIZE), 16384 }, ++ { 0x66, 4, 64, M(_SC_LEVEL1_DCACHE_SIZE), 8192 }, ++ { 0x67, 4, 64, M(_SC_LEVEL1_DCACHE_SIZE), 16384 }, ++ { 0x68, 4, 64, M(_SC_LEVEL1_DCACHE_SIZE), 32768 }, ++ { 0x78, 8, 64, M(_SC_LEVEL2_CACHE_SIZE), 1048576 }, ++ { 0x79, 8, 64, M(_SC_LEVEL2_CACHE_SIZE), 131072 }, ++ { 0x7a, 8, 64, M(_SC_LEVEL2_CACHE_SIZE), 262144 }, ++ { 0x7b, 8, 64, M(_SC_LEVEL2_CACHE_SIZE), 524288 }, ++ { 0x7c, 8, 64, M(_SC_LEVEL2_CACHE_SIZE), 1048576 }, ++ { 0x7d, 8, 64, M(_SC_LEVEL2_CACHE_SIZE), 2097152 }, ++ { 0x7f, 2, 64, M(_SC_LEVEL2_CACHE_SIZE), 524288 }, ++ { 0x80, 8, 64, M(_SC_LEVEL2_CACHE_SIZE), 524288 }, ++ { 0x82, 8, 32, M(_SC_LEVEL2_CACHE_SIZE), 262144 }, ++ { 0x83, 8, 32, M(_SC_LEVEL2_CACHE_SIZE), 524288 }, ++ { 0x84, 8, 32, M(_SC_LEVEL2_CACHE_SIZE), 1048576 }, ++ { 0x85, 8, 32, M(_SC_LEVEL2_CACHE_SIZE), 2097152 }, ++ { 0x86, 4, 64, M(_SC_LEVEL2_CACHE_SIZE), 524288 }, ++ { 0x87, 8, 64, M(_SC_LEVEL2_CACHE_SIZE), 1048576 }, ++ { 0xd0, 4, 64, M(_SC_LEVEL3_CACHE_SIZE), 524288 }, ++ { 0xd1, 4, 64, M(_SC_LEVEL3_CACHE_SIZE), 1048576 }, ++ { 0xd2, 4, 64, M(_SC_LEVEL3_CACHE_SIZE), 2097152 }, ++ { 0xd6, 8, 64, M(_SC_LEVEL3_CACHE_SIZE), 1048576 }, ++ { 0xd7, 8, 64, M(_SC_LEVEL3_CACHE_SIZE), 2097152 }, ++ { 0xd8, 8, 64, M(_SC_LEVEL3_CACHE_SIZE), 4194304 }, ++ { 0xdc, 12, 64, M(_SC_LEVEL3_CACHE_SIZE), 2097152 }, ++ { 0xdd, 12, 64, M(_SC_LEVEL3_CACHE_SIZE), 4194304 }, ++ { 0xde, 12, 64, M(_SC_LEVEL3_CACHE_SIZE), 8388608 }, ++ { 0xe2, 16, 64, M(_SC_LEVEL3_CACHE_SIZE), 2097152 }, ++ { 0xe3, 16, 64, M(_SC_LEVEL3_CACHE_SIZE), 4194304 }, ++ { 0xe4, 16, 64, M(_SC_LEVEL3_CACHE_SIZE), 8388608 }, ++ { 0xea, 24, 64, M(_SC_LEVEL3_CACHE_SIZE), 12582912 }, ++ { 0xeb, 24, 64, M(_SC_LEVEL3_CACHE_SIZE), 18874368 }, ++ { 0xec, 24, 64, M(_SC_LEVEL3_CACHE_SIZE), 25165824 }, ++ }; ++ ++#define nintel_02_known (sizeof (intel_02_known) / sizeof (intel_02_known [0])) ++ ++static int ++intel_02_known_compare (const void *p1, const void *p2) ++{ ++ const struct intel_02_cache_info *i1; ++ const struct intel_02_cache_info *i2; ++ ++ i1 = (const struct intel_02_cache_info *) p1; ++ i2 = (const struct intel_02_cache_info *) p2; ++ ++ if (i1->idx == i2->idx) ++ return 0; ++ ++ return i1->idx < i2->idx ? -1 : 1; ++} ++ ++ ++static long int ++__attribute__ ((noinline)) ++intel_check_word (int name, unsigned int value, bool *has_level_2, ++ bool *no_level_2_or_3, ++ const struct cpu_features *cpu_features) ++{ ++ if ((value & 0x80000000) != 0) ++ /* The register value is reserved. */ ++ return 0; ++ ++ /* Fold the name. The _SC_ constants are always in the order SIZE, ++ ASSOC, LINESIZE. */ ++ int folded_rel_name = (M(name) / 3) * 3; ++ ++ while (value != 0) ++ { ++ unsigned int byte = value & 0xff; ++ ++ if (byte == 0x40) ++ { ++ *no_level_2_or_3 = true; ++ ++ if (folded_rel_name == M(_SC_LEVEL3_CACHE_SIZE)) ++ /* No need to look further. */ ++ break; ++ } ++ else if (byte == 0xff) ++ { ++ /* CPUID leaf 0x4 contains all the information. We need to ++ iterate over it. */ ++ unsigned int eax; ++ unsigned int ebx; ++ unsigned int ecx; ++ unsigned int edx; ++ ++ unsigned int round = 0; ++ while (1) ++ { ++ __cpuid_count (4, round, eax, ebx, ecx, edx); ++ ++ enum { null = 0, data = 1, inst = 2, uni = 3 } type = eax & 0x1f; ++ if (type == null) ++ /* That was the end. */ ++ break; ++ ++ unsigned int level = (eax >> 5) & 0x7; ++ ++ if ((level == 1 && type == data ++ && folded_rel_name == M(_SC_LEVEL1_DCACHE_SIZE)) ++ || (level == 1 && type == inst ++ && folded_rel_name == M(_SC_LEVEL1_ICACHE_SIZE)) ++ || (level == 2 && folded_rel_name == M(_SC_LEVEL2_CACHE_SIZE)) ++ || (level == 3 && folded_rel_name == M(_SC_LEVEL3_CACHE_SIZE)) ++ || (level == 4 && folded_rel_name == M(_SC_LEVEL4_CACHE_SIZE))) ++ { ++ unsigned int offset = M(name) - folded_rel_name; ++ ++ if (offset == 0) ++ /* Cache size. */ ++ return (((ebx >> 22) + 1) ++ * (((ebx >> 12) & 0x3ff) + 1) ++ * ((ebx & 0xfff) + 1) ++ * (ecx + 1)); ++ if (offset == 1) ++ return (ebx >> 22) + 1; ++ ++ assert (offset == 2); ++ return (ebx & 0xfff) + 1; ++ } ++ ++ ++round; ++ } ++ /* There is no other cache information anywhere else. */ ++ break; ++ } ++ else ++ { ++ if (byte == 0x49 && folded_rel_name == M(_SC_LEVEL3_CACHE_SIZE)) ++ { ++ /* Intel reused this value. For family 15, model 6 it ++ specifies the 3rd level cache. Otherwise the 2nd ++ level cache. */ ++ unsigned int family = cpu_features->basic.family; ++ unsigned int model = cpu_features->basic.model; ++ ++ if (family == 15 && model == 6) ++ { ++ /* The level 3 cache is encoded for this model like ++ the level 2 cache is for other models. Pretend ++ the caller asked for the level 2 cache. */ ++ name = (_SC_LEVEL2_CACHE_SIZE ++ + (name - _SC_LEVEL3_CACHE_SIZE)); ++ folded_rel_name = M(_SC_LEVEL2_CACHE_SIZE); ++ } ++ } ++ ++ struct intel_02_cache_info *found; ++ struct intel_02_cache_info search; ++ ++ search.idx = byte; ++ found = bsearch (&search, intel_02_known, nintel_02_known, ++ sizeof (intel_02_known[0]), intel_02_known_compare); ++ if (found != NULL) ++ { ++ if (found->rel_name == folded_rel_name) ++ { ++ unsigned int offset = M(name) - folded_rel_name; ++ ++ if (offset == 0) ++ /* Cache size. */ ++ return found->size; ++ if (offset == 1) ++ return found->assoc; ++ ++ assert (offset == 2); ++ return found->linesize; ++ } ++ ++ if (found->rel_name == M(_SC_LEVEL2_CACHE_SIZE)) ++ *has_level_2 = true; ++ } ++ } ++ ++ /* Next byte for the next round. */ ++ value >>= 8; ++ } ++ ++ /* Nothing found. */ ++ return 0; ++} ++ ++ ++static long int __attribute__ ((noinline)) ++handle_intel (int name, const struct cpu_features *cpu_features) ++{ ++ unsigned int maxidx = cpu_features->basic.max_cpuid; ++ ++ /* Return -1 for older CPUs. */ ++ if (maxidx < 2) ++ return -1; ++ ++ /* OK, we can use the CPUID instruction to get all info about the ++ caches. */ ++ unsigned int cnt = 0; ++ unsigned int max = 1; ++ long int result = 0; ++ bool no_level_2_or_3 = false; ++ bool has_level_2 = false; ++ ++ while (cnt++ < max) ++ { ++ unsigned int eax; ++ unsigned int ebx; ++ unsigned int ecx; ++ unsigned int edx; ++ __cpuid (2, eax, ebx, ecx, edx); ++ ++ /* The low byte of EAX in the first round contain the number of ++ rounds we have to make. At least one, the one we are already ++ doing. */ ++ if (cnt == 1) ++ { ++ max = eax & 0xff; ++ eax &= 0xffffff00; ++ } ++ ++ /* Process the individual registers' value. */ ++ result = intel_check_word (name, eax, &has_level_2, ++ &no_level_2_or_3, cpu_features); ++ if (result != 0) ++ return result; ++ ++ result = intel_check_word (name, ebx, &has_level_2, ++ &no_level_2_or_3, cpu_features); ++ if (result != 0) ++ return result; ++ ++ result = intel_check_word (name, ecx, &has_level_2, ++ &no_level_2_or_3, cpu_features); ++ if (result != 0) ++ return result; ++ ++ result = intel_check_word (name, edx, &has_level_2, ++ &no_level_2_or_3, cpu_features); ++ if (result != 0) ++ return result; ++ } ++ ++ if (name >= _SC_LEVEL2_CACHE_SIZE && name <= _SC_LEVEL3_CACHE_LINESIZE ++ && no_level_2_or_3) ++ return -1; ++ ++ return 0; ++} ++ ++ ++static long int __attribute__ ((noinline)) ++handle_amd (int name) ++{ ++ unsigned int eax; ++ unsigned int ebx; ++ unsigned int ecx; ++ unsigned int edx; ++ __cpuid (0x80000000, eax, ebx, ecx, edx); ++ ++ /* No level 4 cache (yet). */ ++ if (name > _SC_LEVEL3_CACHE_LINESIZE) ++ return 0; ++ ++ unsigned int fn = 0x80000005 + (name >= _SC_LEVEL2_CACHE_SIZE); ++ if (eax < fn) ++ return 0; ++ ++ __cpuid (fn, eax, ebx, ecx, edx); ++ ++ if (name < _SC_LEVEL1_DCACHE_SIZE) ++ { ++ name += _SC_LEVEL1_DCACHE_SIZE - _SC_LEVEL1_ICACHE_SIZE; ++ ecx = edx; ++ } ++ ++ switch (name) ++ { ++ case _SC_LEVEL1_DCACHE_SIZE: ++ return (ecx >> 14) & 0x3fc00; ++ ++ case _SC_LEVEL1_DCACHE_ASSOC: ++ ecx >>= 16; ++ if ((ecx & 0xff) == 0xff) ++ /* Fully associative. */ ++ return (ecx << 2) & 0x3fc00; ++ return ecx & 0xff; ++ ++ case _SC_LEVEL1_DCACHE_LINESIZE: ++ return ecx & 0xff; ++ ++ case _SC_LEVEL2_CACHE_SIZE: ++ return (ecx & 0xf000) == 0 ? 0 : (ecx >> 6) & 0x3fffc00; ++ ++ case _SC_LEVEL2_CACHE_ASSOC: ++ switch ((ecx >> 12) & 0xf) ++ { ++ case 0: ++ case 1: ++ case 2: ++ case 4: ++ return (ecx >> 12) & 0xf; ++ case 6: ++ return 8; ++ case 8: ++ return 16; ++ case 10: ++ return 32; ++ case 11: ++ return 48; ++ case 12: ++ return 64; ++ case 13: ++ return 96; ++ case 14: ++ return 128; ++ case 15: ++ return ((ecx >> 6) & 0x3fffc00) / (ecx & 0xff); ++ default: ++ return 0; ++ } ++ /* NOTREACHED */ ++ ++ case _SC_LEVEL2_CACHE_LINESIZE: ++ return (ecx & 0xf000) == 0 ? 0 : ecx & 0xff; ++ ++ case _SC_LEVEL3_CACHE_SIZE: ++ return (edx & 0xf000) == 0 ? 0 : (edx & 0x3ffc0000) << 1; ++ ++ case _SC_LEVEL3_CACHE_ASSOC: ++ switch ((edx >> 12) & 0xf) ++ { ++ case 0: ++ case 1: ++ case 2: ++ case 4: ++ return (edx >> 12) & 0xf; ++ case 6: ++ return 8; ++ case 8: ++ return 16; ++ case 10: ++ return 32; ++ case 11: ++ return 48; ++ case 12: ++ return 64; ++ case 13: ++ return 96; ++ case 14: ++ return 128; ++ case 15: ++ return ((edx & 0x3ffc0000) << 1) / (edx & 0xff); ++ default: ++ return 0; ++ } ++ /* NOTREACHED */ ++ ++ case _SC_LEVEL3_CACHE_LINESIZE: ++ return (edx & 0xf000) == 0 ? 0 : edx & 0xff; ++ ++ default: ++ assert (! "cannot happen"); ++ } ++ return -1; ++} ++ ++ ++static long int __attribute__ ((noinline)) ++handle_zhaoxin (int name) ++{ ++ unsigned int eax; ++ unsigned int ebx; ++ unsigned int ecx; ++ unsigned int edx; ++ ++ int folded_rel_name = (M(name) / 3) * 3; ++ ++ unsigned int round = 0; ++ while (1) ++ { ++ __cpuid_count (4, round, eax, ebx, ecx, edx); ++ ++ enum { null = 0, data = 1, inst = 2, uni = 3 } type = eax & 0x1f; ++ if (type == null) ++ break; ++ ++ unsigned int level = (eax >> 5) & 0x7; ++ ++ if ((level == 1 && type == data ++ && folded_rel_name == M(_SC_LEVEL1_DCACHE_SIZE)) ++ || (level == 1 && type == inst ++ && folded_rel_name == M(_SC_LEVEL1_ICACHE_SIZE)) ++ || (level == 2 && folded_rel_name == M(_SC_LEVEL2_CACHE_SIZE)) ++ || (level == 3 && folded_rel_name == M(_SC_LEVEL3_CACHE_SIZE))) ++ { ++ unsigned int offset = M(name) - folded_rel_name; ++ ++ if (offset == 0) ++ /* Cache size. */ ++ return (((ebx >> 22) + 1) ++ * (((ebx >> 12) & 0x3ff) + 1) ++ * ((ebx & 0xfff) + 1) ++ * (ecx + 1)); ++ if (offset == 1) ++ return (ebx >> 22) + 1; ++ ++ assert (offset == 2); ++ return (ebx & 0xfff) + 1; ++ } ++ ++ ++round; ++ } ++ ++ /* Nothing found. */ ++ return 0; ++} +diff --git a/sysdeps/x86/dl-get-cpu-features.c b/sysdeps/x86/dl-get-cpu-features.c +index 2aba0d167129b336..82772cc12f0c7e54 100644 +--- a/sysdeps/x86/dl-get-cpu-features.c ++++ b/sysdeps/x86/dl-get-cpu-features.c +@@ -1,5 +1,5 @@ +-/* This file is part of the GNU C Library. +- Copyright (C) 2015-2018 Free Software Foundation, Inc. ++/* Initialize CPU feature data via IFUNC relocation. ++ Copyright (C) 2015-2020 Free Software Foundation, Inc. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public +@@ -18,6 +18,31 @@ + + #include + ++#ifdef SHARED ++# include ++ ++/* NB: Normally, DL_PLATFORM_INIT calls init_cpu_features to initialize ++ CPU features in dynamic executable. But when loading ld.so inside of ++ static executable, DL_PLATFORM_INIT isn't called and IFUNC relocation ++ is used to call init_cpu_features. In static executable, it is called ++ once by IFUNC relocation. In dynamic executable, it is called twice ++ by DL_PLATFORM_INIT and by IFUNC relocation. */ ++extern void __x86_cpu_features (void) attribute_hidden; ++const void (*__x86_cpu_features_p) (void) attribute_hidden ++ = __x86_cpu_features; ++ ++void ++_dl_x86_init_cpu_features (void) ++{ ++ struct cpu_features *cpu_features = __get_cpu_features (); ++ if (cpu_features->basic.kind == arch_kind_unknown) ++ init_cpu_features (cpu_features); ++} ++ ++__ifunc (__x86_cpu_features, __x86_cpu_features, NULL, void, ++ _dl_x86_init_cpu_features); ++#endif ++ + #undef __x86_get_cpu_features + + const struct cpu_features * +diff --git a/sysdeps/x86/include/cpu-features.h b/sysdeps/x86/include/cpu-features.h +index dcf29b6fe8578078..f62be0b9b3746675 100644 +--- a/sysdeps/x86/include/cpu-features.h ++++ b/sysdeps/x86/include/cpu-features.h +@@ -159,6 +159,7 @@ struct cpu_features + /* Unused for x86. */ + # define INIT_ARCH() + # define __x86_get_cpu_features(max) (&GLRO(dl_x86_cpu_features)) ++extern void _dl_x86_init_cpu_features (void) attribute_hidden; + # endif + + # ifdef __x86_64__ +diff --git a/sysdeps/x86/libc-start.c b/sysdeps/x86/libc-start.c +index eb5335c154096384..60f2c34ab5511350 100644 +--- a/sysdeps/x86/libc-start.c ++++ b/sysdeps/x86/libc-start.c +@@ -20,7 +20,6 @@ + PIE. */ + # include + # include +-# include + # include + + extern struct cpu_features _dl_x86_cpu_features; +diff --git a/sysdeps/x86_64/dl-machine.h b/sysdeps/x86_64/dl-machine.h +index d58298d787ef352c..e308b662d245cc63 100644 +--- a/sysdeps/x86_64/dl-machine.h ++++ b/sysdeps/x86_64/dl-machine.h +@@ -26,7 +26,6 @@ + #include + #include + #include +-#include + + /* Return nonzero iff ELF header is compatible with the running host. */ + static inline int __attribute__ ((unused)) +@@ -223,9 +222,9 @@ static inline void __attribute__ ((unused)) + dl_platform_init (void) + { + #if IS_IN (rtld) +- /* init_cpu_features has been called early from __libc_start_main in +- static executable. */ +- init_cpu_features (&GLRO(dl_x86_cpu_features)); ++ /* _dl_x86_init_cpu_features is a wrapper for init_cpu_features which ++ has been called early from __libc_start_main in static executable. */ ++ _dl_x86_init_cpu_features (); + #else + if (GLRO(dl_platform) != NULL && *GLRO(dl_platform) == '\0') + /* Avoid an empty string which would disturb us. */ diff --git a/SOURCES/glibc-rh1817513-108.patch b/SOURCES/glibc-rh1817513-108.patch new file mode 100644 index 0000000..b6dabc9 --- /dev/null +++ b/SOURCES/glibc-rh1817513-108.patch @@ -0,0 +1,364 @@ +commit de1a9197af7f67a89f929dcadb8ceca8c3846b1c +Author: Florian Weimer +Date: Fri Oct 30 11:57:59 2020 +0100 + + elf: Unify old and new format cache handling code in ld.so + + struct file_entry_new starts with the fields of struct file_entry, + so the code can be shared if the size computation is made dynamic. + + Reviewed-by: Adhemerval Zanella + +diff --git a/elf/dl-cache.c b/elf/dl-cache.c +index ef37ca18fa9fb6e0..366a051dfcd26132 100644 +--- a/elf/dl-cache.c ++++ b/elf/dl-cache.c +@@ -35,103 +35,141 @@ static struct cache_file *cache; + static struct cache_file_new *cache_new; + static size_t cachesize; + +-/* 1 if cache_data + PTR points into the cache. */ +-#define _dl_cache_verify_ptr(ptr) (ptr < cache_data_size) +- +-#define SEARCH_CACHE(cache) \ +-/* We use binary search since the table is sorted in the cache file. \ +- The first matching entry in the table is returned. \ +- It is important to use the same algorithm as used while generating \ +- the cache file. */ \ +-do \ +- { \ +- left = 0; \ +- right = cache->nlibs - 1; \ +- \ +- while (left <= right) \ +- { \ +- __typeof__ (cache->libs[0].key) key; \ +- \ +- middle = (left + right) / 2; \ +- \ +- key = cache->libs[middle].key; \ +- \ +- /* Make sure string table indices are not bogus before using \ +- them. */ \ +- if (! _dl_cache_verify_ptr (key)) \ +- { \ +- cmpres = 1; \ +- break; \ +- } \ +- \ +- /* Actually compare the entry with the key. */ \ +- cmpres = _dl_cache_libcmp (name, cache_data + key); \ +- if (__glibc_unlikely (cmpres == 0)) \ +- { \ +- /* Found it. LEFT now marks the last entry for which we \ +- know the name is correct. */ \ +- left = middle; \ +- \ +- /* There might be entries with this name before the one we \ +- found. So we have to find the beginning. */ \ +- while (middle > 0) \ +- { \ +- __typeof__ (cache->libs[0].key) key; \ +- \ +- key = cache->libs[middle - 1].key; \ +- /* Make sure string table indices are not bogus before \ +- using them. */ \ +- if (! _dl_cache_verify_ptr (key) \ +- /* Actually compare the entry. */ \ +- || _dl_cache_libcmp (name, cache_data + key) != 0) \ +- break; \ +- --middle; \ +- } \ +- \ +- do \ +- { \ +- int flags; \ +- __typeof__ (cache->libs[0]) *lib = &cache->libs[middle]; \ +- \ +- /* Only perform the name test if necessary. */ \ +- if (middle > left \ +- /* We haven't seen this string so far. Test whether the \ +- index is ok and whether the name matches. Otherwise \ +- we are done. */ \ +- && (! _dl_cache_verify_ptr (lib->key) \ +- || (_dl_cache_libcmp (name, cache_data + lib->key) \ +- != 0))) \ +- break; \ +- \ +- flags = lib->flags; \ +- if (_dl_cache_check_flags (flags) \ +- && _dl_cache_verify_ptr (lib->value)) \ +- { \ +- if (best == NULL || flags == GLRO(dl_correct_cache_id)) \ +- { \ +- HWCAP_CHECK; \ +- best = cache_data + lib->value; \ +- \ +- if (flags == GLRO(dl_correct_cache_id)) \ +- /* We've found an exact match for the shared \ +- object and no general `ELF' release. Stop \ +- searching. */ \ +- break; \ +- } \ +- } \ +- } \ +- while (++middle <= right); \ +- break; \ +- } \ +- \ +- if (cmpres < 0) \ +- left = middle + 1; \ +- else \ +- right = middle - 1; \ +- } \ +- } \ +-while (0) ++/* True if PTR is a valid string table index. */ ++static inline bool ++_dl_cache_verify_ptr (uint32_t ptr, size_t string_table_size) ++{ ++ return ptr < string_table_size; ++} ++ ++/* Compute the address of the element INDEX of the array at LIBS. ++ Conceptually, this is &LIBS[INDEX], but use ENTRY_SIZE for the size ++ of *LIBS. */ ++static inline const struct file_entry * ++_dl_cache_file_entry (const struct file_entry *libs, size_t entry_size, ++ size_t index) ++{ ++ return (const void *) libs + index * entry_size; ++} ++ ++/* We use binary search since the table is sorted in the cache file. ++ The first matching entry in the table is returned. It is important ++ to use the same algorithm as used while generating the cache file. ++ STRING_TABLE_SIZE indicates the maximum offset in STRING_TABLE at ++ which data is mapped; it is not exact. */ ++static const char * ++search_cache (const char *string_table, uint32_t string_table_size, ++ struct file_entry *libs, uint32_t nlibs, uint32_t entry_size, ++ const char *name) ++{ ++ /* Used by the HWCAP check in the struct file_entry_new case. */ ++ uint64_t platform = _dl_string_platform (GLRO (dl_platform)); ++ if (platform != (uint64_t) -1) ++ platform = 1ULL << platform; ++ uint64_t hwcap_mask = GET_HWCAP_MASK (); ++#define _DL_HWCAP_TLS_MASK (1LL << 63) ++ uint64_t hwcap_exclude = ~((GLRO (dl_hwcap) & hwcap_mask) ++ | _DL_HWCAP_PLATFORM | _DL_HWCAP_TLS_MASK); ++ ++ int left = 0; ++ int right = nlibs - 1; ++ const char *best = NULL; ++ ++ while (left <= right) ++ { ++ int middle = (left + right) / 2; ++ uint32_t key = _dl_cache_file_entry (libs, entry_size, middle)->key; ++ ++ /* Make sure string table indices are not bogus before using ++ them. */ ++ if (!_dl_cache_verify_ptr (key, string_table_size)) ++ return NULL; ++ ++ /* Actually compare the entry with the key. */ ++ int cmpres = _dl_cache_libcmp (name, string_table + key); ++ if (__glibc_unlikely (cmpres == 0)) ++ { ++ /* Found it. LEFT now marks the last entry for which we ++ know the name is correct. */ ++ left = middle; ++ ++ /* There might be entries with this name before the one we ++ found. So we have to find the beginning. */ ++ while (middle > 0) ++ { ++ key = _dl_cache_file_entry (libs, entry_size, middle - 1)->key; ++ /* Make sure string table indices are not bogus before ++ using them. */ ++ if (!_dl_cache_verify_ptr (key, string_table_size) ++ /* Actually compare the entry. */ ++ || _dl_cache_libcmp (name, string_table + key) != 0) ++ break; ++ --middle; ++ } ++ ++ do ++ { ++ int flags; ++ const struct file_entry *lib ++ = _dl_cache_file_entry (libs, entry_size, middle); ++ ++ /* Only perform the name test if necessary. */ ++ if (middle > left ++ /* We haven't seen this string so far. Test whether the ++ index is ok and whether the name matches. Otherwise ++ we are done. */ ++ && (! _dl_cache_verify_ptr (lib->key, string_table_size) ++ || (_dl_cache_libcmp (name, string_table + lib->key) ++ != 0))) ++ break; ++ ++ flags = lib->flags; ++ if (_dl_cache_check_flags (flags) ++ && _dl_cache_verify_ptr (lib->value, string_table_size)) ++ { ++ if (best == NULL || flags == GLRO (dl_correct_cache_id)) ++ { ++ if (entry_size >= sizeof (struct file_entry_new)) ++ { ++ /* The entry is large enough to include ++ HWCAP data. Check it. */ ++ struct file_entry_new *libnew ++ = (struct file_entry_new *) lib; ++ ++ if (libnew->hwcap & hwcap_exclude) ++ continue; ++ if (GLRO (dl_osversion) ++ && libnew->osversion > GLRO (dl_osversion)) ++ continue; ++ if (_DL_PLATFORMS_COUNT ++ && (libnew->hwcap & _DL_HWCAP_PLATFORM) != 0 ++ && ((libnew->hwcap & _DL_HWCAP_PLATFORM) ++ != platform)) ++ continue; ++ } ++ ++ best = string_table + lib->value; ++ ++ if (flags == GLRO (dl_correct_cache_id)) ++ /* We've found an exact match for the shared ++ object and no general `ELF' release. Stop ++ searching. */ ++ break; ++ } ++ } ++ } ++ while (++middle <= right); ++ break; ++ } + ++ if (cmpres < 0) ++ left = middle + 1; ++ else ++ right = middle - 1; ++ } ++ ++ return best; ++} + + int + _dl_cache_libcmp (const char *p1, const char *p2) +@@ -182,12 +220,6 @@ _dl_cache_libcmp (const char *p1, const char *p2) + char * + _dl_load_cache_lookup (const char *name) + { +- int left, right, middle; +- int cmpres; +- const char *cache_data; +- uint32_t cache_data_size; +- const char *best; +- + /* Print a message if the loading of libs is traced. */ + if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_LIBS)) + _dl_debug_printf (" search cache=%s\n", LD_SO_CACHE); +@@ -247,51 +279,22 @@ _dl_load_cache_lookup (const char *name) + /* Previously looked for the cache file and didn't find it. */ + return NULL; + +- best = NULL; +- ++ const char *best; + if (cache_new != (void *) -1) + { +- uint64_t platform; +- +- /* This is where the strings start. */ +- cache_data = (const char *) cache_new; +- +- /* Now we can compute how large the string table is. */ +- cache_data_size = (const char *) cache + cachesize - cache_data; +- +- platform = _dl_string_platform (GLRO(dl_platform)); +- if (platform != (uint64_t) -1) +- platform = 1ULL << platform; +- +- uint64_t hwcap_mask = GET_HWCAP_MASK(); +- +-#define _DL_HWCAP_TLS_MASK (1LL << 63) +- uint64_t hwcap_exclude = ~((GLRO(dl_hwcap) & hwcap_mask) +- | _DL_HWCAP_PLATFORM | _DL_HWCAP_TLS_MASK); +- +- /* Only accept hwcap if it's for the right platform. */ +-#define HWCAP_CHECK \ +- if (lib->hwcap & hwcap_exclude) \ +- continue; \ +- if (GLRO(dl_osversion) && lib->osversion > GLRO(dl_osversion)) \ +- continue; \ +- if (_DL_PLATFORMS_COUNT \ +- && (lib->hwcap & _DL_HWCAP_PLATFORM) != 0 \ +- && (lib->hwcap & _DL_HWCAP_PLATFORM) != platform) \ +- continue +- SEARCH_CACHE (cache_new); ++ const char *string_table = (const char *) cache_new; ++ best = search_cache (string_table, cachesize, ++ &cache_new->libs[0].entry, cache_new->nlibs, ++ sizeof (cache_new->libs[0]), name); + } + else + { +- /* This is where the strings start. */ +- cache_data = (const char *) &cache->libs[cache->nlibs]; +- +- /* Now we can compute how large the string table is. */ +- cache_data_size = (const char *) cache + cachesize - cache_data; +- +-#undef HWCAP_CHECK +-#define HWCAP_CHECK do {} while (0) +- SEARCH_CACHE (cache); ++ const char *string_table = (const char *) &cache->libs[cache->nlibs]; ++ uint32_t string_table_size ++ = (const char *) cache + cachesize - string_table; ++ best = search_cache (string_table, string_table_size, ++ &cache->libs[0], cache->nlibs, ++ sizeof (cache->libs[0]), name); + } + + /* Print our result if wanted. */ +diff --git a/sysdeps/generic/dl-cache.h b/sysdeps/generic/dl-cache.h +index cf43f1cf3b441bc7..3c5730dfe42c7c88 100644 +--- a/sysdeps/generic/dl-cache.h ++++ b/sysdeps/generic/dl-cache.h +@@ -59,8 +59,8 @@ + */ + struct file_entry + { +- int flags; /* This is 1 for an ELF library. */ +- unsigned int key, value; /* String table indices. */ ++ int32_t flags; /* This is 1 for an ELF library. */ ++ uint32_t key, value; /* String table indices. */ + }; + + struct cache_file +@@ -77,8 +77,17 @@ struct cache_file + + struct file_entry_new + { +- int32_t flags; /* This is 1 for an ELF library. */ +- uint32_t key, value; /* String table indices. */ ++ union ++ { ++ /* Fields shared with struct file_entry. */ ++ struct file_entry entry; ++ /* Also expose these fields directly. */ ++ struct ++ { ++ int32_t flags; /* This is 1 for an ELF library. */ ++ uint32_t key, value; /* String table indices. */ ++ }; ++ }; + uint32_t osversion; /* Required OS version. */ + uint64_t hwcap; /* Hwcap entry. */ + }; diff --git a/SOURCES/glibc-rh1817513-109.patch b/SOURCES/glibc-rh1817513-109.patch new file mode 100644 index 0000000..f53c03b --- /dev/null +++ b/SOURCES/glibc-rh1817513-109.patch @@ -0,0 +1,67 @@ +commit 5e598c2bbf938eac0f4045f5143f9dd723646672 +Author: Florian Weimer +Date: Fri Oct 30 18:40:28 2020 +0100 + + elf: In ldconfig, extract the new_sub_entry function from search_dir + + Reviewed-by: Adhemerval Zanella + +diff --git a/elf/ldconfig.c b/elf/ldconfig.c +index 7c8fd29387463a8a..be730ceb075f6c1f 100644 +--- a/elf/ldconfig.c ++++ b/elf/ldconfig.c +@@ -328,6 +328,23 @@ warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\ + "Andreas Jaeger"); + } + ++/* Allocate a new subdirectory with full path PATH under ENTRY, using ++ inode data from *ST. */ ++static struct dir_entry * ++new_sub_entry (const struct dir_entry *entry, const char *path, ++ const struct stat64 *st) ++{ ++ struct dir_entry *new_entry = xmalloc (sizeof (struct dir_entry)); ++ new_entry->from_file = entry->from_file; ++ new_entry->from_line = entry->from_line; ++ new_entry->path = xstrdup (path); ++ new_entry->flag = entry->flag; ++ new_entry->next = NULL; ++ new_entry->ino = st->st_ino; ++ new_entry->dev = st->st_dev; ++ return new_entry; ++} ++ + /* Add a single directory entry. */ + static void + add_single_dir (struct dir_entry *entry, int verbose) +@@ -823,26 +840,17 @@ search_dir (const struct dir_entry *entry) + + if (is_dir && is_hwcap_platform (direntry->d_name)) + { +- /* Handle subdirectory later. */ +- struct dir_entry *new_entry; +- +- new_entry = xmalloc (sizeof (struct dir_entry)); +- new_entry->from_file = entry->from_file; +- new_entry->from_line = entry->from_line; +- new_entry->path = xstrdup (file_name); +- new_entry->flag = entry->flag; +- new_entry->next = NULL; + if (!is_link + && direntry->d_type != DT_UNKNOWN + && __builtin_expect (lstat64 (real_file_name, &lstat_buf), 0)) + { + error (0, errno, _("Cannot lstat %s"), file_name); +- free (new_entry->path); +- free (new_entry); + continue; + } +- new_entry->ino = lstat_buf.st_ino; +- new_entry->dev = lstat_buf.st_dev; ++ ++ /* Handle subdirectory later. */ ++ struct dir_entry *new_entry = new_sub_entry (entry, file_name, ++ &lstat_buf); + add_single_dir (new_entry, 0); + continue; + } diff --git a/SOURCES/glibc-rh1817513-11.patch b/SOURCES/glibc-rh1817513-11.patch new file mode 100644 index 0000000..be54271 --- /dev/null +++ b/SOURCES/glibc-rh1817513-11.patch @@ -0,0 +1,79 @@ +commit 7cc65773f04e0f4252428c40dcbb784a39b58cd1 +Author: H.J. Lu +Date: Wed Oct 24 02:19:15 2018 -0700 + + x86: Support RDTSCP for benchtests + + RDTSCP waits until all previous instructions have executed and all + previous loads are globally visible before reading the counter. RDTSC + doesn't wait until all previous instructions have been executed before + reading the counter. All x86 processors since 2010 support RDTSCP + instruction. This patch adds RDTSCP support to benchtests. + + * benchtests/Makefile (CPPFLAGS-nonlib): Add -DUSE_RDTSCP if + USE_RDTSCP is defined. + * sysdeps/x86/hp-timing.h (HP_TIMING_NOW): Use RDTSCP if + USE_RDTSCP is defined. + +diff --git a/benchtests/Makefile b/benchtests/Makefile +index 28d6b0c43f5bd390..bde0caf140e8cf17 100644 +--- a/benchtests/Makefile ++++ b/benchtests/Makefile +@@ -131,6 +131,12 @@ CPPFLAGS-nonlib += -DDURATION=$(BENCH_DURATION) -D_ISOMAC + # HP_TIMING if it is available. + ifdef USE_CLOCK_GETTIME + CPPFLAGS-nonlib += -DUSE_CLOCK_GETTIME ++else ++# On x86 processors, use RDTSCP, instead of RDTSC, to measure performance ++# of functions. All x86 processors since 2010 support RDTSCP instruction. ++ifdef USE_RDTSCP ++CPPFLAGS-nonlib += -DUSE_RDTSCP ++endif + endif + + DETAILED_OPT := +diff --git a/benchtests/README b/benchtests/README +index 4ddff794d136f65f..aaf0b659e2b25627 100644 +--- a/benchtests/README ++++ b/benchtests/README +@@ -34,6 +34,15 @@ the benchmark to use clock_gettime by invoking make as follows: + + Again, one must run `make bench-clean' before changing the measurement method. + ++On x86 processors, RDTSCP instruction provides more precise timing data ++than RDTSC instruction. All x86 processors since 2010 support RDTSCP ++instruction. One can force the benchmark to use RDTSCP by invoking make ++as follows: ++ ++ $ make USE_RDTSCP=1 bench ++ ++One must run `make bench-clean' before changing the measurement method. ++ + Running benchmarks on another target: + ==================================== + +diff --git a/sysdeps/x86/hp-timing.h b/sysdeps/x86/hp-timing.h +index 77a1360748ca4535..0aa6f5e3f83e0d34 100644 +--- a/sysdeps/x86/hp-timing.h ++++ b/sysdeps/x86/hp-timing.h +@@ -40,7 +40,19 @@ typedef unsigned long long int hp_timing_t; + + NB: Use __builtin_ia32_rdtsc directly since including + makes building glibc very slow. */ +-# define HP_TIMING_NOW(Var) ((Var) = __builtin_ia32_rdtsc ()) ++# ifdef USE_RDTSCP ++/* RDTSCP waits until all previous instructions have executed and all ++ previous loads are globally visible before reading the counter. ++ RDTSC doesn't wait until all previous instructions have been executed ++ before reading the counter. */ ++# define HP_TIMING_NOW(Var) \ ++ (__extension__ ({ \ ++ unsigned int __aux; \ ++ (Var) = __builtin_ia32_rdtscp (&__aux); \ ++ })) ++# else ++# define HP_TIMING_NOW(Var) ((Var) = __builtin_ia32_rdtsc ()) ++# endif + + # include + #else diff --git a/SOURCES/glibc-rh1817513-110.patch b/SOURCES/glibc-rh1817513-110.patch new file mode 100644 index 0000000..57d0c15 --- /dev/null +++ b/SOURCES/glibc-rh1817513-110.patch @@ -0,0 +1,22 @@ +commit df5f473ed5ee95e3179fcb239e33e971619626cd +Author: Shuo Wang +Date: Tue Nov 24 16:42:18 2020 -0300 + + elf: Fix uninitialized variable for _dl_write + + Variable ret in elf/dl-write.c is uninitialized, which should get + return value from __writev. + +diff --git a/elf/dl-write.c b/elf/dl-write.c +index 7350aff0035d4fbc..9b741c8a8fe12f6c 100644 +--- a/elf/dl-write.c ++++ b/elf/dl-write.c +@@ -41,7 +41,7 @@ _dl_write (int fd, const void *buffer, size_t length) + else + { + __rtld_lock_lock_recursive (GL(dl_load_lock)); +- __writev (fd, &iov, 1); ++ ret = __writev (fd, &iov, 1); + if (ret < 0) + ret = -errno; + __rtld_lock_unlock_recursive (GL(dl_load_lock)); diff --git a/SOURCES/glibc-rh1817513-111.patch b/SOURCES/glibc-rh1817513-111.patch new file mode 100644 index 0000000..e194ff1 --- /dev/null +++ b/SOURCES/glibc-rh1817513-111.patch @@ -0,0 +1,85 @@ +commit 603ae243f6fe03208a3bb92adecf72403367bd95 +Author: Florian Weimer +Date: Thu Nov 26 16:59:44 2020 +0100 + + support: Add support_copy_file + + Reviewed-by: Adhemerval Zanella + +diff --git a/support/Makefile b/support/Makefile +index 895b83a426369b0c..35b21b19a248ba7f 100644 +--- a/support/Makefile ++++ b/support/Makefile +@@ -46,6 +46,7 @@ libsupport-routines = \ + support_capture_subprocess \ + support_capture_subprocess_check \ + support_chroot \ ++ support_copy_file \ + support_copy_file_range \ + support_descriptor_supports_holes \ + support_descriptors \ +diff --git a/support/support.h b/support/support.h +index 3af87f85fe1b762d..6f7f804847f67600 100644 +--- a/support/support.h ++++ b/support/support.h +@@ -115,6 +115,11 @@ extern const char support_install_rootsbindir[]; + /* Corresponds to the install's compiled locale directory. */ + extern const char support_complocaledir_prefix[]; + ++/* Copies the file at the path FROM to TO. If TO does not exist, it ++ is created. If TO is a regular file, it is truncated before ++ copying. The file mode is copied, but the permissions are not. */ ++extern void support_copy_file (const char *from, const char *to); ++ + extern ssize_t support_copy_file_range (int, off64_t *, int, off64_t *, + size_t, unsigned int); + +diff --git a/support/support_copy_file.c b/support/support_copy_file.c +new file mode 100644 +index 0000000000000000..c93e1e58c81b749d +--- /dev/null ++++ b/support/support_copy_file.c +@@ -0,0 +1,43 @@ ++/* Copy a file from one path to another. ++ 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 ++ ++void ++support_copy_file (const char *from, const char *to) ++{ ++ struct stat64 st; ++ xstat (from, &st); ++ int fd_from = xopen (from, O_RDONLY, 0); ++ mode_t mode = st.st_mode & 0777; ++ int fd_to = xopen (to, O_WRONLY | O_TRUNC | O_CREAT, mode); ++ ssize_t ret = support_copy_file_range (fd_from, NULL, fd_to, NULL, ++ st.st_size, 0); ++ if (ret < 0) ++ FAIL_EXIT1 ("copying from \"%s\" to \"%s\": %m", from, to); ++ if (ret != st.st_size) ++ FAIL_EXIT1 ("copying from \"%s\" to \"%s\": only %zd of %llu bytes copied", ++ from, to, ret, (unsigned long long int) st.st_size); ++ if (fchmod (fd_to, mode) < 0) ++ FAIL_EXIT1 ("fchmod on %s to 0%o: %m", to, mode); ++ xclose (fd_to); ++ xclose (fd_from); ++} diff --git a/SOURCES/glibc-rh1817513-112.patch b/SOURCES/glibc-rh1817513-112.patch new file mode 100644 index 0000000..80f1c38 --- /dev/null +++ b/SOURCES/glibc-rh1817513-112.patch @@ -0,0 +1,152 @@ +commit db07fae8250401adb2b97ab3e53d41da2a6bd767 +Author: Florian Weimer +Date: Thu Nov 26 16:59:44 2020 +0100 + + elf: Introduce enum opt_format in the ldconfig implementation + + Reviewed-by: Adhemerval Zanella + +diff --git a/elf/cache.c b/elf/cache.c +index c4cd825c30e00e8e..edcdd4b7cc1a6a0b 100644 +--- a/elf/cache.c ++++ b/elf/cache.c +@@ -321,13 +321,13 @@ save_cache (const char *cache_name) + struct cache_file *file_entries = NULL; + size_t file_entries_size = 0; + +- if (opt_format != 2) ++ if (opt_format != opt_format_new) + { + /* struct cache_file_new is 64-bit aligned on some arches while + only 32-bit aligned on other arches. Duplicate last old + cache entry so that new cache in ld.so.cache can be used by + both. */ +- if (opt_format != 0) ++ if (opt_format != opt_format_old) + cache_entry_old_count = (cache_entry_old_count + 1) & ~1; + + /* And the list of all entries in the old format. */ +@@ -345,7 +345,7 @@ save_cache (const char *cache_name) + struct cache_file_new *file_entries_new = NULL; + size_t file_entries_new_size = 0; + +- if (opt_format != 0) ++ if (opt_format != opt_format_old) + { + /* And the list of all entries in the new format. */ + file_entries_new_size = sizeof (struct cache_file_new) +@@ -370,7 +370,7 @@ save_cache (const char *cache_name) + table, we have to adjust all string indices for this so that + old libc5/glibc 2 dynamic linkers just ignore them. */ + unsigned int str_offset; +- if (opt_format != 0) ++ if (opt_format != opt_format_old) + str_offset = file_entries_new_size; + else + str_offset = 0; +@@ -385,13 +385,13 @@ save_cache (const char *cache_name) + entry = entry->next, ++idx_new) + { + /* First the library. */ +- if (opt_format != 2 && entry->hwcap == 0) ++ if (opt_format != opt_format_new && entry->hwcap == 0) + { + file_entries->libs[idx_old].flags = entry->flags; + /* XXX: Actually we can optimize here and remove duplicates. */ + file_entries->libs[idx_old].key = str_offset + pad; + } +- if (opt_format != 0) ++ if (opt_format != opt_format_old) + { + /* We could subtract file_entries_new_size from str_offset - + not doing so makes the code easier, the string table +@@ -407,9 +407,9 @@ save_cache (const char *cache_name) + str = mempcpy (str, entry->lib, len); + str_offset += len; + /* Then the path. */ +- if (opt_format != 2 && entry->hwcap == 0) ++ if (opt_format != opt_format_new && entry->hwcap == 0) + file_entries->libs[idx_old].value = str_offset + pad; +- if (opt_format != 0) ++ if (opt_format != opt_format_old) + file_entries_new->libs[idx_new].value = str_offset; + len = strlen (entry->path) + 1; + str = mempcpy (str, entry->path, len); +@@ -420,7 +420,7 @@ save_cache (const char *cache_name) + } + + /* Duplicate last old cache entry if needed. */ +- if (opt_format != 2 ++ if (opt_format != opt_format_new + && idx_old < cache_entry_old_count) + file_entries->libs[idx_old] = file_entries->libs[idx_old - 1]; + +@@ -438,16 +438,16 @@ save_cache (const char *cache_name) + temp_name); + + /* Write contents. */ +- if (opt_format != 2) ++ if (opt_format != opt_format_new) + { + if (write (fd, file_entries, file_entries_size) + != (ssize_t) file_entries_size) + error (EXIT_FAILURE, errno, _("Writing of cache data failed")); + } +- if (opt_format != 0) ++ if (opt_format != opt_format_old) + { + /* Align cache. */ +- if (opt_format != 2) ++ if (opt_format != opt_format_new) + { + char zero[pad]; + memset (zero, '\0', pad); +diff --git a/elf/ldconfig.c b/elf/ldconfig.c +index be730ceb075f6c1f..0fa5aef83f9cd86c 100644 +--- a/elf/ldconfig.c ++++ b/elf/ldconfig.c +@@ -100,8 +100,7 @@ static int opt_print_cache; + int opt_verbose; + + /* Format to support. */ +-/* 0: only libc5/glibc2; 1: both; 2: only glibc 2.2. */ +-int opt_format = 2; ++enum opt_format opt_format = opt_format_new; + + /* Build cache. */ + static int opt_build_cache = 1; +@@ -281,11 +280,11 @@ parse_opt (int key, char *arg, struct argp_state *state) + break; + case 'c': + if (strcmp (arg, "old") == 0) +- opt_format = 0; ++ opt_format = opt_format_old; + else if (strcmp (arg, "compat") == 0) +- opt_format = 1; ++ opt_format = opt_format_compat; + else if (strcmp (arg, "new") == 0) +- opt_format = 2; ++ opt_format = opt_format_new; + break; + default: + return ARGP_ERR_UNKNOWN; +diff --git a/sysdeps/generic/ldconfig.h b/sysdeps/generic/ldconfig.h +index 6774212110d23eae..b15b142511829436 100644 +--- a/sysdeps/generic/ldconfig.h ++++ b/sysdeps/generic/ldconfig.h +@@ -90,7 +90,14 @@ extern char *chroot_canon (const char *chroot, const char *name); + /* Declared in ldconfig.c. */ + extern int opt_verbose; + +-extern int opt_format; ++enum opt_format ++ { ++ opt_format_old = 0, /* Use struct cache_file. */ ++ opt_format_compat = 1, /* Use both, old format followed by new. */ ++ opt_format_new = 2, /* Use struct cache_file_new. */ ++ }; ++ ++extern enum opt_format opt_format; + + /* Prototypes for a few program-wide used functions. */ + #include diff --git a/SOURCES/glibc-rh1817513-113.patch b/SOURCES/glibc-rh1817513-113.patch new file mode 100644 index 0000000..c37d4df --- /dev/null +++ b/SOURCES/glibc-rh1817513-113.patch @@ -0,0 +1,1111 @@ +commit dad90d528259b669342757c37dedefa8577e2636 +Author: Florian Weimer +Date: Fri Dec 4 09:13:43 2020 +0100 + + elf: Add glibc-hwcaps support for LD_LIBRARY_PATH + + This hacks non-power-set processing into _dl_important_hwcaps. + Once the legacy hwcaps handling goes away, the subdirectory + handling needs to be reworked, but it is premature to do this + while both approaches are still supported. + + ld.so supports two new arguments, --glibc-hwcaps-prepend and + --glibc-hwcaps-mask. Each accepts a colon-separated list of + glibc-hwcaps subdirectory names. The prepend option adds additional + subdirectories that are searched first, in the specified order. The + mask option restricts the automatically selected subdirectories to + those listed in the option argument. For example, on systems where + /usr/lib64 is on the library search path, + --glibc-hwcaps-prepend=valgrind:debug causes the dynamic loader to + search the directories /usr/lib64/glibc-hwcaps/valgrind and + /usr/lib64/glibc-hwcaps/debug just before /usr/lib64 is searched. + + Reviewed-by: Adhemerval Zanella + +Conflicts: + elf/Makefile + (Test backport differences.) + +diff --git a/elf/Makefile b/elf/Makefile +index bc96b8fd65e376cc..f795617780b393ec 100644 +--- a/elf/Makefile ++++ b/elf/Makefile +@@ -59,7 +59,8 @@ elide-routines.os = $(all-dl-routines) dl-support enbl-secure dl-origin \ + # 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-usage ++ dl-error-minimal dl-conflict dl-hwcaps dl-hwcaps_split dl-hwcaps-subdirs \ ++ dl-usage + all-rtld-routines = $(rtld-routines) $(sysdep-rtld-routines) + + CFLAGS-dl-runtime.c += -fexceptions -fasynchronous-unwind-tables +@@ -199,13 +200,14 @@ tests += restest1 preloadtest loadfail multiload origtest resolvfail \ + tst-filterobj tst-filterobj-dlopen tst-auxobj tst-auxobj-dlopen \ + tst-audit14 tst-audit15 tst-audit16 \ + tst-tls-ie tst-tls-ie-dlmopen \ +- argv0test ++ argv0test \ ++ tst-glibc-hwcaps tst-glibc-hwcaps-prepend tst-glibc-hwcaps-mask + # 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-create_format1 tst-tls-surplus tst-dl-hwcaps_split + tests-container += tst-pldd + ifeq ($(build-hardcoded-path-in-tests),yes) + tests += tst-dlopen-aout +@@ -318,7 +320,10 @@ modules-names = testobj1 testobj2 testobj3 testobj4 testobj5 testobj6 \ + 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 ++ 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 \ + + # Most modules build with _ISOMAC defined, but those filtered out + # depend on internal headers. +@@ -1732,3 +1737,60 @@ $(objpfx)argv0test.out: tst-rtld-argv0.sh $(objpfx)ld.so \ + '$(test-wrapper-env)' '$(run_program_env)' \ + '$(rpath-link)' 'test-argv0' > $@; \ + $(evaluate-test) ++ ++# A list containing the name of the most likely searched subdirectory ++# of the glibc-hwcaps directory, for each supported architecture (in ++# other words, the oldest hardware level recognized by the ++# glibc-hwcaps mechanism for this architecture). Used to obtain test ++# coverage for some glibc-hwcaps tests for the widest possible range ++# of systems. ++glibc-hwcaps-first-subdirs-for-tests = ++ ++# The test modules are parameterized by preprocessor macros. ++LDFLAGS-libmarkermod1-1.so += -Wl,-soname,libmarkermod1.so ++LDFLAGS-libmarkermod2-1.so += -Wl,-soname,libmarkermod2.so ++LDFLAGS-libmarkermod3-1.so += -Wl,-soname,libmarkermod3.so ++LDFLAGS-libmarkermod4-1.so += -Wl,-soname,libmarkermod4.so ++$(objpfx)libmarkermod%.os : markermodMARKER-VALUE.c ++ $(compile-command.c) \ ++ -DMARKER=marker$(firstword $(subst -, ,$*)) \ ++ -DVALUE=$(lastword $(subst -, ,$*)) ++$(objpfx)libmarkermod1.so: $(objpfx)libmarkermod1-1.so ++ cp $< $@ ++$(objpfx)libmarkermod2.so: $(objpfx)libmarkermod2-1.so ++ cp $< $@ ++$(objpfx)libmarkermod3.so: $(objpfx)libmarkermod3-1.so ++ cp $< $@ ++$(objpfx)libmarkermod4.so: $(objpfx)libmarkermod4-1.so ++ cp $< $@ ++ ++# tst-glibc-hwcaps-prepend checks that --glibc-hwcaps-prepend is ++# preferred over auto-detected subdirectories. ++$(objpfx)tst-glibc-hwcaps-prepend: $(objpfx)libmarkermod1-1.so ++$(objpfx)glibc-hwcaps/prepend-markermod1/libmarkermod1.so: \ ++ $(objpfx)libmarkermod1-2.so ++ $(make-target-directory) ++ cp $< $@ ++$(objpfx)glibc-hwcaps/%/libmarkermod1.so: $(objpfx)libmarkermod1-3.so ++ $(make-target-directory) ++ cp $< $@ ++$(objpfx)tst-glibc-hwcaps-prepend.out: \ ++ $(objpfx)tst-glibc-hwcaps-prepend $(objpfx)libmarkermod1.so \ ++ $(patsubst %,$(objpfx)glibc-hwcaps/%/libmarkermod1.so,prepend-markermod1 \ ++ $(glibc-hwcaps-first-subdirs-for-tests)) ++ $(test-wrapper) $(rtld-prefix) \ ++ --glibc-hwcaps-prepend prepend-markermod1 \ ++ $< > $@; \ ++ $(evaluate-test) ++ ++# tst-glibc-hwcaps-mask checks that --glibc-hwcaps-mask can be used to ++# suppress all auto-detected subdirectories. ++$(objpfx)tst-glibc-hwcaps-mask: $(objpfx)libmarkermod1-1.so ++$(objpfx)tst-glibc-hwcaps-mask.out: \ ++ $(objpfx)tst-glibc-hwcaps-mask $(objpfx)libmarkermod1.so \ ++ $(patsubst %,$(objpfx)glibc-hwcaps/%/libmarkermod1.so,\ ++ $(glibc-hwcaps-first-subdirs-for-tests)) ++ $(test-wrapper) $(rtld-prefix) \ ++ --glibc-hwcaps-mask does-not-exist \ ++ $< > $@; \ ++ $(evaluate-test) +diff --git a/elf/dl-hwcaps-subdirs.c b/elf/dl-hwcaps-subdirs.c +new file mode 100644 +index 0000000000000000..60c6d59731ee3188 +--- /dev/null ++++ b/elf/dl-hwcaps-subdirs.c +@@ -0,0 +1,29 @@ ++/* Architecture-specific glibc-hwcaps subdirectories. 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, see ++ . */ ++ ++#include ++ ++/* In the generic version, there are no subdirectories defined. */ ++ ++const char _dl_hwcaps_subdirs[] = ""; ++ ++uint32_t ++_dl_hwcaps_subdirs_active (void) ++{ ++ return 0; ++} +diff --git a/elf/dl-hwcaps.c b/elf/dl-hwcaps.c +index 82ee89c36a1eb4ab..e57d0d2d41741021 100644 +--- a/elf/dl-hwcaps.c ++++ b/elf/dl-hwcaps.c +@@ -26,20 +26,97 @@ + #include + #include + ++/* This is the result of counting the substrings in a colon-separated ++ hwcaps string. */ ++struct hwcaps_counts ++{ ++ /* Number of substrings. */ ++ size_t count; ++ ++ /* Sum of the individual substring lengths (without separators or ++ null terminators). */ ++ size_t total_length; ++ ++ /* Maximum length of an individual substring. */ ++ size_t maximum_length; ++}; ++ ++/* Update *COUNTS according to the contents of HWCAPS. Skip over ++ entries whose bit is not set in MASK. */ ++static void ++update_hwcaps_counts (struct hwcaps_counts *counts, const char *hwcaps, ++ uint32_t bitmask, const char *mask) ++{ ++ struct dl_hwcaps_split_masked sp; ++ _dl_hwcaps_split_masked_init (&sp, hwcaps, bitmask, mask); ++ while (_dl_hwcaps_split_masked (&sp)) ++ { ++ ++counts->count; ++ counts->total_length += sp.split.length; ++ if (sp.split.length > counts->maximum_length) ++ counts->maximum_length = sp.split.length; ++ } ++} ++ ++/* State for copy_hwcaps. Must be initialized to point to ++ the storage areas for the array and the strings themselves. */ ++struct copy_hwcaps ++{ ++ struct r_strlenpair *next_pair; ++ char *next_string; ++}; ++ ++/* Copy HWCAPS into the string pairs and strings, advancing *TARGET. ++ Skip over entries whose bit is not set in MASK. */ ++static void ++copy_hwcaps (struct copy_hwcaps *target, const char *hwcaps, ++ uint32_t bitmask, const char *mask) ++{ ++ struct dl_hwcaps_split_masked sp; ++ _dl_hwcaps_split_masked_init (&sp, hwcaps, bitmask, mask); ++ while (_dl_hwcaps_split_masked (&sp)) ++ { ++ target->next_pair->str = target->next_string; ++ char *slash = __mempcpy (__mempcpy (target->next_string, ++ GLIBC_HWCAPS_PREFIX, ++ strlen (GLIBC_HWCAPS_PREFIX)), ++ sp.split.segment, sp.split.length); ++ *slash = '/'; ++ target->next_pair->len ++ = strlen (GLIBC_HWCAPS_PREFIX) + sp.split.length + 1; ++ ++target->next_pair; ++ target->next_string = slash + 1; ++ } ++} ++ + /* Return an array of useful/necessary hardware capability names. */ + const struct r_strlenpair * +-_dl_important_hwcaps (size_t *sz, size_t *max_capstrlen) ++_dl_important_hwcaps (const char *glibc_hwcaps_prepend, ++ const char *glibc_hwcaps_mask, ++ size_t *sz, size_t *max_capstrlen) + { + uint64_t hwcap_mask = GET_HWCAP_MASK(); + /* Determine how many important bits are set. */ + uint64_t masked = GLRO(dl_hwcap) & hwcap_mask; + size_t cnt = GLRO (dl_platform) != NULL; + size_t n, m; +- size_t total; + struct r_strlenpair *result; + struct r_strlenpair *rp; + char *cp; + ++ /* glibc-hwcaps subdirectories. These are exempted from the power ++ set construction below. */ ++ uint32_t hwcaps_subdirs_active = _dl_hwcaps_subdirs_active (); ++ struct hwcaps_counts hwcaps_counts = { 0, }; ++ update_hwcaps_counts (&hwcaps_counts, glibc_hwcaps_prepend, -1, NULL); ++ update_hwcaps_counts (&hwcaps_counts, _dl_hwcaps_subdirs, ++ hwcaps_subdirs_active, glibc_hwcaps_mask); ++ ++ /* Each hwcaps subdirectory has a GLIBC_HWCAPS_PREFIX string prefix ++ and a "/" suffix once stored in the result. */ ++ size_t total = (hwcaps_counts.count * (strlen (GLIBC_HWCAPS_PREFIX) + 1) ++ + hwcaps_counts.total_length); ++ + /* Count the number of bits set in the masked value. */ + for (n = 0; (~((1ULL << n) - 1) & masked) != 0; ++n) + if ((masked & (1ULL << n)) != 0) +@@ -74,10 +151,10 @@ _dl_important_hwcaps (size_t *sz, size_t *max_capstrlen) + + /* Determine the total size of all strings together. */ + 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; +@@ -94,26 +171,48 @@ _dl_important_hwcaps (size_t *sz, size_t *max_capstrlen) + } + } + +- /* The result structure: we use a very compressed way to store the +- various combinations of capability names. */ +- *sz = 1 << cnt; +- result = (struct r_strlenpair *) malloc (*sz * sizeof (*result) + total); +- if (result == NULL) ++ *sz = hwcaps_counts.count + (1 << cnt); ++ ++ /* This is the overall result, including both glibc-hwcaps ++ subdirectories and the legacy hwcaps subdirectories using the ++ power set construction. */ ++ struct r_strlenpair *overall_result ++ = malloc (*sz * sizeof (*result) + total); ++ if (overall_result == NULL) + _dl_signal_error (ENOMEM, NULL, NULL, + N_("cannot create capability list")); + ++ /* Fill in the glibc-hwcaps subdirectories. */ ++ { ++ struct copy_hwcaps target; ++ target.next_pair = overall_result; ++ target.next_string = (char *) (overall_result + *sz); ++ copy_hwcaps (&target, glibc_hwcaps_prepend, -1, NULL); ++ copy_hwcaps (&target, _dl_hwcaps_subdirs, ++ hwcaps_subdirs_active, glibc_hwcaps_mask); ++ /* Set up the write target for the power set construction. */ ++ result = target.next_pair; ++ cp = target.next_string; ++ } ++ ++ ++ /* Power set construction begins here. We use a very compressed way ++ to store the various combinations of capability names. */ ++ + if (cnt == 1) + { +- result[0].str = (char *) (result + *sz); ++ result[0].str = cp; + result[0].len = temp[0].len + 1; +- result[1].str = (char *) (result + *sz); ++ result[1].str = cp; + result[1].len = 0; +- cp = __mempcpy ((char *) (result + *sz), temp[0].str, temp[0].len); ++ cp = __mempcpy (cp, temp[0].str, temp[0].len); + *cp = '/'; +- *sz = 2; +- *max_capstrlen = result[0].len; ++ if (result[0].len > hwcaps_counts.maximum_length) ++ *max_capstrlen = result[0].len; ++ else ++ *max_capstrlen = hwcaps_counts.maximum_length; + +- return result; ++ return overall_result; + } + + /* Fill in the information. This follows the following scheme +@@ -124,7 +223,7 @@ _dl_important_hwcaps (size_t *sz, size_t *max_capstrlen) + #3: 0, 3 1001 + This allows the representation of all possible combinations of + capability names in the string. First generate the strings. */ +- result[1].str = result[0].str = cp = (char *) (result + *sz); ++ result[1].str = result[0].str = cp; + #define add(idx) \ + cp = __mempcpy (__mempcpy (cp, temp[idx].str, temp[idx].len), "/", 1); + if (cnt == 2) +@@ -191,7 +290,10 @@ _dl_important_hwcaps (size_t *sz, size_t *max_capstrlen) + while (--n != 0); + + /* The maximum string length. */ +- *max_capstrlen = result[0].len; ++ if (result[0].len > hwcaps_counts.maximum_length) ++ *max_capstrlen = result[0].len; ++ else ++ *max_capstrlen = hwcaps_counts.maximum_length; + +- return result; ++ return overall_result; + } +diff --git a/elf/dl-hwcaps.h b/elf/dl-hwcaps.h +index d69ee11dc27bb5e5..3fcfbceb1a8fc1c8 100644 +--- a/elf/dl-hwcaps.h ++++ b/elf/dl-hwcaps.h +@@ -16,6 +16,11 @@ + License along with the GNU C Library; if not, see + . */ + ++#ifndef _DL_HWCAPS_H ++#define _DL_HWCAPS_H ++ ++#include ++ + #include + + #if HAVE_TUNABLES +@@ -28,3 +33,103 @@ + # define GET_HWCAP_MASK() (0) + # endif + #endif ++ ++#define GLIBC_HWCAPS_SUBDIRECTORY "glibc-hwcaps" ++#define GLIBC_HWCAPS_PREFIX GLIBC_HWCAPS_SUBDIRECTORY "/" ++ ++/* Used by _dl_hwcaps_split below, to split strings at ':' ++ separators. */ ++struct dl_hwcaps_split ++{ ++ const char *segment; /* Start of the current segment. */ ++ size_t length; /* Number of bytes until ':' or NUL. */ ++}; ++ ++/* Prepare *S to parse SUBJECT, for future _dl_hwcaps_split calls. If ++ SUBJECT is NULL, it is treated as the empty string. */ ++static inline void ++_dl_hwcaps_split_init (struct dl_hwcaps_split *s, const char *subject) ++{ ++ s->segment = subject; ++ /* The initial call to _dl_hwcaps_split will not skip anything. */ ++ s->length = 0; ++} ++ ++/* Extract the next non-empty string segment, up to ':' or the null ++ terminator. Return true if one more segment was found, or false if ++ the end of the string was reached. On success, S->segment is the ++ start of the segment found, and S->length is its length. ++ (Typically, S->segment[S->length] is not null.) */ ++_Bool _dl_hwcaps_split (struct dl_hwcaps_split *s) attribute_hidden; ++ ++/* Similar to dl_hwcaps_split, but with bit-based and name-based ++ masking. */ ++struct dl_hwcaps_split_masked ++{ ++ struct dl_hwcaps_split split; ++ ++ /* For used by the iterator implementation. */ ++ const char *mask; ++ uint32_t bitmask; ++}; ++ ++/* Prepare *S for iteration with _dl_hwcaps_split_masked. Only HWCAP ++ names in SUBJECT whose bit is set in BITMASK and whose name is in ++ MASK will be returned. SUBJECT must not contain empty HWCAP names. ++ If MASK is NULL, no name-based masking is applied. Likewise for ++ BITMASK if BITMASK is -1 (infinite number of bits). */ ++static inline void ++_dl_hwcaps_split_masked_init (struct dl_hwcaps_split_masked *s, ++ const char *subject, ++ uint32_t bitmask, const char *mask) ++{ ++ _dl_hwcaps_split_init (&s->split, subject); ++ s->bitmask = bitmask; ++ s->mask = mask; ++} ++ ++/* Like _dl_hwcaps_split, but apply masking. */ ++_Bool _dl_hwcaps_split_masked (struct dl_hwcaps_split_masked *s) ++ attribute_hidden; ++ ++/* Returns true if the colon-separated HWCAP list HWCAPS contains the ++ capability NAME (with length NAME_LENGTH). If HWCAPS is NULL, the ++ function returns true. */ ++_Bool _dl_hwcaps_contains (const char *hwcaps, const char *name, ++ size_t name_length) attribute_hidden; ++ ++/* Colon-separated string of glibc-hwcaps subdirectories, without the ++ "glibc-hwcaps/" prefix. The most preferred subdirectory needs to ++ be listed first. Up to 32 subdirectories are supported, limited by ++ the width of the uint32_t mask. */ ++extern const char _dl_hwcaps_subdirs[] attribute_hidden; ++ ++/* Returns a bitmap of active subdirectories in _dl_hwcaps_subdirs. ++ Bit 0 (the LSB) corresponds to the first substring in ++ _dl_hwcaps_subdirs, bit 1 to the second substring, and so on. ++ There is no direct correspondence between HWCAP bitmasks and this ++ bitmask. */ ++uint32_t _dl_hwcaps_subdirs_active (void) attribute_hidden; ++ ++/* Returns a bitmask that marks the last ACTIVE subdirectories in a ++ _dl_hwcaps_subdirs_active string (containing SUBDIRS directories in ++ total) as active. Intended for use in _dl_hwcaps_subdirs_active ++ implementations (if a contiguous tail of the list in ++ _dl_hwcaps_subdirs is selected). */ ++static inline uint32_t ++_dl_hwcaps_subdirs_build_bitmask (int subdirs, int active) ++{ ++ /* Leading subdirectories that are not active. */ ++ int inactive = subdirs - active; ++ if (inactive == 32) ++ return 0; ++ ++ uint32_t mask; ++ if (subdirs != 32) ++ mask = (1U << subdirs) - 1; ++ else ++ mask = -1; ++ return mask ^ ((1U << inactive) - 1); ++} ++ ++#endif /* _DL_HWCAPS_H */ +diff --git a/elf/dl-hwcaps_split.c b/elf/dl-hwcaps_split.c +new file mode 100644 +index 0000000000000000..95225e9f409ca229 +--- /dev/null ++++ b/elf/dl-hwcaps_split.c +@@ -0,0 +1,77 @@ ++/* Hardware capability support for run-time dynamic loader. String splitting. ++ 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 ++ ++_Bool ++_dl_hwcaps_split (struct dl_hwcaps_split *s) ++{ ++ if (s->segment == NULL) ++ return false; ++ ++ /* Skip over the previous segment. */ ++ s->segment += s->length; ++ ++ /* Consume delimiters. This also avoids returning an empty ++ segment. */ ++ while (*s->segment == ':') ++ ++s->segment; ++ if (*s->segment == '\0') ++ return false; ++ ++ /* This could use strchrnul, but we would have to link the function ++ into ld.so for that. */ ++ const char *colon = strchr (s->segment, ':'); ++ if (colon == NULL) ++ s->length = strlen (s->segment); ++ else ++ s->length = colon - s->segment; ++ return true; ++} ++ ++_Bool ++_dl_hwcaps_split_masked (struct dl_hwcaps_split_masked *s) ++{ ++ while (true) ++ { ++ if (!_dl_hwcaps_split (&s->split)) ++ return false; ++ bool active = s->bitmask & 1; ++ s->bitmask >>= 1; ++ if (active && _dl_hwcaps_contains (s->mask, ++ s->split.segment, s->split.length)) ++ return true; ++ } ++} ++ ++_Bool ++_dl_hwcaps_contains (const char *hwcaps, const char *name, size_t name_length) ++{ ++ if (hwcaps == NULL) ++ return true; ++ ++ struct dl_hwcaps_split split; ++ _dl_hwcaps_split_init (&split, hwcaps); ++ while (_dl_hwcaps_split (&split)) ++ if (split.length == name_length ++ && memcmp (split.segment, name, name_length) == 0) ++ return true; ++ return false; ++} +diff --git a/elf/dl-load.c b/elf/dl-load.c +index d2be21ea7d1545fe..fee08d7816714178 100644 +--- a/elf/dl-load.c ++++ b/elf/dl-load.c +@@ -682,7 +682,9 @@ cache_rpath (struct link_map *l, + + + void +-_dl_init_paths (const char *llp, const char *source) ++_dl_init_paths (const char *llp, const char *source, ++ const char *glibc_hwcaps_prepend, ++ const char *glibc_hwcaps_mask) + { + size_t idx; + const char *strp; +@@ -697,7 +699,8 @@ _dl_init_paths (const char *llp, const char *source) + + #ifdef SHARED + /* Get the capabilities. */ +- capstr = _dl_important_hwcaps (&ncapstr, &max_capstrlen); ++ capstr = _dl_important_hwcaps (glibc_hwcaps_prepend, glibc_hwcaps_mask, ++ &ncapstr, &max_capstrlen); + #endif + + /* First set up the rest of the default search directory entries. */ +diff --git a/elf/dl-main.h b/elf/dl-main.h +index b51256d3b48230b0..566713a0d10cfdb7 100644 +--- a/elf/dl-main.h ++++ b/elf/dl-main.h +@@ -84,6 +84,14 @@ struct dl_main_state + /* The preload list passed as a command argument. */ + const char *preloadarg; + ++ /* Additional glibc-hwcaps subdirectories to search first. ++ Colon-separated list. */ ++ const char *glibc_hwcaps_prepend; ++ ++ /* Mask for the internal glibc-hwcaps subdirectories. ++ Colon-separated list. */ ++ const char *glibc_hwcaps_mask; ++ + enum rtld_mode mode; + + /* True if any of the debugging options is enabled. */ +@@ -98,7 +106,8 @@ struct dl_main_state + static inline void + call_init_paths (const struct dl_main_state *state) + { +- _dl_init_paths (state->library_path, state->library_path_source); ++ _dl_init_paths (state->library_path, state->library_path_source, ++ state->glibc_hwcaps_prepend, state->glibc_hwcaps_mask); + } + + /* Print ld.so usage information and exit. */ +diff --git a/elf/dl-support.c b/elf/dl-support.c +index fb9672367f8d6abd..34be8e5babfb6af3 100644 +--- a/elf/dl-support.c ++++ b/elf/dl-support.c +@@ -315,7 +315,10 @@ _dl_non_dynamic_init (void) + + /* Initialize the data structures for the search paths for shared + objects. */ +- _dl_init_paths (getenv ("LD_LIBRARY_PATH"), "LD_LIBRARY_PATH"); ++ _dl_init_paths (getenv ("LD_LIBRARY_PATH"), "LD_LIBRARY_PATH", ++ /* No glibc-hwcaps selection support in statically ++ linked binaries. */ ++ NULL, NULL); + + /* Remember the last search directory added at startup. */ + _dl_init_all_dirs = GL(dl_all_dirs); +diff --git a/elf/dl-usage.c b/elf/dl-usage.c +index 796ad38b43c2211b..e22a9c39427187d1 100644 +--- a/elf/dl-usage.c ++++ b/elf/dl-usage.c +@@ -83,7 +83,7 @@ print_search_path_for_help (struct dl_main_state *state) + { + if (__rtld_search_dirs.dirs == NULL) + /* The run-time search paths have not yet been initialized. */ +- _dl_init_paths (state->library_path, state->library_path_source); ++ call_init_paths (state); + + _dl_printf ("\nShared library search path:\n"); + +@@ -132,6 +132,67 @@ print_hwcap_1_finish (bool *first) + _dl_printf (")\n"); + } + ++/* Print the header for print_hwcaps_subdirectories. */ ++static void ++print_hwcaps_subdirectories_header (bool *nothing_printed) ++{ ++ if (*nothing_printed) ++ { ++ _dl_printf ("\n\ ++Subdirectories of glibc-hwcaps directories, in priority order:\n"); ++ *nothing_printed = false; ++ } ++} ++ ++/* Print the HWCAP name itself, indented. */ ++static void ++print_hwcaps_subdirectories_name (const struct dl_hwcaps_split *split) ++{ ++ _dl_write (STDOUT_FILENO, " ", 2); ++ _dl_write (STDOUT_FILENO, split->segment, split->length); ++} ++ ++/* Print the list of recognized glibc-hwcaps subdirectories. */ ++static void ++print_hwcaps_subdirectories (const struct dl_main_state *state) ++{ ++ bool nothing_printed = true; ++ struct dl_hwcaps_split split; ++ ++ /* The prepended glibc-hwcaps subdirectories. */ ++ _dl_hwcaps_split_init (&split, state->glibc_hwcaps_prepend); ++ while (_dl_hwcaps_split (&split)) ++ { ++ print_hwcaps_subdirectories_header (¬hing_printed); ++ print_hwcaps_subdirectories_name (&split); ++ bool first = true; ++ print_hwcap_1 (&first, true, "searched"); ++ print_hwcap_1_finish (&first); ++ } ++ ++ /* The built-in glibc-hwcaps subdirectories. Do the filtering ++ manually, so that more precise diagnostics are possible. */ ++ uint32_t mask = _dl_hwcaps_subdirs_active (); ++ _dl_hwcaps_split_init (&split, _dl_hwcaps_subdirs); ++ while (_dl_hwcaps_split (&split)) ++ { ++ print_hwcaps_subdirectories_header (¬hing_printed); ++ print_hwcaps_subdirectories_name (&split); ++ bool first = true; ++ print_hwcap_1 (&first, mask & 1, "supported"); ++ bool listed = _dl_hwcaps_contains (state->glibc_hwcaps_mask, ++ split.segment, split.length); ++ print_hwcap_1 (&first, !listed, "masked"); ++ print_hwcap_1 (&first, (mask & 1) && listed, "searched"); ++ print_hwcap_1_finish (&first); ++ mask >>= 1; ++ } ++ ++ if (nothing_printed) ++ _dl_printf ("\n\ ++No subdirectories of glibc-hwcaps directories are searched.\n"); ++} ++ + /* Write a list of hwcap subdirectories to standard output. See + _dl_important_hwcaps in dl-hwcaps.c. */ + static void +@@ -186,6 +247,10 @@ setting environment variables (which would be inherited by subprocesses).\n\ + --inhibit-cache Do not use " LD_SO_CACHE "\n\ + --library-path PATH use given PATH instead of content of the environment\n\ + variable LD_LIBRARY_PATH\n\ ++ --glibc-hwcaps-prepend LIST\n\ ++ search glibc-hwcaps subdirectories in LIST\n\ ++ --glibc-hwcaps-mask LIST\n\ ++ only search built-in subdirectories if in LIST\n\ + --inhibit-rpath LIST ignore RUNPATH and RPATH information in object names\n\ + in LIST\n\ + --audit LIST use objects named in LIST as auditors\n\ +@@ -198,6 +263,7 @@ This program interpreter self-identifies as: " RTLD "\n\ + ", + argv0); + print_search_path_for_help (state); ++ print_hwcaps_subdirectories (state); + print_legacy_hwcap_directories (); + _exit (EXIT_SUCCESS); + } +diff --git a/elf/markermodMARKER-VALUE.c b/elf/markermodMARKER-VALUE.c +new file mode 100644 +index 0000000000000000..99bdcf71a4e219c6 +--- /dev/null ++++ b/elf/markermodMARKER-VALUE.c +@@ -0,0 +1,29 @@ ++/* Source file template for building shared objects with marker functions. ++ 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 ++ . */ ++ ++/* MARKER and VALUE must be set on the compiler command line. */ ++ ++#ifndef MARKER ++# error MARKER not defined ++#endif ++ ++int ++MARKER (void) ++{ ++ return VALUE; ++} +diff --git a/elf/rtld.c b/elf/rtld.c +index da1eef108508b95f..fde5a6a4a485207e 100644 +--- a/elf/rtld.c ++++ b/elf/rtld.c +@@ -287,6 +287,8 @@ dl_main_state_init (struct dl_main_state *state) + state->library_path_source = NULL; + state->preloadlist = NULL; + state->preloadarg = NULL; ++ state->glibc_hwcaps_prepend = NULL; ++ state->glibc_hwcaps_mask = NULL; + state->mode = rtld_mode_normal; + state->any_debug = false; + state->version_info = false; +@@ -1238,6 +1240,22 @@ dl_main (const ElfW(Phdr) *phdr, + { + argv0 = _dl_argv[2]; + ++ _dl_skip_args += 2; ++ _dl_argc -= 2; ++ _dl_argv += 2; ++ } ++ else if (strcmp (_dl_argv[1], "--glibc-hwcaps-prepend") == 0 ++ && _dl_argc > 2) ++ { ++ state.glibc_hwcaps_prepend = _dl_argv[2]; ++ _dl_skip_args += 2; ++ _dl_argc -= 2; ++ _dl_argv += 2; ++ } ++ else if (strcmp (_dl_argv[1], "--glibc-hwcaps-mask") == 0 ++ && _dl_argc > 2) ++ { ++ state.glibc_hwcaps_mask = _dl_argv[2]; + _dl_skip_args += 2; + _dl_argc -= 2; + _dl_argv += 2; +diff --git a/elf/tst-dl-hwcaps_split.c b/elf/tst-dl-hwcaps_split.c +new file mode 100644 +index 0000000000000000..364159427074bd1c +--- /dev/null ++++ b/elf/tst-dl-hwcaps_split.c +@@ -0,0 +1,148 @@ ++/* Unit tests for dl-hwcaps.c. ++ 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 ++ ++static void ++check_split_masked (const char *input, int32_t bitmask, const char *mask, ++ const char *expected[], size_t expected_length) ++{ ++ struct dl_hwcaps_split_masked split; ++ _dl_hwcaps_split_masked_init (&split, input, bitmask, mask); ++ size_t index = 0; ++ while (_dl_hwcaps_split_masked (&split)) ++ { ++ TEST_VERIFY_EXIT (index < expected_length); ++ TEST_COMPARE_BLOB (expected[index], strlen (expected[index]), ++ split.split.segment, split.split.length); ++ ++index; ++ } ++ TEST_COMPARE (index, expected_length); ++} ++ ++static void ++check_split (const char *input, ++ const char *expected[], size_t expected_length) ++{ ++ struct dl_hwcaps_split split; ++ _dl_hwcaps_split_init (&split, input); ++ size_t index = 0; ++ while (_dl_hwcaps_split (&split)) ++ { ++ TEST_VERIFY_EXIT (index < expected_length); ++ TEST_COMPARE_BLOB (expected[index], strlen (expected[index]), ++ split.segment, split.length); ++ ++index; ++ } ++ TEST_COMPARE (index, expected_length); ++ ++ /* Reuse the test cases with masking that does not actually remove ++ anything. */ ++ check_split_masked (input, -1, NULL, expected, expected_length); ++ check_split_masked (input, -1, input, expected, expected_length); ++} ++ ++static int ++do_test (void) ++{ ++ /* Splitting tests, without masking. */ ++ check_split (NULL, NULL, 0); ++ check_split ("", NULL, 0); ++ check_split (":", NULL, 0); ++ check_split ("::", NULL, 0); ++ ++ { ++ const char *expected[] = { "first" }; ++ check_split ("first", expected, array_length (expected)); ++ check_split (":first", expected, array_length (expected)); ++ check_split ("first:", expected, array_length (expected)); ++ check_split (":first:", expected, array_length (expected)); ++ } ++ ++ { ++ const char *expected[] = { "first", "second" }; ++ check_split ("first:second", expected, array_length (expected)); ++ check_split ("first::second", expected, array_length (expected)); ++ check_split (":first:second", expected, array_length (expected)); ++ check_split ("first:second:", expected, array_length (expected)); ++ check_split (":first:second:", expected, array_length (expected)); ++ } ++ ++ /* Splitting tests with masking. */ ++ { ++ const char *expected[] = { "first" }; ++ check_split_masked ("first", 3, "first:second", ++ expected, array_length (expected)); ++ check_split_masked ("first:second", 3, "first:", ++ expected, array_length (expected)); ++ check_split_masked ("first:second", 1, NULL, ++ expected, array_length (expected)); ++ } ++ { ++ const char *expected[] = { "second" }; ++ check_split_masked ("first:second", 3, "second", ++ expected, array_length (expected)); ++ check_split_masked ("first:second:third", -1, "second:", ++ expected, array_length (expected)); ++ check_split_masked ("first:second", 2, NULL, ++ expected, array_length (expected)); ++ check_split_masked ("first:second:third", 2, "first:second", ++ expected, array_length (expected)); ++ } ++ ++ /* Tests for _dl_hwcaps_contains. */ ++ TEST_VERIFY (_dl_hwcaps_contains (NULL, "first", strlen ("first"))); ++ TEST_VERIFY (_dl_hwcaps_contains (NULL, "", 0)); ++ TEST_VERIFY (! _dl_hwcaps_contains ("", "first", strlen ("first"))); ++ TEST_VERIFY (! _dl_hwcaps_contains ("firs", "first", strlen ("first"))); ++ TEST_VERIFY (_dl_hwcaps_contains ("firs", "first", strlen ("first") - 1)); ++ for (int i = 0; i < strlen ("first"); ++i) ++ TEST_VERIFY (! _dl_hwcaps_contains ("first", "first", i)); ++ TEST_VERIFY (_dl_hwcaps_contains ("first", "first", strlen ("first"))); ++ TEST_VERIFY (_dl_hwcaps_contains ("first:", "first", strlen ("first"))); ++ TEST_VERIFY (_dl_hwcaps_contains ("first:second", ++ "first", strlen ("first"))); ++ TEST_VERIFY (_dl_hwcaps_contains (":first:second", "first", ++ strlen ("first"))); ++ TEST_VERIFY (_dl_hwcaps_contains ("first:second", "second", ++ strlen ("second"))); ++ TEST_VERIFY (_dl_hwcaps_contains ("first:second:", "second", ++ strlen ("second"))); ++ TEST_VERIFY (_dl_hwcaps_contains ("first::second:", "second", ++ strlen ("second"))); ++ TEST_VERIFY (_dl_hwcaps_contains ("first:second::", "second", ++ strlen ("second"))); ++ for (int i = 0; i < strlen ("second"); ++i) ++ { ++ TEST_VERIFY (!_dl_hwcaps_contains ("first:second", "second", i)); ++ TEST_VERIFY (!_dl_hwcaps_contains ("first:second:", "second", i)); ++ TEST_VERIFY (!_dl_hwcaps_contains ("first:second::", "second", i)); ++ TEST_VERIFY (!_dl_hwcaps_contains ("first::second", "second", i)); ++ } ++ ++ return 0; ++} ++ ++#include ++ ++/* Rebuild the sources here because the object file is built for ++ inclusion into the dynamic loader. */ ++#include "dl-hwcaps_split.c" +diff --git a/elf/tst-glibc-hwcaps-mask.c b/elf/tst-glibc-hwcaps-mask.c +new file mode 100644 +index 0000000000000000..27b09b358caf7853 +--- /dev/null ++++ b/elf/tst-glibc-hwcaps-mask.c +@@ -0,0 +1,31 @@ ++/* Test that --glibc-hwcaps-mask works. ++ 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 ++ ++extern int marker1 (void); ++ ++static int ++do_test (void) ++{ ++ /* The marker1 function in elf/markermod1.so returns 1. */ ++ TEST_COMPARE (marker1 (), 1); ++ return 0; ++} ++ ++#include +diff --git a/elf/tst-glibc-hwcaps-prepend.c b/elf/tst-glibc-hwcaps-prepend.c +new file mode 100644 +index 0000000000000000..57d7319f1484ca4b +--- /dev/null ++++ b/elf/tst-glibc-hwcaps-prepend.c +@@ -0,0 +1,32 @@ ++/* Test that --glibc-hwcaps-prepend works. ++ 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 ++ ++extern int marker1 (void); ++ ++static int ++do_test (void) ++{ ++ /* The marker1 function in ++ glibc-hwcaps/prepend-markermod1/markermod1.so returns 2. */ ++ TEST_COMPARE (marker1 (), 2); ++ return 0; ++} ++ ++#include +diff --git a/elf/tst-glibc-hwcaps.c b/elf/tst-glibc-hwcaps.c +new file mode 100644 +index 0000000000000000..28f47cf8914a1f2a +--- /dev/null ++++ b/elf/tst-glibc-hwcaps.c +@@ -0,0 +1,28 @@ ++/* Stub test for glibc-hwcaps. ++ 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 ++ ++static int ++do_test (void) ++{ ++ puts ("info: generic tst-glibc-hwcaps (tests nothing)"); ++ return 0; ++} ++ ++#include +diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h +index 2c9fdeb286bdaadf..77923499d3de4366 100644 +--- a/sysdeps/generic/ldsodefs.h ++++ b/sysdeps/generic/ldsodefs.h +@@ -1045,8 +1045,13 @@ extern struct r_debug *_dl_debug_initialize (ElfW(Addr) ldbase, Lmid_t ns) + attribute_hidden; + + /* Initialize the basic data structure for the search paths. SOURCE +- is either "LD_LIBRARY_PATH" or "--library-path". */ +-extern void _dl_init_paths (const char *library_path, const char *source) ++ is either "LD_LIBRARY_PATH" or "--library-path". ++ GLIBC_HWCAPS_PREPEND adds additional glibc-hwcaps subdirectories to ++ search. GLIBC_HWCAPS_MASK is used to filter the built-in ++ subdirectories if not NULL. */ ++extern void _dl_init_paths (const char *library_path, const char *source, ++ const char *glibc_hwcaps_prepend, ++ const char *glibc_hwcaps_mask) + attribute_hidden; + + /* Gather the information needed to install the profiling tables and start +@@ -1070,9 +1075,14 @@ extern void _dl_show_auxv (void) attribute_hidden; + extern char *_dl_next_ld_env_entry (char ***position) attribute_hidden; + + /* Return an array with the names of the important hardware +- capabilities. The length of the array is written to *SZ, and the +- maximum of all strings length is written to *MAX_CAPSTRLEN. */ +-const struct r_strlenpair *_dl_important_hwcaps (size_t *sz, ++ capabilities. PREPEND is a colon-separated list of glibc-hwcaps ++ directories to search first. MASK is a colon-separated list used ++ to filter the built-in glibc-hwcaps subdirectories. The length of ++ the array is written to *SZ, and the maximum of all strings length ++ is written to *MAX_CAPSTRLEN. */ ++const struct r_strlenpair *_dl_important_hwcaps (const char *prepend, ++ const char *mask, ++ size_t *sz, + size_t *max_capstrlen) + attribute_hidden; + diff --git a/SOURCES/glibc-rh1817513-114.patch b/SOURCES/glibc-rh1817513-114.patch new file mode 100644 index 0000000..26cd1b6 --- /dev/null +++ b/SOURCES/glibc-rh1817513-114.patch @@ -0,0 +1,190 @@ +commit 84ba719b260551918965d0a433914de683087645 +Author: Florian Weimer +Date: Fri Dec 4 09:13:43 2020 +0100 + + elf: Add endianness markup to ld.so.cache (bug 27008) + + Use a reserved byte in the new format cache header to indicate whether + the file is in little endian or big endian format. Eventually, this + information could be used to provide a unified cache for qemu-user + and similiar scenarios. + + Reviewed-by: Adhemerval Zanella + +diff --git a/elf/cache.c b/elf/cache.c +index edcdd4b7cc1a6a0b..28e4889d006d2f0b 100644 +--- a/elf/cache.c ++++ b/elf/cache.c +@@ -152,6 +152,14 @@ print_entry (const char *lib, int flag, unsigned int osversion, + printf (") => %s\n", key); + } + ++/* Print an error and exit if the new-file cache is internally ++ inconsistent. */ ++static void ++check_new_cache (struct cache_file_new *cache) ++{ ++ if (! cache_file_new_matches_endian (cache)) ++ error (EXIT_FAILURE, 0, _("Cache file has wrong endianness.\n")); ++} + + /* Print the whole cache file, if a file contains the new cache format + hidden in the old one, print the contents of the new format. */ +@@ -193,6 +201,7 @@ print_cache (const char *cache_name) + || memcmp (cache_new->version, CACHE_VERSION, + sizeof CACHE_VERSION - 1)) + error (EXIT_FAILURE, 0, _("File is not a cache file.\n")); ++ check_new_cache (cache_new); + format = 1; + /* This is where the strings start. */ + cache_data = (const char *) cache_new; +@@ -222,6 +231,7 @@ print_cache (const char *cache_name) + && memcmp (cache_new->version, CACHE_VERSION, + sizeof CACHE_VERSION - 1) == 0) + { ++ check_new_cache (cache_new); + cache_data = (const char *) cache_new; + format = 1; + } +@@ -361,6 +371,7 @@ save_cache (const char *cache_name) + + file_entries_new->nlibs = cache_entry_count; + file_entries_new->len_strings = total_strlen; ++ file_entries_new->flags = cache_file_new_flags_endian_current; + } + + /* Pad for alignment of cache_file_new. */ +diff --git a/elf/dl-cache.c b/elf/dl-cache.c +index 366a051dfcd26132..de063faa8b2c88ae 100644 +--- a/elf/dl-cache.c ++++ b/elf/dl-cache.c +@@ -242,6 +242,11 @@ _dl_load_cache_lookup (const char *name) + && ((cachesize - sizeof *cache_new) / sizeof (struct file_entry_new) + >= ((struct cache_file_new *) file)->nlibs)) + { ++ if (! cache_file_new_matches_endian (file)) ++ { ++ __munmap (file, cachesize); ++ file = (void *) -1; ++ } + cache_new = file; + cache = file; + } +@@ -263,7 +268,20 @@ _dl_load_cache_lookup (const char *name) + if (cachesize < (offset + sizeof (struct cache_file_new)) + || memcmp (cache_new->magic, CACHEMAGIC_VERSION_NEW, + sizeof CACHEMAGIC_VERSION_NEW - 1) != 0) +- cache_new = (void *) -1; ++ cache_new = (void *) -1; ++ else ++ { ++ if (! cache_file_new_matches_endian (cache_new)) ++ { ++ /* The old-format part of the cache is bogus as well ++ if the endianness does not match. (But it is ++ unclear how the new header can be located if the ++ endianess does not match.) */ ++ cache = (void *) -1; ++ cache_new = (void *) -1; ++ __munmap (file, cachesize); ++ } ++ } + } + else + { +diff --git a/sysdeps/generic/dl-cache.h b/sysdeps/generic/dl-cache.h +index 3c5730dfe42c7c88..6ecfd6da0e59329c 100644 +--- a/sysdeps/generic/dl-cache.h ++++ b/sysdeps/generic/dl-cache.h +@@ -16,6 +16,11 @@ + License along with the GNU C Library; if not, see + . */ + ++#ifndef _DL_CACHE_H ++#define _DL_CACHE_H ++ ++#include ++#include + #include + + #ifndef _DL_CACHE_DEFAULT_ID +@@ -92,17 +97,72 @@ struct file_entry_new + uint64_t hwcap; /* Hwcap entry. */ + }; + ++/* See flags member of struct cache_file_new below. */ ++enum ++ { ++ /* No endianness information available. An old ldconfig version ++ without endianness support wrote the file. */ ++ cache_file_new_flags_endian_unset = 0, ++ ++ /* Cache is invalid and should be ignored. */ ++ cache_file_new_flags_endian_invalid = 1, ++ ++ /* Cache format is little endian. */ ++ cache_file_new_flags_endian_little = 2, ++ ++ /* Cache format is big endian. */ ++ cache_file_new_flags_endian_big = 3, ++ ++ /* Bit mask to extract the cache_file_new_flags_endian_* ++ values. */ ++ cache_file_new_flags_endian_mask = 3, ++ ++ /* Expected value of the endian bits in the flags member for the ++ current architecture. */ ++ cache_file_new_flags_endian_current ++ = (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ ++ ? cache_file_new_flags_endian_little ++ : cache_file_new_flags_endian_big), ++ }; ++ + struct cache_file_new + { + char magic[sizeof CACHEMAGIC_NEW - 1]; + char version[sizeof CACHE_VERSION - 1]; + uint32_t nlibs; /* Number of entries. */ + uint32_t len_strings; /* Size of string table. */ +- uint32_t unused[5]; /* Leave space for future extensions ++ ++ /* flags & cache_file_new_flags_endian_mask is one of the values ++ cache_file_new_flags_endian_unset, cache_file_new_flags_endian_invalid, ++ cache_file_new_flags_endian_little, cache_file_new_flags_endian_big. ++ ++ The remaining bits are unused and should be generated as zero and ++ ignored by readers. */ ++ uint8_t flags; ++ ++ uint8_t padding_unsed[3]; /* Not used, for future extensions. */ ++ ++ uint32_t unused[4]; /* Leave space for future extensions + and align to 8 byte boundary. */ + struct file_entry_new libs[0]; /* Entries describing libraries. */ + /* After this the string table of size len_strings is found. */ + }; ++_Static_assert (sizeof (struct cache_file_new) == 48, ++ "size of struct cache_file_new"); ++ ++/* Returns false if *CACHE has the wrong endianness for this ++ architecture, and true if the endianness matches (or is ++ unknown). */ ++static inline bool ++cache_file_new_matches_endian (const struct cache_file_new *cache) ++{ ++ /* A zero value for cache->flags means that no endianness ++ information is available. */ ++ return cache->flags == 0 ++ || ((cache->flags & cache_file_new_flags_endian_big) ++ == cache_file_new_flags_endian_current); ++} ++ + + /* Used to align cache_file_new. */ + #define ALIGN_CACHE(addr) \ +@@ -110,3 +170,5 @@ struct cache_file_new + & (~(__alignof__ (struct cache_file_new) - 1))) + + extern int _dl_cache_libcmp (const char *p1, const char *p2) attribute_hidden; ++ ++#endif /* _DL_CACHE_H */ diff --git a/SOURCES/glibc-rh1817513-115.patch b/SOURCES/glibc-rh1817513-115.patch new file mode 100644 index 0000000..3b0db56 --- /dev/null +++ b/SOURCES/glibc-rh1817513-115.patch @@ -0,0 +1,312 @@ +commit dfb3f101c5ef23adf60d389058a2b33e23303d04 +Author: Florian Weimer +Date: Fri Dec 4 09:13:43 2020 +0100 + + elf: Add extension mechanism to ld.so.cache + + A previously unused new-format header field is used to record + the address of an extension directory. + + This change adds a demo extension which records the version of + ldconfig which builds a file. + + Reviewed-by: Adhemerval Zanella + +diff --git a/elf/cache.c b/elf/cache.c +index 28e4889d006d2f0b..5a8f1ad70cc3fead 100644 +--- a/elf/cache.c ++++ b/elf/cache.c +@@ -15,6 +15,7 @@ + You should have received a copy of the GNU General Public License + along with this program; if not, see . */ + ++#include + #include + #include + #include +@@ -33,6 +34,7 @@ + + #include + #include ++#include + + struct cache_entry + { +@@ -161,6 +163,21 @@ check_new_cache (struct cache_file_new *cache) + error (EXIT_FAILURE, 0, _("Cache file has wrong endianness.\n")); + } + ++/* Print the extension information at the cache at start address ++ FILE_BASE, of length FILE_SIZE bytes. The new-format cache header ++ is at CACHE, and the file name for diagnostics is CACHE_NAME. */ ++static void ++print_extensions (struct cache_extension_all_loaded *ext) ++{ ++ if (ext->sections[cache_extension_tag_generator].base != NULL) ++ { ++ fputs (_("Cache generated by: "), stdout); ++ fwrite (ext->sections[cache_extension_tag_generator].base, 1, ++ ext->sections[cache_extension_tag_generator].size, stdout); ++ putchar ('\n'); ++ } ++} ++ + /* Print the whole cache file, if a file contains the new cache format + hidden in the old one, print the contents of the new format. */ + void +@@ -250,6 +267,11 @@ print_cache (const char *cache_name) + } + else if (format == 1) + { ++ struct cache_extension_all_loaded ext; ++ if (!cache_extension_load (cache_new, cache, cache_size, &ext)) ++ error (EXIT_FAILURE, 0, ++ _("Malformed extension data in cache file %s\n"), cache_name); ++ + printf (_("%d libs found in cache `%s'\n"), + cache_new->nlibs, cache_name); + +@@ -260,6 +282,7 @@ print_cache (const char *cache_name) + cache_new->libs[i].osversion, + cache_new->libs[i].hwcap, + cache_data + cache_new->libs[i].value); ++ print_extensions (&ext); + } + /* Cleanup. */ + munmap (cache, cache_size); +@@ -301,6 +324,45 @@ compare (const struct cache_entry *e1, const struct cache_entry *e2) + return res; + } + ++/* Size of the cache extension directory. All tags are assumed to be ++ present. */ ++enum ++ { ++ cache_extension_size = (offsetof (struct cache_extension, sections) ++ + (cache_extension_count ++ * sizeof (struct cache_extension_section))) ++ }; ++ ++/* Write the cache extensions to FD. The extension directory is ++ assumed to be located at CACHE_EXTENSION_OFFSET. */ ++static void ++write_extensions (int fd, uint32_t cache_extension_offset) ++{ ++ assert ((cache_extension_offset % 4) == 0); ++ ++ struct cache_extension *ext = xmalloc (cache_extension_size); ++ ext->magic = cache_extension_magic; ++ ext->count = cache_extension_count; ++ ++ for (int i = 0; i < cache_extension_count; ++i) ++ { ++ ext->sections[i].tag = i; ++ ext->sections[i].flags = 0; ++ } ++ ++ const char *generator ++ = "ldconfig " PKGVERSION RELEASE " release version " VERSION; ++ ext->sections[cache_extension_tag_generator].offset ++ = cache_extension_offset + cache_extension_size; ++ ext->sections[cache_extension_tag_generator].size = strlen (generator); ++ ++ if (write (fd, ext, cache_extension_size) != cache_extension_size ++ || write (fd, generator, strlen (generator)) != strlen (generator)) ++ error (EXIT_FAILURE, errno, _("Writing of cache extension data failed")); ++ ++ free (ext); ++} ++ + /* Save the contents of the cache. */ + void + save_cache (const char *cache_name) +@@ -435,6 +497,25 @@ save_cache (const char *cache_name) + && idx_old < cache_entry_old_count) + file_entries->libs[idx_old] = file_entries->libs[idx_old - 1]; + ++ /* Compute the location of the extension directory. This ++ implementation puts the directory after the string table. The ++ size computation matches the write calls below. The extension ++ directory does not exist with format 0, so the value does not ++ matter. */ ++ uint32_t extension_offset = 0; ++ if (opt_format != opt_format_new) ++ extension_offset += file_entries_size; ++ if (opt_format != opt_format_old) ++ { ++ if (opt_format != opt_format_new) ++ extension_offset += pad; ++ extension_offset += file_entries_new_size; ++ } ++ extension_offset += total_strlen; ++ extension_offset = roundup (extension_offset, 4); /* Provide alignment. */ ++ if (opt_format != opt_format_old) ++ file_entries_new->extension_offset = extension_offset; ++ + /* Write out the cache. */ + + /* Write cache first to a temporary file and rename it later. */ +@@ -473,6 +554,14 @@ save_cache (const char *cache_name) + if (write (fd, strings, total_strlen) != (ssize_t) total_strlen) + error (EXIT_FAILURE, errno, _("Writing of cache data failed")); + ++ if (opt_format != opt_format_old) ++ { ++ /* Align file position to 4. */ ++ off64_t old_offset = lseek64 (fd, extension_offset, SEEK_SET); ++ assert ((unsigned long long int) (extension_offset - old_offset) < 4); ++ write_extensions (fd, extension_offset); ++ } ++ + /* Make sure user can always read cache file */ + if (chmod (temp_name, S_IROTH|S_IRGRP|S_IRUSR|S_IWUSR)) + error (EXIT_FAILURE, errno, +diff --git a/sysdeps/generic/dl-cache.h b/sysdeps/generic/dl-cache.h +index 6ecfd6da0e59329c..259e843724531630 100644 +--- a/sysdeps/generic/dl-cache.h ++++ b/sysdeps/generic/dl-cache.h +@@ -21,7 +21,9 @@ + + #include + #include ++#include + #include ++#include + + #ifndef _DL_CACHE_DEFAULT_ID + # define _DL_CACHE_DEFAULT_ID 3 +@@ -142,7 +144,11 @@ struct cache_file_new + + uint8_t padding_unsed[3]; /* Not used, for future extensions. */ + +- uint32_t unused[4]; /* Leave space for future extensions ++ /* File offset of the extension directory. See struct ++ cache_extension below. Must be a multiple of four. */ ++ uint32_t extension_offset; ++ ++ uint32_t unused[3]; /* Leave space for future extensions + and align to 8 byte boundary. */ + struct file_entry_new libs[0]; /* Entries describing libraries. */ + /* After this the string table of size len_strings is found. */ +@@ -164,6 +170,121 @@ cache_file_new_matches_endian (const struct cache_file_new *cache) + } + + ++/* Randomly chosen magic value, which allows for additional ++ consistency verification. */ ++enum { cache_extension_magic = (uint32_t) -358342284 }; ++ ++/* Tag values for different kinds of extension sections. Similar to ++ SHT_* constants. */ ++enum cache_extension_tag ++ { ++ /* Array of bytes containing the glibc version that generated this ++ cache file. */ ++ cache_extension_tag_generator, ++ ++ /* Total number of known cache extension tags. */ ++ cache_extension_count ++ }; ++ ++/* Element in the array following struct cache_extension. Similar to ++ an ELF section header. */ ++struct cache_extension_section ++{ ++ /* Type of the extension section. A enum cache_extension_tag value. */ ++ uint32_t tag; ++ ++ /* Extension-specific flags. Currently generated as zero. */ ++ uint32_t flags; ++ ++ /* Offset from the start of the file for the data in this extension ++ section. Specific extensions can have alignment constraints. */ ++ uint32_t offset; ++ ++ /* Length in bytes of the extension data. Specific extensions may ++ have size requirements. */ ++ uint32_t size; ++}; ++ ++/* The extension directory in the cache. An array of struct ++ cache_extension_section entries. */ ++struct cache_extension ++{ ++ uint32_t magic; /* Always cache_extension_magic. */ ++ uint32_t count; /* Number of following entries. */ ++ ++ /* count section descriptors of type struct cache_extension_section ++ follow. */ ++ struct cache_extension_section sections[]; ++}; ++ ++/* A relocated version of struct cache_extension_section. */ ++struct cache_extension_loaded ++{ ++ /* Address and size of this extension section. base is NULL if the ++ section is missing from the file. */ ++ const void *base; ++ size_t size; ++ ++ /* Flags from struct cache_extension_section. */ ++ uint32_t flags; ++}; ++ ++/* All supported extension sections, relocated. Filled in by ++ cache_extension_load below. */ ++struct cache_extension_all_loaded ++{ ++ struct cache_extension_loaded sections[cache_extension_count]; ++}; ++ ++static bool __attribute__ ((unused)) ++cache_extension_load (const struct cache_file_new *cache, ++ const void *file_base, size_t file_size, ++ struct cache_extension_all_loaded *loaded) ++{ ++ memset (loaded, 0, sizeof (*loaded)); ++ if (cache->extension_offset == 0) ++ /* No extensions present. This is not a format error. */ ++ return true; ++ if ((cache->extension_offset % 4) != 0) ++ /* Extension offset is misaligned. */ ++ return false; ++ size_t size_tmp; ++ if (__builtin_add_overflow (cache->extension_offset, ++ sizeof (struct cache_extension), &size_tmp) ++ || size_tmp > file_size) ++ /* Extension extends beyond the end of the file. */ ++ return false; ++ const struct cache_extension *ext = file_base + cache->extension_offset; ++ if (ext->magic != cache_extension_magic) ++ return false; ++ if (__builtin_mul_overflow (ext->count, ++ sizeof (struct cache_extension_section), ++ &size_tmp) ++ || __builtin_add_overflow (cache->extension_offset ++ + sizeof (struct cache_extension), size_tmp, ++ &size_tmp) ++ || size_tmp > file_size) ++ /* Extension array extends beyond the end of the file. */ ++ return false; ++ for (uint32_t i = 0; i < ext->count; ++i) ++ { ++ if (__builtin_add_overflow (ext->sections[i].offset, ++ ext->sections[i].size, &size_tmp) ++ || size_tmp > file_size) ++ /* Extension data extends beyond the end of the file. */ ++ return false; ++ ++ uint32_t tag = ext->sections[i].tag; ++ if (tag >= cache_extension_count) ++ /* Tag is out of range and unrecognized. */ ++ continue; ++ loaded->sections[tag].base = file_base + ext->sections[i].offset; ++ loaded->sections[tag].size = ext->sections[i].size; ++ loaded->sections[tag].flags = ext->sections[i].flags; ++ } ++ return true; ++} ++ + /* Used to align cache_file_new. */ + #define ALIGN_CACHE(addr) \ + (((addr) + __alignof__ (struct cache_file_new) -1) \ diff --git a/SOURCES/glibc-rh1817513-116.patch b/SOURCES/glibc-rh1817513-116.patch new file mode 100644 index 0000000..e5f927f --- /dev/null +++ b/SOURCES/glibc-rh1817513-116.patch @@ -0,0 +1,544 @@ +commit 785969a047ad2f23f758901c6816422573544453 +Author: Florian Weimer +Date: Fri Dec 4 09:13:43 2020 +0100 + + elf: Implement a string table for ldconfig, with tail merging + + This will be used in ldconfig to reduce the ld.so.cache size slightly. + + Tail merging is an optimization where a pointer points into another + string if the first string is a suffix of the second string. + + The hash function FNV-1a was chosen because it is simple and achieves + good dispersion even for short strings (so that the hash table bucket + count can be a power of two). It is clearly superior to the hsearch + hash and the ELF hash in this regard. + + The hash table uses chaining for collision resolution. + + Reviewed-by: Adhemerval Zanella + +diff --git a/elf/Makefile b/elf/Makefile +index f795617780b393ec..abb3e9d1179ef5cd 100644 +--- a/elf/Makefile ++++ b/elf/Makefile +@@ -163,7 +163,7 @@ tests-container = \ + + tests := tst-tls9 tst-leaks1 \ + tst-array1 tst-array2 tst-array3 tst-array4 tst-array5 \ +- tst-auxv ++ tst-auxv tst-stringtable + tests-internal := tst-tls1 tst-tls2 $(tests-static-internal) + tests-static := $(tests-static-normal) $(tests-static-internal) + +diff --git a/elf/stringtable.c b/elf/stringtable.c +new file mode 100644 +index 0000000000000000..099347d73ee70b8f +--- /dev/null ++++ b/elf/stringtable.c +@@ -0,0 +1,209 @@ ++/* String tables for ld.so.cache construction. Implementation. ++ Copyright (C) 2020 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published ++ by the Free Software Foundation; version 2 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program; if not, see . */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++static void ++stringtable_init (struct stringtable *table) ++{ ++ table->count = 0; ++ ++ /* This needs to be a power of two. 128 is sufficient to keep track ++ of 42 DSOs without resizing (assuming two strings per DSOs). ++ glibc itself comes with more than 20 DSOs, so 64 would likely to ++ be too small. */ ++ table->allocated = 128; ++ ++ table->entries = xcalloc (table->allocated, sizeof (table->entries[0])); ++} ++ ++/* 32-bit FNV-1a hash function. */ ++static uint32_t ++fnv1a (const char *string, size_t length) ++{ ++ const unsigned char *p = (const unsigned char *) string; ++ uint32_t hash = 2166136261U; ++ for (size_t i = 0; i < length; ++i) ++ { ++ hash ^= p[i]; ++ hash *= 16777619U; ++ } ++ return hash; ++} ++ ++/* Double the capacity of the hash table. */ ++static void ++stringtable_rehash (struct stringtable *table) ++{ ++ /* This computation cannot overflow because the old total in-memory ++ size of the hash table is larger than the computed value. */ ++ uint32_t new_allocated = table->allocated * 2; ++ struct stringtable_entry **new_entries ++ = xcalloc (new_allocated, sizeof (table->entries[0])); ++ ++ uint32_t mask = new_allocated - 1; ++ for (uint32_t i = 0; i < table->allocated; ++i) ++ for (struct stringtable_entry *e = table->entries[i]; e != NULL; ) ++ { ++ struct stringtable_entry *next = e->next; ++ uint32_t hash = fnv1a (e->string, e->length); ++ uint32_t new_index = hash & mask; ++ e->next = new_entries[new_index]; ++ new_entries[new_index] = e; ++ e = next; ++ } ++ ++ free (table->entries); ++ table->entries = new_entries; ++ table->allocated = new_allocated; ++} ++ ++struct stringtable_entry * ++stringtable_add (struct stringtable *table, const char *string) ++{ ++ /* Check for a zero-initialized table. */ ++ if (table->allocated == 0) ++ stringtable_init (table); ++ ++ size_t length = strlen (string); ++ if (length > (1U << 30)) ++ error (EXIT_FAILURE, 0, _("String table string is too long")); ++ uint32_t hash = fnv1a (string, length); ++ ++ /* Return a previously-existing entry. */ ++ for (struct stringtable_entry *e ++ = table->entries[hash & (table->allocated - 1)]; ++ e != NULL; e = e->next) ++ if (e->length == length && memcmp (e->string, string, length) == 0) ++ return e; ++ ++ /* Increase the size of the table if necessary. Keep utilization ++ below two thirds. */ ++ if (table->count >= (1U << 30)) ++ error (EXIT_FAILURE, 0, _("String table has too many entries")); ++ if (table->count * 3 > table->allocated * 2) ++ stringtable_rehash (table); ++ ++ /* Add the new table entry. */ ++ ++table->count; ++ struct stringtable_entry *e ++ = xmalloc (offsetof (struct stringtable_entry, string) + length + 1); ++ uint32_t index = hash & (table->allocated - 1); ++ e->next = table->entries[index]; ++ table->entries[index] = e; ++ e->length = length; ++ e->offset = 0; ++ memcpy (e->string, string, length + 1); ++ return e; ++} ++ ++/* Sort reversed strings in reverse lexicographic order. This is used ++ for tail merging. */ ++static int ++finalize_compare (const void *l, const void *r) ++{ ++ struct stringtable_entry *left = *(struct stringtable_entry **) l; ++ struct stringtable_entry *right = *(struct stringtable_entry **) r; ++ size_t to_compare; ++ if (left->length < right->length) ++ to_compare = left->length; ++ else ++ to_compare = right->length; ++ for (size_t i = 1; i <= to_compare; ++i) ++ { ++ unsigned char lch = left->string[left->length - i]; ++ unsigned char rch = right->string[right->length - i]; ++ if (lch != rch) ++ return rch - lch; ++ } ++ if (left->length == right->length) ++ return 0; ++ else if (left->length < right->length) ++ /* Longer strings should come first. */ ++ return 1; ++ else ++ return -1; ++} ++ ++void ++stringtable_finalize (struct stringtable *table, ++ struct stringtable_finalized *result) ++{ ++ if (table->count == 0) ++ { ++ result->strings = xstrdup (""); ++ result->size = 0; ++ return; ++ } ++ ++ /* Optimize the order of the strings. */ ++ struct stringtable_entry **array = xcalloc (table->count, sizeof (*array)); ++ { ++ size_t j = 0; ++ for (uint32_t i = 0; i < table->allocated; ++i) ++ for (struct stringtable_entry *e = table->entries[i]; e != NULL; ++ e = e->next) ++ { ++ array[j] = e; ++ ++j; ++ } ++ assert (j == table->count); ++ } ++ qsort (array, table->count, sizeof (*array), finalize_compare); ++ ++ /* Assign offsets, using tail merging (sharing suffixes) if possible. */ ++ array[0]->offset = 0; ++ for (uint32_t j = 1; j < table->count; ++j) ++ { ++ struct stringtable_entry *previous = array[j - 1]; ++ struct stringtable_entry *current = array[j]; ++ if (previous->length >= current->length ++ && memcmp (&previous->string[previous->length - current->length], ++ current->string, current->length) == 0) ++ current->offset = (previous->offset + previous->length ++ - current->length); ++ else if (__builtin_add_overflow (previous->offset, ++ previous->length + 1, ++ ¤t->offset)) ++ error (EXIT_FAILURE, 0, _("String table is too large")); ++ } ++ ++ /* Allocate the result string. */ ++ { ++ struct stringtable_entry *last = array[table->count - 1]; ++ if (__builtin_add_overflow (last->offset, last->length + 1, ++ &result->size)) ++ error (EXIT_FAILURE, 0, _("String table is too large")); ++ } ++ /* The strings are copied from the hash table, so the array is no ++ longer needed. */ ++ free (array); ++ result->strings = xcalloc (result->size, 1); ++ ++ /* Copy the strings. */ ++ for (uint32_t i = 0; i < table->allocated; ++i) ++ for (struct stringtable_entry *e = table->entries[i]; e != NULL; ++ e = e->next) ++ if (result->strings[e->offset] == '\0') ++ memcpy (&result->strings[e->offset], e->string, e->length + 1); ++} +diff --git a/elf/stringtable.h b/elf/stringtable.h +new file mode 100644 +index 0000000000000000..7d57d1bda9602947 +--- /dev/null ++++ b/elf/stringtable.h +@@ -0,0 +1,64 @@ ++/* String tables for ld.so.cache construction. ++ Copyright (C) 2020 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published ++ by the Free Software Foundation; version 2 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program; if not, see . */ ++ ++#ifndef _STRINGTABLE_H ++#define _STRINGTABLE_H ++ ++#include ++#include ++ ++/* An entry in the string table. Only the length and string fields are ++ expected to be used outside the string table code. */ ++struct stringtable_entry ++{ ++ struct stringtable_entry *next; /* For collision resolution. */ ++ uint32_t length; /* Length of then string. */ ++ uint32_t offset; /* From start of finalized table. */ ++ char string[]; /* Null-terminated string. */ ++}; ++ ++/* A string table. Zero-initialization produces a valid atable. */ ++struct stringtable ++{ ++ struct stringtable_entry **entries; /* Array of hash table buckets. */ ++ uint32_t count; /* Number of elements in the table. */ ++ uint32_t allocated; /* Length of the entries array. */ ++}; ++ ++/* Adds STRING to TABLE. May return the address of an existing entry. */ ++struct stringtable_entry *stringtable_add (struct stringtable *table, ++ const char *string); ++ ++/* Result of stringtable_finalize. SIZE bytes at STRINGS should be ++ written to the file. */ ++struct stringtable_finalized ++{ ++ char *strings; ++ size_t size; ++}; ++ ++/* Assigns offsets to string table entries and computes the serialized ++ form of the string table. */ ++void stringtable_finalize (struct stringtable *table, ++ struct stringtable_finalized *result); ++ ++/* Deallocate the string table (but not the TABLE pointer itself). ++ (The table can be re-used for adding more strings without ++ initialization.) */ ++void stringtable_free (struct stringtable *table); ++ ++#endif /* _STRINGTABLE_H */ +diff --git a/elf/stringtable_free.c b/elf/stringtable_free.c +new file mode 100644 +index 0000000000000000..8588a254705d4df8 +--- /dev/null ++++ b/elf/stringtable_free.c +@@ -0,0 +1,33 @@ ++/* String tables for ld.so.cache construction. Deallocation (for tests only). ++ Copyright (C) 2020 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published ++ by the Free Software Foundation; version 2 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program; if not, see . */ ++ ++#include ++#include ++ ++void ++stringtable_free (struct stringtable *table) ++{ ++ for (uint32_t i = 0; i < table->allocated; ++i) ++ for (struct stringtable_entry *e = table->entries[i]; e != NULL; ) ++ { ++ struct stringtable_entry *next = e->next; ++ free (e); ++ e = next; ++ } ++ free (table->entries); ++ *table = (struct stringtable) { 0, }; ++} +diff --git a/elf/tst-stringtable.c b/elf/tst-stringtable.c +new file mode 100644 +index 0000000000000000..3731086037567d57 +--- /dev/null ++++ b/elf/tst-stringtable.c +@@ -0,0 +1,181 @@ ++/* Unit test for ldconfig string tables. ++ Copyright (C) 2020 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published ++ by the Free Software Foundation; version 2 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program; if not, see . */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++static int ++do_test (void) ++{ ++ /* Empty string table. */ ++ { ++ struct stringtable s = { 0, }; ++ struct stringtable_finalized f; ++ stringtable_finalize (&s, &f); ++ TEST_COMPARE_STRING (f.strings, ""); ++ TEST_COMPARE (f.size, 0); ++ free (f.strings); ++ stringtable_free (&s); ++ } ++ ++ /* String table with one empty string. */ ++ { ++ struct stringtable s = { 0, }; ++ struct stringtable_entry *e = stringtable_add (&s, ""); ++ TEST_COMPARE_STRING (e->string, ""); ++ TEST_COMPARE (e->length, 0); ++ TEST_COMPARE (s.count, 1); ++ ++ struct stringtable_finalized f; ++ stringtable_finalize (&s, &f); ++ TEST_COMPARE (e->offset, 0); ++ TEST_COMPARE_STRING (f.strings, ""); ++ TEST_COMPARE (f.size, 1); ++ free (f.strings); ++ stringtable_free (&s); ++ } ++ ++ /* String table with one non-empty string. */ ++ { ++ struct stringtable s = { 0, }; ++ struct stringtable_entry *e = stringtable_add (&s, "name"); ++ TEST_COMPARE_STRING (e->string, "name"); ++ TEST_COMPARE (e->length, 4); ++ TEST_COMPARE (s.count, 1); ++ ++ struct stringtable_finalized f; ++ stringtable_finalize (&s, &f); ++ TEST_COMPARE (e->offset, 0); ++ TEST_COMPARE_STRING (f.strings, "name"); ++ TEST_COMPARE (f.size, 5); ++ free (f.strings); ++ stringtable_free (&s); ++ } ++ ++ /* Two strings, one is a prefix of the other. Tail-merging can only ++ happen in one way in this case. */ ++ { ++ struct stringtable s = { 0, }; ++ struct stringtable_entry *suffix = stringtable_add (&s, "suffix"); ++ TEST_COMPARE_STRING (suffix->string, "suffix"); ++ TEST_COMPARE (suffix->length, 6); ++ TEST_COMPARE (s.count, 1); ++ ++ struct stringtable_entry *prefix ++ = stringtable_add (&s, "prefix-suffix"); ++ TEST_COMPARE_STRING (prefix->string, "prefix-suffix"); ++ TEST_COMPARE (prefix->length, strlen ("prefix-suffix")); ++ TEST_COMPARE (s.count, 2); ++ ++ struct stringtable_finalized f; ++ stringtable_finalize (&s, &f); ++ TEST_COMPARE (prefix->offset, 0); ++ TEST_COMPARE (suffix->offset, strlen ("prefix-")); ++ TEST_COMPARE_STRING (f.strings, "prefix-suffix"); ++ TEST_COMPARE (f.size, sizeof ("prefix-suffix")); ++ free (f.strings); ++ stringtable_free (&s); ++ } ++ ++ /* String table with various shared prefixes. Triggers hash ++ resizing. */ ++ { ++ enum { count = 1500 }; ++ char *strings[2 * count]; ++ struct stringtable_entry *entries[2 * count]; ++ struct stringtable s = { 0, }; ++ for (int i = 0; i < count; ++i) ++ { ++ strings[i] = xasprintf ("%d", i); ++ entries[i] = stringtable_add (&s, strings[i]); ++ TEST_COMPARE (entries[i]->length, strlen (strings[i])); ++ TEST_COMPARE_STRING (entries[i]->string, strings[i]); ++ strings[i + count] = xasprintf ("prefix/%d", i); ++ entries[i + count] = stringtable_add (&s, strings[i + count]); ++ TEST_COMPARE (entries[i + count]->length, strlen (strings[i + count])); ++ TEST_COMPARE_STRING (entries[i + count]->string, strings[i + count]); ++ } ++ ++ struct stringtable_finalized f; ++ stringtable_finalize (&s, &f); ++ ++ for (int i = 0; i < 2 * count; ++i) ++ { ++ TEST_COMPARE (entries[i]->length, strlen (strings[i])); ++ TEST_COMPARE_STRING (entries[i]->string, strings[i]); ++ TEST_COMPARE_STRING (f.strings + entries[i]->offset, strings[i]); ++ free (strings[i]); ++ } ++ ++ free (f.strings); ++ stringtable_free (&s); ++ } ++ ++ /* Verify that maximum tail merging happens. */ ++ { ++ struct stringtable s = { 0, }; ++ const char *strings[] = { ++ "", ++ "a", ++ "b", ++ "aa", ++ "aaa", ++ "aa", ++ "bb", ++ "b", ++ "a", ++ "ba", ++ "baa", ++ }; ++ struct stringtable_entry *entries[array_length (strings)]; ++ for (int i = 0; i < array_length (strings); ++i) ++ entries[i] = stringtable_add (&s, strings[i]); ++ for (int i = 0; i < array_length (strings); ++i) ++ TEST_COMPARE_STRING (entries[i]->string, strings[i]); ++ ++ struct stringtable_finalized f; ++ stringtable_finalize (&s, &f); ++ ++ /* There are only four different strings, "aaa", "ba", "baa", ++ "bb". The rest is shared in an unspecified fashion. */ ++ TEST_COMPARE (f.size, 4 + 3 + 4 + 3); ++ ++ for (int i = 0; i < array_length (strings); ++i) ++ { ++ TEST_COMPARE_STRING (entries[i]->string, strings[i]); ++ TEST_COMPARE_STRING (f.strings + entries[i]->offset, strings[i]); ++ } ++ ++ free (f.strings); ++ stringtable_free (&s); ++ } ++ ++ return 0; ++} ++ ++#include ++ ++/* Re-compile the string table implementation here. It is not ++ possible to link against the actual build because it was built for ++ use in ldconfig. */ ++#define _(arg) arg ++#include "stringtable.c" ++#include "stringtable_free.c" diff --git a/SOURCES/glibc-rh1817513-117.patch b/SOURCES/glibc-rh1817513-117.patch new file mode 100644 index 0000000..65516f4 --- /dev/null +++ b/SOURCES/glibc-rh1817513-117.patch @@ -0,0 +1,209 @@ +commit 73b6e50a22dea9ae6144beaaa675d2ac62c281ca +Author: Florian Weimer +Date: Fri Dec 4 09:13:43 2020 +0100 + + elf: Implement tail merging of strings in ldconfig + + This simplifies the string table construction in elf/cache.c + because there is no more need to keep track of offsets explicitly; + the string table implementation does this internally. + + This change slightly reduces the size of the cache on disk. The + file format does not change as a result. The strings are + null-terminated, without explicit length, so tail merging is + transparent to readers. + + Reviewed-by: Adhemerval Zanella + +diff --git a/elf/Makefile b/elf/Makefile +index abb3e9d1179ef5cd..a3e802a9a99b759c 100644 +--- a/elf/Makefile ++++ b/elf/Makefile +@@ -112,7 +112,8 @@ others-static += ldconfig + others += ldconfig + install-rootsbin += ldconfig + +-ldconfig-modules := cache readlib xmalloc xstrdup chroot_canon static-stubs ++ldconfig-modules := cache readlib xmalloc xstrdup chroot_canon static-stubs \ ++ stringtable + extra-objs += $(ldconfig-modules:=.o) + others-extras = $(ldconfig-modules) + endif +diff --git a/elf/cache.c b/elf/cache.c +index 5a8f1ad70cc3fead..f773cacacf26db1c 100644 +--- a/elf/cache.c ++++ b/elf/cache.c +@@ -35,11 +35,15 @@ + #include + #include + #include ++#include ++ ++/* Used to store library names, paths, and other strings. */ ++static struct stringtable strings; + + struct cache_entry + { +- char *lib; /* Library name. */ +- char *path; /* Path to find library. */ ++ struct stringtable_entry *lib; /* Library name. */ ++ struct stringtable_entry *path; /* Path to find library. */ + int flags; /* Flags to indicate kind of library. */ + unsigned int osversion; /* Required OS version. */ + uint64_t hwcap; /* Important hardware capabilities. */ +@@ -300,7 +304,7 @@ static int + compare (const struct cache_entry *e1, const struct cache_entry *e2) + { + /* We need to swap entries here to get the correct sort order. */ +- int res = _dl_cache_libcmp (e2->lib, e1->lib); ++ int res = _dl_cache_libcmp (e2->lib->string, e1->lib->string); + if (res == 0) + { + if (e1->flags < e2->flags) +@@ -369,26 +373,24 @@ save_cache (const char *cache_name) + { + /* The cache entries are sorted already, save them in this order. */ + +- /* Count the length of all strings. */ +- /* The old format doesn't contain hwcap entries and doesn't contain +- libraries in subdirectories with hwcaps entries. Count therefore +- also all entries with hwcap == 0. */ +- size_t total_strlen = 0; + struct cache_entry *entry; + /* Number of cache entries. */ + int cache_entry_count = 0; +- /* Number of normal cache entries. */ ++ /* The old format doesn't contain hwcap entries and doesn't contain ++ libraries in subdirectories with hwcaps entries. Count therefore ++ also all entries with hwcap == 0. */ + int cache_entry_old_count = 0; + + for (entry = entries; entry != NULL; entry = entry->next) + { +- /* Account the final NULs. */ +- total_strlen += strlen (entry->lib) + strlen (entry->path) + 2; + ++cache_entry_count; + if (entry->hwcap == 0) + ++cache_entry_old_count; + } + ++ struct stringtable_finalized strings_finalized; ++ stringtable_finalize (&strings, &strings_finalized); ++ + /* Create the on disk cache structure. */ + struct cache_file *file_entries = NULL; + size_t file_entries_size = 0; +@@ -432,7 +434,7 @@ save_cache (const char *cache_name) + sizeof CACHE_VERSION - 1); + + file_entries_new->nlibs = cache_entry_count; +- file_entries_new->len_strings = total_strlen; ++ file_entries_new->len_strings = strings_finalized.size; + file_entries_new->flags = cache_file_new_flags_endian_current; + } + +@@ -449,20 +451,20 @@ save_cache (const char *cache_name) + str_offset = 0; + + /* An array for all strings. */ +- char *strings = xmalloc (total_strlen); +- char *str = strings; + int idx_old; + int idx_new; + + for (idx_old = 0, idx_new = 0, entry = entries; entry != NULL; + entry = entry->next, ++idx_new) + { +- /* First the library. */ + if (opt_format != opt_format_new && entry->hwcap == 0) + { + file_entries->libs[idx_old].flags = entry->flags; + /* XXX: Actually we can optimize here and remove duplicates. */ + file_entries->libs[idx_old].key = str_offset + pad; ++ file_entries->libs[idx_new].key = str_offset + entry->lib->offset; ++ file_entries->libs[idx_new].value ++ = str_offset + entry->path->offset; + } + if (opt_format != opt_format_old) + { +@@ -473,20 +475,12 @@ save_cache (const char *cache_name) + file_entries_new->libs[idx_new].flags = entry->flags; + file_entries_new->libs[idx_new].osversion = entry->osversion; + file_entries_new->libs[idx_new].hwcap = entry->hwcap; +- file_entries_new->libs[idx_new].key = str_offset; ++ file_entries_new->libs[idx_new].key ++ = str_offset + entry->lib->offset; ++ file_entries_new->libs[idx_new].value ++ = str_offset + entry->path->offset; + } + +- size_t len = strlen (entry->lib) + 1; +- str = mempcpy (str, entry->lib, len); +- str_offset += len; +- /* Then the path. */ +- if (opt_format != opt_format_new && entry->hwcap == 0) +- file_entries->libs[idx_old].value = str_offset + pad; +- if (opt_format != opt_format_old) +- file_entries_new->libs[idx_new].value = str_offset; +- len = strlen (entry->path) + 1; +- str = mempcpy (str, entry->path, len); +- str_offset += len; + /* Ignore entries with hwcap for old format. */ + if (entry->hwcap == 0) + ++idx_old; +@@ -511,7 +505,7 @@ save_cache (const char *cache_name) + extension_offset += pad; + extension_offset += file_entries_new_size; + } +- extension_offset += total_strlen; ++ extension_offset += strings_finalized.size; + extension_offset = roundup (extension_offset, 4); /* Provide alignment. */ + if (opt_format != opt_format_old) + file_entries_new->extension_offset = extension_offset; +@@ -551,7 +545,8 @@ save_cache (const char *cache_name) + error (EXIT_FAILURE, errno, _("Writing of cache data failed")); + } + +- if (write (fd, strings, total_strlen) != (ssize_t) total_strlen) ++ if (write (fd, strings_finalized.strings, strings_finalized.size) ++ != (ssize_t) strings_finalized.size) + error (EXIT_FAILURE, errno, _("Writing of cache data failed")); + + if (opt_format != opt_format_old) +@@ -580,7 +575,7 @@ save_cache (const char *cache_name) + /* Free all allocated memory. */ + free (file_entries_new); + free (file_entries); +- free (strings); ++ free (strings_finalized.strings); + + while (entries) + { +@@ -596,14 +591,19 @@ void + add_to_cache (const char *path, const char *lib, int flags, + unsigned int osversion, uint64_t hwcap) + { +- size_t liblen = strlen (lib) + 1; +- size_t len = liblen + strlen (path) + 1; +- struct cache_entry *new_entry +- = xmalloc (sizeof (struct cache_entry) + liblen + len); +- +- new_entry->lib = memcpy ((char *) (new_entry + 1), lib, liblen); +- new_entry->path = new_entry->lib + liblen; +- snprintf (new_entry->path, len, "%s/%s", path, lib); ++ struct cache_entry *new_entry = xmalloc (sizeof (*new_entry)); ++ ++ struct stringtable_entry *path_interned; ++ { ++ char *p; ++ if (asprintf (&p, "%s/%s", path, lib) < 0) ++ error (EXIT_FAILURE, errno, _("Could not create library path")); ++ path_interned = stringtable_add (&strings, p); ++ free (p); ++ } ++ ++ new_entry->lib = stringtable_add (&strings, lib); ++ new_entry->path = path_interned; + new_entry->flags = flags; + new_entry->osversion = osversion; + new_entry->hwcap = hwcap; diff --git a/SOURCES/glibc-rh1817513-118.patch b/SOURCES/glibc-rh1817513-118.patch new file mode 100644 index 0000000..92620f5 --- /dev/null +++ b/SOURCES/glibc-rh1817513-118.patch @@ -0,0 +1,778 @@ +commit b44ac4f4c7a8bbe5eaa2701aa9452eaf2c96e1dd +Author: Florian Weimer +Date: Fri Dec 4 09:13:43 2020 +0100 + + elf: Process glibc-hwcaps subdirectories in ldconfig + + Libraries from these subdirectories are added to the cache + with a special hwcap bit DL_CACHE_HWCAP_EXTENSION, so that + they are ignored by older dynamic loaders. + + Reviewed-by: Adhemerval Zanella + +diff --git a/elf/cache.c b/elf/cache.c +index f773cacacf26db1c..dde3d7fefa4105f9 100644 +--- a/elf/cache.c ++++ b/elf/cache.c +@@ -40,6 +40,105 @@ + /* Used to store library names, paths, and other strings. */ + static struct stringtable strings; + ++/* Keeping track of "glibc-hwcaps" subdirectories. During cache ++ construction, a linear search by name is performed to deduplicate ++ entries. */ ++struct glibc_hwcaps_subdirectory ++{ ++ struct glibc_hwcaps_subdirectory *next; ++ ++ /* Interned string with the subdirectory name. */ ++ struct stringtable_entry *name; ++ ++ /* Array index in the cache_extension_tag_glibc_hwcaps section in ++ the stored cached file. This is computed after all the ++ subdirectories have been processed, so that subdirectory names in ++ the extension section can be sorted. */ ++ uint32_t section_index; ++ ++ /* True if the subdirectory is actually used for anything. */ ++ bool used; ++}; ++ ++const char * ++glibc_hwcaps_subdirectory_name (const struct glibc_hwcaps_subdirectory *dir) ++{ ++ return dir->name->string; ++} ++ ++/* Linked list of known hwcaps subdirecty names. */ ++static struct glibc_hwcaps_subdirectory *hwcaps; ++ ++struct glibc_hwcaps_subdirectory * ++new_glibc_hwcaps_subdirectory (const char *name) ++{ ++ struct stringtable_entry *name_interned = stringtable_add (&strings, name); ++ for (struct glibc_hwcaps_subdirectory *p = hwcaps; p != NULL; p = p->next) ++ if (p->name == name_interned) ++ return p; ++ struct glibc_hwcaps_subdirectory *p = xmalloc (sizeof (*p)); ++ p->next = hwcaps; ++ p->name = name_interned; ++ p->section_index = 0; ++ p->used = false; ++ hwcaps = p; ++ return p; ++} ++ ++/* Helper for sorting struct glibc_hwcaps_subdirectory elements by ++ name. */ ++static int ++assign_glibc_hwcaps_indices_compare (const void *l, const void *r) ++{ ++ const struct glibc_hwcaps_subdirectory *left ++ = *(struct glibc_hwcaps_subdirectory **)l; ++ const struct glibc_hwcaps_subdirectory *right ++ = *(struct glibc_hwcaps_subdirectory **)r; ++ return strcmp (glibc_hwcaps_subdirectory_name (left), ++ glibc_hwcaps_subdirectory_name (right)); ++} ++ ++/* Count the number of hwcaps subdirectories which are actually ++ used. */ ++static size_t ++glibc_hwcaps_count (void) ++{ ++ size_t count = 0; ++ for (struct glibc_hwcaps_subdirectory *p = hwcaps; p != NULL; p = p->next) ++ if (p->used) ++ ++count; ++ return count; ++} ++ ++/* Compute the section_index fields for all */ ++static void ++assign_glibc_hwcaps_indices (void) ++{ ++ /* Convert the linked list into an array, so that we can use qsort. ++ Only copy the subdirectories which are actually used. */ ++ size_t count = glibc_hwcaps_count (); ++ struct glibc_hwcaps_subdirectory **array ++ = xmalloc (sizeof (*array) * count); ++ { ++ size_t i = 0; ++ for (struct glibc_hwcaps_subdirectory *p = hwcaps; p != NULL; p = p->next) ++ if (p->used) ++ { ++ array[i] = p; ++ ++i; ++ } ++ assert (i == count); ++ } ++ ++ qsort (array, count, sizeof (*array), assign_glibc_hwcaps_indices_compare); ++ ++ /* Assign the array indices. */ ++ for (size_t i = 0; i < count; ++i) ++ array[i]->section_index = i; ++ ++ free (array); ++} ++ + struct cache_entry + { + struct stringtable_entry *lib; /* Library name. */ +@@ -48,6 +147,10 @@ struct cache_entry + unsigned int osversion; /* Required OS version. */ + uint64_t hwcap; /* Important hardware capabilities. */ + int bits_hwcap; /* Number of bits set in hwcap. */ ++ ++ /* glibc-hwcaps subdirectory. If not NULL, hwcap must be zero. */ ++ struct glibc_hwcaps_subdirectory *hwcaps; ++ + struct cache_entry *next; /* Next entry in list. */ + }; + +@@ -60,7 +163,7 @@ static const char *flag_descr[] = + /* Print a single entry. */ + static void + print_entry (const char *lib, int flag, unsigned int osversion, +- uint64_t hwcap, const char *key) ++ uint64_t hwcap, const char *hwcap_string, const char *key) + { + printf ("\t%s (", lib); + switch (flag & FLAG_TYPE_MASK) +@@ -132,7 +235,9 @@ print_entry (const char *lib, int flag, unsigned int osversion, + printf (",%d", flag & FLAG_REQUIRED_MASK); + break; + } +- if (hwcap != 0) ++ if (hwcap_string != NULL) ++ printf (", hwcap: \"%s\"", hwcap_string); ++ else if (hwcap != 0) + printf (", hwcap: %#.16" PRIx64, hwcap); + if (osversion != 0) + { +@@ -158,6 +263,29 @@ print_entry (const char *lib, int flag, unsigned int osversion, + printf (") => %s\n", key); + } + ++/* Returns the string with the name of the glibcs-hwcaps subdirectory ++ associated with ENTRY->hwcap. file_base must be the base address ++ for string table indices. */ ++static const char * ++glibc_hwcaps_string (struct cache_extension_all_loaded *ext, ++ const void *file_base, size_t file_size, ++ struct file_entry_new *entry) ++{ ++ const uint32_t *hwcaps_array ++ = ext->sections[cache_extension_tag_glibc_hwcaps].base; ++ if (dl_cache_hwcap_extension (entry) && hwcaps_array != NULL) ++ { ++ uint32_t index = (uint32_t) entry->hwcap; ++ if (index < ext->sections[cache_extension_tag_glibc_hwcaps].size / 4) ++ { ++ uint32_t string_table_index = hwcaps_array[index]; ++ if (string_table_index < file_size) ++ return file_base + string_table_index; ++ } ++ } ++ return NULL; ++} ++ + /* Print an error and exit if the new-file cache is internally + inconsistent. */ + static void +@@ -167,9 +295,7 @@ check_new_cache (struct cache_file_new *cache) + error (EXIT_FAILURE, 0, _("Cache file has wrong endianness.\n")); + } + +-/* Print the extension information at the cache at start address +- FILE_BASE, of length FILE_SIZE bytes. The new-format cache header +- is at CACHE, and the file name for diagnostics is CACHE_NAME. */ ++/* Print the extension information in *EXT. */ + static void + print_extensions (struct cache_extension_all_loaded *ext) + { +@@ -266,7 +392,7 @@ print_cache (const char *cache_name) + /* Print everything. */ + for (unsigned int i = 0; i < cache->nlibs; i++) + print_entry (cache_data + cache->libs[i].key, +- cache->libs[i].flags, 0, 0, ++ cache->libs[i].flags, 0, 0, NULL, + cache_data + cache->libs[i].value); + } + else if (format == 1) +@@ -281,11 +407,16 @@ print_cache (const char *cache_name) + + /* Print everything. */ + for (unsigned int i = 0; i < cache_new->nlibs; i++) +- print_entry (cache_data + cache_new->libs[i].key, +- cache_new->libs[i].flags, +- cache_new->libs[i].osversion, +- cache_new->libs[i].hwcap, +- cache_data + cache_new->libs[i].value); ++ { ++ const char *hwcaps_string ++ = glibc_hwcaps_string (&ext, cache, cache_size, ++ &cache_new->libs[i]); ++ print_entry (cache_data + cache_new->libs[i].key, ++ cache_new->libs[i].flags, ++ cache_new->libs[i].osversion, ++ cache_new->libs[i].hwcap, hwcaps_string, ++ cache_data + cache_new->libs[i].value); ++ } + print_extensions (&ext); + } + /* Cleanup. */ +@@ -311,8 +442,23 @@ compare (const struct cache_entry *e1, const struct cache_entry *e2) + return 1; + else if (e1->flags > e2->flags) + return -1; ++ /* Keep the glibc-hwcaps extension entries before the regular ++ entries, and sort them by their names. search_cache in ++ dl-cache.c stops searching once the first non-extension entry ++ is found, so the extension entries need to come first. */ ++ else if (e1->hwcaps != NULL && e2->hwcaps == NULL) ++ return -1; ++ else if (e1->hwcaps == NULL && e2->hwcaps != NULL) ++ return 1; ++ else if (e1->hwcaps != NULL && e2->hwcaps != NULL) ++ { ++ res = strcmp (glibc_hwcaps_subdirectory_name (e1->hwcaps), ++ glibc_hwcaps_subdirectory_name (e2->hwcaps)); ++ if (res != 0) ++ return res; ++ } + /* Sort by most specific hwcap. */ +- else if (e2->bits_hwcap > e1->bits_hwcap) ++ if (e2->bits_hwcap > e1->bits_hwcap) + return 1; + else if (e2->bits_hwcap < e1->bits_hwcap) + return -1; +@@ -337,30 +483,65 @@ enum + * sizeof (struct cache_extension_section))) + }; + +-/* Write the cache extensions to FD. The extension directory is +- assumed to be located at CACHE_EXTENSION_OFFSET. */ ++/* Write the cache extensions to FD. The string table is shifted by ++ STRING_TABLE_OFFSET. The extension directory is assumed to be ++ located at CACHE_EXTENSION_OFFSET. assign_glibc_hwcaps_indices ++ must have been called. */ + static void +-write_extensions (int fd, uint32_t cache_extension_offset) ++write_extensions (int fd, uint32_t str_offset, ++ uint32_t cache_extension_offset) + { + assert ((cache_extension_offset % 4) == 0); + ++ /* The length and contents of the glibc-hwcaps section. */ ++ uint32_t hwcaps_count = glibc_hwcaps_count (); ++ uint32_t hwcaps_offset = cache_extension_offset + cache_extension_size; ++ uint32_t hwcaps_size = hwcaps_count * sizeof (uint32_t); ++ uint32_t *hwcaps_array = xmalloc (hwcaps_size); ++ for (struct glibc_hwcaps_subdirectory *p = hwcaps; p != NULL; p = p->next) ++ if (p->used) ++ hwcaps_array[p->section_index] = str_offset + p->name->offset; ++ ++ /* This is the offset of the generator string. */ ++ uint32_t generator_offset = hwcaps_offset; ++ if (hwcaps_count == 0) ++ /* There is no section for the hwcaps subdirectories. */ ++ generator_offset -= sizeof (struct cache_extension_section); ++ else ++ /* The string table indices for the hwcaps subdirectories shift ++ the generator string backwards. */ ++ generator_offset += hwcaps_size; ++ + struct cache_extension *ext = xmalloc (cache_extension_size); + ext->magic = cache_extension_magic; +- ext->count = cache_extension_count; + +- for (int i = 0; i < cache_extension_count; ++i) +- { +- ext->sections[i].tag = i; +- ext->sections[i].flags = 0; +- } ++ /* Extension index current being filled. */ ++ size_t xid = 0; + + const char *generator + = "ldconfig " PKGVERSION RELEASE " release version " VERSION; +- ext->sections[cache_extension_tag_generator].offset +- = cache_extension_offset + cache_extension_size; +- ext->sections[cache_extension_tag_generator].size = strlen (generator); ++ ext->sections[xid].tag = cache_extension_tag_generator; ++ ext->sections[xid].flags = 0; ++ ext->sections[xid].offset = generator_offset; ++ ext->sections[xid].size = strlen (generator); ++ ++ if (hwcaps_count > 0) ++ { ++ ++xid; ++ ext->sections[xid].tag = cache_extension_tag_glibc_hwcaps; ++ ext->sections[xid].flags = 0; ++ ext->sections[xid].offset = hwcaps_offset; ++ ext->sections[xid].size = hwcaps_size; ++ } ++ ++ ++xid; ++ ext->count = xid; ++ assert (xid <= cache_extension_count); + +- if (write (fd, ext, cache_extension_size) != cache_extension_size ++ size_t ext_size = (offsetof (struct cache_extension, sections) ++ + xid * sizeof (struct cache_extension_section)); ++ if (write (fd, ext, ext_size) != ext_size ++ || write (fd, hwcaps_array, hwcaps_size) != hwcaps_size + || write (fd, generator, strlen (generator)) != strlen (generator)) + error (EXIT_FAILURE, errno, _("Writing of cache extension data failed")); + +@@ -373,6 +554,8 @@ save_cache (const char *cache_name) + { + /* The cache entries are sorted already, save them in this order. */ + ++ assign_glibc_hwcaps_indices (); ++ + struct cache_entry *entry; + /* Number of cache entries. */ + int cache_entry_count = 0; +@@ -474,7 +657,11 @@ save_cache (const char *cache_name) + struct. */ + file_entries_new->libs[idx_new].flags = entry->flags; + file_entries_new->libs[idx_new].osversion = entry->osversion; +- file_entries_new->libs[idx_new].hwcap = entry->hwcap; ++ if (entry->hwcaps == NULL) ++ file_entries_new->libs[idx_new].hwcap = entry->hwcap; ++ else ++ file_entries_new->libs[idx_new].hwcap ++ = DL_CACHE_HWCAP_EXTENSION | entry->hwcaps->section_index; + file_entries_new->libs[idx_new].key + = str_offset + entry->lib->offset; + file_entries_new->libs[idx_new].value +@@ -554,7 +741,7 @@ save_cache (const char *cache_name) + /* Align file position to 4. */ + off64_t old_offset = lseek64 (fd, extension_offset, SEEK_SET); + assert ((unsigned long long int) (extension_offset - old_offset) < 4); +- write_extensions (fd, extension_offset); ++ write_extensions (fd, str_offset, extension_offset); + } + + /* Make sure user can always read cache file */ +@@ -588,27 +775,35 @@ save_cache (const char *cache_name) + + /* Add one library to the cache. */ + void +-add_to_cache (const char *path, const char *lib, int flags, +- unsigned int osversion, uint64_t hwcap) ++add_to_cache (const char *path, const char *filename, const char *soname, ++ int flags, unsigned int osversion, uint64_t hwcap, ++ struct glibc_hwcaps_subdirectory *hwcaps) + { + struct cache_entry *new_entry = xmalloc (sizeof (*new_entry)); + + struct stringtable_entry *path_interned; + { + char *p; +- if (asprintf (&p, "%s/%s", path, lib) < 0) ++ if (asprintf (&p, "%s/%s", path, filename) < 0) + error (EXIT_FAILURE, errno, _("Could not create library path")); + path_interned = stringtable_add (&strings, p); + free (p); + } + +- new_entry->lib = stringtable_add (&strings, lib); ++ new_entry->lib = stringtable_add (&strings, soname); + new_entry->path = path_interned; + new_entry->flags = flags; + new_entry->osversion = osversion; + new_entry->hwcap = hwcap; ++ new_entry->hwcaps = hwcaps; + new_entry->bits_hwcap = 0; + ++ if (hwcaps != NULL) ++ { ++ assert (hwcap == 0); ++ hwcaps->used = true; ++ } ++ + /* Count the number of bits set in the masked value. */ + for (size_t i = 0; + (~((1ULL << i) - 1) & hwcap) != 0 && i < 8 * sizeof (hwcap); ++i) +diff --git a/elf/ldconfig.c b/elf/ldconfig.c +index 0fa5aef83f9cd86c..8c66d7e5426d8cc4 100644 +--- a/elf/ldconfig.c ++++ b/elf/ldconfig.c +@@ -16,6 +16,7 @@ + along with this program; if not, see . */ + + #define PROCINFO_CLASS static ++#include + #include + #include + #include +@@ -41,6 +42,7 @@ + + #include + #include ++#include + + #include + +@@ -85,6 +87,10 @@ struct dir_entry + dev_t dev; + const char *from_file; + int from_line; ++ ++ /* Non-NULL for subdirectories under a glibc-hwcaps subdirectory. */ ++ struct glibc_hwcaps_subdirectory *hwcaps; ++ + struct dir_entry *next; + }; + +@@ -338,17 +344,20 @@ new_sub_entry (const struct dir_entry *entry, const char *path, + new_entry->from_line = entry->from_line; + new_entry->path = xstrdup (path); + new_entry->flag = entry->flag; ++ new_entry->hwcaps = NULL; + new_entry->next = NULL; + new_entry->ino = st->st_ino; + new_entry->dev = st->st_dev; + return new_entry; + } + +-/* Add a single directory entry. */ +-static void ++/* Add a single directory entry. Return true if the directory is ++ actually added (because it is not a duplicate). */ ++static bool + add_single_dir (struct dir_entry *entry, int verbose) + { + struct dir_entry *ptr, *prev; ++ bool added = true; + + ptr = dir_entries; + prev = ptr; +@@ -368,6 +377,7 @@ add_single_dir (struct dir_entry *entry, int verbose) + ptr->flag = entry->flag; + free (entry->path); + free (entry); ++ added = false; + break; + } + prev = ptr; +@@ -378,6 +388,73 @@ add_single_dir (struct dir_entry *entry, int verbose) + dir_entries = entry; + else if (ptr == NULL) + prev->next = entry; ++ return added; ++} ++ ++/* Check if PATH contains a "glibc-hwcaps" subdirectory. If so, queue ++ its subdirectories for glibc-hwcaps processing. */ ++static void ++add_glibc_hwcaps_subdirectories (struct dir_entry *entry, const char *path) ++{ ++ /* glibc-hwcaps subdirectories do not nest. */ ++ assert (entry->hwcaps == NULL); ++ ++ char *glibc_hwcaps; ++ if (asprintf (&glibc_hwcaps, "%s/" GLIBC_HWCAPS_SUBDIRECTORY, path) < 0) ++ error (EXIT_FAILURE, errno, _("Could not form glibc-hwcaps path")); ++ ++ DIR *dir = opendir (glibc_hwcaps); ++ if (dir != NULL) ++ { ++ while (true) ++ { ++ errno = 0; ++ struct dirent64 *e = readdir64 (dir); ++ if (e == NULL) ++ { ++ if (errno == 0) ++ break; ++ else ++ error (EXIT_FAILURE, errno, _("Listing directory %s"), path); ++ } ++ ++ /* Ignore hidden subdirectories, including "." and "..", and ++ regular files. File names containing a ':' cannot be ++ looked up by the dynamic loader, so skip those as ++ well. */ ++ if (e->d_name[0] == '.' || e->d_type == DT_REG ++ || strchr (e->d_name, ':') != NULL) ++ continue; ++ ++ /* See if this entry eventually resolves to a directory. */ ++ struct stat64 st; ++ if (fstatat64 (dirfd (dir), e->d_name, &st, 0) < 0) ++ /* Ignore unreadable entries. */ ++ continue; ++ ++ if (S_ISDIR (st.st_mode)) ++ { ++ /* This is a directory, so it needs to be scanned for ++ libraries, associated with the hwcaps implied by the ++ subdirectory name. */ ++ char *new_path; ++ if (asprintf (&new_path, "%s/" GLIBC_HWCAPS_SUBDIRECTORY "/%s", ++ /* Use non-canonicalized path here. */ ++ entry->path, e->d_name) < 0) ++ error (EXIT_FAILURE, errno, ++ _("Could not form glibc-hwcaps path")); ++ struct dir_entry *new_entry = new_sub_entry (entry, new_path, ++ &st); ++ free (new_path); ++ new_entry->hwcaps = new_glibc_hwcaps_subdirectory (e->d_name); ++ add_single_dir (new_entry, 0); ++ } ++ } ++ ++ closedir (dir); ++ } ++ ++ free (glibc_hwcaps); + } + + /* Add one directory to the list of directories to process. */ +@@ -386,6 +463,7 @@ add_dir_1 (const char *line, const char *from_file, int from_line) + { + unsigned int i; + struct dir_entry *entry = xmalloc (sizeof (struct dir_entry)); ++ entry->hwcaps = NULL; + entry->next = NULL; + + entry->from_file = strdup (from_file); +@@ -443,7 +521,9 @@ add_dir_1 (const char *line, const char *from_file, int from_line) + entry->ino = stat_buf.st_ino; + entry->dev = stat_buf.st_dev; + +- add_single_dir (entry, 1); ++ if (add_single_dir (entry, 1)) ++ /* Add glibc-hwcaps subdirectories if present. */ ++ add_glibc_hwcaps_subdirectories (entry, path); + } + + if (opt_chroot) +@@ -695,15 +775,27 @@ struct dlib_entry + static void + search_dir (const struct dir_entry *entry) + { +- uint64_t hwcap = path_hwcap (entry->path); +- if (opt_verbose) ++ uint64_t hwcap; ++ if (entry->hwcaps == NULL) + { +- if (hwcap != 0) +- printf ("%s: (hwcap: %#.16" PRIx64 ")", entry->path, hwcap); +- else +- printf ("%s:", entry->path); +- printf (_(" (from %s:%d)\n"), entry->from_file, entry->from_line); ++ hwcap = path_hwcap (entry->path); ++ if (opt_verbose) ++ { ++ if (hwcap != 0) ++ printf ("%s: (hwcap: %#.16" PRIx64 ")", entry->path, hwcap); ++ else ++ printf ("%s:", entry->path); ++ } + } ++ else ++ { ++ hwcap = 0; ++ if (opt_verbose) ++ printf ("%s: (hwcap: \"%s\")", entry->path, ++ glibc_hwcaps_subdirectory_name (entry->hwcaps)); ++ } ++ if (opt_verbose) ++ printf (_(" (from %s:%d)\n"), entry->from_file, entry->from_line); + + char *dir_name; + char *real_file_name; +@@ -745,13 +837,15 @@ search_dir (const struct dir_entry *entry) + && direntry->d_type != DT_DIR) + continue; + /* Does this file look like a shared library or is it a hwcap +- subdirectory? The dynamic linker is also considered as ++ subdirectory (if not already processing a glibc-hwcaps ++ subdirectory)? The dynamic linker is also considered as + shared library. */ + if (((strncmp (direntry->d_name, "lib", 3) != 0 + && strncmp (direntry->d_name, "ld-", 3) != 0) + || strstr (direntry->d_name, ".so") == NULL) + && (direntry->d_type == DT_REG +- || !is_hwcap_platform (direntry->d_name))) ++ || (entry->hwcaps == NULL ++ && !is_hwcap_platform (direntry->d_name)))) + continue; + + size_t len = strlen (direntry->d_name); +@@ -799,7 +893,7 @@ search_dir (const struct dir_entry *entry) + } + + struct stat64 stat_buf; +- int is_dir; ++ bool is_dir; + int is_link = S_ISLNK (lstat_buf.st_mode); + if (is_link) + { +@@ -837,7 +931,10 @@ search_dir (const struct dir_entry *entry) + else + is_dir = S_ISDIR (lstat_buf.st_mode); + +- if (is_dir && is_hwcap_platform (direntry->d_name)) ++ /* No descending into subdirectories if this directory is a ++ glibc-hwcaps subdirectory (which are not recursive). */ ++ if (entry->hwcaps == NULL ++ && is_dir && is_hwcap_platform (direntry->d_name)) + { + if (!is_link + && direntry->d_type != DT_UNKNOWN +@@ -1028,13 +1125,31 @@ search_dir (const struct dir_entry *entry) + struct dlib_entry *dlib_ptr; + for (dlib_ptr = dlibs; dlib_ptr != NULL; dlib_ptr = dlib_ptr->next) + { +- /* Don't create links to links. */ +- if (dlib_ptr->is_link == 0) +- create_links (dir_name, entry->path, dlib_ptr->name, +- dlib_ptr->soname); ++ /* The cached file name is the soname for non-glibc-hwcaps ++ subdirectories (relying on symbolic links; this helps with ++ library updates that change the file name), and the actual ++ file for glibc-hwcaps subdirectories. */ ++ const char *filename; ++ if (entry->hwcaps == NULL) ++ { ++ /* Don't create links to links. */ ++ if (dlib_ptr->is_link == 0) ++ create_links (dir_name, entry->path, dlib_ptr->name, ++ dlib_ptr->soname); ++ filename = dlib_ptr->soname; ++ } ++ else ++ { ++ /* Do not create links in glibc-hwcaps subdirectories, but ++ still log the cache addition. */ ++ if (opt_verbose) ++ printf ("\t%s -> %s\n", dlib_ptr->soname, dlib_ptr->name); ++ filename = dlib_ptr->name; ++ } + if (opt_build_cache) +- add_to_cache (entry->path, dlib_ptr->soname, dlib_ptr->flag, +- dlib_ptr->osversion, hwcap); ++ add_to_cache (entry->path, filename, dlib_ptr->soname, ++ dlib_ptr->flag, dlib_ptr->osversion, ++ hwcap, entry->hwcaps); + } + + /* Free all resources. */ +diff --git a/sysdeps/generic/dl-cache.h b/sysdeps/generic/dl-cache.h +index 259e843724531630..6adbe3c79a32a4ec 100644 +--- a/sysdeps/generic/dl-cache.h ++++ b/sysdeps/generic/dl-cache.h +@@ -99,6 +99,23 @@ struct file_entry_new + uint64_t hwcap; /* Hwcap entry. */ + }; + ++/* This bit in the hwcap field of struct file_entry_new indicates that ++ the lower 32 bits contain an index into the ++ cache_extension_tag_glibc_hwcaps section. Older glibc versions do ++ not know about this HWCAP bit, so they will ignore these ++ entries. */ ++#define DL_CACHE_HWCAP_EXTENSION (1ULL << 62) ++ ++/* Return true if the ENTRY->hwcap value indicates that ++ DL_CACHE_HWCAP_EXTENSION is used. */ ++static inline bool ++dl_cache_hwcap_extension (struct file_entry_new *entry) ++{ ++ /* If DL_CACHE_HWCAP_EXTENSION is set, but other bits as well, this ++ is a different kind of extension. */ ++ return (entry->hwcap >> 32) == (DL_CACHE_HWCAP_EXTENSION >> 32); ++} ++ + /* See flags member of struct cache_file_new below. */ + enum + { +@@ -182,6 +199,17 @@ enum cache_extension_tag + cache file. */ + cache_extension_tag_generator, + ++ /* glibc-hwcaps subdirectory information. An array of uint32_t ++ values, which are indices into the string table. The strings ++ are sorted lexicographically (according to strcmp). The extra ++ level of indirection (instead of using string table indices ++ directly) allows the dynamic loader to compute the preference ++ order of the hwcaps names more efficiently. ++ ++ For this section, 4-byte alignment is required, and the section ++ size must be a multiple of 4. */ ++ cache_extension_tag_glibc_hwcaps, ++ + /* Total number of known cache extension tags. */ + cache_extension_count + }; +@@ -236,6 +264,27 @@ struct cache_extension_all_loaded + struct cache_extension_loaded sections[cache_extension_count]; + }; + ++/* Performs basic data validation based on section tag, and removes ++ the sections which are invalid. */ ++static void ++cache_extension_verify (struct cache_extension_all_loaded *loaded) ++{ ++ { ++ /* Section must not be empty, it must be aligned at 4 bytes, and ++ the size must be a multiple of 4. */ ++ struct cache_extension_loaded *hwcaps ++ = &loaded->sections[cache_extension_tag_glibc_hwcaps]; ++ if (hwcaps->size == 0 ++ || ((uintptr_t) hwcaps->base % 4) != 0 ++ || (hwcaps->size % 4) != 0) ++ { ++ hwcaps->base = NULL; ++ hwcaps->size = 0; ++ hwcaps->flags = 0; ++ } ++ } ++} ++ + static bool __attribute__ ((unused)) + cache_extension_load (const struct cache_file_new *cache, + const void *file_base, size_t file_size, +@@ -282,6 +331,7 @@ cache_extension_load (const struct cache_file_new *cache, + loaded->sections[tag].size = ext->sections[i].size; + loaded->sections[tag].flags = ext->sections[i].flags; + } ++ cache_extension_verify (loaded); + return true; + } + +diff --git a/sysdeps/generic/ldconfig.h b/sysdeps/generic/ldconfig.h +index b15b142511829436..a8d22f143f867a3e 100644 +--- a/sysdeps/generic/ldconfig.h ++++ b/sysdeps/generic/ldconfig.h +@@ -57,8 +57,22 @@ extern void init_cache (void); + + extern void save_cache (const char *cache_name); + +-extern void add_to_cache (const char *path, const char *lib, int flags, +- unsigned int osversion, uint64_t hwcap); ++struct glibc_hwcaps_subdirectory; ++ ++/* Return a struct describing the subdirectory for NAME. Reuse an ++ existing struct if it exists. */ ++struct glibc_hwcaps_subdirectory *new_glibc_hwcaps_subdirectory ++ (const char *name); ++ ++/* Returns the name that was specified when ++ add_glibc_hwcaps_subdirectory was called. */ ++const char *glibc_hwcaps_subdirectory_name ++ (const struct glibc_hwcaps_subdirectory *); ++ ++extern void add_to_cache (const char *path, const char *filename, ++ const char *soname, ++ int flags, unsigned int osversion, uint64_t hwcap, ++ struct glibc_hwcaps_subdirectory *); + + extern void init_aux_cache (void); + diff --git a/SOURCES/glibc-rh1817513-119.patch b/SOURCES/glibc-rh1817513-119.patch new file mode 100644 index 0000000..adb64de --- /dev/null +++ b/SOURCES/glibc-rh1817513-119.patch @@ -0,0 +1,659 @@ +commit 600d9e0c87940da9b0fdeff492bf888df852d40c +Author: Florian Weimer +Date: Fri Dec 4 09:13:43 2020 +0100 + + elf: Add glibc-hwcaps subdirectory support to ld.so cache processing + + This recognizes the DL_CACHE_HWCAP_EXTENSION flag in cache entries, + and picks the supported cache entry with the highest priority. + + The elf/tst-glibc-hwcaps-prepend-cache test documents a non-desired + aspect of the current cache implementation: If the cache selects a DSO + that does not exist on disk, _dl_map_object falls back to open_path, + which may or may not find an alternative implementation. This is an + existing limitation that also applies to the legacy hwcaps processing + for ld.so.cache. + + Reviewed-by: Adhemerval Zanella + +diff --git a/elf/Makefile b/elf/Makefile +index a3e802a9a99b759c..f67b231c0f8e3aff 100644 +--- a/elf/Makefile ++++ b/elf/Makefile +@@ -162,6 +162,12 @@ tst-tls1-static-non-pie-no-pie = yes + tests-container = \ + tst-ldconfig-bad-aux-cache + ++ifeq (no,$(build-hardcoded-path-in-tests)) ++# This is an ld.so.cache test, and RPATH/RUNPATH in the executable ++# interferes with its test objectives. ++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 +@@ -1784,6 +1790,14 @@ $(objpfx)tst-glibc-hwcaps-prepend.out: \ + $< > $@; \ + $(evaluate-test) + ++# Like tst-glibc-hwcaps-prepend, but uses a container and loads the ++# library via ld.so.cache. Test setup is contained in the test ++# itself. ++$(objpfx)tst-glibc-hwcaps-prepend-cache: $(libdl) ++$(objpfx)tst-glibc-hwcaps-prepend-cache.out: \ ++ $(objpfx)tst-glibc-hwcaps-prepend-cache $(objpfx)libmarkermod1-1.so \ ++ $(objpfx)libmarkermod1-2.so $(objpfx)libmarkermod1-3.so ++ + # tst-glibc-hwcaps-mask checks that --glibc-hwcaps-mask can be used to + # suppress all auto-detected subdirectories. + $(objpfx)tst-glibc-hwcaps-mask: $(objpfx)libmarkermod1-1.so +@@ -1795,3 +1809,7 @@ $(objpfx)tst-glibc-hwcaps-mask.out: \ + --glibc-hwcaps-mask does-not-exist \ + $< > $@; \ + $(evaluate-test) ++ ++# Generic dependency for sysdeps implementation of ++# tst-glibc-hwcaps-cache. ++$(objpfx)tst-glibc-hwcaps-cache.out: $(objpfx)tst-glibc-hwcaps +diff --git a/elf/dl-cache.c b/elf/dl-cache.c +index de063faa8b2c88ae..e75afdaee23226e6 100644 +--- a/elf/dl-cache.c ++++ b/elf/dl-cache.c +@@ -35,6 +35,144 @@ static struct cache_file *cache; + static struct cache_file_new *cache_new; + static size_t cachesize; + ++#ifdef SHARED ++/* This is used to cache the priorities of glibc-hwcaps ++ subdirectories. The elements of _dl_cache_priorities correspond to ++ the strings in the cache_extension_tag_glibc_hwcaps section. */ ++static uint32_t *glibc_hwcaps_priorities; ++static uint32_t glibc_hwcaps_priorities_length; ++static uint32_t glibc_hwcaps_priorities_allocated; ++ ++/* True if the full malloc was used to allocated the array. */ ++static bool glibc_hwcaps_priorities_malloced; ++ ++/* Deallocate the glibc_hwcaps_priorities array. */ ++static void ++glibc_hwcaps_priorities_free (void) ++{ ++ /* When the minimal malloc is in use, free does not do anything, ++ so it does not make sense to call it. */ ++ if (glibc_hwcaps_priorities_malloced) ++ free (glibc_hwcaps_priorities); ++ glibc_hwcaps_priorities = NULL; ++ glibc_hwcaps_priorities_allocated = 0; ++} ++ ++/* Ordered comparison of a hwcaps string from the cache on the left ++ (identified by its string table index) and a _dl_hwcaps_priorities ++ element on the right. */ ++static int ++glibc_hwcaps_compare (uint32_t left_index, struct dl_hwcaps_priority *right) ++{ ++ const char *left_name = (const char *) cache + left_index; ++ uint32_t left_name_length = strlen (left_name); ++ uint32_t to_compare; ++ if (left_name_length < right->name_length) ++ to_compare = left_name_length; ++ else ++ to_compare = right->name_length; ++ int cmp = memcmp (left_name, right->name, to_compare); ++ if (cmp != 0) ++ return cmp; ++ if (left_name_length < right->name_length) ++ return -1; ++ else if (left_name_length > right->name_length) ++ return 1; ++ else ++ return 0; ++} ++ ++/* Initialize the glibc_hwcaps_priorities array and its length, ++ glibc_hwcaps_priorities_length. */ ++static void ++glibc_hwcaps_priorities_init (void) ++{ ++ struct cache_extension_all_loaded ext; ++ if (!cache_extension_load (cache_new, cache, cachesize, &ext)) ++ return; ++ ++ uint32_t length = (ext.sections[cache_extension_tag_glibc_hwcaps].size ++ / sizeof (uint32_t)); ++ if (length > glibc_hwcaps_priorities_allocated) ++ { ++ glibc_hwcaps_priorities_free (); ++ ++ uint32_t *new_allocation = malloc (length * sizeof (uint32_t)); ++ if (new_allocation == NULL) ++ /* This effectively disables hwcaps on memory allocation ++ errors. */ ++ return; ++ ++ glibc_hwcaps_priorities = new_allocation; ++ glibc_hwcaps_priorities_allocated = length; ++ glibc_hwcaps_priorities_malloced = __rtld_malloc_is_complete (); ++ } ++ ++ /* Compute the priorities for the subdirectories by merging the ++ array in the cache with the dl_hwcaps_priorities array. */ ++ const uint32_t *left = ext.sections[cache_extension_tag_glibc_hwcaps].base; ++ const uint32_t *left_end = left + length; ++ struct dl_hwcaps_priority *right = _dl_hwcaps_priorities; ++ struct dl_hwcaps_priority *right_end = right + _dl_hwcaps_priorities_length; ++ uint32_t *result = glibc_hwcaps_priorities; ++ ++ while (left < left_end && right < right_end) ++ { ++ if (*left < cachesize) ++ { ++ int cmp = glibc_hwcaps_compare (*left, right); ++ if (cmp == 0) ++ { ++ *result = right->priority; ++ ++result; ++ ++left; ++ ++right; ++ } ++ else if (cmp < 0) ++ { ++ *result = 0; ++ ++result; ++ ++left; ++ } ++ else ++ ++right; ++ } ++ else ++ { ++ *result = 0; ++ ++result; ++ } ++ } ++ while (left < left_end) ++ { ++ *result = 0; ++ ++result; ++ ++left; ++ } ++ ++ glibc_hwcaps_priorities_length = length; ++} ++ ++/* Return the priority of the cache_extension_tag_glibc_hwcaps section ++ entry at INDEX. Zero means do not use. Otherwise, lower values ++ indicate greater preference. */ ++static uint32_t ++glibc_hwcaps_priority (uint32_t index) ++{ ++ /* This does not need to repeated initialization attempts because ++ this function is only called if there is glibc-hwcaps data in the ++ cache, so the first call initializes the glibc_hwcaps_priorities ++ array. */ ++ if (glibc_hwcaps_priorities_length == 0) ++ glibc_hwcaps_priorities_init (); ++ ++ if (index < glibc_hwcaps_priorities_length) ++ return glibc_hwcaps_priorities[index]; ++ else ++ return 0; ++} ++#endif /* SHARED */ ++ + /* True if PTR is a valid string table index. */ + static inline bool + _dl_cache_verify_ptr (uint32_t ptr, size_t string_table_size) +@@ -74,6 +212,9 @@ search_cache (const char *string_table, uint32_t string_table_size, + int left = 0; + int right = nlibs - 1; + const char *best = NULL; ++#ifdef SHARED ++ uint32_t best_priority = 0; ++#endif + + while (left <= right) + { +@@ -129,6 +270,11 @@ search_cache (const char *string_table, uint32_t string_table_size, + { + if (best == NULL || flags == GLRO (dl_correct_cache_id)) + { ++ /* Named/extension hwcaps get slightly different ++ treatment: We keep searching for a better ++ match. */ ++ bool named_hwcap = false; ++ + if (entry_size >= sizeof (struct file_entry_new)) + { + /* The entry is large enough to include +@@ -136,7 +282,18 @@ search_cache (const char *string_table, uint32_t string_table_size, + struct file_entry_new *libnew + = (struct file_entry_new *) lib; + +- if (libnew->hwcap & hwcap_exclude) ++#ifdef SHARED ++ named_hwcap = dl_cache_hwcap_extension (libnew); ++#endif ++ ++ /* The entries with named/extension hwcaps ++ have been exhausted. Return the best ++ match encountered so far if there is ++ one. */ ++ if (!named_hwcap && best != NULL) ++ break; ++ ++ if ((libnew->hwcap & hwcap_exclude) && !named_hwcap) + continue; + if (GLRO (dl_osversion) + && libnew->osversion > GLRO (dl_osversion)) +@@ -146,14 +303,41 @@ search_cache (const char *string_table, uint32_t string_table_size, + && ((libnew->hwcap & _DL_HWCAP_PLATFORM) + != platform)) + continue; ++ ++#ifdef SHARED ++ /* For named hwcaps, determine the priority ++ and see if beats what has been found so ++ far. */ ++ if (named_hwcap) ++ { ++ uint32_t entry_priority ++ = glibc_hwcaps_priority (libnew->hwcap); ++ if (entry_priority == 0) ++ /* Not usable at all. Skip. */ ++ continue; ++ else if (best == NULL ++ || entry_priority < best_priority) ++ /* This entry is of higher priority ++ than the previous one, or it is the ++ first entry. */ ++ best_priority = entry_priority; ++ else ++ /* An entry has already been found, ++ but it is a better match. */ ++ continue; ++ } ++#endif /* SHARED */ + } + + best = string_table + lib->value; + +- if (flags == GLRO (dl_correct_cache_id)) ++ if (flags == GLRO (dl_correct_cache_id) ++ && !named_hwcap) + /* We've found an exact match for the shared + object and no general `ELF' release. Stop +- searching. */ ++ searching, but not if a named (extension) ++ hwcap is used. In this case, an entry with ++ a higher priority may come up later. */ + break; + } + } +@@ -346,5 +530,9 @@ _dl_unload_cache (void) + __munmap (cache, cachesize); + cache = NULL; + } ++#ifdef SHARED ++ /* This marks the glibc_hwcaps_priorities array as out-of-date. */ ++ glibc_hwcaps_priorities_length = 0; ++#endif + } + #endif +diff --git a/elf/dl-hwcaps.c b/elf/dl-hwcaps.c +index e57d0d2d41741021..098173a84c43c1fd 100644 +--- a/elf/dl-hwcaps.c ++++ b/elf/dl-hwcaps.c +@@ -89,6 +89,81 @@ copy_hwcaps (struct copy_hwcaps *target, const char *hwcaps, + } + } + ++struct dl_hwcaps_priority *_dl_hwcaps_priorities; ++uint32_t _dl_hwcaps_priorities_length; ++ ++/* Allocate _dl_hwcaps_priorities and fill it with data. */ ++static void ++compute_priorities (size_t total_count, const char *prepend, ++ uint32_t bitmask, const char *mask) ++{ ++ _dl_hwcaps_priorities = malloc (total_count ++ * sizeof (*_dl_hwcaps_priorities)); ++ if (_dl_hwcaps_priorities == NULL) ++ _dl_signal_error (ENOMEM, NULL, NULL, ++ N_("cannot create HWCAP priorities")); ++ _dl_hwcaps_priorities_length = total_count; ++ ++ /* First the prepended subdirectories. */ ++ size_t i = 0; ++ { ++ struct dl_hwcaps_split sp; ++ _dl_hwcaps_split_init (&sp, prepend); ++ while (_dl_hwcaps_split (&sp)) ++ { ++ _dl_hwcaps_priorities[i].name = sp.segment; ++ _dl_hwcaps_priorities[i].name_length = sp.length; ++ _dl_hwcaps_priorities[i].priority = i + 1; ++ ++i; ++ } ++ } ++ ++ /* Then the built-in subdirectories that are actually active. */ ++ { ++ struct dl_hwcaps_split_masked sp; ++ _dl_hwcaps_split_masked_init (&sp, _dl_hwcaps_subdirs, bitmask, mask); ++ while (_dl_hwcaps_split_masked (&sp)) ++ { ++ _dl_hwcaps_priorities[i].name = sp.split.segment; ++ _dl_hwcaps_priorities[i].name_length = sp.split.length; ++ _dl_hwcaps_priorities[i].priority = i + 1; ++ ++i; ++ } ++ } ++ assert (i == total_count); ++} ++ ++/* Sort the _dl_hwcaps_priorities array by name. */ ++static void ++sort_priorities_by_name (void) ++{ ++ /* Insertion sort. There is no need to link qsort into the dynamic ++ loader for such a short array. */ ++ for (size_t i = 1; i < _dl_hwcaps_priorities_length; ++i) ++ for (size_t j = i; j > 0; --j) ++ { ++ struct dl_hwcaps_priority *previous = _dl_hwcaps_priorities + j - 1; ++ struct dl_hwcaps_priority *current = _dl_hwcaps_priorities + j; ++ ++ /* Bail out if current is greater or equal to the previous ++ value. */ ++ uint32_t to_compare; ++ if (current->name_length < previous->name_length) ++ to_compare = current->name_length; ++ else ++ to_compare = previous->name_length; ++ int cmp = memcmp (current->name, previous->name, to_compare); ++ if (cmp >= 0 ++ || (cmp == 0 && current->name_length >= previous->name_length)) ++ break; ++ ++ /* Swap *previous and *current. */ ++ struct dl_hwcaps_priority tmp = *previous; ++ *previous = *current; ++ *current = tmp; ++ } ++} ++ + /* Return an array of useful/necessary hardware capability names. */ + const struct r_strlenpair * + _dl_important_hwcaps (const char *glibc_hwcaps_prepend, +@@ -111,6 +186,9 @@ _dl_important_hwcaps (const char *glibc_hwcaps_prepend, + update_hwcaps_counts (&hwcaps_counts, glibc_hwcaps_prepend, -1, NULL); + update_hwcaps_counts (&hwcaps_counts, _dl_hwcaps_subdirs, + hwcaps_subdirs_active, glibc_hwcaps_mask); ++ compute_priorities (hwcaps_counts.count, glibc_hwcaps_prepend, ++ hwcaps_subdirs_active, glibc_hwcaps_mask); ++ sort_priorities_by_name (); + + /* Each hwcaps subdirectory has a GLIBC_HWCAPS_PREFIX string prefix + and a "/" suffix once stored in the result. */ +diff --git a/elf/dl-hwcaps.h b/elf/dl-hwcaps.h +index 3fcfbceb1a8fc1c8..769ecab3f886c6c4 100644 +--- a/elf/dl-hwcaps.h ++++ b/elf/dl-hwcaps.h +@@ -132,4 +132,23 @@ _dl_hwcaps_subdirs_build_bitmask (int subdirs, int active) + return mask ^ ((1U << inactive) - 1); + } + ++/* Pre-computed glibc-hwcaps subdirectory priorities. Used in ++ dl-cache.c to quickly find the proprieties for the stored HWCAP ++ names. */ ++struct dl_hwcaps_priority ++{ ++ /* The name consists of name_length bytes at name (not necessarily ++ null-terminated). */ ++ const char *name; ++ uint32_t name_length; ++ ++ /* Priority of this name. A positive number. */ ++ uint32_t priority; ++}; ++ ++/* Pre-computed hwcaps priorities. Set up by ++ _dl_important_hwcaps. */ ++extern struct dl_hwcaps_priority *_dl_hwcaps_priorities attribute_hidden; ++extern uint32_t _dl_hwcaps_priorities_length attribute_hidden; ++ + #endif /* _DL_HWCAPS_H */ +diff --git a/elf/tst-glibc-hwcaps-cache.c b/elf/tst-glibc-hwcaps-cache.c +new file mode 100644 +index 0000000000000000..4bad56afc03451fc +--- /dev/null ++++ b/elf/tst-glibc-hwcaps-cache.c +@@ -0,0 +1,45 @@ ++/* Wrapper to invoke tst-glibc-hwcaps in a container, to test ld.so.cache. ++ 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 ++ . */ ++ ++/* This program is just a wrapper that runs ldconfig followed by ++ tst-glibc-hwcaps. The actual test is provided via an ++ implementation in a sysdeps subdirectory. */ ++ ++#include ++#include ++#include ++#include ++ ++int ++main (int argc, char **argv) ++{ ++ /* Run ldconfig to populate the cache. */ ++ { ++ char *command = xasprintf ("%s/ldconfig", support_install_rootsbindir); ++ if (system (command) != 0) ++ return 1; ++ free (command); ++ } ++ ++ /* Reuse tst-glibc-hwcaps. Since this code is running in a ++ container, we can launch it directly. */ ++ char *path = xasprintf ("%s/elf/tst-glibc-hwcaps", support_objdir_root); ++ execv (path, argv); ++ printf ("error: execv of %s failed: %m\n", path); ++ return 1; ++} +diff --git a/elf/tst-glibc-hwcaps-cache.root/etc/ld.so.conf b/elf/tst-glibc-hwcaps-cache.root/etc/ld.so.conf +new file mode 100644 +index 0000000000000000..e1e74dbda2bf3dfa +--- /dev/null ++++ b/elf/tst-glibc-hwcaps-cache.root/etc/ld.so.conf +@@ -0,0 +1,2 @@ ++# This file was created to suppress a warning from ldconfig: ++# /sbin/ldconfig: Warning: ignoring configuration file that cannot be opened: /etc/ld.so.conf: No such file or directory +diff --git a/elf/tst-glibc-hwcaps-cache.root/postclean.req b/elf/tst-glibc-hwcaps-cache.root/postclean.req +new file mode 100644 +index 0000000000000000..e69de29bb2d1d643 +diff --git a/elf/tst-glibc-hwcaps-cache.script b/elf/tst-glibc-hwcaps-cache.script +new file mode 100644 +index 0000000000000000..6356d152089cdd9a +--- /dev/null ++++ b/elf/tst-glibc-hwcaps-cache.script +@@ -0,0 +1,6 @@ ++# test-container does not support scripts in sysdeps directories, so ++# collect everything in one file. ++ ++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 +diff --git a/elf/tst-glibc-hwcaps-prepend-cache.c b/elf/tst-glibc-hwcaps-prepend-cache.c +new file mode 100644 +index 0000000000000000..40509cebe2b5ba27 +--- /dev/null ++++ b/elf/tst-glibc-hwcaps-prepend-cache.c +@@ -0,0 +1,149 @@ ++/* Test that --glibc-hwcaps-prepend works, using dlopen and /etc/ld.so.cache. ++ 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 ++ ++/* Invoke /sbin/ldconfig with some error checking. */ ++static void ++run_ldconfig (void) ++{ ++ char *command = xasprintf ("%s/ldconfig", support_install_rootsbindir); ++ TEST_COMPARE (system (command), 0); ++ free (command); ++} ++ ++/* The library under test. */ ++#define SONAME "libmarkermod1.so" ++ ++static int ++do_test (void) ++{ ++ if (dlopen (SONAME, RTLD_NOW) != NULL) ++ FAIL_EXIT1 (SONAME " is already on the search path"); ++ ++ /* Install the default implementation of libmarkermod1.so. */ ++ xmkdirp ("/etc", 0777); ++ support_write_file_string ("/etc/ld.so.conf", "/glibc-test/lib\n"); ++ xmkdirp ("/glibc-test/lib/glibc-hwcaps/prepend2", 0777); ++ xmkdirp ("/glibc-test/lib/glibc-hwcaps/prepend3", 0777); ++ { ++ char *src = xasprintf ("%s/elf/libmarkermod1-1.so", support_objdir_root); ++ support_copy_file (src, "/glibc-test/lib/" SONAME); ++ free (src); ++ } ++ run_ldconfig (); ++ { ++ /* The default implementation can now be loaded. */ ++ void *handle = xdlopen (SONAME, RTLD_NOW); ++ int (*marker1) (void) = xdlsym (handle, "marker1"); ++ TEST_COMPARE (marker1 (), 1); ++ xdlclose (handle); ++ } ++ ++ /* Add the first override to the directory that is searched last. */ ++ { ++ char *src = xasprintf ("%s/elf/libmarkermod1-2.so", support_objdir_root); ++ support_copy_file (src, "/glibc-test/lib/glibc-hwcaps/prepend2/" ++ SONAME); ++ free (src); ++ } ++ { ++ /* This is still the first implementation. The cache has not been ++ updated. */ ++ void *handle = xdlopen (SONAME, RTLD_NOW); ++ int (*marker1) (void) = xdlsym (handle, "marker1"); ++ TEST_COMPARE (marker1 (), 1); ++ xdlclose (handle); ++ } ++ run_ldconfig (); ++ { ++ /* After running ldconfig, it is the second implementation. */ ++ void *handle = xdlopen (SONAME, RTLD_NOW); ++ int (*marker1) (void) = xdlsym (handle, "marker1"); ++ TEST_COMPARE (marker1 (), 2); ++ xdlclose (handle); ++ } ++ ++ /* Add the second override to the directory that is searched first. */ ++ { ++ char *src = xasprintf ("%s/elf/libmarkermod1-3.so", support_objdir_root); ++ support_copy_file (src, "/glibc-test/lib/glibc-hwcaps/prepend3/" ++ SONAME); ++ free (src); ++ } ++ { ++ /* This is still the second implementation. */ ++ void *handle = xdlopen (SONAME, RTLD_NOW); ++ int (*marker1) (void) = xdlsym (handle, "marker1"); ++ TEST_COMPARE (marker1 (), 2); ++ xdlclose (handle); ++ } ++ run_ldconfig (); ++ { ++ /* After running ldconfig, it is the third implementation. */ ++ void *handle = xdlopen (SONAME, RTLD_NOW); ++ int (*marker1) (void) = xdlsym (handle, "marker1"); ++ TEST_COMPARE (marker1 (), 3); ++ xdlclose (handle); ++ } ++ ++ /* Remove the second override again, without running ldconfig. ++ Ideally, this would revert to implementation 2. However, in the ++ current implementation, the cache returns exactly one file name ++ which does not exist after unlinking, so the dlopen fails. */ ++ xunlink ("/glibc-test/lib/glibc-hwcaps/prepend3/" SONAME); ++ TEST_VERIFY (dlopen (SONAME, RTLD_NOW) == NULL); ++ run_ldconfig (); ++ { ++ /* After running ldconfig, the second implementation is available ++ once more. */ ++ void *handle = xdlopen (SONAME, RTLD_NOW); ++ int (*marker1) (void) = xdlsym (handle, "marker1"); ++ TEST_COMPARE (marker1 (), 2); ++ xdlclose (handle); ++ } ++ ++ return 0; ++} ++ ++static void ++prepare (int argc, char **argv) ++{ ++ const char *no_restart = "no-restart"; ++ if (argc == 2 && strcmp (argv[1], no_restart) == 0) ++ return; ++ /* Re-execute the test with an explicit loader invocation. */ ++ execl (support_objdir_elf_ldso, ++ support_objdir_elf_ldso, ++ "--glibc-hwcaps-prepend", "prepend3:prepend2", ++ argv[0], no_restart, ++ NULL); ++ printf ("error: execv of %s failed: %m\n", argv[0]); ++ _exit (1); ++} ++ ++#define PREPARE prepare ++#include +diff --git a/elf/tst-glibc-hwcaps-prepend-cache.root/postclean.req b/elf/tst-glibc-hwcaps-prepend-cache.root/postclean.req +new file mode 100644 +index 0000000000000000..e69de29bb2d1d643 diff --git a/SOURCES/glibc-rh1817513-12.patch b/SOURCES/glibc-rh1817513-12.patch new file mode 100644 index 0000000..b755c39 --- /dev/null +++ b/SOURCES/glibc-rh1817513-12.patch @@ -0,0 +1,38 @@ +commit 2954daf00bb4dc27c69a48e6798d5960ea320741 +Author: Andreas Schwab +Date: Tue Oct 23 09:40:14 2018 +0200 + + Add more checks for valid ld.so.cache file (bug 18093) + +diff --git a/elf/cache.c b/elf/cache.c +index e63979da7d25560c..c4cd825c30e00e8e 100644 +--- a/elf/cache.c ++++ b/elf/cache.c +@@ -199,6 +199,11 @@ print_cache (const char *cache_name) + } + else + { ++ /* Check for corruption, avoiding overflow. */ ++ if ((cache_size - sizeof (struct cache_file)) / sizeof (struct file_entry) ++ < cache->nlibs) ++ error (EXIT_FAILURE, 0, _("File is not a cache file.\n")); ++ + size_t offset = ALIGN_CACHE (sizeof (struct cache_file) + + (cache->nlibs + * sizeof (struct file_entry))); +diff --git a/elf/dl-cache.c b/elf/dl-cache.c +index 6ee5153ff9514872..6dd99a35b9f97cfb 100644 +--- a/elf/dl-cache.c ++++ b/elf/dl-cache.c +@@ -204,7 +204,10 @@ _dl_load_cache_lookup (const char *name) + - only the new format + The following checks if the cache contains any of these formats. */ + if (file != MAP_FAILED && cachesize > sizeof *cache +- && memcmp (file, CACHEMAGIC, sizeof CACHEMAGIC - 1) == 0) ++ && memcmp (file, CACHEMAGIC, sizeof CACHEMAGIC - 1) == 0 ++ /* Check for corruption, avoiding overflow. */ ++ && ((cachesize - sizeof *cache) / sizeof (struct file_entry) ++ >= ((struct cache_file *) file)->nlibs)) + { + size_t offset; + /* Looks ok. */ diff --git a/SOURCES/glibc-rh1817513-120.patch b/SOURCES/glibc-rh1817513-120.patch new file mode 100644 index 0000000..6c5d566 --- /dev/null +++ b/SOURCES/glibc-rh1817513-120.patch @@ -0,0 +1,249 @@ +commit f267e1c9dd7fb8852cc32d6eafd96bbcfd5cbb2b +Author: Florian Weimer +Date: Fri Dec 4 09:13:43 2020 +0100 + + x86_64: Add glibc-hwcaps support + + The subdirectories match those in the x86-64 psABI: + + https://gitlab.com/x86-psABIs/x86-64-ABI/-/commit/77566eb03bc6a326811cb7e9a6b9396884b67c7c + + Reviewed-by: Adhemerval Zanella + +diff --git a/elf/Makefile b/elf/Makefile +index f67b231c0f8e3aff..7f2fc73877f0a4c8 100644 +--- a/elf/Makefile ++++ b/elf/Makefile +@@ -1751,7 +1751,7 @@ $(objpfx)argv0test.out: tst-rtld-argv0.sh $(objpfx)ld.so \ + # glibc-hwcaps mechanism for this architecture). Used to obtain test + # coverage for some glibc-hwcaps tests for the widest possible range + # of systems. +-glibc-hwcaps-first-subdirs-for-tests = ++glibc-hwcaps-first-subdirs-for-tests = x86-64-v2 + + # The test modules are parameterized by preprocessor macros. + LDFLAGS-libmarkermod1-1.so += -Wl,-soname,libmarkermod1.so +diff --git a/elf/tst-glibc-hwcaps-cache.script b/elf/tst-glibc-hwcaps-cache.script +index 6356d152089cdd9a..66d6942402b7233b 100644 +--- a/elf/tst-glibc-hwcaps-cache.script ++++ b/elf/tst-glibc-hwcaps-cache.script +@@ -4,3 +4,13 @@ + 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 ++ ++mkdirp 0770 $L/glibc-hwcaps/x86-64-v2 ++cp $B/elf/libmarkermod2-2.so $L/glibc-hwcaps/x86-64-v2/libmarkermod2.so ++mkdirp 0770 $L/glibc-hwcaps/x86-64-v3 ++cp $B/elf/libmarkermod3-2.so $L/glibc-hwcaps/x86-64-v2/libmarkermod3.so ++cp $B/elf/libmarkermod3-3.so $L/glibc-hwcaps/x86-64-v3/libmarkermod3.so ++mkdirp 0770 $L/glibc-hwcaps/x86-64-v4 ++cp $B/elf/libmarkermod4-2.so $L/glibc-hwcaps/x86-64-v2/libmarkermod4.so ++cp $B/elf/libmarkermod4-3.so $L/glibc-hwcaps/x86-64-v3/libmarkermod4.so ++cp $B/elf/libmarkermod4-4.so $L/glibc-hwcaps/x86-64-v4/libmarkermod4.so +diff --git a/sysdeps/x86_64/Makefile b/sysdeps/x86_64/Makefile +index 42b97c5cc73892cc..d1d7cb9d2eeca9c5 100644 +--- a/sysdeps/x86_64/Makefile ++++ b/sysdeps/x86_64/Makefile +@@ -144,8 +144,47 @@ CFLAGS-tst-auditmod10b.c += $(AVX512-CFLAGS) + CFLAGS-tst-avx512-aux.c += $(AVX512-CFLAGS) + CFLAGS-tst-avx512mod.c += $(AVX512-CFLAGS) + endif ++ ++$(objpfx)tst-glibc-hwcaps: $(objpfx)libmarkermod2-1.so \ ++ $(objpfx)libmarkermod3-1.so $(objpfx)libmarkermod4-1.so ++$(objpfx)tst-glibc-hwcaps.out: \ ++ $(objpfx)libmarkermod2.so \ ++ $(objpfx)glibc-hwcaps/x86-64-v2/libmarkermod2.so \ ++ $(objpfx)libmarkermod3.so \ ++ $(objpfx)glibc-hwcaps/x86-64-v2/libmarkermod3.so \ ++ $(objpfx)glibc-hwcaps/x86-64-v3/libmarkermod3.so \ ++ $(objpfx)libmarkermod4.so \ ++ $(objpfx)glibc-hwcaps/x86-64-v2/libmarkermod4.so \ ++ $(objpfx)glibc-hwcaps/x86-64-v3/libmarkermod4.so \ ++ $(objpfx)glibc-hwcaps/x86-64-v4/libmarkermod4.so \ ++ ++$(objpfx)glibc-hwcaps/x86-64-v2/libmarkermod2.so: $(objpfx)libmarkermod2-2.so ++ $(make-target-directory) ++ cp $< $@ ++$(objpfx)glibc-hwcaps/x86-64-v2/libmarkermod3.so: $(objpfx)libmarkermod3-2.so ++ $(make-target-directory) ++ cp $< $@ ++$(objpfx)glibc-hwcaps/x86-64-v3/libmarkermod3.so: $(objpfx)libmarkermod3-3.so ++ $(make-target-directory) ++ cp $< $@ ++$(objpfx)glibc-hwcaps/x86-64-v2/libmarkermod4.so: $(objpfx)libmarkermod4-2.so ++ $(make-target-directory) ++ cp $< $@ ++$(objpfx)glibc-hwcaps/x86-64-v3/libmarkermod4.so: $(objpfx)libmarkermod4-3.so ++ $(make-target-directory) ++ cp $< $@ ++$(objpfx)glibc-hwcaps/x86-64-v4/libmarkermod4.so: $(objpfx)libmarkermod4-4.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 ++# interferes with its test objectives. ++tests-container += tst-glibc-hwcaps-cache + endif + ++endif # $(subdir) == elf ++ + ifeq ($(subdir),csu) + gen-as-const-headers += tlsdesc.sym rtld-offsets.sym + endif +diff --git a/sysdeps/x86_64/dl-hwcaps-subdirs.c b/sysdeps/x86_64/dl-hwcaps-subdirs.c +new file mode 100644 +index 0000000000000000..8810a822efe36962 +--- /dev/null ++++ b/sysdeps/x86_64/dl-hwcaps-subdirs.c +@@ -0,0 +1,66 @@ ++/* Architecture-specific glibc-hwcaps subdirectories. x86 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, see ++ . */ ++ ++#include ++#include ++ ++const char _dl_hwcaps_subdirs[] = "x86-64-v4:x86-64-v3:x86-64-v2"; ++enum { subdirs_count = 3 }; /* Number of components in _dl_hwcaps_subdirs. */ ++ ++uint32_t ++_dl_hwcaps_subdirs_active (void) ++{ ++ int active = 0; ++ ++ /* Test in reverse preference order. */ ++ ++ /* x86-64-v2. */ ++ if (!(CPU_FEATURE_USABLE (CMPXCHG16B) ++ && CPU_FEATURE_USABLE (LAHF64_SAHF64) ++ && CPU_FEATURE_USABLE (POPCNT) ++ && CPU_FEATURE_USABLE (SSE3) ++ && CPU_FEATURE_USABLE (SSE4_1) ++ && CPU_FEATURE_USABLE (SSE4_2) ++ && CPU_FEATURE_USABLE (SSSE3))) ++ return _dl_hwcaps_subdirs_build_bitmask (subdirs_count, active); ++ ++active; ++ ++ /* x86-64-v3. */ ++ if (!(CPU_FEATURE_USABLE (AVX) ++ && CPU_FEATURE_USABLE (AVX2) ++ && CPU_FEATURE_USABLE (BMI1) ++ && CPU_FEATURE_USABLE (BMI2) ++ && CPU_FEATURE_USABLE (F16C) ++ && CPU_FEATURE_USABLE (FMA) ++ && CPU_FEATURE_USABLE (LZCNT) ++ && CPU_FEATURE_USABLE (MOVBE) ++ && CPU_FEATURE_USABLE (OSXSAVE))) ++ return _dl_hwcaps_subdirs_build_bitmask (subdirs_count, active); ++ ++active; ++ ++ /* x86-64-v4. */ ++ if (!(CPU_FEATURE_USABLE (AVX512F) ++ && CPU_FEATURE_USABLE (AVX512BW) ++ && CPU_FEATURE_USABLE (AVX512CD) ++ && CPU_FEATURE_USABLE (AVX512DQ) ++ && CPU_FEATURE_USABLE (AVX512VL))) ++ return _dl_hwcaps_subdirs_build_bitmask (subdirs_count, active); ++ ++active; ++ ++ return _dl_hwcaps_subdirs_build_bitmask (subdirs_count, active); ++} +diff --git a/sysdeps/x86_64/tst-glibc-hwcaps.c b/sysdeps/x86_64/tst-glibc-hwcaps.c +new file mode 100644 +index 0000000000000000..3075a8286dc30768 +--- /dev/null ++++ b/sysdeps/x86_64/tst-glibc-hwcaps.c +@@ -0,0 +1,76 @@ ++/* glibc-hwcaps subdirectory test. 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, see ++ . */ ++ ++#include ++#include ++#include ++#include ++ ++extern int marker2 (void); ++extern int marker3 (void); ++extern int marker4 (void); ++ ++/* Return the x86-64-vN level, 1 for the baseline. */ ++static int ++compute_level (void) ++{ ++ const struct cpu_features *cpu_features ++ = __x86_get_cpu_features (COMMON_CPUID_INDEX_MAX); ++ ++ if (!(CPU_FEATURE_USABLE_P (cpu_features, CMPXCHG16B) ++ && CPU_FEATURE_USABLE_P (cpu_features, LAHF64_SAHF64) ++ && CPU_FEATURE_USABLE_P (cpu_features, POPCNT) ++ && CPU_FEATURE_USABLE_P (cpu_features, MMX) ++ && CPU_FEATURE_USABLE_P (cpu_features, SSE) ++ && CPU_FEATURE_USABLE_P (cpu_features, SSE2) ++ && CPU_FEATURE_USABLE_P (cpu_features, SSE3) ++ && CPU_FEATURE_USABLE_P (cpu_features, SSSE3) ++ && CPU_FEATURE_USABLE_P (cpu_features, SSE4_1) ++ && CPU_FEATURE_USABLE_P (cpu_features, SSE4_2))) ++ return 1; ++ if (!(CPU_FEATURE_USABLE_P (cpu_features, AVX) ++ && CPU_FEATURE_USABLE_P (cpu_features, AVX2) ++ && CPU_FEATURE_USABLE_P (cpu_features, BMI1) ++ && CPU_FEATURE_USABLE_P (cpu_features, BMI2) ++ && CPU_FEATURE_USABLE_P (cpu_features, F16C) ++ && CPU_FEATURE_USABLE_P (cpu_features, FMA) ++ && CPU_FEATURE_USABLE_P (cpu_features, LZCNT) ++ && CPU_FEATURE_USABLE_P (cpu_features, MOVBE) ++ && CPU_FEATURE_USABLE_P (cpu_features, OSXSAVE))) ++ return 2; ++ if (!(CPU_FEATURE_USABLE_P (cpu_features, AVX512F) ++ && CPU_FEATURE_USABLE_P (cpu_features, AVX512BW) ++ && CPU_FEATURE_USABLE_P (cpu_features, AVX512CD) ++ && CPU_FEATURE_USABLE_P (cpu_features, AVX512DQ) ++ && CPU_FEATURE_USABLE_P (cpu_features, AVX512VL))) ++ return 3; ++ return 4; ++} ++ ++static int ++do_test (void) ++{ ++ int level = compute_level (); ++ printf ("info: detected x86-64 micro-architecture level: %d\n", level); ++ TEST_COMPARE (marker2 (), MIN (level, 2)); ++ TEST_COMPARE (marker3 (), MIN (level, 3)); ++ TEST_COMPARE (marker4 (), MIN (level, 4)); ++ return 0; ++} ++ ++#include diff --git a/SOURCES/glibc-rh1817513-121.patch b/SOURCES/glibc-rh1817513-121.patch new file mode 100644 index 0000000..5280b4b --- /dev/null +++ b/SOURCES/glibc-rh1817513-121.patch @@ -0,0 +1,21 @@ +commit 4f4bd9e47ba98ccfeeaa8c600c0b0c8bbabcebb3 +Author: Matheus Castanho +Date: Fri Dec 4 09:48:56 2020 -0300 + + elf: Add missing header to elf/dl-hwcaps.h + + The lack of this header makes size_t unavailable on builds configured + with --disable-tunables, causing compilation errors. + +diff --git a/elf/dl-hwcaps.h b/elf/dl-hwcaps.h +index 769ecab3f886c6c4..9a34088c17e97d7f 100644 +--- a/elf/dl-hwcaps.h ++++ b/elf/dl-hwcaps.h +@@ -20,6 +20,7 @@ + #define _DL_HWCAPS_H + + #include ++#include + + #include + diff --git a/SOURCES/glibc-rh1817513-122.patch b/SOURCES/glibc-rh1817513-122.patch new file mode 100644 index 0000000..bc3388d --- /dev/null +++ b/SOURCES/glibc-rh1817513-122.patch @@ -0,0 +1,20 @@ +commit 2976082a385a7fb3d0294c6acf745b4f93e834ee +Author: H.J. Lu +Date: Thu Dec 3 15:02:44 2020 -0800 + + x86: Set RDRAND usable if CPU supports RDRAND + + Set RDRAND usable if CPU supports RDRAND. + +diff --git a/sysdeps/x86/cpu-features.c b/sysdeps/x86/cpu-features.c +index 4c9c15a44b618fed..805d00a43309fc23 100644 +--- a/sysdeps/x86/cpu-features.c ++++ b/sysdeps/x86/cpu-features.c +@@ -85,6 +85,7 @@ update_usable (struct cpu_features *cpu_features) + CPU_FEATURE_SET_USABLE (cpu_features, WAITPKG); + CPU_FEATURE_SET_USABLE (cpu_features, GFNI); + CPU_FEATURE_SET_USABLE (cpu_features, RDPID); ++ CPU_FEATURE_SET_USABLE (cpu_features, RDRAND); + CPU_FEATURE_SET_USABLE (cpu_features, CLDEMOTE); + CPU_FEATURE_SET_USABLE (cpu_features, MOVDIRI); + CPU_FEATURE_SET_USABLE (cpu_features, MOVDIR64B); diff --git a/SOURCES/glibc-rh1817513-123.patch b/SOURCES/glibc-rh1817513-123.patch new file mode 100644 index 0000000..1aa9cb7 --- /dev/null +++ b/SOURCES/glibc-rh1817513-123.patch @@ -0,0 +1,65 @@ +commit 93fda28693f0d9060b0aa71eeacaacfe9f16896e +Author: H.J. Lu +Date: Thu Dec 3 15:02:44 2020 -0800 + + x86: Adjust tst-cpu-features-supports.c for GCC 11 + + Check HAS_CPU_FEATURE instead of CPU_FEATURE_USABLE for FSGSBASE, IBT, + LM, SHSTK and XSAVES since FSGSBASE requires kernel support, IBT/SHSTK/LM + require OS support and XSAVES is supervisor-mode only. + +diff --git a/sysdeps/x86/tst-cpu-features-supports.c b/sysdeps/x86/tst-cpu-features-supports.c +index bf881b531f4bc2ed..287cf01fbdfaeda1 100644 +--- a/sysdeps/x86/tst-cpu-features-supports.c ++++ b/sysdeps/x86/tst-cpu-features-supports.c +@@ -40,6 +40,11 @@ check_supports (int supports, int usable, const char *supports_name, + #define CHECK_SUPPORTS(str, name) \ + check_supports (__builtin_cpu_supports (#str), \ + CPU_FEATURE_USABLE (name), \ ++ #str, "CPU_FEATURE_USABLE (" #name ")"); ++ ++#define CHECK_CPU_SUPPORTS(str, name) \ ++ check_supports (__builtin_cpu_supports (#str), \ ++ HAS_CPU_FEATURE (name), \ + #str, "HAS_CPU_FEATURE (" #name ")"); + + static int +@@ -118,7 +123,7 @@ do_test (int argc, char **argv) + fails += CHECK_SUPPORTS (fma4, FMA4); + #endif + #if __GNUC_PREREQ (11, 0) +- fails += CHECK_SUPPORTS (fsgsbase, FSGSBASE); ++ fails += CHECK_CPU_SUPPORTS (fsgsbase, FSGSBASE); + fails += CHECK_SUPPORTS (fxsave, FXSR); + #endif + #if __GNUC_PREREQ (8, 0) +@@ -126,9 +131,9 @@ do_test (int argc, char **argv) + #endif + #if __GNUC_PREREQ (11, 0) + fails += CHECK_SUPPORTS (hle, HLE); +- fails += CHECK_SUPPORTS (ibt, IBT); ++ fails += CHECK_CPU_SUPPORTS (ibt, IBT); + fails += CHECK_SUPPORTS (lahf_lm, LAHF64_SAHF64); +- fails += CHECK_SUPPORTS (lm, LM); ++ fails += CHECK_CPU_SUPPORTS (lm, LM); + fails += CHECK_SUPPORTS (lwp, LWP); + fails += CHECK_SUPPORTS (lzcnt, LZCNT); + #endif +@@ -150,7 +155,7 @@ do_test (int argc, char **argv) + fails += CHECK_SUPPORTS (rtm, RTM); + fails += CHECK_SUPPORTS (serialize, SERIALIZE); + fails += CHECK_SUPPORTS (sha, SHA); +- fails += CHECK_SUPPORTS (shstk, SHSTK); ++ fails += CHECK_CPU_SUPPORTS (shstk, SHSTK); + #endif + fails += CHECK_SUPPORTS (sse, SSE); + fails += CHECK_SUPPORTS (sse2, SSE2); +@@ -180,7 +185,7 @@ do_test (int argc, char **argv) + fails += CHECK_SUPPORTS (xsave, XSAVE); + fails += CHECK_SUPPORTS (xsavec, XSAVEC); + fails += CHECK_SUPPORTS (xsaveopt, XSAVEOPT); +- fails += CHECK_SUPPORTS (xsaves, XSAVES); ++ fails += CHECK_CPU_SUPPORTS (xsaves, XSAVES); + #endif + + printf ("%d differences between __builtin_cpu_supports and glibc code.\n", diff --git a/SOURCES/glibc-rh1817513-124.patch b/SOURCES/glibc-rh1817513-124.patch new file mode 100644 index 0000000..ec9e96d --- /dev/null +++ b/SOURCES/glibc-rh1817513-124.patch @@ -0,0 +1,187 @@ +commit 4c38c1a229bc3628269ad98bd7e8d31d118d91f6 +Author: Florian Weimer +Date: Fri Dec 4 09:13:43 2020 +0100 + + powerpc64le: Add glibc-hwcaps support + + The "power10" and "power9" subdirectories are selected in a way + that matches the -mcpu=power10 and -mcpu=power9 options of GCC. + +diff --git a/elf/Makefile b/elf/Makefile +index 7f2fc73877f0a4c8..57e3a8982297f79a 100644 +--- a/elf/Makefile ++++ b/elf/Makefile +@@ -1751,7 +1751,7 @@ $(objpfx)argv0test.out: tst-rtld-argv0.sh $(objpfx)ld.so \ + # glibc-hwcaps mechanism for this architecture). Used to obtain test + # coverage for some glibc-hwcaps tests for the widest possible range + # of systems. +-glibc-hwcaps-first-subdirs-for-tests = x86-64-v2 ++glibc-hwcaps-first-subdirs-for-tests = power9 x86-64-v2 + + # The test modules are parameterized by preprocessor macros. + LDFLAGS-libmarkermod1-1.so += -Wl,-soname,libmarkermod1.so +diff --git a/elf/tst-glibc-hwcaps-cache.script b/elf/tst-glibc-hwcaps-cache.script +index 66d6942402b7233b..6a4675f9bd30e02f 100644 +--- a/elf/tst-glibc-hwcaps-cache.script ++++ b/elf/tst-glibc-hwcaps-cache.script +@@ -5,6 +5,12 @@ 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 + ++mkdirp 0770 $L/glibc-hwcaps/power9 ++cp $B/elf/libmarkermod2-2.so $L/glibc-hwcaps/power9/libmarkermod2.so ++mkdirp 0770 $L/glibc-hwcaps/power10 ++cp $B/elf/libmarkermod3-2.so $L/glibc-hwcaps/power9/libmarkermod3.so ++cp $B/elf/libmarkermod3-3.so $L/glibc-hwcaps/power10/libmarkermod3.so ++ + mkdirp 0770 $L/glibc-hwcaps/x86-64-v2 + cp $B/elf/libmarkermod2-2.so $L/glibc-hwcaps/x86-64-v2/libmarkermod2.so + mkdirp 0770 $L/glibc-hwcaps/x86-64-v3 +diff --git a/sysdeps/powerpc/powerpc64/le/Makefile b/sysdeps/powerpc/powerpc64/le/Makefile +index f59db1ca3c8ed454..7a4be6bfef729914 100644 +--- a/sysdeps/powerpc/powerpc64/le/Makefile ++++ b/sysdeps/powerpc/powerpc64/le/Makefile +@@ -82,3 +82,31 @@ CFLAGS-printf_fp.c = -mfloat128 + CFLAGS-printf_fphex.c = -mfloat128 + CFLAGS-printf_size.c = -mfloat128 + endif ++ ++ifeq ($(subdir),elf) ++$(objpfx)tst-glibc-hwcaps: \ ++ $(objpfx)libmarkermod2-1.so $(objpfx)libmarkermod3-1.so ++$(objpfx)tst-glibc-hwcaps.out: \ ++ $(objpfx)libmarkermod2.so \ ++ $(objpfx)glibc-hwcaps/power9/libmarkermod2.so \ ++ $(objpfx)libmarkermod3.so \ ++ $(objpfx)glibc-hwcaps/power9/libmarkermod3.so \ ++ $(objpfx)glibc-hwcaps/power10/libmarkermod3.so \ ++ ++$(objpfx)glibc-hwcaps/power9/libmarkermod2.so: $(objpfx)libmarkermod2-2.so ++ $(make-target-directory) ++ cp $< $@ ++$(objpfx)glibc-hwcaps/power9/libmarkermod3.so: $(objpfx)libmarkermod3-2.so ++ $(make-target-directory) ++ cp $< $@ ++$(objpfx)glibc-hwcaps/power10/libmarkermod3.so: $(objpfx)libmarkermod3-3.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 ++# interferes with its test objectives. ++tests-container += tst-glibc-hwcaps-cache ++endif ++ ++endif # $(subdir) == elf +diff --git a/sysdeps/powerpc/powerpc64/le/dl-hwcaps-subdirs.c b/sysdeps/powerpc/powerpc64/le/dl-hwcaps-subdirs.c +new file mode 100644 +index 0000000000000000..6a21d77649f44dd4 +--- /dev/null ++++ b/sysdeps/powerpc/powerpc64/le/dl-hwcaps-subdirs.c +@@ -0,0 +1,46 @@ ++/* Architecture-specific glibc-hwcaps subdirectories. powerpc64le 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, see ++ . */ ++ ++#include ++#include ++ ++const char _dl_hwcaps_subdirs[] = "power10:power9"; ++enum { subdirs_count = 2 }; /* Number of components in _dl_hwcaps_subdirs. */ ++ ++uint32_t ++_dl_hwcaps_subdirs_active (void) ++{ ++ int active = 0; ++ ++ /* Test in reverse preference order. Altivec and VSX are implied by ++ the powerpc64le ABI definition. */ ++ ++ /* POWER9. GCC enables float128 hardware support for -mcpu=power9. */ ++ if ((GLRO (dl_hwcap2) & PPC_FEATURE2_ARCH_3_00) == 0 ++ || (GLRO (dl_hwcap2) & PPC_FEATURE2_HAS_IEEE128) == 0) ++ return _dl_hwcaps_subdirs_build_bitmask (subdirs_count, active); ++ ++active; ++ ++ /* POWER10. GCC defines __MMA__ for -mcpu=power10. */ ++ if ((GLRO (dl_hwcap2) & PPC_FEATURE2_ARCH_3_1) == 0 ++ || (GLRO (dl_hwcap2) & PPC_FEATURE2_MMA) == 0) ++ return _dl_hwcaps_subdirs_build_bitmask (subdirs_count, active); ++ ++active; ++ ++ return _dl_hwcaps_subdirs_build_bitmask (subdirs_count, active); ++} +diff --git a/sysdeps/powerpc/powerpc64/le/tst-glibc-hwcaps.c b/sysdeps/powerpc/powerpc64/le/tst-glibc-hwcaps.c +new file mode 100644 +index 0000000000000000..e510fca80a22aaeb +--- /dev/null ++++ b/sysdeps/powerpc/powerpc64/le/tst-glibc-hwcaps.c +@@ -0,0 +1,54 @@ ++/* glibc-hwcaps subdirectory test. powerpc64le 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, see ++ . */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++extern int marker2 (void); ++extern int marker3 (void); ++ ++/* Return the POWER level, 8 for the baseline. */ ++static int ++compute_level (void) ++{ ++ const char *platform = (const char *) getauxval (AT_PLATFORM); ++ if (strcmp (platform, "power8") == 0) ++ return 8; ++ if (strcmp (platform, "power9") == 0) ++ return 9; ++ if (strcmp (platform, "power10") == 0) ++ return 10; ++ printf ("warning: unrecognized AT_PLATFORM value: %s\n", platform); ++ /* Assume that the new platform supports POWER10. */ ++ return 10; ++} ++ ++static int ++do_test (void) ++{ ++ int level = compute_level (); ++ printf ("info: detected POWER level: %d\n", level); ++ TEST_COMPARE (marker2 (), MIN (level - 7, 2)); ++ TEST_COMPARE (marker3 (), MIN (level - 7, 3)); ++ return 0; ++} ++ ++#include diff --git a/SOURCES/glibc-rh1817513-125.patch b/SOURCES/glibc-rh1817513-125.patch new file mode 100644 index 0000000..648b205 --- /dev/null +++ b/SOURCES/glibc-rh1817513-125.patch @@ -0,0 +1,21 @@ +commit 0d4ed9d40efa84e8dc88e64cf337c8e95af7b045 +Author: Florian Weimer +Date: Wed Dec 9 18:56:14 2020 +0100 + + elf: Fix incorrect comparison in sort_priorities_by_name + + Reported-By: Stefan Liebler + +diff --git a/elf/dl-hwcaps.c b/elf/dl-hwcaps.c +index 098173a84c43c1fd..50d764ae8707f46d 100644 +--- a/elf/dl-hwcaps.c ++++ b/elf/dl-hwcaps.c +@@ -153,7 +153,7 @@ sort_priorities_by_name (void) + else + to_compare = previous->name_length; + int cmp = memcmp (current->name, previous->name, to_compare); +- if (cmp >= 0 ++ if (cmp > 0 + || (cmp == 0 && current->name_length >= previous->name_length)) + break; + diff --git a/SOURCES/glibc-rh1817513-126.patch b/SOURCES/glibc-rh1817513-126.patch new file mode 100644 index 0000000..6d04ee2 --- /dev/null +++ b/SOURCES/glibc-rh1817513-126.patch @@ -0,0 +1,25 @@ +commit 1bb8d05b9c751f6909e85ee96f6c78d536987bfd +Author: Florian Weimer +Date: Thu Dec 10 12:24:53 2020 +0100 + + elf: Fix run-time dependencies of tst-dlopen-fail-2 + + The misattributed dependencies can cause failures in parallel testing + if the dependencies have not been built yet. + + Fixes commit a332bd1518af518c984fad73eba6f46dc5b2b2d4 + ("elf: Add elf/tst-dlopenfail-2 [BZ #25396]"). + +diff --git a/elf/Makefile b/elf/Makefile +index 57e3a8982297f79a..63c61ad63677ec63 100644 +--- a/elf/Makefile ++++ b/elf/Makefile +@@ -1655,7 +1655,7 @@ $(objpfx)tst-dlopenfailmod1.so: \ + LDFLAGS-tst-dlopenfaillinkmod.so = -Wl,-soname,tst-dlopenfail-missingmod.so + $(objpfx)tst-dlopenfailmod2.so: $(shared-thread-library) + $(objpfx)tst-dlopenfail-2: $(libdl) +-$(objpfx)tst-dlopenfail.out: \ ++$(objpfx)tst-dlopenfail-2.out: \ + $(objpfx)tst-dlopenfailmod1.so $(objpfx)tst-dlopenfailmod2.so \ + $(objpfx)tst-dlopenfailmod3.so + diff --git a/SOURCES/glibc-rh1817513-127.patch b/SOURCES/glibc-rh1817513-127.patch new file mode 100644 index 0000000..892276f --- /dev/null +++ b/SOURCES/glibc-rh1817513-127.patch @@ -0,0 +1,241 @@ +commit fdf8fbca455ca3ef57235bde907bcc6a624ac5aa +Author: Florian Weimer +Date: Thu Dec 10 13:51:18 2020 +0100 + + s390x: Add glibc-hwcaps support + + Subdirectories z13, z14, z15 can be selected, mostly based on the + level of support for vector instructions. + + Co-Authored-By: Stefan Liebler + +diff --git a/elf/Makefile b/elf/Makefile +index 63c61ad63677ec63..67029930dd2cb461 100644 +--- a/elf/Makefile ++++ b/elf/Makefile +@@ -1751,7 +1751,7 @@ $(objpfx)argv0test.out: tst-rtld-argv0.sh $(objpfx)ld.so \ + # glibc-hwcaps mechanism for this architecture). Used to obtain test + # coverage for some glibc-hwcaps tests for the widest possible range + # of systems. +-glibc-hwcaps-first-subdirs-for-tests = power9 x86-64-v2 ++glibc-hwcaps-first-subdirs-for-tests = power9 x86-64-v2 z13 + + # The test modules are parameterized by preprocessor macros. + LDFLAGS-libmarkermod1-1.so += -Wl,-soname,libmarkermod1.so +diff --git a/elf/tst-glibc-hwcaps-cache.script b/elf/tst-glibc-hwcaps-cache.script +index 6a4675f9bd30e02f..c3271f61f9e50f2e 100644 +--- a/elf/tst-glibc-hwcaps-cache.script ++++ b/elf/tst-glibc-hwcaps-cache.script +@@ -11,6 +11,16 @@ mkdirp 0770 $L/glibc-hwcaps/power10 + cp $B/elf/libmarkermod3-2.so $L/glibc-hwcaps/power9/libmarkermod3.so + cp $B/elf/libmarkermod3-3.so $L/glibc-hwcaps/power10/libmarkermod3.so + ++mkdirp 0770 $L/glibc-hwcaps/z13 ++cp $B/elf/libmarkermod2-2.so $L/glibc-hwcaps/z13/libmarkermod2.so ++mkdirp 0770 $L/glibc-hwcaps/z14 ++cp $B/elf/libmarkermod3-2.so $L/glibc-hwcaps/z13/libmarkermod3.so ++cp $B/elf/libmarkermod3-3.so $L/glibc-hwcaps/z14/libmarkermod3.so ++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/x86-64-v2 + cp $B/elf/libmarkermod2-2.so $L/glibc-hwcaps/x86-64-v2/libmarkermod2.so + mkdirp 0770 $L/glibc-hwcaps/x86-64-v3 +diff --git a/sysdeps/s390/s390-64/Makefile b/sysdeps/s390/s390-64/Makefile +index b4d793bb3dd1f703..e5da26871c862e63 100644 +--- a/sysdeps/s390/s390-64/Makefile ++++ b/sysdeps/s390/s390-64/Makefile +@@ -6,4 +6,43 @@ ifeq ($(subdir),elf) + CFLAGS-rtld.c += -Wno-uninitialized -Wno-unused + 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.out: \ ++ $(objpfx)libmarkermod2.so \ ++ $(objpfx)glibc-hwcaps/z13/libmarkermod2.so \ ++ $(objpfx)libmarkermod3.so \ ++ $(objpfx)glibc-hwcaps/z13/libmarkermod3.so \ ++ $(objpfx)glibc-hwcaps/z14/libmarkermod3.so \ ++ $(objpfx)libmarkermod4.so \ ++ $(objpfx)glibc-hwcaps/z13/libmarkermod4.so \ ++ $(objpfx)glibc-hwcaps/z14/libmarkermod4.so \ ++ $(objpfx)glibc-hwcaps/z15/libmarkermod4.so \ ++ ++$(objpfx)glibc-hwcaps/z13/libmarkermod2.so: $(objpfx)libmarkermod2-2.so ++ $(make-target-directory) ++ cp $< $@ ++$(objpfx)glibc-hwcaps/z13/libmarkermod3.so: $(objpfx)libmarkermod3-2.so ++ $(make-target-directory) ++ cp $< $@ ++$(objpfx)glibc-hwcaps/z14/libmarkermod3.so: $(objpfx)libmarkermod3-3.so ++ $(make-target-directory) ++ cp $< $@ ++$(objpfx)glibc-hwcaps/z13/libmarkermod4.so: $(objpfx)libmarkermod4-2.so ++ $(make-target-directory) ++ cp $< $@ ++$(objpfx)glibc-hwcaps/z14/libmarkermod4.so: $(objpfx)libmarkermod4-3.so ++ $(make-target-directory) ++ cp $< $@ ++$(objpfx)glibc-hwcaps/z15/libmarkermod4.so: $(objpfx)libmarkermod4-4.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 ++# interferes with its test objectives. ++tests-container += tst-glibc-hwcaps-cache + endif ++ ++endif # $(subdir) == elf +diff --git a/sysdeps/s390/s390-64/dl-hwcaps-subdirs.c b/sysdeps/s390/s390-64/dl-hwcaps-subdirs.c +new file mode 100644 +index 0000000000000000..3673808a458350ad +--- /dev/null ++++ b/sysdeps/s390/s390-64/dl-hwcaps-subdirs.c +@@ -0,0 +1,54 @@ ++/* Architecture-specific glibc-hwcaps subdirectories. s390x 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, see ++ . */ ++ ++#include ++#include ++ ++const char _dl_hwcaps_subdirs[] = "z15:z14:z13"; ++enum { subdirs_count = 3 }; /* Number of components in _dl_hwcaps_subdirs. */ ++ ++uint32_t ++_dl_hwcaps_subdirs_active (void) ++{ ++ int active = 0; ++ ++ /* Test in reverse preference order. */ ++ ++ /* z13. */ ++ if (!(GLRO (dl_hwcap) & HWCAP_S390_VX)) ++ return _dl_hwcaps_subdirs_build_bitmask (subdirs_count, active); ++ ++active; ++ ++ /* z14. */ ++ if (!((GLRO (dl_hwcap) & HWCAP_S390_VXD) ++ && (GLRO (dl_hwcap) & HWCAP_S390_VXE) ++ && (GLRO (dl_hwcap) & HWCAP_S390_GS))) ++ return _dl_hwcaps_subdirs_build_bitmask (subdirs_count, active); ++ ++active; ++ ++ /* z15. ++ Note: We do not list HWCAP_S390_SORT and HWCAP_S390_DFLT here as, ++ according to the Principles of Operation, those may be replaced or removed ++ in future. */ ++ if (!((GLRO (dl_hwcap) & HWCAP_S390_VXRS_EXT2) ++ && (GLRO (dl_hwcap) & HWCAP_S390_VXRS_PDE))) ++ return _dl_hwcaps_subdirs_build_bitmask (subdirs_count, active); ++ ++active; ++ ++ return _dl_hwcaps_subdirs_build_bitmask (subdirs_count, active); ++} +diff --git a/sysdeps/s390/s390-64/tst-glibc-hwcaps.c b/sysdeps/s390/s390-64/tst-glibc-hwcaps.c +new file mode 100644 +index 0000000000000000..690f0d5fab36eb59 +--- /dev/null ++++ b/sysdeps/s390/s390-64/tst-glibc-hwcaps.c +@@ -0,0 +1,82 @@ ++/* glibc-hwcaps subdirectory test. s390x 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, see ++ . */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++extern int marker2 (void); ++extern int marker3 (void); ++extern int marker4 (void); ++ ++/* Return the arch level, 10 for the baseline libmarkermod*.so's. */ ++static int ++compute_level (void) ++{ ++ const char *platform = (const char *) getauxval (AT_PLATFORM); ++ ++ /* The arch* versions refer to the edition of the Principles of ++ Operation, and they are off by two when compared with the recent ++ product names. (The code below should not be considered an ++ accurate mapping to Principles of Operation editions for earlier ++ AT_PLATFORM strings). */ ++ if (strcmp (platform, "z900") == 0) ++ return 10; ++ if (strcmp (platform, "z990") == 0) ++ return 10; ++ if (strcmp (platform, "z9-109") == 0) ++ return 10; ++ if (strcmp (platform, "z10") == 0) ++ return 10; ++ if (strcmp (platform, "z196") == 0) ++ return 10; ++ if (strcmp (platform, "zEC12") == 0) ++ return 10; ++ ++ /* If we are running on z13 or newer and the kernel was booted with novx, ++ then AT_PLATFORM is z13 or newer, but _dl_hwcaps_subdirs_active will ++ return zero and the _dl_hwcaps_subdirs are not searched. */ ++ const unsigned long int hwcap = getauxval (AT_HWCAP); ++ if ((hwcap & HWCAP_S390_VX) == 0) ++ return 10; ++ ++ if (strcmp (platform, "z13") == 0) ++ return 11; ++ if (strcmp (platform, "z14") == 0) ++ return 12; ++ if (strcmp (platform, "z15") == 0) ++ return 13; ++ printf ("warning: unrecognized AT_PLATFORM value: %s\n", platform); ++ /* Assume that the new platform supports z15. */ ++ return 13; ++} ++ ++static int ++do_test (void) ++{ ++ int level = compute_level (); ++ printf ("info: detected architecture level: arch%d\n", level); ++ TEST_COMPARE (marker2 (), MIN (level - 9, 2)); ++ TEST_COMPARE (marker3 (), MIN (level - 9, 3)); ++ TEST_COMPARE (marker4 (), MIN (level - 9, 4)); ++ return 0; ++} ++ ++#include diff --git a/SOURCES/glibc-rh1817513-128.patch b/SOURCES/glibc-rh1817513-128.patch new file mode 100644 index 0000000..a6a4106 --- /dev/null +++ b/SOURCES/glibc-rh1817513-128.patch @@ -0,0 +1,83 @@ +commit 97476447edff96e526daa1a22d6ed3665181ff93 +Author: DJ Delorie +Date: Wed Oct 23 17:52:26 2019 -0400 + + Install charmaps uncompressed in testroot + + The testroot does not have a gunzip command, so the charmap files + should not be installed gzipped else they cannot be used (and thus + tested). With this patch, installing with INSTALL_UNCOMPRESSED=yes + installs uncompressed charmaps instead. + + Note that we must purge the $(symbolic_link_list) as it contains + references to $(DESTDIR), which we change during the testroot + installation. + + Reviewed-by: Carlos O'Donell + +diff --git a/Makefile b/Makefile +index 3748d6f7cfb6223b..6d73241bbc811c13 100644 +--- a/Makefile ++++ b/Makefile +@@ -398,8 +398,15 @@ ifeq ($(run-built-tests),yes) + $(test-wrapper) cp $$dso $(objpfx)testroot.pristine$$dso ;\ + done + endif ++ # $(symbolic-link-list) is a file that encodes $(DESTDIR) so we ++ # have to purge it ++ rm -f $(symbolic-link-list) ++ # Setting INSTALL_UNCOMPRESSED causes localedata/Makefile to ++ # install the charmaps uncompressed, as the testroot does not ++ # provide a gunzip program. + $(MAKE) install DESTDIR=$(objpfx)testroot.pristine \ +- subdirs='$(sorted-subdirs)' ++ INSTALL_UNCOMPRESSED=yes subdirs='$(sorted-subdirs)' ++ rm -f $(symbolic-link-list) + touch $(objpfx)testroot.pristine/install.stamp + + tests-special-notdir = $(patsubst $(objpfx)%, %, $(tests-special)) +diff --git a/localedata/Makefile b/localedata/Makefile +index 0fed95dcae6a9183..14fcc37fed21e740 100644 +--- a/localedata/Makefile ++++ b/localedata/Makefile +@@ -167,9 +167,17 @@ endif + endif + + # Files to install. ++ifeq ($(INSTALL_UNCOMPRESSED),yes) ++# This option is for testing inside the testroot container, as the ++# container does not include a working gunzip program. ++install-others := $(addprefix $(inst_i18ndir)/, \ ++ $(charmaps) \ ++ $(locales)) ++else + install-others := $(addprefix $(inst_i18ndir)/, \ + $(addsuffix .gz, $(charmaps)) \ + $(locales)) ++endif + + tests: $(objdir)/iconvdata/gconv-modules + +@@ -282,12 +290,22 @@ endif + + include ../Rules + ++ifeq ($(INSTALL_UNCOMPRESSED),yes) ++# Install the charmap files as-is. This option is for testing inside ++# the testroot container, as the container does not include a working ++# gunzip program. ++$(inst_i18ndir)/charmaps/%: charmaps/% $(+force) ++ $(make-target-directory) ++ rm -f $@ ++ $(INSTALL_DATA) $< $@ ++else + # Install the charmap files in gzipped format. + $(inst_i18ndir)/charmaps/%.gz: charmaps/% $(+force) + $(make-target-directory) + rm -f $(@:.gz=) $@ + $(INSTALL_DATA) $< $(@:.gz=) + gzip -9n $(@:.gz=) ++endif + + # Install the locale source files in the appropriate directory. + $(inst_i18ndir)/locales/%: locales/% $(+force); $(do-install) diff --git a/SOURCES/glibc-rh1817513-129.patch b/SOURCES/glibc-rh1817513-129.patch new file mode 100644 index 0000000..b34711e --- /dev/null +++ b/SOURCES/glibc-rh1817513-129.patch @@ -0,0 +1,121 @@ +commit de42613540de8d3d70b5f14a14923cab7bd694d0 +Author: Florian Weimer +Date: Mon May 25 18:17:27 2020 +0200 + + elf: Turn _dl_printf, _dl_error_printf, _dl_fatal_printf into functions + + This change makes it easier to set a breakpoint on these calls. + + This also addresses the issue that including without + does not result usable _dl_*printf macros because of the + use of the STD*_FILENO macros there. + + (The private symbol for _dl_fatal_printf will go away again + once the exception handling implementation is unified between + libc and ld.so.) + + Reviewed-by: Adhemerval Zanella + +diff --git a/elf/Versions b/elf/Versions +index 3be879c4adfa74c7..be88c48e6d45a937 100644 +--- a/elf/Versions ++++ b/elf/Versions +@@ -58,7 +58,7 @@ ld { + _dl_allocate_tls; _dl_allocate_tls_init; + _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_rtld_di_serinfo; _dl_starting_up; _dl_fatal_printf; + _rtld_global; _rtld_global_ro; + + # Only here for gdb while a better method is developed. +diff --git a/elf/dl-misc.c b/elf/dl-misc.c +index 3f28de3ee9d68368..508630e444d2a00c 100644 +--- a/elf/dl-misc.c ++++ b/elf/dl-misc.c +@@ -302,6 +302,37 @@ _dl_dprintf (int fd, const char *fmt, ...) + va_end (arg); + } + ++void ++_dl_printf (const char *fmt, ...) ++{ ++ va_list arg; ++ ++ va_start (arg, fmt); ++ _dl_debug_vdprintf (STDOUT_FILENO, 0, fmt, arg); ++ va_end (arg); ++} ++ ++void ++_dl_error_printf (const char *fmt, ...) ++{ ++ va_list arg; ++ ++ va_start (arg, fmt); ++ _dl_debug_vdprintf (STDERR_FILENO, 0, fmt, arg); ++ va_end (arg); ++} ++ ++void ++_dl_fatal_printf (const char *fmt, ...) ++{ ++ va_list arg; ++ ++ va_start (arg, fmt); ++ _dl_debug_vdprintf (STDERR_FILENO, 0, fmt, arg); ++ va_end (arg); ++ _exit (127); ++} ++rtld_hidden_def (_dl_fatal_printf) + + /* Test whether given NAME matches any of the names of the given object. */ + int +diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h +index 77923499d3de4366..6cbbaa808a596f77 100644 +--- a/sysdeps/generic/ldsodefs.h ++++ b/sysdeps/generic/ldsodefs.h +@@ -762,24 +762,19 @@ ssize_t _dl_write (int fd, const void *buffer, size_t length) + + /* Write a message on the specified descriptor standard output. The + parameters are interpreted as for a `printf' call. */ +-#define _dl_printf(fmt, args...) \ +- _dl_dprintf (STDOUT_FILENO, fmt, ##args) ++void _dl_printf (const char *fmt, ...) ++ attribute_hidden __attribute__ ((__format__ (__printf__, 1, 2))); + + /* Write a message on the specified descriptor standard error. The + parameters are interpreted as for a `printf' call. */ +-#define _dl_error_printf(fmt, args...) \ +- _dl_dprintf (STDERR_FILENO, fmt, ##args) ++void _dl_error_printf (const char *fmt, ...) ++ attribute_hidden __attribute__ ((__format__ (__printf__, 1, 2))); + + /* Write a message on the specified descriptor standard error and exit + the program. The parameters are interpreted as for a `printf' call. */ +-#define _dl_fatal_printf(fmt, args...) \ +- do \ +- { \ +- _dl_dprintf (STDERR_FILENO, fmt, ##args); \ +- _exit (127); \ +- } \ +- while (1) +- ++void _dl_fatal_printf (const char *fmt, ...) ++ __attribute__ ((__format__ (__printf__, 1, 2), __noreturn__)); ++rtld_hidden_proto (_dl_fatal_printf) + + /* An exception raised by the _dl_signal_error function family and + caught by _dl_catch_error function family. Exceptions themselves +diff --git a/sysdeps/mach/hurd/i386/localplt.data b/sysdeps/mach/hurd/i386/localplt.data +index 4b9dbf5acc088cff..eb79216e3b494486 100644 +--- a/sysdeps/mach/hurd/i386/localplt.data ++++ b/sysdeps/mach/hurd/i386/localplt.data +@@ -43,6 +43,7 @@ ld.so: _dl_allocate_tls_init + ld.so: _dl_exception_create + ld.so: _dl_exception_create_format + ld.so: _dl_exception_free ++ld.so: _dl_fatal_printf + ld.so: _dl_find_dso_for_object + ld.so: _dl_init_first + ld.so: _dl_mcount diff --git a/SOURCES/glibc-rh1817513-13.patch b/SOURCES/glibc-rh1817513-13.patch new file mode 100644 index 0000000..6267bb6 --- /dev/null +++ b/SOURCES/glibc-rh1817513-13.patch @@ -0,0 +1,199 @@ +commit a5275ba5378c9256d18e582572b4315e8edfcbfb +Author: H.J. Lu +Date: Thu Nov 29 14:15:01 2018 -0800 + + _dl_exception_create_format: Support %x/%lx/%zx + + Add support for %x, %lx and %zx to _dl_exception_create_format and pad + to the full width with 0. + + * elf/Makefile (tests-internal): Add tst-create_format1. + * elf/dl-exception.c (_dl_exception_create_format): Support + %x, %lx and %zx. + * elf/tst-create_format1.c: New file. + +Conflicts: + elf/Makefile + (Different backport order of tests.) + +diff --git a/elf/Makefile b/elf/Makefile +index 89dff92adfc417f5..6d1962b2e4deb871 100644 +--- a/elf/Makefile ++++ b/elf/Makefile +@@ -198,7 +198,8 @@ tests += restest1 preloadtest loadfail multiload origtest resolvfail \ + 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-ptrguard1 tst-stackguard1 tst-libc_dlvsym \ ++ tst-create_format1 + tests-container += tst-pldd + ifeq ($(build-hardcoded-path-in-tests),yes) + tests += tst-dlopen-aout +diff --git a/elf/dl-exception.c b/elf/dl-exception.c +index 1c63e4a3a65b6d55..1e41d89a7db52683 100644 +--- a/elf/dl-exception.c ++++ b/elf/dl-exception.c +@@ -111,6 +111,20 @@ _dl_exception_create_format (struct dl_exception *exception, const char *objname + case 's': + length += strlen (va_arg (ap, const char *)); + break; ++ /* Recognize the l modifier. It is only important on some ++ platforms where long and int have a different size. We ++ can use the same code for size_t. */ ++ case 'l': ++ case 'z': ++ if (p[1] == 'x') ++ { ++ length += LONG_WIDTH / 4; ++ ++p; ++ break; ++ } ++ case 'x': ++ length += INT_WIDTH / 4; ++ break; + default: + /* Assumed to be '%'. */ + ++length; +@@ -167,6 +181,32 @@ _dl_exception_create_format (struct dl_exception *exception, const char *objname + *wptr = '%'; + ++wptr; + break; ++ case 'x': ++ { ++ unsigned long int num = va_arg (ap, unsigned int); ++ char *start = wptr; ++ wptr += INT_WIDTH / 4; ++ char *cp = _itoa (num, wptr, 16, 0); ++ /* Pad to the full width with 0. */ ++ while (cp != start) ++ *--cp = '0'; ++ } ++ break; ++ case 'l': ++ case 'z': ++ if (p[1] == 'x') ++ { ++ unsigned long int num = va_arg (ap, unsigned long int); ++ char *start = wptr; ++ wptr += LONG_WIDTH / 4; ++ char *cp = _itoa (num, wptr, 16, 0); ++ /* Pad to the full width with 0. */ ++ while (cp != start) ++ *--cp = '0'; ++ ++p; ++ break; ++ } ++ /* FALLTHROUGH */ + default: + _dl_fatal_printf ("Fatal error:" + " invalid format in exception string\n"); +diff --git a/elf/tst-create_format1.c b/elf/tst-create_format1.c +new file mode 100644 +index 0000000000000000..8b9edfdc69ea4ced +--- /dev/null ++++ b/elf/tst-create_format1.c +@@ -0,0 +1,103 @@ ++/* Check _dl_exception_create_format. ++ 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 ++#include ++#include ++ ++#define TEST(es, objn, fmt, ...) \ ++ ({ \ ++ struct dl_exception exception; \ ++ _dl_exception_create_format (&exception, objn, fmt, __VA_ARGS__); \ ++ TEST_COMPARE_STRING (exception.objname, objn == NULL ? "" : objn); \ ++ TEST_COMPARE_STRING (exception.errstring, es); \ ++ _dl_exception_free (&exception); \ ++ }) ++ ++static void ++do_test_invalid_conversion (void *closure) ++{ ++ TEST ("(null)", NULL, "%p", NULL); ++} ++ ++/* Exit status after abnormal termination. */ ++static int invalid_status; ++ ++static void ++init_invalid_status (void) ++{ ++ pid_t pid = xfork (); ++ if (pid == 0) ++ _exit (127); ++ xwaitpid (pid, &invalid_status, 0); ++ if (WIFEXITED (invalid_status)) ++ invalid_status = WEXITSTATUS (invalid_status); ++} ++ ++static int ++do_test (void) ++{ ++ init_invalid_status (); ++ ++ TEST ("test", NULL, "%s", "test"); ++ TEST ("test-test", NULL, "%s-test", "test"); ++ TEST ("test", "test", "%s", "test"); ++ TEST ("test-test", "test", "%s-test", "test"); ++ ++ TEST ("test%", NULL, "%s%%", "test"); ++ TEST ("test%-test", NULL, "%s%%-test", "test"); ++ TEST ("test%", "test", "%s%%", "test"); ++ TEST ("test%-test", "test", "%s%%-test", "test"); ++ ++ TEST ("0000007b", NULL, "%x", 123); ++ TEST ("0000007b-test", NULL, "%x-test", 123); ++ TEST ("0000007b", "test", "%x", 123); ++ TEST ("0000007b-test", "test", "%x-test", 123); ++ ++#define TEST_LONG(es, objn, fmt, ...) \ ++ ({ \ ++ if (sizeof (int) == sizeof (long int)) \ ++ TEST (es, objn, fmt, __VA_ARGS__); \ ++ else \ ++ TEST ("ffffffff" es, objn, fmt, __VA_ARGS__); \ ++ }) ++ ++ TEST_LONG ("fffffffd", NULL, "%lx", (long int)~2ul); ++ TEST_LONG ("fffffffd-test", NULL, "%lx-test", (long int)~2ul); ++ TEST_LONG ("fffffffd", "test", "%lx", (long int)~2ul); ++ TEST_LONG ("fffffffd-test", "test", "%lx-test", (long int)~2ul); ++ ++ TEST_LONG ("fffffffe", NULL, "%zx", (size_t)~1ul); ++ TEST_LONG ("fffffffe-test", NULL, "%zx-test", (size_t)~1ul); ++ TEST_LONG ("fffffffe", "test", "%zx", (size_t)~1ul); ++ TEST_LONG ("fffffffe-test", "test", "%zx-test", (size_t)~1ul); ++ ++ struct support_capture_subprocess result; ++ result = support_capture_subprocess (do_test_invalid_conversion, NULL); ++ support_capture_subprocess_check (&result, "dl-exception", ++ invalid_status, sc_allow_stderr); ++ TEST_COMPARE_STRING (result.err.buffer, ++ "Fatal error: invalid format in exception string\n"); ++ ++ return 0; ++} ++ ++#include diff --git a/SOURCES/glibc-rh1817513-130.patch b/SOURCES/glibc-rh1817513-130.patch new file mode 100644 index 0000000..d06b247 --- /dev/null +++ b/SOURCES/glibc-rh1817513-130.patch @@ -0,0 +1,22 @@ +commit 8dddf0bd5a3d57fba8da27e93f3d1a7032fce184 +Author: Florian Weimer +Date: Wed Oct 30 17:44:09 2019 +0100 + + resolv/tst-idna_name_classify: Isolate from system libraries + + Loading NSS modules from static binaries uses installed system + libraries if LD_LIBRARY_PATH is not set. + +diff --git a/inet/Makefile b/inet/Makefile +index 7782913b4c06f057..62d25f853538bb08 100644 +--- a/inet/Makefile ++++ b/inet/Makefile +@@ -112,4 +112,8 @@ ifeq ($(build-static-nss),yes) + CFLAGS += -DSTATIC_NSS + endif + ++# The test uses dlopen indirectly and would otherwise load system ++# objects. ++tst-idna_name_classify-ENV = \ ++ LD_LIBRARY_PATH=$(objpfx):$(common-objpfx):$(common-objpfx)elf + $(objpfx)tst-idna_name_classify.out: $(gen-locales) diff --git a/SOURCES/glibc-rh1817513-131.patch b/SOURCES/glibc-rh1817513-131.patch new file mode 100644 index 0000000..7f650e5 --- /dev/null +++ b/SOURCES/glibc-rh1817513-131.patch @@ -0,0 +1,21 @@ +commit 880433de13fa31e52587720f81b762a6c7797e4e +Author: Florian Weimer +Date: Thu Dec 10 15:47:26 2020 +0100 + + elf: Include in cache.c + + The roundup macro is defined there. Relying on an indirect + definition is brittle. + +diff --git a/elf/cache.c b/elf/cache.c +index dde3d7fefa4105f9..fdfedb0964bcd217 100644 +--- a/elf/cache.c ++++ b/elf/cache.c +@@ -29,6 +29,7 @@ + #include + #include + #include ++#include + #include + #include + diff --git a/SOURCES/glibc-rh1817513-132.patch b/SOURCES/glibc-rh1817513-132.patch new file mode 100644 index 0000000..914292e --- /dev/null +++ b/SOURCES/glibc-rh1817513-132.patch @@ -0,0 +1,33 @@ +commit 2ee7711bdd7de9dd30073b223ce29d5cd50320f6 +Author: H.J. Lu +Date: Sun Dec 13 04:56:41 2020 -0800 + + x86: Remove the default REP MOVSB threshold tunable value [BZ #27061] + + Since we can't tell if the tunable value is set by user or not: + + https://sourceware.org/bugzilla/show_bug.cgi?id=27069 + + remove the default REP MOVSB threshold tunable value so that the correct + default value will be set correctly by init_cacheinfo (). + + Reviewed-by: Carlos O'Donell + +diff --git a/sysdeps/x86/dl-tunables.list b/sysdeps/x86/dl-tunables.list +index e066313a1d1dd009..89bf296626658900 100644 +--- a/sysdeps/x86/dl-tunables.list ++++ b/sysdeps/x86/dl-tunables.list +@@ -39,9 +39,11 @@ glibc { + # REP MOVSB. Since larger register size can move more data with a + # single load and store, the threshold is higher with larger register + # size. Note: Since the REP MOVSB threshold must be greater than 8 +- # times of vector size, the minium value must be updated at run-time. ++ # times of vector size and the default value is 2048 * (vector size ++ # / 16), the default value and the minimum value must be updated at ++ # run-time. NB: Don't set the default value since we can't tell if ++ # the tunable value is set by user or not [BZ #27069]. + minval: 1 +- default: 2048 + } + x86_rep_stosb_threshold { + type: SIZE_T diff --git a/SOURCES/glibc-rh1817513-133.patch b/SOURCES/glibc-rh1817513-133.patch new file mode 100644 index 0000000..a714822 --- /dev/null +++ b/SOURCES/glibc-rh1817513-133.patch @@ -0,0 +1,18 @@ +commit 8a30bb4e0604aefcf28f20360fc8ba8ef8604b9c +Author: Florian Weimer +Date: Wed Dec 23 12:07:20 2020 +0100 + + elf: Account for glibc-hwcaps/ prefix in _dl_important_hwcaps + +diff --git a/elf/dl-hwcaps.c b/elf/dl-hwcaps.c +index 50d764ae8707f46d..2fc4ae67a0f5d051 100644 +--- a/elf/dl-hwcaps.c ++++ b/elf/dl-hwcaps.c +@@ -192,6 +192,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) + + hwcaps_counts.total_length); + diff --git a/SOURCES/glibc-rh1817513-14.patch b/SOURCES/glibc-rh1817513-14.patch new file mode 100644 index 0000000..0186fde --- /dev/null +++ b/SOURCES/glibc-rh1817513-14.patch @@ -0,0 +1,22 @@ +commit ce7387cc250a408d3fbb7a6fff7ad4d977166b00 +Author: H.J. Lu +Date: Thu Nov 29 20:03:46 2018 -0800 + + elf/dl-exception.c: Include <_itoa.h> for _itoa prototype + + Tested with build-many-glibcs.py. + + * elf/dl-exception.c: Include <_itoa.h>. + +diff --git a/elf/dl-exception.c b/elf/dl-exception.c +index 1e41d89a7db52683..3e8e0ba3f1442005 100644 +--- a/elf/dl-exception.c ++++ b/elf/dl-exception.c +@@ -23,6 +23,7 @@ + #include + #include + #include ++#include <_itoa.h> + + /* This message we return as a last resort. We define the string in a + variable since we have to avoid freeing it and so have to enable diff --git a/SOURCES/glibc-rh1817513-15.patch b/SOURCES/glibc-rh1817513-15.patch new file mode 100644 index 0000000..d9ef9ef --- /dev/null +++ b/SOURCES/glibc-rh1817513-15.patch @@ -0,0 +1,1820 @@ +commit c22e4c2a1431c5e77bf4288d35bf7629f2f093aa +Author: H.J. Lu +Date: Mon Dec 3 05:54:43 2018 -0800 + + x86: Extend CPUID support in struct cpu_features + + Extend CPUID support for all feature bits from CPUID. Add a new macro, + CPU_FEATURE_USABLE, which can be used to check if a feature is usable at + run-time, instead of HAS_CPU_FEATURE and HAS_ARCH_FEATURE. + + Add COMMON_CPUID_INDEX_D_ECX_1, COMMON_CPUID_INDEX_80000007 and + COMMON_CPUID_INDEX_80000008 to check CPU feature bits in them. + + Tested on i686 and x86-64 as well as using build-many-glibcs.py with + x86 targets. + + * sysdeps/x86/cacheinfo.c (intel_check_word): Updated for + cpu_features_basic. + (__cache_sysconf): Likewise. + (init_cacheinfo): Likewise. + * sysdeps/x86/cpu-features.c (get_extended_indeces): Also + populate COMMON_CPUID_INDEX_80000007 and + COMMON_CPUID_INDEX_80000008. + (get_common_indices): Also populate COMMON_CPUID_INDEX_D_ECX_1. + Use CPU_FEATURES_CPU_P (cpu_features, XSAVEC) to check if + XSAVEC is available. Set the bit_arch_XXX_Usable bits. + (init_cpu_features): Use _Static_assert on + index_arch_Fast_Unaligned_Load. + __get_cpuid_registers and __get_arch_feature. Updated for + cpu_features_basic. Set stepping in cpu_features. + * sysdeps/x86/cpu-features.h: (FEATURE_INDEX_1): Changed to enum. + (FEATURE_INDEX_2): New. + (FEATURE_INDEX_MAX): Changed to enum. + (COMMON_CPUID_INDEX_D_ECX_1): New. + (COMMON_CPUID_INDEX_80000007): Likewise. + (COMMON_CPUID_INDEX_80000008): Likewise. + (cpuid_registers): Likewise. + (cpu_features_basic): Likewise. + (CPU_FEATURE_USABLE): Likewise. + (bit_arch_XXX_Usable): Likewise. + (cpu_features): Use cpuid_registers and cpu_features_basic. + (bit_arch_XXX): Reweritten. + (bit_cpu_XXX): Likewise. + (index_cpu_XXX): Likewise. + (reg_XXX): Likewise. + * sysdeps/x86/tst-get-cpu-features.c: Include and + . + (CHECK_CPU_FEATURE): New. + (CHECK_CPU_FEATURE_USABLE): Likewise. + (cpu_kinds): Likewise. + (do_test): Print vendor, family, model and stepping. Check + HAS_CPU_FEATURE and CPU_FEATURE_USABLE. + (TEST_FUNCTION): Removed. + Include instead of + "../../test-skeleton.c". + * sysdeps/x86_64/multiarch/sched_cpucount.c (__sched_cpucount): + Check POPCNT instead of POPCOUNT. + * sysdeps/x86_64/multiarch/test-multiarch.c (do_test): Likewise. + +Backport difference: Adjustments to previous cache sizing +backports (which happened later upstream). + +diff --git a/sysdeps/x86/cacheinfo.c b/sysdeps/x86/cacheinfo.c +index 57c36d030a76c8b2..f1125f30223f5ca3 100644 +--- a/sysdeps/x86/cacheinfo.c ++++ b/sysdeps/x86/cacheinfo.c +@@ -205,8 +205,8 @@ intel_check_word (int name, unsigned int value, bool *has_level_2, + /* Intel reused this value. For family 15, model 6 it + specifies the 3rd level cache. Otherwise the 2nd + level cache. */ +- unsigned int family = cpu_features->family; +- unsigned int model = cpu_features->model; ++ unsigned int family = cpu_features->basic.family; ++ unsigned int model = cpu_features->basic.model; + + if (family == 15 && model == 6) + { +@@ -258,7 +258,7 @@ intel_check_word (int name, unsigned int value, bool *has_level_2, + static long int __attribute__ ((noinline)) + handle_intel (int name, const struct cpu_features *cpu_features) + { +- unsigned int maxidx = cpu_features->max_cpuid; ++ unsigned int maxidx = cpu_features->basic.max_cpuid; + + /* Return -1 for older CPUs. */ + if (maxidx < 2) +@@ -443,10 +443,10 @@ __cache_sysconf (int name) + { + const struct cpu_features *cpu_features = __get_cpu_features (); + +- if (cpu_features->kind == arch_kind_intel) ++ if (cpu_features->basic.kind == arch_kind_intel) + return handle_intel (name, cpu_features); + +- if (cpu_features->kind == arch_kind_amd) ++ if (cpu_features->basic.kind == arch_kind_amd) + return handle_amd (name); + + // XXX Fill in more vendors. +@@ -497,9 +497,9 @@ init_cacheinfo (void) + unsigned int level; + unsigned int threads = 0; + const struct cpu_features *cpu_features = __get_cpu_features (); +- int max_cpuid = cpu_features->max_cpuid; ++ int max_cpuid = cpu_features->basic.max_cpuid; + +- if (cpu_features->kind == arch_kind_intel) ++ if (cpu_features->basic.kind == arch_kind_intel) + { + data = handle_intel (_SC_LEVEL1_DCACHE_SIZE, cpu_features); + +@@ -538,8 +538,8 @@ init_cacheinfo (void) + highest cache level. */ + if (max_cpuid >= 4) + { +- unsigned int family = cpu_features->family; +- unsigned int model = cpu_features->model; ++ unsigned int family = cpu_features->basic.family; ++ unsigned int model = cpu_features->basic.model; + + int i = 0; + +@@ -700,7 +700,7 @@ intel_bug_no_cache_info: + shared += core; + } + } +- else if (cpu_features->kind == arch_kind_amd) ++ else if (cpu_features->basic.kind == arch_kind_amd) + { + data = handle_amd (_SC_LEVEL1_DCACHE_SIZE); + long int core = handle_amd (_SC_LEVEL2_CACHE_SIZE); +@@ -722,7 +722,7 @@ intel_bug_no_cache_info: + threads = 1 << ((ecx >> 12) & 0x0f); + } + +- if (threads == 0 || cpu_features->family >= 0x17) ++ if (threads == 0 || cpu_features->basic.family >= 0x17) + { + /* If APIC ID width is not available, use logical + processor count. */ +@@ -738,7 +738,7 @@ intel_bug_no_cache_info: + shared /= threads; + + /* Get shared cache per ccx for Zen architectures. */ +- if (cpu_features->family >= 0x17) ++ if (cpu_features->basic.family >= 0x17) + { + unsigned int eax; + +diff --git a/sysdeps/x86/cpu-features.c b/sysdeps/x86/cpu-features.c +index 3b268efbce627e6c..3a02a9c7d08f9603 100644 +--- a/sysdeps/x86/cpu-features.c ++++ b/sysdeps/x86/cpu-features.c +@@ -52,7 +52,18 @@ get_extended_indices (struct cpu_features *cpu_features) + cpu_features->cpuid[COMMON_CPUID_INDEX_80000001].ebx, + cpu_features->cpuid[COMMON_CPUID_INDEX_80000001].ecx, + cpu_features->cpuid[COMMON_CPUID_INDEX_80000001].edx); +- ++ if (eax >= 0x80000007) ++ __cpuid (0x80000007, ++ cpu_features->cpuid[COMMON_CPUID_INDEX_80000007].eax, ++ cpu_features->cpuid[COMMON_CPUID_INDEX_80000007].ebx, ++ cpu_features->cpuid[COMMON_CPUID_INDEX_80000007].ecx, ++ cpu_features->cpuid[COMMON_CPUID_INDEX_80000007].edx); ++ if (eax >= 0x80000008) ++ __cpuid (0x80000008, ++ cpu_features->cpuid[COMMON_CPUID_INDEX_80000008].eax, ++ cpu_features->cpuid[COMMON_CPUID_INDEX_80000008].ebx, ++ cpu_features->cpuid[COMMON_CPUID_INDEX_80000008].ecx, ++ cpu_features->cpuid[COMMON_CPUID_INDEX_80000008].edx); + } + + static void +@@ -78,13 +89,20 @@ get_common_indices (struct cpu_features *cpu_features, + } + } + +- if (cpu_features->max_cpuid >= 7) ++ if (cpu_features->basic.max_cpuid >= 7) + __cpuid_count (7, 0, + cpu_features->cpuid[COMMON_CPUID_INDEX_7].eax, + cpu_features->cpuid[COMMON_CPUID_INDEX_7].ebx, + cpu_features->cpuid[COMMON_CPUID_INDEX_7].ecx, + cpu_features->cpuid[COMMON_CPUID_INDEX_7].edx); + ++ if (cpu_features->basic.max_cpuid >= 0xd) ++ __cpuid_count (0xd, 1, ++ cpu_features->cpuid[COMMON_CPUID_INDEX_D_ECX_1].eax, ++ cpu_features->cpuid[COMMON_CPUID_INDEX_D_ECX_1].ebx, ++ cpu_features->cpuid[COMMON_CPUID_INDEX_D_ECX_1].ecx, ++ cpu_features->cpuid[COMMON_CPUID_INDEX_D_ECX_1].edx); ++ + /* Can we call xgetbv? */ + if (CPU_FEATURES_CPU_P (cpu_features, OSXSAVE)) + { +@@ -116,6 +134,18 @@ get_common_indices (struct cpu_features *cpu_features, + if (CPU_FEATURES_CPU_P (cpu_features, FMA)) + cpu_features->feature[index_arch_FMA_Usable] + |= bit_arch_FMA_Usable; ++ /* Determine if VAES is usable. */ ++ if (CPU_FEATURES_CPU_P (cpu_features, VAES)) ++ cpu_features->feature[index_arch_VAES_Usable] ++ |= bit_arch_VAES_Usable; ++ /* Determine if VPCLMULQDQ is usable. */ ++ if (CPU_FEATURES_CPU_P (cpu_features, VPCLMULQDQ)) ++ cpu_features->feature[index_arch_VPCLMULQDQ_Usable] ++ |= bit_arch_VPCLMULQDQ_Usable; ++ /* Determine if XOP is usable. */ ++ if (CPU_FEATURES_CPU_P (cpu_features, XOP)) ++ cpu_features->feature[index_arch_XOP_Usable] ++ |= bit_arch_XOP_Usable; + } + + /* Check if OPMASK state, upper 256-bit of ZMM0-ZMM15 and +@@ -129,17 +159,69 @@ get_common_indices (struct cpu_features *cpu_features, + { + cpu_features->feature[index_arch_AVX512F_Usable] + |= bit_arch_AVX512F_Usable; ++ /* Determine if AVX512CD is usable. */ ++ if (CPU_FEATURES_CPU_P (cpu_features, AVX512CD)) ++ cpu_features->feature[index_arch_AVX512CD_Usable] ++ |= bit_arch_AVX512CD_Usable; ++ /* Determine if AVX512ER is usable. */ ++ if (CPU_FEATURES_CPU_P (cpu_features, AVX512ER)) ++ cpu_features->feature[index_arch_AVX512ER_Usable] ++ |= bit_arch_AVX512ER_Usable; ++ /* Determine if AVX512PF is usable. */ ++ if (CPU_FEATURES_CPU_P (cpu_features, AVX512PF)) ++ cpu_features->feature[index_arch_AVX512PF_Usable] ++ |= bit_arch_AVX512PF_Usable; ++ /* Determine if AVX512VL is usable. */ ++ if (CPU_FEATURES_CPU_P (cpu_features, AVX512VL)) ++ cpu_features->feature[index_arch_AVX512VL_Usable] ++ |= bit_arch_AVX512VL_Usable; + /* Determine if AVX512DQ is usable. */ + if (CPU_FEATURES_CPU_P (cpu_features, AVX512DQ)) + cpu_features->feature[index_arch_AVX512DQ_Usable] + |= bit_arch_AVX512DQ_Usable; ++ /* Determine if AVX512BW is usable. */ ++ if (CPU_FEATURES_CPU_P (cpu_features, AVX512BW)) ++ cpu_features->feature[index_arch_AVX512BW_Usable] ++ |= bit_arch_AVX512BW_Usable; ++ /* Determine if AVX512_4FMAPS is usable. */ ++ if (CPU_FEATURES_CPU_P (cpu_features, AVX512_4FMAPS)) ++ cpu_features->feature[index_arch_AVX512_4FMAPS_Usable] ++ |= bit_arch_AVX512_4FMAPS_Usable; ++ /* Determine if AVX512_4VNNIW is usable. */ ++ if (CPU_FEATURES_CPU_P (cpu_features, AVX512_4VNNIW)) ++ cpu_features->feature[index_arch_AVX512_4VNNIW_Usable] ++ |= bit_arch_AVX512_4VNNIW_Usable; ++ /* Determine if AVX512_BITALG is usable. */ ++ if (CPU_FEATURES_CPU_P (cpu_features, AVX512_BITALG)) ++ cpu_features->feature[index_arch_AVX512_BITALG_Usable] ++ |= bit_arch_AVX512_BITALG_Usable; ++ /* Determine if AVX512_IFMA is usable. */ ++ if (CPU_FEATURES_CPU_P (cpu_features, AVX512_IFMA)) ++ cpu_features->feature[index_arch_AVX512_IFMA_Usable] ++ |= bit_arch_AVX512_IFMA_Usable; ++ /* Determine if AVX512_VBMI is usable. */ ++ if (CPU_FEATURES_CPU_P (cpu_features, AVX512_VBMI)) ++ cpu_features->feature[index_arch_AVX512_VBMI_Usable] ++ |= bit_arch_AVX512_VBMI_Usable; ++ /* Determine if AVX512_VBMI2 is usable. */ ++ if (CPU_FEATURES_CPU_P (cpu_features, AVX512_VBMI2)) ++ cpu_features->feature[index_arch_AVX512_VBMI2_Usable] ++ |= bit_arch_AVX512_VBMI2_Usable; ++ /* Determine if is AVX512_VNNI usable. */ ++ if (CPU_FEATURES_CPU_P (cpu_features, AVX512_VNNI)) ++ cpu_features->feature[index_arch_AVX512_VNNI_Usable] ++ |= bit_arch_AVX512_VNNI_Usable; ++ /* Determine if AVX512_VPOPCNTDQ is usable. */ ++ if (CPU_FEATURES_CPU_P (cpu_features, AVX512_VPOPCNTDQ)) ++ cpu_features->feature[index_arch_AVX512_VPOPCNTDQ_Usable] ++ |= bit_arch_AVX512_VPOPCNTDQ_Usable; + } + } + } + + /* For _dl_runtime_resolve, set xsave_state_size to xsave area + size + integer register save size and align it to 64 bytes. */ +- if (cpu_features->max_cpuid >= 0xd) ++ if (cpu_features->basic.max_cpuid >= 0xd) + { + unsigned int eax, ebx, ecx, edx; + +@@ -154,10 +236,8 @@ get_common_indices (struct cpu_features *cpu_features, + cpu_features->xsave_state_full_size + = xsave_state_full_size; + +- __cpuid_count (0xd, 1, eax, ebx, ecx, edx); +- + /* Check if XSAVEC is available. */ +- if ((eax & (1 << 1)) != 0) ++ if (CPU_FEATURES_CPU_P (cpu_features, XSAVEC)) + { + unsigned int xstate_comp_offsets[32]; + unsigned int xstate_comp_sizes[32]; +@@ -209,12 +289,25 @@ get_common_indices (struct cpu_features *cpu_features, + } + } + ++_Static_assert (((index_arch_Fast_Unaligned_Load ++ == index_arch_Fast_Unaligned_Copy) ++ && (index_arch_Fast_Unaligned_Load ++ == index_arch_Prefer_PMINUB_for_stringop) ++ && (index_arch_Fast_Unaligned_Load ++ == index_arch_Slow_SSE4_2) ++ && (index_arch_Fast_Unaligned_Load ++ == index_arch_Fast_Rep_String) ++ && (index_arch_Fast_Unaligned_Load ++ == index_arch_Fast_Copy_Backward)), ++ "Incorrect index_arch_Fast_Unaligned_Load"); ++ + static inline void + init_cpu_features (struct cpu_features *cpu_features) + { + unsigned int ebx, ecx, edx; + unsigned int family = 0; + unsigned int model = 0; ++ unsigned int stepping = 0; + enum cpu_features_kind kind; + + #if !HAS_CPUID +@@ -225,12 +318,12 @@ init_cpu_features (struct cpu_features *cpu_features) + } + #endif + +- __cpuid (0, cpu_features->max_cpuid, ebx, ecx, edx); ++ __cpuid (0, cpu_features->basic.max_cpuid, ebx, ecx, edx); + + /* This spells out "GenuineIntel". */ + if (ebx == 0x756e6547 && ecx == 0x6c65746e && edx == 0x49656e69) + { +- unsigned int extended_model, stepping; ++ unsigned int extended_model; + + kind = arch_kind_intel; + +@@ -269,15 +362,6 @@ init_cpu_features (struct cpu_features *cpu_features) + case 0x5d: + /* Unaligned load versions are faster than SSSE3 + on Silvermont. */ +-#if index_arch_Fast_Unaligned_Load != index_arch_Prefer_PMINUB_for_stringop +-# error index_arch_Fast_Unaligned_Load != index_arch_Prefer_PMINUB_for_stringop +-#endif +-#if index_arch_Fast_Unaligned_Load != index_arch_Slow_SSE4_2 +-# error index_arch_Fast_Unaligned_Load != index_arch_Slow_SSE4_2 +-#endif +-#if index_arch_Fast_Unaligned_Load != index_arch_Fast_Unaligned_Copy +-# error index_arch_Fast_Unaligned_Load != index_arch_Fast_Unaligned_Copy +-#endif + cpu_features->feature[index_arch_Fast_Unaligned_Load] + |= (bit_arch_Fast_Unaligned_Load + | bit_arch_Fast_Unaligned_Copy +@@ -300,15 +384,6 @@ init_cpu_features (struct cpu_features *cpu_features) + case 0x2f: + /* Rep string instructions, unaligned load, unaligned copy, + and pminub are fast on Intel Core i3, i5 and i7. */ +-#if index_arch_Fast_Rep_String != index_arch_Fast_Unaligned_Load +-# error index_arch_Fast_Rep_String != index_arch_Fast_Unaligned_Load +-#endif +-#if index_arch_Fast_Rep_String != index_arch_Prefer_PMINUB_for_stringop +-# error index_arch_Fast_Rep_String != index_arch_Prefer_PMINUB_for_stringop +-#endif +-#if index_arch_Fast_Rep_String != index_arch_Fast_Unaligned_Copy +-# error index_arch_Fast_Rep_String != index_arch_Fast_Unaligned_Copy +-#endif + cpu_features->feature[index_arch_Fast_Rep_String] + |= (bit_arch_Fast_Rep_String + | bit_arch_Fast_Unaligned_Load +@@ -352,7 +427,7 @@ init_cpu_features (struct cpu_features *cpu_features) + /* This spells out "AuthenticAMD". */ + else if (ebx == 0x68747541 && ecx == 0x444d4163 && edx == 0x69746e65) + { +- unsigned int extended_model, stepping; ++ unsigned int extended_model; + + kind = arch_kind_amd; + +@@ -374,9 +449,6 @@ init_cpu_features (struct cpu_features *cpu_features) + + if (family == 0x15) + { +-#if index_arch_Fast_Unaligned_Load != index_arch_Fast_Copy_Backward +-# error index_arch_Fast_Unaligned_Load != index_arch_Fast_Copy_Backward +-#endif + /* "Excavator" */ + if (model >= 0x60 && model <= 0x7f) + { +@@ -408,9 +480,10 @@ init_cpu_features (struct cpu_features *cpu_features) + no_cpuid: + #endif + +- cpu_features->family = family; +- cpu_features->model = model; +- cpu_features->kind = kind; ++ cpu_features->basic.kind = kind; ++ cpu_features->basic.family = family; ++ cpu_features->basic.model = model; ++ cpu_features->basic.stepping = stepping; + + #if HAVE_TUNABLES + TUNABLE_GET (hwcaps, tunable_val_t *, TUNABLE_CALLBACK (set_hwcaps)); +@@ -431,7 +504,7 @@ no_cpuid: + + #ifdef __x86_64__ + GLRO(dl_hwcap) = HWCAP_X86_64; +- if (cpu_features->kind == arch_kind_intel) ++ if (cpu_features->basic.kind == arch_kind_intel) + { + const char *platform = NULL; + +diff --git a/sysdeps/x86/cpu-features.h b/sysdeps/x86/cpu-features.h +index fb22d7b9d6226a92..4917182e99a8ee90 100644 +--- a/sysdeps/x86/cpu-features.h ++++ b/sysdeps/x86/cpu-features.h +@@ -18,108 +18,58 @@ + #ifndef cpu_features_h + #define cpu_features_h + +-#define bit_arch_Fast_Rep_String (1 << 0) +-#define bit_arch_Fast_Copy_Backward (1 << 1) +-#define bit_arch_Slow_BSF (1 << 2) +-#define bit_arch_Fast_Unaligned_Load (1 << 4) +-#define bit_arch_Prefer_PMINUB_for_stringop (1 << 5) +-#define bit_arch_AVX_Usable (1 << 6) +-#define bit_arch_FMA_Usable (1 << 7) +-#define bit_arch_FMA4_Usable (1 << 8) +-#define bit_arch_Slow_SSE4_2 (1 << 9) +-#define bit_arch_AVX2_Usable (1 << 10) +-#define bit_arch_AVX_Fast_Unaligned_Load (1 << 11) +-#define bit_arch_AVX512F_Usable (1 << 12) +-#define bit_arch_AVX512DQ_Usable (1 << 13) +-#define bit_arch_I586 (1 << 14) +-#define bit_arch_I686 (1 << 15) +-#define bit_arch_Prefer_MAP_32BIT_EXEC (1 << 16) +-#define bit_arch_Prefer_No_VZEROUPPER (1 << 17) +-#define bit_arch_Fast_Unaligned_Copy (1 << 18) +-#define bit_arch_Prefer_ERMS (1 << 19) +-#define bit_arch_Prefer_No_AVX512 (1 << 20) +-#define bit_arch_MathVec_Prefer_No_AVX512 (1 << 21) +-#define bit_arch_XSAVEC_Usable (1 << 22) +-#define bit_arch_Prefer_FSRM (1 << 23) +- +-/* CPUID Feature flags. */ +- +-/* COMMON_CPUID_INDEX_1. */ +-#define bit_cpu_CX8 (1 << 8) +-#define bit_cpu_CMOV (1 << 15) +-#define bit_cpu_SSE (1 << 25) +-#define bit_cpu_SSE2 (1 << 26) +-#define bit_cpu_SSSE3 (1 << 9) +-#define bit_cpu_SSE4_1 (1 << 19) +-#define bit_cpu_SSE4_2 (1 << 20) +-#define bit_cpu_OSXSAVE (1 << 27) +-#define bit_cpu_AVX (1 << 28) +-#define bit_cpu_POPCOUNT (1 << 23) +-#define bit_cpu_FMA (1 << 12) +-#define bit_cpu_FMA4 (1 << 16) +-#define bit_cpu_HTT (1 << 28) +-#define bit_cpu_LZCNT (1 << 5) +-#define bit_cpu_MOVBE (1 << 22) +-#define bit_cpu_POPCNT (1 << 23) +- +-/* COMMON_CPUID_INDEX_7. */ +-#define bit_cpu_BMI1 (1 << 3) +-#define bit_cpu_BMI2 (1 << 8) +-#define bit_cpu_ERMS (1 << 9) +-#define bit_cpu_RTM (1 << 11) +-#define bit_cpu_AVX2 (1 << 5) +-#define bit_cpu_AVX512F (1 << 16) +-#define bit_cpu_AVX512DQ (1 << 17) +-#define bit_cpu_AVX512PF (1 << 26) +-#define bit_cpu_AVX512ER (1 << 27) +-#define bit_cpu_AVX512CD (1 << 28) +-#define bit_cpu_AVX512BW (1 << 30) +-#define bit_cpu_AVX512VL (1u << 31) +-#define bit_cpu_IBT (1u << 20) +-#define bit_cpu_SHSTK (1u << 7) +-#define bit_cpu_FSRM (1 << 4) +- +-/* XCR0 Feature flags. */ +-#define bit_XMM_state (1 << 1) +-#define bit_YMM_state (1 << 2) +-#define bit_Opmask_state (1 << 5) +-#define bit_ZMM0_15_state (1 << 6) +-#define bit_ZMM16_31_state (1 << 7) ++enum ++{ ++ /* The integer bit array index for the first set of internal feature ++ bits. */ ++ FEATURE_INDEX_1 = 0, ++ FEATURE_INDEX_2, ++ /* The current maximum size of the feature integer bit array. */ ++ FEATURE_INDEX_MAX ++}; + +-/* The integer bit array index for the first set of internal feature bits. */ +-#define FEATURE_INDEX_1 0 ++enum ++{ ++ COMMON_CPUID_INDEX_1 = 0, ++ COMMON_CPUID_INDEX_7, ++ COMMON_CPUID_INDEX_80000001, ++ COMMON_CPUID_INDEX_D_ECX_1, ++ COMMON_CPUID_INDEX_80000007, ++ COMMON_CPUID_INDEX_80000008, ++ /* Keep the following line at the end. */ ++ COMMON_CPUID_INDEX_MAX ++}; + +-/* The current maximum size of the feature integer bit array. */ +-#define FEATURE_INDEX_MAX 1 ++struct cpuid_registers ++{ ++ unsigned int eax; ++ unsigned int ebx; ++ unsigned int ecx; ++ unsigned int edx; ++}; + +-enum +- { +- COMMON_CPUID_INDEX_1 = 0, +- COMMON_CPUID_INDEX_7, +- COMMON_CPUID_INDEX_80000001, +- /* Keep the following line at the end. */ +- COMMON_CPUID_INDEX_MAX +- }; ++enum cpu_features_kind ++{ ++ arch_kind_unknown = 0, ++ arch_kind_intel, ++ arch_kind_amd, ++ arch_kind_other ++}; + +-struct cpu_features ++struct cpu_features_basic + { +- enum cpu_features_kind +- { +- arch_kind_unknown = 0, +- arch_kind_intel, +- arch_kind_amd, +- arch_kind_other +- } kind; ++ enum cpu_features_kind kind; + int max_cpuid; +- struct cpuid_registers +- { +- unsigned int eax; +- unsigned int ebx; +- unsigned int ecx; +- unsigned int edx; +- } cpuid[COMMON_CPUID_INDEX_MAX]; + unsigned int family; + unsigned int model; ++ unsigned int stepping; ++}; ++ ++struct cpu_features ++{ ++ struct cpuid_registers cpuid[COMMON_CPUID_INDEX_MAX]; ++ unsigned int feature[FEATURE_INDEX_MAX]; ++ struct cpu_features_basic basic; + /* The state size for XSAVEC or XSAVE. The type must be unsigned long + int so that we use + +@@ -132,7 +82,6 @@ struct cpu_features + GLIBC_TUNABLES=glibc.cpu.hwcaps=-XSAVEC_Usable + */ + unsigned int xsave_state_full_size; +- unsigned int feature[FEATURE_INDEX_MAX]; + /* Data cache size for use in memory and string routines, typically + L1 size. */ + unsigned long int data_cache_size; +@@ -148,112 +97,838 @@ struct cpu_features + extern const struct cpu_features *__get_cpu_features (void) + __attribute__ ((const)); + +-# if defined (_LIBC) && !IS_IN (nonlib) +-/* Unused for x86. */ +-# define INIT_ARCH() +-# define __get_cpu_features() (&GLRO(dl_x86_cpu_features)) +-# endif +- +- + /* Only used directly in cpu-features.c. */ + # define CPU_FEATURES_CPU_P(ptr, name) \ + ((ptr->cpuid[index_cpu_##name].reg_##name & (bit_cpu_##name)) != 0) + # define CPU_FEATURES_ARCH_P(ptr, name) \ + ((ptr->feature[index_arch_##name] & (bit_arch_##name)) != 0) + +-/* HAS_* evaluates to true if we may use the feature at runtime. */ +-# define HAS_CPU_FEATURE(name) \ +- CPU_FEATURES_CPU_P (__get_cpu_features (), name) ++/* HAS_CPU_FEATURE evaluates to true if CPU supports the feature. */ ++#define HAS_CPU_FEATURE(name) \ ++ CPU_FEATURES_CPU_P (__get_cpu_features (), name) ++/* HAS_ARCH_FEATURE evaluates to true if we may use the feature at ++ runtime. */ + # define HAS_ARCH_FEATURE(name) \ +- CPU_FEATURES_ARCH_P (__get_cpu_features (), name) +- +-# define index_cpu_CX8 COMMON_CPUID_INDEX_1 +-# define index_cpu_CMOV COMMON_CPUID_INDEX_1 +-# define index_cpu_SSE COMMON_CPUID_INDEX_1 +-# define index_cpu_SSE2 COMMON_CPUID_INDEX_1 +-# define index_cpu_SSSE3 COMMON_CPUID_INDEX_1 +-# define index_cpu_SSE4_1 COMMON_CPUID_INDEX_1 +-# define index_cpu_SSE4_2 COMMON_CPUID_INDEX_1 +-# define index_cpu_AVX COMMON_CPUID_INDEX_1 +-# define index_cpu_AVX2 COMMON_CPUID_INDEX_7 +-# define index_cpu_AVX512F COMMON_CPUID_INDEX_7 +-# define index_cpu_AVX512DQ COMMON_CPUID_INDEX_7 +-# define index_cpu_AVX512PF COMMON_CPUID_INDEX_7 +-# define index_cpu_AVX512ER COMMON_CPUID_INDEX_7 +-# define index_cpu_AVX512CD COMMON_CPUID_INDEX_7 +-# define index_cpu_AVX512BW COMMON_CPUID_INDEX_7 +-# define index_cpu_AVX512VL COMMON_CPUID_INDEX_7 +-# define index_cpu_ERMS COMMON_CPUID_INDEX_7 +-# define index_cpu_RTM COMMON_CPUID_INDEX_7 +-# define index_cpu_FMA COMMON_CPUID_INDEX_1 +-# define index_cpu_FMA4 COMMON_CPUID_INDEX_80000001 +-# define index_cpu_POPCOUNT COMMON_CPUID_INDEX_1 +-# define index_cpu_OSXSAVE COMMON_CPUID_INDEX_1 +-# define index_cpu_HTT COMMON_CPUID_INDEX_1 +-# define index_cpu_BMI1 COMMON_CPUID_INDEX_7 +-# define index_cpu_BMI2 COMMON_CPUID_INDEX_7 +-# define index_cpu_LZCNT COMMON_CPUID_INDEX_80000001 +-# define index_cpu_MOVBE COMMON_CPUID_INDEX_1 +-# define index_cpu_POPCNT COMMON_CPUID_INDEX_1 +-# define index_cpu_IBT COMMON_CPUID_INDEX_7 +-# define index_cpu_SHSTK COMMON_CPUID_INDEX_7 +-# define index_cpu_FSRM COMMON_CPUID_INDEX_7 +- +-# define reg_CX8 edx +-# define reg_CMOV edx +-# define reg_SSE edx +-# define reg_SSE2 edx +-# define reg_SSSE3 ecx +-# define reg_SSE4_1 ecx +-# define reg_SSE4_2 ecx +-# define reg_AVX ecx +-# define reg_AVX2 ebx +-# define reg_AVX512F ebx +-# define reg_AVX512DQ ebx +-# define reg_AVX512PF ebx +-# define reg_AVX512ER ebx +-# define reg_AVX512CD ebx +-# define reg_AVX512BW ebx +-# define reg_AVX512VL ebx +-# define reg_ERMS ebx +-# define reg_RTM ebx +-# define reg_FMA ecx +-# define reg_FMA4 ecx +-# define reg_POPCOUNT ecx +-# define reg_OSXSAVE ecx +-# define reg_HTT edx +-# define reg_BMI1 ebx +-# define reg_BMI2 ebx +-# define reg_LZCNT ecx +-# define reg_MOVBE ecx +-# define reg_POPCNT ecx +-# define reg_IBT edx +-# define reg_SHSTK ecx +-# define reg_FSRM edx +- +-# define index_arch_Fast_Rep_String FEATURE_INDEX_1 +-# define index_arch_Fast_Copy_Backward FEATURE_INDEX_1 +-# define index_arch_Slow_BSF FEATURE_INDEX_1 +-# define index_arch_Fast_Unaligned_Load FEATURE_INDEX_1 +-# define index_arch_Prefer_PMINUB_for_stringop FEATURE_INDEX_1 +-# define index_arch_AVX_Usable FEATURE_INDEX_1 +-# define index_arch_FMA_Usable FEATURE_INDEX_1 +-# define index_arch_FMA4_Usable FEATURE_INDEX_1 +-# define index_arch_Slow_SSE4_2 FEATURE_INDEX_1 +-# define index_arch_AVX2_Usable FEATURE_INDEX_1 +-# define index_arch_AVX_Fast_Unaligned_Load FEATURE_INDEX_1 +-# define index_arch_AVX512F_Usable FEATURE_INDEX_1 +-# define index_arch_AVX512DQ_Usable FEATURE_INDEX_1 +-# define index_arch_I586 FEATURE_INDEX_1 +-# define index_arch_I686 FEATURE_INDEX_1 +-# define index_arch_Prefer_MAP_32BIT_EXEC FEATURE_INDEX_1 +-# define index_arch_Prefer_No_VZEROUPPER FEATURE_INDEX_1 +-# define index_arch_Fast_Unaligned_Copy FEATURE_INDEX_1 +-# define index_arch_Prefer_ERMS FEATURE_INDEX_1 +-# define index_arch_Prefer_No_AVX512 FEATURE_INDEX_1 +-# define index_arch_MathVec_Prefer_No_AVX512 FEATURE_INDEX_1 +-# define index_arch_XSAVEC_Usable FEATURE_INDEX_1 +-# define index_arch_Prefer_FSRM FEATURE_INDEX_1 ++ CPU_FEATURES_ARCH_P (__get_cpu_features (), name) ++/* CPU_FEATURE_USABLE evaluates to true if the feature is usable. */ ++#define CPU_FEATURE_USABLE(name) \ ++ ((need_arch_feature_##name && HAS_ARCH_FEATURE (name##_Usable)) \ ++ || (!need_arch_feature_##name && HAS_CPU_FEATURE(name))) ++ ++/* Architecture features. */ ++ ++/* FEATURE_INDEX_1. */ ++#define bit_arch_AVX_Usable (1u << 0) ++#define bit_arch_AVX2_Usable (1u << 1) ++#define bit_arch_AVX512F_Usable (1u << 2) ++#define bit_arch_AVX512CD_Usable (1u << 3) ++#define bit_arch_AVX512ER_Usable (1u << 4) ++#define bit_arch_AVX512PF_Usable (1u << 5) ++#define bit_arch_AVX512VL_Usable (1u << 6) ++#define bit_arch_AVX512DQ_Usable (1u << 7) ++#define bit_arch_AVX512BW_Usable (1u << 8) ++#define bit_arch_AVX512_4FMAPS_Usable (1u << 9) ++#define bit_arch_AVX512_4VNNIW_Usable (1u << 10) ++#define bit_arch_AVX512_BITALG_Usable (1u << 11) ++#define bit_arch_AVX512_IFMA_Usable (1u << 12) ++#define bit_arch_AVX512_VBMI_Usable (1u << 13) ++#define bit_arch_AVX512_VBMI2_Usable (1u << 14) ++#define bit_arch_AVX512_VNNI_Usable (1u << 15) ++#define bit_arch_AVX512_VPOPCNTDQ_Usable (1u << 16) ++#define bit_arch_FMA_Usable (1u << 17) ++#define bit_arch_FMA4_Usable (1u << 18) ++#define bit_arch_VAES_Usable (1u << 19) ++#define bit_arch_VPCLMULQDQ_Usable (1u << 20) ++#define bit_arch_XOP_Usable (1u << 21) ++#define bit_arch_XSAVEC_Usable (1u << 22) ++ ++#define index_arch_AVX_Usable FEATURE_INDEX_1 ++#define index_arch_AVX2_Usable FEATURE_INDEX_1 ++#define index_arch_AVX512F_Usable FEATURE_INDEX_1 ++#define index_arch_AVX512CD_Usable FEATURE_INDEX_1 ++#define index_arch_AVX512ER_Usable FEATURE_INDEX_1 ++#define index_arch_AVX512PF_Usable FEATURE_INDEX_1 ++#define index_arch_AVX512VL_Usable FEATURE_INDEX_1 ++#define index_arch_AVX512BW_Usable FEATURE_INDEX_1 ++#define index_arch_AVX512DQ_Usable FEATURE_INDEX_1 ++#define index_arch_AVX512_4FMAPS_Usable FEATURE_INDEX_1 ++#define index_arch_AVX512_4VNNIW_Usable FEATURE_INDEX_1 ++#define index_arch_AVX512_BITALG_Usable FEATURE_INDEX_1 ++#define index_arch_AVX512_IFMA_Usable FEATURE_INDEX_1 ++#define index_arch_AVX512_VBMI_Usable FEATURE_INDEX_1 ++#define index_arch_AVX512_VBMI2_Usable FEATURE_INDEX_1 ++#define index_arch_AVX512_VNNI_Usable FEATURE_INDEX_1 ++#define index_arch_AVX512_VPOPCNTDQ_Usable FEATURE_INDEX_1 ++#define index_arch_FMA_Usable FEATURE_INDEX_1 ++#define index_arch_FMA4_Usable FEATURE_INDEX_1 ++#define index_arch_VAES_Usable FEATURE_INDEX_1 ++#define index_arch_VPCLMULQDQ_Usable FEATURE_INDEX_1 ++#define index_arch_XOP_Usable FEATURE_INDEX_1 ++#define index_arch_XSAVEC_Usable FEATURE_INDEX_1 ++ ++/* Unused. Compiler will optimize them out. */ ++#define bit_arch_SSE3_Usable (1u << 0) ++#define bit_arch_PCLMULQDQ_Usable (1u << 0) ++#define bit_arch_SSSE3_Usable (1u << 0) ++#define bit_arch_CMPXCHG16B_Usable (1u << 0) ++#define bit_arch_SSE4_1_Usable (1u << 0) ++#define bit_arch_SSE4_2_Usable (1u << 0) ++#define bit_arch_MOVBE_Usable (1u << 0) ++#define bit_arch_POPCNT_Usable (1u << 0) ++#define bit_arch_AES_Usable (1u << 0) ++#define bit_arch_XSAVE_Usable (1u << 0) ++#define bit_arch_OSXSAVE_Usable (1u << 0) ++#define bit_arch_F16C_Usable (1u << 0) ++#define bit_arch_RDRAND_Usable (1u << 0) ++#define bit_arch_FPU_Usable (1u << 0) ++#define bit_arch_TSC_Usable (1u << 0) ++#define bit_arch_MSR_Usable (1u << 0) ++#define bit_arch_CX8_Usable (1u << 0) ++#define bit_arch_SEP_Usable (1u << 0) ++#define bit_arch_CMOV_Usable (1u << 0) ++#define bit_arch_CLFSH_Usable (1u << 0) ++#define bit_arch_MMX_Usable (1u << 0) ++#define bit_arch_FXSR_Usable (1u << 0) ++#define bit_arch_SSE_Usable (1u << 0) ++#define bit_arch_SSE2_Usable (1u << 0) ++#define bit_arch_FSGSBASE_Usable (1u << 0) ++#define bit_arch_BMI1_Usable (1u << 0) ++#define bit_arch_HLE_Usable (1u << 0) ++#define bit_arch_BMI2_Usable (1u << 0) ++#define bit_arch_ERMS_Usable (1u << 0) ++#define bit_arch_RTM_Usable (1u << 0) ++#define bit_arch_RDSEED_Usable (1u << 0) ++#define bit_arch_ADX_Usable (1u << 0) ++#define bit_arch_CLFLUSHOPT_Usable (1u << 0) ++#define bit_arch_CLWB_Usable (1u << 0) ++#define bit_arch_SHA_Usable (1u << 0) ++#define bit_arch_PREFETCHWT1_Usable (1u << 0) ++#define bit_arch_GFNI_Usable (1u << 0) ++#define bit_arch_RDPID_Usable (1u << 0) ++#define bit_arch_CLDEMOTE_Usable (1u << 0) ++#define bit_arch_MOVDIRI_Usable (1u << 0) ++#define bit_arch_MOVDIR64B_Usable (1u << 0) ++#define bit_arch_FSRM_Usable (1u << 0) ++#define bit_arch_LAHF64_SAHF64_Usable (1u << 0) ++#define bit_arch_SVM_Usable (1u << 0) ++#define bit_arch_LZCNT_Usable (1u << 0) ++#define bit_arch_SSE4A_Usable (1u << 0) ++#define bit_arch_PREFETCHW_Usable (1u << 0) ++#define bit_arch_TBM_Usable (1u << 0) ++#define bit_arch_SYSCALL_SYSRET_Usable (1u << 0) ++#define bit_arch_RDTSCP_Usable (1u << 0) ++#define bit_arch_XSAVEOPT_Usable (1u << 0) ++#define bit_arch_XGETBV_ECX_1_Usable (1u << 0) ++#define bit_arch_XSAVES_Usable (1u << 0) ++#define bit_arch_INVARIANT_TSC_Usable (1u << 0) ++#define bit_arch_WBNOINVD_Usable (1u << 0) ++ ++/* Unused. Compiler will optimize them out. */ ++#define index_arch_SSE3_Usable FEATURE_INDEX_1 ++#define index_arch_PCLMULQDQ_Usable FEATURE_INDEX_1 ++#define index_arch_SSSE3_Usable FEATURE_INDEX_1 ++#define index_arch_CMPXCHG16B_Usable FEATURE_INDEX_1 ++#define index_arch_SSE4_1_Usable FEATURE_INDEX_1 ++#define index_arch_SSE4_2_Usable FEATURE_INDEX_1 ++#define index_arch_MOVBE_Usable FEATURE_INDEX_1 ++#define index_arch_POPCNT_Usable FEATURE_INDEX_1 ++#define index_arch_AES_Usable FEATURE_INDEX_1 ++#define index_arch_XSAVE_Usable FEATURE_INDEX_1 ++#define index_arch_OSXSAVE_Usable FEATURE_INDEX_1 ++#define index_arch_F16C_Usable FEATURE_INDEX_1 ++#define index_arch_RDRAND_Usable FEATURE_INDEX_1 ++#define index_arch_FPU_Usable FEATURE_INDEX_1 ++#define index_arch_TSC_Usable FEATURE_INDEX_1 ++#define index_arch_MSR_Usable FEATURE_INDEX_1 ++#define index_arch_CX8_Usable FEATURE_INDEX_1 ++#define index_arch_SEP_Usable FEATURE_INDEX_1 ++#define index_arch_CMOV_Usable FEATURE_INDEX_1 ++#define index_arch_CLFSH_Usable FEATURE_INDEX_1 ++#define index_arch_MMX_Usable FEATURE_INDEX_1 ++#define index_arch_FXSR_Usable FEATURE_INDEX_1 ++#define index_arch_SSE_Usable FEATURE_INDEX_1 ++#define index_arch_SSE2_Usable FEATURE_INDEX_1 ++#define index_arch_FSGSBASE_Usable FEATURE_INDEX_1 ++#define index_arch_BMI1_Usable FEATURE_INDEX_1 ++#define index_arch_HLE_Usable FEATURE_INDEX_1 ++#define index_arch_BMI2_Usable FEATURE_INDEX_1 ++#define index_arch_ERMS_Usable FEATURE_INDEX_1 ++#define index_arch_RTM_Usable FEATURE_INDEX_1 ++#define index_arch_RDSEED_Usable FEATURE_INDEX_1 ++#define index_arch_ADX_Usable FEATURE_INDEX_1 ++#define index_arch_CLFLUSHOPT_Usable FEATURE_INDEX_1 ++#define index_arch_CLWB_Usable FEATURE_INDEX_1 ++#define index_arch_SHA_Usable FEATURE_INDEX_1 ++#define index_arch_PREFETCHWT1_Usable FEATURE_INDEX_1 ++#define index_arch_GFNI_Usable FEATURE_INDEX_1 ++#define index_arch_RDPID_Usable FEATURE_INDEX_1 ++#define index_arch_CLDEMOTE_Usable FEATURE_INDEX_1 ++#define index_arch_MOVDIRI_Usable FEATURE_INDEX_1 ++#define index_arch_MOVDIR64B_Usable FEATURE_INDEX_1 ++#define index_arch_FSRM_Usable FEATURE_INDEX_1 ++#define index_arch_LAHF64_SAHF64_Usable FEATURE_INDEX_1 ++#define index_arch_LZCNT_Usable FEATURE_INDEX_1 ++#define index_arch_SSE4A_Usable FEATURE_INDEX_1 ++#define index_arch_PREFETCHW_Usable FEATURE_INDEX_1 ++#define index_arch_TBM_Usable FEATURE_INDEX_1 ++#define index_arch_SYSCALL_SYSRET_Usable FEATURE_INDEX_1 ++#define index_arch_RDTSCP_Usable FEATURE_INDEX_1 ++#define index_arch_XSAVEOPT_Usable FEATURE_INDEX_1 ++#define index_arch_XGETBV_ECX_1_Usable FEATURE_INDEX_1 ++#define index_arch_XSAVES_Usable FEATURE_INDEX_1 ++#define index_arch_INVARIANT_TSC_Usable FEATURE_INDEX_1 ++#define index_arch_WBNOINVD_Usable FEATURE_INDEX_1 ++ ++/* COMMON_CPUID_INDEX_1. */ ++ ++/* ECX. */ ++#define need_arch_feature_SSE3 0 ++#define need_arch_feature_PCLMULQDQ 0 ++#define need_arch_feature_SSSE3 0 ++#define need_arch_feature_FMA 1 ++#define need_arch_feature_CMPXCHG16B 0 ++#define need_arch_feature_SSE4_1 0 ++#define need_arch_feature_SSE4_2 0 ++#define need_arch_feature_MOVBE 0 ++#define need_arch_feature_POPCNT 0 ++#define need_arch_feature_AES 0 ++#define need_arch_feature_XSAVE 0 ++#define need_arch_feature_OSXSAVE 0 ++#define need_arch_feature_AVX 1 ++#define need_arch_feature_F16C 0 ++#define need_arch_feature_RDRAND 0 ++ ++/* EDX. */ ++#define need_arch_feature_FPU 0 ++#define need_arch_feature_TSC 0 ++#define need_arch_feature_MSR 0 ++#define need_arch_feature_CX8 0 ++#define need_arch_feature_SEP 0 ++#define need_arch_feature_CMOV 0 ++#define need_arch_feature_CLFSH 0 ++#define need_arch_feature_MMX 0 ++#define need_arch_feature_FXSR 0 ++#define need_arch_feature_SSE 0 ++#define need_arch_feature_SSE2 0 ++ ++/* COMMON_CPUID_INDEX_7. */ ++ ++/* EBX. */ ++#define need_arch_feature_FSGSBASE 0 ++#define need_arch_feature_BMI1 0 ++#define need_arch_feature_HLE 0 ++#define need_arch_feature_AVX2 1 ++#define need_arch_feature_BMI2 0 ++#define need_arch_feature_ERMS 0 ++#define need_arch_feature_RTM 0 ++#define need_arch_feature_AVX512F 1 ++#define need_arch_feature_AVX512DQ 1 ++#define need_arch_feature_RDSEED 0 ++#define need_arch_feature_ADX 0 ++#define need_arch_feature_AVX512_IFMA 1 ++#define need_arch_feature_CLFLUSHOPT 0 ++#define need_arch_feature_CLWB 0 ++#define need_arch_feature_AVX512PF 1 ++#define need_arch_feature_AVX512ER 1 ++#define need_arch_feature_AVX512CD 1 ++#define need_arch_feature_SHA 0 ++#define need_arch_feature_AVX512BW 1 ++#define need_arch_feature_AVX512VL 1 ++ ++/* ECX. */ ++#define need_arch_feature_PREFETCHWT1 0 ++#define need_arch_feature_AVX512_VBMI 1 ++#define need_arch_feature_AVX512_VBMI2 1 ++#define need_arch_feature_GFNI 0 ++#define need_arch_feature_VAES 1 ++#define need_arch_feature_VPCLMULQDQ 1 ++#define need_arch_feature_AVX512_VNNI 1 ++#define need_arch_feature_AVX512_BITALG 1 ++#define need_arch_feature_AVX512_VPOPCNTDQ 1 ++#define need_arch_feature_RDPID 0 ++#define need_arch_feature_CLDEMOTE 0 ++#define need_arch_feature_MOVDIRI 0 ++#define need_arch_feature_MOVDIR64B 0 ++ ++/* EDX. */ ++#define need_arch_feature_AVX512_4VNNIW 1 ++#define need_arch_feature_AVX512_4FMAPS 1 ++#define need_arch_feature_FSRM 0 ++ ++/* COMMON_CPUID_INDEX_80000001. */ ++ ++/* ECX. */ ++#define need_arch_feature_LAHF64_SAHF64 0 ++#define need_arch_feature_LZCNT 0 ++#define need_arch_feature_SSE4A 0 ++#define need_arch_feature_PREFETCHW 0 ++#define need_arch_feature_XOP 1 ++#define need_arch_feature_FMA4 1 ++#define need_arch_feature_TBM 0 ++#define need_arch_feature_SYSCALL_SYSRET 0 ++#define need_arch_feature_RDTSCP 0 ++#define need_arch_feature_XSAVEOPT 0 ++#define need_arch_feature_XSAVEC 1 ++#define need_arch_feature_XGETBV_ECX_1 0 ++#define need_arch_feature_XSAVES 0 ++#define need_arch_feature_INVARIANT_TSC 0 ++#define need_arch_feature_WBNOINVD 0 ++ ++/* CPU features. */ ++ ++/* COMMON_CPUID_INDEX_1. */ ++ ++/* ECX. */ ++#define bit_cpu_SSE3 (1u << 0) ++#define bit_cpu_PCLMULQDQ (1u << 1) ++#define bit_cpu_DTES64 (1u << 2) ++#define bit_cpu_MONITOR (1u << 3) ++#define bit_cpu_DS_CPL (1u << 4) ++#define bit_cpu_VMX (1u << 5) ++#define bit_cpu_SMX (1u << 6) ++#define bit_cpu_EST (1u << 7) ++#define bit_cpu_TM2 (1u << 8) ++#define bit_cpu_SSSE3 (1u << 9) ++#define bit_cpu_CNXT_ID (1u << 10) ++#define bit_cpu_SDBG (1u << 11) ++#define bit_cpu_FMA (1u << 12) ++#define bit_cpu_CMPXCHG16B (1u << 13) ++#define bit_cpu_XTPRUPDCTRL (1u << 14) ++#define bit_cpu_PDCM (1u << 15) ++#define bit_cpu_PCID (1u << 17) ++#define bit_cpu_DCA (1u << 18) ++#define bit_cpu_SSE4_1 (1u << 19) ++#define bit_cpu_SSE4_2 (1u << 20) ++#define bit_cpu_X2APIC (1u << 21) ++#define bit_cpu_MOVBE (1u << 22) ++#define bit_cpu_POPCNT (1u << 23) ++#define bit_cpu_TSC_DEADLINE (1u << 24) ++#define bit_cpu_AES (1u << 25) ++#define bit_cpu_XSAVE (1u << 26) ++#define bit_cpu_OSXSAVE (1u << 27) ++#define bit_cpu_AVX (1u << 28) ++#define bit_cpu_F16C (1u << 29) ++#define bit_cpu_RDRAND (1u << 30) ++ ++/* EDX. */ ++#define bit_cpu_FPU (1u << 0) ++#define bit_cpu_VME (1u << 1) ++#define bit_cpu_DE (1u << 2) ++#define bit_cpu_PSE (1u << 3) ++#define bit_cpu_TSC (1u << 4) ++#define bit_cpu_MSR (1u << 5) ++#define bit_cpu_PAE (1u << 6) ++#define bit_cpu_MCE (1u << 7) ++#define bit_cpu_CX8 (1u << 8) ++#define bit_cpu_APIC (1u << 9) ++#define bit_cpu_SEP (1u << 11) ++#define bit_cpu_MTRR (1u << 12) ++#define bit_cpu_PGE (1u << 13) ++#define bit_cpu_MCA (1u << 14) ++#define bit_cpu_CMOV (1u << 15) ++#define bit_cpu_PAT (1u << 16) ++#define bit_cpu_PSE_36 (1u << 17) ++#define bit_cpu_PSN (1u << 18) ++#define bit_cpu_CLFSH (1u << 20) ++#define bit_cpu_DS (1u << 21) ++#define bit_cpu_ACPI (1u << 22) ++#define bit_cpu_MMX (1u << 23) ++#define bit_cpu_FXSR (1u << 24) ++#define bit_cpu_SSE (1u << 25) ++#define bit_cpu_SSE2 (1u << 26) ++#define bit_cpu_SS (1u << 27) ++#define bit_cpu_HTT (1u << 28) ++#define bit_cpu_TM (1u << 29) ++#define bit_cpu_PBE (1u << 31) ++ ++/* COMMON_CPUID_INDEX_7. */ ++ ++/* EBX. */ ++#define bit_cpu_FSGSBASE (1u << 0) ++#define bit_cpu_TSC_ADJUST (1u << 1) ++#define bit_cpu_SGX (1u << 2) ++#define bit_cpu_BMI1 (1u << 3) ++#define bit_cpu_HLE (1u << 4) ++#define bit_cpu_AVX2 (1u << 5) ++#define bit_cpu_SMEP (1u << 7) ++#define bit_cpu_BMI2 (1u << 8) ++#define bit_cpu_ERMS (1u << 9) ++#define bit_cpu_INVPCID (1u << 10) ++#define bit_cpu_RTM (1u << 11) ++#define bit_cpu_PQM (1u << 12) ++#define bit_cpu_MPX (1u << 14) ++#define bit_cpu_PQE (1u << 15) ++#define bit_cpu_AVX512F (1u << 16) ++#define bit_cpu_AVX512DQ (1u << 17) ++#define bit_cpu_RDSEED (1u << 18) ++#define bit_cpu_ADX (1u << 19) ++#define bit_cpu_SMAP (1u << 20) ++#define bit_cpu_AVX512_IFMA (1u << 21) ++#define bit_cpu_CLFLUSHOPT (1u << 22) ++#define bit_cpu_CLWB (1u << 24) ++#define bit_cpu_TRACE (1u << 25) ++#define bit_cpu_AVX512PF (1u << 26) ++#define bit_cpu_AVX512ER (1u << 27) ++#define bit_cpu_AVX512CD (1u << 28) ++#define bit_cpu_SHA (1u << 29) ++#define bit_cpu_AVX512BW (1u << 30) ++#define bit_cpu_AVX512VL (1u << 31) ++ ++/* ECX. */ ++#define bit_cpu_PREFETCHWT1 (1u << 0) ++#define bit_cpu_AVX512_VBMI (1u << 1) ++#define bit_cpu_UMIP (1u << 2) ++#define bit_cpu_PKU (1u << 3) ++#define bit_cpu_OSPKE (1u << 4) ++#define bit_cpu_WAITPKG (1u << 5) ++#define bit_cpu_AVX512_VBMI2 (1u << 6) ++#define bit_cpu_SHSTK (1u << 7) ++#define bit_cpu_GFNI (1u << 8) ++#define bit_cpu_VAES (1u << 9) ++#define bit_cpu_VPCLMULQDQ (1u << 10) ++#define bit_cpu_AVX512_VNNI (1u << 11) ++#define bit_cpu_AVX512_BITALG (1u << 12) ++#define bit_cpu_AVX512_VPOPCNTDQ (1u << 14) ++#define bit_cpu_RDPID (1u << 22) ++#define bit_cpu_CLDEMOTE (1u << 25) ++#define bit_cpu_MOVDIRI (1u << 27) ++#define bit_cpu_MOVDIR64B (1u << 28) ++#define bit_cpu_SGX_LC (1u << 30) ++ ++/* EDX. */ ++#define bit_cpu_AVX512_4VNNIW (1u << 2) ++#define bit_cpu_AVX512_4FMAPS (1u << 3) ++#define bit_cpu_FSRM (1u << 4) ++#define bit_cpu_PCONFIG (1u << 18) ++#define bit_cpu_IBT (1u << 20) ++#define bit_cpu_IBRS_IBPB (1u << 26) ++#define bit_cpu_STIBP (1u << 27) ++#define bit_cpu_CAPABILITIES (1u << 29) ++#define bit_cpu_SSBD (1u << 31) ++ ++/* COMMON_CPUID_INDEX_80000001. */ ++ ++/* ECX. */ ++#define bit_cpu_LAHF64_SAHF64 (1u << 0) ++#define bit_cpu_SVM (1u << 2) ++#define bit_cpu_LZCNT (1u << 5) ++#define bit_cpu_SSE4A (1u << 6) ++#define bit_cpu_PREFETCHW (1u << 8) ++#define bit_cpu_XOP (1u << 11) ++#define bit_cpu_LWP (1u << 15) ++#define bit_cpu_FMA4 (1u << 16) ++#define bit_cpu_TBM (1u << 21) ++ ++/* EDX. */ ++#define bit_cpu_SYSCALL_SYSRET (1u << 11) ++#define bit_cpu_NX (1u << 20) ++#define bit_cpu_PAGE1GB (1u << 26) ++#define bit_cpu_RDTSCP (1u << 27) ++#define bit_cpu_LM (1u << 29) ++ ++/* COMMON_CPUID_INDEX_D_ECX_1. */ ++ ++/* EAX. */ ++#define bit_cpu_XSAVEOPT (1u << 0) ++#define bit_cpu_XSAVEC (1u << 1) ++#define bit_cpu_XGETBV_ECX_1 (1u << 2) ++#define bit_cpu_XSAVES (1u << 3) ++ ++/* COMMON_CPUID_INDEX_80000007. */ ++ ++/* EDX. */ ++#define bit_cpu_INVARIANT_TSC (1u << 8) ++ ++/* COMMON_CPUID_INDEX_80000008. */ ++ ++/* EBX. */ ++#define bit_cpu_WBNOINVD (1u << 9) ++ ++/* COMMON_CPUID_INDEX_1. */ ++ ++/* ECX. */ ++#define index_cpu_SSE3 COMMON_CPUID_INDEX_1 ++#define index_cpu_PCLMULQDQ COMMON_CPUID_INDEX_1 ++#define index_cpu_DTES64 COMMON_CPUID_INDEX_1 ++#define index_cpu_MONITOR COMMON_CPUID_INDEX_1 ++#define index_cpu_DS_CPL COMMON_CPUID_INDEX_1 ++#define index_cpu_VMX COMMON_CPUID_INDEX_1 ++#define index_cpu_SMX COMMON_CPUID_INDEX_1 ++#define index_cpu_EST COMMON_CPUID_INDEX_1 ++#define index_cpu_TM2 COMMON_CPUID_INDEX_1 ++#define index_cpu_SSSE3 COMMON_CPUID_INDEX_1 ++#define index_cpu_CNXT_ID COMMON_CPUID_INDEX_1 ++#define index_cpu_SDBG COMMON_CPUID_INDEX_1 ++#define index_cpu_FMA COMMON_CPUID_INDEX_1 ++#define index_cpu_CMPXCHG16B COMMON_CPUID_INDEX_1 ++#define index_cpu_XTPRUPDCTRL COMMON_CPUID_INDEX_1 ++#define index_cpu_PDCM COMMON_CPUID_INDEX_1 ++#define index_cpu_PCID COMMON_CPUID_INDEX_1 ++#define index_cpu_DCA COMMON_CPUID_INDEX_1 ++#define index_cpu_SSE4_1 COMMON_CPUID_INDEX_1 ++#define index_cpu_SSE4_2 COMMON_CPUID_INDEX_1 ++#define index_cpu_X2APIC COMMON_CPUID_INDEX_1 ++#define index_cpu_MOVBE COMMON_CPUID_INDEX_1 ++#define index_cpu_POPCNT COMMON_CPUID_INDEX_1 ++#define index_cpu_TSC_DEADLINE COMMON_CPUID_INDEX_1 ++#define index_cpu_AES COMMON_CPUID_INDEX_1 ++#define index_cpu_XSAVE COMMON_CPUID_INDEX_1 ++#define index_cpu_OSXSAVE COMMON_CPUID_INDEX_1 ++#define index_cpu_AVX COMMON_CPUID_INDEX_1 ++#define index_cpu_F16C COMMON_CPUID_INDEX_1 ++#define index_cpu_RDRAND COMMON_CPUID_INDEX_1 ++ ++/* ECX. */ ++#define index_cpu_FPU COMMON_CPUID_INDEX_1 ++#define index_cpu_VME COMMON_CPUID_INDEX_1 ++#define index_cpu_DE COMMON_CPUID_INDEX_1 ++#define index_cpu_PSE COMMON_CPUID_INDEX_1 ++#define index_cpu_TSC COMMON_CPUID_INDEX_1 ++#define index_cpu_MSR COMMON_CPUID_INDEX_1 ++#define index_cpu_PAE COMMON_CPUID_INDEX_1 ++#define index_cpu_MCE COMMON_CPUID_INDEX_1 ++#define index_cpu_CX8 COMMON_CPUID_INDEX_1 ++#define index_cpu_APIC COMMON_CPUID_INDEX_1 ++#define index_cpu_SEP COMMON_CPUID_INDEX_1 ++#define index_cpu_MTRR COMMON_CPUID_INDEX_1 ++#define index_cpu_PGE COMMON_CPUID_INDEX_1 ++#define index_cpu_MCA COMMON_CPUID_INDEX_1 ++#define index_cpu_CMOV COMMON_CPUID_INDEX_1 ++#define index_cpu_PAT COMMON_CPUID_INDEX_1 ++#define index_cpu_PSE_36 COMMON_CPUID_INDEX_1 ++#define index_cpu_PSN COMMON_CPUID_INDEX_1 ++#define index_cpu_CLFSH COMMON_CPUID_INDEX_1 ++#define index_cpu_DS COMMON_CPUID_INDEX_1 ++#define index_cpu_ACPI COMMON_CPUID_INDEX_1 ++#define index_cpu_MMX COMMON_CPUID_INDEX_1 ++#define index_cpu_FXSR COMMON_CPUID_INDEX_1 ++#define index_cpu_SSE COMMON_CPUID_INDEX_1 ++#define index_cpu_SSE2 COMMON_CPUID_INDEX_1 ++#define index_cpu_SS COMMON_CPUID_INDEX_1 ++#define index_cpu_HTT COMMON_CPUID_INDEX_1 ++#define index_cpu_TM COMMON_CPUID_INDEX_1 ++#define index_cpu_PBE COMMON_CPUID_INDEX_1 ++ ++/* COMMON_CPUID_INDEX_7. */ ++ ++/* EBX. */ ++#define index_cpu_FSGSBASE COMMON_CPUID_INDEX_7 ++#define index_cpu_TSC_ADJUST COMMON_CPUID_INDEX_7 ++#define index_cpu_SGX COMMON_CPUID_INDEX_7 ++#define index_cpu_BMI1 COMMON_CPUID_INDEX_7 ++#define index_cpu_HLE COMMON_CPUID_INDEX_7 ++#define index_cpu_AVX2 COMMON_CPUID_INDEX_7 ++#define index_cpu_SMEP COMMON_CPUID_INDEX_7 ++#define index_cpu_BMI2 COMMON_CPUID_INDEX_7 ++#define index_cpu_ERMS COMMON_CPUID_INDEX_7 ++#define index_cpu_INVPCID COMMON_CPUID_INDEX_7 ++#define index_cpu_RTM COMMON_CPUID_INDEX_7 ++#define index_cpu_PQM COMMON_CPUID_INDEX_7 ++#define index_cpu_MPX COMMON_CPUID_INDEX_7 ++#define index_cpu_PQE COMMON_CPUID_INDEX_7 ++#define index_cpu_AVX512F COMMON_CPUID_INDEX_7 ++#define index_cpu_AVX512DQ COMMON_CPUID_INDEX_7 ++#define index_cpu_RDSEED COMMON_CPUID_INDEX_7 ++#define index_cpu_ADX COMMON_CPUID_INDEX_7 ++#define index_cpu_SMAP COMMON_CPUID_INDEX_7 ++#define index_cpu_AVX512_IFMA COMMON_CPUID_INDEX_7 ++#define index_cpu_CLFLUSHOPT COMMON_CPUID_INDEX_7 ++#define index_cpu_CLWB COMMON_CPUID_INDEX_7 ++#define index_cpu_TRACE COMMON_CPUID_INDEX_7 ++#define index_cpu_AVX512PF COMMON_CPUID_INDEX_7 ++#define index_cpu_AVX512ER COMMON_CPUID_INDEX_7 ++#define index_cpu_AVX512CD COMMON_CPUID_INDEX_7 ++#define index_cpu_SHA COMMON_CPUID_INDEX_7 ++#define index_cpu_AVX512BW COMMON_CPUID_INDEX_7 ++#define index_cpu_AVX512VL COMMON_CPUID_INDEX_7 ++ ++/* ECX. */ ++#define index_cpu_PREFETCHWT1 COMMON_CPUID_INDEX_7 ++#define index_cpu_AVX512_VBMI COMMON_CPUID_INDEX_7 ++#define index_cpu_UMIP COMMON_CPUID_INDEX_7 ++#define index_cpu_PKU COMMON_CPUID_INDEX_7 ++#define index_cpu_OSPKE COMMON_CPUID_INDEX_7 ++#define index_cpu_WAITPKG COMMON_CPUID_INDEX_7 ++#define index_cpu_AVX512_VBMI2 COMMON_CPUID_INDEX_7 ++#define index_cpu_SHSTK COMMON_CPUID_INDEX_7 ++#define index_cpu_GFNI COMMON_CPUID_INDEX_7 ++#define index_cpu_VAES COMMON_CPUID_INDEX_7 ++#define index_cpu_VPCLMULQDQ COMMON_CPUID_INDEX_7 ++#define index_cpu_AVX512_VNNI COMMON_CPUID_INDEX_7 ++#define index_cpu_AVX512_BITALG COMMON_CPUID_INDEX_7 ++#define index_cpu_AVX512_VPOPCNTDQ COMMON_CPUID_INDEX_7 ++#define index_cpu_RDPID COMMON_CPUID_INDEX_7 ++#define index_cpu_CLDEMOTE COMMON_CPUID_INDEX_7 ++#define index_cpu_MOVDIRI COMMON_CPUID_INDEX_7 ++#define index_cpu_MOVDIR64B COMMON_CPUID_INDEX_7 ++#define index_cpu_SGX_LC COMMON_CPUID_INDEX_7 ++ ++/* EDX. */ ++#define index_cpu_AVX512_4VNNIW COMMON_CPUID_INDEX_7 ++#define index_cpu_AVX512_4FMAPS COMMON_CPUID_INDEX_7 ++#define index_cpu_FSRM COMMON_CPUID_INDEX_7 ++#define index_cpu_PCONFIG COMMON_CPUID_INDEX_7 ++#define index_cpu_IBT COMMON_CPUID_INDEX_7 ++#define index_cpu_IBRS_IBPB COMMON_CPUID_INDEX_7 ++#define index_cpu_STIBP COMMON_CPUID_INDEX_7 ++#define index_cpu_CAPABILITIES COMMON_CPUID_INDEX_7 ++#define index_cpu_SSBD COMMON_CPUID_INDEX_7 ++ ++/* COMMON_CPUID_INDEX_80000001. */ ++ ++/* ECX. */ ++#define index_cpu_LAHF64_SAHF64 COMMON_CPUID_INDEX_80000001 ++#define index_cpu_SVM COMMON_CPUID_INDEX_80000001 ++#define index_cpu_LZCNT COMMON_CPUID_INDEX_80000001 ++#define index_cpu_SSE4A COMMON_CPUID_INDEX_80000001 ++#define index_cpu_PREFETCHW COMMON_CPUID_INDEX_80000001 ++#define index_cpu_XOP COMMON_CPUID_INDEX_80000001 ++#define index_cpu_LWP COMMON_CPUID_INDEX_80000001 ++#define index_cpu_FMA4 COMMON_CPUID_INDEX_80000001 ++#define index_cpu_TBM COMMON_CPUID_INDEX_80000001 ++ ++/* EDX. */ ++#define index_cpu_SYSCALL_SYSRET COMMON_CPUID_INDEX_80000001 ++#define index_cpu_NX COMMON_CPUID_INDEX_80000001 ++#define index_cpu_PAGE1GB COMMON_CPUID_INDEX_80000001 ++#define index_cpu_RDTSCP COMMON_CPUID_INDEX_80000001 ++#define index_cpu_LM COMMON_CPUID_INDEX_80000001 ++ ++/* COMMON_CPUID_INDEX_D_ECX_1. */ ++ ++/* EAX. */ ++#define index_cpu_XSAVEOPT COMMON_CPUID_INDEX_D_ECX_1 ++#define index_cpu_XSAVEC COMMON_CPUID_INDEX_D_ECX_1 ++#define index_cpu_XGETBV_ECX_1 COMMON_CPUID_INDEX_D_ECX_1 ++#define index_cpu_XSAVES COMMON_CPUID_INDEX_D_ECX_1 ++ ++/* COMMON_CPUID_INDEX_80000007. */ ++ ++/* EDX. */ ++#define index_cpu_INVARIANT_TSC COMMON_CPUID_INDEX_80000007 ++ ++/* COMMON_CPUID_INDEX_80000008. */ ++ ++/* EBX. */ ++#define index_cpu_WBNOINVD COMMON_CPUID_INDEX_80000008 ++ ++/* COMMON_CPUID_INDEX_1. */ ++ ++/* ECX. */ ++#define reg_SSE3 ecx ++#define reg_PCLMULQDQ ecx ++#define reg_DTES64 ecx ++#define reg_MONITOR ecx ++#define reg_DS_CPL ecx ++#define reg_VMX ecx ++#define reg_SMX ecx ++#define reg_EST ecx ++#define reg_TM2 ecx ++#define reg_SSSE3 ecx ++#define reg_CNXT_ID ecx ++#define reg_SDBG ecx ++#define reg_FMA ecx ++#define reg_CMPXCHG16B ecx ++#define reg_XTPRUPDCTRL ecx ++#define reg_PDCM ecx ++#define reg_PCID ecx ++#define reg_DCA ecx ++#define reg_SSE4_1 ecx ++#define reg_SSE4_2 ecx ++#define reg_X2APIC ecx ++#define reg_MOVBE ecx ++#define reg_POPCNT ecx ++#define reg_TSC_DEADLINE ecx ++#define reg_AES ecx ++#define reg_XSAVE ecx ++#define reg_OSXSAVE ecx ++#define reg_AVX ecx ++#define reg_F16C ecx ++#define reg_RDRAND ecx ++ ++/* EDX. */ ++#define reg_FPU edx ++#define reg_VME edx ++#define reg_DE edx ++#define reg_PSE edx ++#define reg_TSC edx ++#define reg_MSR edx ++#define reg_PAE edx ++#define reg_MCE edx ++#define reg_CX8 edx ++#define reg_APIC edx ++#define reg_SEP edx ++#define reg_MTRR edx ++#define reg_PGE edx ++#define reg_MCA edx ++#define reg_CMOV edx ++#define reg_PAT edx ++#define reg_PSE_36 edx ++#define reg_PSN edx ++#define reg_CLFSH edx ++#define reg_DS edx ++#define reg_ACPI edx ++#define reg_MMX edx ++#define reg_FXSR edx ++#define reg_SSE edx ++#define reg_SSE2 edx ++#define reg_SS edx ++#define reg_HTT edx ++#define reg_TM edx ++#define reg_PBE edx ++ ++/* COMMON_CPUID_INDEX_7. */ ++ ++/* EBX. */ ++#define reg_FSGSBASE ebx ++#define reg_TSC_ADJUST ebx ++#define reg_SGX ebx ++#define reg_BMI1 ebx ++#define reg_HLE ebx ++#define reg_BMI2 ebx ++#define reg_AVX2 ebx ++#define reg_SMEP ebx ++#define reg_ERMS ebx ++#define reg_INVPCID ebx ++#define reg_RTM ebx ++#define reg_PQM ebx ++#define reg_MPX ebx ++#define reg_PQE ebx ++#define reg_AVX512F ebx ++#define reg_AVX512DQ ebx ++#define reg_RDSEED ebx ++#define reg_ADX ebx ++#define reg_SMAP ebx ++#define reg_AVX512_IFMA ebx ++#define reg_CLFLUSHOPT ebx ++#define reg_CLWB ebx ++#define reg_TRACE ebx ++#define reg_AVX512PF ebx ++#define reg_AVX512ER ebx ++#define reg_AVX512CD ebx ++#define reg_SHA ebx ++#define reg_AVX512BW ebx ++#define reg_AVX512VL ebx ++ ++/* ECX. */ ++#define reg_PREFETCHWT1 ecx ++#define reg_AVX512_VBMI ecx ++#define reg_UMIP ecx ++#define reg_PKU ecx ++#define reg_OSPKE ecx ++#define reg_WAITPKG ecx ++#define reg_AVX512_VBMI2 ecx ++#define reg_SHSTK ecx ++#define reg_GFNI ecx ++#define reg_VAES ecx ++#define reg_VPCLMULQDQ ecx ++#define reg_AVX512_VNNI ecx ++#define reg_AVX512_BITALG ecx ++#define reg_AVX512_VPOPCNTDQ ecx ++#define reg_RDPID ecx ++#define reg_CLDEMOTE ecx ++#define reg_MOVDIRI ecx ++#define reg_MOVDIR64B ecx ++#define reg_SGX_LC ecx ++ ++/* EDX. */ ++#define reg_AVX512_4VNNIW edx ++#define reg_AVX512_4FMAPS edx ++#define reg_FSRM edx ++#define reg_PCONFIG edx ++#define reg_IBT edx ++#define reg_IBRS_IBPB edx ++#define reg_STIBP edx ++#define reg_CAPABILITIES edx ++#define reg_SSBD edx ++ ++/* COMMON_CPUID_INDEX_80000001. */ ++ ++/* ECX. */ ++#define reg_LAHF64_SAHF64 ecx ++#define reg_SVM ecx ++#define reg_LZCNT ecx ++#define reg_SSE4A ecx ++#define reg_PREFETCHW ecx ++#define reg_XOP ecx ++#define reg_LWP ecx ++#define reg_FMA4 ecx ++#define reg_TBM ecx ++ ++/* EDX. */ ++#define reg_SYSCALL_SYSRET edx ++#define reg_NX edx ++#define reg_PAGE1GB edx ++#define reg_RDTSCP edx ++#define reg_LM edx ++ ++/* COMMON_CPUID_INDEX_D_ECX_1. */ ++ ++/* EAX. */ ++#define reg_XSAVEOPT eax ++#define reg_XSAVEC eax ++#define reg_XGETBV_ECX_1 eax ++#define reg_XSAVES eax ++ ++/* COMMON_CPUID_INDEX_80000007. */ ++ ++/* EDX. */ ++#define reg_INVARIANT_TSC edx ++ ++/* COMMON_CPUID_INDEX_80000008. */ ++ ++/* EBX. */ ++#define reg_WBNOINVD ebx ++ ++/* FEATURE_INDEX_2. */ ++#define bit_arch_I586 (1u << 0) ++#define bit_arch_I686 (1u << 1) ++#define bit_arch_Fast_Rep_String (1u << 2) ++#define bit_arch_Fast_Copy_Backward (1u << 3) ++#define bit_arch_Fast_Unaligned_Load (1u << 4) ++#define bit_arch_Fast_Unaligned_Copy (1u << 5) ++#define bit_arch_Slow_BSF (1u << 6) ++#define bit_arch_Slow_SSE4_2 (1u << 7) ++#define bit_arch_AVX_Fast_Unaligned_Load (1u << 8) ++#define bit_arch_Prefer_MAP_32BIT_EXEC (1u << 9) ++#define bit_arch_Prefer_PMINUB_for_stringop (1u << 10) ++#define bit_arch_Prefer_No_VZEROUPPER (1u << 11) ++#define bit_arch_Prefer_ERMS (1u << 12) ++#define bit_arch_Prefer_FSRM (1u << 13) ++#define bit_arch_Prefer_No_AVX512 (1u << 14) ++#define bit_arch_MathVec_Prefer_No_AVX512 (1u << 15) ++ ++#define index_arch_Fast_Rep_String FEATURE_INDEX_2 ++#define index_arch_Fast_Copy_Backward FEATURE_INDEX_2 ++#define index_arch_Slow_BSF FEATURE_INDEX_2 ++#define index_arch_Fast_Unaligned_Load FEATURE_INDEX_2 ++#define index_arch_Prefer_PMINUB_for_stringop FEATURE_INDEX_2 ++#define index_arch_Fast_Unaligned_Copy FEATURE_INDEX_2 ++#define index_arch_I586 FEATURE_INDEX_2 ++#define index_arch_I686 FEATURE_INDEX_2 ++#define index_arch_Slow_SSE4_2 FEATURE_INDEX_2 ++#define index_arch_AVX_Fast_Unaligned_Load FEATURE_INDEX_2 ++#define index_arch_Prefer_MAP_32BIT_EXEC FEATURE_INDEX_2 ++#define index_arch_Prefer_No_VZEROUPPER FEATURE_INDEX_2 ++#define index_arch_Prefer_ERMS FEATURE_INDEX_2 ++#define index_arch_Prefer_No_AVX512 FEATURE_INDEX_2 ++#define index_arch_MathVec_Prefer_No_AVX512 FEATURE_INDEX_2 ++#define index_arch_Prefer_FSRM FEATURE_INDEX_2 ++ ++/* XCR0 Feature flags. */ ++#define bit_XMM_state (1u << 1) ++#define bit_YMM_state (1u << 2) ++#define bit_Opmask_state (1u << 5) ++#define bit_ZMM0_15_state (1u << 6) ++#define bit_ZMM16_31_state (1u << 7) ++ ++# if defined (_LIBC) && !IS_IN (nonlib) ++/* Unused for x86. */ ++# define INIT_ARCH() ++# define __get_cpu_features() (&GLRO(dl_x86_cpu_features)) ++# define x86_get_cpuid_registers(i) \ ++ (&(GLRO(dl_x86_cpu_features).cpuid[i])) ++# endif + + #ifdef __x86_64__ + # define HAS_CPUID 1 +diff --git a/sysdeps/x86/tst-get-cpu-features.c b/sysdeps/x86/tst-get-cpu-features.c +index b2fac197dac7708e..64a7fd6157242bdd 100644 +--- a/sysdeps/x86/tst-get-cpu-features.c ++++ b/sysdeps/x86/tst-get-cpu-features.c +@@ -17,15 +17,271 @@ + . */ + + #include ++#include + #include ++#include ++ ++#define CHECK_CPU_FEATURE(name) \ ++ { \ ++ if (HAS_CPU_FEATURE (name)) \ ++ printf (" " #name "\n"); \ ++ } ++ ++#define CHECK_CPU_FEATURE_USABLE(name) \ ++ { \ ++ if (CPU_FEATURE_USABLE(name)) \ ++ printf (" " #name "\n"); \ ++ } ++ ++static const char * const cpu_kinds[] = ++{ ++ "Unknown", ++ "Intel", ++ "AMD", ++ "Other", ++}; + + static int + do_test (void) + { +- if (__get_cpu_features ()->kind == arch_kind_unknown) +- abort (); ++ const struct cpu_features *cpu_features = __get_cpu_features (); ++ ++ switch (cpu_features->basic.kind) ++ { ++ case arch_kind_intel: ++ case arch_kind_amd: ++ case arch_kind_other: ++ printf ("Vendor: %s\n", cpu_kinds[cpu_features->basic.kind]); ++ printf ("Family: 0x%x\n", cpu_features->basic.family); ++ printf ("Model: 0x%x\n", cpu_features->basic.model); ++ printf ("Stepping: 0x%x\n", cpu_features->basic.stepping); ++ break; ++ ++ default: ++ abort (); ++ } ++ ++#ifdef __SSE2__ ++ TEST_VERIFY_EXIT (HAS_CPU_FEATURE (SSE2)); ++#endif ++ ++ printf ("CPU features:\n"); ++ CHECK_CPU_FEATURE (SSE3); ++ CHECK_CPU_FEATURE (PCLMULQDQ); ++ CHECK_CPU_FEATURE (DTES64); ++ CHECK_CPU_FEATURE (MONITOR); ++ CHECK_CPU_FEATURE (DS_CPL); ++ CHECK_CPU_FEATURE (VMX); ++ CHECK_CPU_FEATURE (SMX); ++ CHECK_CPU_FEATURE (EST); ++ CHECK_CPU_FEATURE (TM2); ++ CHECK_CPU_FEATURE (SSSE3); ++ CHECK_CPU_FEATURE (CNXT_ID); ++ CHECK_CPU_FEATURE (SDBG); ++ CHECK_CPU_FEATURE (FMA); ++ CHECK_CPU_FEATURE (CMPXCHG16B); ++ CHECK_CPU_FEATURE (XTPRUPDCTRL); ++ CHECK_CPU_FEATURE (PDCM); ++ CHECK_CPU_FEATURE (PCID); ++ CHECK_CPU_FEATURE (DCA); ++ CHECK_CPU_FEATURE (SSE4_1); ++ CHECK_CPU_FEATURE (SSE4_2); ++ CHECK_CPU_FEATURE (X2APIC); ++ CHECK_CPU_FEATURE (MOVBE); ++ CHECK_CPU_FEATURE (POPCNT); ++ CHECK_CPU_FEATURE (TSC_DEADLINE); ++ CHECK_CPU_FEATURE (AES); ++ CHECK_CPU_FEATURE (XSAVE); ++ CHECK_CPU_FEATURE (OSXSAVE); ++ CHECK_CPU_FEATURE (AVX); ++ CHECK_CPU_FEATURE (F16C); ++ CHECK_CPU_FEATURE (RDRAND); ++ CHECK_CPU_FEATURE (FPU); ++ CHECK_CPU_FEATURE (VME); ++ CHECK_CPU_FEATURE (DE); ++ CHECK_CPU_FEATURE (PSE); ++ CHECK_CPU_FEATURE (TSC); ++ CHECK_CPU_FEATURE (MSR); ++ CHECK_CPU_FEATURE (PAE); ++ CHECK_CPU_FEATURE (MCE); ++ CHECK_CPU_FEATURE (CX8); ++ CHECK_CPU_FEATURE (APIC); ++ CHECK_CPU_FEATURE (SEP); ++ CHECK_CPU_FEATURE (MTRR); ++ CHECK_CPU_FEATURE (PGE); ++ CHECK_CPU_FEATURE (MCA); ++ CHECK_CPU_FEATURE (CMOV); ++ CHECK_CPU_FEATURE (PAT); ++ CHECK_CPU_FEATURE (PSE_36); ++ CHECK_CPU_FEATURE (PSN); ++ CHECK_CPU_FEATURE (CLFSH); ++ CHECK_CPU_FEATURE (DS); ++ CHECK_CPU_FEATURE (ACPI); ++ CHECK_CPU_FEATURE (MMX); ++ CHECK_CPU_FEATURE (FXSR); ++ CHECK_CPU_FEATURE (SSE); ++ CHECK_CPU_FEATURE (SSE2); ++ CHECK_CPU_FEATURE (SS); ++ CHECK_CPU_FEATURE (HTT); ++ CHECK_CPU_FEATURE (TM); ++ CHECK_CPU_FEATURE (PBE); ++ CHECK_CPU_FEATURE (FSGSBASE); ++ CHECK_CPU_FEATURE (TSC_ADJUST); ++ CHECK_CPU_FEATURE (SGX); ++ CHECK_CPU_FEATURE (BMI1); ++ CHECK_CPU_FEATURE (HLE); ++ CHECK_CPU_FEATURE (AVX2); ++ CHECK_CPU_FEATURE (SMEP); ++ CHECK_CPU_FEATURE (BMI2); ++ CHECK_CPU_FEATURE (ERMS); ++ CHECK_CPU_FEATURE (INVPCID); ++ CHECK_CPU_FEATURE (RTM); ++ CHECK_CPU_FEATURE (PQM); ++ CHECK_CPU_FEATURE (MPX); ++ CHECK_CPU_FEATURE (PQE); ++ CHECK_CPU_FEATURE (AVX512F); ++ CHECK_CPU_FEATURE (AVX512DQ); ++ CHECK_CPU_FEATURE (RDSEED); ++ CHECK_CPU_FEATURE (ADX); ++ CHECK_CPU_FEATURE (SMAP); ++ CHECK_CPU_FEATURE (AVX512_IFMA); ++ CHECK_CPU_FEATURE (CLFLUSHOPT); ++ CHECK_CPU_FEATURE (CLWB); ++ CHECK_CPU_FEATURE (TRACE); ++ CHECK_CPU_FEATURE (AVX512PF); ++ CHECK_CPU_FEATURE (AVX512ER); ++ CHECK_CPU_FEATURE (AVX512CD); ++ CHECK_CPU_FEATURE (SHA); ++ CHECK_CPU_FEATURE (AVX512BW); ++ CHECK_CPU_FEATURE (AVX512VL); ++ CHECK_CPU_FEATURE (PREFETCHWT1); ++ CHECK_CPU_FEATURE (AVX512_VBMI); ++ CHECK_CPU_FEATURE (UMIP); ++ CHECK_CPU_FEATURE (PKU); ++ CHECK_CPU_FEATURE (OSPKE); ++ CHECK_CPU_FEATURE (WAITPKG); ++ CHECK_CPU_FEATURE (AVX512_VBMI2); ++ CHECK_CPU_FEATURE (SHSTK); ++ CHECK_CPU_FEATURE (GFNI); ++ CHECK_CPU_FEATURE (VAES); ++ CHECK_CPU_FEATURE (VPCLMULQDQ); ++ CHECK_CPU_FEATURE (AVX512_VNNI); ++ CHECK_CPU_FEATURE (AVX512_BITALG); ++ CHECK_CPU_FEATURE (AVX512_VPOPCNTDQ); ++ CHECK_CPU_FEATURE (RDPID); ++ CHECK_CPU_FEATURE (CLDEMOTE); ++ CHECK_CPU_FEATURE (MOVDIRI); ++ CHECK_CPU_FEATURE (MOVDIR64B); ++ CHECK_CPU_FEATURE (SGX_LC); ++ CHECK_CPU_FEATURE (AVX512_4VNNIW); ++ CHECK_CPU_FEATURE (AVX512_4FMAPS); ++ CHECK_CPU_FEATURE (FSRM); ++ CHECK_CPU_FEATURE (PCONFIG); ++ CHECK_CPU_FEATURE (IBT); ++ CHECK_CPU_FEATURE (IBRS_IBPB); ++ CHECK_CPU_FEATURE (STIBP); ++ CHECK_CPU_FEATURE (CAPABILITIES); ++ CHECK_CPU_FEATURE (SSBD); ++ CHECK_CPU_FEATURE (LAHF64_SAHF64); ++ CHECK_CPU_FEATURE (SVM); ++ CHECK_CPU_FEATURE (LZCNT); ++ CHECK_CPU_FEATURE (SSE4A); ++ CHECK_CPU_FEATURE (PREFETCHW); ++ CHECK_CPU_FEATURE (XOP); ++ CHECK_CPU_FEATURE (LWP); ++ CHECK_CPU_FEATURE (FMA4); ++ CHECK_CPU_FEATURE (TBM); ++ CHECK_CPU_FEATURE (SYSCALL_SYSRET); ++ CHECK_CPU_FEATURE (NX); ++ CHECK_CPU_FEATURE (PAGE1GB); ++ CHECK_CPU_FEATURE (RDTSCP); ++ CHECK_CPU_FEATURE (LM); ++ CHECK_CPU_FEATURE (XSAVEOPT); ++ CHECK_CPU_FEATURE (XSAVEC); ++ CHECK_CPU_FEATURE (XGETBV_ECX_1); ++ CHECK_CPU_FEATURE (XSAVES); ++ CHECK_CPU_FEATURE (INVARIANT_TSC); ++ CHECK_CPU_FEATURE (WBNOINVD); ++ ++ printf ("Usable CPU features:\n"); ++ CHECK_CPU_FEATURE_USABLE (SSE3); ++ CHECK_CPU_FEATURE_USABLE (PCLMULQDQ); ++ CHECK_CPU_FEATURE_USABLE (SSSE3); ++ CHECK_CPU_FEATURE_USABLE (FMA); ++ CHECK_CPU_FEATURE_USABLE (CMPXCHG16B); ++ CHECK_CPU_FEATURE_USABLE (SSE4_1); ++ CHECK_CPU_FEATURE_USABLE (SSE4_2); ++ CHECK_CPU_FEATURE_USABLE (MOVBE); ++ CHECK_CPU_FEATURE_USABLE (POPCNT); ++ CHECK_CPU_FEATURE_USABLE (AES); ++ CHECK_CPU_FEATURE_USABLE (XSAVE); ++ CHECK_CPU_FEATURE_USABLE (OSXSAVE); ++ CHECK_CPU_FEATURE_USABLE (AVX); ++ CHECK_CPU_FEATURE_USABLE (F16C); ++ CHECK_CPU_FEATURE_USABLE (RDRAND); ++ CHECK_CPU_FEATURE_USABLE (FPU); ++ CHECK_CPU_FEATURE_USABLE (TSC); ++ CHECK_CPU_FEATURE_USABLE (MSR); ++ CHECK_CPU_FEATURE_USABLE (CX8); ++ CHECK_CPU_FEATURE_USABLE (SEP); ++ CHECK_CPU_FEATURE_USABLE (CMOV); ++ CHECK_CPU_FEATURE_USABLE (CLFSH); ++ CHECK_CPU_FEATURE_USABLE (MMX); ++ CHECK_CPU_FEATURE_USABLE (FXSR); ++ CHECK_CPU_FEATURE_USABLE (SSE); ++ CHECK_CPU_FEATURE_USABLE (SSE2); ++ CHECK_CPU_FEATURE_USABLE (FSGSBASE); ++ CHECK_CPU_FEATURE_USABLE (BMI1); ++ CHECK_CPU_FEATURE_USABLE (HLE); ++ CHECK_CPU_FEATURE_USABLE (AVX2); ++ CHECK_CPU_FEATURE_USABLE (BMI2); ++ CHECK_CPU_FEATURE_USABLE (ERMS); ++ CHECK_CPU_FEATURE_USABLE (AVX512F); ++ CHECK_CPU_FEATURE_USABLE (AVX512DQ); ++ CHECK_CPU_FEATURE_USABLE (RDSEED); ++ CHECK_CPU_FEATURE_USABLE (ADX); ++ CHECK_CPU_FEATURE_USABLE (AVX512_IFMA); ++ CHECK_CPU_FEATURE_USABLE (CLFLUSHOPT); ++ CHECK_CPU_FEATURE_USABLE (CLWB); ++ CHECK_CPU_FEATURE_USABLE (AVX512PF); ++ CHECK_CPU_FEATURE_USABLE (AVX512ER); ++ CHECK_CPU_FEATURE_USABLE (AVX512CD); ++ CHECK_CPU_FEATURE_USABLE (SHA); ++ CHECK_CPU_FEATURE_USABLE (AVX512BW); ++ CHECK_CPU_FEATURE_USABLE (AVX512VL); ++ CHECK_CPU_FEATURE_USABLE (PREFETCHWT1); ++ CHECK_CPU_FEATURE_USABLE (AVX512_VBMI); ++ CHECK_CPU_FEATURE_USABLE (AVX512_VBMI2); ++ CHECK_CPU_FEATURE_USABLE (GFNI); ++ CHECK_CPU_FEATURE_USABLE (VAES); ++ CHECK_CPU_FEATURE_USABLE (VPCLMULQDQ); ++ CHECK_CPU_FEATURE_USABLE (AVX512_VNNI); ++ CHECK_CPU_FEATURE_USABLE (AVX512_BITALG); ++ CHECK_CPU_FEATURE_USABLE (AVX512_VPOPCNTDQ); ++ CHECK_CPU_FEATURE_USABLE (RDPID); ++ CHECK_CPU_FEATURE_USABLE (CLDEMOTE); ++ CHECK_CPU_FEATURE_USABLE (MOVDIRI); ++ CHECK_CPU_FEATURE_USABLE (MOVDIR64B); ++ CHECK_CPU_FEATURE_USABLE (AVX512_4VNNIW); ++ CHECK_CPU_FEATURE_USABLE (AVX512_4FMAPS); ++ CHECK_CPU_FEATURE_USABLE (FSRM); ++ CHECK_CPU_FEATURE_USABLE (LAHF64_SAHF64); ++ CHECK_CPU_FEATURE_USABLE (LZCNT); ++ CHECK_CPU_FEATURE_USABLE (SSE4A); ++ CHECK_CPU_FEATURE_USABLE (PREFETCHW); ++ CHECK_CPU_FEATURE_USABLE (XOP); ++ CHECK_CPU_FEATURE_USABLE (FMA4); ++ CHECK_CPU_FEATURE_USABLE (TBM); ++ CHECK_CPU_FEATURE_USABLE (SYSCALL_SYSRET); ++ CHECK_CPU_FEATURE_USABLE (RDTSCP); ++ CHECK_CPU_FEATURE_USABLE (XSAVEOPT); ++ CHECK_CPU_FEATURE_USABLE (XSAVEC); ++ CHECK_CPU_FEATURE_USABLE (XGETBV_ECX_1); ++ CHECK_CPU_FEATURE_USABLE (XSAVES); ++ CHECK_CPU_FEATURE_USABLE (INVARIANT_TSC); ++ CHECK_CPU_FEATURE_USABLE (WBNOINVD); ++ + return 0; + } + +-#define TEST_FUNCTION do_test () +-#include "../../test-skeleton.c" ++#include +diff --git a/sysdeps/x86_64/multiarch/sched_cpucount.c b/sysdeps/x86_64/multiarch/sched_cpucount.c +index d10d74ae21e05d47..7949119dcdb5a94b 100644 +--- a/sysdeps/x86_64/multiarch/sched_cpucount.c ++++ b/sysdeps/x86_64/multiarch/sched_cpucount.c +@@ -33,4 +33,4 @@ + #undef __sched_cpucount + + libc_ifunc (__sched_cpucount, +- HAS_CPU_FEATURE (POPCOUNT) ? popcount_cpucount : generic_cpucount); ++ HAS_CPU_FEATURE (POPCNT) ? popcount_cpucount : generic_cpucount); +diff --git a/sysdeps/x86_64/multiarch/test-multiarch.c b/sysdeps/x86_64/multiarch/test-multiarch.c +index aa872f27dbe7ea2f..417147c3d5f325a5 100644 +--- a/sysdeps/x86_64/multiarch/test-multiarch.c ++++ b/sysdeps/x86_64/multiarch/test-multiarch.c +@@ -85,8 +85,8 @@ do_test (int argc, char **argv) + , "HAS_CPU_FEATURE (SSE4_1)"); + fails += check_proc ("ssse3", HAS_CPU_FEATURE (SSSE3), + "HAS_CPU_FEATURE (SSSE3)"); +- fails += check_proc ("popcnt", HAS_CPU_FEATURE (POPCOUNT), +- "HAS_CPU_FEATURE (POPCOUNT)"); ++ fails += check_proc ("popcnt", HAS_CPU_FEATURE (POPCNT), ++ "HAS_CPU_FEATURE (POPCNT)"); + + printf ("%d differences between /proc/cpuinfo and glibc code.\n", fails); + diff --git a/SOURCES/glibc-rh1817513-16.patch b/SOURCES/glibc-rh1817513-16.patch new file mode 100644 index 0000000..2698a30 --- /dev/null +++ b/SOURCES/glibc-rh1817513-16.patch @@ -0,0 +1,146 @@ +commit b2e93de0ffedcfe2cfba100d47a4d4f6f85cea0b +Author: DJ Delorie +Date: Tue Dec 4 00:03:12 2018 -0500 + + test-container: add "su" command to run test as root, add unshare hints + + * support/test-container.c (check_for_unshare_hints): New. + (main): Call it if unshare fails. Add support for "su" scriptlet + command. + +diff --git a/support/test-container.c b/support/test-container.c +index fe0ebbd07df83da7..1d1aebeaf3412573 100644 +--- a/support/test-container.c ++++ b/support/test-container.c +@@ -88,15 +88,22 @@ int verbose = 0; + * mytest.root/ is rsync'd into container + * mytest.root/preclean.req causes fresh rsync (with delete) before + test if present +- * mytest.root/mytset.script has a list of "commands" to run: ++ * mytest.root/mytest.script has a list of "commands" to run: + syntax: + # comment ++ su + mv FILE FILE + cp FILE FILE + rm FILE + FILE must start with $B/, $S/, $I/, $L/, or / + (expands to build dir, source dir, install dir, library dir + (in container), or container's root) ++ details: ++ - '#': A comment. ++ - 'su': Enables running test as root in the container. ++ - 'mv': A minimal move files command. ++ - 'cp': A minimal copy files command. ++ - 'rm': A minimal remove files command. + * mytest.root/postclean.req causes fresh rsync (with delete) after + test if present + +@@ -349,6 +356,7 @@ recursive_remove (char *path) + + switch (child) { + case -1: ++ perror("fork"); + FAIL_EXIT1 ("Unable to fork"); + case 0: + /* Child. */ +@@ -610,6 +618,47 @@ rsync (char *src, char *dest, int and_delete) + } + + ++ ++/* See if we can detect what the user needs to do to get unshare ++ support working for us. */ ++void ++check_for_unshare_hints (void) ++{ ++ FILE *f; ++ int i; ++ ++ /* Default Debian Linux disables user namespaces, but allows a way ++ to enable them. */ ++ f = fopen ("/proc/sys/kernel/unprivileged_userns_clone", "r"); ++ if (f != NULL) ++ { ++ i = 99; /* Sentinel. */ ++ fscanf (f, "%d", &i); ++ if (i == 0) ++ { ++ printf ("To enable test-container, please run this as root:\n"); ++ printf (" echo 1 > /proc/sys/kernel/unprivileged_userns_clone\n"); ++ } ++ fclose (f); ++ return; ++ } ++ ++ /* ALT Linux has an alternate way of doing the same. */ ++ f = fopen ("/proc/sys/kernel/userns_restrict", "r"); ++ if (f != NULL) ++ { ++ i = 99; /* Sentinel. */ ++ fscanf (f, "%d", &i); ++ if (i == 1) ++ { ++ printf ("To enable test-container, please run this as root:\n"); ++ printf (" echo 0 > /proc/sys/kernel/userns_restrict\n"); ++ } ++ fclose (f); ++ return; ++ } ++} ++ + int + main (int argc, char **argv) + { +@@ -628,6 +677,8 @@ main (int argc, char **argv) + + uid_t original_uid; + gid_t original_gid; ++ /* If set, the test runs as root instead of the user running the testsuite. */ ++ int be_su = 0; + int UMAP; + int GMAP; + /* Used for "%lld %lld 1" so need not be large. */ +@@ -857,6 +908,10 @@ main (int argc, char **argv) + { + maybe_xunlink (the_words[1]); + } ++ else if (nt == 1 && strcmp (the_words[0], "su") == 0) ++ { ++ be_su = 1; ++ } + else if (nt > 0 && the_words[0][0] != '#') + { + printf ("\033[31minvalid [%s]\033[0m\n", the_words[0]); +@@ -910,7 +965,12 @@ main (int argc, char **argv) + /* Older kernels may not support all the options, or security + policy may block this call. */ + if (errno == EINVAL || errno == EPERM) +- FAIL_UNSUPPORTED ("unable to unshare user/fs: %s", strerror (errno)); ++ { ++ int saved_errno = errno; ++ if (errno == EPERM) ++ check_for_unshare_hints (); ++ FAIL_UNSUPPORTED ("unable to unshare user/fs: %s", strerror (saved_errno)); ++ } + else + FAIL_EXIT1 ("unable to unshare user/fs: %s", strerror (errno)); + } +@@ -981,7 +1041,7 @@ main (int argc, char **argv) + FAIL_EXIT1 ("can't write to /proc/self/uid_map\n"); + + sprintf (tmp, "%lld %lld 1\n", +- (long long) original_uid, (long long) original_uid); ++ (long long) (be_su ? 0 : original_uid), (long long) original_uid); + write (UMAP, tmp, strlen (tmp)); + xclose (UMAP); + +@@ -1002,7 +1062,7 @@ main (int argc, char **argv) + FAIL_EXIT1 ("can't write to /proc/self/gid_map\n"); + + sprintf (tmp, "%lld %lld 1\n", +- (long long) original_gid, (long long) original_gid); ++ (long long) (be_su ? 0 : original_gid), (long long) original_gid); + write (GMAP, tmp, strlen (tmp)); + xclose (GMAP); + diff --git a/SOURCES/glibc-rh1817513-17.patch b/SOURCES/glibc-rh1817513-17.patch new file mode 100644 index 0000000..faeb2bd --- /dev/null +++ b/SOURCES/glibc-rh1817513-17.patch @@ -0,0 +1,1559 @@ +commit 1a153e47fcc9401d8ea424ad86569a57ed0f8c52 +Author: Leonardo Sandoval +Date: Mon Oct 8 08:59:50 2018 -0500 + + x86-64: Optimize strcat/strncat, strcpy/strncpy and stpcpy/stpncpy with AVX2 + + Optimize x86-64 strcat/strncat, strcpy/strncpy and stpcpy/stpncpy with AVX2. + It uses vector comparison as much as possible. In general, the larger the + source string, the greater performance gain observed, reaching speedups of + 1.6x compared to SSE2 unaligned routines. Select AVX2 strcat/strncat, + strcpy/strncpy and stpcpy/stpncpy on AVX2 machines where vzeroupper is + preferred and AVX unaligned load is fast. + + * sysdeps/x86_64/multiarch/Makefile (sysdep_routines): Add + strcat-avx2, strncat-avx2, strcpy-avx2, strncpy-avx2, + stpcpy-avx2 and stpncpy-avx2. + * sysdeps/x86_64/multiarch/ifunc-impl-list.c: + (__libc_ifunc_impl_list): Add tests for __strcat_avx2, + __strncat_avx2, __strcpy_avx2, __strncpy_avx2, __stpcpy_avx2 + and __stpncpy_avx2. + * sysdeps/x86_64/multiarch/{ifunc-unaligned-ssse3.h => + ifunc-strcpy.h}: rename header for a more generic name. + * sysdeps/x86_64/multiarch/ifunc-strcpy.h: + (IFUNC_SELECTOR): Return OPTIMIZE (avx2) on AVX 2 machines if + AVX unaligned load is fast and vzeroupper is preferred. + * sysdeps/x86_64/multiarch/stpcpy-avx2.S: New file + * sysdeps/x86_64/multiarch/stpncpy-avx2.S: Likewise + * sysdeps/x86_64/multiarch/strcat-avx2.S: Likewise + * sysdeps/x86_64/multiarch/strcpy-avx2.S: Likewise + * sysdeps/x86_64/multiarch/strncat-avx2.S: Likewise + * sysdeps/x86_64/multiarch/strncpy-avx2.S: Likewise + +diff --git a/sysdeps/x86_64/multiarch/Makefile b/sysdeps/x86_64/multiarch/Makefile +index bb5e97073520ee51..395e432c092ca17c 100644 +--- a/sysdeps/x86_64/multiarch/Makefile ++++ b/sysdeps/x86_64/multiarch/Makefile +@@ -24,11 +24,14 @@ sysdep_routines += strncat-c stpncpy-c strncpy-c \ + strchr-sse2 strchrnul-sse2 strchr-avx2 strchrnul-avx2 \ + strrchr-sse2 strrchr-avx2 \ + strlen-sse2 strnlen-sse2 strlen-avx2 strnlen-avx2 \ ++ strcat-avx2 strncat-avx2 \ + strcat-ssse3 strncat-ssse3\ ++ strcpy-avx2 strncpy-avx2 \ + strcpy-sse2 stpcpy-sse2 \ + strcpy-ssse3 strncpy-ssse3 stpcpy-ssse3 stpncpy-ssse3 \ + strcpy-sse2-unaligned strncpy-sse2-unaligned \ + stpcpy-sse2-unaligned stpncpy-sse2-unaligned \ ++ stpcpy-avx2 stpncpy-avx2 \ + strcat-sse2 \ + strcat-sse2-unaligned strncat-sse2-unaligned \ + strchr-sse2-no-bsf memcmp-ssse3 strstr-sse2-unaligned \ +diff --git a/sysdeps/x86_64/multiarch/ifunc-impl-list.c b/sysdeps/x86_64/multiarch/ifunc-impl-list.c +index 9aaaef7251b8edfe..8b55bb6954000cc2 100644 +--- a/sysdeps/x86_64/multiarch/ifunc-impl-list.c ++++ b/sysdeps/x86_64/multiarch/ifunc-impl-list.c +@@ -199,6 +199,8 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + IFUNC_IMPL (i, name, stpncpy, + IFUNC_IMPL_ADD (array, i, stpncpy, HAS_CPU_FEATURE (SSSE3), + __stpncpy_ssse3) ++ IFUNC_IMPL_ADD (array, i, stpncpy, HAS_ARCH_FEATURE (AVX2_Usable), ++ __stpncpy_avx2) + IFUNC_IMPL_ADD (array, i, stpncpy, 1, + __stpncpy_sse2_unaligned) + IFUNC_IMPL_ADD (array, i, stpncpy, 1, __stpncpy_sse2)) +@@ -207,6 +209,8 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + IFUNC_IMPL (i, name, stpcpy, + IFUNC_IMPL_ADD (array, i, stpcpy, HAS_CPU_FEATURE (SSSE3), + __stpcpy_ssse3) ++ IFUNC_IMPL_ADD (array, i, stpcpy, HAS_ARCH_FEATURE (AVX2_Usable), ++ __stpcpy_avx2) + IFUNC_IMPL_ADD (array, i, stpcpy, 1, __stpcpy_sse2_unaligned) + IFUNC_IMPL_ADD (array, i, stpcpy, 1, __stpcpy_sse2)) + +@@ -239,6 +243,8 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + + /* Support sysdeps/x86_64/multiarch/strcat.c. */ + IFUNC_IMPL (i, name, strcat, ++ IFUNC_IMPL_ADD (array, i, strcat, HAS_ARCH_FEATURE (AVX2_Usable), ++ __strcat_avx2) + IFUNC_IMPL_ADD (array, i, strcat, HAS_CPU_FEATURE (SSSE3), + __strcat_ssse3) + IFUNC_IMPL_ADD (array, i, strcat, 1, __strcat_sse2_unaligned) +@@ -280,6 +286,8 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + + /* Support sysdeps/x86_64/multiarch/strcpy.c. */ + IFUNC_IMPL (i, name, strcpy, ++ IFUNC_IMPL_ADD (array, i, strcpy, HAS_ARCH_FEATURE (AVX2_Usable), ++ __strcpy_avx2) + IFUNC_IMPL_ADD (array, i, strcpy, HAS_CPU_FEATURE (SSSE3), + __strcpy_ssse3) + IFUNC_IMPL_ADD (array, i, strcpy, 1, __strcpy_sse2_unaligned) +@@ -321,6 +329,8 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + + /* Support sysdeps/x86_64/multiarch/strncat.c. */ + IFUNC_IMPL (i, name, strncat, ++ IFUNC_IMPL_ADD (array, i, strncat, HAS_ARCH_FEATURE (AVX2_Usable), ++ __strncat_avx2) + IFUNC_IMPL_ADD (array, i, strncat, HAS_CPU_FEATURE (SSSE3), + __strncat_ssse3) + IFUNC_IMPL_ADD (array, i, strncat, 1, +@@ -329,6 +339,8 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + + /* Support sysdeps/x86_64/multiarch/strncpy.c. */ + IFUNC_IMPL (i, name, strncpy, ++ IFUNC_IMPL_ADD (array, i, strncpy, HAS_ARCH_FEATURE (AVX2_Usable), ++ __strncpy_avx2) + IFUNC_IMPL_ADD (array, i, strncpy, HAS_CPU_FEATURE (SSSE3), + __strncpy_ssse3) + IFUNC_IMPL_ADD (array, i, strncpy, 1, +diff --git a/sysdeps/x86_64/multiarch/ifunc-unaligned-ssse3.h b/sysdeps/x86_64/multiarch/ifunc-strcpy.h +similarity index 83% +rename from sysdeps/x86_64/multiarch/ifunc-unaligned-ssse3.h +rename to sysdeps/x86_64/multiarch/ifunc-strcpy.h +index 81805f9832345923..4f2286fefccda069 100644 +--- a/sysdeps/x86_64/multiarch/ifunc-unaligned-ssse3.h ++++ b/sysdeps/x86_64/multiarch/ifunc-strcpy.h +@@ -24,12 +24,18 @@ extern __typeof (REDIRECT_NAME) OPTIMIZE (sse2) attribute_hidden; + extern __typeof (REDIRECT_NAME) OPTIMIZE (sse2_unaligned) + attribute_hidden; + extern __typeof (REDIRECT_NAME) OPTIMIZE (ssse3) attribute_hidden; ++extern __typeof (REDIRECT_NAME) OPTIMIZE (avx2) attribute_hidden; + + static inline void * + IFUNC_SELECTOR (void) + { + const struct cpu_features* cpu_features = __get_cpu_features (); + ++ if (!CPU_FEATURES_ARCH_P (cpu_features, Prefer_No_VZEROUPPER) ++ && CPU_FEATURES_ARCH_P (cpu_features, AVX2_Usable) ++ && CPU_FEATURES_ARCH_P (cpu_features, AVX_Fast_Unaligned_Load)) ++ return OPTIMIZE (avx2); ++ + if (CPU_FEATURES_ARCH_P (cpu_features, Fast_Unaligned_Load)) + return OPTIMIZE (sse2_unaligned); + +diff --git a/sysdeps/x86_64/multiarch/stpcpy-avx2.S b/sysdeps/x86_64/multiarch/stpcpy-avx2.S +new file mode 100644 +index 0000000000000000..f0bd3029fe3047ed +--- /dev/null ++++ b/sysdeps/x86_64/multiarch/stpcpy-avx2.S +@@ -0,0 +1,3 @@ ++#define USE_AS_STPCPY ++#define STRCPY __stpcpy_avx2 ++#include "strcpy-avx2.S" +diff --git a/sysdeps/x86_64/multiarch/stpcpy.c b/sysdeps/x86_64/multiarch/stpcpy.c +index 1e340fca991a021c..8ffd13b48c83ca8e 100644 +--- a/sysdeps/x86_64/multiarch/stpcpy.c ++++ b/sysdeps/x86_64/multiarch/stpcpy.c +@@ -28,7 +28,7 @@ + # undef __stpcpy + + # define SYMBOL_NAME stpcpy +-# include "ifunc-unaligned-ssse3.h" ++# include "ifunc-strcpy.h" + + libc_ifunc_redirected (__redirect_stpcpy, __stpcpy, IFUNC_SELECTOR ()); + +diff --git a/sysdeps/x86_64/multiarch/stpncpy-avx2.S b/sysdeps/x86_64/multiarch/stpncpy-avx2.S +new file mode 100644 +index 0000000000000000..032b0407d08c6a9d +--- /dev/null ++++ b/sysdeps/x86_64/multiarch/stpncpy-avx2.S +@@ -0,0 +1,4 @@ ++#define USE_AS_STPCPY ++#define USE_AS_STRNCPY ++#define STRCPY __stpncpy_avx2 ++#include "strcpy-avx2.S" +diff --git a/sysdeps/x86_64/multiarch/stpncpy.c b/sysdeps/x86_64/multiarch/stpncpy.c +index 28842ece2b0998e3..f3e203f78cca2e61 100644 +--- a/sysdeps/x86_64/multiarch/stpncpy.c ++++ b/sysdeps/x86_64/multiarch/stpncpy.c +@@ -26,7 +26,7 @@ + # undef __stpncpy + + # define SYMBOL_NAME stpncpy +-# include "ifunc-unaligned-ssse3.h" ++# include "ifunc-strcpy.h" + + libc_ifunc_redirected (__redirect_stpncpy, __stpncpy, IFUNC_SELECTOR ()); + +diff --git a/sysdeps/x86_64/multiarch/strcat-avx2.S b/sysdeps/x86_64/multiarch/strcat-avx2.S +new file mode 100644 +index 0000000000000000..b062356427677ca6 +--- /dev/null ++++ b/sysdeps/x86_64/multiarch/strcat-avx2.S +@@ -0,0 +1,275 @@ ++/* strcat with AVX2 ++ Copyright (C) 2011-2018 Free Software Foundation, Inc. ++ Contributed by Intel Corporation. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#if IS_IN (libc) ++ ++# include ++ ++# ifndef STRCAT ++# define STRCAT __strcat_avx2 ++# endif ++ ++# define USE_AS_STRCAT ++ ++/* Number of bytes in a vector register */ ++# define VEC_SIZE 32 ++ ++ .section .text.avx,"ax",@progbits ++ENTRY (STRCAT) ++ mov %rdi, %r9 ++# ifdef USE_AS_STRNCAT ++ mov %rdx, %r8 ++# endif ++ ++ xor %eax, %eax ++ mov %edi, %ecx ++ and $((VEC_SIZE * 4) - 1), %ecx ++ vpxor %xmm6, %xmm6, %xmm6 ++ cmp $(VEC_SIZE * 3), %ecx ++ ja L(fourth_vector_boundary) ++ vpcmpeqb (%rdi), %ymm6, %ymm0 ++ vpmovmskb %ymm0, %edx ++ test %edx, %edx ++ jnz L(exit_null_on_first_vector) ++ mov %rdi, %rax ++ and $-VEC_SIZE, %rax ++ jmp L(align_vec_size_start) ++L(fourth_vector_boundary): ++ mov %rdi, %rax ++ and $-VEC_SIZE, %rax ++ vpcmpeqb (%rax), %ymm6, %ymm0 ++ mov $-1, %r10d ++ sub %rax, %rcx ++ shl %cl, %r10d ++ vpmovmskb %ymm0, %edx ++ and %r10d, %edx ++ jnz L(exit) ++ ++L(align_vec_size_start): ++ vpcmpeqb VEC_SIZE(%rax), %ymm6, %ymm0 ++ vpmovmskb %ymm0, %edx ++ test %edx, %edx ++ jnz L(exit_null_on_second_vector) ++ ++ vpcmpeqb (VEC_SIZE * 2)(%rax), %ymm6, %ymm1 ++ vpmovmskb %ymm1, %edx ++ test %edx, %edx ++ jnz L(exit_null_on_third_vector) ++ ++ vpcmpeqb (VEC_SIZE * 3)(%rax), %ymm6, %ymm2 ++ vpmovmskb %ymm2, %edx ++ test %edx, %edx ++ jnz L(exit_null_on_fourth_vector) ++ ++ vpcmpeqb (VEC_SIZE * 4)(%rax), %ymm6, %ymm3 ++ vpmovmskb %ymm3, %edx ++ test %edx, %edx ++ jnz L(exit_null_on_fifth_vector) ++ ++ vpcmpeqb (VEC_SIZE * 5)(%rax), %ymm6, %ymm0 ++ add $(VEC_SIZE * 4), %rax ++ vpmovmskb %ymm0, %edx ++ test %edx, %edx ++ jnz L(exit_null_on_second_vector) ++ ++ vpcmpeqb (VEC_SIZE * 2)(%rax), %ymm6, %ymm1 ++ vpmovmskb %ymm1, %edx ++ test %edx, %edx ++ jnz L(exit_null_on_third_vector) ++ ++ vpcmpeqb (VEC_SIZE * 3)(%rax), %ymm6, %ymm2 ++ vpmovmskb %ymm2, %edx ++ test %edx, %edx ++ jnz L(exit_null_on_fourth_vector) ++ ++ vpcmpeqb (VEC_SIZE * 4)(%rax), %ymm6, %ymm3 ++ vpmovmskb %ymm3, %edx ++ test %edx, %edx ++ jnz L(exit_null_on_fifth_vector) ++ ++ vpcmpeqb (VEC_SIZE * 5)(%rax), %ymm6, %ymm0 ++ add $(VEC_SIZE * 4), %rax ++ vpmovmskb %ymm0, %edx ++ test %edx, %edx ++ jnz L(exit_null_on_second_vector) ++ ++ vpcmpeqb (VEC_SIZE * 2)(%rax), %ymm6, %ymm1 ++ vpmovmskb %ymm1, %edx ++ test %edx, %edx ++ jnz L(exit_null_on_third_vector) ++ ++ vpcmpeqb (VEC_SIZE * 3)(%rax), %ymm6, %ymm2 ++ vpmovmskb %ymm2, %edx ++ test %edx, %edx ++ jnz L(exit_null_on_fourth_vector) ++ ++ vpcmpeqb (VEC_SIZE * 4)(%rax), %ymm6, %ymm3 ++ vpmovmskb %ymm3, %edx ++ test %edx, %edx ++ jnz L(exit_null_on_fifth_vector) ++ ++ vpcmpeqb (VEC_SIZE * 5)(%rax), %ymm6, %ymm0 ++ add $(VEC_SIZE * 4), %rax ++ vpmovmskb %ymm0, %edx ++ test %edx, %edx ++ jnz L(exit_null_on_second_vector) ++ ++ vpcmpeqb (VEC_SIZE * 2)(%rax), %ymm6, %ymm1 ++ vpmovmskb %ymm1, %edx ++ test %edx, %edx ++ jnz L(exit_null_on_third_vector) ++ ++ vpcmpeqb (VEC_SIZE * 3)(%rax), %ymm6, %ymm2 ++ vpmovmskb %ymm2, %edx ++ test %edx, %edx ++ jnz L(exit_null_on_fourth_vector) ++ ++ vpcmpeqb (VEC_SIZE * 4)(%rax), %ymm6, %ymm3 ++ vpmovmskb %ymm3, %edx ++ test %edx, %edx ++ jnz L(exit_null_on_fifth_vector) ++ ++ test $((VEC_SIZE * 4) - 1), %rax ++ jz L(align_four_vec_loop) ++ ++ vpcmpeqb (VEC_SIZE * 5)(%rax), %ymm6, %ymm0 ++ add $(VEC_SIZE * 5), %rax ++ vpmovmskb %ymm0, %edx ++ test %edx, %edx ++ jnz L(exit) ++ ++ test $((VEC_SIZE * 4) - 1), %rax ++ jz L(align_four_vec_loop) ++ ++ vpcmpeqb VEC_SIZE(%rax), %ymm6, %ymm1 ++ add $VEC_SIZE, %rax ++ vpmovmskb %ymm1, %edx ++ test %edx, %edx ++ jnz L(exit) ++ ++ test $((VEC_SIZE * 4) - 1), %rax ++ jz L(align_four_vec_loop) ++ ++ vpcmpeqb VEC_SIZE(%rax), %ymm6, %ymm2 ++ add $VEC_SIZE, %rax ++ vpmovmskb %ymm2, %edx ++ test %edx, %edx ++ jnz L(exit) ++ ++ test $((VEC_SIZE * 4) - 1), %rax ++ jz L(align_four_vec_loop) ++ ++ vpcmpeqb VEC_SIZE(%rax), %ymm6, %ymm3 ++ add $VEC_SIZE, %rax ++ vpmovmskb %ymm3, %edx ++ test %edx, %edx ++ jnz L(exit) ++ ++ add $VEC_SIZE, %rax ++ ++ .p2align 4 ++L(align_four_vec_loop): ++ vmovaps (%rax), %ymm4 ++ vpminub VEC_SIZE(%rax), %ymm4, %ymm4 ++ vmovaps (VEC_SIZE * 2)(%rax), %ymm5 ++ vpminub (VEC_SIZE * 3)(%rax), %ymm5, %ymm5 ++ add $(VEC_SIZE * 4), %rax ++ vpminub %ymm4, %ymm5, %ymm5 ++ vpcmpeqb %ymm5, %ymm6, %ymm5 ++ vpmovmskb %ymm5, %edx ++ test %edx, %edx ++ jz L(align_four_vec_loop) ++ ++ vpcmpeqb -(VEC_SIZE * 4)(%rax), %ymm6, %ymm0 ++ sub $(VEC_SIZE * 5), %rax ++ vpmovmskb %ymm0, %edx ++ test %edx, %edx ++ jnz L(exit_null_on_second_vector) ++ ++ vpcmpeqb (VEC_SIZE * 2)(%rax), %ymm6, %ymm1 ++ vpmovmskb %ymm1, %edx ++ test %edx, %edx ++ jnz L(exit_null_on_third_vector) ++ ++ vpcmpeqb (VEC_SIZE * 3)(%rax), %ymm6, %ymm2 ++ vpmovmskb %ymm2, %edx ++ test %edx, %edx ++ jnz L(exit_null_on_fourth_vector) ++ ++ vpcmpeqb (VEC_SIZE * 4)(%rax), %ymm6, %ymm3 ++ vpmovmskb %ymm3, %edx ++ sub %rdi, %rax ++ bsf %rdx, %rdx ++ add %rdx, %rax ++ add $(VEC_SIZE * 4), %rax ++ jmp L(StartStrcpyPart) ++ ++ .p2align 4 ++L(exit): ++ sub %rdi, %rax ++L(exit_null_on_first_vector): ++ bsf %rdx, %rdx ++ add %rdx, %rax ++ jmp L(StartStrcpyPart) ++ ++ .p2align 4 ++L(exit_null_on_second_vector): ++ sub %rdi, %rax ++ bsf %rdx, %rdx ++ add %rdx, %rax ++ add $VEC_SIZE, %rax ++ jmp L(StartStrcpyPart) ++ ++ .p2align 4 ++L(exit_null_on_third_vector): ++ sub %rdi, %rax ++ bsf %rdx, %rdx ++ add %rdx, %rax ++ add $(VEC_SIZE * 2), %rax ++ jmp L(StartStrcpyPart) ++ ++ .p2align 4 ++L(exit_null_on_fourth_vector): ++ sub %rdi, %rax ++ bsf %rdx, %rdx ++ add %rdx, %rax ++ add $(VEC_SIZE * 3), %rax ++ jmp L(StartStrcpyPart) ++ ++ .p2align 4 ++L(exit_null_on_fifth_vector): ++ sub %rdi, %rax ++ bsf %rdx, %rdx ++ add %rdx, %rax ++ add $(VEC_SIZE * 4), %rax ++ ++ .p2align 4 ++L(StartStrcpyPart): ++ lea (%r9, %rax), %rdi ++ mov %rsi, %rcx ++ mov %r9, %rax /* save result */ ++ ++# ifdef USE_AS_STRNCAT ++ test %r8, %r8 ++ jz L(ExitZero) ++# define USE_AS_STRNCPY ++# endif ++ ++# include "strcpy-avx2.S" ++#endif +diff --git a/sysdeps/x86_64/multiarch/strcat.c b/sysdeps/x86_64/multiarch/strcat.c +index 1f7f6263f35ba402..694b9b2405827bd4 100644 +--- a/sysdeps/x86_64/multiarch/strcat.c ++++ b/sysdeps/x86_64/multiarch/strcat.c +@@ -24,7 +24,7 @@ + # undef strcat + + # define SYMBOL_NAME strcat +-# include "ifunc-unaligned-ssse3.h" ++# include "ifunc-strcpy.h" + + libc_ifunc_redirected (__redirect_strcat, strcat, IFUNC_SELECTOR ()); + +diff --git a/sysdeps/x86_64/multiarch/strcpy-avx2.S b/sysdeps/x86_64/multiarch/strcpy-avx2.S +new file mode 100644 +index 0000000000000000..81677f9060773a49 +--- /dev/null ++++ b/sysdeps/x86_64/multiarch/strcpy-avx2.S +@@ -0,0 +1,1022 @@ ++/* strcpy with AVX2 ++ Copyright (C) 2011-2018 Free Software Foundation, Inc. ++ Contributed by Intel Corporation. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#if IS_IN (libc) ++ ++# ifndef USE_AS_STRCAT ++# include ++ ++# ifndef STRCPY ++# define STRCPY __strcpy_avx2 ++# endif ++ ++# endif ++ ++/* Number of bytes in a vector register */ ++# ifndef VEC_SIZE ++# define VEC_SIZE 32 ++# endif ++ ++# ifndef VZEROUPPER ++# define VZEROUPPER vzeroupper ++# endif ++ ++/* zero register */ ++#define xmmZ xmm0 ++#define ymmZ ymm0 ++ ++/* mask register */ ++#define ymmM ymm1 ++ ++# ifndef USE_AS_STRCAT ++ ++ .section .text.avx,"ax",@progbits ++ENTRY (STRCPY) ++# ifdef USE_AS_STRNCPY ++ mov %rdx, %r8 ++ test %r8, %r8 ++ jz L(ExitZero) ++# endif ++ mov %rsi, %rcx ++# ifndef USE_AS_STPCPY ++ mov %rdi, %rax /* save result */ ++# endif ++ ++# endif ++ ++ vpxor %xmmZ, %xmmZ, %xmmZ ++ ++ and $((VEC_SIZE * 4) - 1), %ecx ++ cmp $(VEC_SIZE * 2), %ecx ++ jbe L(SourceStringAlignmentLessTwoVecSize) ++ ++ and $-VEC_SIZE, %rsi ++ and $(VEC_SIZE - 1), %ecx ++ ++ vpcmpeqb (%rsi), %ymmZ, %ymmM ++ vpmovmskb %ymmM, %edx ++ shr %cl, %rdx ++ ++# ifdef USE_AS_STRNCPY ++# if defined USE_AS_STPCPY || defined USE_AS_STRCAT ++ mov $VEC_SIZE, %r10 ++ sub %rcx, %r10 ++ cmp %r10, %r8 ++# else ++ mov $(VEC_SIZE + 1), %r10 ++ sub %rcx, %r10 ++ cmp %r10, %r8 ++# endif ++ jbe L(CopyVecSizeTailCase2OrCase3) ++# endif ++ test %edx, %edx ++ jnz L(CopyVecSizeTail) ++ ++ vpcmpeqb VEC_SIZE(%rsi), %ymmZ, %ymm2 ++ vpmovmskb %ymm2, %edx ++ ++# ifdef USE_AS_STRNCPY ++ add $VEC_SIZE, %r10 ++ cmp %r10, %r8 ++ jbe L(CopyTwoVecSizeCase2OrCase3) ++# endif ++ test %edx, %edx ++ jnz L(CopyTwoVecSize) ++ ++ vmovdqu (%rsi, %rcx), %ymm2 /* copy VEC_SIZE bytes */ ++ vmovdqu %ymm2, (%rdi) ++ ++/* If source address alignment != destination address alignment */ ++ .p2align 4 ++L(UnalignVecSizeBoth): ++ sub %rcx, %rdi ++# ifdef USE_AS_STRNCPY ++ add %rcx, %r8 ++ sbb %rcx, %rcx ++ or %rcx, %r8 ++# endif ++ mov $VEC_SIZE, %rcx ++ vmovdqa (%rsi, %rcx), %ymm2 ++ vmovdqu %ymm2, (%rdi, %rcx) ++ vmovdqa VEC_SIZE(%rsi, %rcx), %ymm2 ++ vpcmpeqb %ymm2, %ymmZ, %ymmM ++ vpmovmskb %ymmM, %edx ++ add $VEC_SIZE, %rcx ++# ifdef USE_AS_STRNCPY ++ sub $(VEC_SIZE * 3), %r8 ++ jbe L(CopyVecSizeCase2OrCase3) ++# endif ++ test %edx, %edx ++# if defined USE_AS_STRNCPY && !defined USE_AS_STRCAT ++ jnz L(CopyVecSizeUnalignedVec2) ++# else ++ jnz L(CopyVecSize) ++# endif ++ ++ vmovdqu %ymm2, (%rdi, %rcx) ++ vmovdqa VEC_SIZE(%rsi, %rcx), %ymm3 ++ vpcmpeqb %ymm3, %ymmZ, %ymmM ++ vpmovmskb %ymmM, %edx ++ add $VEC_SIZE, %rcx ++# ifdef USE_AS_STRNCPY ++ sub $VEC_SIZE, %r8 ++ jbe L(CopyVecSizeCase2OrCase3) ++# endif ++ test %edx, %edx ++# if defined USE_AS_STRNCPY && !defined USE_AS_STRCAT ++ jnz L(CopyVecSizeUnalignedVec3) ++# else ++ jnz L(CopyVecSize) ++# endif ++ ++ vmovdqu %ymm3, (%rdi, %rcx) ++ vmovdqa VEC_SIZE(%rsi, %rcx), %ymm4 ++ vpcmpeqb %ymm4, %ymmZ, %ymmM ++ vpmovmskb %ymmM, %edx ++ add $VEC_SIZE, %rcx ++# ifdef USE_AS_STRNCPY ++ sub $VEC_SIZE, %r8 ++ jbe L(CopyVecSizeCase2OrCase3) ++# endif ++ test %edx, %edx ++# if defined USE_AS_STRNCPY && !defined USE_AS_STRCAT ++ jnz L(CopyVecSizeUnalignedVec4) ++# else ++ jnz L(CopyVecSize) ++# endif ++ ++ vmovdqu %ymm4, (%rdi, %rcx) ++ vmovdqa VEC_SIZE(%rsi, %rcx), %ymm2 ++ vpcmpeqb %ymm2, %ymmZ, %ymmM ++ vpmovmskb %ymmM, %edx ++ add $VEC_SIZE, %rcx ++# ifdef USE_AS_STRNCPY ++ sub $VEC_SIZE, %r8 ++ jbe L(CopyVecSizeCase2OrCase3) ++# endif ++ test %edx, %edx ++# if defined USE_AS_STRNCPY && !defined USE_AS_STRCAT ++ jnz L(CopyVecSizeUnalignedVec2) ++# else ++ jnz L(CopyVecSize) ++# endif ++ ++ vmovdqu %ymm2, (%rdi, %rcx) ++ vmovdqa VEC_SIZE(%rsi, %rcx), %ymm2 ++ vpcmpeqb %ymm2, %ymmZ, %ymmM ++ vpmovmskb %ymmM, %edx ++ add $VEC_SIZE, %rcx ++# ifdef USE_AS_STRNCPY ++ sub $VEC_SIZE, %r8 ++ jbe L(CopyVecSizeCase2OrCase3) ++# endif ++ test %edx, %edx ++# if defined USE_AS_STRNCPY && !defined USE_AS_STRCAT ++ jnz L(CopyVecSizeUnalignedVec2) ++# else ++ jnz L(CopyVecSize) ++# endif ++ ++ vmovdqa VEC_SIZE(%rsi, %rcx), %ymm3 ++ vmovdqu %ymm2, (%rdi, %rcx) ++ vpcmpeqb %ymm3, %ymmZ, %ymmM ++ vpmovmskb %ymmM, %edx ++ add $VEC_SIZE, %rcx ++# ifdef USE_AS_STRNCPY ++ sub $VEC_SIZE, %r8 ++ jbe L(CopyVecSizeCase2OrCase3) ++# endif ++ test %edx, %edx ++# if defined USE_AS_STRNCPY && !defined USE_AS_STRCAT ++ jnz L(CopyVecSizeUnalignedVec3) ++# else ++ jnz L(CopyVecSize) ++# endif ++ ++ vmovdqu %ymm3, (%rdi, %rcx) ++ mov %rsi, %rdx ++ lea VEC_SIZE(%rsi, %rcx), %rsi ++ and $-(VEC_SIZE * 4), %rsi ++ sub %rsi, %rdx ++ sub %rdx, %rdi ++# ifdef USE_AS_STRNCPY ++ lea (VEC_SIZE * 8)(%r8, %rdx), %r8 ++# endif ++L(UnalignedFourVecSizeLoop): ++ vmovdqa (%rsi), %ymm4 ++ vmovdqa VEC_SIZE(%rsi), %ymm5 ++ vmovdqa (VEC_SIZE * 2)(%rsi), %ymm6 ++ vmovdqa (VEC_SIZE * 3)(%rsi), %ymm7 ++ vpminub %ymm5, %ymm4, %ymm2 ++ vpminub %ymm7, %ymm6, %ymm3 ++ vpminub %ymm2, %ymm3, %ymm3 ++ vpcmpeqb %ymmM, %ymm3, %ymm3 ++ vpmovmskb %ymm3, %edx ++# ifdef USE_AS_STRNCPY ++ sub $(VEC_SIZE * 4), %r8 ++ jbe L(UnalignedLeaveCase2OrCase3) ++# endif ++ test %edx, %edx ++ jnz L(UnalignedFourVecSizeLeave) ++ ++L(UnalignedFourVecSizeLoop_start): ++ add $(VEC_SIZE * 4), %rdi ++ add $(VEC_SIZE * 4), %rsi ++ vmovdqu %ymm4, -(VEC_SIZE * 4)(%rdi) ++ vmovdqa (%rsi), %ymm4 ++ vmovdqu %ymm5, -(VEC_SIZE * 3)(%rdi) ++ vmovdqa VEC_SIZE(%rsi), %ymm5 ++ vpminub %ymm5, %ymm4, %ymm2 ++ vmovdqu %ymm6, -(VEC_SIZE * 2)(%rdi) ++ vmovdqa (VEC_SIZE * 2)(%rsi), %ymm6 ++ vmovdqu %ymm7, -VEC_SIZE(%rdi) ++ vmovdqa (VEC_SIZE * 3)(%rsi), %ymm7 ++ vpminub %ymm7, %ymm6, %ymm3 ++ vpminub %ymm2, %ymm3, %ymm3 ++ vpcmpeqb %ymmM, %ymm3, %ymm3 ++ vpmovmskb %ymm3, %edx ++# ifdef USE_AS_STRNCPY ++ sub $(VEC_SIZE * 4), %r8 ++ jbe L(UnalignedLeaveCase2OrCase3) ++# endif ++ test %edx, %edx ++ jz L(UnalignedFourVecSizeLoop_start) ++ ++L(UnalignedFourVecSizeLeave): ++ vpcmpeqb %ymm4, %ymmZ, %ymmM ++ vpmovmskb %ymmM, %edx ++ test %edx, %edx ++ jnz L(CopyVecSizeUnaligned_0) ++ ++ vpcmpeqb %ymm5, %ymmZ, %ymmM ++ vpmovmskb %ymmM, %ecx ++ test %ecx, %ecx ++ jnz L(CopyVecSizeUnaligned_16) ++ ++ vpcmpeqb %ymm6, %ymmZ, %ymmM ++ vpmovmskb %ymmM, %edx ++ test %edx, %edx ++ jnz L(CopyVecSizeUnaligned_32) ++ ++ vpcmpeqb %ymm7, %ymmZ, %ymmM ++ vpmovmskb %ymmM, %ecx ++ bsf %ecx, %edx ++ vmovdqu %ymm4, (%rdi) ++ vmovdqu %ymm5, VEC_SIZE(%rdi) ++ vmovdqu %ymm6, (VEC_SIZE * 2)(%rdi) ++# if defined USE_AS_STRNCPY && !defined USE_AS_STRCAT ++# ifdef USE_AS_STPCPY ++ lea (VEC_SIZE * 3)(%rdi, %rdx), %rax ++# endif ++ vmovdqu %ymm7, (VEC_SIZE * 3)(%rdi) ++ add $(VEC_SIZE - 1), %r8 ++ sub %rdx, %r8 ++ lea ((VEC_SIZE * 3) + 1)(%rdi, %rdx), %rdi ++ jmp L(StrncpyFillTailWithZero) ++# else ++ add $(VEC_SIZE * 3), %rsi ++ add $(VEC_SIZE * 3), %rdi ++ jmp L(CopyVecSizeExit) ++# endif ++ ++/* If source address alignment == destination address alignment */ ++ ++L(SourceStringAlignmentLessTwoVecSize): ++ vmovdqu (%rsi), %ymm3 ++ vmovdqu VEC_SIZE(%rsi), %ymm2 ++ vpcmpeqb %ymm3, %ymmZ, %ymmM ++ vpmovmskb %ymmM, %edx ++ ++# ifdef USE_AS_STRNCPY ++# if defined USE_AS_STPCPY || defined USE_AS_STRCAT ++ cmp $VEC_SIZE, %r8 ++# else ++ cmp $(VEC_SIZE + 1), %r8 ++# endif ++ jbe L(CopyVecSizeTail1Case2OrCase3) ++# endif ++ test %edx, %edx ++ jnz L(CopyVecSizeTail1) ++ ++ vmovdqu %ymm3, (%rdi) ++ vpcmpeqb %ymm2, %ymmZ, %ymmM ++ vpmovmskb %ymmM, %edx ++ ++# ifdef USE_AS_STRNCPY ++# if defined USE_AS_STPCPY || defined USE_AS_STRCAT ++ cmp $(VEC_SIZE * 2), %r8 ++# else ++ cmp $((VEC_SIZE * 2) + 1), %r8 ++# endif ++ jbe L(CopyTwoVecSize1Case2OrCase3) ++# endif ++ test %edx, %edx ++ jnz L(CopyTwoVecSize1) ++ ++ and $-VEC_SIZE, %rsi ++ and $(VEC_SIZE - 1), %ecx ++ jmp L(UnalignVecSizeBoth) ++ ++/*------End of main part with loops---------------------*/ ++ ++/* Case1 */ ++ ++# if (!defined USE_AS_STRNCPY) || (defined USE_AS_STRCAT) ++ .p2align 4 ++L(CopyVecSize): ++ add %rcx, %rdi ++# endif ++L(CopyVecSizeTail): ++ add %rcx, %rsi ++L(CopyVecSizeTail1): ++ bsf %edx, %edx ++L(CopyVecSizeExit): ++ cmp $32, %edx ++ jae L(Exit32_63) ++ cmp $16, %edx ++ jae L(Exit16_31) ++ cmp $8, %edx ++ jae L(Exit8_15) ++ cmp $4, %edx ++ jae L(Exit4_7) ++ cmp $3, %edx ++ je L(Exit3) ++ cmp $1, %edx ++ ja L(Exit2) ++ je L(Exit1) ++ movb $0, (%rdi) ++# ifdef USE_AS_STPCPY ++ lea (%rdi), %rax ++# endif ++# if defined USE_AS_STRNCPY && !defined USE_AS_STRCAT ++ sub $1, %r8 ++ lea 1(%rdi), %rdi ++ jnz L(StrncpyFillTailWithZero) ++# endif ++ VZEROUPPER ++ ret ++ ++ .p2align 4 ++L(CopyTwoVecSize1): ++ add $VEC_SIZE, %rsi ++ add $VEC_SIZE, %rdi ++# if defined USE_AS_STRNCPY && !defined USE_AS_STRCAT ++ sub $VEC_SIZE, %r8 ++# endif ++ jmp L(CopyVecSizeTail1) ++ ++ .p2align 4 ++L(CopyTwoVecSize): ++ bsf %edx, %edx ++ add %rcx, %rsi ++ add $VEC_SIZE, %edx ++ sub %ecx, %edx ++ jmp L(CopyVecSizeExit) ++ ++ .p2align 4 ++L(CopyVecSizeUnaligned_0): ++ bsf %edx, %edx ++# if defined USE_AS_STRNCPY && !defined USE_AS_STRCAT ++# ifdef USE_AS_STPCPY ++ lea (%rdi, %rdx), %rax ++# endif ++ vmovdqu %ymm4, (%rdi) ++ add $((VEC_SIZE * 4) - 1), %r8 ++ sub %rdx, %r8 ++ lea 1(%rdi, %rdx), %rdi ++ jmp L(StrncpyFillTailWithZero) ++# else ++ jmp L(CopyVecSizeExit) ++# endif ++ ++ .p2align 4 ++L(CopyVecSizeUnaligned_16): ++ bsf %ecx, %edx ++ vmovdqu %ymm4, (%rdi) ++# if defined USE_AS_STRNCPY && !defined USE_AS_STRCAT ++# ifdef USE_AS_STPCPY ++ lea VEC_SIZE(%rdi, %rdx), %rax ++# endif ++ vmovdqu %ymm5, VEC_SIZE(%rdi) ++ add $((VEC_SIZE * 3) - 1), %r8 ++ sub %rdx, %r8 ++ lea (VEC_SIZE + 1)(%rdi, %rdx), %rdi ++ jmp L(StrncpyFillTailWithZero) ++# else ++ add $VEC_SIZE, %rsi ++ add $VEC_SIZE, %rdi ++ jmp L(CopyVecSizeExit) ++# endif ++ ++ .p2align 4 ++L(CopyVecSizeUnaligned_32): ++ bsf %edx, %edx ++ vmovdqu %ymm4, (%rdi) ++ vmovdqu %ymm5, VEC_SIZE(%rdi) ++# if defined USE_AS_STRNCPY && !defined USE_AS_STRCAT ++# ifdef USE_AS_STPCPY ++ lea (VEC_SIZE * 2)(%rdi, %rdx), %rax ++# endif ++ vmovdqu %ymm6, (VEC_SIZE * 2)(%rdi) ++ add $((VEC_SIZE * 2) - 1), %r8 ++ sub %rdx, %r8 ++ lea ((VEC_SIZE * 2) + 1)(%rdi, %rdx), %rdi ++ jmp L(StrncpyFillTailWithZero) ++# else ++ add $(VEC_SIZE * 2), %rsi ++ add $(VEC_SIZE * 2), %rdi ++ jmp L(CopyVecSizeExit) ++# endif ++ ++# ifdef USE_AS_STRNCPY ++# ifndef USE_AS_STRCAT ++ .p2align 4 ++L(CopyVecSizeUnalignedVec6): ++ vmovdqu %ymm6, (%rdi, %rcx) ++ jmp L(CopyVecSizeVecExit) ++ ++ .p2align 4 ++L(CopyVecSizeUnalignedVec5): ++ vmovdqu %ymm5, (%rdi, %rcx) ++ jmp L(CopyVecSizeVecExit) ++ ++ .p2align 4 ++L(CopyVecSizeUnalignedVec4): ++ vmovdqu %ymm4, (%rdi, %rcx) ++ jmp L(CopyVecSizeVecExit) ++ ++ .p2align 4 ++L(CopyVecSizeUnalignedVec3): ++ vmovdqu %ymm3, (%rdi, %rcx) ++ jmp L(CopyVecSizeVecExit) ++# endif ++ ++/* Case2 */ ++ ++ .p2align 4 ++L(CopyVecSizeCase2): ++ add $VEC_SIZE, %r8 ++ add %rcx, %rdi ++ add %rcx, %rsi ++ bsf %edx, %edx ++ cmp %r8d, %edx ++ jb L(CopyVecSizeExit) ++ jmp L(StrncpyExit) ++ ++ .p2align 4 ++L(CopyTwoVecSizeCase2): ++ add %rcx, %rsi ++ bsf %edx, %edx ++ add $VEC_SIZE, %edx ++ sub %ecx, %edx ++ cmp %r8d, %edx ++ jb L(CopyVecSizeExit) ++ jmp L(StrncpyExit) ++ ++L(CopyVecSizeTailCase2): ++ add %rcx, %rsi ++ bsf %edx, %edx ++ cmp %r8d, %edx ++ jb L(CopyVecSizeExit) ++ jmp L(StrncpyExit) ++ ++L(CopyVecSizeTail1Case2): ++ bsf %edx, %edx ++ cmp %r8d, %edx ++ jb L(CopyVecSizeExit) ++ jmp L(StrncpyExit) ++ ++/* Case2 or Case3, Case3 */ ++ ++ .p2align 4 ++L(CopyVecSizeCase2OrCase3): ++ test %rdx, %rdx ++ jnz L(CopyVecSizeCase2) ++L(CopyVecSizeCase3): ++ add $VEC_SIZE, %r8 ++ add %rcx, %rdi ++ add %rcx, %rsi ++ jmp L(StrncpyExit) ++ ++ .p2align 4 ++L(CopyTwoVecSizeCase2OrCase3): ++ test %rdx, %rdx ++ jnz L(CopyTwoVecSizeCase2) ++ add %rcx, %rsi ++ jmp L(StrncpyExit) ++ ++ .p2align 4 ++L(CopyVecSizeTailCase2OrCase3): ++ test %rdx, %rdx ++ jnz L(CopyVecSizeTailCase2) ++ add %rcx, %rsi ++ jmp L(StrncpyExit) ++ ++ .p2align 4 ++L(CopyTwoVecSize1Case2OrCase3): ++ add $VEC_SIZE, %rdi ++ add $VEC_SIZE, %rsi ++ sub $VEC_SIZE, %r8 ++L(CopyVecSizeTail1Case2OrCase3): ++ test %rdx, %rdx ++ jnz L(CopyVecSizeTail1Case2) ++ jmp L(StrncpyExit) ++# endif ++ ++/*------------End labels regarding with copying 1-VEC_SIZE bytes--and 1-(VEC_SIZE*2) bytes----*/ ++ ++ .p2align 4 ++L(Exit1): ++ movzwl (%rsi), %edx ++ mov %dx, (%rdi) ++# ifdef USE_AS_STPCPY ++ lea 1(%rdi), %rax ++# endif ++# if defined USE_AS_STRNCPY && !defined USE_AS_STRCAT ++ sub $2, %r8 ++ lea 2(%rdi), %rdi ++ jnz L(StrncpyFillTailWithZero) ++# endif ++ VZEROUPPER ++ ret ++ ++ .p2align 4 ++L(Exit2): ++ movzwl (%rsi), %ecx ++ mov %cx, (%rdi) ++ movb $0, 2(%rdi) ++# ifdef USE_AS_STPCPY ++ lea 2(%rdi), %rax ++# endif ++# if defined USE_AS_STRNCPY && !defined USE_AS_STRCAT ++ sub $3, %r8 ++ lea 3(%rdi), %rdi ++ jnz L(StrncpyFillTailWithZero) ++# endif ++ VZEROUPPER ++ ret ++ ++ .p2align 4 ++L(Exit3): ++ mov (%rsi), %edx ++ mov %edx, (%rdi) ++# ifdef USE_AS_STPCPY ++ lea 3(%rdi), %rax ++# endif ++# if defined USE_AS_STRNCPY && !defined USE_AS_STRCAT ++ sub $4, %r8 ++ lea 4(%rdi), %rdi ++ jnz L(StrncpyFillTailWithZero) ++# endif ++ VZEROUPPER ++ ret ++ ++ .p2align 4 ++L(Exit4_7): ++ mov (%rsi), %ecx ++ mov %ecx, (%rdi) ++ mov -3(%rsi, %rdx), %ecx ++ mov %ecx, -3(%rdi, %rdx) ++# ifdef USE_AS_STPCPY ++ lea (%rdi, %rdx), %rax ++# endif ++# if defined USE_AS_STRNCPY && !defined USE_AS_STRCAT ++ sub %rdx, %r8 ++ sub $1, %r8 ++ lea 1(%rdi, %rdx), %rdi ++ jnz L(StrncpyFillTailWithZero) ++# endif ++ VZEROUPPER ++ ret ++ ++ .p2align 4 ++L(Exit8_15): ++ mov (%rsi), %rcx ++ mov -7(%rsi, %rdx), %r9 ++ mov %rcx, (%rdi) ++ mov %r9, -7(%rdi, %rdx) ++# ifdef USE_AS_STPCPY ++ lea (%rdi, %rdx), %rax ++# endif ++# if defined USE_AS_STRNCPY && !defined USE_AS_STRCAT ++ sub %rdx, %r8 ++ sub $1, %r8 ++ lea 1(%rdi, %rdx), %rdi ++ jnz L(StrncpyFillTailWithZero) ++# endif ++ VZEROUPPER ++ ret ++ ++ .p2align 4 ++L(Exit16_31): ++ vmovdqu (%rsi), %xmm2 ++ vmovdqu -15(%rsi, %rdx), %xmm3 ++ vmovdqu %xmm2, (%rdi) ++ vmovdqu %xmm3, -15(%rdi, %rdx) ++# ifdef USE_AS_STPCPY ++ lea (%rdi, %rdx), %rax ++# endif ++# if defined USE_AS_STRNCPY && !defined USE_AS_STRCAT ++ sub %rdx, %r8 ++ sub $1, %r8 ++ lea 1(%rdi, %rdx), %rdi ++ jnz L(StrncpyFillTailWithZero) ++# endif ++ VZEROUPPER ++ ret ++ ++ .p2align 4 ++L(Exit32_63): ++ vmovdqu (%rsi), %ymm2 ++ vmovdqu -31(%rsi, %rdx), %ymm3 ++ vmovdqu %ymm2, (%rdi) ++ vmovdqu %ymm3, -31(%rdi, %rdx) ++# ifdef USE_AS_STPCPY ++ lea (%rdi, %rdx), %rax ++# endif ++# if defined USE_AS_STRNCPY && !defined USE_AS_STRCAT ++ sub %rdx, %r8 ++ sub $1, %r8 ++ lea 1(%rdi, %rdx), %rdi ++ jnz L(StrncpyFillTailWithZero) ++# endif ++ VZEROUPPER ++ ret ++ ++# ifdef USE_AS_STRNCPY ++ ++ .p2align 4 ++L(StrncpyExit1): ++ movzbl (%rsi), %edx ++ mov %dl, (%rdi) ++# ifdef USE_AS_STPCPY ++ lea 1(%rdi), %rax ++# endif ++# ifdef USE_AS_STRCAT ++ movb $0, 1(%rdi) ++# endif ++ VZEROUPPER ++ ret ++ ++ .p2align 4 ++L(StrncpyExit2): ++ movzwl (%rsi), %edx ++ mov %dx, (%rdi) ++# ifdef USE_AS_STPCPY ++ lea 2(%rdi), %rax ++# endif ++# ifdef USE_AS_STRCAT ++ movb $0, 2(%rdi) ++# endif ++ VZEROUPPER ++ ret ++ ++ .p2align 4 ++L(StrncpyExit3_4): ++ movzwl (%rsi), %ecx ++ movzwl -2(%rsi, %r8), %edx ++ mov %cx, (%rdi) ++ mov %dx, -2(%rdi, %r8) ++# ifdef USE_AS_STPCPY ++ lea (%rdi, %r8), %rax ++# endif ++# ifdef USE_AS_STRCAT ++ movb $0, (%rdi, %r8) ++# endif ++ VZEROUPPER ++ ret ++ ++ .p2align 4 ++L(StrncpyExit5_8): ++ mov (%rsi), %ecx ++ mov -4(%rsi, %r8), %edx ++ mov %ecx, (%rdi) ++ mov %edx, -4(%rdi, %r8) ++# ifdef USE_AS_STPCPY ++ lea (%rdi, %r8), %rax ++# endif ++# ifdef USE_AS_STRCAT ++ movb $0, (%rdi, %r8) ++# endif ++ VZEROUPPER ++ ret ++ ++ .p2align 4 ++L(StrncpyExit9_16): ++ mov (%rsi), %rcx ++ mov -8(%rsi, %r8), %rdx ++ mov %rcx, (%rdi) ++ mov %rdx, -8(%rdi, %r8) ++# ifdef USE_AS_STPCPY ++ lea (%rdi, %r8), %rax ++# endif ++# ifdef USE_AS_STRCAT ++ movb $0, (%rdi, %r8) ++# endif ++ VZEROUPPER ++ ret ++ ++ .p2align 4 ++L(StrncpyExit17_32): ++ vmovdqu (%rsi), %xmm2 ++ vmovdqu -16(%rsi, %r8), %xmm3 ++ vmovdqu %xmm2, (%rdi) ++ vmovdqu %xmm3, -16(%rdi, %r8) ++# ifdef USE_AS_STPCPY ++ lea (%rdi, %r8), %rax ++# endif ++# ifdef USE_AS_STRCAT ++ movb $0, (%rdi, %r8) ++# endif ++ VZEROUPPER ++ ret ++ ++ .p2align 4 ++L(StrncpyExit33_64): ++ /* 0/32, 31/16 */ ++ vmovdqu (%rsi), %ymm2 ++ vmovdqu -VEC_SIZE(%rsi, %r8), %ymm3 ++ vmovdqu %ymm2, (%rdi) ++ vmovdqu %ymm3, -VEC_SIZE(%rdi, %r8) ++# ifdef USE_AS_STPCPY ++ lea (%rdi, %r8), %rax ++# endif ++# ifdef USE_AS_STRCAT ++ movb $0, (%rdi, %r8) ++# endif ++ VZEROUPPER ++ ret ++ ++ .p2align 4 ++L(StrncpyExit65): ++ /* 0/32, 32/32, 64/1 */ ++ vmovdqu (%rsi), %ymm2 ++ vmovdqu 32(%rsi), %ymm3 ++ mov 64(%rsi), %cl ++ vmovdqu %ymm2, (%rdi) ++ vmovdqu %ymm3, 32(%rdi) ++ mov %cl, 64(%rdi) ++# ifdef USE_AS_STPCPY ++ lea 65(%rdi), %rax ++# endif ++# ifdef USE_AS_STRCAT ++ movb $0, 65(%rdi) ++# endif ++ VZEROUPPER ++ ret ++ ++# ifndef USE_AS_STRCAT ++ ++ .p2align 4 ++L(Fill1): ++ mov %dl, (%rdi) ++ VZEROUPPER ++ ret ++ ++ .p2align 4 ++L(Fill2): ++ mov %dx, (%rdi) ++ VZEROUPPER ++ ret ++ ++ .p2align 4 ++L(Fill3_4): ++ mov %dx, (%rdi) ++ mov %dx, -2(%rdi, %r8) ++ VZEROUPPER ++ ret ++ ++ .p2align 4 ++L(Fill5_8): ++ mov %edx, (%rdi) ++ mov %edx, -4(%rdi, %r8) ++ VZEROUPPER ++ ret ++ ++ .p2align 4 ++L(Fill9_16): ++ mov %rdx, (%rdi) ++ mov %rdx, -8(%rdi, %r8) ++ VZEROUPPER ++ ret ++ ++ .p2align 4 ++L(Fill17_32): ++ vmovdqu %xmmZ, (%rdi) ++ vmovdqu %xmmZ, -16(%rdi, %r8) ++ VZEROUPPER ++ ret ++ ++ .p2align 4 ++L(CopyVecSizeUnalignedVec2): ++ vmovdqu %ymm2, (%rdi, %rcx) ++ ++ .p2align 4 ++L(CopyVecSizeVecExit): ++ bsf %edx, %edx ++ add $(VEC_SIZE - 1), %r8 ++ add %rcx, %rdi ++# ifdef USE_AS_STPCPY ++ lea (%rdi, %rdx), %rax ++# endif ++ sub %rdx, %r8 ++ lea 1(%rdi, %rdx), %rdi ++ ++ .p2align 4 ++L(StrncpyFillTailWithZero): ++ xor %edx, %edx ++ sub $VEC_SIZE, %r8 ++ jbe L(StrncpyFillExit) ++ ++ vmovdqu %ymmZ, (%rdi) ++ add $VEC_SIZE, %rdi ++ ++ mov %rdi, %rsi ++ and $(VEC_SIZE - 1), %esi ++ sub %rsi, %rdi ++ add %rsi, %r8 ++ sub $(VEC_SIZE * 4), %r8 ++ jb L(StrncpyFillLessFourVecSize) ++ ++L(StrncpyFillLoopVmovdqa): ++ vmovdqa %ymmZ, (%rdi) ++ vmovdqa %ymmZ, VEC_SIZE(%rdi) ++ vmovdqa %ymmZ, (VEC_SIZE * 2)(%rdi) ++ vmovdqa %ymmZ, (VEC_SIZE * 3)(%rdi) ++ add $(VEC_SIZE * 4), %rdi ++ sub $(VEC_SIZE * 4), %r8 ++ jae L(StrncpyFillLoopVmovdqa) ++ ++L(StrncpyFillLessFourVecSize): ++ add $(VEC_SIZE * 2), %r8 ++ jl L(StrncpyFillLessTwoVecSize) ++ vmovdqa %ymmZ, (%rdi) ++ vmovdqa %ymmZ, VEC_SIZE(%rdi) ++ add $(VEC_SIZE * 2), %rdi ++ sub $VEC_SIZE, %r8 ++ jl L(StrncpyFillExit) ++ vmovdqa %ymmZ, (%rdi) ++ add $VEC_SIZE, %rdi ++ jmp L(Fill) ++ ++ .p2align 4 ++L(StrncpyFillLessTwoVecSize): ++ add $VEC_SIZE, %r8 ++ jl L(StrncpyFillExit) ++ vmovdqa %ymmZ, (%rdi) ++ add $VEC_SIZE, %rdi ++ jmp L(Fill) ++ ++ .p2align 4 ++L(StrncpyFillExit): ++ add $VEC_SIZE, %r8 ++L(Fill): ++ cmp $17, %r8d ++ jae L(Fill17_32) ++ cmp $9, %r8d ++ jae L(Fill9_16) ++ cmp $5, %r8d ++ jae L(Fill5_8) ++ cmp $3, %r8d ++ jae L(Fill3_4) ++ cmp $1, %r8d ++ ja L(Fill2) ++ je L(Fill1) ++ VZEROUPPER ++ ret ++ ++/* end of ifndef USE_AS_STRCAT */ ++# endif ++ ++ .p2align 4 ++L(UnalignedLeaveCase2OrCase3): ++ test %rdx, %rdx ++ jnz L(UnalignedFourVecSizeLeaveCase2) ++L(UnalignedFourVecSizeLeaveCase3): ++ lea (VEC_SIZE * 4)(%r8), %rcx ++ and $-VEC_SIZE, %rcx ++ add $(VEC_SIZE * 3), %r8 ++ jl L(CopyVecSizeCase3) ++ vmovdqu %ymm4, (%rdi) ++ sub $VEC_SIZE, %r8 ++ jb L(CopyVecSizeCase3) ++ vmovdqu %ymm5, VEC_SIZE(%rdi) ++ sub $VEC_SIZE, %r8 ++ jb L(CopyVecSizeCase3) ++ vmovdqu %ymm6, (VEC_SIZE * 2)(%rdi) ++ sub $VEC_SIZE, %r8 ++ jb L(CopyVecSizeCase3) ++ vmovdqu %ymm7, (VEC_SIZE * 3)(%rdi) ++# ifdef USE_AS_STPCPY ++ lea (VEC_SIZE * 4)(%rdi), %rax ++# endif ++# ifdef USE_AS_STRCAT ++ movb $0, (VEC_SIZE * 4)(%rdi) ++# endif ++ VZEROUPPER ++ ret ++ ++ .p2align 4 ++L(UnalignedFourVecSizeLeaveCase2): ++ xor %ecx, %ecx ++ vpcmpeqb %ymm4, %ymmZ, %ymmM ++ vpmovmskb %ymmM, %edx ++ add $(VEC_SIZE * 3), %r8 ++ jle L(CopyVecSizeCase2OrCase3) ++ test %edx, %edx ++# ifndef USE_AS_STRCAT ++ jnz L(CopyVecSizeUnalignedVec4) ++# else ++ jnz L(CopyVecSize) ++# endif ++ vpcmpeqb %ymm5, %ymmZ, %ymmM ++ vpmovmskb %ymmM, %edx ++ vmovdqu %ymm4, (%rdi) ++ add $VEC_SIZE, %rcx ++ sub $VEC_SIZE, %r8 ++ jbe L(CopyVecSizeCase2OrCase3) ++ test %edx, %edx ++# ifndef USE_AS_STRCAT ++ jnz L(CopyVecSizeUnalignedVec5) ++# else ++ jnz L(CopyVecSize) ++# endif ++ ++ vpcmpeqb %ymm6, %ymmZ, %ymmM ++ vpmovmskb %ymmM, %edx ++ vmovdqu %ymm5, VEC_SIZE(%rdi) ++ add $VEC_SIZE, %rcx ++ sub $VEC_SIZE, %r8 ++ jbe L(CopyVecSizeCase2OrCase3) ++ test %edx, %edx ++# ifndef USE_AS_STRCAT ++ jnz L(CopyVecSizeUnalignedVec6) ++# else ++ jnz L(CopyVecSize) ++# endif ++ ++ vpcmpeqb %ymm7, %ymmZ, %ymmM ++ vpmovmskb %ymmM, %edx ++ vmovdqu %ymm6, (VEC_SIZE * 2)(%rdi) ++ lea VEC_SIZE(%rdi, %rcx), %rdi ++ lea VEC_SIZE(%rsi, %rcx), %rsi ++ bsf %edx, %edx ++ cmp %r8d, %edx ++ jb L(CopyVecSizeExit) ++L(StrncpyExit): ++ cmp $65, %r8d ++ je L(StrncpyExit65) ++ cmp $33, %r8d ++ jae L(StrncpyExit33_64) ++ cmp $17, %r8d ++ jae L(StrncpyExit17_32) ++ cmp $9, %r8d ++ jae L(StrncpyExit9_16) ++ cmp $5, %r8d ++ jae L(StrncpyExit5_8) ++ cmp $3, %r8d ++ jae L(StrncpyExit3_4) ++ cmp $1, %r8d ++ ja L(StrncpyExit2) ++ je L(StrncpyExit1) ++# ifdef USE_AS_STPCPY ++ mov %rdi, %rax ++# endif ++# ifdef USE_AS_STRCAT ++ movb $0, (%rdi) ++# endif ++ VZEROUPPER ++ ret ++ ++ .p2align 4 ++L(ExitZero): ++# ifndef USE_AS_STRCAT ++ mov %rdi, %rax ++# endif ++ VZEROUPPER ++ ret ++ ++# endif ++ ++# ifndef USE_AS_STRCAT ++END (STRCPY) ++# else ++END (STRCAT) ++# endif ++#endif +diff --git a/sysdeps/x86_64/multiarch/strcpy.c b/sysdeps/x86_64/multiarch/strcpy.c +index 12e0e3ffe20602c6..ecf90d4b044a1b01 100644 +--- a/sysdeps/x86_64/multiarch/strcpy.c ++++ b/sysdeps/x86_64/multiarch/strcpy.c +@@ -24,7 +24,7 @@ + # undef strcpy + + # define SYMBOL_NAME strcpy +-# include "ifunc-unaligned-ssse3.h" ++# include "ifunc-strcpy.h" + + libc_ifunc_redirected (__redirect_strcpy, strcpy, IFUNC_SELECTOR ()); + +diff --git a/sysdeps/x86_64/multiarch/strncat-avx2.S b/sysdeps/x86_64/multiarch/strncat-avx2.S +new file mode 100644 +index 0000000000000000..bfefa659bb6281fa +--- /dev/null ++++ b/sysdeps/x86_64/multiarch/strncat-avx2.S +@@ -0,0 +1,3 @@ ++#define USE_AS_STRNCAT ++#define STRCAT __strncat_avx2 ++#include "strcat-avx2.S" +diff --git a/sysdeps/x86_64/multiarch/strncat.c b/sysdeps/x86_64/multiarch/strncat.c +index 841c165565add132..74f7d028ae23d700 100644 +--- a/sysdeps/x86_64/multiarch/strncat.c ++++ b/sysdeps/x86_64/multiarch/strncat.c +@@ -24,7 +24,7 @@ + # undef strncat + + # define SYMBOL_NAME strncat +-# include "ifunc-unaligned-ssse3.h" ++# include "ifunc-strcpy.h" + + libc_ifunc_redirected (__redirect_strncat, strncat, IFUNC_SELECTOR ()); + strong_alias (strncat, __strncat); +diff --git a/sysdeps/x86_64/multiarch/strncpy-avx2.S b/sysdeps/x86_64/multiarch/strncpy-avx2.S +new file mode 100644 +index 0000000000000000..9ef8c87627dc4924 +--- /dev/null ++++ b/sysdeps/x86_64/multiarch/strncpy-avx2.S +@@ -0,0 +1,3 @@ ++#define USE_AS_STRNCPY ++#define STRCPY __strncpy_avx2 ++#include "strcpy-avx2.S" +diff --git a/sysdeps/x86_64/multiarch/strncpy.c b/sysdeps/x86_64/multiarch/strncpy.c +index 3c3de8b18ebb177f..93dfb4cfde79467a 100644 +--- a/sysdeps/x86_64/multiarch/strncpy.c ++++ b/sysdeps/x86_64/multiarch/strncpy.c +@@ -24,7 +24,7 @@ + # undef strncpy + + # define SYMBOL_NAME strncpy +-# include "ifunc-unaligned-ssse3.h" ++# include "ifunc-strcpy.h" + + libc_ifunc_redirected (__redirect_strncpy, strncpy, IFUNC_SELECTOR ()); + diff --git a/SOURCES/glibc-rh1817513-18.patch b/SOURCES/glibc-rh1817513-18.patch new file mode 100644 index 0000000..d7d84b7 --- /dev/null +++ b/SOURCES/glibc-rh1817513-18.patch @@ -0,0 +1,191 @@ +commit 32db86d558193ad4ad5a00926ce3c350c89eb8df +Author: Joseph Myers +Date: Tue Feb 12 10:30:34 2019 +0000 + + Add fall-through comments. + + This patch adds fall-through comments in some cases where -Wextra + produces implicit-fallthrough warnings. + + The patch is non-exhaustive. Apart from architecture-specific code + for non-x86_64 architectures, it does not change sunrpc/xdr.c (legacy + code, probably should have such changes, but left to be dealt with + separately), or places that already had comments about the + fall-through but not matching the form expected by + -Wimplicit-fallthrough=3 (the default level with -Wextra; my + inclination is to adjust those comments to match rather than + downgrading to -Wimplicit-fallthrough=1 to allow any comment), or one + place where I thought the implicit fallthrough was not correct and so + should be handled separately as a bug fix. I think the key thing to + consider in review of this patch is whether the fall-through is indeed + intended and correct in each place where such a comment is added. + + Tested for x86_64. + + * elf/dl-exception.c (_dl_exception_create_format): Add + fall-through comments. + * elf/ldconfig.c (parse_conf_include): Likewise. + * elf/rtld.c (print_statistics): Likewise. + * locale/programs/charmap.c (parse_charmap): Likewise. + * misc/mntent_r.c (__getmntent_r): Likewise. + * posix/wordexp.c (parse_arith): Likewise. + (parse_backtick): Likewise. + * resolv/ns_ttl.c (ns_parse_ttl): Likewise. + * sysdeps/x86/cpu-features.c (init_cpu_features): Likewise. + * sysdeps/x86_64/dl-machine.h (elf_machine_rela): Likewise. + +diff --git a/elf/dl-exception.c b/elf/dl-exception.c +index 3e8e0ba3f1442005..d24bf30a5cf39bc2 100644 +--- a/elf/dl-exception.c ++++ b/elf/dl-exception.c +@@ -123,6 +123,7 @@ _dl_exception_create_format (struct dl_exception *exception, const char *objname + ++p; + break; + } ++ /* Fall through. */ + case 'x': + length += INT_WIDTH / 4; + break; +diff --git a/elf/ldconfig.c b/elf/ldconfig.c +index fbdd814edf59bc77..ed7d9ab0412d93fd 100644 +--- a/elf/ldconfig.c ++++ b/elf/ldconfig.c +@@ -1228,6 +1228,7 @@ parse_conf_include (const char *config_file, unsigned int lineno, + + case GLOB_NOSPACE: + errno = ENOMEM; ++ /* Fall through. */ + case GLOB_ABORTED: + if (opt_verbose) + error (0, errno, _("%s:%u: cannot read directory %s"), +diff --git a/elf/rtld.c b/elf/rtld.c +index 7f030f75a22c532e..8bb5f548a0ff8eb4 100644 +--- a/elf/rtld.c ++++ b/elf/rtld.c +@@ -2734,8 +2734,10 @@ print_statistics (hp_timing_t *rtld_total_timep) + { + case 3: + *wp++ = *cp++; ++ /* Fall through. */ + case 2: + *wp++ = *cp++; ++ /* Fall through. */ + case 1: + *wp++ = '.'; + *wp++ = *cp++; +@@ -2797,8 +2799,10 @@ print_statistics (hp_timing_t *rtld_total_timep) + { + case 3: + *wp++ = *cp++; ++ /* Fall through. */ + case 2: + *wp++ = *cp++; ++ /* Fall through. */ + case 1: + *wp++ = '.'; + *wp++ = *cp++; +diff --git a/locale/programs/charmap.c b/locale/programs/charmap.c +index 2d54dd3c027d11d2..8041a0e5d292f3f5 100644 +--- a/locale/programs/charmap.c ++++ b/locale/programs/charmap.c +@@ -713,6 +713,7 @@ only WIDTH definitions are allowed to follow the CHARMAP definition")); + state = 95; + continue; + } ++ /* Fall through. */ + + case 96: + if (nowtok != tok_number) +diff --git a/misc/mntent_r.c b/misc/mntent_r.c +index 7bb224f044150ab4..add39d4537eaccb5 100644 +--- a/misc/mntent_r.c ++++ b/misc/mntent_r.c +@@ -167,8 +167,10 @@ get_mnt_entry (FILE *stream, struct mntent *mp, char *buffer, int bufsiz) + { + case 0: + mp->mnt_freq = 0; ++ /* Fall through. */ + case 1: + mp->mnt_passno = 0; ++ /* Fall through. */ + case 2: + break; + } +diff --git a/posix/wordexp.c b/posix/wordexp.c +index 7548e0329fdeafaa..048a8068544c81fa 100644 +--- a/posix/wordexp.c ++++ b/posix/wordexp.c +@@ -799,6 +799,7 @@ parse_arith (char **word, size_t *word_length, size_t *max_length, + + case '(': + ++paren_depth; ++ /* Fall through. */ + default: + expr = w_addchar (expr, &expr_length, &expr_maxlen, words[*offset]); + if (expr == NULL) +@@ -2127,6 +2128,7 @@ parse_backtick (char **word, size_t *word_length, size_t *max_length, + + case '\'': + squoting = 1 - squoting; ++ /* Fall through. */ + default: + comm = w_addchar (comm, &comm_length, &comm_maxlen, words[*offset]); + if (comm == NULL) +diff --git a/resolv/ns_ttl.c b/resolv/ns_ttl.c +index 079948790b94b05e..d29d9dc00cfcab2c 100644 +--- a/resolv/ns_ttl.c ++++ b/resolv/ns_ttl.c +@@ -113,9 +113,13 @@ ns_parse_ttl(const char *src, u_long *dst) { + ch = toupper(ch); + switch (ch) { + case 'W': tmp *= 7; ++ /* Fall through. */ + case 'D': tmp *= 24; ++ /* Fall through. */ + case 'H': tmp *= 60; ++ /* Fall through. */ + case 'M': tmp *= 60; ++ /* Fall through. */ + case 'S': break; + default: goto einval; + } +diff --git a/sysdeps/x86/cpu-features.c b/sysdeps/x86/cpu-features.c +index 3a02a9c7d08f9603..ade37a9bb3de86cc 100644 +--- a/sysdeps/x86/cpu-features.c ++++ b/sysdeps/x86/cpu-features.c +@@ -374,6 +374,7 @@ init_cpu_features (struct cpu_features *cpu_features) + of Core i3/i5/i7 processors if AVX is available. */ + if (!CPU_FEATURES_CPU_P (cpu_features, AVX)) + break; ++ /* Fall through. */ + + case 0x1a: + case 0x1e: +@@ -401,6 +402,7 @@ init_cpu_features (struct cpu_features *cpu_features) + /* Xeon E7 v3 with stepping >= 4 has working TSX. */ + if (stepping >= 4) + break; ++ /* Fall through. */ + case 0x3c: + case 0x45: + case 0x46: +diff --git a/sysdeps/x86_64/dl-machine.h b/sysdeps/x86_64/dl-machine.h +index 1942ed5061d18c68..23afb3c05dbe17d6 100644 +--- a/sysdeps/x86_64/dl-machine.h ++++ b/sysdeps/x86_64/dl-machine.h +@@ -347,6 +347,7 @@ elf_machine_rela (struct link_map *map, const ElfW(Rela) *reloc, + /* Set to symbol size plus addend. */ + value = sym->st_size; + # endif ++ /* Fall through. */ + case R_X86_64_GLOB_DAT: + case R_X86_64_JUMP_SLOT: + *reloc_addr = value + reloc->r_addend; +@@ -460,6 +461,7 @@ elf_machine_rela (struct link_map *map, const ElfW(Rela) *reloc, + /* Set to symbol size plus addend. */ + value = sym->st_size; + # endif ++ /* Fall through. */ + case R_X86_64_32: + value += reloc->r_addend; + *(unsigned int *) reloc_addr = value; diff --git a/SOURCES/glibc-rh1817513-19.patch b/SOURCES/glibc-rh1817513-19.patch new file mode 100644 index 0000000..674aa43 --- /dev/null +++ b/SOURCES/glibc-rh1817513-19.patch @@ -0,0 +1,408 @@ +commit 3b856d093f5197637a5927c37d6c07dad8c86d45 +Author: Florian Weimer +Date: Tue Feb 12 13:36:56 2019 +0100 + + elf: Ignore LD_AUDIT interfaces if la_version returns 0 [BZ #24122] + + This change moves the audit module loading and early notification into + separate functions out of dl_main. + + It restores the bug fix from commit + 8e889c5da3c5981c5a46a93fec02de40131ac5a6 ("elf: Fix LD_AUDIT for + modules with invalid version (BZ#24122)") which was reverted in commit + 83e6b59625f45db1eee93e5684091f740c52a083 ("[elf] Revert 8e889c5da3 + (BZ#24122)"). + + The actual bug fix is the separate error message for the case when + la_version returns zero. The dynamic linker error message (which is + NULL in this case) is no longer used. Based on the intended use of + version zero (ignore this module due to explicit request), the message + is only printed if debugging is enabled. + +diff --git a/elf/rtld.c b/elf/rtld.c +index 8bb5f548a0ff8eb4..375e0de8fa2e049e 100644 +--- a/elf/rtld.c ++++ b/elf/rtld.c +@@ -864,6 +864,205 @@ handle_preload_list (const char *preloadlist, struct link_map *main_map, + return npreloads; + } + ++/* Called if the audit DSO cannot be used: if it does not have the ++ appropriate interfaces, or it expects a more recent version library ++ version than what the dynamic linker provides. */ ++static void ++unload_audit_module (struct link_map *map, int original_tls_idx) ++{ ++#ifndef NDEBUG ++ Lmid_t ns = map->l_ns; ++#endif ++ _dl_close (map); ++ ++ /* Make sure the namespace has been cleared entirely. */ ++ assert (GL(dl_ns)[ns]._ns_loaded == NULL); ++ assert (GL(dl_ns)[ns]._ns_nloaded == 0); ++ ++ GL(dl_tls_max_dtv_idx) = original_tls_idx; ++} ++ ++/* Called to print an error message if loading of an audit module ++ failed. */ ++static void ++report_audit_module_load_error (const char *name, const char *err_str, ++ bool malloced) ++{ ++ _dl_error_printf ("\ ++ERROR: ld.so: object '%s' cannot be loaded as audit interface: %s; ignored.\n", ++ name, err_str); ++ if (malloced) ++ free ((char *) err_str); ++} ++ ++/* Load one audit module. */ ++static void ++load_audit_module (const char *name, struct audit_ifaces **last_audit) ++{ ++ int original_tls_idx = GL(dl_tls_max_dtv_idx); ++ ++ struct dlmopen_args dlmargs; ++ dlmargs.fname = name; ++ dlmargs.map = NULL; ++ ++ const char *objname; ++ const char *err_str = NULL; ++ bool malloced; ++ _dl_catch_error (&objname, &err_str, &malloced, dlmopen_doit, &dlmargs); ++ if (__glibc_unlikely (err_str != NULL)) ++ { ++ report_audit_module_load_error (name, err_str, malloced); ++ return; ++ } ++ ++ struct lookup_args largs; ++ largs.name = "la_version"; ++ largs.map = dlmargs.map; ++ _dl_catch_error (&objname, &err_str, &malloced, lookup_doit, &largs); ++ if (__glibc_likely (err_str != NULL)) ++ { ++ unload_audit_module (dlmargs.map, original_tls_idx); ++ report_audit_module_load_error (name, err_str, malloced); ++ return; ++ } ++ ++ unsigned int (*laversion) (unsigned int) = largs.result; ++ ++ /* A null symbol indicates that something is very wrong with the ++ loaded object because defined symbols are supposed to have a ++ valid, non-null address. */ ++ assert (laversion != NULL); ++ ++ unsigned int lav = laversion (LAV_CURRENT); ++ if (lav == 0) ++ { ++ /* Only print an error message if debugging because this can ++ happen deliberately. */ ++ if (GLRO(dl_debug_mask) & DL_DEBUG_FILES) ++ _dl_debug_printf ("\ ++file=%s [%lu]; audit interface function la_version returned zero; ignored.\n", ++ dlmargs.map->l_name, dlmargs.map->l_ns); ++ unload_audit_module (dlmargs.map, original_tls_idx); ++ return; ++ } ++ ++ if (lav > LAV_CURRENT) ++ { ++ _dl_debug_printf ("\ ++ERROR: audit interface '%s' requires version %d (maximum supported version %d); ignored.\n", ++ name, lav, LAV_CURRENT); ++ unload_audit_module (dlmargs.map, original_tls_idx); ++ return; ++ } ++ ++ enum { naudit_ifaces = 8 }; ++ union ++ { ++ struct audit_ifaces ifaces; ++ void (*fptr[naudit_ifaces]) (void); ++ } *newp = malloc (sizeof (*newp)); ++ if (newp == NULL) ++ _dl_fatal_printf ("Out of memory while loading audit modules\n"); ++ ++ /* Names of the auditing interfaces. All in one ++ long string. */ ++ static const char audit_iface_names[] = ++ "la_activity\0" ++ "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 ++#define STRING(s) __STRING (s) ++ "la_" STRING (ARCH_LA_PLTENTER) "\0" ++ "la_" STRING (ARCH_LA_PLTEXIT) "\0" ++ "la_objclose\0"; ++ unsigned int cnt = 0; ++ const char *cp = audit_iface_names; ++ do ++ { ++ largs.name = cp; ++ _dl_catch_error (&objname, &err_str, &malloced, lookup_doit, &largs); ++ ++ /* Store the pointer. */ ++ if (err_str == NULL && largs.result != NULL) ++ { ++ newp->fptr[cnt] = largs.result; ++ ++ /* The dynamic linker link map is statically allocated, ++ initialize the data now. */ ++ GL(dl_rtld_map).l_audit[cnt].cookie = (intptr_t) &GL(dl_rtld_map); ++ } ++ else ++ newp->fptr[cnt] = NULL; ++ ++cnt; ++ ++ cp = rawmemchr (cp, '\0') + 1; ++ } ++ while (*cp != '\0'); ++ assert (cnt == naudit_ifaces); ++ ++ /* Now append the new auditing interface to the list. */ ++ newp->ifaces.next = NULL; ++ if (*last_audit == NULL) ++ *last_audit = GLRO(dl_audit) = &newp->ifaces; ++ else ++ *last_audit = (*last_audit)->next = &newp->ifaces; ++ ++GLRO(dl_naudit); ++ ++ /* Mark the DSO as being used for auditing. */ ++ 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) ++ { ++ map->l_audit[cnt].bindflags ++ = afct->objopen (map, LM_ID_BASE, &map->l_audit[cnt].cookie); ++ map->l_audit_any_plt |= map->l_audit[cnt].bindflags != 0; ++ } ++ ++ afct = afct->next; ++ } ++} ++ ++/* Load all audit modules. */ ++static void ++load_audit_modules (struct link_map *main_map) ++{ ++ struct audit_ifaces *last_audit = NULL; ++ struct audit_list_iter al_iter; ++ audit_list_iter_init (&al_iter); ++ ++ while (true) ++ { ++ const char *name = audit_list_iter_next (&al_iter); ++ if (name == NULL) ++ break; ++ load_audit_module (name, &last_audit); ++ } ++ ++ /* Notify audit modules of the initially loaded modules (the main ++ 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)); ++ } ++} ++ + static void + dl_main (const ElfW(Phdr) *phdr, + ElfW(Word) phnum, +@@ -1402,10 +1601,6 @@ ERROR: '%s': cannot process note segment.\n", _dl_argv[0]); + if (__glibc_unlikely (audit_list != NULL) + || __glibc_unlikely (audit_list_string != NULL)) + { +- struct audit_ifaces *last_audit = NULL; +- struct audit_list_iter al_iter; +- audit_list_iter_init (&al_iter); +- + /* Since we start using the auditing DSOs right away we need to + initialize the data structures now. */ + tcbp = init_tls (); +@@ -1417,164 +1612,7 @@ ERROR: '%s': cannot process note segment.\n", _dl_argv[0]); + security_init (); + need_security_init = false; + +- while (true) +- { +- const char *name = audit_list_iter_next (&al_iter); +- if (name == NULL) +- break; +- +- int tls_idx = GL(dl_tls_max_dtv_idx); +- +- /* Now it is time to determine the layout of the static TLS +- block and allocate it for the initial thread. Note that we +- always allocate the static block, we never defer it even if +- no DF_STATIC_TLS bit is set. The reason is that we know +- glibc will use the static model. */ +- struct dlmopen_args dlmargs; +- dlmargs.fname = name; +- dlmargs.map = NULL; +- +- const char *objname; +- const char *err_str = NULL; +- bool malloced; +- (void) _dl_catch_error (&objname, &err_str, &malloced, dlmopen_doit, +- &dlmargs); +- if (__glibc_unlikely (err_str != NULL)) +- { +- not_loaded: +- _dl_error_printf ("\ +-ERROR: ld.so: object '%s' cannot be loaded as audit interface: %s; ignored.\n", +- name, err_str); +- if (malloced) +- free ((char *) err_str); +- } +- else +- { +- struct lookup_args largs; +- largs.name = "la_version"; +- largs.map = dlmargs.map; +- +- /* Check whether the interface version matches. */ +- (void) _dl_catch_error (&objname, &err_str, &malloced, +- lookup_doit, &largs); +- +- unsigned int (*laversion) (unsigned int); +- unsigned int lav; +- if (err_str == NULL +- && (laversion = largs.result) != NULL +- && (lav = laversion (LAV_CURRENT)) > 0 +- && lav <= LAV_CURRENT) +- { +- /* Allocate structure for the callback function pointers. +- This call can never fail. */ +- union +- { +- struct audit_ifaces ifaces; +-#define naudit_ifaces 8 +- void (*fptr[naudit_ifaces]) (void); +- } *newp = malloc (sizeof (*newp)); +- +- /* Names of the auditing interfaces. All in one +- long string. */ +- static const char audit_iface_names[] = +- "la_activity\0" +- "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 +-#define STRING(s) __STRING (s) +- "la_" STRING (ARCH_LA_PLTENTER) "\0" +- "la_" STRING (ARCH_LA_PLTEXIT) "\0" +- "la_objclose\0"; +- unsigned int cnt = 0; +- const char *cp = audit_iface_names; +- do +- { +- largs.name = cp; +- (void) _dl_catch_error (&objname, &err_str, &malloced, +- lookup_doit, &largs); +- +- /* Store the pointer. */ +- if (err_str == NULL && largs.result != NULL) +- { +- newp->fptr[cnt] = largs.result; +- +- /* The dynamic linker link map is statically +- allocated, initialize the data now. */ +- GL(dl_rtld_map).l_audit[cnt].cookie +- = (intptr_t) &GL(dl_rtld_map); +- } +- else +- newp->fptr[cnt] = NULL; +- ++cnt; +- +- cp = (char *) rawmemchr (cp, '\0') + 1; +- } +- while (*cp != '\0'); +- assert (cnt == naudit_ifaces); +- +- /* Now append the new auditing interface to the list. */ +- newp->ifaces.next = NULL; +- if (last_audit == NULL) +- last_audit = GLRO(dl_audit) = &newp->ifaces; +- else +- last_audit = last_audit->next = &newp->ifaces; +- ++GLRO(dl_naudit); +- +- /* Mark the DSO as being used for auditing. */ +- dlmargs.map->l_auditing = 1; +- } +- else +- { +- /* We cannot use the DSO, it does not have the +- appropriate interfaces or it expects something +- more recent. */ +-#ifndef NDEBUG +- Lmid_t ns = dlmargs.map->l_ns; +-#endif +- _dl_close (dlmargs.map); +- +- /* Make sure the namespace has been cleared entirely. */ +- assert (GL(dl_ns)[ns]._ns_loaded == NULL); +- assert (GL(dl_ns)[ns]._ns_nloaded == 0); +- +- GL(dl_tls_max_dtv_idx) = tls_idx; +- goto not_loaded; +- } +- } +- } +- +- /* If we have any auditing modules, announce that we already +- have two objects loaded. */ +- if (__glibc_unlikely (GLRO(dl_naudit) > 0)) +- { +- struct link_map *ls[2] = { main_map, &GL(dl_rtld_map) }; +- +- for (unsigned int outer = 0; outer < 2; ++outer) +- { +- struct audit_ifaces *afct = GLRO(dl_audit); +- for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt) +- { +- if (afct->objopen != NULL) +- { +- ls[outer]->l_audit[cnt].bindflags +- = afct->objopen (ls[outer], LM_ID_BASE, +- &ls[outer]->l_audit[cnt].cookie); +- +- ls[outer]->l_audit_any_plt +- |= ls[outer]->l_audit[cnt].bindflags != 0; +- } +- +- afct = afct->next; +- } +- } +- } ++ load_audit_modules (main_map); + } + + /* Keep track of the currently loaded modules to count how many diff --git a/SOURCES/glibc-rh1817513-2.patch b/SOURCES/glibc-rh1817513-2.patch new file mode 100644 index 0000000..f477471 --- /dev/null +++ b/SOURCES/glibc-rh1817513-2.patch @@ -0,0 +1,401 @@ +commit dce452dc5278f2985d21315721a6ba802537b862 +Author: Siddhesh Poyarekar +Date: Thu Aug 2 23:49:19 2018 +0530 + + Rename the glibc.tune namespace to glibc.cpu + + The glibc.tune namespace is vaguely named since it is a 'tunable', so + give it a more specific name that describes what it refers to. Rename + the tunable namespace to 'cpu' to more accurately reflect what it + encompasses. Also rename glibc.tune.cpu to glibc.cpu.name since + glibc.cpu.cpu is weird. + + * NEWS: Mention the change. + * elf/dl-tunables.list: Rename tune namespace to cpu. + * sysdeps/powerpc/dl-tunables.list: Likewise. + * sysdeps/x86/dl-tunables.list: Likewise. + * sysdeps/aarch64/dl-tunables.list: Rename tune.cpu to + cpu.name. + * elf/dl-hwcaps.c (_dl_important_hwcaps): Adjust. + * elf/dl-hwcaps.h (GET_HWCAP_MASK): Likewise. + * manual/README.tunables: Likewise. + * manual/tunables.texi: Likewise. + * sysdeps/powerpc/cpu-features.c: Likewise. + * sysdeps/unix/sysv/linux/aarch64/cpu-features.c + (init_cpu_features): Likewise. + * sysdeps/x86/cpu-features.c: Likewise. + * sysdeps/x86/cpu-features.h: Likewise. + * sysdeps/x86/cpu-tunables.c: Likewise. + * sysdeps/x86_64/Makefile: Likewise. + * sysdeps/x86/dl-cet.c: Likewise. + + Reviewed-by: Carlos O'Donell + +Conflicts: + manual/tunables.texi + (Earlier backport of non-temporal memcpy threshold.) + sysdeps/x86/Makefile + (Earlier CET backports.) + +diff --git a/elf/dl-hwcaps.c b/elf/dl-hwcaps.c +index 23482a88a1c9bca9..ecf00b457760e517 100644 +--- a/elf/dl-hwcaps.c ++++ b/elf/dl-hwcaps.c +@@ -140,7 +140,7 @@ _dl_important_hwcaps (const char *platform, size_t platform_len, size_t *sz, + string and bit like you can ignore an OS-supplied HWCAP bit. */ + hwcap_mask |= (uint64_t) mask << _DL_FIRST_EXTRA; + #if HAVE_TUNABLES +- TUNABLE_SET (glibc, tune, hwcap_mask, uint64_t, hwcap_mask); ++ TUNABLE_SET (glibc, cpu, hwcap_mask, uint64_t, hwcap_mask); + #else + GLRO(dl_hwcap_mask) = hwcap_mask; + #endif +diff --git a/elf/dl-hwcaps.h b/elf/dl-hwcaps.h +index 17f0da4c73772425..d69ee11dc27bb5e5 100644 +--- a/elf/dl-hwcaps.h ++++ b/elf/dl-hwcaps.h +@@ -19,7 +19,7 @@ + #include + + #if HAVE_TUNABLES +-# define GET_HWCAP_MASK() TUNABLE_GET (glibc, tune, hwcap_mask, uint64_t, NULL) ++# define GET_HWCAP_MASK() TUNABLE_GET (glibc, cpu, hwcap_mask, uint64_t, NULL) + #else + # ifdef SHARED + # define GET_HWCAP_MASK() GLRO(dl_hwcap_mask) +diff --git a/elf/dl-tunables.list b/elf/dl-tunables.list +index 1ff6fcb6f24f93a8..b7cc79f8bfe0a7c6 100644 +--- a/elf/dl-tunables.list ++++ b/elf/dl-tunables.list +@@ -91,7 +91,7 @@ glibc { + security_level: SXID_IGNORE + } + } +- tune { ++ cpu { + hwcap_mask { + type: UINT_64 + env_alias: LD_HWCAP_MASK +diff --git a/manual/README.tunables b/manual/README.tunables +index 3967679f432a6378..f87a31a65e0a3455 100644 +--- a/manual/README.tunables ++++ b/manual/README.tunables +@@ -105,11 +105,11 @@ where 'check' is the tunable name, 'int32_t' is the C type of the tunable and + To get and set tunables in a different namespace from that module, use the full + form of the macros as follows: + +- val = TUNABLE_GET_FULL (glibc, tune, hwcap_mask, uint64_t, NULL) ++ val = TUNABLE_GET_FULL (glibc, cpu, hwcap_mask, uint64_t, NULL) + +- TUNABLE_SET_FULL (glibc, tune, hwcap_mask, uint64_t, val) ++ TUNABLE_SET_FULL (glibc, cpu, hwcap_mask, uint64_t, val) + +-where 'glibc' is the top namespace, 'tune' is the tunable namespace and the ++where 'glibc' is the top namespace, 'cpu' is the tunable namespace and the + remaining arguments are the same as the short form macros. + + When TUNABLE_NAMESPACE is not defined in a module, TUNABLE_GET is equivalent to +diff --git a/manual/tunables.texi b/manual/tunables.texi +index 3e1e519dff153b09..ef10d2872cfc244e 100644 +--- a/manual/tunables.texi ++++ b/manual/tunables.texi +@@ -307,23 +307,23 @@ The default value of this tunable is @samp{3}. + @cindex non_temporal_threshold tunables + @cindex tunables, non_temporal_threshold + +-@deftp {Tunable namespace} glibc.tune ++@deftp {Tunable namespace} glibc.cpu + Behavior of @theglibc{} can be tuned to assume specific hardware capabilities +-by setting the following tunables in the @code{tune} namespace: ++by setting the following tunables in the @code{cpu} namespace: + @end deftp + +-@deftp Tunable glibc.tune.hwcap_mask ++@deftp Tunable glibc.cpu.hwcap_mask + This tunable supersedes the @env{LD_HWCAP_MASK} environment variable and is + identical in features. + + The @code{AT_HWCAP} key in the Auxiliary Vector specifies instruction set + extensions available in the processor at runtime for some architectures. The +-@code{glibc.tune.hwcap_mask} tunable allows the user to mask out those ++@code{glibc.cpu.hwcap_mask} tunable allows the user to mask out those + capabilities at runtime, thus disabling use of those extensions. + @end deftp + +-@deftp Tunable glibc.tune.hwcaps +-The @code{glibc.tune.hwcaps=-xxx,yyy,-zzz...} tunable allows the user to ++@deftp Tunable glibc.cpu.hwcaps ++The @code{glibc.cpu.hwcaps=-xxx,yyy,-zzz...} tunable allows the user to + enable CPU/ARCH feature @code{yyy}, disable CPU/ARCH feature @code{xxx} + and @code{zzz} where the feature name is case-sensitive and has to match + the ones in @code{sysdeps/x86/cpu-features.h}. +@@ -331,8 +331,8 @@ the ones in @code{sysdeps/x86/cpu-features.h}. + This tunable is specific to i386 and x86-64. + @end deftp + +-@deftp Tunable glibc.tune.cached_memopt +-The @code{glibc.tune.cached_memopt=[0|1]} tunable allows the user to ++@deftp Tunable glibc.cpu.cached_memopt ++The @code{glibc.cpu.cached_memopt=[0|1]} tunable allows the user to + enable optimizations recommended for cacheable memory. If set to + @code{1}, @theglibc{} assumes that the process memory image consists + of cacheable (non-device) memory only. The default, @code{0}, +@@ -341,8 +341,8 @@ indicates that the process may use device memory. + This tunable is specific to powerpc, powerpc64 and powerpc64le. + @end deftp + +-@deftp Tunable glibc.tune.cpu +-The @code{glibc.tune.cpu=xxx} tunable allows the user to tell @theglibc{} to ++@deftp Tunable glibc.cpu.name ++The @code{glibc.cpu.name=xxx} tunable allows the user to tell @theglibc{} to + assume that the CPU is @code{xxx} where xxx may have one of these values: + @code{generic}, @code{falkor}, @code{thunderxt88}, @code{thunderx2t99}, + @code{thunderx2t99p1}. +@@ -350,20 +350,20 @@ assume that the CPU is @code{xxx} where xxx may have one of these values: + This tunable is specific to aarch64. + @end deftp + +-@deftp Tunable glibc.tune.x86_data_cache_size +-The @code{glibc.tune.x86_data_cache_size} tunable allows the user to set ++@deftp Tunable glibc.cpu.x86_data_cache_size ++The @code{glibc.cpu.x86_data_cache_size} tunable allows the user to set + data cache size in bytes for use in memory and string routines. + + This tunable is specific to i386 and x86-64. + @end deftp + +-@deftp Tunable glibc.tune.x86_shared_cache_size +-The @code{glibc.tune.x86_shared_cache_size} tunable allows the user to ++@deftp Tunable glibc.cpu.x86_shared_cache_size ++The @code{glibc.cpu.x86_shared_cache_size} tunable allows the user to + set shared cache size in bytes for use in memory and string routines. + @end deftp + +-@deftp Tunable glibc.tune.x86_non_temporal_threshold +-The @code{glibc.tune.x86_non_temporal_threshold} tunable allows the user ++@deftp Tunable glibc.cpu.x86_non_temporal_threshold ++The @code{glibc.cpu.x86_non_temporal_threshold} tunable allows the user + to set threshold in bytes for non temporal store. Non temporal stores + give a hint to the hardware to move data directly to memory without + displacing other data from the cache. This tunable is used by some +@@ -373,8 +373,8 @@ like memmove and memcpy. + This tunable is specific to i386 and x86-64. + @end deftp + +-@deftp Tunable glibc.tune.x86_ibt +-The @code{glibc.tune.x86_ibt} tunable allows the user to control how ++@deftp Tunable glibc.cpu.x86_ibt ++The @code{glibc.cpu.x86_ibt} tunable allows the user to control how + indirect branch tracking (IBT) should be enabled. Accepted values are + @code{on}, @code{off}, and @code{permissive}. @code{on} always turns + on IBT regardless of whether IBT is enabled in the executable and its +@@ -386,8 +386,8 @@ IBT on non-CET executables and shared libraries. + This tunable is specific to i386 and x86-64. + @end deftp + +-@deftp Tunable glibc.tune.x86_shstk +-The @code{glibc.tune.x86_shstk} tunable allows the user to control how ++@deftp Tunable glibc.cpu.x86_shstk ++The @code{glibc.cpu.x86_shstk} tunable allows the user to control how + the shadow stack (SHSTK) should be enabled. Accepted values are + @code{on}, @code{off}, and @code{permissive}. @code{on} always turns on + SHSTK regardless of whether SHSTK is enabled in the executable and its +diff --git a/sysdeps/aarch64/dl-tunables.list b/sysdeps/aarch64/dl-tunables.list +index f6a88168cc5ec7e6..cfcf940ebd15a9aa 100644 +--- a/sysdeps/aarch64/dl-tunables.list ++++ b/sysdeps/aarch64/dl-tunables.list +@@ -17,8 +17,8 @@ + # . + + glibc { +- tune { +- cpu { ++ cpu { ++ name { + type: STRING + } + } +diff --git a/sysdeps/powerpc/cpu-features.c b/sysdeps/powerpc/cpu-features.c +index 955d4778a69db607..ad809b9815eb68f0 100644 +--- a/sysdeps/powerpc/cpu-features.c ++++ b/sysdeps/powerpc/cpu-features.c +@@ -30,7 +30,7 @@ init_cpu_features (struct cpu_features *cpu_features) + tunables is enable, since for this case user can explicit disable + unaligned optimizations. */ + #if HAVE_TUNABLES +- int32_t cached_memfunc = TUNABLE_GET (glibc, tune, cached_memopt, int32_t, ++ int32_t cached_memfunc = TUNABLE_GET (glibc, cpu, cached_memopt, int32_t, + NULL); + cpu_features->use_cached_memopt = (cached_memfunc > 0); + #else +diff --git a/sysdeps/powerpc/dl-tunables.list b/sysdeps/powerpc/dl-tunables.list +index d26636a16bfcd6d9..b3372555f75f8e38 100644 +--- a/sysdeps/powerpc/dl-tunables.list ++++ b/sysdeps/powerpc/dl-tunables.list +@@ -17,7 +17,7 @@ + # . + + glibc { +- tune { ++ cpu { + cached_memopt { + type: INT_32 + minval: 0 +diff --git a/sysdeps/unix/sysv/linux/aarch64/cpu-features.c b/sysdeps/unix/sysv/linux/aarch64/cpu-features.c +index 39eba0186f55b5de..b4f348509eb1c6b3 100644 +--- a/sysdeps/unix/sysv/linux/aarch64/cpu-features.c ++++ b/sysdeps/unix/sysv/linux/aarch64/cpu-features.c +@@ -57,7 +57,7 @@ init_cpu_features (struct cpu_features *cpu_features) + + #if HAVE_TUNABLES + /* Get the tunable override. */ +- const char *mcpu = TUNABLE_GET (glibc, tune, cpu, const char *, NULL); ++ const char *mcpu = TUNABLE_GET (glibc, cpu, name, const char *, NULL); + if (mcpu != NULL) + midr = get_midr_from_mcpu (mcpu); + #endif +diff --git a/sysdeps/x86/Makefile b/sysdeps/x86/Makefile +index d5f821e0831997ac..a936134a577e42a5 100644 +--- a/sysdeps/x86/Makefile ++++ b/sysdeps/x86/Makefile +@@ -84,21 +84,21 @@ LDFLAGS-tst-cet-legacy-mod-6c.so = -Wl,--enable-new-dtags,-z,nodelete + ifneq (no,$(have-tunables)) + $(objpfx)tst-cet-legacy-4a: $(libdl) + $(objpfx)tst-cet-legacy-4a.out: $(objpfx)tst-cet-legacy-mod-4.so +-tst-cet-legacy-4a-ENV = GLIBC_TUNABLES=glibc.tune.x86_shstk=permissive ++tst-cet-legacy-4a-ENV = GLIBC_TUNABLES=glibc.cpu.x86_shstk=permissive + $(objpfx)tst-cet-legacy-4b: $(libdl) + $(objpfx)tst-cet-legacy-4b.out: $(objpfx)tst-cet-legacy-mod-4.so +-tst-cet-legacy-4b-ENV = GLIBC_TUNABLES=glibc.tune.x86_shstk=on ++tst-cet-legacy-4b-ENV = GLIBC_TUNABLES=glibc.cpu.x86_shstk=on + $(objpfx)tst-cet-legacy-4c: $(libdl) + $(objpfx)tst-cet-legacy-4c.out: $(objpfx)tst-cet-legacy-mod-4.so +-tst-cet-legacy-4c-ENV = GLIBC_TUNABLES=glibc.tune.x86_shstk=off ++tst-cet-legacy-4c-ENV = GLIBC_TUNABLES=glibc.cpu.x86_shstk=off + $(objpfx)tst-cet-legacy-5b: $(libdl) + $(objpfx)tst-cet-legacy-5b.out: $(objpfx)tst-cet-legacy-mod-5a.so \ + $(objpfx)tst-cet-legacy-mod-5b.so +-tst-cet-legacy-5b-ENV = GLIBC_TUNABLES=glibc.tune.x86_ibt=off:glibc.tune.x86_shstk=off ++tst-cet-legacy-5b-ENV = GLIBC_TUNABLES=glibc.cpu.x86_ibt=off:glibc.cpu.x86_shstk=off + $(objpfx)tst-cet-legacy-6b: $(libdl) + $(objpfx)tst-cet-legacy-6b.out: $(objpfx)tst-cet-legacy-mod-6a.so \ + $(objpfx)tst-cet-legacy-mod-6b.so +-tst-cet-legacy-6b-ENV = GLIBC_TUNABLES=glibc.tune.x86_ibt=off:glibc.tune.x86_shstk=off ++tst-cet-legacy-6b-ENV = GLIBC_TUNABLES=glibc.cpu.x86_ibt=off:glibc.cpu.x86_shstk=off + endif + endif + +diff --git a/sysdeps/x86/cpu-features.c b/sysdeps/x86/cpu-features.c +index 41f2d15fa5c8a756..3b268efbce627e6c 100644 +--- a/sysdeps/x86/cpu-features.c ++++ b/sysdeps/x86/cpu-features.c +@@ -22,7 +22,7 @@ + #include + + #if HAVE_TUNABLES +-# define TUNABLE_NAMESPACE tune ++# define TUNABLE_NAMESPACE cpu + # include /* Get STDOUT_FILENO for _dl_printf. */ + # include + +@@ -424,7 +424,7 @@ no_cpuid: + + /* Reuse dl_platform, dl_hwcap and dl_hwcap_mask for x86. */ + #if !HAVE_TUNABLES && defined SHARED +- /* The glibc.tune.hwcap_mask tunable is initialized already, so no need to do ++ /* The glibc.cpu.hwcap_mask tunable is initialized already, so no need to do + this. */ + GLRO(dl_hwcap_mask) = HWCAP_IMPORTANT; + #endif +@@ -499,7 +499,7 @@ no_cpuid: + /* Disable IBT and/or SHSTK if they are enabled by kernel, but + disabled by environment variable: + +- GLIBC_TUNABLES=glibc.tune.hwcaps=-IBT,-SHSTK ++ GLIBC_TUNABLES=glibc.cpu.hwcaps=-IBT,-SHSTK + */ + unsigned int cet_feature = 0; + if (!HAS_CPU_FEATURE (IBT)) +diff --git a/sysdeps/x86/cpu-features.h b/sysdeps/x86/cpu-features.h +index 347a4b118d007fd8..4c6d08c709eea204 100644 +--- a/sysdeps/x86/cpu-features.h ++++ b/sysdeps/x86/cpu-features.h +@@ -141,7 +141,7 @@ struct cpu_features + unsigned long int xsave_state_size; + /* The full state size for XSAVE when XSAVEC is disabled by + +- GLIBC_TUNABLES=glibc.tune.hwcaps=-XSAVEC_Usable ++ GLIBC_TUNABLES=glibc.cpu.hwcaps=-XSAVEC_Usable + */ + unsigned int xsave_state_full_size; + unsigned int feature[FEATURE_INDEX_MAX]; +diff --git a/sysdeps/x86/cpu-tunables.c b/sysdeps/x86/cpu-tunables.c +index fad6726882fa7e2d..2e5d37753713e975 100644 +--- a/sysdeps/x86/cpu-tunables.c ++++ b/sysdeps/x86/cpu-tunables.c +@@ -17,7 +17,7 @@ + . */ + + #if HAVE_TUNABLES +-# define TUNABLE_NAMESPACE tune ++# define TUNABLE_NAMESPACE cpu + # include + # include + # include /* Get STDOUT_FILENO for _dl_printf. */ +@@ -116,7 +116,7 @@ TUNABLE_CALLBACK (set_hwcaps) (tunable_val_t *valp) + the hardware which wasn't available when the selection was made. + The environment variable: + +- GLIBC_TUNABLES=glibc.tune.hwcaps=-xxx,yyy,-zzz,.... ++ GLIBC_TUNABLES=glibc.cpu.hwcaps=-xxx,yyy,-zzz,.... + + can be used to enable CPU/ARCH feature yyy, disable CPU/ARCH feature + yyy and zzz, where the feature name is case-sensitive and has to +diff --git a/sysdeps/x86/dl-cet.c b/sysdeps/x86/dl-cet.c +index ebc0d577e414c807..d481bddc27e5d7cc 100644 +--- a/sysdeps/x86/dl-cet.c ++++ b/sysdeps/x86/dl-cet.c +@@ -72,7 +72,7 @@ dl_cet_check (struct link_map *m, const char *program) + /* Enable IBT and SHSTK only if they are enabled in executable. + NB: IBT and SHSTK may be disabled by environment variable: + +- GLIBC_TUNABLES=glibc.tune.hwcaps=-IBT,-SHSTK ++ GLIBC_TUNABLES=glibc.cpu.hwcaps=-IBT,-SHSTK + */ + enable_ibt &= (HAS_CPU_FEATURE (IBT) + && (enable_ibt_type == cet_always_on +diff --git a/sysdeps/x86/dl-tunables.list b/sysdeps/x86/dl-tunables.list +index 73886b1352316854..2a457d0eec9c3122 100644 +--- a/sysdeps/x86/dl-tunables.list ++++ b/sysdeps/x86/dl-tunables.list +@@ -17,7 +17,7 @@ + # . + + glibc { +- tune { ++ cpu { + hwcaps { + type: STRING + } +diff --git a/sysdeps/x86_64/Makefile b/sysdeps/x86_64/Makefile +index 9f1562f1b25a2df5..d51cf03ac92ebcc2 100644 +--- a/sysdeps/x86_64/Makefile ++++ b/sysdeps/x86_64/Makefile +@@ -57,7 +57,7 @@ modules-names += x86_64/tst-x86_64mod-1 + LDFLAGS-tst-x86_64mod-1.so = -Wl,-soname,tst-x86_64mod-1.so + ifneq (no,$(have-tunables)) + # Test the state size for XSAVE when XSAVEC is disabled. +-tst-x86_64-1-ENV = GLIBC_TUNABLES=glibc.tune.hwcaps=-XSAVEC_Usable ++tst-x86_64-1-ENV = GLIBC_TUNABLES=glibc.cpu.hwcaps=-XSAVEC_Usable + endif + + $(objpfx)tst-x86_64-1: $(objpfx)x86_64/tst-x86_64mod-1.so +@@ -74,7 +74,7 @@ $(objpfx)tst-platform-1.out: $(objpfx)x86_64/tst-platformmod-2.so + # Turn off AVX512F_Usable and AVX2_Usable so that GLRO(dl_platform) is + # always set to x86_64. + tst-platform-1-ENV = LD_PRELOAD=$(objpfx)\$$PLATFORM/tst-platformmod-2.so \ +- GLIBC_TUNABLES=glibc.tune.hwcaps=-AVX512F_Usable,-AVX2_Usable ++ GLIBC_TUNABLES=glibc.cpu.hwcaps=-AVX512F_Usable,-AVX2_Usable + endif + + tests += tst-audit3 tst-audit4 tst-audit5 tst-audit6 tst-audit7 \ diff --git a/SOURCES/glibc-rh1817513-20.patch b/SOURCES/glibc-rh1817513-20.patch new file mode 100644 index 0000000..f111f46 --- /dev/null +++ b/SOURCES/glibc-rh1817513-20.patch @@ -0,0 +1,179 @@ +commit b3fbfe81961a1d14d7b54d1c9757e1f487073bcb +Author: Adhemerval Zanella +Date: Tue Feb 12 13:51:43 2019 +0100 + + elf: Test for LD_AUDIT module returning zero from la_version [BZ #24122] + + This includes the original test case from commit + 8e889c5da3c5981c5a46a93fec02de40131ac5a6 ("elf: Fix LD_AUDIT for + modules with invalid version (BZ#24122)). + +Conflicts: + elf/Makefile + (Different backport order of tests.) + +diff --git a/elf/Makefile b/elf/Makefile +index 6d1962b2e4deb871..4e1356b9172aee02 100644 +--- a/elf/Makefile ++++ b/elf/Makefile +@@ -191,6 +191,7 @@ tests += restest1 preloadtest loadfail multiload origtest resolvfail \ + 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-initfinilazyfail \ + tst-dlopenfail tst-dlopenfail-2 \ + tst-filterobj tst-filterobj-dlopen tst-auxobj tst-auxobj-dlopen +@@ -300,7 +301,7 @@ modules-names = testobj1 testobj2 testobj3 testobj4 testobj5 testobj6 \ + 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-sonamemove-linkmod1 \ ++ tst-audit13mod1 tst-sonamemove-linkmod1 \ + tst-sonamemove-runmod1 tst-sonamemove-runmod2 \ + tst-initlazyfailmod tst-finilazyfailmod \ + tst-dlopenfailmod1 tst-dlopenfaillinkmod tst-dlopenfailmod2 \ +@@ -1428,6 +1429,10 @@ tst-audit12-ENV = LD_AUDIT=$(objpfx)tst-auditmod12.so + $(objpfx)tst-audit12mod1.so: $(objpfx)tst-audit12mod2.so + LDFLAGS-tst-audit12mod2.so = -Wl,--version-script=tst-audit12mod2.map + ++$(objpfx)tst-audit13.out: $(objpfx)tst-audit13mod1.so ++LDFLAGS-tst-audit13mod1.so = -Wl,-z,lazy ++tst-audit13-ENV = LD_AUDIT=$(objpfx)tst-audit13mod1.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-audit13.c b/elf/tst-audit13.c +new file mode 100644 +index 0000000000000000..6f587baf581ce32c +--- /dev/null ++++ b/elf/tst-audit13.c +@@ -0,0 +1,28 @@ ++/* Check for invalid audit version (BZ#24122). ++ 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, see ++ . */ ++ ++#include ++ ++static int ++do_test (void) ++{ ++ puts ("plt call"); ++ return 0; ++} ++ ++#include +diff --git a/elf/tst-audit13mod1.c b/elf/tst-audit13mod1.c +new file mode 100644 +index 0000000000000000..cf017e235c7ae030 +--- /dev/null ++++ b/elf/tst-audit13mod1.c +@@ -0,0 +1,93 @@ ++/* Check for invalid audit version (BZ#24122). ++ 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, see ++ . */ ++ ++#include ++#include ++ ++unsigned int ++la_version (unsigned int version) ++{ ++ /* The audit specification says that a version of 0 or a version ++ greater than any version supported by the dynamic loader shall ++ cause the module to be ignored. */ ++ return 0; ++} ++ ++void ++la_activity (uintptr_t *cookie, unsigned int flag) ++{ ++ exit (EXIT_FAILURE); ++} ++ ++char * ++la_objsearch (const char *name, uintptr_t *cookie, unsigned int flag) ++{ ++ exit (EXIT_FAILURE); ++} ++ ++unsigned int ++la_objopen (struct link_map *map, Lmid_t lmid, uintptr_t * cookie) ++{ ++ exit (EXIT_FAILURE); ++} ++ ++void ++la_preinit (uintptr_t * cookie) ++{ ++ exit (EXIT_FAILURE); ++} ++ ++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 ++{ ++ exit (EXIT_FAILURE); ++} ++ ++unsigned int ++la_objclose (uintptr_t * cookie) ++{ ++ exit (EXIT_FAILURE); ++} ++ ++#include ++#if (!defined (pltenter) || !defined (pltexit) || !defined (La_regs) \ ++ || !defined (La_retval) || !defined (int_retval)) ++# error "architecture specific code needed in sysdeps/CPU/tst-audit.h" ++#endif ++ ++ElfW(Addr) ++pltenter (ElfW(Sym) *sym, unsigned int ndx, uintptr_t *refcook, ++ uintptr_t *defcook, La_regs *regs, unsigned int *flags, ++ const char *symname, long int *framesizep) ++{ ++ exit (EXIT_FAILURE); ++} ++ ++unsigned int ++pltexit (ElfW(Sym) *sym, unsigned int ndx, uintptr_t *refcook, ++ uintptr_t *defcook, const La_regs *inregs, La_retval *outregs, ++ const char *symname) ++{ ++ exit (EXIT_FAILURE); ++} diff --git a/SOURCES/glibc-rh1817513-21.patch b/SOURCES/glibc-rh1817513-21.patch new file mode 100644 index 0000000..c7550dc --- /dev/null +++ b/SOURCES/glibc-rh1817513-21.patch @@ -0,0 +1,29 @@ +commit 86140c6223b5d14d773cf3050ffd0d14977c2c2d +Author: Joseph Myers +Date: Wed Feb 13 13:34:24 2019 +0000 + + Avoid fall-through in test-container if execlp fails. + + One of the implicit-fallthrough warnings from compiling glibc with + -Wextra appears to indicate an actual bug: the test-container code + could fall through inappropriately if execlp returns (which only + occurs on error). This patch adds appropriate error handling in this + case to avoid that fall-through. + + Tested for x86_64. + + * support/test-container.c (recursive_remove): Use FAIL_EXIT1 if + execlp returns. + +diff --git a/support/test-container.c b/support/test-container.c +index 1d1aebeaf3412573..f0d9e3060e80bda5 100644 +--- a/support/test-container.c ++++ b/support/test-container.c +@@ -361,6 +361,7 @@ recursive_remove (char *path) + case 0: + /* Child. */ + execlp ("rm", "rm", "-rf", path, NULL); ++ FAIL_EXIT1 ("exec rm: %m"); + default: + /* Parent. */ + waitpid (child, &status, 0); diff --git a/SOURCES/glibc-rh1817513-22.patch b/SOURCES/glibc-rh1817513-22.patch new file mode 100644 index 0000000..f7b0320 --- /dev/null +++ b/SOURCES/glibc-rh1817513-22.patch @@ -0,0 +1,223 @@ +commit 77b6f5534778b5403c87fa5415625aeb4c3cbf44 +Author: Adhemerval Zanella +Date: Wed Jan 16 17:30:07 2019 +0000 + + linux: Assume clock_getres CLOCK_{PROCESS,THREAD}_CPUTIME_ID + + The Linux 3.2 clock_getres kernel code (kernel/posix-cpu-timers.c) + issued for clock_getres CLOCK_PROCESS_CPUTIME_ID (process_cpu_clock_getres) + and CLOCK_THREAD_CPUTIME_ID (thread_cpu_clock_getres) call + posix_cpu_clock_getres. And it fails on check_clock only if an invalid + clock is used (not the case) or if we pass an invalid the pid/tid in + 29 msb of clock_id (not the case either). + + This patch assumes that clock_getres syscall always support + CLOCK_PROCESS_CPUTIME_ID and CLOCK_THREAD_CPUTIME_ID, so there is no need + to fallback to hp-timing support for _SC_MONOTONIC_CLOCK neither to issue + the syscall to certify the clock_id is supported bt the kernel. This + allows simplify the sysconf support to always use the syscall. + + it also removes ia64 itc drift check and assume kernel handles it correctly. + + Checked on aarch64-linux-gnu, x86_64-linux-gnu, and i686-linux-gnu. + + * sysdeps/unix/sysv/linux/ia64/has_cpuclock.c: Remove file. + * sysdeps/unix/sysv/linux/ia64/sysconf.c: Likewise. + * sysdeps/unix/sysv/linux/sysconf.c (has_cpuclock): Remove function. + (__sysconf): Assume kernel support for _SC_MONOTONIC_CLOCK, + _SC_CPUTIME, and _SC_THREAD_CPUTIME. + +Conflicts: + sysdeps/unix/sysv/linux/ia64/has_cpuclock.c + sysdeps/unix/sysv/linux/ia64/sysconf.c + (Removal after copyright year update.) + +diff --git a/sysdeps/unix/sysv/linux/ia64/has_cpuclock.c b/sysdeps/unix/sysv/linux/ia64/has_cpuclock.c +deleted file mode 100644 +index 75f3ef9f4d1366fb..0000000000000000 +--- a/sysdeps/unix/sysv/linux/ia64/has_cpuclock.c ++++ /dev/null +@@ -1,51 +0,0 @@ +-/* 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 +-#include +-#include +-#include +- +-static int itc_usable; +- +-static int +-has_cpuclock (void) +-{ +- if (__builtin_expect (itc_usable == 0, 0)) +- { +- int newval = 1; +- int fd = __open_nocancel ("/proc/sal/itc_drift", O_RDONLY); +- if (__builtin_expect (fd != -1, 1)) +- { +- char buf[16]; +- /* We expect the file to contain a single digit followed by +- a newline. If the format changes we better not rely on +- the file content. */ +- if (__read_nocancel (fd, buf, sizeof buf) != 2 +- || buf[0] != '0' || buf[1] != '\n') +- newval = -1; +- +- __close_nocancel_nostatus (fd); +- } +- +- itc_usable = newval; +- } +- +- return itc_usable; +-} +diff --git a/sysdeps/unix/sysv/linux/ia64/sysconf.c b/sysdeps/unix/sysv/linux/ia64/sysconf.c +deleted file mode 100644 +index 6c39db5a4af3e15a..0000000000000000 +--- a/sysdeps/unix/sysv/linux/ia64/sysconf.c ++++ /dev/null +@@ -1,30 +0,0 @@ +-/* Get file-specific information about a file. Linux/ia64 version. +- 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 +-#include +-#include +- +- +-#include "has_cpuclock.c" +-#define HAS_CPUCLOCK(name) (has_cpuclock () ? _POSIX_VERSION : -1) +- +- +-/* Now the generic Linux version. */ +-#include +diff --git a/sysdeps/unix/sysv/linux/sysconf.c b/sysdeps/unix/sysv/linux/sysconf.c +index 4e49ebaa7a25748c..6fab1601034e4724 100644 +--- a/sysdeps/unix/sysv/linux/sysconf.c ++++ b/sysdeps/unix/sysv/linux/sysconf.c +@@ -35,34 +35,6 @@ + static long int posix_sysconf (int name); + + +-#ifndef HAS_CPUCLOCK +-static long int +-has_cpuclock (int name) +-{ +-# if defined __NR_clock_getres || HP_TIMING_AVAIL +- /* If we have HP_TIMING, we will fall back on that if the system +- call does not work, so we support it either way. */ +-# if !HP_TIMING_AVAIL +- /* Check using the clock_getres system call. */ +- struct timespec ts; +- INTERNAL_SYSCALL_DECL (err); +- int r = INTERNAL_SYSCALL (clock_getres, err, 2, +- (name == _SC_CPUTIME +- ? CLOCK_PROCESS_CPUTIME_ID +- : CLOCK_THREAD_CPUTIME_ID), +- &ts); +- if (INTERNAL_SYSCALL_ERROR_P (r, err)) +- return -1; +-# endif +- return _POSIX_VERSION; +-# else +- return -1; +-# endif +-} +-# define HAS_CPUCLOCK(name) has_cpuclock (name) +-#endif +- +- + /* Get the value of the system variable NAME. */ + long int + __sysconf (int name) +@@ -71,29 +43,20 @@ __sysconf (int name) + + switch (name) + { +- struct rlimit rlimit; +-#ifdef __NR_clock_getres + case _SC_MONOTONIC_CLOCK: +- /* Check using the clock_getres system call. */ +- { +- struct timespec ts; +- INTERNAL_SYSCALL_DECL (err); +- int r; +- r = INTERNAL_SYSCALL (clock_getres, err, 2, CLOCK_MONOTONIC, &ts); +- return INTERNAL_SYSCALL_ERROR_P (r, err) ? -1 : _POSIX_VERSION; +- } +-#endif +- + case _SC_CPUTIME: + case _SC_THREAD_CPUTIME: +- return HAS_CPUCLOCK (name); ++ return _POSIX_VERSION; + + case _SC_ARG_MAX: +- /* Use getrlimit to get the stack limit. */ +- if (__getrlimit (RLIMIT_STACK, &rlimit) == 0) +- return MAX (legacy_ARG_MAX, rlimit.rlim_cur / 4); ++ { ++ struct rlimit rlimit; ++ /* Use getrlimit to get the stack limit. */ ++ if (__getrlimit (RLIMIT_STACK, &rlimit) == 0) ++ return MAX (legacy_ARG_MAX, rlimit.rlim_cur / 4); + +- return legacy_ARG_MAX; ++ return legacy_ARG_MAX; ++ } + + case _SC_NGROUPS_MAX: + /* Try to read the information from the /proc/sys/kernel/ngroups_max +@@ -102,11 +65,14 @@ __sysconf (int name) + break; + + case _SC_SIGQUEUE_MAX: +- if (__getrlimit (RLIMIT_SIGPENDING, &rlimit) == 0) +- return rlimit.rlim_cur; ++ { ++ struct rlimit rlimit; ++ if (__getrlimit (RLIMIT_SIGPENDING, &rlimit) == 0) ++ return rlimit.rlim_cur; + +- /* The /proc/sys/kernel/rtsig-max file contains the answer. */ +- procfname = "/proc/sys/kernel/rtsig-max"; ++ /* The /proc/sys/kernel/rtsig-max file contains the answer. */ ++ procfname = "/proc/sys/kernel/rtsig-max"; ++ } + break; + + default: diff --git a/SOURCES/glibc-rh1817513-23.patch b/SOURCES/glibc-rh1817513-23.patch new file mode 100644 index 0000000..91ccdfa --- /dev/null +++ b/SOURCES/glibc-rh1817513-23.patch @@ -0,0 +1,211 @@ +commit 359653aaacad463d916323f03c0ac3c47405aafa +Author: Adhemerval Zanella +Date: Wed Jan 16 18:10:56 2019 +0000 + + Do not use HP_TIMING_NOW for random bits + + This patch removes the HP_TIMING_BITS usage for fast random bits and replace + with clock_gettime (CLOCK_MONOTONIC). It has unspecified starting time and + nano-second accuracy, so its randomness is significantly better than + gettimeofday. + + Althoug it should incur in more overhead (specially for architecture that + support hp-timing), the symbol is also common implemented as a vDSO. + + Checked on aarch64-linux-gnu, x86_64-linux-gnu, and i686-linux-gnu. I also + checked on a i686-gnu build. + + * include/random-bits.h: New file. + * resolv/res_mkquery.c [HP_TIMING_AVAIL] (RANDOM_BITS, + (__res_context_mkquery): Remove usage hp-timing usage and replace with + random_bits. + * resolv/res_send.c [HP_TIMING_AVAIL] (nameserver_offset): Likewise. + * sysdeps/posix/tempname.c [HP_TIMING_AVAIL] (__gen_tempname): + Likewise. + +diff --git a/include/random-bits.h b/include/random-bits.h +new file mode 100644 +index 0000000000000000..a0651a5a34f80a8d +--- /dev/null ++++ b/include/random-bits.h +@@ -0,0 +1,41 @@ ++/* Fast pseudo-random bits based on clock_gettime. ++ 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, see ++ . */ ++ ++#ifndef _RANDOM_BITS_H ++# define _RANDOM_BITS_H ++ ++#include ++#include ++ ++/* Provides fast pseudo-random bits through clock_gettime. It has unspecified ++ starting time, nano-second accuracy, its randomness is significantly better ++ than gettimeofday, and for mostly architectures it is implemented through ++ vDSO instead of a syscall. Since the source is a system clock, the upper ++ bits will have less entropy. */ ++static inline uint32_t ++random_bits (void) ++{ ++ struct timespec tv; ++ __clock_gettime (CLOCK_MONOTONIC, &tv); ++ /* Shuffle the lower bits to minimize the clock bias. */ ++ uint32_t ret = tv.tv_nsec ^ tv.tv_sec; ++ ret ^= (ret << 24) | (ret >> 8); ++ return ret; ++} ++ ++#endif +diff --git a/resolv/res_mkquery.c b/resolv/res_mkquery.c +index 213abeefadf7ece5..4471a8838b1de7ee 100644 +--- a/resolv/res_mkquery.c ++++ b/resolv/res_mkquery.c +@@ -82,6 +82,7 @@ + * SOFTWARE. + */ + ++#include + #include + #include + #include +@@ -92,12 +93,7 @@ + #include + #include + #include +- +-#include +-#include +-#if HP_TIMING_AVAIL +-# define RANDOM_BITS(Var) { uint64_t v64; HP_TIMING_NOW (v64); Var = v64; } +-#endif ++#include + + int + __res_context_mkquery (struct resolv_context *ctx, int op, const char *dname, +@@ -120,16 +116,7 @@ __res_context_mkquery (struct resolv_context *ctx, int op, const char *dname, + /* We randomize the IDs every time. The old code just incremented + by one after the initial randomization which still predictable if + the application does multiple requests. */ +- int randombits; +-#ifdef RANDOM_BITS +- RANDOM_BITS (randombits); +-#else +- struct timeval tv; +- __gettimeofday (&tv, NULL); +- randombits = (tv.tv_sec << 8) ^ tv.tv_usec; +-#endif +- +- hp->id = randombits; ++ hp->id = random_bits (); + hp->opcode = op; + hp->rd = (ctx->resp->options & RES_RECURSE) != 0; + hp->rcode = NOERROR; +diff --git a/resolv/res_send.c b/resolv/res_send.c +index ac19627634281c2f..55e7fa438e7baac1 100644 +--- a/resolv/res_send.c ++++ b/resolv/res_send.c +@@ -109,7 +109,7 @@ + #include + #include + #include +-#include ++#include + + #if PACKETSZ > 65536 + #define MAXPACKET PACKETSZ +@@ -309,15 +309,7 @@ nameserver_offset (struct __res_state *statp) + if ((offset & 1) == 0) + { + /* Initialization is required. */ +-#if HP_TIMING_AVAIL +- uint64_t ticks; +- HP_TIMING_NOW (ticks); +- offset = ticks; +-#else +- struct timeval tv; +- __gettimeofday (&tv, NULL); +- offset = ((tv.tv_sec << 8) ^ tv.tv_usec); +-#endif ++ offset = random_bits (); + /* The lowest bit is the most random. Preserve it. */ + offset <<= 1; + +diff --git a/sysdeps/posix/tempname.c b/sysdeps/posix/tempname.c +index 432262a03b6ecc23..3d26f378021680ae 100644 +--- a/sysdeps/posix/tempname.c ++++ b/sysdeps/posix/tempname.c +@@ -71,22 +71,15 @@ + #endif + + #ifdef _LIBC +-# include +-# if HP_TIMING_AVAIL +-# define RANDOM_BITS(Var) \ +- if (__glibc_unlikely (value == UINT64_C (0))) \ +- { \ +- /* If this is the first time this function is used initialize \ +- the variable we accumulate the value in to some somewhat \ +- random value. If we'd not do this programs at startup time \ +- might have a reduced set of possible names, at least on slow \ +- machines. */ \ +- struct timeval tv; \ +- __gettimeofday (&tv, NULL); \ +- value = ((uint64_t) tv.tv_usec << 16) ^ tv.tv_sec; \ +- } \ +- HP_TIMING_NOW (Var) +-# endif ++# include ++# define RANDOM_BITS(Var) ((Var) = random_bits ()) ++# else ++# define RANDOM_BITS(Var) \ ++ { \ ++ struct timeval tv; \ ++ __gettimeofday (&tv, NULL); \ ++ (Var) = ((uint64_t) tv.tv_usec << 16) ^ tv.tv_sec; \ ++ } + #endif + + /* Use the widest available unsigned type if uint64_t is not +@@ -193,8 +186,7 @@ __gen_tempname (char *tmpl, int suffixlen, int flags, int kind) + { + int len; + char *XXXXXX; +- static uint64_t value; +- uint64_t random_time_bits; ++ uint64_t value; + unsigned int count; + int fd = -1; + int save_errno = errno; +@@ -227,16 +219,8 @@ __gen_tempname (char *tmpl, int suffixlen, int flags, int kind) + XXXXXX = &tmpl[len - 6 - suffixlen]; + + /* Get some more or less random data. */ +-#ifdef RANDOM_BITS +- RANDOM_BITS (random_time_bits); +-#else +- { +- struct timeval tv; +- __gettimeofday (&tv, NULL); +- random_time_bits = ((uint64_t) tv.tv_usec << 16) ^ tv.tv_sec; +- } +-#endif +- value += random_time_bits ^ __getpid (); ++ RANDOM_BITS (value); ++ value ^= (uint64_t)__getpid () << 32; + + for (count = 0; count < attempts; value += 7777, ++count) + { diff --git a/SOURCES/glibc-rh1817513-24.patch b/SOURCES/glibc-rh1817513-24.patch new file mode 100644 index 0000000..3347d97 --- /dev/null +++ b/SOURCES/glibc-rh1817513-24.patch @@ -0,0 +1,702 @@ +commit 1e372ded4f83362509c8672ff501cba871bb1edc +Author: Adhemerval Zanella +Date: Thu Jan 24 12:46:59 2019 +0000 + + Refactor hp-timing rtld usage + + This patch refactor how hp-timing is used on loader code for statistics + report. The HP_TIMING_AVAIL and HP_SMALL_TIMING_AVAIL are removed and + HP_TIMING_INLINE is used instead to check for hp-timing avaliability. + For alpha, which only defines HP_SMALL_TIMING_AVAIL, the HP_TIMING_INLINE + is set iff for IS_IN(rtld). + + Checked on aarch64-linux-gnu, x86_64-linux-gnu, and i686-linux-gnu. I also + checked the builds for all afected ABIs. + + * benchtests/bench-timing.h: Replace HP_TIMING_AVAIL with + HP_TIMING_INLINE. + * nptl/descr.h: Likewise. + * elf/rtld.c (RLTD_TIMING_DECLARE, RTLD_TIMING_NOW, RTLD_TIMING_DIFF, + RTLD_TIMING_ACCUM_NT, RTLD_TIMING_SET): Define. + (dl_start_final_info, _dl_start_final, dl_main, print_statistics): + Abstract hp-timing usage with RTLD_* macros. + * sysdeps/alpha/hp-timing.h (HP_TIMING_INLINE): Define iff IS_IN(rtld). + (HP_TIMING_AVAIL, HP_SMALL_TIMING_AVAIL): Remove. + * sysdeps/generic/hp-timing.h (HP_TIMING_AVAIL, HP_SMALL_TIMING_AVAIL, + HP_TIMING_NONAVAIL): Likewise. + * sysdeps/ia64/hp-timing.h (HP_TIMING_AVAIL, HP_SMALL_TIMING_AVAIL): + Likewise. + * sysdeps/powerpc/powerpc32/power4/hp-timing.h (HP_TIMING_AVAIL, + HP_SMALL_TIMING_AVAIL): Likewise. + * sysdeps/powerpc/powerpc64/hp-timing.h (HP_TIMING_AVAIL, + HP_SMALL_TIMING_AVAIL): Likewise. + * sysdeps/sparc/sparc32/sparcv9/hp-timing.h (HP_TIMING_AVAIL, + HP_SMALL_TIMING_AVAIL): Likewise. + * sysdeps/sparc/sparc64/hp-timing.h (HP_TIMING_AVAIL, + HP_SMALL_TIMING_AVAIL): Likewise. + * sysdeps/x86/hp-timing.h (HP_TIMING_AVAIL, HP_SMALL_TIMING_AVAIL): + Likewise. + * sysdeps/generic/hp-timing-common.h: Update comment with + HP_TIMING_AVAIL removal. + +diff --git a/benchtests/bench-timing.h b/benchtests/bench-timing.h +index 96cde1e8be2e0c2f..8ba6be51d5b6d4e1 100644 +--- a/benchtests/bench-timing.h ++++ b/benchtests/bench-timing.h +@@ -21,7 +21,7 @@ + #include + #include + +-#if HP_TIMING_AVAIL && !defined USE_CLOCK_GETTIME ++#if HP_TIMING_INLINE && !defined USE_CLOCK_GETTIME + # define GL(x) _##x + # define GLRO(x) _##x + typedef hp_timing_t timing_t; +diff --git a/elf/rtld.c b/elf/rtld.c +index 375e0de8fa2e049e..ffbd8f4553bb3425 100644 +--- a/elf/rtld.c ++++ b/elf/rtld.c +@@ -46,6 +46,49 @@ + + #include + ++/* Only enables rtld profiling for architectures which provides non generic ++ hp-timing support. The generic support requires either syscall ++ (clock_gettime), which will incur in extra overhead on loading time. ++ Using vDSO is also an option, but it will require extra support on loader ++ to setup the vDSO pointer before its usage. */ ++#if HP_TIMING_INLINE ++# define RLTD_TIMING_DECLARE(var, classifier,...) \ ++ classifier hp_timing_t var __VA_ARGS__ ++# define RTLD_TIMING_VAR(var) RLTD_TIMING_DECLARE (var, ) ++# define RTLD_TIMING_SET(var, value) (var) = (value) ++# define RTLD_TIMING_REF(var) &(var) ++ ++static inline void ++rtld_timer_start (hp_timing_t *var) ++{ ++ HP_TIMING_NOW (*var); ++} ++ ++static inline void ++rtld_timer_stop (hp_timing_t *var, hp_timing_t start) ++{ ++ hp_timing_t stop; ++ HP_TIMING_NOW (stop); ++ HP_TIMING_DIFF (*var, start, stop); ++} ++ ++static inline void ++rtld_timer_accum (hp_timing_t *sum, hp_timing_t start) ++{ ++ hp_timing_t stop; ++ rtld_timer_stop (&stop, start); ++ HP_TIMING_ACCUM_NT(*sum, stop); ++} ++#else ++# define RLTD_TIMING_DECLARE(var, classifier...) ++# define RTLD_TIMING_SET(var, value) ++# define RTLD_TIMING_VAR(var) ++# define RTLD_TIMING_REF(var) 0 ++# define rtld_timer_start(var) ++# define rtld_timer_stop(var, start) ++# define rtld_timer_accum(sum, start) ++#endif ++ + /* Avoid PLT use for our local calls at startup. */ + extern __typeof (__mempcpy) __mempcpy attribute_hidden; + +@@ -62,7 +105,7 @@ static void print_missing_version (int errcode, const char *objname, + const char *errsting); + + /* Print the various times we collected. */ +-static void print_statistics (hp_timing_t *total_timep); ++static void print_statistics (const hp_timing_t *total_timep); + + /* Add audit objects. */ + static void process_dl_audit (char *str); +@@ -303,11 +346,9 @@ static struct libname_list _dl_rtld_libname; + static struct libname_list _dl_rtld_libname2; + + /* Variable for statistics. */ +-#ifndef HP_TIMING_NONAVAIL +-static hp_timing_t relocate_time; +-static hp_timing_t load_time attribute_relro; +-static hp_timing_t start_time attribute_relro; +-#endif ++RLTD_TIMING_DECLARE (relocate_time, static); ++RLTD_TIMING_DECLARE (load_time, static, attribute_relro); ++RLTD_TIMING_DECLARE (start_time, static, attribute_relro); + + /* Additional definitions needed by TLS initialization. */ + #ifdef TLS_INIT_HELPER +@@ -335,9 +376,7 @@ static ElfW(Addr) _dl_start_final (void *arg); + struct dl_start_final_info + { + struct link_map l; +-#if !defined HP_TIMING_NONAVAIL && HP_TIMING_INLINE +- hp_timing_t start_time; +-#endif ++ RTLD_TIMING_VAR (start_time); + }; + static ElfW(Addr) _dl_start_final (void *arg, + struct dl_start_final_info *info); +@@ -371,16 +410,11 @@ _dl_start_final (void *arg, struct dl_start_final_info *info) + { + ElfW(Addr) start_addr; + +- if (HP_SMALL_TIMING_AVAIL) +- { +- /* If it hasn't happen yet record the startup time. */ +- if (! HP_TIMING_INLINE) +- HP_TIMING_NOW (start_time); +-#if !defined DONT_USE_BOOTSTRAP_MAP && !defined HP_TIMING_NONAVAIL +- else +- start_time = info->start_time; ++ /* If it hasn't happen yet record the startup time. */ ++ rtld_timer_start (&start_time); ++#if !defined DONT_USE_BOOTSTRAP_MAP ++ RTLD_TIMING_SET (start_time, info->start_time); + #endif +- } + + /* Transfer data about ourselves to the permanent link_map structure. */ + #ifndef DONT_USE_BOOTSTRAP_MAP +@@ -412,27 +446,11 @@ _dl_start_final (void *arg, struct dl_start_final_info *info) + entry point on the same stack we entered on. */ + start_addr = _dl_sysdep_start (arg, &dl_main); + +-#ifndef HP_TIMING_NONAVAIL +- hp_timing_t rtld_total_time; +- if (HP_SMALL_TIMING_AVAIL) +- { +- hp_timing_t end_time; +- +- /* Get the current time. */ +- HP_TIMING_NOW (end_time); +- +- /* Compute the difference. */ +- HP_TIMING_DIFF (rtld_total_time, start_time, end_time); +- } +-#endif +- + if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_STATISTICS)) + { +-#ifndef HP_TIMING_NONAVAIL +- print_statistics (&rtld_total_time); +-#else +- print_statistics (NULL); +-#endif ++ RTLD_TIMING_VAR (rtld_total_time); ++ rtld_timer_stop (&rtld_total_time, start_time); ++ print_statistics (RTLD_TIMING_REF(rtld_total_time)); + } + + return start_addr; +@@ -457,11 +475,10 @@ _dl_start (void *arg) + #define RESOLVE_MAP(sym, version, flags) BOOTSTRAP_MAP + #include "dynamic-link.h" + +- if (HP_TIMING_INLINE && HP_SMALL_TIMING_AVAIL) + #ifdef DONT_USE_BOOTSTRAP_MAP +- HP_TIMING_NOW (start_time); ++ rtld_timer_start (&start_time); + #else +- HP_TIMING_NOW (info.start_time); ++ rtld_timer_start (&info.start_time); + #endif + + /* Partly clean the `bootstrap_map' structure up. Don't use +@@ -1078,11 +1095,6 @@ dl_main (const ElfW(Phdr) *phdr, + unsigned int i; + bool prelinked = false; + bool rtld_is_main = false; +-#ifndef HP_TIMING_NONAVAIL +- hp_timing_t start; +- hp_timing_t stop; +- hp_timing_t diff; +-#endif + void *tcbp = NULL; + + GL(dl_init_static_tls) = &_dl_nothread_init_static_tls; +@@ -1256,12 +1268,11 @@ of this helper program; chances are you did not intend to run this program.\n\ + } + else + { +- HP_TIMING_NOW (start); ++ RTLD_TIMING_VAR (start); ++ rtld_timer_start (&start); + _dl_map_object (NULL, rtld_progname, lt_executable, 0, + __RTLD_OPENEXEC, LM_ID_BASE); +- HP_TIMING_NOW (stop); +- +- HP_TIMING_DIFF (load_time, start, stop); ++ rtld_timer_stop (&load_time, start); + } + + /* Now the map for the main executable is available. */ +@@ -1664,20 +1675,18 @@ ERROR: '%s': cannot process note segment.\n", _dl_argv[0]); + + if (__glibc_unlikely (preloadlist != NULL)) + { +- HP_TIMING_NOW (start); ++ RTLD_TIMING_VAR (start); ++ rtld_timer_start (&start); + npreloads += handle_preload_list (preloadlist, main_map, "LD_PRELOAD"); +- HP_TIMING_NOW (stop); +- HP_TIMING_DIFF (diff, start, stop); +- HP_TIMING_ACCUM_NT (load_time, diff); ++ rtld_timer_accum (&load_time, start); + } + + if (__glibc_unlikely (preloadarg != NULL)) + { +- HP_TIMING_NOW (start); ++ RTLD_TIMING_VAR (start); ++ rtld_timer_start (&start); + npreloads += handle_preload_list (preloadarg, main_map, "--preload"); +- HP_TIMING_NOW (stop); +- HP_TIMING_DIFF (diff, start, stop); +- HP_TIMING_ACCUM_NT (load_time, diff); ++ rtld_timer_accum (&load_time, start); + } + + /* There usually is no ld.so.preload file, it should only be used +@@ -1737,7 +1746,8 @@ ERROR: '%s': cannot process note segment.\n", _dl_argv[0]); + file[file_size - 1] = '\0'; + } + +- HP_TIMING_NOW (start); ++ RTLD_TIMING_VAR (start); ++ rtld_timer_start (&start); + + if (file != problem) + { +@@ -1755,9 +1765,7 @@ ERROR: '%s': cannot process note segment.\n", _dl_argv[0]); + npreloads += do_preload (p, main_map, preload_file); + } + +- HP_TIMING_NOW (stop); +- HP_TIMING_DIFF (diff, start, stop); +- HP_TIMING_ACCUM_NT (load_time, diff); ++ rtld_timer_accum (&load_time, start); + + /* We don't need the file anymore. */ + __munmap (file, file_size); +@@ -1781,11 +1789,12 @@ ERROR: '%s': cannot process note segment.\n", _dl_argv[0]); + /* 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. */ +- HP_TIMING_NOW (start); +- _dl_map_object_deps (main_map, preloads, npreloads, mode == trace, 0); +- HP_TIMING_NOW (stop); +- HP_TIMING_DIFF (diff, start, stop); +- HP_TIMING_ACCUM_NT (load_time, diff); ++ { ++ RTLD_TIMING_VAR (start); ++ rtld_timer_start (&start); ++ _dl_map_object_deps (main_map, preloads, npreloads, mode == trace, 0); ++ rtld_timer_accum (&load_time, start); ++ } + + /* Mark all objects as being in the global scope. */ + for (i = main_map->l_searchlist.r_nlist; i > 0; ) +@@ -2178,12 +2187,10 @@ ERROR: '%s': cannot process note segment.\n", _dl_argv[0]); + if (main_map->l_info [ADDRIDX (DT_GNU_CONFLICT)] != NULL) + { + ElfW(Rela) *conflict, *conflictend; +-#ifndef HP_TIMING_NONAVAIL +- hp_timing_t start; +- hp_timing_t stop; +-#endif + +- HP_TIMING_NOW (start); ++ RTLD_TIMING_VAR (start); ++ rtld_timer_start (&start); ++ + assert (main_map->l_info [VALIDX (DT_GNU_CONFLICTSZ)] != NULL); + conflict = (ElfW(Rela) *) + main_map->l_info [ADDRIDX (DT_GNU_CONFLICT)]->d_un.d_ptr; +@@ -2191,8 +2198,8 @@ ERROR: '%s': cannot process note segment.\n", _dl_argv[0]); + ((char *) conflict + + main_map->l_info [VALIDX (DT_GNU_CONFLICTSZ)]->d_un.d_val); + _dl_resolve_conflicts (main_map, conflict, conflictend); +- HP_TIMING_NOW (stop); +- HP_TIMING_DIFF (relocate_time, start, stop); ++ ++ rtld_timer_stop (&relocate_time, start); + } + + +@@ -2220,15 +2227,12 @@ ERROR: '%s': cannot process note segment.\n", _dl_argv[0]); + know that because it is self-contained). */ + + int consider_profiling = GLRO(dl_profile) != NULL; +-#ifndef HP_TIMING_NONAVAIL +- hp_timing_t start; +- hp_timing_t stop; +-#endif + + /* If we are profiling we also must do lazy reloaction. */ + GLRO(dl_lazy) |= consider_profiling; + +- HP_TIMING_NOW (start); ++ RTLD_TIMING_VAR (start); ++ rtld_timer_start (&start); + unsigned i = main_map->l_searchlist.r_nlist; + while (i-- > 0) + { +@@ -2255,9 +2259,7 @@ ERROR: '%s': cannot process note segment.\n", _dl_argv[0]); + if (l->l_tls_blocksize != 0 && tls_init_tp_called) + _dl_add_to_slotinfo (l, true); + } +- HP_TIMING_NOW (stop); +- +- HP_TIMING_DIFF (relocate_time, start, stop); ++ rtld_timer_stop (&relocate_time, start); + + /* Now enable profiling if needed. Like the previous call, + this has to go here because the calls it makes should use the +@@ -2300,19 +2302,14 @@ ERROR: '%s': cannot process note segment.\n", _dl_argv[0]); + re-relocation, we might call a user-supplied function + (e.g. calloc from _dl_relocate_object) that uses TLS data. */ + +-#ifndef HP_TIMING_NONAVAIL +- hp_timing_t start; +- hp_timing_t stop; +- hp_timing_t add; +-#endif ++ RTLD_TIMING_VAR (start); ++ rtld_timer_start (&start); + +- HP_TIMING_NOW (start); + /* Mark the link map as not yet relocated again. */ + GL(dl_rtld_map).l_relocated = 0; + _dl_relocate_object (&GL(dl_rtld_map), main_map->l_scope, 0, 0); +- HP_TIMING_NOW (stop); +- HP_TIMING_DIFF (add, start, stop); +- HP_TIMING_ACCUM_NT (relocate_time, add); ++ ++ rtld_timer_accum (&relocate_time, start); + } + + /* Do any necessary cleanups for the startup OS interface code. +@@ -2744,46 +2741,51 @@ process_envvars (enum mode *modep) + } + } + ++#if HP_TIMING_INLINE ++static void ++print_statistics_item (const char *title, hp_timing_t time, ++ hp_timing_t total) ++{ ++ char cycles[HP_TIMING_PRINT_SIZE]; ++ HP_TIMING_PRINT (cycles, sizeof (cycles), time); ++ ++ char relative[3 * sizeof (hp_timing_t) + 2]; ++ char *cp = _itoa ((1000ULL * time) / total, relative + sizeof (relative), ++ 10, 0); ++ /* Sets the decimal point. */ ++ char *wp = relative; ++ switch (relative + sizeof (relative) - cp) ++ { ++ case 3: ++ *wp++ = *cp++; ++ /* Fall through. */ ++ case 2: ++ *wp++ = *cp++; ++ /* Fall through. */ ++ case 1: ++ *wp++ = '.'; ++ *wp++ = *cp++; ++ } ++ *wp = '\0'; ++ _dl_debug_printf ("%s: %s cycles (%s%%)\n", title, cycles, relative); ++} ++#endif + + /* Print the various times we collected. */ + static void + __attribute ((noinline)) +-print_statistics (hp_timing_t *rtld_total_timep) ++print_statistics (const hp_timing_t *rtld_total_timep) + { +-#ifndef HP_TIMING_NONAVAIL +- char buf[200]; +- char *cp; +- char *wp; +- +- /* Total time rtld used. */ +- if (HP_SMALL_TIMING_AVAIL) +- { +- HP_TIMING_PRINT (buf, sizeof (buf), *rtld_total_timep); +- _dl_debug_printf ("\nruntime linker statistics:\n" +- " total startup time in dynamic loader: %s\n", buf); +- +- /* Print relocation statistics. */ +- char pbuf[30]; +- HP_TIMING_PRINT (buf, sizeof (buf), relocate_time); +- cp = _itoa ((1000ULL * relocate_time) / *rtld_total_timep, +- pbuf + sizeof (pbuf), 10, 0); +- wp = pbuf; +- switch (pbuf + sizeof (pbuf) - cp) +- { +- case 3: +- *wp++ = *cp++; +- /* Fall through. */ +- case 2: +- *wp++ = *cp++; +- /* Fall through. */ +- case 1: +- *wp++ = '.'; +- *wp++ = *cp++; +- } +- *wp = '\0'; +- _dl_debug_printf ("\ +- time needed for relocation: %s (%s%%)\n", buf, pbuf); +- } ++#if HP_TIMING_INLINE ++ { ++ char cycles[HP_TIMING_PRINT_SIZE]; ++ HP_TIMING_PRINT (cycles, sizeof (cycles), *rtld_total_timep); ++ _dl_debug_printf ("\nruntime linker statistics:\n" ++ " total startup time in dynamic loader: %s cycles\n", ++ cycles); ++ print_statistics_item (" time needed for relocation", ++ relocate_time, *rtld_total_timep); ++ } + #endif + + unsigned long int num_relative_relocations = 0; +@@ -2824,31 +2826,8 @@ print_statistics (hp_timing_t *rtld_total_timep) + GL(dl_num_cache_relocations), + num_relative_relocations); + +-#ifndef HP_TIMING_NONAVAIL +- /* Time spend while loading the object and the dependencies. */ +- if (HP_SMALL_TIMING_AVAIL) +- { +- char pbuf[30]; +- HP_TIMING_PRINT (buf, sizeof (buf), load_time); +- cp = _itoa ((1000ULL * load_time) / *rtld_total_timep, +- pbuf + sizeof (pbuf), 10, 0); +- wp = pbuf; +- switch (pbuf + sizeof (pbuf) - cp) +- { +- case 3: +- *wp++ = *cp++; +- /* Fall through. */ +- case 2: +- *wp++ = *cp++; +- /* Fall through. */ +- case 1: +- *wp++ = '.'; +- *wp++ = *cp++; +- } +- *wp = '\0'; +- _dl_debug_printf ("\ +- time needed to load objects: %s (%s%%)\n", +- buf, pbuf); +- } ++#if HP_TIMING_INLINE ++ print_statistics_item (" time needed to load objects", ++ load_time, *rtld_total_timep); + #endif + } +diff --git a/nptl/descr.h b/nptl/descr.h +index c3b81d8b27839502..98ba730bfeb7e4dd 100644 +--- a/nptl/descr.h ++++ b/nptl/descr.h +@@ -342,7 +342,7 @@ struct pthread + /* Lock for synchronizing setxid calls. */ + unsigned int setxid_futex; + +-#if HP_TIMING_AVAIL ++#if HP_TIMING_INLINE + hp_timing_t cpuclock_offset_ununsed; + #endif + +diff --git a/sysdeps/alpha/hp-timing.h b/sysdeps/alpha/hp-timing.h +index 62284e003acbca64..d6b603e2c51d1688 100644 +--- a/sysdeps/alpha/hp-timing.h ++++ b/sysdeps/alpha/hp-timing.h +@@ -17,16 +17,13 @@ + License along with the GNU C Library. If not, see + . */ + +-#ifndef _HP_TIMING_H +-#define _HP_TIMING_H 1 ++#ifndef _HP_TIMING_ALPHA_H ++#define _HP_TIMING_ALPHA_H 1 + ++#if IS_IN(rtld) + /* We always have the timestamp register, but it's got only a 4 second + range. Use it for ld.so profiling only. */ +-#define HP_TIMING_AVAIL (0) +-#define HP_SMALL_TIMING_AVAIL (1) +- +-/* We indeed have inlined functions. */ +-#define HP_TIMING_INLINE (1) ++# define HP_TIMING_INLINE (1) + + /* We use 32 bit values for the times. */ + typedef unsigned int hp_timing_t; +@@ -34,13 +31,16 @@ typedef unsigned int hp_timing_t; + /* The "rpcc" instruction returns a 32-bit counting half and a 32-bit + "virtual cycle counter displacement". Subtracting the two gives us + a virtual cycle count. */ +-#define HP_TIMING_NOW(VAR) \ ++# define HP_TIMING_NOW(VAR) \ + do { \ + unsigned long int x_; \ + asm volatile ("rpcc %0" : "=r"(x_)); \ + (VAR) = (int) (x_) - (int) (x_ >> 32); \ + } while (0) ++# include + +-#include ++#else ++# include ++#endif /* IS_IN(rtld) */ + + #endif /* hp-timing.h */ +diff --git a/sysdeps/generic/hp-timing-common.h b/sysdeps/generic/hp-timing-common.h +index 505c6bf5d2ee9395..ce338c990bd9fccd 100644 +--- a/sysdeps/generic/hp-timing-common.h ++++ b/sysdeps/generic/hp-timing-common.h +@@ -20,8 +20,6 @@ + /* In case a platform supports timers in the hardware the following macros + and types must be defined: + +- - HP_TIMING_AVAIL: test for availability. +- + - HP_TIMING_INLINE: this macro is non-zero if the functionality is not + implemented using function calls but instead uses some inlined code + which might simply consist of a few assembler instructions. We have to +@@ -47,16 +45,16 @@ + /* Accumulate ADD into SUM. No attempt is made to be thread-safe. */ + #define HP_TIMING_ACCUM_NT(Sum, Diff) ((Sum) += (Diff)) + ++#define HP_TIMING_PRINT_SIZE (3 * sizeof (hp_timing_t) + 1) ++ + /* Write a decimal representation of the timing value into the given string. */ + #define HP_TIMING_PRINT(Dest, Len, Val) \ + do { \ +- char __buf[20]; \ ++ char __buf[HP_TIMING_PRINT_SIZE]; \ + char *__dest = (Dest); \ + size_t __len = (Len); \ + char *__cp = _itoa ((Val), __buf + sizeof (__buf), 10, 0); \ + size_t __cp_len = MIN (__buf + sizeof (__buf) - __cp, __len); \ + memcpy (__dest, __cp, __cp_len); \ +- memcpy (__dest + __cp_len, " cycles", \ +- MIN (__len - __cp_len, sizeof (" cycles"))); \ + __dest[__len - 1] = '\0'; \ + } while (0) +diff --git a/sysdeps/generic/hp-timing.h b/sysdeps/generic/hp-timing.h +index e2c02c2bc0fd1564..97598099db29d69d 100644 +--- a/sysdeps/generic/hp-timing.h ++++ b/sysdeps/generic/hp-timing.h +@@ -25,8 +25,6 @@ + the system call might be too high. */ + + /* Provide dummy definitions. */ +-#define HP_TIMING_AVAIL (0) +-#define HP_SMALL_TIMING_AVAIL (0) + #define HP_TIMING_INLINE (0) + typedef int hp_timing_t; + #define HP_TIMING_NOW(var) +@@ -34,7 +32,4 @@ typedef int hp_timing_t; + #define HP_TIMING_ACCUM_NT(Sum, Diff) + #define HP_TIMING_PRINT(Buf, Len, Val) + +-/* Since this implementation is not available we tell the user about it. */ +-#define HP_TIMING_NONAVAIL 1 +- + #endif /* hp-timing.h */ +diff --git a/sysdeps/ia64/hp-timing.h b/sysdeps/ia64/hp-timing.h +index d8d1d7bf2c21f6e6..5ebbbc45746d5cf2 100644 +--- a/sysdeps/ia64/hp-timing.h ++++ b/sysdeps/ia64/hp-timing.h +@@ -20,10 +20,6 @@ + #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) + +diff --git a/sysdeps/powerpc/powerpc32/power4/hp-timing.h b/sysdeps/powerpc/powerpc32/power4/hp-timing.h +index 10efcac481349ee3..0e81f4fe6a46ab86 100644 +--- a/sysdeps/powerpc/powerpc32/power4/hp-timing.h ++++ b/sysdeps/powerpc/powerpc32/power4/hp-timing.h +@@ -20,10 +20,6 @@ + #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) + +diff --git a/sysdeps/powerpc/powerpc64/hp-timing.h b/sysdeps/powerpc/powerpc64/hp-timing.h +index c0aa3642f6ff1a42..77fe5e85bb32c163 100644 +--- a/sysdeps/powerpc/powerpc64/hp-timing.h ++++ b/sysdeps/powerpc/powerpc64/hp-timing.h +@@ -20,10 +20,6 @@ + #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) + +diff --git a/sysdeps/sparc/sparc32/sparcv9/hp-timing.h b/sysdeps/sparc/sparc32/sparcv9/hp-timing.h +index 42451966f6192bcb..aedf9c031a0daad9 100644 +--- a/sysdeps/sparc/sparc32/sparcv9/hp-timing.h ++++ b/sysdeps/sparc/sparc32/sparcv9/hp-timing.h +@@ -20,8 +20,6 @@ + #ifndef _HP_TIMING_H + #define _HP_TIMING_H 1 + +-#define HP_TIMING_AVAIL (1) +-#define HP_SMALL_TIMING_AVAIL (1) + #define HP_TIMING_INLINE (1) + + typedef unsigned long long int hp_timing_t; +diff --git a/sysdeps/sparc/sparc64/hp-timing.h b/sysdeps/sparc/sparc64/hp-timing.h +index 66325641067e1198..ee22729063745944 100644 +--- a/sysdeps/sparc/sparc64/hp-timing.h ++++ b/sysdeps/sparc/sparc64/hp-timing.h +@@ -20,8 +20,6 @@ + #ifndef _HP_TIMING_H + #define _HP_TIMING_H 1 + +-#define HP_TIMING_AVAIL (1) +-#define HP_SMALL_TIMING_AVAIL (1) + #define HP_TIMING_INLINE (1) + + typedef unsigned long int hp_timing_t; +diff --git a/sysdeps/x86/hp-timing.h b/sysdeps/x86/hp-timing.h +index 0aa6f5e3f83e0d34..4dbd2aa8af69f95e 100644 +--- a/sysdeps/x86/hp-timing.h ++++ b/sysdeps/x86/hp-timing.h +@@ -22,10 +22,6 @@ + #include + + #if MINIMUM_ISA == 686 || MINIMUM_ISA == 8664 +-/* 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) + diff --git a/SOURCES/glibc-rh1817513-25.patch b/SOURCES/glibc-rh1817513-25.patch new file mode 100644 index 0000000..91c0bf1 --- /dev/null +++ b/SOURCES/glibc-rh1817513-25.patch @@ -0,0 +1,113 @@ +commit b2af6fb2ed23930c148bae382ca85fad4d1cf32e +Author: Adhemerval Zanella +Date: Tue Apr 30 16:11:57 2019 -0300 + + elf: Fix elf/tst-pldd with --enable-hardcoded-path-in-tests (BZ#24506) + + The elf/tst-pldd (added by 1a4c27355e146 to fix BZ#18035) test does + not expect the hardcoded paths that are output by pldd when the test + is built with --enable-hardcoded-path-in-tests. Instead of showing + the ABI installed library names for loader and libc (such as + ld-linux-x86-64.so.2 and libc.so.6 for x86_64), pldd shows the default + built ld.so and libc.so. + + It makes the tests fail with an invalid expected loader/libc name. + + This patch fixes the elf-pldd test by adding the canonical ld.so and + libc.so names in the expected list of possible outputs when parsing + the result output from pldd. The test now handles both default + build and --enable-hardcoded-path-in-tests option. + + Checked on x86_64-linux-gnu (built with and without + --enable-hardcoded-path-in-tests) and i686-linux-gnu. + + * elf/tst-pldd.c (in_str_list): New function. + (do_test): Add default names for ld and libc as one option. + + Reviewed-by: Carlos O'Donell + +Conflicts: + elf/tst-pldd.c + (Original backport uses spaces instead of tabs.) + +diff --git a/elf/tst-pldd.c b/elf/tst-pldd.c +index 0f51c95935ffb2cf..40abee9efb9e7484 100644 +--- a/elf/tst-pldd.c ++++ b/elf/tst-pldd.c +@@ -20,7 +20,6 @@ + #include + #include + #include +-#include + #include + + #include +@@ -39,6 +38,15 @@ target_process (void *arg) + /* The test runs in a container because pldd does not support tracing + a binary started by the loader iself (as with testrun.sh). */ + ++static bool ++in_str_list (const char *libname, const char *const strlist[]) ++{ ++ for (const char *const *str = strlist; *str != NULL; str++) ++ if (strcmp (libname, *str) == 0) ++ return true; ++ return false; ++} ++ + static int + do_test (void) + { +@@ -82,26 +90,32 @@ do_test (void) + { + /* Ignore vDSO. */ + if (buffer[0] != '/') +- continue; +- +- /* Remove newline so baseline (buffer) can compare against the +- LD_SO and LIBC_SO macros unmodified. */ +- if (buffer[strlen(buffer)-1] == '\n') +- buffer[strlen(buffer)-1] = '\0'; +- +- if (strcmp (basename (buffer), LD_SO) == 0) +- { +- TEST_COMPARE (interpreter_found, false); +- interpreter_found = true; +- continue; +- } +- +- if (strcmp (basename (buffer), LIBC_SO) == 0) +- { +- TEST_COMPARE (libc_found, false); +- libc_found = true; +- continue; +- } ++ continue; ++ ++ /* Remove newline so baseline (buffer) can compare against the ++ LD_SO and LIBC_SO macros unmodified. */ ++ if (buffer[strlen(buffer)-1] == '\n') ++ buffer[strlen(buffer)-1] = '\0'; ++ ++ const char *libname = basename (buffer); ++ ++ /* It checks for default names in case of build configure with ++ --enable-hardcoded-path-in-tests (BZ #24506). */ ++ if (in_str_list (libname, ++ (const char *const []) { "ld.so", LD_SO, NULL })) ++ { ++ TEST_COMPARE (interpreter_found, false); ++ interpreter_found = true; ++ continue; ++ } ++ ++ if (in_str_list (libname, ++ (const char *const []) { "libc.so", LIBC_SO, NULL })) ++ { ++ TEST_COMPARE (libc_found, false); ++ libc_found = true; ++ continue; ++ } + } + TEST_COMPARE (interpreter_found, true); + TEST_COMPARE (libc_found, true); diff --git a/SOURCES/glibc-rh1817513-26.patch b/SOURCES/glibc-rh1817513-26.patch new file mode 100644 index 0000000..ff53662 --- /dev/null +++ b/SOURCES/glibc-rh1817513-26.patch @@ -0,0 +1,54 @@ +commit da2b83ef6ba6f4c974664f69e715cc85b9173938 +Author: Adhemerval Zanella +Date: Mon May 13 13:13:46 2019 -0300 + + elf: Fix tst-pldd for non-default --prefix and/or --bindir (BZ#24544) + + Use a new libsupport support_bindir_prefix instead of a hardcoded + /usr/bin to create the pldd path on container directory. + + Checked on x86_64-linux-gnu with default and non-default --prefix and + --bindir paths, as well with --enable-hardcoded-path-in-tests. + + [BZ #24544] + * elf/tst-pldd.c (do_test): Use support_bindir_prefix instead of + pre-defined value. + + Reviewed-by: DJ Delorie + +diff --git a/elf/tst-pldd.c b/elf/tst-pldd.c +index 40abee9efb9e7484..e2de31282a131166 100644 +--- a/elf/tst-pldd.c ++++ b/elf/tst-pldd.c +@@ -18,6 +18,7 @@ + + #include + #include ++#include + #include + #include + #include +@@ -28,6 +29,7 @@ + #include + #include + #include ++#include + + static void + target_process (void *arg) +@@ -60,12 +62,14 @@ do_test (void) + char pid[3 * sizeof (uint32_t) + 1]; + snprintf (pid, array_length (pid), "%d", target.pid); + +- const char prog[] = "/usr/bin/pldd"; ++ char *prog = xasprintf ("%s/pldd", support_bindir_prefix); + + pldd = support_capture_subprogram (prog, + (char *const []) { (char *) prog, pid, NULL }); + + support_capture_subprocess_check (&pldd, "pldd", 0, sc_allow_stdout); ++ ++ free (prog); + } + + /* Check 'pldd' output. The test is expected to be linked against only diff --git a/SOURCES/glibc-rh1817513-27.patch b/SOURCES/glibc-rh1817513-27.patch new file mode 100644 index 0000000..48e5930 --- /dev/null +++ b/SOURCES/glibc-rh1817513-27.patch @@ -0,0 +1,49 @@ +commit 75c51570c710aa9c6df6b7a1e131392e1408c63f +Author: Florian Weimer +Date: Mon May 20 21:08:40 2019 +0200 + + support: Expose sbindir as support_sbindir_prefix + +diff --git a/support/Makefile b/support/Makefile +index 6afaa6836c944398..65b16299573af1ed 100644 +--- a/support/Makefile ++++ b/support/Makefile +@@ -178,6 +178,7 @@ CFLAGS-support_paths.c = \ + -DINSTDIR_PATH=\"$(prefix)\" \ + -DLIBDIR_PATH=\"$(libdir)\" \ + -DBINDIR_PATH=\"$(bindir)\" \ ++ -DSBINDIR_PATH=\"$(sbindir)\" \ + -DROOTSBINDIR_PATH=\"$(rootsbindir)\" + + ifeq (,$(CXX)) +diff --git a/support/support.h b/support/support.h +index 97d142e9b6f68188..121cc9e9b7c98ca6 100644 +--- a/support/support.h ++++ b/support/support.h +@@ -109,6 +109,8 @@ extern const char support_libdir_prefix[]; + /* Corresponds to the install's bin/ directory. */ + extern const char support_bindir_prefix[]; + /* Corresponds to the install's sbin/ directory. */ ++extern const char support_sbindir_prefix[]; ++/* Corresponds to the install's sbin/ directory (without prefix). */ + extern const char support_install_rootsbindir[]; + + extern ssize_t support_copy_file_range (int, off64_t *, int, off64_t *, +diff --git a/support/support_paths.c b/support/support_paths.c +index a37a0720dc7339f0..eb2390227433aa70 100644 +--- a/support/support_paths.c ++++ b/support/support_paths.c +@@ -65,6 +65,13 @@ const char support_bindir_prefix[] = BINDIR_PATH; + # error please -DBINDIR_PATH=something in the Makefile + #endif + ++#ifdef SBINDIR_PATH ++/* Corresponds to the install's bin/ directory. */ ++const char support_sbindir_prefix[] = SBINDIR_PATH; ++#else ++# error please -DSBINDIR_PATH=something in the Makefile ++#endif ++ + #ifdef ROOTSBINDIR_PATH + /* Corresponds to the install's sbin/ directory. */ + const char support_install_rootsbindir[] = ROOTSBINDIR_PATH; diff --git a/SOURCES/glibc-rh1817513-28.patch b/SOURCES/glibc-rh1817513-28.patch new file mode 100644 index 0000000..c52ed81 --- /dev/null +++ b/SOURCES/glibc-rh1817513-28.patch @@ -0,0 +1,58 @@ +commit d039da1c00e01f8d3c3d74f439a971eb73e3045e +Author: H.J. Lu +Date: Wed Jun 26 15:07:18 2019 -0700 + + x86: Add sysdeps/x86/dl-lookupcfg.h + + Since sysdeps/i386/dl-lookupcfg.h and sysdeps/x86_64/dl-lookupcfg.h are + identical, we can replace them with sysdeps/x86/dl-lookupcfg.h. + + * sysdeps/i386/dl-lookupcfg.h: Moved to ... + * sysdeps/x86/dl-lookupcfg.h: Here. + * sysdeps/x86_64/dl-lookupcfg.h: Removed. + +Conflicts: + sysdeps/x86_64/dl-lookupcfg.h + (Removal after copyright year update.) + +diff --git a/sysdeps/i386/dl-lookupcfg.h b/sysdeps/x86/dl-lookupcfg.h +similarity index 100% +rename from sysdeps/i386/dl-lookupcfg.h +rename to sysdeps/x86/dl-lookupcfg.h +diff --git a/sysdeps/x86_64/dl-lookupcfg.h b/sysdeps/x86_64/dl-lookupcfg.h +deleted file mode 100644 +index 5399cf25abde592d..0000000000000000 +--- a/sysdeps/x86_64/dl-lookupcfg.h ++++ /dev/null +@@ -1,31 +0,0 @@ +-/* Configuration of lookup functions. +- 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 +- . */ +- +-#define DL_UNMAP_IS_SPECIAL +- +-#include_next +- +-/* Address of protected data defined in the shared library may be +- external due to copy relocation. */ +-#define DL_EXTERN_PROTECTED_DATA +- +-struct link_map; +- +-extern void _dl_unmap (struct link_map *map) attribute_hidden; +- +-#define DL_UNMAP(map) _dl_unmap (map) diff --git a/SOURCES/glibc-rh1817513-29.patch b/SOURCES/glibc-rh1817513-29.patch new file mode 100644 index 0000000..bc9a8f4 --- /dev/null +++ b/SOURCES/glibc-rh1817513-29.patch @@ -0,0 +1,109 @@ +commit 23d2e5faf0bca6d9b31bef4aa162b95ee64cbfc6 +Author: Florian Weimer +Date: Thu Aug 15 14:37:50 2019 +0200 + + elf: Self-dlopen failure with explict loader invocation [BZ #24900] + + In case of an explicit loader invocation, ld.so essentially performs + a dlopen call to load the main executable. Since the pathname of + the executable is known at this point, it gets stored in the link + map. In regular mode, the pathname is not known and "" is used + instead. + + As a result, if a program calls dlopen on the pathname of the main + program, the dlopen call succeeds and returns a handle for the main + map. This results in an unnecessary difference between glibc + testing (without --enable-hardcoded-path-in-tests) and production + usage. + + This commit discards the names when building the link map in + _dl_new_object for the main executable, but it still determines + the origin at this point in case of an explict loader invocation. + The reason is that the specified pathname has to be used; the kernel + has a different notion of the main executable. + +Conflicts: + elf/Makefile + elf/tst-dlopen-aout.c + (Differences due to the complicated history of the test. + The new test elf/tst-dlopen-aout-container is not backported + here.) + +diff --git a/elf/dl-object.c b/elf/dl-object.c +index b37bcc1295f475f6..f6544a8fec45bdce 100644 +--- a/elf/dl-object.c ++++ b/elf/dl-object.c +@@ -57,14 +57,30 @@ struct link_map * + _dl_new_object (char *realname, const char *libname, int type, + struct link_map *loader, int mode, Lmid_t nsid) + { ++#ifdef SHARED ++ unsigned int naudit; ++ if (__glibc_unlikely ((mode & __RTLD_OPENEXEC) != 0)) ++ { ++ 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 = ""; ++ ++ /* We create the map for the executable before we know whether ++ we have auditing libraries and if yes, how many. Assume the ++ worst. */ ++ naudit = DL_NNS; ++ } ++ else ++ naudit = GLRO (dl_naudit); ++#endif ++ + size_t libname_len = strlen (libname) + 1; + struct link_map *new; + struct libname_list *newname; + #ifdef SHARED +- /* We create the map for the executable before we know whether we have +- auditing libraries and if yes, how many. Assume the worst. */ +- unsigned int naudit = GLRO(dl_naudit) ?: ((mode & __RTLD_OPENEXEC) +- ? DL_NNS : 0); + size_t audit_space = naudit * sizeof (new->l_audit[0]); + #else + # define audit_space 0 +@@ -91,8 +107,20 @@ _dl_new_object (char *realname, const char *libname, int type, + and won't get dumped during core file generation. Therefore to assist + gdb and to create more self-contained core files we adjust l_name to + point at the newly allocated copy (which will get dumped) instead of +- the ld.so rodata copy. */ +- new->l_name = *realname ? realname : (char *) newname->name + libname_len - 1; ++ the ld.so rodata copy. ++ ++ Furthermore, in case of explicit loader invocation, discard the ++ name of the main executable, to match the regular behavior, where ++ name of the executable is not known. */ ++#ifdef SHARED ++ if (*realname != '\0' && (mode & __RTLD_OPENEXEC) == 0) ++#else ++ if (*realname != '\0') ++#endif ++ new->l_name = realname; ++ else ++ new->l_name = (char *) newname->name + libname_len - 1; ++ + new->l_type = type; + /* If we set the bit now since we know it is never used we avoid + dirtying the cache line later. */ +@@ -149,7 +177,14 @@ _dl_new_object (char *realname, const char *libname, int type, + + new->l_local_scope[0] = &new->l_searchlist; + +- /* Don't try to find the origin for the main map which has the name "". */ ++ /* Determine the origin. If allocating the link map for the main ++ executable, the realname is not known and "". In this case, the ++ origin needs to be determined by other means. However, in case ++ of an explicit loader invocation, the pathname of the main ++ executable is known and needs to be processed here: From the ++ point of view of the kernel, the main executable is the ++ dynamic loader, and this would lead to a computation of the wrong ++ origin. */ + if (realname[0] != '\0') + { + size_t realname_len = strlen (realname) + 1; diff --git a/SOURCES/glibc-rh1817513-3.patch b/SOURCES/glibc-rh1817513-3.patch new file mode 100644 index 0000000..f6eccb4 --- /dev/null +++ b/SOURCES/glibc-rh1817513-3.patch @@ -0,0 +1,56 @@ +commit ae67f2e562603a0b58f59aef4f31aa33de05ba88 +Author: H.J. Lu +Date: Fri Aug 3 06:40:48 2018 -0700 + + x86: Cleanup cpu-features-offsets.sym + + Remove the unused macros. There is no code changes in libc.so nor + ld.so on i686 and x86-64. + + * sysdeps/x86/cpu-features-offsets.sym + (rtld_global_ro_offsetof): Removed. + (CPU_FEATURES_SIZE): Likewise. + (CPUID_OFFSET): Likewise. + (CPUID_SIZE): Likewise. + (CPUID_EAX_OFFSET): Likewise. + (CPUID_EBX_OFFSET): Likewise. + (CPUID_ECX_OFFSET): Likewise. + (CPUID_EDX_OFFSET): Likewise. + (FAMILY_OFFSET): Likewise. + (MODEL_OFFSET): Likewise. + (FEATURE_OFFSET): Likewise. + (FEATURE_SIZ): Likewise. + (COMMON_CPUID_INDEX_1): Likewise. + (COMMON_CPUID_INDEX_7): Likewise. + (FEATURE_INDEX_1): Likewise. + (RTLD_GLOBAL_RO_DL_X86_CPU_FEATURES_OFFSET): Updated. + +diff --git a/sysdeps/x86/cpu-features-offsets.sym b/sysdeps/x86/cpu-features-offsets.sym +index 33dd094e37f0fec7..6d03cea8e8fcdc36 100644 +--- a/sysdeps/x86/cpu-features-offsets.sym ++++ b/sysdeps/x86/cpu-features-offsets.sym +@@ -2,23 +2,5 @@ + + #include + +-#define rtld_global_ro_offsetof(mem) offsetof (struct rtld_global_ro, mem) +- +-RTLD_GLOBAL_RO_DL_X86_CPU_FEATURES_OFFSET rtld_global_ro_offsetof (_dl_x86_cpu_features) +- +-CPU_FEATURES_SIZE sizeof (struct cpu_features) +-CPUID_OFFSET offsetof (struct cpu_features, cpuid) +-CPUID_SIZE sizeof (struct cpuid_registers) +-CPUID_EAX_OFFSET offsetof (struct cpuid_registers, eax) +-CPUID_EBX_OFFSET offsetof (struct cpuid_registers, ebx) +-CPUID_ECX_OFFSET offsetof (struct cpuid_registers, ecx) +-CPUID_EDX_OFFSET offsetof (struct cpuid_registers, edx) +-FAMILY_OFFSET offsetof (struct cpu_features, family) +-MODEL_OFFSET offsetof (struct cpu_features, model) ++RTLD_GLOBAL_RO_DL_X86_CPU_FEATURES_OFFSET offsetof (struct rtld_global_ro, _dl_x86_cpu_features) + XSAVE_STATE_SIZE_OFFSET offsetof (struct cpu_features, xsave_state_size) +-FEATURE_OFFSET offsetof (struct cpu_features, feature) +-FEATURE_SIZE sizeof (unsigned int) +- +-COMMON_CPUID_INDEX_1 +-COMMON_CPUID_INDEX_7 +-FEATURE_INDEX_1 diff --git a/SOURCES/glibc-rh1817513-30.patch b/SOURCES/glibc-rh1817513-30.patch new file mode 100644 index 0000000..8fe1e89 --- /dev/null +++ b/SOURCES/glibc-rh1817513-30.patch @@ -0,0 +1,141 @@ +commit edd8d70b91e1ccef549a7c668499596cc4d56ad1 +Author: Mihailo Stojanovic +Date: Fri Aug 23 16:47:27 2019 +0000 + + [MIPS] Raise highest supported EI_ABIVERSION value [BZ #24916] + + This bumps the highest valid EI_ABIVERSION value to ABSOLUTE ABI. + + New testcase loads the symbol from the GOT with the "lb" instruction + so that the EI_ABIVERSION header field of the shared object is set + to ABSOLUTE (it doesn't actually check the value of the symbol), and + makes sure that the main executable is executed without "ABI version + invalid" error. + + Tested for all three ABIs (o32, n32, n64) using both static linker which + handles undefined weak symbols correctly [1] (and sets the EI_ABIVERSION + of the test module) and the one that doesn't (EI_ABIVERSION left as 0). + + [1] https://sourceware.org/ml/binutils/2018-07/msg00268.html + + [BZ #24916] + * sysdeps/mips/Makefile [$(subdir) = elf] (tests): Add + tst-undefined-weak. + [$(subdir) = elf] (modules-names): Add tst-undefined-weak-lib. + [$(subdir) = elf] ($(objpfx)tst-undefined-weak): Add dependency. + * sysdeps/mips/tst-undefined-weak-lib.S: New file. + * sysdeps/mips/tst-undefined-weak.c: Likewise. + * sysdeps/unix/sysv/linux/mips/ldsodefs.h (VALID_ELF_ABIVERSION): + Increment highest valid ABIVERSION value. + +diff --git a/sysdeps/mips/Makefile b/sysdeps/mips/Makefile +index 7ac6fa50311d60b7..6ad69e9ef9e88728 100644 +--- a/sysdeps/mips/Makefile ++++ b/sysdeps/mips/Makefile +@@ -82,3 +82,10 @@ $(objpfx)tst-mode-switch-2: $(shared-thread-library) + endif + endif + endif ++ ++ifeq ($(subdir),elf) ++tests += tst-undefined-weak ++modules-names += tst-undefined-weak-lib ++ ++$(objpfx)tst-undefined-weak: $(objpfx)tst-undefined-weak-lib.so ++endif +diff --git a/sysdeps/mips/tst-undefined-weak-lib.S b/sysdeps/mips/tst-undefined-weak-lib.S +new file mode 100644 +index 0000000000000000..a175ebf90e01b372 +--- /dev/null ++++ b/sysdeps/mips/tst-undefined-weak-lib.S +@@ -0,0 +1,43 @@ ++/* Undefined weak symbol loading shared module. ++ 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, see ++ . */ ++ ++#include ++ ++ .text ++ .globl x ++ .set nomips16 ++ .set nomicromips ++ .ent x ++ .type x, @function ++x: ++ .set noreorder ++#if _MIPS_SIM == _ABIO32 ++ .cpload $25 ++ jr $31 ++ lb $2,%got(a)($28) ++#else ++ .cpsetup $25,$24,x ++ lb $2,%got_disp(a)($28) ++ jr $31 ++ .cpreturn ++#endif ++ .set reorder ++ .end x ++ .size x, .-x ++ .weak a ++ .hidden a +diff --git a/sysdeps/mips/tst-undefined-weak.c b/sysdeps/mips/tst-undefined-weak.c +new file mode 100644 +index 0000000000000000..1231da6912508c19 +--- /dev/null ++++ b/sysdeps/mips/tst-undefined-weak.c +@@ -0,0 +1,28 @@ ++/* Undefined weak symbol loading main executable. ++ 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, see ++ . */ ++ ++int *x (void); ++ ++int ++do_test (void) ++{ ++ x (); ++ return 0; ++} ++ ++#include +diff --git a/sysdeps/unix/sysv/linux/mips/ldsodefs.h b/sysdeps/unix/sysv/linux/mips/ldsodefs.h +index 68a0a99bb1f1ec85..d2912cadabfd6877 100644 +--- a/sysdeps/unix/sysv/linux/mips/ldsodefs.h ++++ b/sysdeps/unix/sysv/linux/mips/ldsodefs.h +@@ -34,7 +34,7 @@ extern void _dl_static_init (struct link_map *map); + #undef VALID_ELF_ABIVERSION + #define VALID_ELF_ABIVERSION(osabi,ver) \ + (ver == 0 \ +- || (osabi == ELFOSABI_SYSV && ver < 4) \ ++ || (osabi == ELFOSABI_SYSV && ver < 5) \ + || (osabi == ELFOSABI_GNU && ver < LIBC_ABI_MAX)) + + #endif /* ldsodefs.h */ diff --git a/SOURCES/glibc-rh1817513-31.patch b/SOURCES/glibc-rh1817513-31.patch new file mode 100644 index 0000000..2081d6b --- /dev/null +++ b/SOURCES/glibc-rh1817513-31.patch @@ -0,0 +1,241 @@ +commit 23c1c256ae7b0f010d0fcaff60682b620887b164 +Author: Mihailo Stojanovic +Date: Thu Aug 29 20:11:42 2019 +0000 + + MIPS support for GNU hash + + This patch is a reimplementation of [1], which was submitted back in + 2015. Copyright issue has been sorted [2] last year. It proposed a new + section (.gnu.xhash) and related dynamic tag (GT_GNU_XHASH). The new + section would be virtually identical to the existing .gnu.hash except + for the translation table (xlat) which would contain correct MIPS + .dynsym indexes corresponding to the hashvals in chains. This is because + MIPS ABI imposes a different ordering of the dynsyms than the one + expected by the .gnu.hash section. Another addition would be a leading + word at the beggining of the section, which would contain the number of + entries in the translation table. + + In this patch, the new section name and dynamic tag are changed to + reflect the fact that the section should be treated as MIPS specific + (.MIPS.xhash and DT_MIPS_XHASH). + + This patch addresses the alignment issue reported in [3] which is caused + by the leading word of the .MIPS.xhash section. Leading word is now + removed in the corresponding binutils patch, and the number of entries + in the translation table is computed using DT_MIPS_SYMTABNO dynamic tag. + + Since the MIPS specific dl-lookup.c file was removed following the + initial patch submission, I opted for the definition of three new macros + in the generic ldsodefs.h. ELF_MACHINE_GNU_HASH_ADDRIDX defines the + index of the dynamic tag in the l_info array. ELF_MACHINE_HASH_SYMIDX is + used to calculate the index of a symbol in GNU hash. On MIPS, it is + defined to look up the symbol index in the translation table. + ELF_MACHINE_XHASH_SETUP is defined for MIPS only. It initializes the + .MIPS.xhash pointer in the link_map_machine struct. + + The other major change is bumping the highest EI_ABIVERSION value for + MIPS to suggest that the dynamic linker now supports GNU hash. + + The patch was tested by running the glibc testsuite for the three MIPS + ABIs (o32, n32 and n64) and for x86_64-linux-gnu. + + [1] https://sourceware.org/ml/binutils/2015-10/msg00057.html + [2] https://sourceware.org/ml/binutils/2018-03/msg00025.html + [3] https://sourceware.org/ml/binutils/2016-01/msg00006.html + + * elf/dl-addr.c (determine_info): Calculate the symbol index + using the newly defined ELF_MACHINE_HASH_SYMIDX macro. + * elf/dl-lookup.c (do_lookup_x): Ditto. + (_dl_setup_hash): Initialize MIPS xhash translation table. + * elf/elf.h (SHT_MIPS_XHASH): New define. + (DT_MIPS_XHASH): New define. + * sysdeps/generic/ldsodefs.h (ELF_MACHINE_GNU_HASH_ADDRIDX): New + define. + (ELF_MACHINE_HASH_SYMIDX): Ditto. + (ELF_MACHINE_XHASH_SETUP): Ditto. + * sysdeps/mips/ldsodefs.h (ELF_MACHINE_GNU_HASH_ADDRIDX): New + define. + (ELF_MACHINE_HASH_SYMIDX): Ditto. + (ELF_MACHINE_XHASH_SETUP): Ditto. + * sysdeps/mips/linkmap.h (struct link_map_machine): New member. + * sysdeps/unix/sysv/linux/mips/ldsodefs.h: Increment valid ABI + version. + * sysdeps/unix/sysv/linux/mips/libc-abis: New ABI version. + +diff --git a/elf/dl-addr.c b/elf/dl-addr.c +index e6c7d020945c51d2..b146fed09a46ff76 100644 +--- a/elf/dl-addr.c ++++ b/elf/dl-addr.c +@@ -42,7 +42,7 @@ determine_info (const ElfW(Addr) addr, struct link_map *match, Dl_info *info, + ElfW(Word) strtabsize = match->l_info[DT_STRSZ]->d_un.d_val; + + const ElfW(Sym) *matchsym = NULL; +- if (match->l_info[ADDRIDX (DT_GNU_HASH)] != NULL) ++ if (match->l_info[ELF_MACHINE_GNU_HASH_ADDRIDX] != NULL) + { + /* We look at all symbol table entries referenced by the hash + table. */ +@@ -57,6 +57,7 @@ determine_info (const ElfW(Addr) addr, struct link_map *match, Dl_info *info, + { + /* The hash table never references local symbols so + we can omit that test here. */ ++ symndx = ELF_MACHINE_HASH_SYMIDX (match, hasharr); + if ((symtab[symndx].st_shndx != SHN_UNDEF + || symtab[symndx].st_value != 0) + && symtab[symndx].st_shndx != SHN_ABS +@@ -65,8 +66,6 @@ determine_info (const ElfW(Addr) addr, struct link_map *match, Dl_info *info, + matchsym, addr) + && symtab[symndx].st_name < strtabsize) + matchsym = (ElfW(Sym) *) &symtab[symndx]; +- +- ++symndx; + } + while ((*hasharr++ & 1u) == 0); + } +diff --git a/elf/dl-lookup.c b/elf/dl-lookup.c +index 01724a54f8840f9f..42fdaed99296137f 100644 +--- a/elf/dl-lookup.c ++++ b/elf/dl-lookup.c +@@ -432,7 +432,7 @@ do_lookup_x (const char *undef_name, uint_fast32_t new_hash, + do + if (((*hasharr ^ new_hash) >> 1) == 0) + { +- symidx = hasharr - map->l_gnu_chain_zero; ++ symidx = ELF_MACHINE_HASH_SYMIDX (map, hasharr); + sym = check_match (undef_name, ref, version, flags, + type_class, &symtab[symidx], symidx, + strtab, map, &versioned_sym, +@@ -961,10 +961,10 @@ _dl_setup_hash (struct link_map *map) + { + Elf_Symndx *hash; + +- if (__glibc_likely (map->l_info[ADDRIDX (DT_GNU_HASH)] != NULL)) ++ if (__glibc_likely (map->l_info[ELF_MACHINE_GNU_HASH_ADDRIDX] != NULL)) + { + Elf32_Word *hash32 +- = (void *) D_PTR (map, l_info[ADDRIDX (DT_GNU_HASH)]); ++ = (void *) D_PTR (map, l_info[ELF_MACHINE_GNU_HASH_ADDRIDX]); + map->l_nbuckets = *hash32++; + Elf32_Word symbias = *hash32++; + Elf32_Word bitmask_nwords = *hash32++; +@@ -979,6 +979,10 @@ _dl_setup_hash (struct link_map *map) + map->l_gnu_buckets = hash32; + hash32 += map->l_nbuckets; + map->l_gnu_chain_zero = hash32 - symbias; ++ ++ /* Initialize MIPS xhash translation table. */ ++ ELF_MACHINE_XHASH_SETUP (hash32, symbias, map); ++ + return; + } + +diff --git a/elf/elf.h b/elf/elf.h +index 74f7f479ce817040..d6506ea1c7160dea 100644 +--- a/elf/elf.h ++++ b/elf/elf.h +@@ -1698,6 +1698,7 @@ typedef struct + #define SHT_MIPS_EH_REGION 0x70000027 + #define SHT_MIPS_XLATE_OLD 0x70000028 + #define SHT_MIPS_PDR_EXCEPTION 0x70000029 ++#define SHT_MIPS_XHASH 0x7000002b + + /* Legal values for sh_flags field of Elf32_Shdr. */ + +@@ -1945,7 +1946,9 @@ typedef struct + in a PIE as it stores a relative offset from the address of the tag + rather than an absolute address. */ + #define DT_MIPS_RLD_MAP_REL 0x70000035 +-#define DT_MIPS_NUM 0x36 ++/* GNU-style hash table with xlat. */ ++#define DT_MIPS_XHASH 0x70000036 ++#define DT_MIPS_NUM 0x37 + + /* Legal values for DT_MIPS_FLAGS Elf32_Dyn entry. */ + +diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h +index f0185ce0d16c0f69..3bdbdd6e67dacc85 100644 +--- a/sysdeps/generic/ldsodefs.h ++++ b/sysdeps/generic/ldsodefs.h +@@ -47,6 +47,23 @@ __BEGIN_DECLS + #define ADDRIDX(tag) (DT_NUM + DT_THISPROCNUM + DT_VERSIONTAGNUM \ + + DT_EXTRANUM + DT_VALNUM + DT_ADDRTAGIDX (tag)) + ++/* Type of GNU hash which the machine uses. */ ++#ifndef ELF_MACHINE_GNU_HASH_ADDRIDX ++# define ELF_MACHINE_GNU_HASH_ADDRIDX ADDRIDX (DT_GNU_HASH) ++#endif ++ ++/* Calculate the index of a symbol in GNU hash. */ ++#ifndef ELF_MACHINE_HASH_SYMIDX ++# define ELF_MACHINE_HASH_SYMIDX(map, hasharr) \ ++ ((hasharr) - (map)->l_gnu_chain_zero) ++#endif ++ ++/* Setup MIPS xhash. Defined only for MIPS. */ ++#ifndef ELF_MACHINE_XHASH_SETUP ++# define ELF_MACHINE_XHASH_SETUP(hash32, symbias, map) \ ++ ((void) (hash32), (void) (symbias), (void) (map)) ++#endif ++ + /* We use this macro to refer to ELF types independent of the native wordsize. + `ElfW(TYPE)' is used in place of `Elf32_TYPE' or `Elf64_TYPE'. */ + #define ELFW(type) _ElfW (ELF, __ELF_NATIVE_CLASS, type) +diff --git a/sysdeps/mips/ldsodefs.h b/sysdeps/mips/ldsodefs.h +index c6e5ce7e660325c1..35043b7c6d416c50 100644 +--- a/sysdeps/mips/ldsodefs.h ++++ b/sysdeps/mips/ldsodefs.h +@@ -26,6 +26,21 @@ struct La_mips_32_retval; + struct La_mips_64_regs; + struct La_mips_64_retval; + ++#define ELF_MACHINE_GNU_HASH_ADDRIDX (DT_MIPS_XHASH - DT_LOPROC + DT_NUM) ++ ++/* Calculate the index of a symbol in MIPS xhash. */ ++#define ELF_MACHINE_HASH_SYMIDX(map, hasharr) \ ++ ((map)->l_mach.mips_xlat_zero[(hasharr) - (map)->l_gnu_chain_zero]) ++ ++/* Setup MIPS xhash. */ ++#define ELF_MACHINE_XHASH_SETUP(hash32, symbias, map) \ ++ do \ ++ { \ ++ (hash32) += (map)->l_info[DT_MIPS (SYMTABNO)]->d_un.d_val - (symbias); \ ++ (map)->l_mach.mips_xlat_zero = (hash32) - (symbias); \ ++ } \ ++ while (0) ++ + #define ARCH_PLTENTER_MEMBERS \ + Elf32_Addr (*mips_o32_gnu_pltenter) (Elf32_Sym *, unsigned int, \ + uintptr_t *, uintptr_t *, \ +diff --git a/sysdeps/mips/linkmap.h b/sysdeps/mips/linkmap.h +index 1fb9678a6d1625fd..1e640c3ba9bd18e4 100644 +--- a/sysdeps/mips/linkmap.h ++++ b/sysdeps/mips/linkmap.h +@@ -3,4 +3,5 @@ struct link_map_machine + ElfW(Addr) plt; /* Address of .plt */ + ElfW(Word) fpabi; /* FP ABI of the object */ + unsigned int odd_spreg; /* Does the object require odd_spreg support? */ ++ const Elf32_Word *mips_xlat_zero; /* .MIPS.xhash */ + }; +diff --git a/sysdeps/unix/sysv/linux/mips/ldsodefs.h b/sysdeps/unix/sysv/linux/mips/ldsodefs.h +index d2912cadabfd6877..03f3e12f202a0563 100644 +--- a/sysdeps/unix/sysv/linux/mips/ldsodefs.h ++++ b/sysdeps/unix/sysv/linux/mips/ldsodefs.h +@@ -34,7 +34,7 @@ extern void _dl_static_init (struct link_map *map); + #undef VALID_ELF_ABIVERSION + #define VALID_ELF_ABIVERSION(osabi,ver) \ + (ver == 0 \ +- || (osabi == ELFOSABI_SYSV && ver < 5) \ ++ || (osabi == ELFOSABI_SYSV && ver < 6) \ + || (osabi == ELFOSABI_GNU && ver < LIBC_ABI_MAX)) + + #endif /* ldsodefs.h */ +diff --git a/sysdeps/unix/sysv/linux/mips/libc-abis b/sysdeps/unix/sysv/linux/mips/libc-abis +index eaea558720f42a48..c0b67dae3ece1511 100644 +--- a/sysdeps/unix/sysv/linux/mips/libc-abis ++++ b/sysdeps/unix/sysv/linux/mips/libc-abis +@@ -16,3 +16,5 @@ UNIQUE + MIPS_O32_FP64 mips*-*-linux* + # Absolute (SHN_ABS) symbols working correctly. + ABSOLUTE ++# GNU-style hash table with translation table. ++MIPS_XHASH diff --git a/SOURCES/glibc-rh1817513-32.patch b/SOURCES/glibc-rh1817513-32.patch new file mode 100644 index 0000000..4f68439 --- /dev/null +++ b/SOURCES/glibc-rh1817513-32.patch @@ -0,0 +1,254 @@ +commit 2f9046fb059e94fe254c9a4ff5bcd52182069e44 +Author: Stefan Liebler +Date: Wed Sep 18 12:40:00 2019 +0200 + + Add UNSUPPORTED check in elf/tst-pldd. + + The testcase forks a child process and runs pldd with PID of + this child. On systems where /proc/sys/kernel/yama/ptrace_scope + differs from zero, pldd will fail with + /usr/bin/pldd: cannot attach to process 3: Operation not permitted + + This patch checks if ptrace_scope exists, is zero "classic ptrace permissions" + or one "restricted ptrace". If ptrace_scope exists and has a higher + restriction, then the test is marked as UNSUPPORTED. + + The case "restricted ptrace" is handled by rearranging the processes involved + during the test. Now we have the following process tree: + -parent: do_test (performs output checks) + --subprocess 1: pldd_process (becomes pldd via execve) + ---subprocess 2: target_process (ptraced via pldd) + + ChangeLog: + + * elf/tst-pldd.c (do_test): Add UNSUPPORTED check. + Rearrange subprocesses. + (pldd_process): New function. + * support/Makefile (libsupport-routines): Add support_ptrace. + * support/xptrace.h: New file. + * support/support_ptrace.c: Likewise. + +Conflicts: + elf/tst-pldd.c + (Original backport uses spaces instead of tabs.) + +diff --git a/elf/tst-pldd.c b/elf/tst-pldd.c +index e2de31282a131166..f381cb0fa7e6b93d 100644 +--- a/elf/tst-pldd.c ++++ b/elf/tst-pldd.c +@@ -30,6 +30,11 @@ + #include + #include + #include ++#include ++#include ++#include ++#include ++#include + + static void + target_process (void *arg) +@@ -37,6 +42,34 @@ target_process (void *arg) + pause (); + } + ++static void ++pldd_process (void *arg) ++{ ++ pid_t *target_pid_ptr = (pid_t *) arg; ++ ++ /* Create a copy of current test to check with pldd. As the ++ target_process is a child of this pldd_process, pldd is also able ++ to attach to target_process if YAMA is configured to 1 = ++ "restricted ptrace". */ ++ struct support_subprocess target = support_subprocess (target_process, NULL); ++ ++ /* Store the pid of target-process as do_test needs it in order to ++ e.g. terminate it at end of the test. */ ++ *target_pid_ptr = target.pid; ++ ++ /* Three digits per byte plus null terminator. */ ++ char pid[3 * sizeof (uint32_t) + 1]; ++ snprintf (pid, array_length (pid), "%d", target.pid); ++ ++ char *prog = xasprintf ("%s/pldd", support_bindir_prefix); ++ ++ /* Run pldd and use the pid of target_process as argument. */ ++ execve (prog, (char *const []) { (char *) prog, pid, NULL }, ++ (char *const []) { NULL }); ++ ++ FAIL_EXIT1 ("Returned from execve: errno=%d=%m\n", errno); ++} ++ + /* The test runs in a container because pldd does not support tracing + a binary started by the loader iself (as with testrun.sh). */ + +@@ -52,25 +85,22 @@ in_str_list (const char *libname, const char *const strlist[]) + static int + do_test (void) + { +- /* Create a copy of current test to check with pldd. */ +- struct support_subprocess target = support_subprocess (target_process, NULL); +- +- /* Run 'pldd' on test subprocess. */ +- struct support_capture_subprocess pldd; ++ /* Check if our subprocess can be debugged with ptrace. */ + { +- /* Three digits per byte plus null terminator. */ +- char pid[3 * sizeof (uint32_t) + 1]; +- snprintf (pid, array_length (pid), "%d", target.pid); +- +- char *prog = xasprintf ("%s/pldd", support_bindir_prefix); +- +- pldd = support_capture_subprogram (prog, +- (char *const []) { (char *) prog, pid, NULL }); ++ int ptrace_scope = support_ptrace_scope (); ++ if (ptrace_scope >= 2) ++ FAIL_UNSUPPORTED ("/proc/sys/kernel/yama/ptrace_scope >= 2"); ++ } + +- support_capture_subprocess_check (&pldd, "pldd", 0, sc_allow_stdout); ++ pid_t *target_pid_ptr = (pid_t *) xmmap (NULL, sizeof (pid_t), ++ PROT_READ | PROT_WRITE, ++ MAP_SHARED | MAP_ANONYMOUS, -1); + +- free (prog); +- } ++ /* Run 'pldd' on test subprocess which will be created in pldd_process. ++ The pid of the subprocess will be written to target_pid_ptr. */ ++ struct support_capture_subprocess pldd; ++ pldd = support_capture_subprocess (pldd_process, target_pid_ptr); ++ support_capture_subprocess_check (&pldd, "pldd", 0, sc_allow_stdout); + + /* Check 'pldd' output. The test is expected to be linked against only + loader and libc. */ +@@ -85,15 +115,15 @@ do_test (void) + /* First line is in the form of : */ + TEST_COMPARE (fscanf (out, "%u: " STRINPUT (512), &pid, buffer), 2); + +- TEST_COMPARE (pid, target.pid); ++ TEST_COMPARE (pid, *target_pid_ptr); + TEST_COMPARE (strcmp (basename (buffer), "tst-pldd"), 0); + + /* It expects only one loader and libc loaded by the program. */ + bool interpreter_found = false, libc_found = false; + while (fgets (buffer, array_length (buffer), out) != NULL) + { +- /* Ignore vDSO. */ +- if (buffer[0] != '/') ++ /* Ignore vDSO. */ ++ if (buffer[0] != '/') + continue; + + /* Remove newline so baseline (buffer) can compare against the +@@ -128,7 +158,9 @@ do_test (void) + } + + support_capture_subprocess_free (&pldd); +- support_process_terminate (&target); ++ if (kill (*target_pid_ptr, SIGKILL) != 0) ++ FAIL_EXIT1 ("Unable to kill target_process: errno=%d=%m\n", errno); ++ xmunmap (target_pid_ptr, sizeof (pid_t)); + + return 0; + } +diff --git a/support/Makefile b/support/Makefile +index 65b16299573af1ed..79d03bd6bfe02540 100644 +--- a/support/Makefile ++++ b/support/Makefile +@@ -58,6 +58,7 @@ libsupport-routines = \ + support_format_hostent \ + support_format_netent \ + support_isolate_in_subprocess \ ++ support_ptrace \ + support_openpty \ + support_paths \ + support_quote_blob \ +diff --git a/support/support_ptrace.c b/support/support_ptrace.c +new file mode 100644 +index 0000000000000000..616b08cff33022ef +--- /dev/null ++++ b/support/support_ptrace.c +@@ -0,0 +1,44 @@ ++/* Support functions handling ptrace_scope. ++ 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, see ++ . */ ++ ++#include ++#include ++#include ++#include ++ ++int ++support_ptrace_scope (void) ++{ ++ int ptrace_scope = -1; ++ ++#ifdef __linux__ ++ /* YAMA may be not enabled. Otherwise it contains a value from 0 to 3: ++ - 0 classic ptrace permissions ++ - 1 restricted ptrace ++ - 2 admin-only attach ++ - 3 no attach */ ++ FILE *f = fopen ("/proc/sys/kernel/yama/ptrace_scope", "r"); ++ if (f != NULL) ++ { ++ TEST_COMPARE (fscanf (f, "%d", &ptrace_scope), 1); ++ xfclose (f); ++ } ++#endif ++ ++ return ptrace_scope; ++} +diff --git a/support/xptrace.h b/support/xptrace.h +new file mode 100644 +index 0000000000000000..7af892680578fffd +--- /dev/null ++++ b/support/xptrace.h +@@ -0,0 +1,32 @@ ++/* Support functions handling ptrace_scope. ++ 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, see ++ . */ ++ ++#ifndef SUPPORT_PTRACE_H ++#define SUPPORT_PTRACE_H ++ ++#include ++ ++__BEGIN_DECLS ++ ++/* Return the current YAMA mode set on the machine (0 to 3) or -1 ++ if YAMA is not supported. */ ++int support_ptrace_scope (void); ++ ++__END_DECLS ++ ++#endif diff --git a/SOURCES/glibc-rh1817513-33.patch b/SOURCES/glibc-rh1817513-33.patch new file mode 100644 index 0000000..db77728 --- /dev/null +++ b/SOURCES/glibc-rh1817513-33.patch @@ -0,0 +1,29 @@ +commit 64fab3633aecc8eadc1338aa8953f8b2f37e3ebf +Author: Stefan Liebler +Date: Thu Sep 19 12:26:18 2019 +0200 + + Fix building support_ptrace.c on i686-gnu. + + On i686-gnu the build is broken: + In file included from support_ptrace.c:22: + ../include/sys/prctl.h:2:15: fatal error: sys/prctl.h: No such file or directory + #include_next + + This patch just removes the unused prctl.h inclusion. + + ChangeLog: + + * support/support_ptrace.c: Remove inclusion of sys/prctl.h. + +diff --git a/support/support_ptrace.c b/support/support_ptrace.c +index 616b08cff33022ef..a733adf2c8dfd073 100644 +--- a/support/support_ptrace.c ++++ b/support/support_ptrace.c +@@ -19,7 +19,6 @@ + #include + #include + #include +-#include + + int + support_ptrace_scope (void) diff --git a/SOURCES/glibc-rh1817513-34.patch b/SOURCES/glibc-rh1817513-34.patch new file mode 100644 index 0000000..1d8b561 --- /dev/null +++ b/SOURCES/glibc-rh1817513-34.patch @@ -0,0 +1,155 @@ +commit 4052fa22f69c0964bb42c0f13daa791617253de5 +Author: DJ Delorie +Date: Wed Oct 2 14:46:46 2019 -0400 + + Add wait-for-debugger test harness hooks + + If WAIT_FOR_DEBUGGER is set to a non-zero value in the environment, + any test that runs will print some useful gdb information and wait + for gdb to attach to it and clear the "wait_for_debugger" variable. + + Reviewed-by: Carlos O'Donell + +diff --git a/support/support_test_main.c b/support/support_test_main.c +index fa3c2e06dee5ae0f..def84d803928176b 100644 +--- a/support/support_test_main.c ++++ b/support/support_test_main.c +@@ -19,6 +19,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -36,6 +37,8 @@ + #include + #include + ++#include ++ + static const struct option default_options[] = + { + TEST_DEFAULT_OPTIONS +@@ -176,10 +179,55 @@ signal_handler (int sig) + exit (1); + } + ++/* This must be volatile as it will be modified by the debugger. */ ++static volatile int wait_for_debugger = 0; ++ + /* Run test_function or test_function_argv. */ + static int + run_test_function (int argc, char **argv, const struct test_config *config) + { ++ const char *wfd = getenv("WAIT_FOR_DEBUGGER"); ++ if (wfd != NULL) ++ wait_for_debugger = atoi (wfd); ++ if (wait_for_debugger) ++ { ++ pid_t mypid; ++ FILE *gdb_script; ++ char *gdb_script_name; ++ int inside_container = 0; ++ ++ mypid = getpid(); ++ if (mypid < 3) ++ { ++ const char *outside_pid = getenv("PID_OUTSIDE_CONTAINER"); ++ if (outside_pid) ++ { ++ mypid = atoi (outside_pid); ++ inside_container = 1; ++ } ++ } ++ ++ gdb_script_name = (char *) xmalloc (strlen (argv[0]) + strlen (".gdb") + 1); ++ sprintf (gdb_script_name, "%s.gdb", argv[0]); ++ gdb_script = xfopen (gdb_script_name, "w"); ++ ++ fprintf (stderr, "Waiting for debugger, test process is pid %d\n", mypid); ++ fprintf (stderr, "gdb -x %s\n", gdb_script_name); ++ if (inside_container) ++ fprintf (gdb_script, "set sysroot %s/testroot.root\n", support_objdir_root); ++ fprintf (gdb_script, "file\n"); ++ fprintf (gdb_script, "file %s\n", argv[0]); ++ fprintf (gdb_script, "symbol-file %s\n", argv[0]); ++ fprintf (gdb_script, "exec-file %s\n", argv[0]); ++ fprintf (gdb_script, "attach %ld\n", (long int) mypid); ++ fprintf (gdb_script, "set wait_for_debugger = 0\n"); ++ fclose (gdb_script); ++ } ++ ++ /* Wait for the debugger to set wait_for_debugger to zero. */ ++ while (wait_for_debugger) ++ usleep (1000); ++ + if (config->test_function != NULL) + return config->test_function (); + else if (config->test_function_argv != NULL) +@@ -229,6 +277,11 @@ support_test_main (int argc, char **argv, const struct test_config *config) + unsigned int timeoutfactor = 1; + pid_t termpid; + ++ /* If we're debugging the test, we need to disable timeouts and use ++ the initial pid (esp if we're running inside a container). */ ++ if (getenv("WAIT_FOR_DEBUGGER") != NULL) ++ direct = 1; ++ + if (!config->no_mallopt) + { + /* Make uses of freed and uninitialized memory known. Do not +diff --git a/support/test-container.c b/support/test-container.c +index f0d9e3060e80bda5..6503cea90309b9b0 100644 +--- a/support/test-container.c ++++ b/support/test-container.c +@@ -676,6 +676,9 @@ main (int argc, char **argv) + char *so_base; + int do_postclean = 0; + ++ int pipes[2]; ++ char pid_buf[20]; ++ + uid_t original_uid; + gid_t original_gid; + /* If set, the test runs as root instead of the user running the testsuite. */ +@@ -999,6 +1002,11 @@ main (int argc, char **argv) + if (chdir (new_cwd_path) < 0) + FAIL_EXIT1 ("Can't cd to new %s - ", new_cwd_path); + ++ /* This is to pass the "outside" PID to the child, which will be PID ++ 1. */ ++ if (pipe2 (pipes, O_CLOEXEC) < 0) ++ FAIL_EXIT1 ("Can't create pid pipe"); ++ + /* To complete the containerization, we need to fork () at least + once. We can't exec, nor can we somehow link the new child to + our parent. So we run the child and propogate it's exit status +@@ -1010,6 +1018,12 @@ main (int argc, char **argv) + { + /* Parent. */ + int status; ++ ++ /* Send the child's "outside" pid to it. */ ++ write (pipes[1], &child, sizeof(child)); ++ close (pipes[0]); ++ close (pipes[1]); ++ + waitpid (child, &status, 0); + + if (WIFEXITED (status)) +@@ -1028,6 +1042,14 @@ main (int argc, char **argv) + /* The rest is the child process, which is now PID 1 and "in" the + new root. */ + ++ /* Get our "outside" pid from our parent. We use this to help with ++ debugging from outside the container. */ ++ read (pipes[0], &child, sizeof(child)); ++ close (pipes[0]); ++ close (pipes[1]); ++ sprintf (pid_buf, "%lu", (long unsigned)child); ++ setenv ("PID_OUTSIDE_CONTAINER", pid_buf, 0); ++ + maybe_xmkdir ("/tmp", 0755); + + /* Now that we're pid 1 (effectively "root") we can mount /proc */ diff --git a/SOURCES/glibc-rh1817513-35.patch b/SOURCES/glibc-rh1817513-35.patch new file mode 100644 index 0000000..4cea796 --- /dev/null +++ b/SOURCES/glibc-rh1817513-35.patch @@ -0,0 +1,421 @@ +commit c7bf5ceab6ec776ac7350d3b0190776bf532ac54 +Author: Florian Weimer +Date: Sat Nov 2 21:55:35 2019 +0100 + + Properly initialize audit cookie for the dynamic loader [BZ #25157] + + The l_audit array is indexed by audit module, not audit function. + + Change-Id: I180eb3573dc1c57433750f5d8cb18271460ba5f2 + +Conflicts: + elf/Makefile + (Test backport differences.) + +diff --git a/elf/Makefile b/elf/Makefile +index 4e1356b9172aee02..4ab73dc48d9ac126 100644 +--- a/elf/Makefile ++++ b/elf/Makefile +@@ -192,7 +192,8 @@ tests += restest1 preloadtest loadfail multiload origtest resolvfail \ + 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-initfinilazyfail \ ++ 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 + # reldep9 +@@ -303,6 +304,9 @@ modules-names = testobj1 testobj2 testobj3 testobj4 testobj5 testobj6 \ + 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 \ +@@ -1433,6 +1437,14 @@ $(objpfx)tst-audit13.out: $(objpfx)tst-audit13mod1.so + LDFLAGS-tst-audit13mod1.so = -Wl,-z,lazy + tst-audit13-ENV = LD_AUDIT=$(objpfx)tst-audit13mod1.so + ++$(objpfx)tst-auditmany.out: $(objpfx)tst-auditmanymod1.so \ ++ $(objpfx)tst-auditmanymod2.so $(objpfx)tst-auditmanymod3.so \ ++ $(objpfx)tst-auditmanymod4.so $(objpfx)tst-auditmanymod5.so \ ++ $(objpfx)tst-auditmanymod6.so $(objpfx)tst-auditmanymod7.so \ ++ $(objpfx)tst-auditmanymod8.so $(objpfx)tst-auditmanymod9.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 ++ + # 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/rtld.c b/elf/rtld.c +index ffbd8f4553bb3425..f557f39a70669c09 100644 +--- a/elf/rtld.c ++++ b/elf/rtld.c +@@ -1008,13 +1008,7 @@ ERROR: audit interface '%s' requires version %d (maximum supported version %d); + + /* Store the pointer. */ + if (err_str == NULL && largs.result != NULL) +- { +- newp->fptr[cnt] = largs.result; +- +- /* The dynamic linker link map is statically allocated, +- initialize the data now. */ +- GL(dl_rtld_map).l_audit[cnt].cookie = (intptr_t) &GL(dl_rtld_map); +- } ++ newp->fptr[cnt] = largs.result; + else + newp->fptr[cnt] = NULL; + ++cnt; +@@ -1030,6 +1024,12 @@ ERROR: audit interface '%s' requires version %d (maximum supported version %d); + *last_audit = GLRO(dl_audit) = &newp->ifaces; + else + *last_audit = (*last_audit)->next = &newp->ifaces; ++ ++ /* The dynamic linker link map is statically allocated, initialize ++ the data now. */ ++ GL (dl_rtld_map).l_audit[GLRO (dl_naudit)].cookie ++ = (intptr_t) &GL (dl_rtld_map); ++ + ++GLRO(dl_naudit); + + /* Mark the DSO as being used for auditing. */ +diff --git a/elf/tst-auditmany.c b/elf/tst-auditmany.c +new file mode 100644 +index 0000000000000000..9d68105b9e707b46 +--- /dev/null ++++ b/elf/tst-auditmany.c +@@ -0,0 +1,26 @@ ++/* Check cookie initialization for many auditors. Main program. ++ 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, see ++ . */ ++ ++/* It does not make sense to use the test harness for this test ++ because the testing happens in auditors. */ ++ ++int ++main (void) ++{ ++ return 0; ++} +diff --git a/elf/tst-auditmanymod.h b/elf/tst-auditmanymod.h +new file mode 100644 +index 0000000000000000..d1d89e08431ce32f +--- /dev/null ++++ b/elf/tst-auditmanymod.h +@@ -0,0 +1,64 @@ ++/* Check cookie initialization for many auditors. Auditor template. ++ 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, see ++ . */ ++ ++/* The macro MOD must be defined to the number of this auditor (an ++ integer) before including this file. */ ++ ++#include ++#include ++#include ++ ++/* Error counter for delayed error reporting. */ ++static int errors; ++ ++unsigned int ++la_version (unsigned int version) ++{ ++ return version; ++} ++ ++unsigned int ++la_objopen (struct link_map *map, Lmid_t lmid, ++ uintptr_t *cookie) ++{ ++ struct link_map *cookie_map = (struct link_map *) *cookie; ++ printf ("info: %d, la_objopen: map=%p name=%s cookie=%p:%p diff=%td\n", ++ MOD, map, map->l_name, cookie, cookie_map, ++ (char *) cookie - (char *) map); ++ fflush (stdout); ++ if (map != cookie_map) ++ { ++ printf ("error: %d, la_objopen:" ++ " map address does not match cookie value\n", ++ MOD); ++ fflush (stdout); ++ ++errors; ++ } ++ return 0; ++} ++ ++extern unsigned int ++la_objclose (uintptr_t *__cookie) ++{ ++ if (errors != 0) ++ { ++ printf ("error: exiting due to previous errors"); ++ _exit (1); ++ } ++ return 0; ++} +diff --git a/elf/tst-auditmanymod1.c b/elf/tst-auditmanymod1.c +new file mode 100644 +index 0000000000000000..c7de49d446a7e52d +--- /dev/null ++++ b/elf/tst-auditmanymod1.c +@@ -0,0 +1,20 @@ ++/* Check cookie initialization for many auditors. Auditor 1. ++ 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, see ++ . */ ++ ++#define MOD 1 ++#include "tst-auditmanymod.h" +diff --git a/elf/tst-auditmanymod2.c b/elf/tst-auditmanymod2.c +new file mode 100644 +index 0000000000000000..4254f022a177b844 +--- /dev/null ++++ b/elf/tst-auditmanymod2.c +@@ -0,0 +1,20 @@ ++/* Check cookie initialization for many auditors. Auditor 2. ++ 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, see ++ . */ ++ ++#define MOD 2 ++#include "tst-auditmanymod.h" +diff --git a/elf/tst-auditmanymod3.c b/elf/tst-auditmanymod3.c +new file mode 100644 +index 0000000000000000..ee90f4eb3a5c1b35 +--- /dev/null ++++ b/elf/tst-auditmanymod3.c +@@ -0,0 +1,20 @@ ++/* Check cookie initialization for many auditors. Auditor 3. ++ 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, see ++ . */ ++ ++#define MOD 3 ++#include "tst-auditmanymod.h" +diff --git a/elf/tst-auditmanymod4.c b/elf/tst-auditmanymod4.c +new file mode 100644 +index 0000000000000000..6379fa1d55014998 +--- /dev/null ++++ b/elf/tst-auditmanymod4.c +@@ -0,0 +1,20 @@ ++/* Check cookie initialization for many auditors. Auditor 4. ++ 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, see ++ . */ ++ ++#define MOD 4 ++#include "tst-auditmanymod.h" +diff --git a/elf/tst-auditmanymod5.c b/elf/tst-auditmanymod5.c +new file mode 100644 +index 0000000000000000..17c0f617aa4d1893 +--- /dev/null ++++ b/elf/tst-auditmanymod5.c +@@ -0,0 +1,20 @@ ++/* Check cookie initialization for many auditors. Auditor 5. ++ 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, see ++ . */ ++ ++#define MOD 5 ++#include "tst-auditmanymod.h" +diff --git a/elf/tst-auditmanymod6.c b/elf/tst-auditmanymod6.c +new file mode 100644 +index 0000000000000000..86bc6801a4454742 +--- /dev/null ++++ b/elf/tst-auditmanymod6.c +@@ -0,0 +1,20 @@ ++/* Check cookie initialization for many auditors. Auditor 6. ++ 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, see ++ . */ ++ ++#define MOD 6 ++#include "tst-auditmanymod.h" +diff --git a/elf/tst-auditmanymod7.c b/elf/tst-auditmanymod7.c +new file mode 100644 +index 0000000000000000..92b0bf6006876dff +--- /dev/null ++++ b/elf/tst-auditmanymod7.c +@@ -0,0 +1,20 @@ ++/* Check cookie initialization for many auditors. Auditor 7. ++ 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, see ++ . */ ++ ++#define MOD 7 ++#include "tst-auditmanymod.h" +diff --git a/elf/tst-auditmanymod8.c b/elf/tst-auditmanymod8.c +new file mode 100644 +index 0000000000000000..d42f884d2f24f4c0 +--- /dev/null ++++ b/elf/tst-auditmanymod8.c +@@ -0,0 +1,20 @@ ++/* Check cookie initialization for many auditors. Auditor 8. ++ 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, see ++ . */ ++ ++#define MOD 8 ++#include "tst-auditmanymod.h" +diff --git a/elf/tst-auditmanymod9.c b/elf/tst-auditmanymod9.c +new file mode 100644 +index 0000000000000000..6bee81d69c6d3c22 +--- /dev/null ++++ b/elf/tst-auditmanymod9.c +@@ -0,0 +1,20 @@ ++/* Check cookie initialization for many auditors. Auditor 9. ++ 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, see ++ . */ ++ ++#define MOD 9 ++#include "tst-auditmanymod.h" diff --git a/SOURCES/glibc-rh1817513-36.patch b/SOURCES/glibc-rh1817513-36.patch new file mode 100644 index 0000000..a7ac8c7 --- /dev/null +++ b/SOURCES/glibc-rh1817513-36.patch @@ -0,0 +1,340 @@ +commit e1d559f337de2c8ab68a6749dfe873477c883807 +Author: Florian Weimer +Date: Sat Nov 2 20:04:02 2019 +0100 + + Introduce link_map_audit_state accessor function + + To improve GCC 10 compatibility, it is necessary to remove the l_audit + zero-length array from the end of struct link_map. In preparation of + that, this commit introduces an accessor function for the audit state, + so that it is possible to change the representation of the audit state + without adjusting the code that accesses it. + + Tested on x86_64-linux-gnu. Built on i686-gnu. + + Change-Id: Id815673c29950fc011ae5301d7cde12624f658df + +diff --git a/csu/libc-start.c b/csu/libc-start.c +index 494132368f8fe486..dfbf195328239a17 100644 +--- a/csu/libc-start.c ++++ b/csu/libc-start.c +@@ -272,7 +272,7 @@ LIBC_START_MAIN (int (*main) (int, char **, char ** MAIN_AUXVEC_DECL), + for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt) + { + if (afct->preinit != NULL) +- afct->preinit (&head->l_audit[cnt].cookie); ++ afct->preinit (&link_map_audit_state (head, cnt)->cookie); + + afct = afct->next; + } +diff --git a/elf/dl-close.c b/elf/dl-close.c +index a9ecdff62dba88fb..1ece0ae1dd062d1e 100644 +--- a/elf/dl-close.c ++++ b/elf/dl-close.c +@@ -305,8 +305,12 @@ _dl_close_worker (struct link_map *map, bool force) + for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt) + { + if (afct->objclose != NULL) +- /* Return value is ignored. */ +- (void) afct->objclose (&imap->l_audit[cnt].cookie); ++ { ++ struct auditstate *state ++ = link_map_audit_state (imap, cnt); ++ /* Return value is ignored. */ ++ (void) afct->objclose (&state->cookie); ++ } + + afct = afct->next; + } +@@ -481,7 +485,10 @@ _dl_close_worker (struct link_map *map, bool force) + for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt) + { + if (afct->activity != NULL) +- afct->activity (&head->l_audit[cnt].cookie, LA_ACT_DELETE); ++ { ++ struct auditstate *state = link_map_audit_state (head, cnt); ++ afct->activity (&state->cookie, LA_ACT_DELETE); ++ } + + afct = afct->next; + } +@@ -781,7 +788,10 @@ _dl_close_worker (struct link_map *map, bool force) + for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt) + { + if (afct->activity != NULL) +- afct->activity (&head->l_audit[cnt].cookie, LA_ACT_CONSISTENT); ++ { ++ struct auditstate *state = link_map_audit_state (head, cnt); ++ afct->activity (&state->cookie, LA_ACT_CONSISTENT); ++ } + + afct = afct->next; + } +diff --git a/elf/dl-fini.c b/elf/dl-fini.c +index 3cfc262400da4db9..915ceb104e1c81d6 100644 +--- a/elf/dl-fini.c ++++ b/elf/dl-fini.c +@@ -152,9 +152,12 @@ _dl_fini (void) + for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt) + { + if (afct->objclose != NULL) +- /* Return value is ignored. */ +- (void) afct->objclose (&l->l_audit[cnt].cookie); +- ++ { ++ struct auditstate *state ++ = link_map_audit_state (l, cnt); ++ /* Return value is ignored. */ ++ (void) afct->objclose (&state->cookie); ++ } + afct = afct->next; + } + } +diff --git a/elf/dl-load.c b/elf/dl-load.c +index b190b28e32e47391..8f8869ff524ab9f2 100644 +--- a/elf/dl-load.c ++++ b/elf/dl-load.c +@@ -979,7 +979,8 @@ _dl_map_object_from_fd (const char *name, const char *origname, int fd, + for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt) + { + if (afct->activity != NULL) +- afct->activity (&head->l_audit[cnt].cookie, LA_ACT_ADD); ++ afct->activity (&link_map_audit_state (head, cnt)->cookie, ++ LA_ACT_ADD); + + afct = afct->next; + } +@@ -1418,10 +1419,9 @@ cannot enable executable stack as shared object requires"); + { + if (afct->objopen != NULL) + { +- l->l_audit[cnt].bindflags +- = afct->objopen (l, nsid, &l->l_audit[cnt].cookie); +- +- l->l_audit_any_plt |= l->l_audit[cnt].bindflags != 0; ++ 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; +@@ -1527,8 +1527,8 @@ open_verify (const char *name, int fd, + { + if (afct->objsearch != NULL) + { +- name = afct->objsearch (name, &loader->l_audit[cnt].cookie, +- whatcode); ++ struct auditstate *state = link_map_audit_state (loader, cnt); ++ name = afct->objsearch (name, &state->cookie, whatcode); + if (name == NULL) + /* Ignore the path. */ + return -1; +@@ -1998,8 +1998,8 @@ _dl_map_object (struct link_map *loader, const char *name, + if (afct->objsearch != NULL) + { + const char *before = name; +- name = afct->objsearch (name, &loader->l_audit[cnt].cookie, +- LA_SER_ORIG); ++ 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. */ +diff --git a/elf/dl-object.c b/elf/dl-object.c +index f6544a8fec45bdce..05a7750c65305771 100644 +--- a/elf/dl-object.c ++++ b/elf/dl-object.c +@@ -81,7 +81,7 @@ _dl_new_object (char *realname, const char *libname, int type, + struct link_map *new; + struct libname_list *newname; + #ifdef SHARED +- size_t audit_space = naudit * sizeof (new->l_audit[0]); ++ size_t audit_space = naudit * sizeof (struct auditstate); + #else + # define audit_space 0 + #endif +@@ -134,10 +134,8 @@ _dl_new_object (char *realname, const char *libname, int type, + + #ifdef SHARED + for (unsigned int cnt = 0; cnt < naudit; ++cnt) +- { +- new->l_audit[cnt].cookie = (uintptr_t) new; +- /* new->l_audit[cnt].bindflags = 0; */ +- } ++ /* No need to initialize bindflags due to calloc. */ ++ link_map_audit_state (new, cnt)->cookie = (uintptr_t) new; + #endif + + /* new->l_global = 0; We use calloc therefore not necessary. */ +diff --git a/elf/dl-open.c b/elf/dl-open.c +index 46a4c1e5a3f8d2dd..7113c4a04f0fddbc 100644 +--- a/elf/dl-open.c ++++ b/elf/dl-open.c +@@ -589,7 +589,10 @@ dl_open_worker (void *a) + for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt) + { + if (afct->activity != NULL) +- afct->activity (&head->l_audit[cnt].cookie, LA_ACT_CONSISTENT); ++ { ++ struct auditstate *state = link_map_audit_state (head, cnt); ++ afct->activity (&state->cookie, LA_ACT_CONSISTENT); ++ } + + afct = afct->next; + } +diff --git a/elf/dl-runtime.c b/elf/dl-runtime.c +index 3d2f4a7a76e616e3..72b03e000dcf190e 100644 +--- a/elf/dl-runtime.c ++++ b/elf/dl-runtime.c +@@ -325,15 +325,18 @@ _dl_profile_fixup ( + { + /* XXX Check whether both DSOs must request action or + only one */ +- if ((l->l_audit[cnt].bindflags & LA_FLG_BINDFROM) != 0 +- && (result->l_audit[cnt].bindflags & LA_FLG_BINDTO) != 0) ++ 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->l_audit[cnt].cookie, +- &result->l_audit[cnt].cookie, ++ &l_state->cookie, ++ &result_state->cookie, + &flags, + strtab2 + defsym->st_name); + if (new_value != (uintptr_t) sym.st_value) +@@ -421,10 +424,13 @@ _dl_profile_fixup ( + & (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->l_audit[cnt].cookie, +- &reloc_result->bound->l_audit[cnt].cookie, ++ &l_state->cookie, ++ &bound_state->cookie, + regs, &flags, symname, + &new_framesize); + if (new_value != (uintptr_t) sym.st_value) +@@ -504,9 +510,11 @@ _dl_call_pltexit (struct link_map *l, ElfW(Word) reloc_arg, + && (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->l_audit[cnt].cookie, +- &reloc_result->bound->l_audit[cnt].cookie, ++ &l_state->cookie, &bound_state->cookie, + inregs, outregs, symname); + } + +diff --git a/elf/dl-sym.c b/elf/dl-sym.c +index 189628adc05aedf1..286cf7e27fd59f20 100644 +--- a/elf/dl-sym.c ++++ b/elf/dl-sym.c +@@ -198,17 +198,20 @@ RTLD_NEXT used in code not dynamically loaded")); + + 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->l_audit[cnt].bindflags & LA_FLG_BINDFROM) +- != 0 +- || ((result->l_audit[cnt].bindflags & LA_FLG_BINDTO) ++ && ((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->l_audit[cnt].cookie, +- &result->l_audit[cnt].cookie, ++ &match_audit->cookie, ++ &result_audit->cookie, + &flags, strtab + ref->st_name); + if (new_value != (uintptr_t) sym.st_value) + { +diff --git a/elf/rtld.c b/elf/rtld.c +index f557f39a70669c09..18335bc666f2b89d 100644 +--- a/elf/rtld.c ++++ b/elf/rtld.c +@@ -1025,9 +1025,9 @@ ERROR: audit interface '%s' requires version %d (maximum supported version %d); + else + *last_audit = (*last_audit)->next = &newp->ifaces; + +- /* The dynamic linker link map is statically allocated, initialize +- the data now. */ +- GL (dl_rtld_map).l_audit[GLRO (dl_naudit)].cookie ++ /* The dynamic linker link map is statically allocated, so the ++ cookie in _dl_new_object has not happened. */ ++ link_map_audit_state (&GL (dl_rtld_map), GLRO (dl_naudit))->cookie + = (intptr_t) &GL (dl_rtld_map); + + ++GLRO(dl_naudit); +@@ -1046,9 +1046,9 @@ notify_audit_modules_of_loaded_object (struct link_map *map) + { + if (afct->objopen != NULL) + { +- map->l_audit[cnt].bindflags +- = afct->objopen (map, LM_ID_BASE, &map->l_audit[cnt].cookie); +- map->l_audit_any_plt |= map->l_audit[cnt].bindflags != 0; ++ 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; +@@ -1660,7 +1660,8 @@ ERROR: '%s': cannot process note segment.\n", _dl_argv[0]); + for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt) + { + if (afct->activity != NULL) +- afct->activity (&main_map->l_audit[cnt].cookie, LA_ACT_ADD); ++ afct->activity (&link_map_audit_state (main_map, cnt)->cookie, ++ LA_ACT_ADD); + + afct = afct->next; + } +@@ -2331,7 +2332,8 @@ ERROR: '%s': cannot process note segment.\n", _dl_argv[0]); + for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt) + { + if (afct->activity != NULL) +- afct->activity (&head->l_audit[cnt].cookie, LA_ACT_CONSISTENT); ++ afct->activity (&link_map_audit_state (head, cnt)->cookie, ++ LA_ACT_CONSISTENT); + + afct = afct->next; + } +diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h +index 3bdbdd6e67dacc85..a8fb0d211426e4b1 100644 +--- a/sysdeps/generic/ldsodefs.h ++++ b/sysdeps/generic/ldsodefs.h +@@ -1197,7 +1197,13 @@ rtld_active (void) + initialized and active ld.so copy. */ + return GLRO(dl_init_all_dirs) != NULL; + } +-#endif ++ ++static inline struct auditstate * ++link_map_audit_state (struct link_map *l, size_t index) ++{ ++ return &l->l_audit[index]; ++} ++#endif /* SHARED */ + + __END_DECLS + diff --git a/SOURCES/glibc-rh1817513-37.patch b/SOURCES/glibc-rh1817513-37.patch new file mode 100644 index 0000000..33008bf --- /dev/null +++ b/SOURCES/glibc-rh1817513-37.patch @@ -0,0 +1,80 @@ +commit 4a2ab5843a5cc4a5db1b3b79916a520ea8b115dc +Author: Florian Weimer +Date: Fri Nov 8 15:48:51 2019 +0100 + + dlsym: Do not determine caller link map if not needed + + Obtaining the link map is potentially very slow because it requires + iterating over all loaded objects in the current implementation. If + the caller supplied an explicit handle (i.e., not one of the RTLD_* + constants), the dlsym implementation does not need the identity of the + caller (except in the special case of auditing), so this change + avoids computing it in that case. + + Even in the minimal case (dlsym called from a main program linked with + -dl), this shows a small speedup, perhaps around five percent. The + performance improvement can be arbitrarily large in principle (if + _dl_find_dso_for_object has to iterate over many link maps). + + Change-Id: Ide5d9e2cc7ac25a0ffae8fb4c26def0c898efa29 + +diff --git a/elf/dl-sym.c b/elf/dl-sym.c +index 286cf7e27fd59f20..b133850a3c6657a4 100644 +--- a/elf/dl-sym.c ++++ b/elf/dl-sym.c +@@ -80,6 +80,18 @@ call_dl_lookup (void *ptr) + args->flags, NULL); + } + ++/* Return the link map containing the caller address. */ ++static inline struct link_map * ++find_caller_link_map (ElfW(Addr) caller) ++{ ++ struct link_map *l = _dl_find_dso_for_object (caller); ++ if (l != NULL) ++ return l; ++ else ++ /* If the address is not recognized the call comes from the main ++ program (we hope). */ ++ return GL(dl_ns)[LM_ID_BASE]._ns_loaded; ++} + + static void * + do_sym (void *handle, const char *name, void *who, +@@ -89,13 +101,13 @@ do_sym (void *handle, const char *name, void *who, + lookup_t result; + ElfW(Addr) caller = (ElfW(Addr)) who; + +- struct link_map *l = _dl_find_dso_for_object (caller); +- /* If the address is not recognized the call comes from the main +- program (we hope). */ +- struct link_map *match = l ? l : GL(dl_ns)[LM_ID_BASE]._ns_loaded; ++ /* Link map of the caller if needed. */ ++ struct link_map *match = NULL; + + if (handle == RTLD_DEFAULT) + { ++ match = find_caller_link_map (caller); ++ + /* Search the global scope. We have the simple case where + we look up in the scope of an object which was part of + the initial binary. And then the more complex part +@@ -128,6 +140,8 @@ do_sym (void *handle, const char *name, void *who, + } + else if (handle == RTLD_NEXT) + { ++ match = find_caller_link_map (caller); ++ + if (__glibc_unlikely (match == GL(dl_ns)[LM_ID_BASE]._ns_loaded)) + { + if (match == NULL +@@ -187,6 +201,9 @@ RTLD_NEXT used in code not dynamically loaded")); + unsigned int ndx = (ref - (ElfW(Sym) *) D_PTR (result, + l_info[DT_SYMTAB])); + ++ if (match == NULL) ++ match = find_caller_link_map (caller); ++ + if ((match->l_audit_any_plt | result->l_audit_any_plt) != 0) + { + unsigned int altvalue = 0; diff --git a/SOURCES/glibc-rh1817513-38.patch b/SOURCES/glibc-rh1817513-38.patch new file mode 100644 index 0000000..4700cf4 --- /dev/null +++ b/SOURCES/glibc-rh1817513-38.patch @@ -0,0 +1,211 @@ +commit 4f79b3e2fb3eba003240ec38a0e68702b9a60b86 +Author: DJ Delorie +Date: Mon Feb 3 14:49:25 2020 -0500 + + test-container: add exec, cwd + + exec [optional_argv_0] + + copies test binary to specified location and runs it from + there. If the second argument is provided, that will + be used for argv[0] + + cwd + + attempts to chdir(directory) before running test + + Note: "cwd" not "cd" as it takes effect just before the + test binary runs, not when it's encountered in the script, + so it can't be used as a path shortcut like "cd" would imply. + + cleanup: use xstrdup() instead of strdup() + + Reviewed-by: Carlos O'Donell + +diff --git a/support/test-container.c b/support/test-container.c +index 6503cea90309b9b0..9488ec7b4a824380 100644 +--- a/support/test-container.c ++++ b/support/test-container.c +@@ -95,6 +95,8 @@ int verbose = 0; + mv FILE FILE + cp FILE FILE + rm FILE ++ cwd PATH ++ exec FILE + FILE must start with $B/, $S/, $I/, $L/, or / + (expands to build dir, source dir, install dir, library dir + (in container), or container's root) +@@ -104,6 +106,8 @@ int verbose = 0; + - 'mv': A minimal move files command. + - 'cp': A minimal copy files command. + - 'rm': A minimal remove files command. ++ - 'cwd': set test working directory ++ - 'exec': change test binary location (may end in /) + * mytest.root/postclean.req causes fresh rsync (with delete) after + test if present + +@@ -147,7 +151,7 @@ maybe_xmkdir (const char *path, mode_t mode) + } + + /* Temporarily concatenate multiple strings into one. Allows up to 10 +- temporary results; use strdup () if you need them to be ++ temporary results; use xstrdup () if you need them to be + permanent. */ + static char * + concat (const char *str, ...) +@@ -670,11 +674,13 @@ main (int argc, char **argv) + char *new_objdir_path; + char *new_srcdir_path; + char **new_child_proc; ++ char *new_child_exec; + char *command_root; + char *command_base; + char *command_basename; + char *so_base; + int do_postclean = 0; ++ char *change_cwd = NULL; + + int pipes[2]; + char pid_buf[20]; +@@ -701,7 +707,7 @@ main (int argc, char **argv) + + if (argc < 2) + { +- fprintf (stderr, "Usage: containerize \n"); ++ fprintf (stderr, "Usage: test-container \n"); + exit (1); + } + +@@ -746,12 +752,13 @@ main (int argc, char **argv) + } + } + +- pristine_root_path = strdup (concat (support_objdir_root, ++ pristine_root_path = xstrdup (concat (support_objdir_root, + "/testroot.pristine", NULL)); +- new_root_path = strdup (concat (support_objdir_root, ++ new_root_path = xstrdup (concat (support_objdir_root, + "/testroot.root", NULL)); + new_cwd_path = get_current_dir_name (); + new_child_proc = argv + 1; ++ new_child_exec = argv[1]; + + lock_fd = open (concat (pristine_root_path, "/lock.fd", NULL), + O_CREAT | O_TRUNC | O_RDWR, 0666); +@@ -778,10 +785,10 @@ main (int argc, char **argv) + command_root = concat (support_srcdir_root, + argv[1] + strlen (support_objdir_root), + ".root", NULL); +- command_root = strdup (command_root); ++ command_root = xstrdup (command_root); + + /* This cuts off the ".root" we appended above. */ +- command_base = strdup (command_root); ++ command_base = xstrdup (command_root); + command_base[strlen (command_base) - 5] = 0; + + /* This is the basename of the test we're running. */ +@@ -792,7 +799,7 @@ main (int argc, char **argv) + ++command_basename; + + /* Shared object base directory. */ +- so_base = strdup (argv[1]); ++ so_base = xstrdup (argv[1]); + if (strrchr (so_base, '/') != NULL) + strrchr (so_base, '/')[1] = 0; + +@@ -806,9 +813,9 @@ main (int argc, char **argv) + && S_ISDIR (st.st_mode)) + rsync (command_root, new_root_path, 0); + +- new_objdir_path = strdup (concat (new_root_path, ++ new_objdir_path = xstrdup (concat (new_root_path, + support_objdir_root, NULL)); +- new_srcdir_path = strdup (concat (new_root_path, ++ new_srcdir_path = xstrdup (concat (new_root_path, + support_srcdir_root, NULL)); + + /* new_cwd_path starts with '/' so no "/" needed between the two. */ +@@ -868,7 +875,10 @@ main (int argc, char **argv) + the_words[i] = concat (new_root_path, + support_libdir_prefix, + the_words[i] + 2, NULL); +- else if (the_words[i][0] == '/') ++ /* "exec" and "cwd" use inside-root paths. */ ++ else if (strcmp (the_words[0], "exec") != 0 ++ && strcmp (the_words[0], "cwd") != 0 ++ && the_words[i][0] == '/') + the_words[i] = concat (new_root_path, + the_words[i], NULL); + } +@@ -912,13 +922,49 @@ main (int argc, char **argv) + { + maybe_xunlink (the_words[1]); + } ++ else if (nt >= 2 && strcmp (the_words[0], "exec") == 0) ++ { ++ /* The first argument is the desired location and name ++ of the test binary as we wish to exec it; we will ++ copy the binary there. The second (optional) ++ argument is the value to pass as argv[0], it ++ defaults to the same as the first argument. */ ++ char *new_exec_path = the_words[1]; ++ ++ /* If the new exec path ends with a slash, that's the ++ * directory, and use the old test base name. */ ++ if (new_exec_path [strlen(new_exec_path) - 1] == '/') ++ new_exec_path = concat (new_exec_path, ++ basename (new_child_proc[0]), ++ NULL); ++ ++ ++ /* new_child_proc is in the build tree, so has the ++ same path inside the chroot as outside. The new ++ exec path is, by definition, relative to the ++ chroot. */ ++ copy_one_file (new_child_proc[0], concat (new_root_path, ++ new_exec_path, ++ NULL)); ++ ++ new_child_exec = xstrdup (new_exec_path); ++ if (the_words[2]) ++ new_child_proc[0] = xstrdup (the_words[2]); ++ else ++ new_child_proc[0] = new_child_exec; ++ } ++ else if (nt == 2 && strcmp (the_words[0], "cwd") == 0) ++ { ++ change_cwd = xstrdup (the_words[1]); ++ } + else if (nt == 1 && strcmp (the_words[0], "su") == 0) + { + be_su = 1; + } + else if (nt > 0 && the_words[0][0] != '#') + { +- printf ("\033[31minvalid [%s]\033[0m\n", the_words[0]); ++ fprintf (stderr, "\033[31minvalid [%s]\033[0m\n", the_words[0]); ++ exit (1); + } + } + fclose (f); +@@ -1089,11 +1135,17 @@ main (int argc, char **argv) + write (GMAP, tmp, strlen (tmp)); + xclose (GMAP); + ++ if (change_cwd) ++ { ++ if (chdir (change_cwd) < 0) ++ FAIL_EXIT1 ("Can't cd to %s inside container - ", change_cwd); ++ } ++ + /* Now run the child. */ +- execvp (new_child_proc[0], new_child_proc); ++ execvp (new_child_exec, new_child_proc); + + /* Or don't run the child? */ +- FAIL_EXIT1 ("Unable to exec %s\n", new_child_proc[0]); ++ FAIL_EXIT1 ("Unable to exec %s\n", new_child_exec); + + /* Because gcc won't know error () never returns... */ + exit (EXIT_UNSUPPORTED); diff --git a/SOURCES/glibc-rh1817513-39.patch b/SOURCES/glibc-rh1817513-39.patch new file mode 100644 index 0000000..d514b49 --- /dev/null +++ b/SOURCES/glibc-rh1817513-39.patch @@ -0,0 +1,50 @@ +commit abcc039d2e26b3c9c723d6419e086753a791b3d5 +Author: Florian Weimer +Date: Fri Feb 7 20:06:32 2020 +0100 + + elf: Introduce the rtld-stubbed-symbols makefile variable + + This generalizes a mechanism used for stack-protector support, so + that it can be applied to other symbols if required. + + Reviewed-by: Carlos O'Donell + +diff --git a/elf/Makefile b/elf/Makefile +index 4ab73dc48d9ac126..a1ea44f231d8cec5 100644 +--- a/elf/Makefile ++++ b/elf/Makefile +@@ -474,21 +474,25 @@ $(objpfx)dl-allobjs.os: $(all-rtld-routines:%=$(objpfx)%.os) + # are compiled with special flags, and puts these modules into rtld-libc.a + # for us. Then we do the real link using rtld-libc.a instead of libc_pic.a. + +-# If the compiler can do SSP, build the mapfile with dummy __stack_chk_fail +-# and __stack_chk_fail_local symbols defined, to prevent the real things +-# being dragged into rtld even though rtld is never built with stack- +-# protection. ++# These symbols need to be stubbed out during symbol discovery because ++# their implementation is provided differently in rtld, and the symbol ++# discovery mechanism is not compatible with the libc implementation ++# when compiled for libc. ++rtld-stubbed-symbols = ++ ++# The GCC arguments that implement $(rtld-stubbed-symbols). ++rtld-stubbed-symbols-args = \ ++ $(patsubst %,-Wl$(comma)--defsym=%=0, $(rtld-stubbed-symbols)) + + ifeq ($(have-ssp),yes) +-dummy-stack-chk-fail := -Wl,--defsym='__stack_chk_fail=0' \ +- -Wl,--defsym='__stack_chk_fail_local=0' +-else +-dummy-stack-chk-fail := ++# rtld is not built with the stack protector, so these references will ++# go away in the rebuilds. ++rtld-stubbed-symbols += __stack_chk_fail __stack_chk_fail_local + endif + + $(objpfx)librtld.map: $(objpfx)dl-allobjs.os $(common-objpfx)libc_pic.a + @-rm -f $@T +- $(reloc-link) -o $@.o $(dummy-stack-chk-fail) \ ++ $(reloc-link) -o $@.o $(rtld-stubbed-symbols-args) \ + '-Wl,-(' $^ -lgcc '-Wl,-)' -Wl,-Map,$@T + rm -f $@.o + mv -f $@T $@ diff --git a/SOURCES/glibc-rh1817513-4.patch b/SOURCES/glibc-rh1817513-4.patch new file mode 100644 index 0000000..b3b1c74 --- /dev/null +++ b/SOURCES/glibc-rh1817513-4.patch @@ -0,0 +1,64 @@ +commit 430388d5dc0e1861b869096f4f5d946d7d74232a +Author: H.J. Lu +Date: Fri Aug 3 08:04:49 2018 -0700 + + x86: Don't include in assembly codes + + There is no need to include in assembly codes since all + x86 IFUNC selector functions are written in C. Tested on i686 and + x86-64. There is no code change in libc.so, ld.so and libmvec.so. + + * sysdeps/i386/i686/multiarch/bzero-ia32.S: Don't include + . + * sysdeps/x86_64/fpu/multiarch/svml_d_sin8_core-avx2.S: Likewise. + * sysdeps/x86_64/fpu/multiarch/svml_s_expf16_core-avx2.S: Likewise. + * sysdeps/x86_64/multiarch/memset-sse2-unaligned-erms.S: Likewise. + +diff --git a/sysdeps/i386/i686/multiarch/bzero-ia32.S b/sysdeps/i386/i686/multiarch/bzero-ia32.S +index 68ff9e1e903f7c4c..94d13e88f7532bc0 100644 +--- a/sysdeps/i386/i686/multiarch/bzero-ia32.S ++++ b/sysdeps/i386/i686/multiarch/bzero-ia32.S +@@ -17,7 +17,6 @@ + . */ + + #include +-#include + + #if IS_IN (libc) + # define __bzero __bzero_ia32 +diff --git a/sysdeps/x86_64/fpu/multiarch/svml_d_sin8_core-avx2.S b/sysdeps/x86_64/fpu/multiarch/svml_d_sin8_core-avx2.S +index b64c3390d6169d18..87536a06a3ed54c6 100644 +--- a/sysdeps/x86_64/fpu/multiarch/svml_d_sin8_core-avx2.S ++++ b/sysdeps/x86_64/fpu/multiarch/svml_d_sin8_core-avx2.S +@@ -17,7 +17,6 @@ + . */ + + #include +-#include + + #define _ZGVeN8v_sin _ZGVeN8v_sin_avx2_wrapper + #include "../svml_d_sin8_core.S" +diff --git a/sysdeps/x86_64/fpu/multiarch/svml_s_expf16_core-avx2.S b/sysdeps/x86_64/fpu/multiarch/svml_s_expf16_core-avx2.S +index e0b7fd787fa6428d..16713ba7142ecad6 100644 +--- a/sysdeps/x86_64/fpu/multiarch/svml_s_expf16_core-avx2.S ++++ b/sysdeps/x86_64/fpu/multiarch/svml_s_expf16_core-avx2.S +@@ -17,7 +17,6 @@ + . */ + + #include +-#include + + #define _ZGVeN16v_expf _ZGVeN16v_expf_avx2_wrapper + #include "../svml_s_expf16_core.S" +diff --git a/sysdeps/x86_64/multiarch/memset-sse2-unaligned-erms.S b/sysdeps/x86_64/multiarch/memset-sse2-unaligned-erms.S +index be6671759beaaa84..56b81f5cc5288808 100644 +--- a/sysdeps/x86_64/multiarch/memset-sse2-unaligned-erms.S ++++ b/sysdeps/x86_64/multiarch/memset-sse2-unaligned-erms.S +@@ -19,7 +19,6 @@ + + #include + #include +-#include + + #if IS_IN (libc) + # define MEMSET_SYMBOL(p,s) p##_sse2_##s diff --git a/SOURCES/glibc-rh1817513-40.patch b/SOURCES/glibc-rh1817513-40.patch new file mode 100644 index 0000000..d30002b --- /dev/null +++ b/SOURCES/glibc-rh1817513-40.patch @@ -0,0 +1,248 @@ +commit c76147afe917ef7d309ee893f8f017a3c2934aac +Author: Florian Weimer +Date: Sat Feb 8 15:00:28 2020 +0100 + + elf: Extract _dl_sym_post, _dl_sym_find_caller_map from elf/dl-sym.c + + The definitions are moved into a new file, elf/dl-sym-post.h, so that + this code can be used by the dynamic loader as well. + + Reviewed-by: Carlos O'Donell + +diff --git a/elf/dl-sym-post.h b/elf/dl-sym-post.h +new file mode 100644 +index 0000000000000000..4c4f574633497789 +--- /dev/null ++++ b/elf/dl-sym-post.h +@@ -0,0 +1,106 @@ ++/* Post-processing of a symbol produced by dlsym, dlvsym. ++ Copyright (C) 1999-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 ++ . */ ++ ++ ++/* Return the link map containing the caller address. */ ++static struct link_map * ++_dl_sym_find_caller_link_map (ElfW(Addr) caller) ++{ ++ struct link_map *l = _dl_find_dso_for_object (caller); ++ if (l != NULL) ++ return l; ++ else ++ /* If the address is not recognized the call comes from the main ++ program (we hope). */ ++ return GL(dl_ns)[LM_ID_BASE]._ns_loaded; ++} ++ ++/* Translates RESULT, *REF, VALUE into a symbol address from the point ++ of view of MATCH. Performs IFUNC resolution and auditing if ++ necessary. If MATCH is NULL, CALLER is used to determine it. */ ++static void * ++_dl_sym_post (lookup_t result, const ElfW(Sym) *ref, void *value, ++ ElfW(Addr) caller, struct link_map *match) ++{ ++ /* Resolve indirect function address. */ ++ if (__glibc_unlikely (ELFW(ST_TYPE) (ref->st_info) == STT_GNU_IFUNC)) ++ { ++ DL_FIXUP_VALUE_TYPE fixup ++ = DL_FIXUP_MAKE_VALUE (result, (ElfW(Addr)) value); ++ fixup = elf_ifunc_invoke (DL_FIXUP_VALUE_ADDR (fixup)); ++ value = (void *) DL_FIXUP_VALUE_CODE_ADDR (fixup); ++ } ++ ++#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. */ ++ 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; ++ } ++ } ++#endif ++ return value; ++} +diff --git a/elf/dl-sym.c b/elf/dl-sym.c +index b133850a3c6657a4..5698fd7874a0ce48 100644 +--- a/elf/dl-sym.c ++++ b/elf/dl-sym.c +@@ -28,6 +28,7 @@ + #include + #include + #include ++#include + + + #ifdef SHARED +@@ -80,19 +81,6 @@ call_dl_lookup (void *ptr) + args->flags, NULL); + } + +-/* Return the link map containing the caller address. */ +-static inline struct link_map * +-find_caller_link_map (ElfW(Addr) caller) +-{ +- struct link_map *l = _dl_find_dso_for_object (caller); +- if (l != NULL) +- return l; +- else +- /* If the address is not recognized the call comes from the main +- program (we hope). */ +- return GL(dl_ns)[LM_ID_BASE]._ns_loaded; +-} +- + static void * + do_sym (void *handle, const char *name, void *who, + struct r_found_version *vers, int flags) +@@ -106,7 +94,7 @@ do_sym (void *handle, const char *name, void *who, + + if (handle == RTLD_DEFAULT) + { +- match = find_caller_link_map (caller); ++ match = _dl_sym_find_caller_link_map (caller); + + /* Search the global scope. We have the simple case where + we look up in the scope of an object which was part of +@@ -140,7 +128,7 @@ do_sym (void *handle, const char *name, void *who, + } + else if (handle == RTLD_NEXT) + { +- match = find_caller_link_map (caller); ++ match = _dl_sym_find_caller_link_map (caller); + + if (__glibc_unlikely (match == GL(dl_ns)[LM_ID_BASE]._ns_loaded)) + { +@@ -179,73 +167,7 @@ RTLD_NEXT used in code not dynamically loaded")); + #endif + value = DL_SYMBOL_ADDRESS (result, ref); + +- /* Resolve indirect function address. */ +- if (__glibc_unlikely (ELFW(ST_TYPE) (ref->st_info) == STT_GNU_IFUNC)) +- { +- DL_FIXUP_VALUE_TYPE fixup +- = DL_FIXUP_MAKE_VALUE (result, (ElfW(Addr)) value); +- fixup = elf_ifunc_invoke (DL_FIXUP_VALUE_ADDR (fixup)); +- value = (void *) DL_FIXUP_VALUE_CODE_ADDR (fixup); +- } +- +-#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. */ +- 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 = 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; +- } +- } +-#endif +- +- return value; ++ return _dl_sym_post (result, ref, value, caller, match); + } + + return NULL; diff --git a/SOURCES/glibc-rh1817513-41.patch b/SOURCES/glibc-rh1817513-41.patch new file mode 100644 index 0000000..0c00b3a --- /dev/null +++ b/SOURCES/glibc-rh1817513-41.patch @@ -0,0 +1,1102 @@ +commit 3a0ecccb599a6b1ad4b149dc569c0080e92d057b +Author: Florian Weimer +Date: Sat Feb 8 19:58:43 2020 +0100 + + ld.so: Do not export free/calloc/malloc/realloc functions [BZ #25486] + + Exporting functions and relying on symbol interposition from libc.so + makes the choice of implementation dependent on DT_NEEDED order, which + is not what some compiler drivers expect. + + This commit replaces one magic mechanism (symbol interposition) with + another one (preprocessor-/compiler-based redirection). This makes + the hand-over from the minimal malloc to the full malloc more + explicit. + + Removing the ABI symbols is backwards-compatible because libc.so is + always in scope, and the dynamic loader will find the malloc-related + symbols there since commit f0b2132b35248c1f4a80f62a2c38cddcc802aa8c + ("ld.so: Support moving versioned symbols between sonames + [BZ #24741]"). + + Reviewed-by: Carlos O'Donell + +Conflicts: + sysdeps/unix/sysv/linux/arm/le/ld.abilist + sysdeps/unix/sysv/linux/sh/le/ld.abilist + (Missing abilist split.) + sysdeps/unix/sysv/linux/csky/ld.abilist + sysdeps/unix/sysv/linux/csky/localplt.data + (Missing architecture.) + +diff --git a/elf/Makefile b/elf/Makefile +index a1ea44f231d8cec5..5b0aeccb0a53c182 100644 +--- a/elf/Makefile ++++ b/elf/Makefile +@@ -478,7 +478,11 @@ $(objpfx)dl-allobjs.os: $(all-rtld-routines:%=$(objpfx)%.os) + # their implementation is provided differently in rtld, and the symbol + # discovery mechanism is not compatible with the libc implementation + # when compiled for libc. +-rtld-stubbed-symbols = ++rtld-stubbed-symbols = \ ++ calloc \ ++ free \ ++ malloc \ ++ realloc \ + + # The GCC arguments that implement $(rtld-stubbed-symbols). + rtld-stubbed-symbols-args = \ +diff --git a/elf/Versions b/elf/Versions +index 3b09901f6c31e3d4..705489fc51f4ac5f 100644 +--- a/elf/Versions ++++ b/elf/Versions +@@ -35,9 +35,6 @@ libc { + + ld { + GLIBC_2.0 { +- # Functions which are interposed from libc.so. +- calloc; free; malloc; realloc; +- + _r_debug; + } + GLIBC_2.1 { +diff --git a/elf/dl-lookup.c b/elf/dl-lookup.c +index 42fdaed99296137f..e4c479de9a1fd6ec 100644 +--- a/elf/dl-lookup.c ++++ b/elf/dl-lookup.c +@@ -291,7 +291,7 @@ do_lookup_unique (const char *undef_name, uint_fast32_t new_hash, + tab->size = newsize; + size = newsize; + entries = tab->entries = newentries; +- tab->free = free; ++ tab->free = __rtld_free; + } + } + else +@@ -322,7 +322,7 @@ do_lookup_unique (const char *undef_name, uint_fast32_t new_hash, + + tab->entries = entries; + tab->size = size; +- tab->free = free; ++ tab->free = __rtld_free; + } + + if ((type_class & ELF_RTYPE_CLASS_COPY) != 0) +diff --git a/elf/dl-minimal.c b/elf/dl-minimal.c +index 25ceded6fe120b07..95ea7b024044864f 100644 +--- a/elf/dl-minimal.c ++++ b/elf/dl-minimal.c +@@ -26,11 +26,87 @@ + #include + #include + #include ++#include ++#include ++#include + #include <_itoa.h> + #include + + #include + ++/* The rtld startup code calls __rtld_malloc_init_stubs after the ++ first self-relocation to adjust the pointers to the minimal ++ implementation below. Before the final relocation, ++ __rtld_malloc_init_real is called to replace the pointers with the ++ real implementation. */ ++__typeof (calloc) *__rtld_calloc; ++__typeof (free) *__rtld_free; ++__typeof (malloc) *__rtld_malloc; ++__typeof (realloc) *__rtld_realloc; ++ ++/* Defined below. */ ++static __typeof (calloc) rtld_calloc attribute_relro; ++static __typeof (free) rtld_free attribute_relro; ++static __typeof (malloc) rtld_malloc attribute_relro; ++static __typeof (realloc) rtld_realloc attribute_relro; ++ ++void ++__rtld_malloc_init_stubs (void) ++{ ++ __rtld_calloc = &rtld_calloc; ++ __rtld_free = &rtld_free; ++ __rtld_malloc = &rtld_malloc; ++ __rtld_realloc = &rtld_realloc; ++} ++ ++/* Lookup NAME at VERSION in the scope of MATCH. */ ++static void * ++lookup_malloc_symbol (struct link_map *main_map, const char *name, ++ struct r_found_version *version) ++{ ++ ++ const ElfW(Sym) *ref = NULL; ++ lookup_t result = _dl_lookup_symbol_x (name, main_map, &ref, ++ main_map->l_scope, ++ version, 0, 0, NULL); ++ ++ assert (ELFW(ST_TYPE) (ref->st_info) != STT_TLS); ++ void *value = DL_SYMBOL_ADDRESS (result, ref); ++ ++ return _dl_sym_post (result, ref, value, 0, main_map); ++} ++ ++void ++__rtld_malloc_init_real (struct link_map *main_map) ++{ ++ /* We cannot use relocations and initializers for this because the ++ changes made by __rtld_malloc_init_stubs break REL-style ++ (non-RELA) relocations that depend on the previous pointer ++ contents. Also avoid direct relocation depedencies for the ++ malloc symbols so this function can be called before the final ++ rtld relocation (which enables RELRO, after which the pointer ++ variables cannot be written to). */ ++ ++ struct r_found_version version; ++ version.name = symbol_version_string (libc, GLIBC_2_0); ++ version.hidden = 0; ++ version.hash = _dl_elf_hash (version.name); ++ version.filename = NULL; ++ ++ 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); ++ ++ /* Update the pointers in one go, so that any internal allocations ++ performed by lookup_malloc_symbol see a consistent ++ implementation. */ ++ __rtld_calloc = new_calloc; ++ __rtld_free = new_free; ++ __rtld_malloc = new_malloc; ++ __rtld_realloc = new_realloc; ++} ++ + /* Minimal malloc allocator for used during initial link. After the + initial link, a full malloc implementation is interposed, either + the one in libc, or a different one supplied by the user through +@@ -38,14 +114,9 @@ + + static void *alloc_ptr, *alloc_end, *alloc_last_block; + +-/* Declarations of global functions. */ +-extern void weak_function free (void *ptr); +-extern void * weak_function realloc (void *ptr, size_t n); +- +- + /* Allocate an aligned memory block. */ +-void * weak_function +-malloc (size_t n) ++static void * ++rtld_malloc (size_t n) + { + if (alloc_end == 0) + { +@@ -87,8 +158,8 @@ malloc (size_t n) + /* We use this function occasionally since the real implementation may + be optimized when it can assume the memory it returns already is + set to NUL. */ +-void * weak_function +-calloc (size_t nmemb, size_t size) ++static void * ++rtld_calloc (size_t nmemb, size_t size) + { + /* New memory from the trivial malloc above is always already cleared. + (We make sure that's true in the rare occasion it might not be, +@@ -104,8 +175,8 @@ calloc (size_t nmemb, size_t size) + } + + /* This will rarely be called. */ +-void weak_function +-free (void *ptr) ++void ++rtld_free (void *ptr) + { + /* We can free only the last block allocated. */ + if (ptr == alloc_last_block) +@@ -118,8 +189,8 @@ free (void *ptr) + } + + /* This is only called with the most recent block returned by malloc. */ +-void * weak_function +-realloc (void *ptr, size_t n) ++void * ++rtld_realloc (void *ptr, size_t n) + { + if (ptr == NULL) + return malloc (n); +diff --git a/elf/rtld.c b/elf/rtld.c +index 18335bc666f2b89d..f755dc30331f799f 100644 +--- a/elf/rtld.c ++++ b/elf/rtld.c +@@ -532,6 +532,9 @@ _dl_start (void *arg) + header table in core. Put the rest of _dl_start into a separate + function, that way the compiler cannot put accesses to the GOT + before ELF_DYNAMIC_RELOCATE. */ ++ ++ __rtld_malloc_init_stubs (); ++ + { + #ifdef DONT_USE_BOOTSTRAP_MAP + ElfW(Addr) entry = _dl_start_final (arg); +@@ -2203,6 +2206,10 @@ ERROR: '%s': cannot process note segment.\n", _dl_argv[0]); + rtld_timer_stop (&relocate_time, start); + } + ++ /* The library defining malloc has already been relocated due to ++ prelinking. Resolve the malloc symbols for the dynamic ++ loader. */ ++ __rtld_malloc_init_real (main_map); + + /* Mark all the objects so we know they have been already relocated. */ + for (struct link_map *l = main_map; l != NULL; l = l->l_next) +@@ -2303,6 +2310,11 @@ ERROR: '%s': cannot process note segment.\n", _dl_argv[0]); + re-relocation, we might call a user-supplied function + (e.g. calloc from _dl_relocate_object) that uses TLS data. */ + ++ /* The malloc implementation has been relocated, so resolving ++ its symbols (and potentially calling IFUNC resolvers) is safe ++ at this point. */ ++ __rtld_malloc_init_real (main_map); ++ + RTLD_TIMING_VAR (start); + rtld_timer_start (&start); + +diff --git a/include/inline-hashtab.h b/include/inline-hashtab.h +index ad73650ecc59dec1..b658e4a54b9c8187 100644 +--- a/include/inline-hashtab.h ++++ b/include/inline-hashtab.h +@@ -53,7 +53,7 @@ htab_create (void) + return NULL; + ht->size = 3; + ht->entries = malloc (sizeof (void *) * ht->size); +- ht->free = free; ++ ht->free = __rtld_free; + if (! ht->entries) + { + if (ht->free) +@@ -172,7 +172,7 @@ htab_expand (struct hashtab *htab, int (*hash_fn) (void *)) + + /* Use the free() corresponding to the malloc() above to free this + up. */ +- htab->free = free; ++ htab->free = __rtld_free; + + return 1; + } +diff --git a/include/libc-symbols.h b/include/libc-symbols.h +index 8b9273c13a19f265..41436050d060b89f 100644 +--- a/include/libc-symbols.h ++++ b/include/libc-symbols.h +@@ -413,7 +413,14 @@ for linking") + # define _default_symbol_version(real, name, version) \ + __asm__ (".symver " #real "," #name "@@" #version) + # endif +-#else ++ ++/* Evalutes to a string literal for VERSION in LIB. */ ++# define symbol_version_string(lib, version) \ ++ _symbol_version_stringify_1 (VERSION_##lib##_##version) ++# define _symbol_version_stringify_1(arg) _symbol_version_stringify_2 (arg) ++# define _symbol_version_stringify_2(arg) #arg ++ ++#else /* !SHARED */ + # define symbol_version(real, name, version) + # define default_symbol_version(real, name, version) \ + strong_alias(real, name) +diff --git a/include/malloc.h b/include/malloc.h +index d4cd9a5ffc929a96..e528718ac0734e5e 100644 +--- a/include/malloc.h ++++ b/include/malloc.h +@@ -1,7 +1,9 @@ + #ifndef _MALLOC_H ++ + #include + + # ifndef _ISOMAC ++# include + + /* In the GNU libc we rename the global variable + `__malloc_initialized' to `__libc_malloc_initialized'. */ +diff --git a/include/rtld-malloc.h b/include/rtld-malloc.h +new file mode 100644 +index 0000000000000000..b026a3270cd24819 +--- /dev/null ++++ b/include/rtld-malloc.h +@@ -0,0 +1,85 @@ ++/* Redirection of malloc inside the dynamic linker. ++ 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 ++ . */ ++ ++/* The dynamic linker needs to use its own minimal malloc before libc ++ has been relocated, and the libc malloc afterwards. The active ++ malloc implementation is reached via the __rtld_* function pointers ++ declared below. They are initialized to the minimal malloc by ++ __rtld_malloc_init_stubs, and set to the final implementation by ++ __rtld_malloc_init_real. */ ++ ++#ifndef _RTLD_MALLOC_H ++#define _RTLD_MALLOC_H ++ ++#if IS_IN (rtld) ++ ++extern __typeof (calloc) *__rtld_calloc attribute_hidden; ++extern __typeof (free) *__rtld_free attribute_hidden; ++extern __typeof (malloc) *__rtld_malloc attribute_hidden; ++extern __typeof (realloc) *__rtld_realloc attribute_hidden; ++ ++/* Wrapper functions which call through the function pointers above. ++ Note that it is not supported to take the address of those ++ functions. Instead the function pointers must be used ++ directly. */ ++ ++__extern_inline void * ++calloc (size_t a, size_t b) ++{ ++ return __rtld_calloc (a, b); ++} ++ ++__extern_inline void ++free (void *ptr) ++{ ++ __rtld_free (ptr); ++} ++ ++__extern_inline void * ++malloc (size_t size) ++{ ++ return __rtld_malloc (size); ++} ++ ++__extern_inline void * ++realloc (void *ptr, size_t size) ++{ ++ return __rtld_realloc (ptr, size); ++} ++ ++/* Called after the first self-relocation to activate the minimal malloc ++ implementation. */ ++void __rtld_malloc_init_stubs (void) attribute_hidden; ++ ++/* Called shortly before the final self-relocation (when RELRO ++ variables are still writable) to activate the real malloc ++ implementation. MAIN_MAP is the link map of the executable. */ ++struct link_map; ++void __rtld_malloc_init_real (struct link_map *main_map) attribute_hidden; ++ ++#else /* !IS_IN (rtld) */ ++ ++/* This allows static/non-rtld builds to get a pointer to the ++ functions, in the same way that is required inside rtld. */ ++# define __rtld_calloc (&calloc) ++# define __rtld_free (&free) ++# define __rtld_malloc (&malloc) ++# define __rtld_realloc (&realloc) ++ ++#endif /* !IS_IN (rtld) */ ++#endif /* _RTLD_MALLOC_H */ +diff --git a/include/stdlib.h b/include/stdlib.h +index 114e12d255977676..d7720967448f2a8f 100644 +--- a/include/stdlib.h ++++ b/include/stdlib.h +@@ -9,6 +9,8 @@ + #if !defined _ISOMAC + # include + ++# include ++ + extern __typeof (strtol_l) __strtol_l; + extern __typeof (strtoul_l) __strtoul_l; + extern __typeof (strtoll_l) __strtoll_l; +diff --git a/sysdeps/generic/localplt.data b/sysdeps/generic/localplt.data +index 2d5c66ae28a2e851..e2083c0ce6869572 100644 +--- a/sysdeps/generic/localplt.data ++++ b/sysdeps/generic/localplt.data +@@ -7,12 +7,6 @@ libc.so: malloc + libc.so: memalign + libc.so: realloc + libm.so: matherr +-# The main malloc is interposed into the dynamic linker, for +-# allocations after the initial link (when dlopen is used). +-ld.so: malloc +-ld.so: calloc +-ld.so: realloc +-ld.so: free + # The TLS-enabled version of these functions is interposed from libc.so. + ld.so: _dl_signal_error + ld.so: _dl_catch_error +diff --git a/sysdeps/mach/hurd/i386/ld.abilist b/sysdeps/mach/hurd/i386/ld.abilist +index c76b913486acf6d8..6f591b249699e10c 100644 +--- a/sysdeps/mach/hurd/i386/ld.abilist ++++ b/sysdeps/mach/hurd/i386/ld.abilist +@@ -16,10 +16,6 @@ GLIBC_2.2.6 _dl_mcount F + GLIBC_2.2.6 _hurd_intr_rpc_mach_msg F + GLIBC_2.2.6 _r_debug D 0x14 + GLIBC_2.2.6 abort F +-GLIBC_2.2.6 calloc F +-GLIBC_2.2.6 free F +-GLIBC_2.2.6 malloc F +-GLIBC_2.2.6 realloc F + GLIBC_2.3 ___tls_get_addr F + GLIBC_2.3 __tls_get_addr F + GLIBC_2.4 __stack_chk_guard D 0x4 +diff --git a/sysdeps/mach/hurd/i386/localplt.data b/sysdeps/mach/hurd/i386/localplt.data +index a5b5241b84812425..4b9dbf5acc088cff 100644 +--- a/sysdeps/mach/hurd/i386/localplt.data ++++ b/sysdeps/mach/hurd/i386/localplt.data +@@ -9,12 +9,6 @@ libc.so: malloc + REL R_386_GLOB_DAT + libc.so: memalign + REL R_386_GLOB_DAT + libc.so: realloc + REL R_386_GLOB_DAT + libm.so: matherr + REL R_386_GLOB_DAT +-# The main malloc is interposed into the dynamic linker, for +-# allocations after the initial link (when dlopen is used). +-ld.so: malloc + REL R_386_GLOB_DAT +-ld.so: calloc + REL R_386_GLOB_DAT +-ld.so: realloc + REL R_386_GLOB_DAT +-ld.so: free + REL R_386_GLOB_DAT + # The TLS-enabled version of these functions is interposed from libc.so. + ld.so: _dl_signal_error + REL R_386_GLOB_DAT + ld.so: _dl_catch_error + REL R_386_GLOB_DAT +diff --git a/sysdeps/unix/sysv/linux/aarch64/ld.abilist b/sysdeps/unix/sysv/linux/aarch64/ld.abilist +index 4ffe688649ca02e2..80b2fe672541c6e9 100644 +--- a/sysdeps/unix/sysv/linux/aarch64/ld.abilist ++++ b/sysdeps/unix/sysv/linux/aarch64/ld.abilist +@@ -3,7 +3,3 @@ GLIBC_2.17 __stack_chk_guard D 0x8 + GLIBC_2.17 __tls_get_addr F + GLIBC_2.17 _dl_mcount F + GLIBC_2.17 _r_debug D 0x28 +-GLIBC_2.17 calloc F +-GLIBC_2.17 free F +-GLIBC_2.17 malloc F +-GLIBC_2.17 realloc F +diff --git a/sysdeps/unix/sysv/linux/aarch64/localplt.data b/sysdeps/unix/sysv/linux/aarch64/localplt.data +index 08af68b5e840b5d8..2c14b652efbfdf44 100644 +--- a/sysdeps/unix/sysv/linux/aarch64/localplt.data ++++ b/sysdeps/unix/sysv/linux/aarch64/localplt.data +@@ -12,12 +12,6 @@ libm.so: matherr + libc.so: __getauxval ? + # The dynamic loader needs __tls_get_addr for TLS. + ld.so: __tls_get_addr +-# The main malloc is interposed into the dynamic linker, for +-# allocations after the initial link (when dlopen is used). +-ld.so: malloc +-ld.so: calloc +-ld.so: realloc +-ld.so: free + # The TLS-enabled version of these functions is interposed from libc.so. + ld.so: _dl_signal_error + ld.so: _dl_catch_error +diff --git a/sysdeps/unix/sysv/linux/alpha/ld.abilist b/sysdeps/unix/sysv/linux/alpha/ld.abilist +index 98b66edabf1a79c7..98a03f611f98f3a4 100644 +--- a/sysdeps/unix/sysv/linux/alpha/ld.abilist ++++ b/sysdeps/unix/sysv/linux/alpha/ld.abilist +@@ -1,8 +1,4 @@ + GLIBC_2.0 _r_debug D 0x28 +-GLIBC_2.0 calloc F +-GLIBC_2.0 free F +-GLIBC_2.0 malloc F +-GLIBC_2.0 realloc F + GLIBC_2.1 __libc_stack_end D 0x8 + GLIBC_2.1 _dl_mcount F + GLIBC_2.3 __tls_get_addr F +diff --git a/sysdeps/unix/sysv/linux/alpha/localplt.data b/sysdeps/unix/sysv/linux/alpha/localplt.data +index c69eb04ce53e292e..43f6fdaea18b25f3 100644 +--- a/sysdeps/unix/sysv/linux/alpha/localplt.data ++++ b/sysdeps/unix/sysv/linux/alpha/localplt.data +@@ -26,12 +26,6 @@ libm.so: matherr + RELA R_ALPHA_GLOB_DAT + libm.so: __atan2 + # The dynamic loader needs __tls_get_addr for TLS. + ld.so: __tls_get_addr ? +-# The main malloc is interposed into the dynamic linker, for +-# allocations after the initial link (when dlopen is used). +-ld.so: malloc + RELA R_ALPHA_GLOB_DAT +-ld.so: calloc + RELA R_ALPHA_GLOB_DAT +-ld.so: realloc + RELA R_ALPHA_GLOB_DAT +-ld.so: free + RELA R_ALPHA_GLOB_DAT + # The TLS-enabled version of these functions is interposed from libc.so. + ld.so: _dl_signal_error + RELA R_ALPHA_GLOB_DAT + ld.so: _dl_catch_error + RELA R_ALPHA_GLOB_DAT +diff --git a/sysdeps/unix/sysv/linux/arm/ld.abilist b/sysdeps/unix/sysv/linux/arm/ld.abilist +index a301c6ebc49db1d7..cc8825c3bc68ad4a 100644 +--- a/sysdeps/unix/sysv/linux/arm/ld.abilist ++++ b/sysdeps/unix/sysv/linux/arm/ld.abilist +@@ -3,7 +3,3 @@ GLIBC_2.4 __stack_chk_guard D 0x4 + GLIBC_2.4 __tls_get_addr F + GLIBC_2.4 _dl_mcount F + GLIBC_2.4 _r_debug D 0x14 +-GLIBC_2.4 calloc F +-GLIBC_2.4 free F +-GLIBC_2.4 malloc F +-GLIBC_2.4 realloc F +diff --git a/sysdeps/unix/sysv/linux/arm/localplt.data b/sysdeps/unix/sysv/linux/arm/localplt.data +index 7bd541c28a842526..0c3af0c64e95df4b 100644 +--- a/sysdeps/unix/sysv/linux/arm/localplt.data ++++ b/sysdeps/unix/sysv/linux/arm/localplt.data +@@ -8,12 +8,6 @@ libm.so: matherr + libpthread.so: raise + # The dynamic loader needs __tls_get_addr for TLS. + ld.so: __tls_get_addr +-# The main malloc is interposed into the dynamic linker, for +-# allocations after the initial link (when dlopen is used). +-ld.so: malloc +-ld.so: calloc +-ld.so: realloc +-ld.so: free + # The TLS-enabled version of these functions is interposed from libc.so. + ld.so: _dl_signal_error + ld.so: _dl_catch_error +diff --git a/sysdeps/unix/sysv/linux/hppa/ld.abilist b/sysdeps/unix/sysv/linux/hppa/ld.abilist +index 0387614d8fd784eb..d155a59843df9091 100644 +--- a/sysdeps/unix/sysv/linux/hppa/ld.abilist ++++ b/sysdeps/unix/sysv/linux/hppa/ld.abilist +@@ -1,9 +1,5 @@ + GLIBC_2.2 __libc_stack_end D 0x4 + GLIBC_2.2 _dl_mcount F + GLIBC_2.2 _r_debug D 0x14 +-GLIBC_2.2 calloc F +-GLIBC_2.2 free F +-GLIBC_2.2 malloc F +-GLIBC_2.2 realloc F + GLIBC_2.3 __tls_get_addr F + GLIBC_2.4 __stack_chk_guard D 0x4 +diff --git a/sysdeps/unix/sysv/linux/hppa/localplt.data b/sysdeps/unix/sysv/linux/hppa/localplt.data +index 867413f0c54d3d71..09893d4dcfd3a1f3 100644 +--- a/sysdeps/unix/sysv/linux/hppa/localplt.data ++++ b/sysdeps/unix/sysv/linux/hppa/localplt.data +@@ -10,12 +10,6 @@ libc.so: __sigsetjmp + libc.so: _IO_funlockfile + libc.so: __errno_location + libm.so: matherr +-# The main malloc is interposed into the dynamic linker, for +-# allocations after the initial link (when dlopen is used). +-ld.so: malloc +-ld.so: calloc +-ld.so: realloc +-ld.so: free + # The TLS-enabled version of these functions is interposed from libc.so. + ld.so: _dl_signal_error + ld.so: _dl_catch_error +diff --git a/sysdeps/unix/sysv/linux/i386/ld.abilist b/sysdeps/unix/sysv/linux/i386/ld.abilist +index edb7307228110c33..0478e220712a55e6 100644 +--- a/sysdeps/unix/sysv/linux/i386/ld.abilist ++++ b/sysdeps/unix/sysv/linux/i386/ld.abilist +@@ -1,8 +1,4 @@ + GLIBC_2.0 _r_debug D 0x14 +-GLIBC_2.0 calloc F +-GLIBC_2.0 free F +-GLIBC_2.0 malloc F +-GLIBC_2.0 realloc F + GLIBC_2.1 __libc_stack_end D 0x4 + GLIBC_2.1 _dl_mcount F + GLIBC_2.3 ___tls_get_addr F +diff --git a/sysdeps/unix/sysv/linux/i386/localplt.data b/sysdeps/unix/sysv/linux/i386/localplt.data +index f6f20a5d15bc79e4..5334875b4b4a4dee 100644 +--- a/sysdeps/unix/sysv/linux/i386/localplt.data ++++ b/sysdeps/unix/sysv/linux/i386/localplt.data +@@ -7,12 +7,6 @@ libc.so: malloc + REL R_386_GLOB_DAT + libc.so: memalign + REL R_386_GLOB_DAT + libc.so: realloc + REL R_386_GLOB_DAT + libm.so: matherr + REL R_386_GLOB_DAT +-# The main malloc is interposed into the dynamic linker, for +-# allocations after the initial link (when dlopen is used). +-ld.so: malloc + REL R_386_GLOB_DAT +-ld.so: calloc + REL R_386_GLOB_DAT +-ld.so: realloc + REL R_386_GLOB_DAT +-ld.so: free + REL R_386_GLOB_DAT + # The TLS-enabled version of these functions is interposed from libc.so. + ld.so: _dl_signal_error + REL R_386_GLOB_DAT + ld.so: _dl_catch_error + REL R_386_GLOB_DAT +diff --git a/sysdeps/unix/sysv/linux/ia64/ld.abilist b/sysdeps/unix/sysv/linux/ia64/ld.abilist +index 82042472c3089a29..33f91199bfa516fb 100644 +--- a/sysdeps/unix/sysv/linux/ia64/ld.abilist ++++ b/sysdeps/unix/sysv/linux/ia64/ld.abilist +@@ -1,8 +1,4 @@ + GLIBC_2.2 __libc_stack_end D 0x8 + GLIBC_2.2 _dl_mcount F + GLIBC_2.2 _r_debug D 0x28 +-GLIBC_2.2 calloc F +-GLIBC_2.2 free F +-GLIBC_2.2 malloc F +-GLIBC_2.2 realloc F + GLIBC_2.3 __tls_get_addr F +diff --git a/sysdeps/unix/sysv/linux/ia64/localplt.data b/sysdeps/unix/sysv/linux/ia64/localplt.data +index 3820e2a4e682af2e..1c566a503e2eba00 100644 +--- a/sysdeps/unix/sysv/linux/ia64/localplt.data ++++ b/sysdeps/unix/sysv/linux/ia64/localplt.data +@@ -6,12 +6,6 @@ libc.so: realloc + libm.so: matherr + libm.so: matherrf + libm.so: matherrl +-# The main malloc is interposed into the dynamic linker, for +-# allocations after the initial link (when dlopen is used). +-ld.so: malloc +-ld.so: calloc +-ld.so: realloc +-ld.so: free + # The TLS-enabled version of these functions is interposed from libc.so. + ld.so: _dl_signal_error + ld.so: _dl_catch_error +diff --git a/sysdeps/unix/sysv/linux/m68k/coldfire/ld.abilist b/sysdeps/unix/sysv/linux/m68k/coldfire/ld.abilist +index a301c6ebc49db1d7..cc8825c3bc68ad4a 100644 +--- a/sysdeps/unix/sysv/linux/m68k/coldfire/ld.abilist ++++ b/sysdeps/unix/sysv/linux/m68k/coldfire/ld.abilist +@@ -3,7 +3,3 @@ GLIBC_2.4 __stack_chk_guard D 0x4 + GLIBC_2.4 __tls_get_addr F + GLIBC_2.4 _dl_mcount F + GLIBC_2.4 _r_debug D 0x14 +-GLIBC_2.4 calloc F +-GLIBC_2.4 free F +-GLIBC_2.4 malloc F +-GLIBC_2.4 realloc F +diff --git a/sysdeps/unix/sysv/linux/m68k/coldfire/localplt.data b/sysdeps/unix/sysv/linux/m68k/coldfire/localplt.data +index 4a07bf387e2da296..3c5efb7204281e2a 100644 +--- a/sysdeps/unix/sysv/linux/m68k/coldfire/localplt.data ++++ b/sysdeps/unix/sysv/linux/m68k/coldfire/localplt.data +@@ -5,12 +5,6 @@ libc.so: malloc + libc.so: memalign + libc.so: realloc + libm.so: matherr +-# The main malloc is interposed into the dynamic linker, for +-# allocations after the initial link (when dlopen is used). +-ld.so: malloc +-ld.so: calloc +-ld.so: realloc +-ld.so: free + # The TLS-enabled version of these functions is interposed from libc.so. + ld.so: _dl_signal_error + ld.so: _dl_catch_error +diff --git a/sysdeps/unix/sysv/linux/m68k/m680x0/ld.abilist b/sysdeps/unix/sysv/linux/m68k/m680x0/ld.abilist +index c9ec45cf1cf6c1c5..3ba474c27f62fb10 100644 +--- a/sysdeps/unix/sysv/linux/m68k/m680x0/ld.abilist ++++ b/sysdeps/unix/sysv/linux/m68k/m680x0/ld.abilist +@@ -1,8 +1,4 @@ + GLIBC_2.0 _r_debug D 0x14 +-GLIBC_2.0 calloc F +-GLIBC_2.0 free F +-GLIBC_2.0 malloc F +-GLIBC_2.0 realloc F + GLIBC_2.1 __libc_stack_end D 0x4 + GLIBC_2.1 _dl_mcount F + GLIBC_2.3 __tls_get_addr F +diff --git a/sysdeps/unix/sysv/linux/m68k/m680x0/localplt.data b/sysdeps/unix/sysv/linux/m68k/m680x0/localplt.data +index c70d6ea3011c4511..843f4e25f213d632 100644 +--- a/sysdeps/unix/sysv/linux/m68k/m680x0/localplt.data ++++ b/sysdeps/unix/sysv/linux/m68k/m680x0/localplt.data +@@ -6,12 +6,6 @@ libc.so: malloc + libc.so: memalign + libc.so: realloc + libm.so: matherr +-# The main malloc is interposed into the dynamic linker, for +-# allocations after the initial link (when dlopen is used). +-ld.so: malloc +-ld.so: calloc +-ld.so: realloc +-ld.so: free + # The TLS-enabled version of these functions is interposed from libc.so. + ld.so: _dl_signal_error + ld.so: _dl_catch_error +diff --git a/sysdeps/unix/sysv/linux/microblaze/ld.abilist b/sysdeps/unix/sysv/linux/microblaze/ld.abilist +index aa0d71150af8c62c..a4933c3541119538 100644 +--- a/sysdeps/unix/sysv/linux/microblaze/ld.abilist ++++ b/sysdeps/unix/sysv/linux/microblaze/ld.abilist +@@ -3,7 +3,3 @@ GLIBC_2.18 __stack_chk_guard D 0x4 + GLIBC_2.18 __tls_get_addr F + GLIBC_2.18 _dl_mcount F + GLIBC_2.18 _r_debug D 0x14 +-GLIBC_2.18 calloc F +-GLIBC_2.18 free F +-GLIBC_2.18 malloc F +-GLIBC_2.18 realloc F +diff --git a/sysdeps/unix/sysv/linux/microblaze/localplt.data b/sysdeps/unix/sysv/linux/microblaze/localplt.data +index 8ca23897dfa5b01c..0e98d5251ee14475 100644 +--- a/sysdeps/unix/sysv/linux/microblaze/localplt.data ++++ b/sysdeps/unix/sysv/linux/microblaze/localplt.data +@@ -7,12 +7,6 @@ libc.so: realloc + libm.so: matherr + # The dynamic loader needs __tls_get_addr for TLS. + ld.so: __tls_get_addr ? +-# The main malloc is interposed into the dynamic linker, for +-# allocations after the initial link (when dlopen is used). +-ld.so: malloc +-ld.so: calloc +-ld.so: realloc +-ld.so: free + # The TLS-enabled version of these functions is interposed from libc.so. + ld.so: _dl_signal_error + ld.so: _dl_catch_error +diff --git a/sysdeps/unix/sysv/linux/mips/mips32/ld.abilist b/sysdeps/unix/sysv/linux/mips/mips32/ld.abilist +index 55d48868e8b686dc..be09641a48962434 100644 +--- a/sysdeps/unix/sysv/linux/mips/mips32/ld.abilist ++++ b/sysdeps/unix/sysv/linux/mips/mips32/ld.abilist +@@ -1,8 +1,4 @@ + GLIBC_2.0 _r_debug D 0x14 +-GLIBC_2.0 calloc F +-GLIBC_2.0 free F +-GLIBC_2.0 malloc F +-GLIBC_2.0 realloc F + GLIBC_2.2 __libc_stack_end D 0x4 + GLIBC_2.2 _dl_mcount F + GLIBC_2.3 __tls_get_addr F +diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n32/ld.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n32/ld.abilist +index 55d48868e8b686dc..be09641a48962434 100644 +--- a/sysdeps/unix/sysv/linux/mips/mips64/n32/ld.abilist ++++ b/sysdeps/unix/sysv/linux/mips/mips64/n32/ld.abilist +@@ -1,8 +1,4 @@ + GLIBC_2.0 _r_debug D 0x14 +-GLIBC_2.0 calloc F +-GLIBC_2.0 free F +-GLIBC_2.0 malloc F +-GLIBC_2.0 realloc F + GLIBC_2.2 __libc_stack_end D 0x4 + GLIBC_2.2 _dl_mcount F + GLIBC_2.3 __tls_get_addr F +diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n64/ld.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n64/ld.abilist +index 44b345b7cf31e854..1ea36e13f294a249 100644 +--- a/sysdeps/unix/sysv/linux/mips/mips64/n64/ld.abilist ++++ b/sysdeps/unix/sysv/linux/mips/mips64/n64/ld.abilist +@@ -1,8 +1,4 @@ + GLIBC_2.0 _r_debug D 0x28 +-GLIBC_2.0 calloc F +-GLIBC_2.0 free F +-GLIBC_2.0 malloc F +-GLIBC_2.0 realloc F + GLIBC_2.2 __libc_stack_end D 0x8 + GLIBC_2.2 _dl_mcount F + GLIBC_2.3 __tls_get_addr F +diff --git a/sysdeps/unix/sysv/linux/nios2/ld.abilist b/sysdeps/unix/sysv/linux/nios2/ld.abilist +index 110f1039fa39fb1c..52178802dd82b59a 100644 +--- a/sysdeps/unix/sysv/linux/nios2/ld.abilist ++++ b/sysdeps/unix/sysv/linux/nios2/ld.abilist +@@ -3,7 +3,3 @@ GLIBC_2.21 __stack_chk_guard D 0x4 + GLIBC_2.21 __tls_get_addr F + GLIBC_2.21 _dl_mcount F + GLIBC_2.21 _r_debug D 0x14 +-GLIBC_2.21 calloc F +-GLIBC_2.21 free F +-GLIBC_2.21 malloc F +-GLIBC_2.21 realloc F +diff --git a/sysdeps/unix/sysv/linux/nios2/localplt.data b/sysdeps/unix/sysv/linux/nios2/localplt.data +index 4430a5891e847aed..39009a62d6385849 100644 +--- a/sysdeps/unix/sysv/linux/nios2/localplt.data ++++ b/sysdeps/unix/sysv/linux/nios2/localplt.data +@@ -27,12 +27,6 @@ libc.so: __nedf2 + libc.so: __eqdf2 + libc.so: __extendsfdf2 + libm.so: matherr +-# The main malloc is interposed into the dynamic linker, for +-# allocations after the initial link (when dlopen is used). +-ld.so: malloc +-ld.so: calloc +-ld.so: realloc +-ld.so: free + # The TLS-enabled version of these functions is interposed from libc.so. + ld.so: _dl_signal_error + ld.so: _dl_catch_error +diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/localplt.data b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/localplt.data +index e822e0a4809e5088..a02dd5cc246329a0 100644 +--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/localplt.data ++++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/localplt.data +@@ -5,12 +5,6 @@ libc.so: malloc + libc.so: memalign + libc.so: realloc + libm.so: matherr +-# The main malloc is interposed into the dynamic linker, for +-# allocations after the initial link (when dlopen is used). +-ld.so: malloc +-ld.so: calloc +-ld.so: realloc +-ld.so: free + # The TLS-enabled version of these functions is interposed from libc.so. + ld.so: _dl_signal_error + ld.so: _dl_catch_error +diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/ld.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/ld.abilist +index e8b0ea3a9bd98b92..4bbfba7a61c7a5ef 100644 +--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/ld.abilist ++++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/ld.abilist +@@ -1,8 +1,4 @@ + GLIBC_2.0 _r_debug D 0x14 +-GLIBC_2.0 calloc F +-GLIBC_2.0 free F +-GLIBC_2.0 malloc F +-GLIBC_2.0 realloc F + GLIBC_2.1 __libc_stack_end D 0x4 + GLIBC_2.1 _dl_mcount F + GLIBC_2.22 __tls_get_addr_opt F +diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/localplt.data b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/localplt.data +index fead931d4e5c4bc4..a4cd7cfb04249ae3 100644 +--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/localplt.data ++++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/localplt.data +@@ -35,12 +35,6 @@ libc.so: realloc + libm.so: copysignl ? + libm.so: fabsl + libm.so: matherr +-# The main malloc is interposed into the dynamic linker, for +-# allocations after the initial link (when dlopen is used). +-ld.so: malloc +-ld.so: calloc +-ld.so: realloc +-ld.so: free + # The TLS-enabled version of these functions is interposed from libc.so. + ld.so: _dl_signal_error + ld.so: _dl_catch_error +diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/ld-le.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/ld-le.abilist +index 37c8f6684b54341b..b1f313c7cd33defc 100644 +--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/ld-le.abilist ++++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/ld-le.abilist +@@ -2,9 +2,5 @@ GLIBC_2.17 __libc_stack_end D 0x8 + GLIBC_2.17 __tls_get_addr F + GLIBC_2.17 _dl_mcount F + GLIBC_2.17 _r_debug D 0x28 +-GLIBC_2.17 calloc F +-GLIBC_2.17 free F +-GLIBC_2.17 malloc F +-GLIBC_2.17 realloc F + GLIBC_2.22 __tls_get_addr_opt F + GLIBC_2.23 __parse_hwcap_and_convert_at_platform F +diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/ld.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/ld.abilist +index edfc9ca56f2e4fee..283fb4510bea40ba 100644 +--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/ld.abilist ++++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/ld.abilist +@@ -4,7 +4,3 @@ GLIBC_2.3 __libc_stack_end D 0x8 + GLIBC_2.3 __tls_get_addr F + GLIBC_2.3 _dl_mcount F + GLIBC_2.3 _r_debug D 0x28 +-GLIBC_2.3 calloc F +-GLIBC_2.3 free F +-GLIBC_2.3 malloc F +-GLIBC_2.3 realloc F +diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/localplt.data b/sysdeps/unix/sysv/linux/powerpc/powerpc64/localplt.data +index c1209336d2d339d4..bb498fbe3ae28d03 100644 +--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/localplt.data ++++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/localplt.data +@@ -4,12 +4,6 @@ libc.so: malloc + libc.so: memalign + libc.so: realloc + libm.so: matherr +-# The main malloc is interposed into the dynamic linker, for +-# allocations after the initial link (when dlopen is used). +-ld.so: malloc +-ld.so: calloc +-ld.so: realloc +-ld.so: free + # The TLS-enabled version of these functions is interposed from libc.so. + ld.so: _dl_signal_error + ld.so: _dl_catch_error +diff --git a/sysdeps/unix/sysv/linux/riscv/localplt.data b/sysdeps/unix/sysv/linux/riscv/localplt.data +index 14c02cb2d6c016d3..0ed8650b65a0ecbf 100644 +--- a/sysdeps/unix/sysv/linux/riscv/localplt.data ++++ b/sysdeps/unix/sysv/linux/riscv/localplt.data +@@ -6,12 +6,6 @@ libc.so: free + libc.so: malloc + libc.so: memalign + libc.so: realloc +-# The main malloc is interposed into the dynamic linker, for +-# allocations after the initial link (when dlopen is used). +-ld.so: malloc +-ld.so: calloc +-ld.so: realloc +-ld.so: free + # The TLS-enabled version of these functions is interposed from libc.so. + ld.so: _dl_signal_error + ld.so: _dl_catch_error +diff --git a/sysdeps/unix/sysv/linux/riscv/rv64/ld.abilist b/sysdeps/unix/sysv/linux/riscv/rv64/ld.abilist +index b411871d0631e1a3..845f356c3c3fad54 100644 +--- a/sysdeps/unix/sysv/linux/riscv/rv64/ld.abilist ++++ b/sysdeps/unix/sysv/linux/riscv/rv64/ld.abilist +@@ -3,7 +3,3 @@ 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 +-GLIBC_2.27 calloc F +-GLIBC_2.27 free F +-GLIBC_2.27 malloc F +-GLIBC_2.27 realloc F +diff --git a/sysdeps/unix/sysv/linux/s390/localplt.data b/sysdeps/unix/sysv/linux/s390/localplt.data +index e822e0a4809e5088..a02dd5cc246329a0 100644 +--- a/sysdeps/unix/sysv/linux/s390/localplt.data ++++ b/sysdeps/unix/sysv/linux/s390/localplt.data +@@ -5,12 +5,6 @@ libc.so: malloc + libc.so: memalign + libc.so: realloc + libm.so: matherr +-# The main malloc is interposed into the dynamic linker, for +-# allocations after the initial link (when dlopen is used). +-ld.so: malloc +-ld.so: calloc +-ld.so: realloc +-ld.so: free + # The TLS-enabled version of these functions is interposed from libc.so. + ld.so: _dl_signal_error + ld.so: _dl_catch_error +diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/ld.abilist b/sysdeps/unix/sysv/linux/s390/s390-32/ld.abilist +index 0576c9575ea6118e..b56f005bebd3baf1 100644 +--- a/sysdeps/unix/sysv/linux/s390/s390-32/ld.abilist ++++ b/sysdeps/unix/sysv/linux/s390/s390-32/ld.abilist +@@ -1,8 +1,4 @@ + GLIBC_2.0 _r_debug D 0x14 +-GLIBC_2.0 calloc F +-GLIBC_2.0 free F +-GLIBC_2.0 malloc F +-GLIBC_2.0 realloc F + GLIBC_2.1 __libc_stack_end D 0x4 + GLIBC_2.1 _dl_mcount F + GLIBC_2.3 __tls_get_offset F +diff --git a/sysdeps/unix/sysv/linux/s390/s390-64/ld.abilist b/sysdeps/unix/sysv/linux/s390/s390-64/ld.abilist +index 1fbb890d1dc495e5..6f788a086d68aaa5 100644 +--- a/sysdeps/unix/sysv/linux/s390/s390-64/ld.abilist ++++ b/sysdeps/unix/sysv/linux/s390/s390-64/ld.abilist +@@ -1,8 +1,4 @@ + GLIBC_2.2 __libc_stack_end D 0x8 + GLIBC_2.2 _dl_mcount F + GLIBC_2.2 _r_debug D 0x28 +-GLIBC_2.2 calloc F +-GLIBC_2.2 free F +-GLIBC_2.2 malloc F +-GLIBC_2.2 realloc F + GLIBC_2.3 __tls_get_offset F +diff --git a/sysdeps/unix/sysv/linux/sh/ld.abilist b/sysdeps/unix/sysv/linux/sh/ld.abilist +index 0387614d8fd784eb..d155a59843df9091 100644 +--- a/sysdeps/unix/sysv/linux/sh/ld.abilist ++++ b/sysdeps/unix/sysv/linux/sh/ld.abilist +@@ -1,9 +1,5 @@ + GLIBC_2.2 __libc_stack_end D 0x4 + GLIBC_2.2 _dl_mcount F + GLIBC_2.2 _r_debug D 0x14 +-GLIBC_2.2 calloc F +-GLIBC_2.2 free F +-GLIBC_2.2 malloc F +-GLIBC_2.2 realloc F + GLIBC_2.3 __tls_get_addr F + GLIBC_2.4 __stack_chk_guard D 0x4 +diff --git a/sysdeps/unix/sysv/linux/sh/localplt.data b/sysdeps/unix/sysv/linux/sh/localplt.data +index babb19d71785515d..3225177c50956972 100644 +--- a/sysdeps/unix/sysv/linux/sh/localplt.data ++++ b/sysdeps/unix/sysv/linux/sh/localplt.data +@@ -12,12 +12,6 @@ libc.so: __errno_location + libm.so: matherr + # Generated by the compiler because there is no trap insn pattern. + libc.so: abort ? +-# The main malloc is interposed into the dynamic linker, for +-# allocations after the initial link (when dlopen is used). +-ld.so: malloc +-ld.so: calloc +-ld.so: realloc +-ld.so: free + # The TLS-enabled version of these functions is interposed from libc.so. + ld.so: _dl_signal_error + ld.so: _dl_catch_error +diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/ld.abilist b/sysdeps/unix/sysv/linux/sparc/sparc32/ld.abilist +index fd0b33f86d3f9c5c..0c6610e3c2f00cf3 100644 +--- a/sysdeps/unix/sysv/linux/sparc/sparc32/ld.abilist ++++ b/sysdeps/unix/sysv/linux/sparc/sparc32/ld.abilist +@@ -1,8 +1,4 @@ + GLIBC_2.0 _r_debug D 0x14 +-GLIBC_2.0 calloc F +-GLIBC_2.0 free F +-GLIBC_2.0 malloc F +-GLIBC_2.0 realloc F + GLIBC_2.1 __libc_stack_end D 0x4 + GLIBC_2.1 _dl_mcount F + GLIBC_2.3 __tls_get_addr F +diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/localplt.data b/sysdeps/unix/sysv/linux/sparc/sparc32/localplt.data +index 1668f4017e0f28f0..be40910c4de9859a 100644 +--- a/sysdeps/unix/sysv/linux/sparc/sparc32/localplt.data ++++ b/sysdeps/unix/sysv/linux/sparc/sparc32/localplt.data +@@ -17,12 +17,6 @@ libc.so: malloc + libc.so: memalign + libc.so: realloc + libm.so: matherr +-# The main malloc is interposed into the dynamic linker, for +-# allocations after the initial link (when dlopen is used). +-ld.so: malloc +-ld.so: calloc +-ld.so: realloc +-ld.so: free + # The TLS-enabled version of these functions is interposed from libc.so. + ld.so: _dl_signal_error + ld.so: _dl_catch_error +diff --git a/sysdeps/unix/sysv/linux/sparc/sparc64/ld.abilist b/sysdeps/unix/sysv/linux/sparc/sparc64/ld.abilist +index 82042472c3089a29..33f91199bfa516fb 100644 +--- a/sysdeps/unix/sysv/linux/sparc/sparc64/ld.abilist ++++ b/sysdeps/unix/sysv/linux/sparc/sparc64/ld.abilist +@@ -1,8 +1,4 @@ + GLIBC_2.2 __libc_stack_end D 0x8 + GLIBC_2.2 _dl_mcount F + GLIBC_2.2 _r_debug D 0x28 +-GLIBC_2.2 calloc F +-GLIBC_2.2 free F +-GLIBC_2.2 malloc F +-GLIBC_2.2 realloc F + GLIBC_2.3 __tls_get_addr F +diff --git a/sysdeps/unix/sysv/linux/sparc/sparc64/localplt.data b/sysdeps/unix/sysv/linux/sparc/sparc64/localplt.data +index b881b9096d9fa38f..809062d46c1b4837 100644 +--- a/sysdeps/unix/sysv/linux/sparc/sparc64/localplt.data ++++ b/sysdeps/unix/sysv/linux/sparc/sparc64/localplt.data +@@ -18,12 +18,6 @@ libc.so: malloc + libc.so: memalign + libc.so: realloc + libm.so: matherr +-# The main malloc is interposed into the dynamic linker, for +-# allocations after the initial link (when dlopen is used). +-ld.so: malloc +-ld.so: calloc +-ld.so: realloc +-ld.so: free + # The TLS-enabled version of these functions is interposed from libc.so. + ld.so: _dl_signal_error + ld.so: _dl_catch_error +diff --git a/sysdeps/unix/sysv/linux/x86_64/64/ld.abilist b/sysdeps/unix/sysv/linux/x86_64/64/ld.abilist +index 0dc943061197d374..d3cdf7611eb9cab3 100644 +--- a/sysdeps/unix/sysv/linux/x86_64/64/ld.abilist ++++ b/sysdeps/unix/sysv/linux/x86_64/64/ld.abilist +@@ -1,8 +1,4 @@ + GLIBC_2.2.5 __libc_stack_end D 0x8 + GLIBC_2.2.5 _dl_mcount F + GLIBC_2.2.5 _r_debug D 0x28 +-GLIBC_2.2.5 calloc F +-GLIBC_2.2.5 free F +-GLIBC_2.2.5 malloc F +-GLIBC_2.2.5 realloc F + GLIBC_2.3 __tls_get_addr F +diff --git a/sysdeps/unix/sysv/linux/x86_64/x32/ld.abilist b/sysdeps/unix/sysv/linux/x86_64/x32/ld.abilist +index 80f3161586414674..c70bccf78245a552 100644 +--- a/sysdeps/unix/sysv/linux/x86_64/x32/ld.abilist ++++ b/sysdeps/unix/sysv/linux/x86_64/x32/ld.abilist +@@ -2,7 +2,3 @@ GLIBC_2.16 __libc_stack_end D 0x4 + GLIBC_2.16 __tls_get_addr F + GLIBC_2.16 _dl_mcount F + GLIBC_2.16 _r_debug D 0x14 +-GLIBC_2.16 calloc F +-GLIBC_2.16 free F +-GLIBC_2.16 malloc F +-GLIBC_2.16 realloc F +diff --git a/sysdeps/x86_64/localplt.data b/sysdeps/x86_64/localplt.data +index c27a02b66acd2ab4..8f41e928708d9a42 100644 +--- a/sysdeps/x86_64/localplt.data ++++ b/sysdeps/x86_64/localplt.data +@@ -9,12 +9,6 @@ libc.so: malloc + RELA R_X86_64_GLOB_DAT + libc.so: memalign + RELA R_X86_64_GLOB_DAT + libc.so: realloc + RELA R_X86_64_GLOB_DAT + libm.so: matherr + RELA R_X86_64_GLOB_DAT +-# The main malloc is interposed into the dynamic linker, for +-# allocations after the initial link (when dlopen is used). +-ld.so: malloc + RELA R_X86_64_GLOB_DAT +-ld.so: calloc + RELA R_X86_64_GLOB_DAT +-ld.so: realloc + RELA R_X86_64_GLOB_DAT +-ld.so: free + RELA R_X86_64_GLOB_DAT + # The TLS-enabled version of these functions is interposed from libc.so. + ld.so: _dl_signal_error + RELA R_X86_64_GLOB_DAT + ld.so: _dl_catch_error + RELA R_X86_64_GLOB_DAT diff --git a/SOURCES/glibc-rh1817513-42.patch b/SOURCES/glibc-rh1817513-42.patch new file mode 100644 index 0000000..473724f --- /dev/null +++ b/SOURCES/glibc-rh1817513-42.patch @@ -0,0 +1,46 @@ +commit 758599bc9dcc5764e862bd9e1613c5d1e6efc5d3 +Author: Florian Weimer +Date: Wed Feb 26 15:58:23 2020 +0100 + + elf: Apply attribute_relro to pointers in elf/dl-minimal.c + + The present code leaves the function pointers unprotected, but moves + some of the static functions into .data.rel.ro instead. This causes + the linker to produce an allocatable, executable, writable section + and eventually an RWX load segment. Not only do we really do not + want that, it also breaks valgrind because valgrind does not load + debuginfo from the mmap interceptor if all it sees are RX and RWX + mappings. + + Fixes commit 3a0ecccb599a6b1ad4b149dc569c0080e92d057b ("ld.so: Do not + export free/calloc/malloc/realloc functions [BZ #25486]"). + +diff --git a/elf/dl-minimal.c b/elf/dl-minimal.c +index 95ea7b024044864f..4335f1bd24289b01 100644 +--- a/elf/dl-minimal.c ++++ b/elf/dl-minimal.c +@@ -39,16 +39,16 @@ + implementation below. Before the final relocation, + __rtld_malloc_init_real is called to replace the pointers with the + real implementation. */ +-__typeof (calloc) *__rtld_calloc; +-__typeof (free) *__rtld_free; +-__typeof (malloc) *__rtld_malloc; +-__typeof (realloc) *__rtld_realloc; ++__typeof (calloc) *__rtld_calloc attribute_relro; ++__typeof (free) *__rtld_free attribute_relro; ++__typeof (malloc) *__rtld_malloc attribute_relro; ++__typeof (realloc) *__rtld_realloc attribute_relro; + + /* Defined below. */ +-static __typeof (calloc) rtld_calloc attribute_relro; +-static __typeof (free) rtld_free attribute_relro; +-static __typeof (malloc) rtld_malloc attribute_relro; +-static __typeof (realloc) rtld_realloc attribute_relro; ++static __typeof (calloc) rtld_calloc; ++static __typeof (free) rtld_free; ++static __typeof (malloc) rtld_malloc; ++static __typeof (realloc) rtld_realloc; + + void + __rtld_malloc_init_stubs (void) diff --git a/SOURCES/glibc-rh1817513-43.patch b/SOURCES/glibc-rh1817513-43.patch new file mode 100644 index 0000000..212bdc1 --- /dev/null +++ b/SOURCES/glibc-rh1817513-43.patch @@ -0,0 +1,356 @@ +commit dfe9aa91564c1bf2a23b5589a5db42f9da5d29b5 +Author: Adhemerval Zanella +Date: Tue Nov 19 17:17:05 2019 -0300 + + support: Add support_process_state_wait + + It allows parent process to wait for child state using a polling + strategy over procfs on Linux. The polling is used over ptrace to + avoid the need to handle signals on the target pid and to handle some + system specific limitation (such as YAMA). + + The polling has some limitations, such as resource consumption due + the procfs read in a loop and the lack of synchronization after the + state is obtained. + + The interface idea is to simplify some sleep synchronization waitid + tests and is to reduce timeouts by replacing arbitrary waits. + +diff --git a/support/Makefile b/support/Makefile +index 79d03bd6bfe02540..117cfdd4f22fc405 100644 +--- a/support/Makefile ++++ b/support/Makefile +@@ -58,6 +58,7 @@ libsupport-routines = \ + support_format_hostent \ + support_format_netent \ + support_isolate_in_subprocess \ ++ support_process_state \ + support_ptrace \ + support_openpty \ + support_paths \ +@@ -90,6 +91,7 @@ libsupport-routines = \ + xfopen \ + xfork \ + xftruncate \ ++ xgetline \ + xgetsockname \ + xlisten \ + xlseek \ +@@ -217,6 +219,7 @@ tests = \ + 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 \ +diff --git a/support/process_state.h b/support/process_state.h +new file mode 100644 +index 0000000000000000..6c19afdbb7462277 +--- /dev/null ++++ b/support/process_state.h +@@ -0,0 +1,43 @@ ++/* Wait for process state. ++ 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 ++ . */ ++ ++#ifndef SUPPORT_PROCESS_STATE_H ++#define SUPPORT_PROCESS_STATE_H ++ ++#include ++ ++enum support_process_state ++{ ++ support_process_state_running = 0x01, /* R (running). */ ++ support_process_state_sleeping = 0x02, /* S (sleeping). */ ++ support_process_state_disk_sleep = 0x04, /* D (disk sleep). */ ++ support_process_state_stopped = 0x08, /* T (stopped). */ ++ support_process_state_tracing_stop = 0x10, /* t (tracing stop). */ ++ support_process_state_dead = 0x20, /* X (dead). */ ++ support_process_state_zombie = 0x40, /* Z (zombie). */ ++ support_process_state_parked = 0x80, /* P (parked). */ ++}; ++ ++/* Wait for process PID to reach state STATE. It can be a combination of ++ multiple possible states ('process_state_running | process_state_sleeping') ++ where the function return when any of these state are observed. ++ For an invalid state not represented by SUPPORT_PROCESS_STATE, it fallbacks ++ to a 2 second sleep. */ ++void support_process_state_wait (pid_t pid, enum support_process_state state); ++ ++#endif +diff --git a/support/support_process_state.c b/support/support_process_state.c +new file mode 100644 +index 0000000000000000..76dc798728ece0d9 +--- /dev/null ++++ b/support/support_process_state.c +@@ -0,0 +1,92 @@ ++/* Wait for process state. ++ 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 ++ ++void ++support_process_state_wait (pid_t pid, enum support_process_state state) ++{ ++#ifdef __linux__ ++ /* For Linux it does a polling check on /proc//status checking on ++ third field. */ ++ ++ /* It mimics the kernel states from fs/proc/array.c */ ++ static const struct process_states ++ { ++ enum support_process_state s; ++ char v; ++ } process_states[] = { ++ { support_process_state_running, 'R' }, ++ { support_process_state_sleeping, 'S' }, ++ { support_process_state_disk_sleep, 'D' }, ++ { support_process_state_stopped, 'T' }, ++ { support_process_state_tracing_stop, 't' }, ++ { support_process_state_dead, 'X' }, ++ { support_process_state_zombie, 'Z' }, ++ { support_process_state_parked, 'P' }, ++ }; ++ ++ char spath[sizeof ("/proc/" + 3) * sizeof (pid_t) + sizeof ("/status") + 1]; ++ snprintf (spath, sizeof (spath), "/proc/%i/status", pid); ++ ++ FILE *fstatus = xfopen (spath, "r"); ++ char *line = NULL; ++ size_t linesiz = 0; ++ ++ for (;;) ++ { ++ char cur_state = -1; ++ while (xgetline (&line, &linesiz, fstatus) != -1) ++ if (strncmp (line, "State:", strlen ("State:")) == 0) ++ { ++ TEST_COMPARE (sscanf (line, "%*s %c", &cur_state), 1); ++ break; ++ } ++ /* Fallback to nanosleep for invalid state. */ ++ if (cur_state == -1) ++ break; ++ ++ for (size_t i = 0; i < array_length (process_states); ++i) ++ if (state & process_states[i].s && cur_state == process_states[i].v) ++ { ++ free (line); ++ xfclose (fstatus); ++ return; ++ } ++ ++ rewind (fstatus); ++ fflush (fstatus); ++ ++ if (nanosleep (&(struct timespec) { 0, 10000000 }, NULL) != 0) ++ FAIL_EXIT1 ("nanosleep: %m"); ++ } ++ ++ free (line); ++ xfclose (fstatus); ++ /* Fallback to nanosleep if an invalid state is found. */ ++#endif ++ nanosleep (&(struct timespec) { 2, 0 }, NULL); ++} +diff --git a/support/tst-support-process_state.c b/support/tst-support-process_state.c +new file mode 100644 +index 0000000000000000..3fc103ab9205ddb0 +--- /dev/null ++++ b/support/tst-support-process_state.c +@@ -0,0 +1,105 @@ ++/* Wait for process state tests. ++ 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 ++ ++#ifndef WEXITED ++# define WEXITED 0 ++#endif ++ ++static void ++sigusr1_handler (int signo) ++{ ++} ++ ++static void ++test_child (void) ++{ ++ xsignal (SIGUSR1, sigusr1_handler); ++ ++ raise (SIGSTOP); ++ ++ TEST_COMPARE (pause (), -1); ++ TEST_COMPARE (errno, EINTR); ++ ++ while (1) ++ asm (""); ++} ++ ++static int ++do_test (void) ++{ ++ pid_t pid = xfork (); ++ if (pid == 0) ++ { ++ test_child (); ++ _exit (127); ++ } ++ ++ /* Adding process_state_tracing_stop ('t') allows the test to work under ++ trace programs such as ptrace. */ ++ enum support_process_state stop_state = support_process_state_stopped ++ | support_process_state_tracing_stop; ++ ++ if (test_verbose) ++ printf ("info: waiting pid %d, state_stopped/state_tracing_stop\n", ++ (int) pid); ++ support_process_state_wait (pid, stop_state); ++ ++ if (kill (pid, SIGCONT) != 0) ++ FAIL_RET ("kill (%d, SIGCONT): %m\n", pid); ++ ++ if (test_verbose) ++ printf ("info: waiting pid %d, state_sleeping\n", (int) pid); ++ support_process_state_wait (pid, support_process_state_sleeping); ++ ++ if (kill (pid, SIGUSR1) != 0) ++ FAIL_RET ("kill (%d, SIGUSR1): %m\n", pid); ++ ++ if (test_verbose) ++ printf ("info: waiting pid %d, state_running\n", (int) pid); ++ support_process_state_wait (pid, support_process_state_running); ++ ++ if (kill (pid, SIGKILL) != 0) ++ FAIL_RET ("kill (%d, SIGKILL): %m\n", pid); ++ ++ if (test_verbose) ++ printf ("info: waiting pid %d, state_zombie\n", (int) pid); ++ support_process_state_wait (pid, support_process_state_zombie); ++ ++ siginfo_t info; ++ int r = waitid (P_PID, pid, &info, WEXITED); ++ TEST_COMPARE (r, 0); ++ TEST_COMPARE (info.si_signo, SIGCHLD); ++ TEST_COMPARE (info.si_code, CLD_KILLED); ++ TEST_COMPARE (info.si_status, SIGKILL); ++ TEST_COMPARE (info.si_pid, pid); ++ ++ return 0; ++} ++ ++#include +diff --git a/support/xgetline.c b/support/xgetline.c +new file mode 100644 +index 0000000000000000..180bc2db95a9c5d4 +--- /dev/null ++++ b/support/xgetline.c +@@ -0,0 +1,33 @@ ++/* fopen with error checking. ++ 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 ++ ++ssize_t ++xgetline (char **lineptr, size_t *n, FILE *stream) ++{ ++ int old_errno = errno; ++ errno = 0; ++ size_t ret = getline (lineptr, n, stream); ++ if (!feof (stream) && ferror (stream)) ++ FAIL_EXIT1 ("getline failed: %m"); ++ errno = old_errno; ++ return ret; ++} +diff --git a/support/xstdio.h b/support/xstdio.h +index e7d0274474706380..9446b1f27b0f881e 100644 +--- a/support/xstdio.h ++++ b/support/xstdio.h +@@ -27,6 +27,8 @@ __BEGIN_DECLS + FILE *xfopen (const char *path, const char *mode); + void xfclose (FILE *); + ++ssize_t xgetline (char **lineptr, size_t *n, FILE *stream); ++ + __END_DECLS + + #endif /* SUPPORT_XSTDIO_H */ diff --git a/SOURCES/glibc-rh1817513-44.patch b/SOURCES/glibc-rh1817513-44.patch new file mode 100644 index 0000000..1b591b4 --- /dev/null +++ b/SOURCES/glibc-rh1817513-44.patch @@ -0,0 +1,24 @@ +commit 083d644d420f49c992667f4c7a54848ad3dee54d +Author: Michael Hudson-Doyle +Date: Wed Mar 11 13:05:25 2020 +1300 + + test-container: print errno when execvp fails + + I'm debugging a situation where lots of tests using test-container fail + and it's possible knowing errno would help understand why. + + Reviewed-by: DJ Delorie + +diff --git a/support/test-container.c b/support/test-container.c +index 9488ec7b4a824380..9eff8baeef0e9d8a 100644 +--- a/support/test-container.c ++++ b/support/test-container.c +@@ -1145,7 +1145,7 @@ main (int argc, char **argv) + execvp (new_child_exec, new_child_proc); + + /* Or don't run the child? */ +- FAIL_EXIT1 ("Unable to exec %s\n", new_child_exec); ++ FAIL_EXIT1 ("Unable to exec %s: %s\n", new_child_exec, strerror (errno)); + + /* Because gcc won't know error () never returns... */ + exit (EXIT_UNSUPPORTED); diff --git a/SOURCES/glibc-rh1817513-45.patch b/SOURCES/glibc-rh1817513-45.patch new file mode 100644 index 0000000..b578717 --- /dev/null +++ b/SOURCES/glibc-rh1817513-45.patch @@ -0,0 +1,106 @@ +commit b7176cc2aff4a8883e4834ddf65f8a6fdb1f160e +Author: DJ Delorie +Date: Wed Feb 19 12:31:38 2020 -0500 + + ldconfig: trace origin paths with -v + + With this patch, -v turns on a "from" trace for each directory + searched, that tells you WHY that directory is being searched - + is it a builtin, from the command line, or from some config file? + +diff --git a/elf/ldconfig.c b/elf/ldconfig.c +index ed7d9ab0412d93fd..5e6516688a1c192a 100644 +--- a/elf/ldconfig.c ++++ b/elf/ldconfig.c +@@ -79,6 +79,8 @@ struct dir_entry + int flag; + ino64_t ino; + dev_t dev; ++ const char *from_file; ++ int from_line; + struct dir_entry *next; + }; + +@@ -344,7 +346,12 @@ add_single_dir (struct dir_entry *entry, int verbose) + if (ptr->ino == entry->ino && ptr->dev == entry->dev) + { + if (opt_verbose && verbose) +- error (0, 0, _("Path `%s' given more than once"), entry->path); ++ { ++ error (0, 0, _("Path `%s' given more than once"), entry->path); ++ fprintf (stderr, _("(from %s:%d and %s:%d)\n"), ++ entry->from_file, entry->from_line, ++ ptr->from_file, ptr->from_line); ++ } + /* Use the newer information. */ + ptr->flag = entry->flag; + free (entry->path); +@@ -363,12 +370,15 @@ add_single_dir (struct dir_entry *entry, int verbose) + + /* Add one directory to the list of directories to process. */ + static void +-add_dir (const char *line) ++add_dir_1 (const char *line, const char *from_file, int from_line) + { + unsigned int i; + struct dir_entry *entry = xmalloc (sizeof (struct dir_entry)); + entry->next = NULL; + ++ entry->from_file = strdup (from_file); ++ entry->from_line = from_line; ++ + /* Search for an '=' sign. */ + entry->path = xstrdup (line); + char *equal_sign = strchr (entry->path, '='); +@@ -428,6 +438,11 @@ add_dir (const char *line) + free (path); + } + ++static void ++add_dir (const char *line) ++{ ++ add_dir_1 (line, "", 0); ++} + + static int + chroot_stat (const char *real_path, const char *path, struct stat64 *st) +@@ -672,9 +687,10 @@ search_dir (const struct dir_entry *entry) + if (opt_verbose) + { + if (hwcap != 0) +- printf ("%s: (hwcap: %#.16" PRIx64 ")\n", entry->path, hwcap); ++ printf ("%s: (hwcap: %#.16" PRIx64 ")", entry->path, hwcap); + else +- printf ("%s:\n", entry->path); ++ printf ("%s:", entry->path); ++ printf (_(" (from %s:%d)\n"), entry->from_file, entry->from_line); + } + + char *dir_name; +@@ -815,6 +831,8 @@ search_dir (const struct dir_entry *entry) + struct dir_entry *new_entry; + + new_entry = xmalloc (sizeof (struct dir_entry)); ++ new_entry->from_file = entry->from_file; ++ new_entry->from_line = entry->from_line; + new_entry->path = xstrdup (file_name); + new_entry->flag = entry->flag; + new_entry->next = NULL; +@@ -1174,7 +1192,7 @@ Warning: ignoring configuration file that cannot be opened: %s"), + } + } + else +- add_dir (cp); ++ add_dir_1 (cp, filename, lineno); + } + while (!feof_unlocked (file)); + +@@ -1282,7 +1300,7 @@ main (int argc, char **argv) + _("relative path `%s' used to build cache"), + argv[i]); + else +- add_dir (argv[i]); ++ add_dir_1 (argv[i], "", 0); + } + + /* The last entry in hwcap_extra is reserved for the "tls" pseudo-hwcap which diff --git a/SOURCES/glibc-rh1817513-46.patch b/SOURCES/glibc-rh1817513-46.patch new file mode 100644 index 0000000..7947d9f --- /dev/null +++ b/SOURCES/glibc-rh1817513-46.patch @@ -0,0 +1,83 @@ +commit cea56af185eae45b1f0963351e3d4daa1cbde521 +Author: Florian Weimer +Date: Thu Apr 2 17:09:36 2020 +0200 + + support: Change xgetline to return 0 on EOF + + The advantage is that the buffer will always contain the number + of characters as returned from the function, which allows one to use + a sequence like + + /* No more audit module output. */ + line_length = xgetline (&buffer, &buffer_length, fp); + TEST_COMPARE_BLOB ("", 0, buffer, line_length); + + to check for an expected EOF, while also reporting any unexpected + extra data encountered. + + Reviewed-by: Carlos O'Donell + +diff --git a/support/support_process_state.c b/support/support_process_state.c +index 76dc798728ece0d9..e303c78fc874b2f9 100644 +--- a/support/support_process_state.c ++++ b/support/support_process_state.c +@@ -59,7 +59,7 @@ support_process_state_wait (pid_t pid, enum support_process_state state) + for (;;) + { + char cur_state = -1; +- while (xgetline (&line, &linesiz, fstatus) != -1) ++ while (xgetline (&line, &linesiz, fstatus) > 0) + if (strncmp (line, "State:", strlen ("State:")) == 0) + { + TEST_COMPARE (sscanf (line, "%*s %c", &cur_state), 1); +diff --git a/support/xgetline.c b/support/xgetline.c +index 180bc2db95a9c5d4..d91c09ac108b4c75 100644 +--- a/support/xgetline.c ++++ b/support/xgetline.c +@@ -18,16 +18,22 @@ + + #include + #include +-#include + +-ssize_t ++size_t + xgetline (char **lineptr, size_t *n, FILE *stream) + { +- int old_errno = errno; +- errno = 0; +- size_t ret = getline (lineptr, n, stream); +- if (!feof (stream) && ferror (stream)) +- FAIL_EXIT1 ("getline failed: %m"); +- errno = old_errno; ++ TEST_VERIFY (!ferror (stream)); ++ ssize_t ret = getline (lineptr, n, stream); ++ if (ferror (stream)) ++ { ++ TEST_VERIFY (ret < 0); ++ FAIL_EXIT1 ("getline: %m"); ++ } ++ if (feof (stream)) ++ { ++ TEST_VERIFY (ret <= 0); ++ return 0; ++ } ++ TEST_VERIFY (ret > 0); + return ret; + } +diff --git a/support/xstdio.h b/support/xstdio.h +index 9446b1f27b0f881e..36071cf78822ec8d 100644 +--- a/support/xstdio.h ++++ b/support/xstdio.h +@@ -27,7 +27,10 @@ __BEGIN_DECLS + FILE *xfopen (const char *path, const char *mode); + void xfclose (FILE *); + +-ssize_t xgetline (char **lineptr, size_t *n, FILE *stream); ++/* Read a line from FP, using getline. *BUFFER must be NULL, or a ++ heap-allocated pointer of *LENGTH bytes. Return the number of ++ bytes in the line if a line was read, or 0 on EOF. */ ++size_t xgetline (char **lineptr, size_t *n, FILE *stream); + + __END_DECLS + diff --git a/SOURCES/glibc-rh1817513-47.patch b/SOURCES/glibc-rh1817513-47.patch new file mode 100644 index 0000000..ef5036c --- /dev/null +++ b/SOURCES/glibc-rh1817513-47.patch @@ -0,0 +1,373 @@ +commit 4c6e0415ef206a595c62d5d37e3b9a821782c533 +Author: Florian Weimer +Date: Fri Apr 3 13:17:48 2020 +0200 + + elf: Simplify handling of lists of audit strings + + All list elements are colon-separated strings, and there is a hard + upper limit for the number of audit modules, so it is possible to + pre-allocate a fixed-size array of strings to which the LD_AUDIT + environment variable and --audit arguments are added. + + Also eliminate the global variables for the audit list because + the list is only needed briefly during startup. + + There is a slight behavior change: All duplicate LD_AUDIT environment + variables are now processed, not just the last one as before. However, + such environment vectors are invalid anyway. + + Reviewed-by: Carlos O'Donell + +diff --git a/elf/rtld.c b/elf/rtld.c +index f755dc30331f799f..c39cb8f2cd4bb1cc 100644 +--- a/elf/rtld.c ++++ b/elf/rtld.c +@@ -43,6 +43,7 @@ + #include + #include + #include ++#include + + #include + +@@ -107,8 +108,53 @@ static void print_missing_version (int errcode, const char *objname, + /* Print the various times we collected. */ + static void print_statistics (const hp_timing_t *total_timep); + +-/* Add audit objects. */ +-static void process_dl_audit (char *str); ++/* Length limits for names and paths, to protect the dynamic linker, ++ particularly when __libc_enable_secure is active. */ ++#ifdef NAME_MAX ++# define SECURE_NAME_LIMIT NAME_MAX ++#else ++# define SECURE_NAME_LIMIT 255 ++#endif ++#ifdef PATH_MAX ++# define SECURE_PATH_LIMIT PATH_MAX ++#else ++# define SECURE_PATH_LIMIT 1024 ++#endif ++ ++/* Strings containing colon-separated lists of audit modules. */ ++struct audit_list ++{ ++ /* Array of strings containing colon-separated path lists. Each ++ audit module needs its own namespace, so pre-allocate the largest ++ possible list. */ ++ const char *audit_strings[DL_NNS]; ++ ++ /* Number of entries added to audit_strings. */ ++ size_t length; ++ ++ /* Index into the audit_strings array (for the iteration phase). */ ++ size_t current_index; ++ ++ /* Tail of audit_strings[current_index] which still needs ++ processing. */ ++ const char *current_tail; ++ ++ /* Scratch buffer for returning a name which is part of the strings ++ in audit_strings. */ ++ char fname[SECURE_NAME_LIMIT]; ++}; ++ ++/* Creates an empty audit list. */ ++static void audit_list_init (struct audit_list *); ++ ++/* Add a string to the end of the audit list, for later parsing. Must ++ not be called after audit_list_next. */ ++static void audit_list_add_string (struct audit_list *, const char *); ++ ++/* Extract the next audit module from the audit list. Only modules ++ for which dso_name_valid_for_suid is true are returned. Must be ++ called after all the audit_list_add_string calls. */ ++static const char *audit_list_next (struct audit_list *); + + /* This is a list of all the modes the dynamic loader can be in. */ + enum mode { normal, list, verify, trace }; +@@ -116,7 +162,7 @@ enum mode { normal, list, verify, trace }; + /* Process all environments variables the dynamic linker must recognize. + Since all of them start with `LD_' we are a bit smarter while finding + all the entries. */ +-static void process_envvars (enum mode *modep); ++static void process_envvars (enum mode *modep, struct audit_list *); + + #ifdef DL_ARGV_NOT_RELRO + int _dl_argc attribute_hidden; +@@ -144,19 +190,6 @@ uintptr_t __pointer_chk_guard_local + strong_alias (__pointer_chk_guard_local, __pointer_chk_guard) + #endif + +-/* Length limits for names and paths, to protect the dynamic linker, +- particularly when __libc_enable_secure is active. */ +-#ifdef NAME_MAX +-# define SECURE_NAME_LIMIT NAME_MAX +-#else +-# define SECURE_NAME_LIMIT 255 +-#endif +-#ifdef PATH_MAX +-# define SECURE_PATH_LIMIT PATH_MAX +-#else +-# define SECURE_PATH_LIMIT 1024 +-#endif +- + /* Check that AT_SECURE=0, or that the passed name does not contain + directories and is not overly long. Reject empty names + unconditionally. */ +@@ -174,89 +207,75 @@ dso_name_valid_for_suid (const char *p) + return *p != '\0'; + } + +-/* LD_AUDIT variable contents. Must be processed before the +- audit_list below. */ +-const char *audit_list_string; +- +-/* Cyclic list of auditing DSOs. audit_list->next is the first +- element. */ +-static struct audit_list ++static void ++audit_list_init (struct audit_list *list) + { +- const char *name; +- struct audit_list *next; +-} *audit_list; ++ list->length = 0; ++ list->current_index = 0; ++ list->current_tail = NULL; ++} + +-/* Iterator for audit_list_string followed by audit_list. */ +-struct audit_list_iter ++static void ++audit_list_add_string (struct audit_list *list, const char *string) + { +- /* Tail of audit_list_string still needing processing, or NULL. */ +- const char *audit_list_tail; ++ /* Empty strings do not load anything. */ ++ if (*string == '\0') ++ return; + +- /* The list element returned in the previous iteration. NULL before +- the first element. */ +- struct audit_list *previous; ++ if (list->length == array_length (list->audit_strings)) ++ _dl_fatal_printf ("Fatal glibc error: Too many audit modules requested\n"); + +- /* Scratch buffer for returning a name which is part of +- audit_list_string. */ +- char fname[SECURE_NAME_LIMIT]; +-}; ++ list->audit_strings[list->length++] = string; + +-/* Initialize an audit list iterator. */ +-static void +-audit_list_iter_init (struct audit_list_iter *iter) +-{ +- iter->audit_list_tail = audit_list_string; +- iter->previous = NULL; ++ /* Initialize processing of the first string for ++ audit_list_next. */ ++ if (list->length == 1) ++ list->current_tail = string; + } + +-/* Iterate through both audit_list_string and audit_list. */ + static const char * +-audit_list_iter_next (struct audit_list_iter *iter) ++audit_list_next (struct audit_list *list) + { +- if (iter->audit_list_tail != NULL) ++ if (list->current_tail == NULL) ++ return NULL; ++ ++ while (true) + { +- /* First iterate over audit_list_string. */ +- while (*iter->audit_list_tail != '\0') ++ /* Advance to the next string in audit_strings if the current ++ string has been exhausted. */ ++ while (*list->current_tail == '\0') + { +- /* Split audit list at colon. */ +- size_t len = strcspn (iter->audit_list_tail, ":"); +- if (len > 0 && len < sizeof (iter->fname)) ++ ++list->current_index; ++ if (list->current_index == list->length) + { +- memcpy (iter->fname, iter->audit_list_tail, len); +- iter->fname[len] = '\0'; ++ list->current_tail = NULL; ++ return NULL; + } +- else +- /* Do not return this name to the caller. */ +- iter->fname[0] = '\0'; +- +- /* Skip over the substring and the following delimiter. */ +- iter->audit_list_tail += len; +- if (*iter->audit_list_tail == ':') +- ++iter->audit_list_tail; +- +- /* If the name is valid, return it. */ +- if (dso_name_valid_for_suid (iter->fname)) +- return iter->fname; +- /* Otherwise, wrap around and try the next name. */ ++ list->current_tail = list->audit_strings[list->current_index]; + } +- /* Fall through to the procesing of audit_list. */ +- } + +- if (iter->previous == NULL) +- { +- if (audit_list == NULL) +- /* No pre-parsed audit list. */ +- return NULL; +- /* Start of audit list. The first list element is at +- audit_list->next (cyclic list). */ +- iter->previous = audit_list->next; +- return iter->previous->name; ++ /* Split the in-string audit list at the next colon colon. */ ++ size_t len = strcspn (list->current_tail, ":"); ++ if (len > 0 && len < sizeof (list->fname)) ++ { ++ memcpy (list->fname, list->current_tail, len); ++ list->fname[len] = '\0'; ++ } ++ else ++ /* Mark the name as unusable for dso_name_valid_for_suid. */ ++ list->fname[0] = '\0'; ++ ++ /* Skip over the substring and the following delimiter. */ ++ list->current_tail += len; ++ if (*list->current_tail == ':') ++ ++list->current_tail; ++ ++ /* If the name is valid, return it. */ ++ if (dso_name_valid_for_suid (list->fname)) ++ return list->fname; ++ ++ /* Otherwise wrap around to find the next list element. . */ + } +- if (iter->previous == audit_list) +- /* Cyclic list wrap-around. */ +- return NULL; +- iter->previous = iter->previous->next; +- return iter->previous->name; + } + + /* Set nonzero during loading and initialization of executable and +@@ -1060,15 +1079,13 @@ notify_audit_modules_of_loaded_object (struct link_map *map) + + /* Load all audit modules. */ + static void +-load_audit_modules (struct link_map *main_map) ++load_audit_modules (struct link_map *main_map, struct audit_list *audit_list) + { + struct audit_ifaces *last_audit = NULL; +- struct audit_list_iter al_iter; +- audit_list_iter_init (&al_iter); + + while (true) + { +- const char *name = audit_list_iter_next (&al_iter); ++ const char *name = audit_list_next (audit_list); + if (name == NULL) + break; + load_audit_module (name, &last_audit); +@@ -1100,6 +1117,9 @@ dl_main (const ElfW(Phdr) *phdr, + bool rtld_is_main = false; + void *tcbp = NULL; + ++ struct audit_list audit_list; ++ audit_list_init (&audit_list); ++ + GL(dl_init_static_tls) = &_dl_nothread_init_static_tls; + + #if defined SHARED && defined _LIBC_REENTRANT \ +@@ -1113,7 +1133,7 @@ dl_main (const ElfW(Phdr) *phdr, + GL(dl_make_stack_executable_hook) = &_dl_make_stack_executable; + + /* Process the environment variable which control the behaviour. */ +- process_envvars (&mode); ++ process_envvars (&mode, &audit_list); + + /* Set up a flag which tells we are just starting. */ + _dl_starting_up = 1; +@@ -1185,7 +1205,7 @@ dl_main (const ElfW(Phdr) *phdr, + } + else if (! strcmp (_dl_argv[1], "--audit") && _dl_argc > 2) + { +- process_dl_audit (_dl_argv[2]); ++ audit_list_add_string (&audit_list, _dl_argv[2]); + + _dl_skip_args += 2; + _dl_argc -= 2; +@@ -1612,8 +1632,7 @@ ERROR: '%s': cannot process note segment.\n", _dl_argv[0]); + + /* If we have auditing DSOs to load, do it now. */ + bool need_security_init = true; +- if (__glibc_unlikely (audit_list != NULL) +- || __glibc_unlikely (audit_list_string != NULL)) ++ if (audit_list.length > 0) + { + /* Since we start using the auditing DSOs right away we need to + initialize the data structures now. */ +@@ -1626,7 +1645,7 @@ ERROR: '%s': cannot process note segment.\n", _dl_argv[0]); + security_init (); + need_security_init = false; + +- load_audit_modules (main_map); ++ load_audit_modules (main_map, &audit_list); + } + + /* Keep track of the currently loaded modules to count how many +@@ -2500,30 +2519,6 @@ a filename can be specified using the LD_DEBUG_OUTPUT environment variable.\n"); + } + } + +-static void +-process_dl_audit (char *str) +-{ +- /* The parameter is a colon separated list of DSO names. */ +- char *p; +- +- while ((p = (strsep) (&str, ":")) != NULL) +- if (dso_name_valid_for_suid (p)) +- { +- /* This is using the local malloc, not the system malloc. The +- memory can never be freed. */ +- struct audit_list *newp = malloc (sizeof (*newp)); +- newp->name = p; +- +- if (audit_list == NULL) +- audit_list = newp->next = newp; +- else +- { +- newp->next = audit_list->next; +- audit_list = audit_list->next = newp; +- } +- } +-} +- + /* Process all environments variables the dynamic linker must recognize. + Since all of them start with `LD_' we are a bit smarter while finding + all the entries. */ +@@ -2531,7 +2526,7 @@ extern char **_environ attribute_hidden; + + + static void +-process_envvars (enum mode *modep) ++process_envvars (enum mode *modep, struct audit_list *audit_list) + { + char **runp = _environ; + char *envline; +@@ -2571,7 +2566,7 @@ process_envvars (enum mode *modep) + break; + } + if (memcmp (envline, "AUDIT", 5) == 0) +- audit_list_string = &envline[6]; ++ audit_list_add_string (audit_list, &envline[6]); + break; + + case 7: diff --git a/SOURCES/glibc-rh1817513-48.patch b/SOURCES/glibc-rh1817513-48.patch new file mode 100644 index 0000000..455373d --- /dev/null +++ b/SOURCES/glibc-rh1817513-48.patch @@ -0,0 +1,379 @@ +commit 8f7a75d700af809eeb4363895078fabfb3a9d7c3 +Author: Florian Weimer +Date: Mon Feb 17 16:49:40 2020 +0100 + + elf: Implement DT_AUDIT, DT_DEPAUDIT support [BZ #24943] + + binutils ld has supported --audit, --depaudit for a long time, + only support in glibc has been missing. + + Reviewed-by: Carlos O'Donell + +Conflicts: + elf/Makefile + (Test backport differences.) + +diff --git a/elf/Makefile b/elf/Makefile +index 5b0aeccb0a53c182..a6601ba84c8f4017 100644 +--- a/elf/Makefile ++++ b/elf/Makefile +@@ -195,7 +195,8 @@ tests += restest1 preloadtest loadfail multiload origtest resolvfail \ + 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-filterobj tst-filterobj-dlopen tst-auxobj tst-auxobj-dlopen \ ++ tst-audit14 tst-audit15 tst-audit16 + # reldep9 + tests-internal += loadtest unload unload2 circleload1 \ + neededtest neededtest2 neededtest3 neededtest4 \ +@@ -310,7 +311,8 @@ modules-names = testobj1 testobj2 testobj3 testobj4 testobj5 testobj6 \ + tst-initlazyfailmod tst-finilazyfailmod \ + tst-dlopenfailmod1 tst-dlopenfaillinkmod tst-dlopenfailmod2 \ + tst-dlopenfailmod3 \ +- tst-filterobj-flt tst-filterobj-aux tst-filterobj-filtee ++ tst-filterobj-flt tst-filterobj-aux tst-filterobj-filtee \ ++ tst-auditlogmod-1 tst-auditlogmod-2 tst-auditlogmod-3 + + # Most modules build with _ISOMAC defined, but those filtered out + # depend on internal headers. +@@ -1453,6 +1455,22 @@ $(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 ++$(objpfx)tst-auditlogmod-1.so: $(libsupport) ++$(objpfx)tst-audit14.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) ++$(objpfx)tst-audit15.out: \ ++ $(objpfx)tst-auditlogmod-1.so $(objpfx)tst-auditlogmod-2.so ++LDFLAGS-tst-audit16 = \ ++ -Wl,--audit=tst-auditlogmod-1.so:tst-auditlogmod-2.so \ ++ -Wl,--depaudit=tst-auditlogmod-3.so ++$(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 ++ + # 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/rtld.c b/elf/rtld.c +index c39cb8f2cd4bb1cc..d44facf5343b3301 100644 +--- a/elf/rtld.c ++++ b/elf/rtld.c +@@ -151,9 +151,17 @@ static void audit_list_init (struct audit_list *); + not be called after audit_list_next. */ + static void audit_list_add_string (struct audit_list *, const char *); + ++/* Add the audit strings from the link map, found in the dynamic ++ segment at TG (either DT_AUDIT and DT_DEPAUDIT). Must be called ++ before audit_list_next. */ ++static void audit_list_add_dynamic_tag (struct audit_list *, ++ struct link_map *, ++ unsigned int tag); ++ + /* Extract the next audit module from the audit list. Only modules + for which dso_name_valid_for_suid is true are returned. Must be +- called after all the audit_list_add_string calls. */ ++ called after all the audit_list_add_string, ++ audit_list_add_dynamic_tags calls. */ + static const char *audit_list_next (struct audit_list *); + + /* This is a list of all the modes the dynamic loader can be in. */ +@@ -233,6 +241,16 @@ audit_list_add_string (struct audit_list *list, const char *string) + list->current_tail = string; + } + ++static void ++audit_list_add_dynamic_tag (struct audit_list *list, struct link_map *main_map, ++ unsigned int tag) ++{ ++ ElfW(Dyn) *info = main_map->l_info[ADDRIDX (tag)]; ++ const char *strtab = (const char *) D_PTR (main_map, l_info[DT_STRTAB]); ++ if (info != NULL) ++ audit_list_add_string (list, strtab + info->d_un.d_val); ++} ++ + static const char * + audit_list_next (struct audit_list *list) + { +@@ -1630,6 +1648,9 @@ ERROR: '%s': cannot process note segment.\n", _dl_argv[0]); + /* Assign a module ID. Do this before loading any audit modules. */ + GL(dl_rtld_map).l_tls_modid = _dl_next_tls_modid (); + ++ audit_list_add_dynamic_tag (&audit_list, main_map, DT_AUDIT); ++ audit_list_add_dynamic_tag (&audit_list, main_map, DT_DEPAUDIT); ++ + /* If we have auditing DSOs to load, do it now. */ + bool need_security_init = true; + if (audit_list.length > 0) +diff --git a/elf/tst-audit14.c b/elf/tst-audit14.c +new file mode 100644 +index 0000000000000000..27ff8db9480a98cc +--- /dev/null ++++ b/elf/tst-audit14.c +@@ -0,0 +1,46 @@ ++/* Main program with DT_AUDIT. One audit module. ++ 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 ++ ++static int ++do_test (void) ++{ ++ /* Verify what the audit module has written. This test assumes that ++ standard output has been redirected to a regular file. */ ++ FILE *fp = xfopen ("/dev/stdout", "r"); ++ ++ char *buffer = NULL; ++ size_t buffer_length = 0; ++ size_t line_length = xgetline (&buffer, &buffer_length, fp); ++ const char *message = "info: tst-auditlogmod-1.so loaded\n"; ++ TEST_COMPARE_BLOB (message, strlen (message), buffer, line_length); ++ ++ /* No more audit module output. */ ++ line_length = xgetline (&buffer, &buffer_length, fp); ++ TEST_COMPARE_BLOB ("", 0, buffer, line_length); ++ ++ free (buffer); ++ xfclose (fp); ++ return 0; ++} ++ ++#include +diff --git a/elf/tst-audit15.c b/elf/tst-audit15.c +new file mode 100644 +index 0000000000000000..cbd1589ec40653d1 +--- /dev/null ++++ b/elf/tst-audit15.c +@@ -0,0 +1,50 @@ ++/* Main program with DT_AUDIT and DT_DEPAUDIT. Two audit modules. ++ 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 ++ ++static int ++do_test (void) ++{ ++ /* Verify what the audit modules have written. This test assumes ++ that standard output has been redirected to a regular file. */ ++ FILE *fp = xfopen ("/dev/stdout", "r"); ++ ++ char *buffer = NULL; ++ size_t buffer_length = 0; ++ size_t line_length = xgetline (&buffer, &buffer_length, fp); ++ const char *message = "info: tst-auditlogmod-1.so loaded\n"; ++ TEST_COMPARE_BLOB (message, strlen (message), buffer, line_length); ++ ++ line_length = xgetline (&buffer, &buffer_length, fp); ++ message = "info: tst-auditlogmod-2.so loaded\n"; ++ TEST_COMPARE_BLOB (message, strlen (message), buffer, line_length); ++ ++ /* No more audit module output. */ ++ line_length = xgetline (&buffer, &buffer_length, fp); ++ TEST_COMPARE_BLOB ("", 0, buffer, line_length); ++ ++ free (buffer); ++ xfclose (fp); ++ return 0; ++} ++ ++#include +diff --git a/elf/tst-audit16.c b/elf/tst-audit16.c +new file mode 100644 +index 0000000000000000..dd6ce189ea6fffa3 +--- /dev/null ++++ b/elf/tst-audit16.c +@@ -0,0 +1,54 @@ ++/* Main program with DT_AUDIT and DT_DEPAUDIT. Three audit modules. ++ 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 ++ ++static int ++do_test (void) ++{ ++ /* Verify what the audit modules have written. This test assumes ++ that standard output has been redirected to a regular file. */ ++ FILE *fp = xfopen ("/dev/stdout", "r"); ++ ++ char *buffer = NULL; ++ size_t buffer_length = 0; ++ size_t line_length = xgetline (&buffer, &buffer_length, fp); ++ const char *message = "info: tst-auditlogmod-1.so loaded\n"; ++ TEST_COMPARE_BLOB (message, strlen (message), buffer, line_length); ++ ++ line_length = xgetline (&buffer, &buffer_length, fp); ++ message = "info: tst-auditlogmod-2.so loaded\n"; ++ TEST_COMPARE_BLOB (message, strlen (message), buffer, line_length); ++ ++ line_length = xgetline (&buffer, &buffer_length, fp); ++ message = "info: tst-auditlogmod-3.so loaded\n"; ++ TEST_COMPARE_BLOB (message, strlen (message), buffer, line_length); ++ ++ /* No more audit module output. */ ++ line_length = xgetline (&buffer, &buffer_length, fp); ++ TEST_COMPARE_BLOB ("", 0, buffer, line_length); ++ ++ free (buffer); ++ xfclose (fp); ++ return 0; ++} ++ ++#include +diff --git a/elf/tst-auditlogmod-1.c b/elf/tst-auditlogmod-1.c +new file mode 100644 +index 0000000000000000..db9dac4c01a58dcd +--- /dev/null ++++ b/elf/tst-auditlogmod-1.c +@@ -0,0 +1,27 @@ ++/* Audit module which logs that it was loaded. Variant 1. ++ 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 ++ ++unsigned int ++la_version (unsigned int v) ++{ ++ write_message ("info: tst-auditlogmod-1.so loaded\n"); ++ return LAV_CURRENT; ++} +diff --git a/elf/tst-auditlogmod-2.c b/elf/tst-auditlogmod-2.c +new file mode 100644 +index 0000000000000000..871c22641c47fed0 +--- /dev/null ++++ b/elf/tst-auditlogmod-2.c +@@ -0,0 +1,27 @@ ++/* Audit module which logs that it was loaded. Variant 2. ++ 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 ++ ++unsigned int ++la_version (unsigned int v) ++{ ++ write_message ("info: tst-auditlogmod-2.so loaded\n"); ++ return LAV_CURRENT; ++} +diff --git a/elf/tst-auditlogmod-3.c b/elf/tst-auditlogmod-3.c +new file mode 100644 +index 0000000000000000..da2ee19d4ab9e861 +--- /dev/null ++++ b/elf/tst-auditlogmod-3.c +@@ -0,0 +1,27 @@ ++/* Audit module which logs that it was loaded. Variant 3. ++ 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 ++ ++unsigned int ++la_version (unsigned int v) ++{ ++ write_message ("info: tst-auditlogmod-3.so loaded\n"); ++ return LAV_CURRENT; ++} diff --git a/SOURCES/glibc-rh1817513-49.patch b/SOURCES/glibc-rh1817513-49.patch new file mode 100644 index 0000000..23a310a --- /dev/null +++ b/SOURCES/glibc-rh1817513-49.patch @@ -0,0 +1,163 @@ +commit 50a2d83c08a94a10f88a1fedeb7a6e3667a6b732 +Author: Florian Weimer +Date: Fri Apr 24 22:13:03 2020 +0200 + + elf: Introduce + + MIPS needs to ignore certain existing symbols during symbol lookup. + The old scheme uses the ELF_MACHINE_SYM_NO_MATCH macro, with an + inline function, within its own header, with a sysdeps override for + MIPS. This allows re-use of the function from another file (without + having to include or providing the default definition + for ELF_MACHINE_SYM_NO_MATCH). + + Reviewed-by: Carlos O'Donell + +diff --git a/elf/dl-lookup.c b/elf/dl-lookup.c +index e4c479de9a1fd6ec..47acd134600b44b5 100644 +--- a/elf/dl-lookup.c ++++ b/elf/dl-lookup.c +@@ -28,18 +28,12 @@ + #include + #include + #include ++#include + + #include + +-/* Return nonzero if check_match should consider SYM to fail to match a +- symbol reference for some machine-specific reason. */ +-#ifndef ELF_MACHINE_SYM_NO_MATCH +-# define ELF_MACHINE_SYM_NO_MATCH(sym) 0 +-#endif +- + #define VERSTAG(tag) (DT_NUM + DT_THISPROCNUM + DT_VERSIONTAGIDX (tag)) + +- + struct sym_val + { + const ElfW(Sym) *s; +@@ -78,7 +72,7 @@ check_match (const char *const undef_name, + if (__glibc_unlikely ((sym->st_value == 0 /* No value. */ + && sym->st_shndx != SHN_ABS + && stt != STT_TLS) +- || ELF_MACHINE_SYM_NO_MATCH (sym) ++ || elf_machine_sym_no_match (sym) + || (type_class & (sym->st_shndx == SHN_UNDEF)))) + return NULL; + +diff --git a/sysdeps/generic/elf_machine_sym_no_match.h b/sysdeps/generic/elf_machine_sym_no_match.h +new file mode 100644 +index 0000000000000000..27155de4c0358460 +--- /dev/null ++++ b/sysdeps/generic/elf_machine_sym_no_match.h +@@ -0,0 +1,34 @@ ++/* Function to ignore certain symbol matches for machine-specific reasons. ++ 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 ++ . */ ++ ++#ifndef _ELF_MACHINE_SYM_NO_MATCH_H ++#define _ELF_MACHINE_SYM_NO_MATCH_H ++ ++#include ++#include ++ ++/* This can be customized to ignore certain symbols during lookup in ++ case there are machine-specific rules to disregard some ++ symbols. */ ++static inline bool ++elf_machine_sym_no_match (const ElfW(Sym) *sym) ++{ ++ return false; ++} ++ ++#endif /* _ELF_MACHINE_SYM_NO_MATCH_H */ +diff --git a/sysdeps/mips/dl-machine.h b/sysdeps/mips/dl-machine.h +index 91fc640388a735c7..b41e10647d81843b 100644 +--- a/sysdeps/mips/dl-machine.h ++++ b/sysdeps/mips/dl-machine.h +@@ -467,21 +467,6 @@ elf_machine_plt_value (struct link_map *map, const ElfW(Rel) *reloc, + return value; + } + +-/* The semantics of zero/non-zero values of undefined symbols differs +- depending on whether the non-PIC ABI is in use. Under the non-PIC +- ABI, a non-zero value indicates that there is an address reference +- to the symbol and thus it must always be resolved (except when +- resolving a jump slot relocation) to the PLT entry whose address is +- provided as the symbol's value; a zero value indicates that this +- canonical-address behaviour is not required. Yet under the classic +- MIPS psABI, a zero value indicates that there is an address +- reference to the function and the dynamic linker must resolve the +- symbol immediately upon loading. To avoid conflict, symbols for +- which the dynamic linker must assume the non-PIC ABI semantics are +- marked with the STO_MIPS_PLT flag. */ +-#define ELF_MACHINE_SYM_NO_MATCH(sym) \ +- ((sym)->st_shndx == SHN_UNDEF && !((sym)->st_other & STO_MIPS_PLT)) +- + #endif /* !dl_machine_h */ + + #ifdef RESOLVE_MAP +diff --git a/sysdeps/mips/elf_machine_sym_no_match.h b/sysdeps/mips/elf_machine_sym_no_match.h +new file mode 100644 +index 0000000000000000..9d09e5fa2db1ff6c +--- /dev/null ++++ b/sysdeps/mips/elf_machine_sym_no_match.h +@@ -0,0 +1,43 @@ ++/* MIPS-specific handling of undefined symbols. ++ Copyright (C) 2008-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 ++ . */ ++ ++#ifndef _ELF_MACHINE_SYM_NO_MATCH_H ++#define _ELF_MACHINE_SYM_NO_MATCH_H ++ ++#include ++#include ++ ++/* The semantics of zero/non-zero values of undefined symbols differs ++ depending on whether the non-PIC ABI is in use. Under the non-PIC ++ ABI, a non-zero value indicates that there is an address reference ++ to the symbol and thus it must always be resolved (except when ++ resolving a jump slot relocation) to the PLT entry whose address is ++ provided as the symbol's value; a zero value indicates that this ++ canonical-address behaviour is not required. Yet under the classic ++ MIPS psABI, a zero value indicates that there is an address ++ reference to the function and the dynamic linker must resolve the ++ symbol immediately upon loading. To avoid conflict, symbols for ++ which the dynamic linker must assume the non-PIC ABI semantics are ++ marked with the STO_MIPS_PLT flag. */ ++static inline bool ++elf_machine_sym_no_match (const ElfW(Sym) *sym) ++{ ++ return sym->st_shndx == SHN_UNDEF && !(sym->st_other & STO_MIPS_PLT); ++} ++ ++#endif /* _ELF_MACHINE_SYM_NO_MATCH_H */ diff --git a/SOURCES/glibc-rh1817513-5.patch b/SOURCES/glibc-rh1817513-5.patch new file mode 100644 index 0000000..dba4a6e --- /dev/null +++ b/SOURCES/glibc-rh1817513-5.patch @@ -0,0 +1,82 @@ +commit fb4c32aef64500c65c7fc95ca06d7e17d467be45 +Author: H.J. Lu +Date: Mon Aug 6 06:25:28 2018 -0700 + + x86: Move STATE_SAVE_OFFSET/STATE_SAVE_MASK to sysdep.h + + Move STATE_SAVE_OFFSET and STATE_SAVE_MASK to sysdep.h to make + sysdeps/x86/cpu-features.h a C header file. + + * sysdeps/x86/cpu-features.h (STATE_SAVE_OFFSET): Removed. + (STATE_SAVE_MASK): Likewise. + Don't check __ASSEMBLER__ to include . + * sysdeps/x86/sysdep.h (STATE_SAVE_OFFSET): New. + (STATE_SAVE_MASK): Likewise. + * sysdeps/x86_64/dl-trampoline.S: Include + instead of . + +diff --git a/sysdeps/x86/cpu-features.h b/sysdeps/x86/cpu-features.h +index 4c6d08c709eea204..d342664c64ab7aa1 100644 +--- a/sysdeps/x86/cpu-features.h ++++ b/sysdeps/x86/cpu-features.h +@@ -92,18 +92,6 @@ + /* The current maximum size of the feature integer bit array. */ + #define FEATURE_INDEX_MAX 1 + +-/* Offset for fxsave/xsave area used by _dl_runtime_resolve. Also need +- space to preserve RCX, RDX, RSI, RDI, R8, R9 and RAX. It must be +- aligned to 16 bytes for fxsave and 64 bytes for xsave. */ +-#define STATE_SAVE_OFFSET (8 * 7 + 8) +- +-/* Save SSE, AVX, AVX512, mask and bound registers. */ +-#define STATE_SAVE_MASK \ +- ((1 << 1) | (1 << 2) | (1 << 3) | (1 << 5) | (1 << 6) | (1 << 7)) +- +-#ifdef __ASSEMBLER__ +-# include +-#else /* __ASSEMBLER__ */ + enum + { + COMMON_CPUID_INDEX_1 = 0, +@@ -267,8 +255,6 @@ extern const struct cpu_features *__get_cpu_features (void) + # define index_arch_XSAVEC_Usable FEATURE_INDEX_1 + # define index_arch_Prefer_FSRM FEATURE_INDEX_1 + +-#endif /* !__ASSEMBLER__ */ +- + #ifdef __x86_64__ + # define HAS_CPUID 1 + #elif defined __i586__ || defined __pentium__ +diff --git a/sysdeps/x86/sysdep.h b/sysdeps/x86/sysdep.h +index 8776ad8374e056d3..f41f4ebd425cfbaf 100644 +--- a/sysdeps/x86/sysdep.h ++++ b/sysdeps/x86/sysdep.h +@@ -48,6 +48,15 @@ enum cf_protection_level + # define SHSTK_ENABLED 0 + #endif + ++/* Offset for fxsave/xsave area used by _dl_runtime_resolve. Also need ++ space to preserve RCX, RDX, RSI, RDI, R8, R9 and RAX. It must be ++ aligned to 16 bytes for fxsave and 64 bytes for xsave. */ ++#define STATE_SAVE_OFFSET (8 * 7 + 8) ++ ++/* Save SSE, AVX, AVX512, mask and bound registers. */ ++#define STATE_SAVE_MASK \ ++ ((1 << 1) | (1 << 2) | (1 << 3) | (1 << 5) | (1 << 6) | (1 << 7)) ++ + #ifdef __ASSEMBLER__ + + /* Syntactic details of assembler. */ +diff --git a/sysdeps/x86_64/dl-trampoline.S b/sysdeps/x86_64/dl-trampoline.S +index ef1425cbb909529a..fd918510fe155733 100644 +--- a/sysdeps/x86_64/dl-trampoline.S ++++ b/sysdeps/x86_64/dl-trampoline.S +@@ -18,7 +18,7 @@ + + #include + #include +-#include ++#include + #include + + #ifndef DL_STACK_ALIGNMENT diff --git a/SOURCES/glibc-rh1817513-50.patch b/SOURCES/glibc-rh1817513-50.patch new file mode 100644 index 0000000..a3092bd --- /dev/null +++ b/SOURCES/glibc-rh1817513-50.patch @@ -0,0 +1,538 @@ +commit ec935dea6332cb22f9881cd1162bad156173f4b0 +Author: Florian Weimer +Date: Fri Apr 24 22:31:15 2020 +0200 + + elf: Implement __libc_early_init + + This function is defined in libc.so, and the dynamic loader calls + right after relocation has been finished, before any ELF constructors + or the preinit function is invoked. It is also used in the static + build for initializing parts of the static libc. + + To locate __libc_early_init, a direct symbol lookup function is used, + _dl_lookup_direct. It does not search the entire symbol scope and + consults merely a single link map. This function could also be used + to implement lookups in the vDSO (as an optimization). + + A per-namespace variable (libc_map) is added for locating libc.so, + to avoid repeated traversals of the search scope. It is similar to + GL(dl_initfirst). An alternative would have been to thread a context + argument from _dl_open down to _dl_map_object_from_fd (where libc.so + is identified). This could have avoided the global variable, but + the change would be larger as a result. It would not have been + possible to use this to replace GL(dl_initfirst) because that global + variable is used to pass the function pointer past the stack switch + from dl_main to the main program. Replacing that requires adding + a new argument to _dl_init, which in turn needs changes to the + architecture-specific libc.so startup code written in assembler. + + __libc_early_init should not be used to replace _dl_var_init (as + it exists today on some architectures). Instead, _dl_lookup_direct + should be used to look up a new variable symbol in libc.so, and + that should then be initialized from the dynamic loader, immediately + after the object has been loaded in _dl_map_object_from_fd (before + relocation is run). This way, more IFUNC resolvers which depend on + these variables will work. + + Reviewed-by: Carlos O'Donell + +diff --git a/csu/init-first.c b/csu/init-first.c +index 289373f9d8bd98f4..544229151ef79c67 100644 +--- a/csu/init-first.c ++++ b/csu/init-first.c +@@ -16,7 +16,6 @@ + License along with the GNU C Library; if not, see + . */ + +-#include + #include + #include + #include +@@ -80,9 +79,6 @@ _init (int argc, char **argv, char **envp) + + __init_misc (argc, argv, envp); + +- /* Initialize ctype data. */ +- __ctype_init (); +- + #if defined SHARED && !defined NO_CTORS_DTORS_SECTIONS + __libc_global_ctors (); + #endif +diff --git a/csu/libc-start.c b/csu/libc-start.c +index dfbf195328239a17..d9c3248219d8f84f 100644 +--- a/csu/libc-start.c ++++ b/csu/libc-start.c +@@ -22,6 +22,7 @@ + #include + #include + #include ++#include + + #include + +@@ -238,6 +239,10 @@ LIBC_START_MAIN (int (*main) (int, char **, char ** MAIN_AUXVEC_DECL), + __cxa_atexit ((void (*) (void *)) rtld_fini, NULL, NULL); + + #ifndef SHARED ++ /* Perform early initialization. In the shared case, this function ++ is called from the dynamic loader as early as possible. */ ++ __libc_early_init (); ++ + /* Call the initializer of the libc. This is only needed here if we + are compiling for the static library in which case we haven't + run the constructors in `_dl_start_user'. */ +diff --git a/elf/Makefile b/elf/Makefile +index a6601ba84c8f4017..cbced7605ebe2443 100644 +--- a/elf/Makefile ++++ b/elf/Makefile +@@ -25,7 +25,7 @@ headers = elf.h bits/elfclass.h link.h bits/link.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 ++ dl-reloc-static-pie libc_early_init + + # The core dynamic linking functions are in libc for the static and + # profiled libraries. +@@ -33,7 +33,8 @@ dl-routines = $(addprefix dl-,load lookup object reloc deps hwcaps \ + runtime init fini debug misc \ + version profile tls origin scope \ + execstack open close trampoline \ +- exception sort-maps) ++ exception sort-maps lookup-direct \ ++ call-libc-early-init) + ifeq (yes,$(use-ldconfig)) + dl-routines += dl-cache + endif +diff --git a/elf/Versions b/elf/Versions +index 705489fc51f4ac5f..3be879c4adfa74c7 100644 +--- a/elf/Versions ++++ b/elf/Versions +@@ -26,6 +26,7 @@ libc { + _dl_open_hook; _dl_open_hook2; + _dl_sym; _dl_vsym; + __libc_dlclose; __libc_dlopen_mode; __libc_dlsym; __libc_dlvsym; ++ __libc_early_init; + + # Internal error handling support. Interposes the functions in ld.so. + _dl_signal_exception; _dl_catch_exception; +diff --git a/elf/dl-call-libc-early-init.c b/elf/dl-call-libc-early-init.c +new file mode 100644 +index 0000000000000000..41e9ad9aad8b5b46 +--- /dev/null ++++ b/elf/dl-call-libc-early-init.c +@@ -0,0 +1,41 @@ ++/* Invoke the early initialization function in libc.so. ++ 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 ++ ++void ++_dl_call_libc_early_init (struct link_map *libc_map) ++{ ++ /* There is nothing to do if we did not actually load libc.so. */ ++ if (libc_map == NULL) ++ return; ++ ++ const ElfW(Sym) *sym ++ = _dl_lookup_direct (libc_map, "__libc_early_init", ++ 0x069682ac, /* dl_new_hash output. */ ++ "GLIBC_PRIVATE", ++ 0x0963cf85); /* _dl_elf_hash output. */ ++ assert (sym != NULL); ++ __typeof (__libc_early_init) *early_init ++ = DL_SYMBOL_ADDRESS (libc_map, sym); ++ early_init (); ++} +diff --git a/elf/dl-load.c b/elf/dl-load.c +index 8f8869ff524ab9f2..64da5323d0e368c1 100644 +--- a/elf/dl-load.c ++++ b/elf/dl-load.c +@@ -30,6 +30,7 @@ + #include + #include + #include ++#include + + /* Type for the buffer we put the ELF header and hopefully the program + header. This buffer does not really have to be too large. In most +@@ -1390,6 +1391,14 @@ cannot enable executable stack as shared object requires"); + add_name_to_object (l, ((const char *) D_PTR (l, l_info[DT_STRTAB]) + + l->l_info[DT_SONAME]->d_un.d_val)); + ++ /* If we have newly loaded libc.so, update the namespace ++ description. */ ++ if (GL(dl_ns)[nsid].libc_map == NULL ++ && l->l_info[DT_SONAME] != NULL ++ && strcmp (((const char *) D_PTR (l, l_info[DT_STRTAB]) ++ + l->l_info[DT_SONAME]->d_un.d_val), LIBC_SO) == 0) ++ GL(dl_ns)[nsid].libc_map = l; ++ + /* _dl_close can only eventually undo the module ID assignment (via + remove_slotinfo) if this function returns a pointer to a link + map. Therefore, delay this step until all possibilities for +diff --git a/elf/dl-lookup-direct.c b/elf/dl-lookup-direct.c +new file mode 100644 +index 0000000000000000..5637ae89de8a9d61 +--- /dev/null ++++ b/elf/dl-lookup-direct.c +@@ -0,0 +1,116 @@ ++/* Look up a symbol in a single specified object. ++ Copyright (C) 1995-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 ++ ++/* This function corresponds to do_lookup_x in elf/dl-lookup.c. The ++ variant here is simplified because it requires symbol ++ versioning. */ ++static const ElfW(Sym) * ++check_match (const struct link_map *const map, const char *const undef_name, ++ const char *version, uint32_t version_hash, ++ const Elf_Symndx symidx) ++{ ++ const ElfW(Sym) *symtab = (const void *) D_PTR (map, l_info[DT_SYMTAB]); ++ const ElfW(Sym) *sym = &symtab[symidx]; ++ ++ unsigned int stt = ELFW(ST_TYPE) (sym->st_info); ++ if (__glibc_unlikely ((sym->st_value == 0 /* No value. */ ++ && sym->st_shndx != SHN_ABS ++ && stt != STT_TLS) ++ || elf_machine_sym_no_match (sym))) ++ return NULL; ++ ++ /* Ignore all but STT_NOTYPE, STT_OBJECT, STT_FUNC, ++ STT_COMMON, STT_TLS, and STT_GNU_IFUNC since these are no ++ code/data definitions. */ ++#define ALLOWED_STT \ ++ ((1 << STT_NOTYPE) | (1 << STT_OBJECT) | (1 << STT_FUNC) \ ++ | (1 << STT_COMMON) | (1 << STT_TLS) | (1 << STT_GNU_IFUNC)) ++ if (__glibc_unlikely (((1 << stt) & ALLOWED_STT) == 0)) ++ return NULL; ++ ++ const char *strtab = (const void *) D_PTR (map, l_info[DT_STRTAB]); ++ ++ if (strcmp (strtab + sym->st_name, undef_name) != 0) ++ /* Not the symbol we are looking for. */ ++ return NULL; ++ ++ ElfW(Half) ndx = map->l_versyms[symidx] & 0x7fff; ++ if (map->l_versions[ndx].hash != version_hash ++ || strcmp (map->l_versions[ndx].name, version) != 0) ++ /* It's not the version we want. */ ++ return NULL; ++ ++ return sym; ++} ++ ++ ++/* This function corresponds to do_lookup_x in elf/dl-lookup.c. The ++ variant here is simplified because it does not search object ++ dependencies. It is optimized for a successful lookup. */ ++const ElfW(Sym) * ++_dl_lookup_direct (struct link_map *map, ++ const char *undef_name, uint32_t new_hash, ++ const char *version, uint32_t version_hash) ++{ ++ const ElfW(Addr) *bitmask = map->l_gnu_bitmask; ++ if (__glibc_likely (bitmask != NULL)) ++ { ++ Elf32_Word bucket = map->l_gnu_buckets[new_hash % map->l_nbuckets]; ++ if (bucket != 0) ++ { ++ const Elf32_Word *hasharr = &map->l_gnu_chain_zero[bucket]; ++ ++ do ++ if (((*hasharr ^ new_hash) >> 1) == 0) ++ { ++ Elf_Symndx symidx = ELF_MACHINE_HASH_SYMIDX (map, hasharr); ++ const ElfW(Sym) *sym = check_match (map, undef_name, ++ version, version_hash, ++ symidx); ++ if (sym != NULL) ++ return sym; ++ } ++ while ((*hasharr++ & 1u) == 0); ++ } ++ } ++ else ++ { ++ /* Fallback code for lack of GNU_HASH support. */ ++ uint32_t old_hash = _dl_elf_hash (undef_name); ++ ++ /* Use the old SysV-style hash table. Search the appropriate ++ hash bucket in this object's symbol table for a definition ++ for the same symbol name. */ ++ for (Elf_Symndx symidx = map->l_buckets[old_hash % map->l_nbuckets]; ++ symidx != STN_UNDEF; ++ symidx = map->l_chain[symidx]) ++ { ++ const ElfW(Sym) *sym = check_match (map, undef_name, ++ version, version_hash, symidx); ++ if (sym != NULL) ++ return sym; ++ } ++ } ++ ++ return NULL; ++} +diff --git a/elf/dl-open.c b/elf/dl-open.c +index 7113c4a04f0fddbc..1a77ec833cad6c55 100644 +--- a/elf/dl-open.c ++++ b/elf/dl-open.c +@@ -34,6 +34,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -57,6 +58,13 @@ struct dl_open_args + (non-negative). */ + unsigned int original_global_scope_pending_adds; + ++ /* Set to true by dl_open_worker if libc.so was already loaded into ++ the namespace at the time dl_open_worker was called. This is ++ used to determine whether libc.so early initialization has ++ already been done before, and whether to roll back the cached ++ libc_map value in the namespace in case of a dlopen failure. */ ++ bool libc_already_loaded; ++ + /* Original parameters to the program and the current environment. */ + int argc; + char **argv; +@@ -500,6 +508,11 @@ dl_open_worker (void *a) + args->nsid = call_map->l_ns; + } + ++ /* The namespace ID is now known. Keep track of whether libc.so was ++ already loaded, to determine whether it is necessary to call the ++ early initialization routine (or clear libc_map on error). */ ++ args->libc_already_loaded = GL(dl_ns)[args->nsid].libc_map != NULL; ++ + /* Retain the old value, so that it can be restored. */ + args->original_global_scope_pending_adds + = GL (dl_ns)[args->nsid]._ns_global_scope_pending_adds; +@@ -734,6 +747,11 @@ dl_open_worker (void *a) + if (relocation_in_progress) + LIBC_PROBE (reloc_complete, 3, args->nsid, r, new); + ++ /* If libc.so was not there before, attempt to call its early ++ initialization routine. */ ++ if (!args->libc_already_loaded) ++ _dl_call_libc_early_init (GL(dl_ns)[args->nsid].libc_map); ++ + #ifndef SHARED + DL_STATIC_INIT (new); + #endif +@@ -828,6 +846,8 @@ no more namespaces available for dlmopen()")); + args.caller_dlopen = caller_dlopen; + args.map = NULL; + args.nsid = nsid; ++ /* args.libc_already_loaded is always assigned by dl_open_worker ++ (before any explicit/non-local returns). */ + args.argc = argc; + args.argv = argv; + args.env = env; +@@ -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; ++ + /* Remove the object from memory. It may be in an inconsistent + state if relocation failed, for example. */ + if (args.map) +diff --git a/elf/libc-early-init.h b/elf/libc-early-init.h +new file mode 100644 +index 0000000000000000..5185fa8895c0e11a +--- /dev/null ++++ b/elf/libc-early-init.h +@@ -0,0 +1,35 @@ ++/* Early initialization of libc.so. ++ 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 ++ . */ ++ ++#ifndef _LIBC_EARLY_INIT_H ++#define _LIBC_EARLY_INIT_H ++ ++struct link_map; ++ ++/* If LIBC_MAP is not NULL, look up the __libc_early_init symbol in it ++ and call this function. */ ++void _dl_call_libc_early_init (struct link_map *libc_map) attribute_hidden; ++ ++/* In the shared case, this function is defined in libc.so and invoked ++ from ld.so (or on the fist static dlopen) after complete relocation ++ of a new loaded libc.so, but before user-defined ELF constructors ++ run. In the static case, this function is called directly from the ++ startup code. */ ++void __libc_early_init (void); ++ ++#endif /* _LIBC_EARLY_INIT_H */ +diff --git a/elf/libc_early_init.c b/elf/libc_early_init.c +new file mode 100644 +index 0000000000000000..7f4ca332b805a22c +--- /dev/null ++++ b/elf/libc_early_init.c +@@ -0,0 +1,27 @@ ++/* Early initialization of libc.so, libc.so side. ++ 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 ++ ++void ++__libc_early_init (void) ++{ ++ /* Initialize ctype data. */ ++ __ctype_init (); ++} +diff --git a/elf/rtld.c b/elf/rtld.c +index d44facf5343b3301..a40d5f17db0dac8b 100644 +--- a/elf/rtld.c ++++ b/elf/rtld.c +@@ -44,6 +44,7 @@ + #include + #include + #include ++#include + + #include + +@@ -2365,6 +2366,9 @@ ERROR: '%s': cannot process note segment.\n", _dl_argv[0]); + rtld_timer_accum (&relocate_time, start); + } + ++ /* Relocation is complete. Perform early libc initialization. */ ++ _dl_call_libc_early_init (GL(dl_ns)[LM_ID_BASE].libc_map); ++ + /* Do any necessary cleanups for the startup OS interface code. + We do these now so that no calls are made after rtld re-relocation + which might be resolved to different functions than we expect. +diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h +index a8fb0d211426e4b1..ccec08929e4ad4e7 100644 +--- a/sysdeps/generic/ldsodefs.h ++++ b/sysdeps/generic/ldsodefs.h +@@ -336,6 +336,10 @@ struct rtld_global + recursive dlopen calls from ELF constructors. */ + unsigned int _ns_global_scope_pending_adds; + ++ /* Once libc.so has been loaded into the namespace, this points to ++ its link map. */ ++ struct link_map *libc_map; ++ + /* Search table for unique objects. */ + struct unique_sym_table + { +@@ -943,6 +947,19 @@ extern lookup_t _dl_lookup_symbol_x (const char *undef, + attribute_hidden; + + ++/* Restricted version of _dl_lookup_symbol_x. Searches MAP (and only ++ MAP) for the symbol UNDEF_NAME, with GNU hash NEW_HASH (computed ++ with dl_new_hash), symbol version VERSION, and symbol version hash ++ VERSION_HASH (computed with _dl_elf_hash). Returns a pointer to ++ the symbol table entry in MAP on success, or NULL on failure. MAP ++ must have symbol versioning information, or otherwise the result is ++ undefined. */ ++const ElfW(Sym) *_dl_lookup_direct (struct link_map *map, ++ const char *undef_name, ++ uint32_t new_hash, ++ const char *version, ++ uint32_t version_hash) attribute_hidden; ++ + /* Add the new link_map NEW to the end of the namespace list. */ + extern void _dl_add_to_namespace_list (struct link_map *new, Lmid_t nsid) + attribute_hidden; +diff --git a/sysdeps/mach/hurd/i386/init-first.c b/sysdeps/mach/hurd/i386/init-first.c +index f8ad2ceb8e324f92..1636a40ee5d78858 100644 +--- a/sysdeps/mach/hurd/i386/init-first.c ++++ b/sysdeps/mach/hurd/i386/init-first.c +@@ -17,7 +17,6 @@ + . */ + + #include +-#include + #include + #include + #include +@@ -84,9 +83,6 @@ posixland_init (int argc, char **argv, char **envp) + #endif + __init_misc (argc, argv, envp); + +- /* Initialize ctype data. */ +- __ctype_init (); +- + #if defined SHARED && !defined NO_CTORS_DTORS_SECTIONS + __libc_global_ctors (); + #endif diff --git a/SOURCES/glibc-rh1817513-51.patch b/SOURCES/glibc-rh1817513-51.patch new file mode 100644 index 0000000..2b56755 --- /dev/null +++ b/SOURCES/glibc-rh1817513-51.patch @@ -0,0 +1,688 @@ +commit 92954ffa5a5662fbfde14febd7e5dcc358c85470 +Author: Carlos O'Donell +Date: Wed Jan 8 13:24:42 2020 -0500 + + localedef: Add verbose messages for failure paths. + + During testing of localedef running in a minimal container + there were several error cases which were hard to diagnose + since they appeared as strerror (errno) values printed by the + higher level functions. This change adds three new verbose + messages for potential failure paths. The new messages give + the user the opportunity to use -v and display additional + information about why localedef might be failing. I found + these messages useful myself while writing a localedef + container test for --no-hard-links. + + Since the changes cleanup the code that handle codeset + normalization we add tst-localedef-path-norm which contains + many sub-tests to verify the correct expected normalization of + codeset strings both when installing to default paths (the + only time normalization is enabled) and installing to absolute + paths. During the refactoring I created at least one + buffer-overflow which valgrind caught, but these tests did not + catch because the exec in the container had a very clean heap + with zero-initialized memory. However, between valgrind and + the tests the results are clean. + + The new tst-localedef-path-norm passes without regression on + x86_64. + + Change-Id: I28b9f680711ff00252a2cb15625b774cc58ecb9d + +diff --git a/include/programs/xasprintf.h b/include/programs/xasprintf.h +new file mode 100644 +index 0000000000000000..53193ba3837f7418 +--- /dev/null ++++ b/include/programs/xasprintf.h +@@ -0,0 +1,24 @@ ++/* asprintf with out of memory checking ++ Copyright (C) 2019 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published ++ by the Free Software Foundation; version 2 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program; if not, see . */ ++ ++#ifndef _XASPRINTF_H ++#define _XASPRINTF_H 1 ++ ++extern char *xasprintf (const char *format, ...) ++ __attribute__ ((__format__ (__printf__, 1, 2), __warn_unused_result__)); ++ ++#endif /* xasprintf.h */ +diff --git a/locale/Makefile b/locale/Makefile +index 23a71321b6646c49..4278350cdc7be28d 100644 +--- a/locale/Makefile ++++ b/locale/Makefile +@@ -28,6 +28,7 @@ routines = setlocale findlocale loadlocale loadarchive \ + localeconv nl_langinfo nl_langinfo_l mb_cur_max \ + newlocale duplocale freelocale uselocale + tests = tst-C-locale tst-locname tst-duplocale ++tests-container = tst-localedef-path-norm + categories = ctype messages monetary numeric time paper name \ + address telephone measurement identification collate + aux = $(categories:%=lc-%) $(categories:%=C-%) SYS_libc C_name \ +@@ -54,7 +55,7 @@ localedef-modules := localedef $(categories:%=ld-%) \ + localedef-aux := md5 + locale-modules := locale locale-spec + lib-modules := charmap-dir simple-hash xmalloc xstrdup \ +- record-status ++ record-status xasprintf + + + GPERF = gperf +diff --git a/locale/programs/localedef.c b/locale/programs/localedef.c +index d718d2e9f47382bc..9a57d2cb435b25ed 100644 +--- a/locale/programs/localedef.c ++++ b/locale/programs/localedef.c +@@ -174,14 +174,14 @@ static struct argp argp = + + /* Prototypes for local functions. */ + static void error_print (void); +-static const char *construct_output_path (char *path); +-static const char *normalize_codeset (const char *codeset, size_t name_len); ++static char *construct_output_path (char *path); ++static char *normalize_codeset (const char *codeset, size_t name_len); + + + int + main (int argc, char *argv[]) + { +- const char *output_path; ++ char *output_path; + int cannot_write_why; + struct charmap_t *charmap; + struct localedef_t global; +@@ -226,7 +226,8 @@ main (int argc, char *argv[]) + } + + /* The parameter describes the output path of the constructed files. +- If the described files cannot be written return a NULL pointer. */ ++ If the described files cannot be written return a NULL pointer. ++ We don't free output_path because we will exit. */ + output_path = construct_output_path (argv[remaining]); + if (output_path == NULL && ! no_archive) + error (4, errno, _("cannot create directory for output files")); +@@ -424,20 +425,16 @@ more_help (int key, const char *text, void *input) + { + case ARGP_KEY_HELP_EXTRA: + /* We print some extra information. */ +- if (asprintf (&tp, gettext ("\ ++ tp = xasprintf (gettext ("\ + For bug reporting instructions, please see:\n\ +-%s.\n"), REPORT_BUGS_TO) < 0) +- return NULL; +- if (asprintf (&cp, gettext ("\ ++%s.\n"), REPORT_BUGS_TO); ++ cp = xasprintf (gettext ("\ + System's directory for character maps : %s\n\ + repertoire maps: %s\n\ + locale path : %s\n\ + %s"), +- CHARMAP_PATH, REPERTOIREMAP_PATH, LOCALE_PATH, tp) < 0) +- { +- free (tp); +- return NULL; +- } ++ CHARMAP_PATH, REPERTOIREMAP_PATH, LOCALE_PATH, tp); ++ free (tp); + return cp; + default: + break; +@@ -467,15 +464,13 @@ error_print (void) + } + + +-/* The parameter to localedef describes the output path. If it does +- contain a '/' character it is a relative path. Otherwise it names the +- locale this definition is for. */ +-static const char * ++/* The parameter to localedef describes the output path. If it does contain a ++ '/' character it is a relative path. Otherwise it names the locale this ++ definition is for. The returned path must be freed by the caller. */ ++static char * + construct_output_path (char *path) + { +- const char *normal = NULL; + char *result; +- char *endp; + + if (strchr (path, '/') == NULL) + { +@@ -483,50 +478,44 @@ construct_output_path (char *path) + contains a reference to the codeset. This should be + normalized. */ + char *startp; ++ char *endp = NULL; ++ char *normal = NULL; + + startp = path; +- /* We must be prepared for finding a CEN name or a location of +- the introducing `.' where it is not possible anymore. */ ++ /* Either we have a '@' which starts a CEN name or '.' which starts the ++ codeset specification. The CEN name starts with '@' and may also have ++ a codeset specification, but we do not normalize the string after '@'. ++ If we only find the codeset specification then we normalize only the codeset ++ specification (but not anything after a subsequent '@'). */ + while (*startp != '\0' && *startp != '@' && *startp != '.') + ++startp; + if (*startp == '.') + { + /* We found a codeset specification. Now find the end. */ + endp = ++startp; ++ ++ /* Stop at the first '@', and don't normalize anything past that. */ + while (*endp != '\0' && *endp != '@') + ++endp; + + if (endp > startp) + normal = normalize_codeset (startp, endp - startp); + } +- else +- /* This is to keep gcc quiet. */ +- endp = NULL; + +- /* We put an additional '\0' at the end of the string because at +- the end of the function we need another byte for the trailing +- '/'. */ +- ssize_t n; + if (normal == NULL) +- n = asprintf (&result, "%s%s/%s%c", output_prefix ?: "", +- COMPLOCALEDIR, path, '\0'); ++ result = xasprintf ("%s%s/%s/", output_prefix ?: "", ++ COMPLOCALEDIR, path); + else +- n = asprintf (&result, "%s%s/%.*s%s%s%c", +- output_prefix ?: "", COMPLOCALEDIR, +- (int) (startp - path), path, normal, endp, '\0'); +- +- if (n < 0) +- return NULL; +- +- endp = result + n - 1; ++ result = xasprintf ("%s%s/%.*s%s%s/", ++ output_prefix ?: "", COMPLOCALEDIR, ++ (int) (startp - path), path, normal, endp ?: ""); ++ /* Free the allocated normalized codeset name. */ ++ free (normal); + } + else + { +- /* This is a user path. Please note the additional byte in the +- memory allocation. */ +- size_t len = strlen (path) + 1; +- result = xmalloc (len + 1); +- endp = mempcpy (result, path, len) - 1; ++ /* This is a user path. */ ++ result = xasprintf ("%s/", path); + + /* If the user specified an output path we cannot add the output + to the archive. */ +@@ -536,25 +525,41 @@ construct_output_path (char *path) + errno = 0; + + if (no_archive && euidaccess (result, W_OK) == -1) +- /* Perhaps the directory does not exist now. Try to create it. */ +- if (errno == ENOENT) +- { +- errno = 0; +- if (mkdir (result, 0777) < 0) +- return NULL; +- } +- +- *endp++ = '/'; +- *endp = '\0'; ++ { ++ /* Perhaps the directory does not exist now. Try to create it. */ ++ if (errno == ENOENT) ++ { ++ errno = 0; ++ if (mkdir (result, 0777) < 0) ++ { ++ record_verbose (stderr, ++ _("cannot create output path \'%s\': %s"), ++ result, strerror (errno)); ++ free (result); ++ return NULL; ++ } ++ } ++ else ++ record_verbose (stderr, ++ _("no write permission to output path \'%s\': %s"), ++ result, strerror (errno)); ++ } + + return result; + } + + +-/* Normalize codeset name. There is no standard for the codeset +- names. Normalization allows the user to use any of the common +- names. */ +-static const char * ++/* Normalize codeset name. There is no standard for the codeset names. ++ Normalization allows the user to use any of the common names e.g. UTF-8, ++ utf-8, utf8, UTF8 etc. ++ ++ We normalize using the following rules: ++ - Remove all non-alpha-numeric characters ++ - Lowercase all characters. ++ - If there are only digits assume it's an ISO standard and prefix with 'iso' ++ ++ We return the normalized string which needs to be freed by free. */ ++static char * + normalize_codeset (const char *codeset, size_t name_len) + { + int len = 0; +@@ -563,6 +568,7 @@ normalize_codeset (const char *codeset, size_t name_len) + char *wp; + size_t cnt; + ++ /* Compute the length of only the alpha-numeric characters. */ + for (cnt = 0; cnt < name_len; ++cnt) + if (isalnum (codeset[cnt])) + { +@@ -572,25 +578,24 @@ normalize_codeset (const char *codeset, size_t name_len) + only_digit = 0; + } + +- retval = (char *) malloc ((only_digit ? 3 : 0) + len + 1); ++ /* If there were only digits we assume it's an ISO standard and we will ++ prefix with 'iso' so include space for that. We fill in the required ++ space from codeset up to the converted length. */ ++ wp = retval = xasprintf ("%s%.*s", only_digit ? "iso" : "", len, codeset); + +- if (retval != NULL) +- { +- if (only_digit) +- wp = stpcpy (retval, "iso"); +- else +- wp = retval; +- +- for (cnt = 0; cnt < name_len; ++cnt) +- if (isalpha (codeset[cnt])) +- *wp++ = tolower (codeset[cnt]); +- else if (isdigit (codeset[cnt])) +- *wp++ = codeset[cnt]; ++ /* Skip "iso". */ ++ if (only_digit) ++ wp += 3; + +- *wp = '\0'; +- } ++ /* Lowercase all characters. */ ++ for (cnt = 0; cnt < name_len; ++cnt) ++ if (isalpha (codeset[cnt])) ++ *wp++ = tolower (codeset[cnt]); ++ else if (isdigit (codeset[cnt])) ++ *wp++ = codeset[cnt]; + +- return (const char *) retval; ++ /* Return allocated and converted name for caller to free. */ ++ return retval; + } + + +diff --git a/locale/programs/localedef.h b/locale/programs/localedef.h +index 0083faceabbf3dd9..c528dbb97854dbd1 100644 +--- a/locale/programs/localedef.h ++++ b/locale/programs/localedef.h +@@ -122,6 +122,7 @@ extern const char *alias_file; + + /* Prototypes for a few program-wide used functions. */ + #include ++#include + + + /* Mark given locale as to be read. */ +diff --git a/locale/programs/xasprintf.c b/locale/programs/xasprintf.c +new file mode 100644 +index 0000000000000000..efc91a9c34074736 +--- /dev/null ++++ b/locale/programs/xasprintf.c +@@ -0,0 +1,34 @@ ++/* asprintf with out of memory checking ++ Copyright (C) 2019 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published ++ by the Free Software Foundation; version 2 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program; if not, see . */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++char * ++xasprintf (const char *format, ...) ++{ ++ va_list ap; ++ va_start (ap, format); ++ char *result; ++ if (vasprintf (&result, format, ap) < 0) ++ error (EXIT_FAILURE, 0, _("memory exhausted")); ++ va_end (ap); ++ return result; ++} +diff --git a/locale/tst-localedef-path-norm.c b/locale/tst-localedef-path-norm.c +new file mode 100644 +index 0000000000000000..2ef1d26f07084c68 +--- /dev/null ++++ b/locale/tst-localedef-path-norm.c +@@ -0,0 +1,242 @@ ++/* Test for localedef path name handling and normalization. ++ 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, see ++ . */ ++ ++/* The test runs localedef with various named paths to test for expected ++ behaviours dealing with codeset name normalization. That is to say that use ++ of UTF-8, and it's variations, are normalized to utf8. Likewise that values ++ after the @ are not normalized and left as-is. The test needs to run ++ localedef with known input values and then check that the generated path ++ matches the expected value after normalization. */ ++ ++/* Note: In some cases adding -v (verbose) to localedef changes the exit ++ status to a non-zero value because some warnings are only enabled in verbose ++ mode. This should probably be changed so warnings are either present or not ++ present, regardless of verbosity. POSIX requires that any warnings cause the ++ exit status to be non-zero. */ ++ ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++ ++/* Full path to localedef. */ ++char *prog; ++ ++/* Execute localedef in a subprocess. */ ++static void ++execv_wrapper (void *args) ++{ ++ char **argv = args; ++ ++ execv (prog, argv); ++ FAIL_EXIT1 ("execv: %m"); ++} ++ ++struct test_closure ++{ ++ /* Arguments for running localedef. */ ++ const char *const argv[16]; ++ /* Expected directory name for compiled locale. */ ++ const char *exp; ++ /* Expected path to compiled locale. */ ++ const char *complocaledir; ++}; ++ ++/* Run localedef with DATA.ARGV arguments (NULL terminated), and expect path to ++ the compiled locale is "DATA.COMPLOCALEDIR/DATA.EXP". */ ++static void ++run_test (struct test_closure data) ++{ ++ const char * const *args = data.argv; ++ const char *exp = data.exp; ++ const char *complocaledir = data.complocaledir; ++ struct stat64 fs; ++ ++ /* Expected output path. */ ++ const char *path = xasprintf ("%s/%s", complocaledir, exp); ++ ++ /* Run test. */ ++ struct support_capture_subprocess result; ++ result = support_capture_subprocess (execv_wrapper, (void *)args); ++ support_capture_subprocess_check (&result, "execv", 0, sc_allow_none); ++ support_capture_subprocess_free (&result); ++ ++ /* Verify path is present and is a directory. */ ++ xstat (path, &fs); ++ TEST_VERIFY_EXIT (S_ISDIR (fs.st_mode)); ++ printf ("info: Directory '%s' exists.\n", path); ++} ++ ++static int ++do_test (void) ++{ ++ /* We are running as root inside the container. */ ++ prog = xasprintf ("%s/localedef", support_bindir_prefix); ++ ++ /* Create the needed directories: ++ - We need the default compiled locale dir for default output. ++ - We need an arbitrary absolute path for localedef output. ++ ++ Note: Writing to a non-default absolute path disables any kind ++ of path normalization since we expect the user wants the path ++ exactly as they specified it. */ ++ xmkdirp (support_complocaledir_prefix, 0777); ++ xmkdirp ("/output", 0777); ++ ++ /* It takes ~10 seconds to serially execute 9 localedef test. We ++ could run the compilations in parallel if we want to reduce test ++ time. We don't want to split this out into distinct tests because ++ it would require multiple chroots. Batching the same localedef ++ tests saves disk space during testing. */ ++ ++ /* Test 1: Expected normalization. ++ Run localedef and expect output in /usr/lib/locale/en_US1.utf8, ++ with normalization changing UTF-8 to utf8. */ ++ run_test ((struct test_closure) ++ { ++ .argv = { prog, ++ "--no-archive", ++ "-i", "en_US", ++ "-f", "UTF-8", ++ "en_US1.UTF-8", NULL }, ++ .exp = "en_US1.utf8", ++ .complocaledir = support_complocaledir_prefix ++ }); ++ ++ /* Test 2: No normalization past '@'. ++ Run localedef and expect output in /usr/lib/locale/en_US2.utf8@tEsT, ++ with normalization changing UTF-8@tEsT to utf8@tEsT (everything after ++ @ is untouched). */ ++ run_test ((struct test_closure) ++ { ++ .argv = { prog, ++ "--no-archive", ++ "-i", "en_US", ++ "-f", "UTF-8", ++ "en_US2.UTF-8@tEsT", NULL }, ++ .exp = "en_US2.utf8@tEsT", ++ .complocaledir = support_complocaledir_prefix ++ }); ++ ++ /* Test 3: No normalization past '@' despite period. ++ Run localedef and expect output in /usr/lib/locale/en_US3@tEsT.UTF-8, ++ with normalization changing nothing (everything after @ is untouched) ++ despite there being a period near the end. */ ++ run_test ((struct test_closure) ++ { ++ .argv = { prog, ++ "--no-archive", ++ "-i", "en_US", ++ "-f", "UTF-8", ++ "en_US3@tEsT.UTF-8", NULL }, ++ .exp = "en_US3@tEsT.UTF-8", ++ .complocaledir = support_complocaledir_prefix ++ }); ++ ++ /* Test 4: Normalize numeric codeset by adding 'iso' prefix. ++ Run localedef and expect output in /usr/lib/locale/en_US4.88591, ++ with normalization changing 88591 to iso88591. */ ++ run_test ((struct test_closure) ++ { ++ .argv = { prog, ++ "--no-archive", ++ "-i", "en_US", ++ "-f", "UTF-8", ++ "en_US4.88591", NULL }, ++ .exp = "en_US4.iso88591", ++ .complocaledir = support_complocaledir_prefix ++ }); ++ ++ /* Test 5: Don't add 'iso' prefix if first char is alpha. ++ Run localedef and expect output in /usr/lib/locale/en_US5.a88591, ++ with normalization changing nothing. */ ++ run_test ((struct test_closure) ++ { ++ .argv = { prog, ++ "--no-archive", ++ "-i", "en_US", ++ "-f", "UTF-8", ++ "en_US5.a88591", NULL }, ++ .exp = "en_US5.a88591", ++ .complocaledir = support_complocaledir_prefix ++ }); ++ ++ /* Test 6: Don't add 'iso' prefix if last char is alpha. ++ Run localedef and expect output in /usr/lib/locale/en_US6.88591a, ++ with normalization changing nothing. */ ++ run_test ((struct test_closure) ++ { ++ .argv = { prog, ++ "--no-archive", ++ "-i", "en_US", ++ "-f", "UTF-8", ++ "en_US6.88591a", NULL }, ++ .exp = "en_US6.88591a", ++ .complocaledir = support_complocaledir_prefix ++ }); ++ ++ /* Test 7: Don't normalize anything with an absolute path. ++ Run localedef and expect output in /output/en_US7.UTF-8, ++ with normalization changing nothing. */ ++ run_test ((struct test_closure) ++ { ++ .argv = { prog, ++ "--no-archive", ++ "-i", "en_US", ++ "-f", "UTF-8", ++ "/output/en_US7.UTF-8", NULL }, ++ .exp = "en_US7.UTF-8", ++ .complocaledir = "/output" ++ }); ++ ++ /* Test 8: Don't normalize anything with an absolute path. ++ Run localedef and expect output in /output/en_US8.UTF-8@tEsT, ++ with normalization changing nothing. */ ++ run_test ((struct test_closure) ++ { ++ .argv = { prog, ++ "--no-archive", ++ "-i", "en_US", ++ "-f", "UTF-8", ++ "/output/en_US8.UTF-8@tEsT", NULL }, ++ .exp = "en_US8.UTF-8@tEsT", ++ .complocaledir = "/output" ++ }); ++ ++ /* Test 9: Don't normalize anything with an absolute path. ++ Run localedef and expect output in /output/en_US9@tEsT.UTF-8, ++ with normalization changing nothing. */ ++ run_test ((struct test_closure) ++ { ++ .argv = { prog, ++ "--no-archive", ++ "-i", "en_US", ++ "-f", "UTF-8", ++ "/output/en_US9@tEsT.UTF-8", NULL }, ++ .exp = "en_US9@tEsT.UTF-8", ++ .complocaledir = "/output" ++ }); ++ ++ return 0; ++} ++ ++#include +diff --git a/locale/tst-localedef-path-norm.root/postclean.req b/locale/tst-localedef-path-norm.root/postclean.req +new file mode 100644 +index 0000000000000000..e69de29bb2d1d643 +diff --git a/locale/tst-localedef-path-norm.root/tst-localedef-path-norm.script b/locale/tst-localedef-path-norm.root/tst-localedef-path-norm.script +new file mode 100644 +index 0000000000000000..b0f016256a47f762 +--- /dev/null ++++ b/locale/tst-localedef-path-norm.root/tst-localedef-path-norm.script +@@ -0,0 +1,2 @@ ++# Must run localedef as root to write into default paths. ++su +diff --git a/support/Makefile b/support/Makefile +index 117cfdd4f22fc405..5808a42dce87151f 100644 +--- a/support/Makefile ++++ b/support/Makefile +@@ -182,7 +182,8 @@ CFLAGS-support_paths.c = \ + -DLIBDIR_PATH=\"$(libdir)\" \ + -DBINDIR_PATH=\"$(bindir)\" \ + -DSBINDIR_PATH=\"$(sbindir)\" \ +- -DROOTSBINDIR_PATH=\"$(rootsbindir)\" ++ -DROOTSBINDIR_PATH=\"$(rootsbindir)\" \ ++ -DCOMPLOCALEDIR_PATH=\"$(complocaledir)\" + + ifeq (,$(CXX)) + LINKS_DSO_PROGRAM = links-dso-program-c +diff --git a/support/support.h b/support/support.h +index 121cc9e9b7c98ca6..3af87f85fe1b762d 100644 +--- a/support/support.h ++++ b/support/support.h +@@ -112,6 +112,8 @@ extern const char support_bindir_prefix[]; + extern const char support_sbindir_prefix[]; + /* Corresponds to the install's sbin/ directory (without prefix). */ + extern const char support_install_rootsbindir[]; ++/* Corresponds to the install's compiled locale directory. */ ++extern const char support_complocaledir_prefix[]; + + extern ssize_t support_copy_file_range (int, off64_t *, int, off64_t *, + size_t, unsigned int); +diff --git a/support/support_paths.c b/support/support_paths.c +index eb2390227433aa70..6b15fae0f0173b1e 100644 +--- a/support/support_paths.c ++++ b/support/support_paths.c +@@ -78,3 +78,10 @@ const char support_install_rootsbindir[] = ROOTSBINDIR_PATH; + #else + # error please -DROOTSBINDIR_PATH=something in the Makefile + #endif ++ ++#ifdef COMPLOCALEDIR_PATH ++/* Corresponds to the install's compiled locale directory. */ ++const char support_complocaledir_prefix[] = COMPLOCALEDIR_PATH; ++#else ++# error please -DCOMPLOCALEDIR_PATH=something in the Makefile ++#endif diff --git a/SOURCES/glibc-rh1817513-52.patch b/SOURCES/glibc-rh1817513-52.patch new file mode 100644 index 0000000..61dbcf9 --- /dev/null +++ b/SOURCES/glibc-rh1817513-52.patch @@ -0,0 +1,141 @@ +commit 03e187a41d91069543cfcf33469a05912e555447 +Author: Florian Weimer +Date: Wed Apr 29 15:44:03 2020 +0200 + + elf: Add initial flag argument to __libc_early_init + + The rseq initialization should happen only for the libc in the base + namespace (in the dynamic case) or the statically linked libc. The + __libc_multiple_libcs flag does not quite cover this case at present, + so this commit introduces a flag argument to __libc_early_init, + indicating whether the libc being libc is the primary one (of the main + program). + + Reviewed-by: Carlos O'Donell + +diff --git a/csu/libc-start.c b/csu/libc-start.c +index d9c3248219d8f84f..fd0f8640eaeae34c 100644 +--- a/csu/libc-start.c ++++ b/csu/libc-start.c +@@ -23,6 +23,7 @@ + #include + #include + #include ++#include + + #include + +@@ -241,7 +242,7 @@ LIBC_START_MAIN (int (*main) (int, char **, char ** MAIN_AUXVEC_DECL), + #ifndef SHARED + /* Perform early initialization. In the shared case, this function + is called from the dynamic loader as early as possible. */ +- __libc_early_init (); ++ __libc_early_init (true); + + /* Call the initializer of the libc. This is only needed here if we + are compiling for the static library in which case we haven't +diff --git a/elf/dl-call-libc-early-init.c b/elf/dl-call-libc-early-init.c +index 41e9ad9aad8b5b46..9a84680a1ceafba2 100644 +--- a/elf/dl-call-libc-early-init.c ++++ b/elf/dl-call-libc-early-init.c +@@ -23,7 +23,7 @@ + #include + + void +-_dl_call_libc_early_init (struct link_map *libc_map) ++_dl_call_libc_early_init (struct link_map *libc_map, _Bool initial) + { + /* There is nothing to do if we did not actually load libc.so. */ + if (libc_map == NULL) +@@ -37,5 +37,5 @@ _dl_call_libc_early_init (struct link_map *libc_map) + assert (sym != NULL); + __typeof (__libc_early_init) *early_init + = DL_SYMBOL_ADDRESS (libc_map, sym); +- early_init (); ++ early_init (initial); + } +diff --git a/elf/dl-open.c b/elf/dl-open.c +index 1a77ec833cad6c55..3d49a84596e99bf6 100644 +--- a/elf/dl-open.c ++++ b/elf/dl-open.c +@@ -748,9 +748,22 @@ dl_open_worker (void *a) + LIBC_PROBE (reloc_complete, 3, args->nsid, r, new); + + /* If libc.so was not there before, attempt to call its early +- initialization routine. */ ++ initialization routine. Indicate to the initialization routine ++ whether the libc being initialized is the one in the base ++ namespace. */ + if (!args->libc_already_loaded) +- _dl_call_libc_early_init (GL(dl_ns)[args->nsid].libc_map); ++ { ++ 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); ++ } + + #ifndef SHARED + DL_STATIC_INIT (new); +diff --git a/elf/libc-early-init.h b/elf/libc-early-init.h +index 5185fa8895c0e11a..8f7836dceaeecd5a 100644 +--- a/elf/libc-early-init.h ++++ b/elf/libc-early-init.h +@@ -22,14 +22,17 @@ + struct link_map; + + /* If LIBC_MAP is not NULL, look up the __libc_early_init symbol in it +- and call this function. */ +-void _dl_call_libc_early_init (struct link_map *libc_map) attribute_hidden; ++ and call this function, with INITIAL as the argument. */ ++void _dl_call_libc_early_init (struct link_map *libc_map, _Bool initial) ++ attribute_hidden; + + /* In the shared case, this function is defined in libc.so and invoked + from ld.so (or on the fist static dlopen) after complete relocation + of a new loaded libc.so, but before user-defined ELF constructors + run. In the static case, this function is called directly from the +- startup code. */ +-void __libc_early_init (void); ++ startup code. If INITIAL is true, the libc being initialized is ++ the libc for the main program. INITIAL is false for libcs loaded ++ for audit modules, dlmopen, and static dlopen. */ ++void __libc_early_init (_Bool initial); + + #endif /* _LIBC_EARLY_INIT_H */ +diff --git a/elf/libc_early_init.c b/elf/libc_early_init.c +index 7f4ca332b805a22c..e6c64fb526600fae 100644 +--- a/elf/libc_early_init.c ++++ b/elf/libc_early_init.c +@@ -20,7 +20,7 @@ + #include + + void +-__libc_early_init (void) ++__libc_early_init (_Bool initial) + { + /* Initialize ctype data. */ + __ctype_init (); +diff --git a/elf/rtld.c b/elf/rtld.c +index a40d5f17db0dac8b..772aff5160359b7b 100644 +--- a/elf/rtld.c ++++ b/elf/rtld.c +@@ -2366,8 +2366,10 @@ ERROR: '%s': cannot process note segment.\n", _dl_argv[0]); + rtld_timer_accum (&relocate_time, start); + } + +- /* Relocation is complete. Perform early libc initialization. */ +- _dl_call_libc_early_init (GL(dl_ns)[LM_ID_BASE].libc_map); ++ /* Relocation is complete. Perform early libc initialization. This ++ is the initial libc, even if audit modules have been loaded with ++ other libcs. */ ++ _dl_call_libc_early_init (GL(dl_ns)[LM_ID_BASE].libc_map, true); + + /* Do any necessary cleanups for the startup OS interface code. + We do these now so that no calls are made after rtld re-relocation diff --git a/SOURCES/glibc-rh1817513-53.patch b/SOURCES/glibc-rh1817513-53.patch new file mode 100644 index 0000000..fdd8a41 --- /dev/null +++ b/SOURCES/glibc-rh1817513-53.patch @@ -0,0 +1,86 @@ +commit 32ac0b988466785d6e3cc1dffc364bb26fc63193 +Author: mayshao +Date: Fri Apr 24 12:55:38 2020 +0800 + + x86: Add CPU Vendor ID detection support for Zhaoxin processors + + To recognize Zhaoxin CPU Vendor ID, add a new architecture type + arch_kind_zhaoxin for Vendor Zhaoxin detection. + +diff --git a/sysdeps/x86/cpu-features.c b/sysdeps/x86/cpu-features.c +index ade37a9bb3de86cc..c432d646ce6806a6 100644 +--- a/sysdeps/x86/cpu-features.c ++++ b/sysdeps/x86/cpu-features.c +@@ -464,6 +464,60 @@ init_cpu_features (struct cpu_features *cpu_features) + } + } + } ++ /* This spells out "CentaurHauls" or " Shanghai ". */ ++ else if ((ebx == 0x746e6543 && ecx == 0x736c7561 && edx == 0x48727561) ++ || (ebx == 0x68532020 && ecx == 0x20206961 && edx == 0x68676e61)) ++ { ++ unsigned int extended_model, stepping; ++ ++ kind = arch_kind_zhaoxin; ++ ++ get_common_indices (cpu_features, &family, &model, &extended_model, ++ &stepping); ++ ++ get_extended_indices (cpu_features); ++ ++ model += extended_model; ++ if (family == 0x6) ++ { ++ if (model == 0xf || model == 0x19) ++ { ++ cpu_features->feature[index_arch_AVX_Usable] ++ &= (~bit_arch_AVX_Usable ++ & ~bit_arch_AVX2_Usable); ++ ++ cpu_features->feature[index_arch_Slow_SSE4_2] ++ |= (bit_arch_Slow_SSE4_2); ++ ++ cpu_features->feature[index_arch_AVX_Fast_Unaligned_Load] ++ &= ~bit_arch_AVX_Fast_Unaligned_Load; ++ } ++ } ++ else if (family == 0x7) ++ { ++ if (model == 0x1b) ++ { ++ cpu_features->feature[index_arch_AVX_Usable] ++ &= (~bit_arch_AVX_Usable ++ & ~bit_arch_AVX2_Usable); ++ ++ cpu_features->feature[index_arch_Slow_SSE4_2] ++ |= bit_arch_Slow_SSE4_2; ++ ++ cpu_features->feature[index_arch_AVX_Fast_Unaligned_Load] ++ &= ~bit_arch_AVX_Fast_Unaligned_Load; ++ } ++ else if (model == 0x3b) ++ { ++ cpu_features->feature[index_arch_AVX_Usable] ++ &= (~bit_arch_AVX_Usable ++ & ~bit_arch_AVX2_Usable); ++ ++ cpu_features->feature[index_arch_AVX_Fast_Unaligned_Load] ++ &= ~bit_arch_AVX_Fast_Unaligned_Load; ++ } ++ } ++ } + else + { + kind = arch_kind_other; +diff --git a/sysdeps/x86/cpu-features.h b/sysdeps/x86/cpu-features.h +index 4917182e99a8ee90..388172a1c07bf979 100644 +--- a/sysdeps/x86/cpu-features.h ++++ b/sysdeps/x86/cpu-features.h +@@ -53,6 +53,7 @@ enum cpu_features_kind + arch_kind_unknown = 0, + arch_kind_intel, + arch_kind_amd, ++ arch_kind_zhaoxin, + arch_kind_other + }; + diff --git a/SOURCES/glibc-rh1817513-54.patch b/SOURCES/glibc-rh1817513-54.patch new file mode 100644 index 0000000..44a747e --- /dev/null +++ b/SOURCES/glibc-rh1817513-54.patch @@ -0,0 +1,534 @@ +commit a98dc92dd1e278df4c501deb07985018bc2b06de +Author: mayshao-oc +Date: Sun Apr 26 13:48:27 2020 +0800 + + x86: Add cache information support for Zhaoxin processors + + To obtain Zhaoxin CPU cache information, add a new function + handle_zhaoxin(). + + Add a new function get_common_cache_info() that extracts the code + in init_cacheinfo() to get the value of the variable shared, threads. + + Add Zhaoxin branch in init_cacheinfo() for initializing variables, + such as __x86_shared_cache_size. + +diff --git a/sysdeps/x86/cacheinfo.c b/sysdeps/x86/cacheinfo.c +index f1125f30223f5ca3..aa7cb705d546bcd0 100644 +--- a/sysdeps/x86/cacheinfo.c ++++ b/sysdeps/x86/cacheinfo.c +@@ -436,6 +436,57 @@ handle_amd (int name) + } + + ++static long int __attribute__ ((noinline)) ++handle_zhaoxin (int name) ++{ ++ unsigned int eax; ++ unsigned int ebx; ++ unsigned int ecx; ++ unsigned int edx; ++ ++ int folded_rel_name = (M(name) / 3) * 3; ++ ++ unsigned int round = 0; ++ while (1) ++ { ++ __cpuid_count (4, round, eax, ebx, ecx, edx); ++ ++ enum { null = 0, data = 1, inst = 2, uni = 3 } type = eax & 0x1f; ++ if (type == null) ++ break; ++ ++ unsigned int level = (eax >> 5) & 0x7; ++ ++ if ((level == 1 && type == data ++ && folded_rel_name == M(_SC_LEVEL1_DCACHE_SIZE)) ++ || (level == 1 && type == inst ++ && folded_rel_name == M(_SC_LEVEL1_ICACHE_SIZE)) ++ || (level == 2 && folded_rel_name == M(_SC_LEVEL2_CACHE_SIZE)) ++ || (level == 3 && folded_rel_name == M(_SC_LEVEL3_CACHE_SIZE))) ++ { ++ unsigned int offset = M(name) - folded_rel_name; ++ ++ if (offset == 0) ++ /* Cache size. */ ++ return (((ebx >> 22) + 1) ++ * (((ebx >> 12) & 0x3ff) + 1) ++ * ((ebx & 0xfff) + 1) ++ * (ecx + 1)); ++ if (offset == 1) ++ return (ebx >> 22) + 1; ++ ++ assert (offset == 2); ++ return (ebx & 0xfff) + 1; ++ } ++ ++ ++round; ++ } ++ ++ /* Nothing found. */ ++ return 0; ++} ++ ++ + /* Get the value of the system variable NAME. */ + long int + attribute_hidden +@@ -449,6 +500,9 @@ __cache_sysconf (int name) + if (cpu_features->basic.kind == arch_kind_amd) + return handle_amd (name); + ++ if (cpu_features->basic.kind == arch_kind_zhaoxin) ++ return handle_zhaoxin (name); ++ + // XXX Fill in more vendors. + + /* CPU not known, we have no information. */ +@@ -482,6 +536,224 @@ int __x86_prefetchw attribute_hidden; + #endif + + ++static void ++get_common_cache_info (long int *shared_ptr, unsigned int *threads_ptr, ++ long int core) ++{ ++ unsigned int eax; ++ unsigned int ebx; ++ unsigned int ecx; ++ unsigned int edx; ++ ++ /* Number of logical processors sharing L2 cache. */ ++ int threads_l2; ++ ++ /* Number of logical processors sharing L3 cache. */ ++ int threads_l3; ++ ++ const struct cpu_features *cpu_features = __get_cpu_features (); ++ int max_cpuid = cpu_features->basic.max_cpuid; ++ unsigned int family = cpu_features->basic.family; ++ unsigned int model = cpu_features->basic.model; ++ long int shared = *shared_ptr; ++ unsigned int threads = *threads_ptr; ++ bool inclusive_cache = true; ++ bool support_count_mask = true; ++ ++ /* Try L3 first. */ ++ unsigned int level = 3; ++ ++ if (cpu_features->basic.kind == arch_kind_zhaoxin && family == 6) ++ support_count_mask = false; ++ ++ if (shared <= 0) ++ { ++ /* Try L2 otherwise. */ ++ level = 2; ++ shared = core; ++ threads_l2 = 0; ++ threads_l3 = -1; ++ } ++ else ++ { ++ threads_l2 = 0; ++ threads_l3 = 0; ++ } ++ ++ /* A value of 0 for the HTT bit indicates there is only a single ++ logical processor. */ ++ if (HAS_CPU_FEATURE (HTT)) ++ { ++ /* Figure out the number of logical threads that share the ++ highest cache level. */ ++ if (max_cpuid >= 4) ++ { ++ int i = 0; ++ ++ /* Query until cache level 2 and 3 are enumerated. */ ++ int check = 0x1 | (threads_l3 == 0) << 1; ++ do ++ { ++ __cpuid_count (4, i++, eax, ebx, ecx, edx); ++ ++ /* There seems to be a bug in at least some Pentium Ds ++ which sometimes fail to iterate all cache parameters. ++ Do not loop indefinitely here, stop in this case and ++ assume there is no such information. */ ++ if (cpu_features->basic.kind == arch_kind_intel ++ && (eax & 0x1f) == 0 ) ++ goto intel_bug_no_cache_info; ++ ++ switch ((eax >> 5) & 0x7) ++ { ++ default: ++ break; ++ case 2: ++ if ((check & 0x1)) ++ { ++ /* Get maximum number of logical processors ++ sharing L2 cache. */ ++ threads_l2 = (eax >> 14) & 0x3ff; ++ check &= ~0x1; ++ } ++ break; ++ case 3: ++ if ((check & (0x1 << 1))) ++ { ++ /* Get maximum number of logical processors ++ sharing L3 cache. */ ++ threads_l3 = (eax >> 14) & 0x3ff; ++ ++ /* Check if L2 and L3 caches are inclusive. */ ++ inclusive_cache = (edx & 0x2) != 0; ++ check &= ~(0x1 << 1); ++ } ++ break; ++ } ++ } ++ while (check); ++ ++ /* If max_cpuid >= 11, THREADS_L2/THREADS_L3 are the maximum ++ numbers of addressable IDs for logical processors sharing ++ the cache, instead of the maximum number of threads ++ sharing the cache. */ ++ if (max_cpuid >= 11 && support_count_mask) ++ { ++ /* Find the number of logical processors shipped in ++ one core and apply count mask. */ ++ i = 0; ++ ++ /* Count SMT only if there is L3 cache. Always count ++ core if there is no L3 cache. */ ++ int count = ((threads_l2 > 0 && level == 3) ++ | ((threads_l3 > 0 ++ || (threads_l2 > 0 && level == 2)) << 1)); ++ ++ while (count) ++ { ++ __cpuid_count (11, i++, eax, ebx, ecx, edx); ++ ++ int shipped = ebx & 0xff; ++ int type = ecx & 0xff00; ++ if (shipped == 0 || type == 0) ++ break; ++ else if (type == 0x100) ++ { ++ /* Count SMT. */ ++ if ((count & 0x1)) ++ { ++ int count_mask; ++ ++ /* Compute count mask. */ ++ asm ("bsr %1, %0" ++ : "=r" (count_mask) : "g" (threads_l2)); ++ count_mask = ~(-1 << (count_mask + 1)); ++ threads_l2 = (shipped - 1) & count_mask; ++ count &= ~0x1; ++ } ++ } ++ else if (type == 0x200) ++ { ++ /* Count core. */ ++ if ((count & (0x1 << 1))) ++ { ++ int count_mask; ++ int threads_core ++ = (level == 2 ? threads_l2 : threads_l3); ++ ++ /* Compute count mask. */ ++ asm ("bsr %1, %0" ++ : "=r" (count_mask) : "g" (threads_core)); ++ count_mask = ~(-1 << (count_mask + 1)); ++ threads_core = (shipped - 1) & count_mask; ++ if (level == 2) ++ threads_l2 = threads_core; ++ else ++ threads_l3 = threads_core; ++ count &= ~(0x1 << 1); ++ } ++ } ++ } ++ } ++ if (threads_l2 > 0) ++ threads_l2 += 1; ++ if (threads_l3 > 0) ++ threads_l3 += 1; ++ if (level == 2) ++ { ++ if (threads_l2) ++ { ++ threads = threads_l2; ++ if (cpu_features->basic.kind == arch_kind_intel ++ && threads > 2 ++ && family == 6) ++ switch (model) ++ { ++ case 0x37: ++ case 0x4a: ++ case 0x4d: ++ case 0x5a: ++ case 0x5d: ++ /* Silvermont has L2 cache shared by 2 cores. */ ++ threads = 2; ++ break; ++ default: ++ break; ++ } ++ } ++ } ++ else if (threads_l3) ++ threads = threads_l3; ++ } ++ else ++ { ++intel_bug_no_cache_info: ++ /* Assume that all logical threads share the highest cache ++ level. */ ++ threads ++ = ((cpu_features->cpuid[COMMON_CPUID_INDEX_1].ebx ++ >> 16) & 0xff); ++ } ++ ++ /* Cap usage of highest cache level to the number of supported ++ threads. */ ++ if (shared > 0 && threads > 0) ++ shared /= threads; ++ } ++ ++ /* Account for non-inclusive L2 and L3 caches. */ ++ if (!inclusive_cache) ++ { ++ if (threads_l2 > 0) ++ core /= threads_l2; ++ shared += core; ++ } ++ ++ *shared_ptr = shared; ++ *threads_ptr = threads; ++} ++ ++ + static void + __attribute__((constructor)) + init_cacheinfo (void) +@@ -494,211 +766,25 @@ init_cacheinfo (void) + int max_cpuid_ex; + long int data = -1; + long int shared = -1; +- unsigned int level; ++ long int core; + unsigned int threads = 0; + const struct cpu_features *cpu_features = __get_cpu_features (); +- int max_cpuid = cpu_features->basic.max_cpuid; + + if (cpu_features->basic.kind == arch_kind_intel) + { + data = handle_intel (_SC_LEVEL1_DCACHE_SIZE, cpu_features); +- +- long int core = handle_intel (_SC_LEVEL2_CACHE_SIZE, cpu_features); +- bool inclusive_cache = true; +- +- /* Try L3 first. */ +- level = 3; ++ core = handle_intel (_SC_LEVEL2_CACHE_SIZE, cpu_features); + shared = handle_intel (_SC_LEVEL3_CACHE_SIZE, cpu_features); + +- /* Number of logical processors sharing L2 cache. */ +- int threads_l2; +- +- /* Number of logical processors sharing L3 cache. */ +- int threads_l3; +- +- if (shared <= 0) +- { +- /* Try L2 otherwise. */ +- level = 2; +- shared = core; +- threads_l2 = 0; +- threads_l3 = -1; +- } +- else +- { +- threads_l2 = 0; +- threads_l3 = 0; +- } +- +- /* A value of 0 for the HTT bit indicates there is only a single +- logical processor. */ +- if (HAS_CPU_FEATURE (HTT)) +- { +- /* Figure out the number of logical threads that share the +- highest cache level. */ +- if (max_cpuid >= 4) +- { +- unsigned int family = cpu_features->basic.family; +- unsigned int model = cpu_features->basic.model; +- +- int i = 0; +- +- /* Query until cache level 2 and 3 are enumerated. */ +- int check = 0x1 | (threads_l3 == 0) << 1; +- do +- { +- __cpuid_count (4, i++, eax, ebx, ecx, edx); +- +- /* There seems to be a bug in at least some Pentium Ds +- which sometimes fail to iterate all cache parameters. +- Do not loop indefinitely here, stop in this case and +- assume there is no such information. */ +- if ((eax & 0x1f) == 0) +- goto intel_bug_no_cache_info; +- +- switch ((eax >> 5) & 0x7) +- { +- default: +- break; +- case 2: +- if ((check & 0x1)) +- { +- /* Get maximum number of logical processors +- sharing L2 cache. */ +- threads_l2 = (eax >> 14) & 0x3ff; +- check &= ~0x1; +- } +- break; +- case 3: +- if ((check & (0x1 << 1))) +- { +- /* Get maximum number of logical processors +- sharing L3 cache. */ +- threads_l3 = (eax >> 14) & 0x3ff; +- +- /* Check if L2 and L3 caches are inclusive. */ +- inclusive_cache = (edx & 0x2) != 0; +- check &= ~(0x1 << 1); +- } +- break; +- } +- } +- while (check); +- +- /* If max_cpuid >= 11, THREADS_L2/THREADS_L3 are the maximum +- numbers of addressable IDs for logical processors sharing +- the cache, instead of the maximum number of threads +- sharing the cache. */ +- if (max_cpuid >= 11) +- { +- /* Find the number of logical processors shipped in +- one core and apply count mask. */ +- i = 0; +- +- /* Count SMT only if there is L3 cache. Always count +- core if there is no L3 cache. */ +- int count = ((threads_l2 > 0 && level == 3) +- | ((threads_l3 > 0 +- || (threads_l2 > 0 && level == 2)) << 1)); +- +- while (count) +- { +- __cpuid_count (11, i++, eax, ebx, ecx, edx); +- +- int shipped = ebx & 0xff; +- int type = ecx & 0xff00; +- if (shipped == 0 || type == 0) +- break; +- else if (type == 0x100) +- { +- /* Count SMT. */ +- if ((count & 0x1)) +- { +- int count_mask; +- +- /* Compute count mask. */ +- asm ("bsr %1, %0" +- : "=r" (count_mask) : "g" (threads_l2)); +- count_mask = ~(-1 << (count_mask + 1)); +- threads_l2 = (shipped - 1) & count_mask; +- count &= ~0x1; +- } +- } +- else if (type == 0x200) +- { +- /* Count core. */ +- if ((count & (0x1 << 1))) +- { +- int count_mask; +- int threads_core +- = (level == 2 ? threads_l2 : threads_l3); +- +- /* Compute count mask. */ +- asm ("bsr %1, %0" +- : "=r" (count_mask) : "g" (threads_core)); +- count_mask = ~(-1 << (count_mask + 1)); +- threads_core = (shipped - 1) & count_mask; +- if (level == 2) +- threads_l2 = threads_core; +- else +- threads_l3 = threads_core; +- count &= ~(0x1 << 1); +- } +- } +- } +- } +- if (threads_l2 > 0) +- threads_l2 += 1; +- if (threads_l3 > 0) +- threads_l3 += 1; +- if (level == 2) +- { +- if (threads_l2) +- { +- threads = threads_l2; +- if (threads > 2 && family == 6) +- switch (model) +- { +- case 0x37: +- case 0x4a: +- case 0x4d: +- case 0x5a: +- case 0x5d: +- /* Silvermont has L2 cache shared by 2 cores. */ +- threads = 2; +- break; +- default: +- break; +- } +- } +- } +- else if (threads_l3) +- threads = threads_l3; +- } +- else +- { +-intel_bug_no_cache_info: +- /* Assume that all logical threads share the highest cache +- level. */ +- +- threads +- = ((cpu_features->cpuid[COMMON_CPUID_INDEX_1].ebx +- >> 16) & 0xff); +- } +- +- /* Cap usage of highest cache level to the number of supported +- threads. */ +- if (shared > 0 && threads > 0) +- shared /= threads; +- } ++ get_common_cache_info (&shared, &threads, core); ++ } ++ else if (cpu_features->basic.kind == arch_kind_zhaoxin) ++ { ++ data = handle_zhaoxin (_SC_LEVEL1_DCACHE_SIZE); ++ core = handle_zhaoxin (_SC_LEVEL2_CACHE_SIZE); ++ shared = handle_zhaoxin (_SC_LEVEL3_CACHE_SIZE); + +- /* Account for non-inclusive L2 and L3 caches. */ +- if (!inclusive_cache) +- { +- if (threads_l2 > 0) +- core /= threads_l2; +- shared += core; +- } ++ get_common_cache_info (&shared, &threads, core); + } + else if (cpu_features->basic.kind == arch_kind_amd) + { diff --git a/SOURCES/glibc-rh1817513-55.patch b/SOURCES/glibc-rh1817513-55.patch new file mode 100644 index 0000000..b649118 --- /dev/null +++ b/SOURCES/glibc-rh1817513-55.patch @@ -0,0 +1,136 @@ +commit 033362cfd7e0e1dccd6c9a2642710d6e3a7e7007 +Author: Carlos O'Donell +Date: Thu Jan 23 09:45:00 2020 -0500 + + test-container: Support $(complocaledir) and mkdirp. + + Expand the support infrastructure: + - Create $(complocaledir) in the testroot.pristine to support localedef. + - Add the variable $complocaledir to script support. + - Add the script command 'mkdirp'. + + All localedef tests which run with default paths need to have the + $(complocaledir) created in testroot.pristine. The localedef binary + will not by itself create the default path, but it will write into + the path. By adding this we can simplify the localedef tests. + + The variable $complocaledir is the value of the configured + $(complocaledir) which is the location of the compiled locales that + will be searched by the runtime by default. + + The command mkdirp will be available in script setup and will + be equivalent to running `mkdir -p`. + + The variable and command can be used to write more complex tests. + + Reviewed-by: DJ Delorie + +diff --git a/Makefile b/Makefile +index ae44b9cdd29fb0e3..3748d6f7cfb6223b 100644 +--- a/Makefile ++++ b/Makefile +@@ -371,6 +371,9 @@ $(objpfx)testroot.pristine/install.stamp : + # We need a working /bin/sh for some of the tests. + test -d $(objpfx)testroot.pristine/bin || \ + mkdir $(objpfx)testroot.pristine/bin ++ # We need the compiled locale dir for localedef tests. ++ test -d $(objpfx)testroot.pristine/$(complocaledir) || \ ++ mkdir -p $(objpfx)testroot.pristine/$(complocaledir) + cp $(objpfx)support/shell-container $(objpfx)testroot.pristine/bin/sh + cp $(objpfx)support/echo-container $(objpfx)testroot.pristine/bin/echo + cp $(objpfx)support/true-container $(objpfx)testroot.pristine/bin/true +diff --git a/support/test-container.c b/support/test-container.c +index 9eff8baeef0e9d8a..9fcc91e478038232 100644 +--- a/support/test-container.c ++++ b/support/test-container.c +@@ -72,6 +72,10 @@ int verbose = 0; + + * mkdir $buildroot/testroot.pristine/ + * install into it ++ * default glibc install ++ * create /bin for /bin/sh ++ * create $(complocaledir) so localedef tests work with default paths. ++ * install /bin/sh, /bin/echo, and /bin/true. + * rsync to $buildroot/testroot.root/ + + "Per-test" actions: +@@ -97,9 +101,23 @@ int verbose = 0; + rm FILE + cwd PATH + exec FILE +- FILE must start with $B/, $S/, $I/, $L/, or / +- (expands to build dir, source dir, install dir, library dir +- (in container), or container's root) ++ mkdirp MODE DIR ++ ++ variables: ++ $B/ build dir, equivalent to $(common-objpfx) ++ $S/ source dir, equivalent to $(srcdir) ++ $I/ install dir, equivalent to $(prefix) ++ $L/ library dir (in container), equivalent to $(libdir) ++ $complocaledir/ compiled locale dir, equivalent to $(complocaledir) ++ / container's root ++ ++ If FILE begins with any of these variables then they will be ++ substituted for the described value. ++ ++ The goal is to expose as many of the runtime's configured paths ++ via variables so they can be used to setup the container environment ++ before execution reaches the test. ++ + details: + - '#': A comment. + - 'su': Enables running test as root in the container. +@@ -108,6 +126,8 @@ int verbose = 0; + - 'rm': A minimal remove files command. + - 'cwd': set test working directory + - 'exec': change test binary location (may end in /) ++ - 'mkdirp': A minimal "mkdir -p FILE" command. ++ + * mytest.root/postclean.req causes fresh rsync (with delete) after + test if present + +@@ -859,6 +879,7 @@ main (int argc, char **argv) + int nt = tokenize (the_line, the_words, 3); + int i; + ++ /* Expand variables. */ + for (i = 1; i < nt; ++i) + { + if (memcmp (the_words[i], "$B/", 3) == 0) +@@ -875,6 +896,10 @@ main (int argc, char **argv) + the_words[i] = concat (new_root_path, + support_libdir_prefix, + the_words[i] + 2, NULL); ++ else if (memcmp (the_words[i], "$complocaledir/", 15) == 0) ++ the_words[i] = concat (new_root_path, ++ support_complocaledir_prefix, ++ the_words[i] + 14, NULL); + /* "exec" and "cwd" use inside-root paths. */ + else if (strcmp (the_words[0], "exec") != 0 + && strcmp (the_words[0], "cwd") != 0 +@@ -892,6 +917,9 @@ main (int argc, char **argv) + the_words[2] = concat (the_words[2], the_words[1], NULL); + } + ++ /* Run the following commands in the_words[0] with NT number of ++ arguments (including the command). */ ++ + if (nt == 2 && strcmp (the_words[0], "so") == 0) + { + the_words[2] = concat (new_root_path, support_libdir_prefix, +@@ -961,6 +989,14 @@ main (int argc, char **argv) + { + be_su = 1; + } ++ else if (nt == 3 && strcmp (the_words[0], "mkdirp") == 0) ++ { ++ long int m; ++ errno = 0; ++ m = strtol (the_words[1], NULL, 0); ++ TEST_COMPARE (errno, 0); ++ xmkdirp (the_words[2], m); ++ } + else if (nt > 0 && the_words[0][0] != '#') + { + fprintf (stderr, "\033[31minvalid [%s]\033[0m\n", the_words[0]); diff --git a/SOURCES/glibc-rh1817513-56.patch b/SOURCES/glibc-rh1817513-56.patch new file mode 100644 index 0000000..1cfb701 --- /dev/null +++ b/SOURCES/glibc-rh1817513-56.patch @@ -0,0 +1,45 @@ +commit 183083c35972611e7786c7ee0c96d7da571631ed +Author: Carlos O'Donell +Date: Wed Apr 29 16:31:29 2020 -0400 + + support: Set errno before testing it. + + In test-conainer we should set errno to 0 before calling strtol, + and check after with TEST_COMPARE. + + In tst-support_capture_subprocess we should set errno to 0 before + checking it after the call to strtol. + + Tested on x86_64. + + Reviewed-by: DJ Delorie + +diff --git a/support/test-container.c b/support/test-container.c +index 9fcc91e478038232..d7ed073812305f71 100644 +--- a/support/test-container.c ++++ b/support/test-container.c +@@ -940,7 +940,9 @@ main (int argc, char **argv) + else if (nt == 3 && strcmp (the_words[0], "chmod") == 0) + { + long int m; ++ errno = 0; + m = strtol (the_words[1], NULL, 0); ++ TEST_COMPARE (errno, 0); + if (chmod (the_words[2], m) < 0) + FAIL_EXIT1 ("chmod %s: %s\n", + the_words[2], strerror (errno)); +diff --git a/support/tst-support_capture_subprocess.c b/support/tst-support_capture_subprocess.c +index 99570879eedd65b1..fe6649dda6032de2 100644 +--- a/support/tst-support_capture_subprocess.c ++++ b/support/tst-support_capture_subprocess.c +@@ -133,7 +133,9 @@ static int + parse_int (const char *str) + { + char *endptr; +- long int ret = strtol (str, &endptr, 10); ++ long int ret; ++ errno = 0; ++ ret = strtol (str, &endptr, 10); + TEST_COMPARE (errno, 0); + TEST_VERIFY (ret >= 0 && ret <= INT_MAX); + return ret; diff --git a/SOURCES/glibc-rh1817513-57.patch b/SOURCES/glibc-rh1817513-57.patch new file mode 100644 index 0000000..93ac1e4 --- /dev/null +++ b/SOURCES/glibc-rh1817513-57.patch @@ -0,0 +1,30 @@ +commit cad64f778aced84efdaa04ae64f8737b86f063ab +Author: Josh Triplett +Date: Tue May 19 14:41:48 2020 +0200 + + ldconfig: Default to the new format for ld.so.cache + + glibc has supported this format for close to 20 years. + +diff --git a/elf/ldconfig.c b/elf/ldconfig.c +index 5e6516688a1c192a..f31e10817dd5d665 100644 +--- a/elf/ldconfig.c ++++ b/elf/ldconfig.c +@@ -97,7 +97,7 @@ int opt_verbose; + + /* Format to support. */ + /* 0: only libc5/glibc2; 1: both; 2: only glibc 2.2. */ +-int opt_format = 1; ++int opt_format = 2; + + /* Build cache. */ + static int opt_build_cache = 1; +@@ -150,7 +150,7 @@ static const struct argp_option options[] = + { NULL, 'f', N_("CONF"), 0, N_("Use CONF as configuration file"), 0}, + { NULL, 'n', NULL, 0, N_("Only process directories specified on the command line. Don't build cache."), 0}, + { NULL, 'l', NULL, 0, N_("Manually link individual libraries."), 0}, +- { "format", 'c', N_("FORMAT"), 0, N_("Format to use: new, old or compat (default)"), 0}, ++ { "format", 'c', N_("FORMAT"), 0, N_("Format to use: new (default), old, or compat"), 0}, + { "ignore-aux-cache", 'i', NULL, 0, N_("Ignore auxiliary cache file"), 0}, + { NULL, 0, NULL, 0, NULL, 0 } + }; diff --git a/SOURCES/glibc-rh1817513-58.patch b/SOURCES/glibc-rh1817513-58.patch new file mode 100644 index 0000000..9133d56 --- /dev/null +++ b/SOURCES/glibc-rh1817513-58.patch @@ -0,0 +1,59 @@ +commit 76d5b2f002a1243ddba06bd646249553353f4322 +Author: H.J. Lu +Date: Thu May 21 13:36:54 2020 -0700 + + x86: Update Intel Atom processor family optimization + + Enable Intel Silvermont optimization for Intel Goldmont Plus. Detect more + Intel Airmont processors. Optimize Intel Tremont like Intel Silvermont + with rep string instructions. + +diff --git a/sysdeps/x86/cpu-features.c b/sysdeps/x86/cpu-features.c +index c432d646ce6806a6..2a801e1856cfe1b3 100644 +--- a/sysdeps/x86/cpu-features.c ++++ b/sysdeps/x86/cpu-features.c +@@ -347,18 +347,23 @@ init_cpu_features (struct cpu_features *cpu_features) + case 0x57: + /* Knights Landing. Enable Silvermont optimizations. */ + ++ case 0x7a: ++ /* Unaligned load versions are faster than SSSE3 ++ on Goldmont Plus. */ ++ + case 0x5c: + case 0x5f: + /* Unaligned load versions are faster than SSSE3 + on Goldmont. */ + + case 0x4c: ++ case 0x5a: ++ case 0x75: + /* Airmont is a die shrink of Silvermont. */ + + case 0x37: + case 0x4a: + case 0x4d: +- case 0x5a: + case 0x5d: + /* Unaligned load versions are faster than SSSE3 + on Silvermont. */ +@@ -369,6 +374,19 @@ init_cpu_features (struct cpu_features *cpu_features) + | bit_arch_Slow_SSE4_2); + break; + ++ case 0x86: ++ case 0x96: ++ case 0x9c: ++ /* Enable rep string instructions, unaligned load, unaligned ++ copy, pminub and avoid SSE 4.2 on Tremont. */ ++ cpu_features->feature[index_arch_Fast_Rep_String] ++ |= (bit_arch_Fast_Rep_String ++ | bit_arch_Fast_Unaligned_Load ++ | bit_arch_Fast_Unaligned_Copy ++ | bit_arch_Prefer_PMINUB_for_stringop ++ | bit_arch_Slow_SSE4_2); ++ break; ++ + default: + /* Unknown family 0x06 processors. Assuming this is one + of Core i3/i5/i7 processors if AVX is available. */ diff --git a/SOURCES/glibc-rh1817513-59.patch b/SOURCES/glibc-rh1817513-59.patch new file mode 100644 index 0000000..0fbaab7 --- /dev/null +++ b/SOURCES/glibc-rh1817513-59.patch @@ -0,0 +1,148 @@ +commit dcbc6b83eff5b9238170bdfed834ba934150895f +Author: Florian Weimer +Date: Thu May 28 10:20:56 2020 +0200 + + elf: Do not read hwcaps from the vDSO in ld.so + + This was only ever used for the "nosegneg" flag. This approach for + passing hardware capability information creates a subtle dependency + between the kernel and userspace, and ld.so.cache contents. It seems + inappropriate for toady, where people expect to be able to run + system images which very different kernel versions. + + Reviewed-by: Adhemerval Zanella + +diff --git a/elf/dl-hwcaps.c b/elf/dl-hwcaps.c +index ecf00b457760e517..ae2e4ca7fe91d407 100644 +--- a/elf/dl-hwcaps.c ++++ b/elf/dl-hwcaps.c +@@ -26,12 +26,6 @@ + #include + #include + +-#ifdef _DL_FIRST_PLATFORM +-# define _DL_FIRST_EXTRA (_DL_FIRST_PLATFORM + _DL_PLATFORMS_COUNT) +-#else +-# define _DL_FIRST_EXTRA _DL_HWCAP_COUNT +-#endif +- + /* Return an array of useful/necessary hardware capability names. */ + const struct r_strlenpair * + _dl_important_hwcaps (const char *platform, size_t platform_len, size_t *sz, +@@ -52,116 +46,12 @@ _dl_important_hwcaps (const char *platform, size_t platform_len, size_t *sz, + if ((masked & (1ULL << n)) != 0) + ++cnt; + +-#ifdef NEED_DL_SYSINFO_DSO +- /* The system-supplied DSO can contain a note of type 2, vendor "GNU". +- This gives us a list of names to treat as fake hwcap bits. */ +- +- const char *dsocaps = NULL; +- size_t dsocapslen = 0; +- if (GLRO(dl_sysinfo_map) != NULL) +- { +- const ElfW(Phdr) *const phdr = GLRO(dl_sysinfo_map)->l_phdr; +- const ElfW(Word) phnum = GLRO(dl_sysinfo_map)->l_phnum; +- for (uint_fast16_t i = 0; i < phnum; ++i) +- if (phdr[i].p_type == PT_NOTE) +- { +- const ElfW(Addr) start = (phdr[i].p_vaddr +- + GLRO(dl_sysinfo_map)->l_addr); +- /* NB: Some PT_NOTE segment may have alignment value of 0 +- or 1. gABI specifies that PT_NOTE segments should be +- aligned to 4 bytes in 32-bit objects and to 8 bytes in +- 64-bit objects. As a Linux extension, we also support +- 4 byte alignment in 64-bit objects. If p_align is less +- than 4, we treate alignment as 4 bytes since some note +- segments have 0 or 1 byte alignment. */ +- ElfW(Addr) align = phdr[i].p_align; +- if (align < 4) +- align = 4; +- else if (align != 4 && align != 8) +- continue; +- /* The standard ELF note layout is exactly as the anonymous struct. +- The next element is a variable length vendor name of length +- VENDORLEN (with a real length rounded to ElfW(Word)), followed +- by the data of length DATALEN (with a real length rounded to +- ElfW(Word)). */ +- const struct +- { +- ElfW(Word) vendorlen; +- ElfW(Word) datalen; +- ElfW(Word) type; +- } *note = (const void *) start; +- while ((ElfW(Addr)) (note + 1) - start < phdr[i].p_memsz) +- { +- /* The layout of the type 2, vendor "GNU" note is as follows: +- .long +- .long (as mask >> _DL_FIRST_EXTRA). +- .byte +- .asciz . */ +- if (note->type == NT_GNU_HWCAP +- && note->vendorlen == sizeof "GNU" +- && !memcmp ((note + 1), "GNU", sizeof "GNU") +- && note->datalen > 2 * sizeof (ElfW(Word)) + 2) +- { +- const ElfW(Word) *p +- = ((const void *) note +- + ELF_NOTE_DESC_OFFSET (sizeof "GNU", align)); +- cnt += *p++; +- ++p; /* Skip mask word. */ +- dsocaps = (const char *) p; /* Pseudo-string "name" */ +- dsocapslen = note->datalen - sizeof *p * 2; +- break; +- } +- note = ((const void *) note +- + ELF_NOTE_NEXT_OFFSET (note->vendorlen, +- note->datalen, align)); +- } +- if (dsocaps != NULL) +- break; +- } +- } +-#endif +- + /* For TLS enabled builds always add 'tls'. */ + ++cnt; + + /* Create temporary data structure to generate result table. */ + struct r_strlenpair temp[cnt]; + m = 0; +-#ifdef NEED_DL_SYSINFO_DSO +- if (dsocaps != NULL) +- { +- /* dsocaps points to the .asciz string, and -1 points to the mask +- .long just before the string. */ +- const ElfW(Word) mask = ((const ElfW(Word) *) dsocaps)[-1]; +- GLRO(dl_hwcap) |= (uint64_t) mask << _DL_FIRST_EXTRA; +- /* Note that we add the dsocaps to the set already chosen by the +- LD_HWCAP_MASK environment variable (or default HWCAP_IMPORTANT). +- So there is no way to request ignoring an OS-supplied dsocap +- string and bit like you can ignore an OS-supplied HWCAP bit. */ +- hwcap_mask |= (uint64_t) mask << _DL_FIRST_EXTRA; +-#if HAVE_TUNABLES +- TUNABLE_SET (glibc, cpu, hwcap_mask, uint64_t, hwcap_mask); +-#else +- GLRO(dl_hwcap_mask) = hwcap_mask; +-#endif +- size_t len; +- for (const char *p = dsocaps; p < dsocaps + dsocapslen; p += len + 1) +- { +- uint_fast8_t bit = *p++; +- len = strlen (p); +- +- /* Skip entries that are not enabled in the mask word. */ +- if (__glibc_likely (mask & ((ElfW(Word)) 1 << bit))) +- { +- temp[m].str = p; +- temp[m].len = len; +- ++m; +- } +- else +- --cnt; +- } +- } +-#endif + for (n = 0; masked != 0; ++n) + if ((masked & (1ULL << n)) != 0) + { diff --git a/SOURCES/glibc-rh1817513-6.patch b/SOURCES/glibc-rh1817513-6.patch new file mode 100644 index 0000000..4f8e256 --- /dev/null +++ b/SOURCES/glibc-rh1817513-6.patch @@ -0,0 +1,53 @@ +commit d330f31af68f96dde82840d1e9343b479a8c179e +Author: Carlos O'Donell +Date: Thu Aug 30 11:01:33 2018 -0400 + + Fix test failure with -DNDEBUG. + + The elf/tst-dlopen-aout.c test uses asserts to verify properties of the + test execution. Instead of using assert it should use xpthread_create + and xpthread_join to catch errors starting the threads and fail the + test. This shows up in Fedora 28 when building for i686-pc-linux-gnu + and using gcc 8.1.1. + + Tested on i686, and fixes a check failure with -DNDEBUG. + + Signed-off-by: Carlos O'Donell + +diff --git a/elf/tst-dlopen-aout.c b/elf/tst-dlopen-aout.c +index 9038e2096add8798..b0264515cfe62276 100644 +--- a/elf/tst-dlopen-aout.c ++++ b/elf/tst-dlopen-aout.c +@@ -27,6 +27,7 @@ + #include + #include + #include ++#include + + __thread int x; + +@@ -45,7 +46,6 @@ do_test (int argc, char *argv[]) + { + pthread_t thr; + void *p; +- int rc; + + p = dlopen (argv[0], RTLD_LAZY); + if (p != NULL) +@@ -53,11 +53,11 @@ do_test (int argc, char *argv[]) + fprintf (stderr, "dlopen unexpectedly succeeded\n"); + return 1; + } +- rc = pthread_create (&thr, NULL, fn, NULL); +- assert (rc == 0); +- +- rc = pthread_join (thr, NULL); +- assert (rc == 0); ++ /* We create threads to force TLS allocation, which triggers ++ the original bug i.e. running out of surplus slotinfo entries ++ for TLS. */ ++ thr = xpthread_create (NULL, fn, NULL); ++ xpthread_join (thr); + } + + return 0; diff --git a/SOURCES/glibc-rh1817513-60.patch b/SOURCES/glibc-rh1817513-60.patch new file mode 100644 index 0000000..f6b4907 --- /dev/null +++ b/SOURCES/glibc-rh1817513-60.patch @@ -0,0 +1,151 @@ +commit 31563b68410ff8e9490c5aafca31ec71b38f87a5 +Author: Florian Weimer +Date: Thu May 28 10:21:17 2020 +0200 + + elf: Remove extra hwcap mechanism from ldconfig + + Historically, this mechanism was used to process "nosegneg" + subdirectories, and it is still used to include the "tls" + subdirectories. With nosegneg support gone from ld.so, this is part + no longer useful. + + The entire mechanism is not well-designed because it causes the + meaning of hwcap bits in ld.so.cache to depend on the kernel version + that was used to generate the cache, which makes it difficult to use + this mechanism for anything else in the future. + + Reviewed-by: Adhemerval Zanella + +diff --git a/elf/ldconfig.c b/elf/ldconfig.c +index f31e10817dd5d665..7c8fd29387463a8a 100644 +--- a/elf/ldconfig.c ++++ b/elf/ldconfig.c +@@ -44,11 +44,15 @@ + + #include + +-#ifdef _DL_FIRST_PLATFORM +-# define _DL_FIRST_EXTRA (_DL_FIRST_PLATFORM + _DL_PLATFORMS_COUNT) +-#else +-# define _DL_FIRST_EXTRA _DL_HWCAP_COUNT +-#endif ++/* This subpath in search path entries is always supported and ++ included in the cache for backwards compatibility. */ ++#define TLS_SUBPATH "tls" ++ ++/* The MSB of the hwcap field is set for objects in TLS_SUBPATH ++ directories. There is always TLS support in glibc, so the dynamic ++ loader does not check the bit directly. But more hwcap bits make a ++ an object more preferred, so the bit still has meaning. */ ++#define TLS_HWCAP_BIT 63 + + #ifndef LD_SO_CONF + # define LD_SO_CONF SYSCONFDIR "/ld.so.conf" +@@ -127,9 +131,6 @@ static const char *config_file; + /* Mask to use for important hardware capabilities. */ + static unsigned long int hwcap_mask = HWCAP_IMPORTANT; + +-/* Configuration-defined capabilities defined in kernel vDSOs. */ +-static const char *hwcap_extra[64 - _DL_FIRST_EXTRA]; +- + /* Name and version of program. */ + static void print_version (FILE *stream, struct argp_state *state); + void (*argp_program_version_hook) (FILE *, struct argp_state *) +@@ -186,12 +187,9 @@ is_hwcap_platform (const char *name) + if (hwcap_idx != -1) + return 1; + +- /* Is this one of the extra pseudo-hwcaps that we map beyond +- _DL_FIRST_EXTRA like "tls", or "nosegneg?" */ +- for (hwcap_idx = _DL_FIRST_EXTRA; hwcap_idx < 64; ++hwcap_idx) +- if (hwcap_extra[hwcap_idx - _DL_FIRST_EXTRA] != NULL +- && !strcmp (name, hwcap_extra[hwcap_idx - _DL_FIRST_EXTRA])) +- return 1; ++ /* Backwards-compatibility for the "tls" subdirectory. */ ++ if (strcmp (name, TLS_SUBPATH) == 0) ++ return 1; + + return 0; + } +@@ -226,11 +224,9 @@ path_hwcap (const char *path) + h = _dl_string_platform (ptr + 1); + if (h == (uint64_t) -1) + { +- for (h = _DL_FIRST_EXTRA; h < 64; ++h) +- if (hwcap_extra[h - _DL_FIRST_EXTRA] != NULL +- && !strcmp (ptr + 1, hwcap_extra[h - _DL_FIRST_EXTRA])) +- break; +- if (h == 64) ++ if (strcmp (ptr + 1, TLS_SUBPATH) == 0) ++ h = TLS_HWCAP_BIT; ++ else + break; + } + } +@@ -1145,52 +1141,7 @@ Warning: ignoring configuration file that cannot be opened: %s"), + parse_conf_include (filename, lineno, do_chroot, dir); + } + else if (!strncasecmp (cp, "hwcap", 5) && isblank (cp[5])) +- { +- cp += 6; +- char *p, *name = NULL; +- unsigned long int n = strtoul (cp, &cp, 0); +- if (cp != NULL && isblank (*cp)) +- while ((p = strsep (&cp, " \t")) != NULL) +- if (p[0] != '\0') +- { +- if (name == NULL) +- name = p; +- else +- { +- name = NULL; +- break; +- } +- } +- if (name == NULL) +- { +- error (EXIT_FAILURE, 0, _("%s:%u: bad syntax in hwcap line"), +- filename, lineno); +- break; +- } +- if (n >= (64 - _DL_FIRST_EXTRA)) +- error (EXIT_FAILURE, 0, +- _("%s:%u: hwcap index %lu above maximum %u"), +- filename, lineno, n, 64 - _DL_FIRST_EXTRA - 1); +- if (hwcap_extra[n] == NULL) +- { +- for (unsigned long int h = 0; h < (64 - _DL_FIRST_EXTRA); ++h) +- if (hwcap_extra[h] != NULL && !strcmp (name, hwcap_extra[h])) +- error (EXIT_FAILURE, 0, +- _("%s:%u: hwcap index %lu already defined as %s"), +- filename, lineno, h, name); +- hwcap_extra[n] = xstrdup (name); +- } +- else +- { +- if (strcmp (name, hwcap_extra[n])) +- error (EXIT_FAILURE, 0, +- _("%s:%u: hwcap index %lu already defined as %s"), +- filename, lineno, n, hwcap_extra[n]); +- if (opt_verbose) +- error (0, 0, _("%s:%u: duplicate hwcap %lu %s"), +- filename, lineno, n, name); +- } +- } ++ error (0, 0, _("%s:%u: hwcap directive ignored"), filename, lineno); + else + add_dir_1 (cp, filename, lineno); + } +@@ -1303,12 +1254,6 @@ main (int argc, char **argv) + add_dir_1 (argv[i], "", 0); + } + +- /* The last entry in hwcap_extra is reserved for the "tls" pseudo-hwcap which +- indicates support for TLS. This pseudo-hwcap is only used by old versions +- under which TLS support was optional. The entry is no longer needed, but +- must remain for compatibility. */ +- hwcap_extra[63 - _DL_FIRST_EXTRA] = "tls"; +- + set_hwcap (); + + if (opt_chroot) diff --git a/SOURCES/glibc-rh1817513-61.patch b/SOURCES/glibc-rh1817513-61.patch new file mode 100644 index 0000000..87cf249 --- /dev/null +++ b/SOURCES/glibc-rh1817513-61.patch @@ -0,0 +1,21 @@ +commit 9e2dc874e62b0950891b319c000b009ea12ac8c2 +Author: Girish Joshi +Date: Fri May 29 10:11:24 2020 -0300 + + build: Use FAIL_EXIT1 () on failure to exec child [BZ #23990] + + Reviewed-by: Adhemerval Zanella + +diff --git a/support/test-container.c b/support/test-container.c +index d7ed073812305f71..9975c8cb7bc9a955 100644 +--- a/support/test-container.c ++++ b/support/test-container.c +@@ -392,7 +392,7 @@ recursive_remove (char *path) + /* "rm" would have already printed a suitable error message. */ + if (! WIFEXITED (status) + || WEXITSTATUS (status) != 0) +- exit (1); ++ FAIL_EXIT1 ("exec child returned status: %d", status); + + break; + } diff --git a/SOURCES/glibc-rh1817513-62.patch b/SOURCES/glibc-rh1817513-62.patch new file mode 100644 index 0000000..77f123a --- /dev/null +++ b/SOURCES/glibc-rh1817513-62.patch @@ -0,0 +1,67 @@ +commit 533dd2acf7eefa969fb770fa782b20519bd4bc0f +Author: H.J. Lu +Date: Tue Jun 9 12:15:01 2020 -0700 + + Add "%d" support to _dl_debug_vdprintf + + "%d" will be used to print out signed value. + +diff --git a/elf/dl-misc.c b/elf/dl-misc.c +index 2eb81eeb0231368d..3f28de3ee9d68368 100644 +--- a/elf/dl-misc.c ++++ b/elf/dl-misc.c +@@ -167,6 +167,7 @@ _dl_debug_vdprintf (int fd, int tag_p, const char *fmt, va_list arg) + switch (*fmt) + { + /* Integer formatting. */ ++ case 'd': + case 'u': + case 'x': + { +@@ -179,11 +180,34 @@ _dl_debug_vdprintf (int fd, int tag_p, const char *fmt, va_list arg) + #else + unsigned long int num = va_arg (arg, unsigned int); + #endif ++ bool negative = false; ++ if (*fmt == 'd') ++ { ++#if LONG_MAX != INT_MAX ++ if (long_mod) ++ { ++ if ((long int) num < 0) ++ negative = true; ++ } ++ else ++ { ++ if ((int) num < 0) ++ { ++ num = (unsigned int) num; ++ negative = true; ++ } ++ } ++#else ++ if ((int) num < 0) ++ negative = true; ++#endif ++ } ++ + /* We use alloca() to allocate the buffer with the most + pessimistic guess for the size. Using alloca() allows + having more than one integer formatting in a call. */ +- char *buf = (char *) alloca (3 * sizeof (unsigned long int)); +- char *endp = &buf[3 * sizeof (unsigned long int)]; ++ char *buf = (char *) alloca (1 + 3 * sizeof (unsigned long int)); ++ char *endp = &buf[1 + 3 * sizeof (unsigned long int)]; + char *cp = _itoa (num, endp, *fmt == 'x' ? 16 : 10, 0); + + /* Pad to the width the user specified. */ +@@ -191,6 +215,9 @@ _dl_debug_vdprintf (int fd, int tag_p, const char *fmt, va_list arg) + while (endp - cp < width) + *--cp = fill; + ++ if (negative) ++ *--cp = '-'; ++ + iov[niov].iov_base = cp; + iov[niov].iov_len = endp - cp; + ++niov; diff --git a/SOURCES/glibc-rh1817513-63.patch b/SOURCES/glibc-rh1817513-63.patch new file mode 100644 index 0000000..7e42638 --- /dev/null +++ b/SOURCES/glibc-rh1817513-63.patch @@ -0,0 +1,62 @@ +commit e221c512c74ec42fd47b71de2981a475b38110a4 +Author: Florian Weimer +Date: Mon Jun 15 09:50:14 2020 +0200 + + ld.so: Check for new cache format first and enhance corruption check + + Now that ldconfig defaults to the new format (only), check for it + first. Also apply the corruption check added in commit 2954daf00bb4d + ("Add more checks for valid ld.so.cache file (bug 18093)") to the + new-format-only case. + + Suggested-by: Josh Triplett + +diff --git a/elf/dl-cache.c b/elf/dl-cache.c +index 6dd99a35b9f97cfb..ef37ca18fa9fb6e0 100644 +--- a/elf/dl-cache.c ++++ b/elf/dl-cache.c +@@ -199,15 +199,25 @@ _dl_load_cache_lookup (const char *name) + PROT_READ); + + /* We can handle three different cache file formats here: ++ - only the new format + - the old libc5/glibc2.0/2.1 format + - the old format with the new format in it +- - only the new format + The following checks if the cache contains any of these formats. */ +- if (file != MAP_FAILED && cachesize > sizeof *cache +- && memcmp (file, CACHEMAGIC, sizeof CACHEMAGIC - 1) == 0 ++ if (file != MAP_FAILED && cachesize > sizeof *cache_new ++ && memcmp (file, CACHEMAGIC_VERSION_NEW, ++ sizeof CACHEMAGIC_VERSION_NEW - 1) == 0 + /* Check for corruption, avoiding overflow. */ +- && ((cachesize - sizeof *cache) / sizeof (struct file_entry) +- >= ((struct cache_file *) file)->nlibs)) ++ && ((cachesize - sizeof *cache_new) / sizeof (struct file_entry_new) ++ >= ((struct cache_file_new *) file)->nlibs)) ++ { ++ cache_new = file; ++ cache = file; ++ } ++ else if (file != MAP_FAILED && cachesize > sizeof *cache ++ && memcmp (file, CACHEMAGIC, sizeof CACHEMAGIC - 1) == 0 ++ /* Check for corruption, avoiding overflow. */ ++ && ((cachesize - sizeof *cache) / sizeof (struct file_entry) ++ >= ((struct cache_file *) file)->nlibs)) + { + size_t offset; + /* Looks ok. */ +@@ -223,13 +233,6 @@ _dl_load_cache_lookup (const char *name) + sizeof CACHEMAGIC_VERSION_NEW - 1) != 0) + cache_new = (void *) -1; + } +- else if (file != MAP_FAILED && cachesize > sizeof *cache_new +- && memcmp (file, CACHEMAGIC_VERSION_NEW, +- sizeof CACHEMAGIC_VERSION_NEW - 1) == 0) +- { +- cache_new = file; +- cache = file; +- } + else + { + if (file != MAP_FAILED) diff --git a/SOURCES/glibc-rh1817513-64.patch b/SOURCES/glibc-rh1817513-64.patch new file mode 100644 index 0000000..13fbc6c --- /dev/null +++ b/SOURCES/glibc-rh1817513-64.patch @@ -0,0 +1,21 @@ +commit b7c9bb183b799b10c09ec32e98d1843546ea4324 +Author: H.J. Lu +Date: Wed Jun 17 05:32:37 2020 -0700 + + x86: Correct bit_cpu_CLFLUSHOPT [BZ #26128] + + bit_cpu_CLFLUSHOPT should be (1u << 23), not (1u << 22). + +diff --git a/sysdeps/x86/cpu-features.h b/sysdeps/x86/cpu-features.h +index 388172a1c07bf979..7abfa046c4b8f6ac 100644 +--- a/sysdeps/x86/cpu-features.h ++++ b/sysdeps/x86/cpu-features.h +@@ -465,7 +465,7 @@ extern const struct cpu_features *__get_cpu_features (void) + #define bit_cpu_ADX (1u << 19) + #define bit_cpu_SMAP (1u << 20) + #define bit_cpu_AVX512_IFMA (1u << 21) +-#define bit_cpu_CLFLUSHOPT (1u << 22) ++#define bit_cpu_CLFLUSHOPT (1u << 23) + #define bit_cpu_CLWB (1u << 24) + #define bit_cpu_TRACE (1u << 25) + #define bit_cpu_AVX512PF (1u << 26) diff --git a/SOURCES/glibc-rh1817513-65.patch b/SOURCES/glibc-rh1817513-65.patch new file mode 100644 index 0000000..14f1c78 --- /dev/null +++ b/SOURCES/glibc-rh1817513-65.patch @@ -0,0 +1,68 @@ +commit 27f8864bd41f0f1b61e8e947d9a030b1a0d23df9 +Author: H.J. Lu +Date: Thu Jun 18 05:34:15 2020 -0700 + + x86: Update F16C detection [BZ #26133] + + Since F16C requires AVX, set F16C usable only when AVX is usable. + +diff --git a/sysdeps/x86/cpu-features.c b/sysdeps/x86/cpu-features.c +index 2a801e1856cfe1b3..37619c93f8dbcc5d 100644 +--- a/sysdeps/x86/cpu-features.c ++++ b/sysdeps/x86/cpu-features.c +@@ -146,6 +146,10 @@ get_common_indices (struct cpu_features *cpu_features, + if (CPU_FEATURES_CPU_P (cpu_features, XOP)) + cpu_features->feature[index_arch_XOP_Usable] + |= bit_arch_XOP_Usable; ++ /* Determine if F16C is usable. */ ++ if (CPU_FEATURES_CPU_P (cpu_features, F16C)) ++ cpu_features->feature[index_arch_F16C_Usable] ++ |= bit_arch_F16C_Usable; + } + + /* Check if OPMASK state, upper 256-bit of ZMM0-ZMM15 and +diff --git a/sysdeps/x86/cpu-features.h b/sysdeps/x86/cpu-features.h +index 7abfa046c4b8f6ac..f18f7520fcb7714a 100644 +--- a/sysdeps/x86/cpu-features.h ++++ b/sysdeps/x86/cpu-features.h +@@ -142,6 +142,7 @@ extern const struct cpu_features *__get_cpu_features (void) + #define bit_arch_VPCLMULQDQ_Usable (1u << 20) + #define bit_arch_XOP_Usable (1u << 21) + #define bit_arch_XSAVEC_Usable (1u << 22) ++#define bit_arch_F16C_Usable (1u << 23) + + #define index_arch_AVX_Usable FEATURE_INDEX_1 + #define index_arch_AVX2_Usable FEATURE_INDEX_1 +@@ -166,6 +167,7 @@ extern const struct cpu_features *__get_cpu_features (void) + #define index_arch_VPCLMULQDQ_Usable FEATURE_INDEX_1 + #define index_arch_XOP_Usable FEATURE_INDEX_1 + #define index_arch_XSAVEC_Usable FEATURE_INDEX_1 ++#define index_arch_F16C_Usable FEATURE_INDEX_1 + + /* Unused. Compiler will optimize them out. */ + #define bit_arch_SSE3_Usable (1u << 0) +@@ -179,7 +181,6 @@ extern const struct cpu_features *__get_cpu_features (void) + #define bit_arch_AES_Usable (1u << 0) + #define bit_arch_XSAVE_Usable (1u << 0) + #define bit_arch_OSXSAVE_Usable (1u << 0) +-#define bit_arch_F16C_Usable (1u << 0) + #define bit_arch_RDRAND_Usable (1u << 0) + #define bit_arch_FPU_Usable (1u << 0) + #define bit_arch_TSC_Usable (1u << 0) +@@ -236,7 +237,6 @@ extern const struct cpu_features *__get_cpu_features (void) + #define index_arch_AES_Usable FEATURE_INDEX_1 + #define index_arch_XSAVE_Usable FEATURE_INDEX_1 + #define index_arch_OSXSAVE_Usable FEATURE_INDEX_1 +-#define index_arch_F16C_Usable FEATURE_INDEX_1 + #define index_arch_RDRAND_Usable FEATURE_INDEX_1 + #define index_arch_FPU_Usable FEATURE_INDEX_1 + #define index_arch_TSC_Usable FEATURE_INDEX_1 +@@ -296,7 +296,7 @@ extern const struct cpu_features *__get_cpu_features (void) + #define need_arch_feature_XSAVE 0 + #define need_arch_feature_OSXSAVE 0 + #define need_arch_feature_AVX 1 +-#define need_arch_feature_F16C 0 ++#define need_arch_feature_F16C 1 + #define need_arch_feature_RDRAND 0 + + /* EDX. */ diff --git a/SOURCES/glibc-rh1817513-66.patch b/SOURCES/glibc-rh1817513-66.patch new file mode 100644 index 0000000..04b83b4 --- /dev/null +++ b/SOURCES/glibc-rh1817513-66.patch @@ -0,0 +1,1123 @@ +commit ecbbadbf107ea1155ae5b71a8b7bd48f38c76731 +Author: H.J. Lu +Date: Wed Jun 17 06:34:46 2020 -0700 + + x86: Update CPU feature detection [BZ #26149] + + 1. Divide architecture features into the usable features and the preferred + features. The usable features are for correctness and can be exported in + a stable ABI. The preferred features are for performance and only for + glibc internal use. + 2. Change struct cpu_features to + + struct cpu_features + { + struct cpu_features_basic basic; + unsigned int *usable_p; + struct cpuid_registers cpuid[COMMON_CPUID_INDEX_MAX]; + unsigned int usable[USABLE_FEATURE_INDEX_MAX]; + unsigned int preferred[PREFERRED_FEATURE_INDEX_MAX]; + ... + }; + + and initialize usable_p to pointer to the usable arary so that + + struct cpu_features + { + struct cpu_features_basic basic; + unsigned int *usable_p; + struct cpuid_registers cpuid[COMMON_CPUID_INDEX_MAX]; + }; + + can be exported via a stable ABI. The cpuid and usable arrays can be + expanded with backward binary compatibility for both .o and .so files. + 3. Add COMMON_CPUID_INDEX_7_ECX_1 for AVX512_BF16. + 4. Detect ENQCMD, PKS, AVX512_VP2INTERSECT, MD_CLEAR, SERIALIZE, HYBRID, + TSXLDTRK, L1D_FLUSH, CORE_CAPABILITIES and AVX512_BF16. + 5. Rename CAPABILITIES to ARCH_CAPABILITIES. + 6. Check if AVX512_VP2INTERSECT, AVX512_BF16 and PKU are usable. + 7. Update CPU feature detection test. + +diff --git a/sysdeps/unix/sysv/linux/x86_64/64/dl-librecon.h b/sysdeps/unix/sysv/linux/x86_64/64/dl-librecon.h +index ac694c032e7baf87..32f93bb3773a318b 100644 +--- a/sysdeps/unix/sysv/linux/x86_64/64/dl-librecon.h ++++ b/sysdeps/unix/sysv/linux/x86_64/64/dl-librecon.h +@@ -33,7 +33,7 @@ + case 21: \ + if (!__libc_enable_secure \ + && memcmp (envline, "PREFER_MAP_32BIT_EXEC", 21) == 0) \ +- GLRO(dl_x86_cpu_features).feature[index_arch_Prefer_MAP_32BIT_EXEC] \ ++ GLRO(dl_x86_cpu_features).preferred[index_arch_Prefer_MAP_32BIT_EXEC] \ + |= bit_arch_Prefer_MAP_32BIT_EXEC; \ + break; + +diff --git a/sysdeps/x86/cpu-features.c b/sysdeps/x86/cpu-features.c +index 37619c93f8dbcc5d..7b2a5bc3ed27ec39 100644 +--- a/sysdeps/x86/cpu-features.c ++++ b/sysdeps/x86/cpu-features.c +@@ -90,11 +90,18 @@ get_common_indices (struct cpu_features *cpu_features, + } + + if (cpu_features->basic.max_cpuid >= 7) +- __cpuid_count (7, 0, +- cpu_features->cpuid[COMMON_CPUID_INDEX_7].eax, +- cpu_features->cpuid[COMMON_CPUID_INDEX_7].ebx, +- cpu_features->cpuid[COMMON_CPUID_INDEX_7].ecx, +- cpu_features->cpuid[COMMON_CPUID_INDEX_7].edx); ++ { ++ __cpuid_count (7, 0, ++ cpu_features->cpuid[COMMON_CPUID_INDEX_7].eax, ++ cpu_features->cpuid[COMMON_CPUID_INDEX_7].ebx, ++ cpu_features->cpuid[COMMON_CPUID_INDEX_7].ecx, ++ cpu_features->cpuid[COMMON_CPUID_INDEX_7].edx); ++ __cpuid_count (7, 1, ++ cpu_features->cpuid[COMMON_CPUID_INDEX_7_ECX_1].eax, ++ cpu_features->cpuid[COMMON_CPUID_INDEX_7_ECX_1].ebx, ++ cpu_features->cpuid[COMMON_CPUID_INDEX_7_ECX_1].ecx, ++ cpu_features->cpuid[COMMON_CPUID_INDEX_7_ECX_1].edx); ++ } + + if (cpu_features->basic.max_cpuid >= 0xd) + __cpuid_count (0xd, 1, +@@ -116,39 +123,39 @@ get_common_indices (struct cpu_features *cpu_features, + /* Determine if AVX is usable. */ + if (CPU_FEATURES_CPU_P (cpu_features, AVX)) + { +- cpu_features->feature[index_arch_AVX_Usable] ++ cpu_features->usable[index_arch_AVX_Usable] + |= bit_arch_AVX_Usable; + /* The following features depend on AVX being usable. */ + /* Determine if AVX2 is usable. */ + if (CPU_FEATURES_CPU_P (cpu_features, AVX2)) + { +- cpu_features->feature[index_arch_AVX2_Usable] ++ cpu_features->usable[index_arch_AVX2_Usable] + |= bit_arch_AVX2_Usable; + + /* Unaligned load with 256-bit AVX registers are faster on + Intel/AMD processors with AVX2. */ +- cpu_features->feature[index_arch_AVX_Fast_Unaligned_Load] ++ cpu_features->preferred[index_arch_AVX_Fast_Unaligned_Load] + |= bit_arch_AVX_Fast_Unaligned_Load; + } + /* Determine if FMA is usable. */ + if (CPU_FEATURES_CPU_P (cpu_features, FMA)) +- cpu_features->feature[index_arch_FMA_Usable] ++ cpu_features->usable[index_arch_FMA_Usable] + |= bit_arch_FMA_Usable; + /* Determine if VAES is usable. */ + if (CPU_FEATURES_CPU_P (cpu_features, VAES)) +- cpu_features->feature[index_arch_VAES_Usable] ++ cpu_features->usable[index_arch_VAES_Usable] + |= bit_arch_VAES_Usable; + /* Determine if VPCLMULQDQ is usable. */ + if (CPU_FEATURES_CPU_P (cpu_features, VPCLMULQDQ)) +- cpu_features->feature[index_arch_VPCLMULQDQ_Usable] ++ cpu_features->usable[index_arch_VPCLMULQDQ_Usable] + |= bit_arch_VPCLMULQDQ_Usable; + /* Determine if XOP is usable. */ + if (CPU_FEATURES_CPU_P (cpu_features, XOP)) +- cpu_features->feature[index_arch_XOP_Usable] ++ cpu_features->usable[index_arch_XOP_Usable] + |= bit_arch_XOP_Usable; + /* Determine if F16C is usable. */ + if (CPU_FEATURES_CPU_P (cpu_features, F16C)) +- cpu_features->feature[index_arch_F16C_Usable] ++ cpu_features->usable[index_arch_F16C_Usable] + |= bit_arch_F16C_Usable; + } + +@@ -161,64 +168,73 @@ get_common_indices (struct cpu_features *cpu_features, + /* Determine if AVX512F is usable. */ + if (CPU_FEATURES_CPU_P (cpu_features, AVX512F)) + { +- cpu_features->feature[index_arch_AVX512F_Usable] ++ cpu_features->usable[index_arch_AVX512F_Usable] + |= bit_arch_AVX512F_Usable; + /* Determine if AVX512CD is usable. */ + if (CPU_FEATURES_CPU_P (cpu_features, AVX512CD)) +- cpu_features->feature[index_arch_AVX512CD_Usable] ++ cpu_features->usable[index_arch_AVX512CD_Usable] + |= bit_arch_AVX512CD_Usable; + /* Determine if AVX512ER is usable. */ + if (CPU_FEATURES_CPU_P (cpu_features, AVX512ER)) +- cpu_features->feature[index_arch_AVX512ER_Usable] ++ cpu_features->usable[index_arch_AVX512ER_Usable] + |= bit_arch_AVX512ER_Usable; + /* Determine if AVX512PF is usable. */ + if (CPU_FEATURES_CPU_P (cpu_features, AVX512PF)) +- cpu_features->feature[index_arch_AVX512PF_Usable] ++ cpu_features->usable[index_arch_AVX512PF_Usable] + |= bit_arch_AVX512PF_Usable; + /* Determine if AVX512VL is usable. */ + if (CPU_FEATURES_CPU_P (cpu_features, AVX512VL)) +- cpu_features->feature[index_arch_AVX512VL_Usable] ++ cpu_features->usable[index_arch_AVX512VL_Usable] + |= bit_arch_AVX512VL_Usable; + /* Determine if AVX512DQ is usable. */ + if (CPU_FEATURES_CPU_P (cpu_features, AVX512DQ)) +- cpu_features->feature[index_arch_AVX512DQ_Usable] ++ cpu_features->usable[index_arch_AVX512DQ_Usable] + |= bit_arch_AVX512DQ_Usable; + /* Determine if AVX512BW is usable. */ + if (CPU_FEATURES_CPU_P (cpu_features, AVX512BW)) +- cpu_features->feature[index_arch_AVX512BW_Usable] ++ cpu_features->usable[index_arch_AVX512BW_Usable] + |= bit_arch_AVX512BW_Usable; + /* Determine if AVX512_4FMAPS is usable. */ + if (CPU_FEATURES_CPU_P (cpu_features, AVX512_4FMAPS)) +- cpu_features->feature[index_arch_AVX512_4FMAPS_Usable] ++ cpu_features->usable[index_arch_AVX512_4FMAPS_Usable] + |= bit_arch_AVX512_4FMAPS_Usable; + /* Determine if AVX512_4VNNIW is usable. */ + if (CPU_FEATURES_CPU_P (cpu_features, AVX512_4VNNIW)) +- cpu_features->feature[index_arch_AVX512_4VNNIW_Usable] ++ cpu_features->usable[index_arch_AVX512_4VNNIW_Usable] + |= bit_arch_AVX512_4VNNIW_Usable; + /* Determine if AVX512_BITALG is usable. */ + if (CPU_FEATURES_CPU_P (cpu_features, AVX512_BITALG)) +- cpu_features->feature[index_arch_AVX512_BITALG_Usable] ++ cpu_features->usable[index_arch_AVX512_BITALG_Usable] + |= bit_arch_AVX512_BITALG_Usable; + /* Determine if AVX512_IFMA is usable. */ + if (CPU_FEATURES_CPU_P (cpu_features, AVX512_IFMA)) +- cpu_features->feature[index_arch_AVX512_IFMA_Usable] ++ cpu_features->usable[index_arch_AVX512_IFMA_Usable] + |= bit_arch_AVX512_IFMA_Usable; + /* Determine if AVX512_VBMI is usable. */ + if (CPU_FEATURES_CPU_P (cpu_features, AVX512_VBMI)) +- cpu_features->feature[index_arch_AVX512_VBMI_Usable] ++ cpu_features->usable[index_arch_AVX512_VBMI_Usable] + |= bit_arch_AVX512_VBMI_Usable; + /* Determine if AVX512_VBMI2 is usable. */ + if (CPU_FEATURES_CPU_P (cpu_features, AVX512_VBMI2)) +- cpu_features->feature[index_arch_AVX512_VBMI2_Usable] ++ cpu_features->usable[index_arch_AVX512_VBMI2_Usable] + |= bit_arch_AVX512_VBMI2_Usable; + /* Determine if is AVX512_VNNI usable. */ + if (CPU_FEATURES_CPU_P (cpu_features, AVX512_VNNI)) +- cpu_features->feature[index_arch_AVX512_VNNI_Usable] ++ cpu_features->usable[index_arch_AVX512_VNNI_Usable] + |= bit_arch_AVX512_VNNI_Usable; + /* Determine if AVX512_VPOPCNTDQ is usable. */ + if (CPU_FEATURES_CPU_P (cpu_features, AVX512_VPOPCNTDQ)) +- cpu_features->feature[index_arch_AVX512_VPOPCNTDQ_Usable] ++ cpu_features->usable[index_arch_AVX512_VPOPCNTDQ_Usable] + |= bit_arch_AVX512_VPOPCNTDQ_Usable; ++ /* Determine if AVX512_VP2INTERSECT is usable. */ ++ if (CPU_FEATURES_CPU_P (cpu_features, ++ AVX512_VP2INTERSECT)) ++ cpu_features->usable[index_arch_AVX512_VP2INTERSECT_Usable] ++ |= bit_arch_AVX512_VP2INTERSECT_Usable; ++ /* Determine if AVX512_BF16 is usable. */ ++ if (CPU_FEATURES_CPU_P (cpu_features, AVX512_BF16)) ++ cpu_features->usable[index_arch_AVX512_BF16_Usable] ++ |= bit_arch_AVX512_BF16_Usable; + } + } + } +@@ -284,13 +300,18 @@ get_common_indices (struct cpu_features *cpu_features, + { + cpu_features->xsave_state_size + = ALIGN_UP (size + STATE_SAVE_OFFSET, 64); +- cpu_features->feature[index_arch_XSAVEC_Usable] ++ cpu_features->usable[index_arch_XSAVEC_Usable] + |= bit_arch_XSAVEC_Usable; + } + } + } + } + } ++ ++ /* Determine if PKU is usable. */ ++ if (CPU_FEATURES_CPU_P (cpu_features, OSPKE)) ++ cpu_features->usable[index_arch_PKU_Usable] ++ |= bit_arch_PKU_Usable; + } + + _Static_assert (((index_arch_Fast_Unaligned_Load +@@ -314,6 +335,8 @@ init_cpu_features (struct cpu_features *cpu_features) + unsigned int stepping = 0; + enum cpu_features_kind kind; + ++ cpu_features->usable_p = cpu_features->usable; ++ + #if !HAS_CPUID + if (__get_cpuid_max (0, 0) == 0) + { +@@ -344,7 +367,7 @@ init_cpu_features (struct cpu_features *cpu_features) + case 0x1c: + case 0x26: + /* BSF is slow on Atom. */ +- cpu_features->feature[index_arch_Slow_BSF] ++ cpu_features->preferred[index_arch_Slow_BSF] + |= bit_arch_Slow_BSF; + break; + +@@ -371,7 +394,7 @@ init_cpu_features (struct cpu_features *cpu_features) + case 0x5d: + /* Unaligned load versions are faster than SSSE3 + on Silvermont. */ +- cpu_features->feature[index_arch_Fast_Unaligned_Load] ++ cpu_features->preferred[index_arch_Fast_Unaligned_Load] + |= (bit_arch_Fast_Unaligned_Load + | bit_arch_Fast_Unaligned_Copy + | bit_arch_Prefer_PMINUB_for_stringop +@@ -383,7 +406,7 @@ init_cpu_features (struct cpu_features *cpu_features) + case 0x9c: + /* Enable rep string instructions, unaligned load, unaligned + copy, pminub and avoid SSE 4.2 on Tremont. */ +- cpu_features->feature[index_arch_Fast_Rep_String] ++ cpu_features->preferred[index_arch_Fast_Rep_String] + |= (bit_arch_Fast_Rep_String + | bit_arch_Fast_Unaligned_Load + | bit_arch_Fast_Unaligned_Copy +@@ -407,7 +430,7 @@ init_cpu_features (struct cpu_features *cpu_features) + case 0x2f: + /* Rep string instructions, unaligned load, unaligned copy, + and pminub are fast on Intel Core i3, i5 and i7. */ +- cpu_features->feature[index_arch_Fast_Rep_String] ++ cpu_features->preferred[index_arch_Fast_Rep_String] + |= (bit_arch_Fast_Rep_String + | bit_arch_Fast_Unaligned_Load + | bit_arch_Fast_Unaligned_Copy +@@ -442,10 +465,10 @@ init_cpu_features (struct cpu_features *cpu_features) + if AVX512ER is available. Don't use AVX512 to avoid lower CPU + frequency if AVX512ER isn't available. */ + if (CPU_FEATURES_CPU_P (cpu_features, AVX512ER)) +- cpu_features->feature[index_arch_Prefer_No_VZEROUPPER] ++ cpu_features->preferred[index_arch_Prefer_No_VZEROUPPER] + |= bit_arch_Prefer_No_VZEROUPPER; + else +- cpu_features->feature[index_arch_Prefer_No_AVX512] ++ cpu_features->preferred[index_arch_Prefer_No_AVX512] + |= bit_arch_Prefer_No_AVX512; + } + /* This spells out "AuthenticAMD". */ +@@ -467,7 +490,7 @@ init_cpu_features (struct cpu_features *cpu_features) + /* Since the FMA4 bit is in COMMON_CPUID_INDEX_80000001 and + FMA4 requires AVX, determine if FMA4 is usable here. */ + if (CPU_FEATURES_CPU_P (cpu_features, FMA4)) +- cpu_features->feature[index_arch_FMA4_Usable] ++ cpu_features->usable[index_arch_FMA4_Usable] + |= bit_arch_FMA4_Usable; + } + +@@ -476,13 +499,13 @@ init_cpu_features (struct cpu_features *cpu_features) + /* "Excavator" */ + if (model >= 0x60 && model <= 0x7f) + { +- cpu_features->feature[index_arch_Fast_Unaligned_Load] ++ cpu_features->preferred[index_arch_Fast_Unaligned_Load] + |= (bit_arch_Fast_Unaligned_Load + | bit_arch_Fast_Copy_Backward); + + /* Unaligned AVX loads are slower.*/ +- cpu_features->feature[index_arch_AVX_Fast_Unaligned_Load] +- &= ~bit_arch_AVX_Fast_Unaligned_Load; ++ cpu_features->preferred[index_arch_AVX_Fast_Unaligned_Load] ++ &= ~bit_arch_AVX_Fast_Unaligned_Load; + } + } + } +@@ -504,41 +527,38 @@ init_cpu_features (struct cpu_features *cpu_features) + { + if (model == 0xf || model == 0x19) + { +- cpu_features->feature[index_arch_AVX_Usable] +- &= (~bit_arch_AVX_Usable +- & ~bit_arch_AVX2_Usable); ++ cpu_features->usable[index_arch_AVX_Usable] ++ &= ~(bit_arch_AVX_Usable | bit_arch_AVX2_Usable); + +- cpu_features->feature[index_arch_Slow_SSE4_2] +- |= (bit_arch_Slow_SSE4_2); ++ cpu_features->preferred[index_arch_Slow_SSE4_2] ++ |= bit_arch_Slow_SSE4_2; + +- cpu_features->feature[index_arch_AVX_Fast_Unaligned_Load] +- &= ~bit_arch_AVX_Fast_Unaligned_Load; ++ cpu_features->preferred[index_arch_AVX_Fast_Unaligned_Load] ++ &= ~bit_arch_AVX_Fast_Unaligned_Load; + } + } + else if (family == 0x7) + { +- if (model == 0x1b) +- { +- cpu_features->feature[index_arch_AVX_Usable] +- &= (~bit_arch_AVX_Usable +- & ~bit_arch_AVX2_Usable); ++ if (model == 0x1b) ++ { ++ cpu_features->usable[index_arch_AVX_Usable] ++ &= ~(bit_arch_AVX_Usable | bit_arch_AVX2_Usable); + +- cpu_features->feature[index_arch_Slow_SSE4_2] +- |= bit_arch_Slow_SSE4_2; ++ cpu_features->preferred[index_arch_Slow_SSE4_2] ++ |= bit_arch_Slow_SSE4_2; ++ ++ cpu_features->preferred[index_arch_AVX_Fast_Unaligned_Load] ++ &= ~bit_arch_AVX_Fast_Unaligned_Load; ++ } ++ else if (model == 0x3b) ++ { ++ cpu_features->usable[index_arch_AVX_Usable] ++ &= ~(bit_arch_AVX_Usable | bit_arch_AVX2_Usable); + +- cpu_features->feature[index_arch_AVX_Fast_Unaligned_Load] +- &= ~bit_arch_AVX_Fast_Unaligned_Load; +- } +- else if (model == 0x3b) +- { +- cpu_features->feature[index_arch_AVX_Usable] +- &= (~bit_arch_AVX_Usable +- & ~bit_arch_AVX2_Usable); +- +- cpu_features->feature[index_arch_AVX_Fast_Unaligned_Load] +- &= ~bit_arch_AVX_Fast_Unaligned_Load; +- } +- } ++ cpu_features->preferred[index_arch_AVX_Fast_Unaligned_Load] ++ &= ~bit_arch_AVX_Fast_Unaligned_Load; ++ } ++ } + } + else + { +@@ -548,11 +568,11 @@ init_cpu_features (struct cpu_features *cpu_features) + + /* Support i586 if CX8 is available. */ + if (CPU_FEATURES_CPU_P (cpu_features, CX8)) +- cpu_features->feature[index_arch_I586] |= bit_arch_I586; ++ cpu_features->preferred[index_arch_I586] |= bit_arch_I586; + + /* Support i686 if CMOV is available. */ + if (CPU_FEATURES_CPU_P (cpu_features, CMOV)) +- cpu_features->feature[index_arch_I686] |= bit_arch_I686; ++ cpu_features->preferred[index_arch_I686] |= bit_arch_I686; + + #if !HAS_CPUID + no_cpuid: +diff --git a/sysdeps/x86/cpu-features.h b/sysdeps/x86/cpu-features.h +index f18f7520fcb7714a..41c3855e94d16b49 100644 +--- a/sysdeps/x86/cpu-features.h ++++ b/sysdeps/x86/cpu-features.h +@@ -20,12 +20,20 @@ + + enum + { +- /* The integer bit array index for the first set of internal feature ++ /* The integer bit array index for the first set of usable feature + bits. */ +- FEATURE_INDEX_1 = 0, +- FEATURE_INDEX_2, ++ USABLE_FEATURE_INDEX_1 = 0, + /* The current maximum size of the feature integer bit array. */ +- FEATURE_INDEX_MAX ++ USABLE_FEATURE_INDEX_MAX ++}; ++ ++enum ++{ ++ /* The integer bit array index for the first set of preferred feature ++ bits. */ ++ PREFERRED_FEATURE_INDEX_1 = 0, ++ /* The current maximum size of the feature integer bit array. */ ++ PREFERRED_FEATURE_INDEX_MAX + }; + + enum +@@ -36,6 +44,7 @@ enum + COMMON_CPUID_INDEX_D_ECX_1, + COMMON_CPUID_INDEX_80000007, + COMMON_CPUID_INDEX_80000008, ++ COMMON_CPUID_INDEX_7_ECX_1, + /* Keep the following line at the end. */ + COMMON_CPUID_INDEX_MAX + }; +@@ -68,9 +77,11 @@ struct cpu_features_basic + + struct cpu_features + { +- struct cpuid_registers cpuid[COMMON_CPUID_INDEX_MAX]; +- unsigned int feature[FEATURE_INDEX_MAX]; + struct cpu_features_basic basic; ++ unsigned int *usable_p; ++ struct cpuid_registers cpuid[COMMON_CPUID_INDEX_MAX]; ++ unsigned int usable[USABLE_FEATURE_INDEX_MAX]; ++ unsigned int preferred[PREFERRED_FEATURE_INDEX_MAX]; + /* The state size for XSAVEC or XSAVE. The type must be unsigned long + int so that we use + +@@ -102,7 +113,7 @@ extern const struct cpu_features *__get_cpu_features (void) + # define CPU_FEATURES_CPU_P(ptr, name) \ + ((ptr->cpuid[index_cpu_##name].reg_##name & (bit_cpu_##name)) != 0) + # define CPU_FEATURES_ARCH_P(ptr, name) \ +- ((ptr->feature[index_arch_##name] & (bit_arch_##name)) != 0) ++ ((ptr->feature_##name[index_arch_##name] & (bit_arch_##name)) != 0) + + /* HAS_CPU_FEATURE evaluates to true if CPU supports the feature. */ + #define HAS_CPU_FEATURE(name) \ +@@ -112,13 +123,12 @@ extern const struct cpu_features *__get_cpu_features (void) + # define HAS_ARCH_FEATURE(name) \ + CPU_FEATURES_ARCH_P (__get_cpu_features (), name) + /* CPU_FEATURE_USABLE evaluates to true if the feature is usable. */ +-#define CPU_FEATURE_USABLE(name) \ +- ((need_arch_feature_##name && HAS_ARCH_FEATURE (name##_Usable)) \ +- || (!need_arch_feature_##name && HAS_CPU_FEATURE(name))) ++#define CPU_FEATURE_USABLE(name) \ ++ HAS_ARCH_FEATURE (name##_Usable) + + /* Architecture features. */ + +-/* FEATURE_INDEX_1. */ ++/* USABLE_FEATURE_INDEX_1. */ + #define bit_arch_AVX_Usable (1u << 0) + #define bit_arch_AVX2_Usable (1u << 1) + #define bit_arch_AVX512F_Usable (1u << 2) +@@ -143,237 +153,65 @@ extern const struct cpu_features *__get_cpu_features (void) + #define bit_arch_XOP_Usable (1u << 21) + #define bit_arch_XSAVEC_Usable (1u << 22) + #define bit_arch_F16C_Usable (1u << 23) +- +-#define index_arch_AVX_Usable FEATURE_INDEX_1 +-#define index_arch_AVX2_Usable FEATURE_INDEX_1 +-#define index_arch_AVX512F_Usable FEATURE_INDEX_1 +-#define index_arch_AVX512CD_Usable FEATURE_INDEX_1 +-#define index_arch_AVX512ER_Usable FEATURE_INDEX_1 +-#define index_arch_AVX512PF_Usable FEATURE_INDEX_1 +-#define index_arch_AVX512VL_Usable FEATURE_INDEX_1 +-#define index_arch_AVX512BW_Usable FEATURE_INDEX_1 +-#define index_arch_AVX512DQ_Usable FEATURE_INDEX_1 +-#define index_arch_AVX512_4FMAPS_Usable FEATURE_INDEX_1 +-#define index_arch_AVX512_4VNNIW_Usable FEATURE_INDEX_1 +-#define index_arch_AVX512_BITALG_Usable FEATURE_INDEX_1 +-#define index_arch_AVX512_IFMA_Usable FEATURE_INDEX_1 +-#define index_arch_AVX512_VBMI_Usable FEATURE_INDEX_1 +-#define index_arch_AVX512_VBMI2_Usable FEATURE_INDEX_1 +-#define index_arch_AVX512_VNNI_Usable FEATURE_INDEX_1 +-#define index_arch_AVX512_VPOPCNTDQ_Usable FEATURE_INDEX_1 +-#define index_arch_FMA_Usable FEATURE_INDEX_1 +-#define index_arch_FMA4_Usable FEATURE_INDEX_1 +-#define index_arch_VAES_Usable FEATURE_INDEX_1 +-#define index_arch_VPCLMULQDQ_Usable FEATURE_INDEX_1 +-#define index_arch_XOP_Usable FEATURE_INDEX_1 +-#define index_arch_XSAVEC_Usable FEATURE_INDEX_1 +-#define index_arch_F16C_Usable FEATURE_INDEX_1 +- +-/* Unused. Compiler will optimize them out. */ +-#define bit_arch_SSE3_Usable (1u << 0) +-#define bit_arch_PCLMULQDQ_Usable (1u << 0) +-#define bit_arch_SSSE3_Usable (1u << 0) +-#define bit_arch_CMPXCHG16B_Usable (1u << 0) +-#define bit_arch_SSE4_1_Usable (1u << 0) +-#define bit_arch_SSE4_2_Usable (1u << 0) +-#define bit_arch_MOVBE_Usable (1u << 0) +-#define bit_arch_POPCNT_Usable (1u << 0) +-#define bit_arch_AES_Usable (1u << 0) +-#define bit_arch_XSAVE_Usable (1u << 0) +-#define bit_arch_OSXSAVE_Usable (1u << 0) +-#define bit_arch_RDRAND_Usable (1u << 0) +-#define bit_arch_FPU_Usable (1u << 0) +-#define bit_arch_TSC_Usable (1u << 0) +-#define bit_arch_MSR_Usable (1u << 0) +-#define bit_arch_CX8_Usable (1u << 0) +-#define bit_arch_SEP_Usable (1u << 0) +-#define bit_arch_CMOV_Usable (1u << 0) +-#define bit_arch_CLFSH_Usable (1u << 0) +-#define bit_arch_MMX_Usable (1u << 0) +-#define bit_arch_FXSR_Usable (1u << 0) +-#define bit_arch_SSE_Usable (1u << 0) +-#define bit_arch_SSE2_Usable (1u << 0) +-#define bit_arch_FSGSBASE_Usable (1u << 0) +-#define bit_arch_BMI1_Usable (1u << 0) +-#define bit_arch_HLE_Usable (1u << 0) +-#define bit_arch_BMI2_Usable (1u << 0) +-#define bit_arch_ERMS_Usable (1u << 0) +-#define bit_arch_RTM_Usable (1u << 0) +-#define bit_arch_RDSEED_Usable (1u << 0) +-#define bit_arch_ADX_Usable (1u << 0) +-#define bit_arch_CLFLUSHOPT_Usable (1u << 0) +-#define bit_arch_CLWB_Usable (1u << 0) +-#define bit_arch_SHA_Usable (1u << 0) +-#define bit_arch_PREFETCHWT1_Usable (1u << 0) +-#define bit_arch_GFNI_Usable (1u << 0) +-#define bit_arch_RDPID_Usable (1u << 0) +-#define bit_arch_CLDEMOTE_Usable (1u << 0) +-#define bit_arch_MOVDIRI_Usable (1u << 0) +-#define bit_arch_MOVDIR64B_Usable (1u << 0) +-#define bit_arch_FSRM_Usable (1u << 0) +-#define bit_arch_LAHF64_SAHF64_Usable (1u << 0) +-#define bit_arch_SVM_Usable (1u << 0) +-#define bit_arch_LZCNT_Usable (1u << 0) +-#define bit_arch_SSE4A_Usable (1u << 0) +-#define bit_arch_PREFETCHW_Usable (1u << 0) +-#define bit_arch_TBM_Usable (1u << 0) +-#define bit_arch_SYSCALL_SYSRET_Usable (1u << 0) +-#define bit_arch_RDTSCP_Usable (1u << 0) +-#define bit_arch_XSAVEOPT_Usable (1u << 0) +-#define bit_arch_XGETBV_ECX_1_Usable (1u << 0) +-#define bit_arch_XSAVES_Usable (1u << 0) +-#define bit_arch_INVARIANT_TSC_Usable (1u << 0) +-#define bit_arch_WBNOINVD_Usable (1u << 0) +- +-/* Unused. Compiler will optimize them out. */ +-#define index_arch_SSE3_Usable FEATURE_INDEX_1 +-#define index_arch_PCLMULQDQ_Usable FEATURE_INDEX_1 +-#define index_arch_SSSE3_Usable FEATURE_INDEX_1 +-#define index_arch_CMPXCHG16B_Usable FEATURE_INDEX_1 +-#define index_arch_SSE4_1_Usable FEATURE_INDEX_1 +-#define index_arch_SSE4_2_Usable FEATURE_INDEX_1 +-#define index_arch_MOVBE_Usable FEATURE_INDEX_1 +-#define index_arch_POPCNT_Usable FEATURE_INDEX_1 +-#define index_arch_AES_Usable FEATURE_INDEX_1 +-#define index_arch_XSAVE_Usable FEATURE_INDEX_1 +-#define index_arch_OSXSAVE_Usable FEATURE_INDEX_1 +-#define index_arch_RDRAND_Usable FEATURE_INDEX_1 +-#define index_arch_FPU_Usable FEATURE_INDEX_1 +-#define index_arch_TSC_Usable FEATURE_INDEX_1 +-#define index_arch_MSR_Usable FEATURE_INDEX_1 +-#define index_arch_CX8_Usable FEATURE_INDEX_1 +-#define index_arch_SEP_Usable FEATURE_INDEX_1 +-#define index_arch_CMOV_Usable FEATURE_INDEX_1 +-#define index_arch_CLFSH_Usable FEATURE_INDEX_1 +-#define index_arch_MMX_Usable FEATURE_INDEX_1 +-#define index_arch_FXSR_Usable FEATURE_INDEX_1 +-#define index_arch_SSE_Usable FEATURE_INDEX_1 +-#define index_arch_SSE2_Usable FEATURE_INDEX_1 +-#define index_arch_FSGSBASE_Usable FEATURE_INDEX_1 +-#define index_arch_BMI1_Usable FEATURE_INDEX_1 +-#define index_arch_HLE_Usable FEATURE_INDEX_1 +-#define index_arch_BMI2_Usable FEATURE_INDEX_1 +-#define index_arch_ERMS_Usable FEATURE_INDEX_1 +-#define index_arch_RTM_Usable FEATURE_INDEX_1 +-#define index_arch_RDSEED_Usable FEATURE_INDEX_1 +-#define index_arch_ADX_Usable FEATURE_INDEX_1 +-#define index_arch_CLFLUSHOPT_Usable FEATURE_INDEX_1 +-#define index_arch_CLWB_Usable FEATURE_INDEX_1 +-#define index_arch_SHA_Usable FEATURE_INDEX_1 +-#define index_arch_PREFETCHWT1_Usable FEATURE_INDEX_1 +-#define index_arch_GFNI_Usable FEATURE_INDEX_1 +-#define index_arch_RDPID_Usable FEATURE_INDEX_1 +-#define index_arch_CLDEMOTE_Usable FEATURE_INDEX_1 +-#define index_arch_MOVDIRI_Usable FEATURE_INDEX_1 +-#define index_arch_MOVDIR64B_Usable FEATURE_INDEX_1 +-#define index_arch_FSRM_Usable FEATURE_INDEX_1 +-#define index_arch_LAHF64_SAHF64_Usable FEATURE_INDEX_1 +-#define index_arch_LZCNT_Usable FEATURE_INDEX_1 +-#define index_arch_SSE4A_Usable FEATURE_INDEX_1 +-#define index_arch_PREFETCHW_Usable FEATURE_INDEX_1 +-#define index_arch_TBM_Usable FEATURE_INDEX_1 +-#define index_arch_SYSCALL_SYSRET_Usable FEATURE_INDEX_1 +-#define index_arch_RDTSCP_Usable FEATURE_INDEX_1 +-#define index_arch_XSAVEOPT_Usable FEATURE_INDEX_1 +-#define index_arch_XGETBV_ECX_1_Usable FEATURE_INDEX_1 +-#define index_arch_XSAVES_Usable FEATURE_INDEX_1 +-#define index_arch_INVARIANT_TSC_Usable FEATURE_INDEX_1 +-#define index_arch_WBNOINVD_Usable FEATURE_INDEX_1 +- +-/* COMMON_CPUID_INDEX_1. */ +- +-/* ECX. */ +-#define need_arch_feature_SSE3 0 +-#define need_arch_feature_PCLMULQDQ 0 +-#define need_arch_feature_SSSE3 0 +-#define need_arch_feature_FMA 1 +-#define need_arch_feature_CMPXCHG16B 0 +-#define need_arch_feature_SSE4_1 0 +-#define need_arch_feature_SSE4_2 0 +-#define need_arch_feature_MOVBE 0 +-#define need_arch_feature_POPCNT 0 +-#define need_arch_feature_AES 0 +-#define need_arch_feature_XSAVE 0 +-#define need_arch_feature_OSXSAVE 0 +-#define need_arch_feature_AVX 1 +-#define need_arch_feature_F16C 1 +-#define need_arch_feature_RDRAND 0 +- +-/* EDX. */ +-#define need_arch_feature_FPU 0 +-#define need_arch_feature_TSC 0 +-#define need_arch_feature_MSR 0 +-#define need_arch_feature_CX8 0 +-#define need_arch_feature_SEP 0 +-#define need_arch_feature_CMOV 0 +-#define need_arch_feature_CLFSH 0 +-#define need_arch_feature_MMX 0 +-#define need_arch_feature_FXSR 0 +-#define need_arch_feature_SSE 0 +-#define need_arch_feature_SSE2 0 +- +-/* COMMON_CPUID_INDEX_7. */ +- +-/* EBX. */ +-#define need_arch_feature_FSGSBASE 0 +-#define need_arch_feature_BMI1 0 +-#define need_arch_feature_HLE 0 +-#define need_arch_feature_AVX2 1 +-#define need_arch_feature_BMI2 0 +-#define need_arch_feature_ERMS 0 +-#define need_arch_feature_RTM 0 +-#define need_arch_feature_AVX512F 1 +-#define need_arch_feature_AVX512DQ 1 +-#define need_arch_feature_RDSEED 0 +-#define need_arch_feature_ADX 0 +-#define need_arch_feature_AVX512_IFMA 1 +-#define need_arch_feature_CLFLUSHOPT 0 +-#define need_arch_feature_CLWB 0 +-#define need_arch_feature_AVX512PF 1 +-#define need_arch_feature_AVX512ER 1 +-#define need_arch_feature_AVX512CD 1 +-#define need_arch_feature_SHA 0 +-#define need_arch_feature_AVX512BW 1 +-#define need_arch_feature_AVX512VL 1 +- +-/* ECX. */ +-#define need_arch_feature_PREFETCHWT1 0 +-#define need_arch_feature_AVX512_VBMI 1 +-#define need_arch_feature_AVX512_VBMI2 1 +-#define need_arch_feature_GFNI 0 +-#define need_arch_feature_VAES 1 +-#define need_arch_feature_VPCLMULQDQ 1 +-#define need_arch_feature_AVX512_VNNI 1 +-#define need_arch_feature_AVX512_BITALG 1 +-#define need_arch_feature_AVX512_VPOPCNTDQ 1 +-#define need_arch_feature_RDPID 0 +-#define need_arch_feature_CLDEMOTE 0 +-#define need_arch_feature_MOVDIRI 0 +-#define need_arch_feature_MOVDIR64B 0 +- +-/* EDX. */ +-#define need_arch_feature_AVX512_4VNNIW 1 +-#define need_arch_feature_AVX512_4FMAPS 1 +-#define need_arch_feature_FSRM 0 +- +-/* COMMON_CPUID_INDEX_80000001. */ +- +-/* ECX. */ +-#define need_arch_feature_LAHF64_SAHF64 0 +-#define need_arch_feature_LZCNT 0 +-#define need_arch_feature_SSE4A 0 +-#define need_arch_feature_PREFETCHW 0 +-#define need_arch_feature_XOP 1 +-#define need_arch_feature_FMA4 1 +-#define need_arch_feature_TBM 0 +-#define need_arch_feature_SYSCALL_SYSRET 0 +-#define need_arch_feature_RDTSCP 0 +-#define need_arch_feature_XSAVEOPT 0 +-#define need_arch_feature_XSAVEC 1 +-#define need_arch_feature_XGETBV_ECX_1 0 +-#define need_arch_feature_XSAVES 0 +-#define need_arch_feature_INVARIANT_TSC 0 +-#define need_arch_feature_WBNOINVD 0 ++#define bit_arch_AVX512_VP2INTERSECT_Usable (1u << 24) ++#define bit_arch_AVX512_BF16_Usable (1u << 25) ++#define bit_arch_PKU_Usable (1u << 26) ++ ++#define index_arch_AVX_Usable USABLE_FEATURE_INDEX_1 ++#define index_arch_AVX2_Usable USABLE_FEATURE_INDEX_1 ++#define index_arch_AVX512F_Usable USABLE_FEATURE_INDEX_1 ++#define index_arch_AVX512CD_Usable USABLE_FEATURE_INDEX_1 ++#define index_arch_AVX512ER_Usable USABLE_FEATURE_INDEX_1 ++#define index_arch_AVX512PF_Usable USABLE_FEATURE_INDEX_1 ++#define index_arch_AVX512VL_Usable USABLE_FEATURE_INDEX_1 ++#define index_arch_AVX512BW_Usable USABLE_FEATURE_INDEX_1 ++#define index_arch_AVX512DQ_Usable USABLE_FEATURE_INDEX_1 ++#define index_arch_AVX512_4FMAPS_Usable USABLE_FEATURE_INDEX_1 ++#define index_arch_AVX512_4VNNIW_Usable USABLE_FEATURE_INDEX_1 ++#define index_arch_AVX512_BITALG_Usable USABLE_FEATURE_INDEX_1 ++#define index_arch_AVX512_IFMA_Usable USABLE_FEATURE_INDEX_1 ++#define index_arch_AVX512_VBMI_Usable USABLE_FEATURE_INDEX_1 ++#define index_arch_AVX512_VBMI2_Usable USABLE_FEATURE_INDEX_1 ++#define index_arch_AVX512_VNNI_Usable USABLE_FEATURE_INDEX_1 ++#define index_arch_AVX512_VPOPCNTDQ_Usable USABLE_FEATURE_INDEX_1 ++#define index_arch_FMA_Usable USABLE_FEATURE_INDEX_1 ++#define index_arch_FMA4_Usable USABLE_FEATURE_INDEX_1 ++#define index_arch_VAES_Usable USABLE_FEATURE_INDEX_1 ++#define index_arch_VPCLMULQDQ_Usable USABLE_FEATURE_INDEX_1 ++#define index_arch_XOP_Usable USABLE_FEATURE_INDEX_1 ++#define index_arch_XSAVEC_Usable USABLE_FEATURE_INDEX_1 ++#define index_arch_F16C_Usable USABLE_FEATURE_INDEX_1 ++#define index_arch_AVX512_VP2INTERSECT_Usable USABLE_FEATURE_INDEX_1 ++#define index_arch_AVX512_BF16_Usable USABLE_FEATURE_INDEX_1 ++#define index_arch_PKU_Usable USABLE_FEATURE_INDEX_1 ++ ++#define feature_AVX_Usable usable ++#define feature_AVX2_Usable usable ++#define feature_AVX512F_Usable usable ++#define feature_AVX512CD_Usable usable ++#define feature_AVX512ER_Usable usable ++#define feature_AVX512PF_Usable usable ++#define feature_AVX512VL_Usable usable ++#define feature_AVX512BW_Usable usable ++#define feature_AVX512DQ_Usable usable ++#define feature_AVX512_4FMAPS_Usable usable ++#define feature_AVX512_4VNNIW_Usable usable ++#define feature_AVX512_BITALG_Usable usable ++#define feature_AVX512_IFMA_Usable usable ++#define feature_AVX512_VBMI_Usable usable ++#define feature_AVX512_VBMI2_Usable usable ++#define feature_AVX512_VNNI_Usable usable ++#define feature_AVX512_VPOPCNTDQ_Usable usable ++#define feature_FMA_Usable usable ++#define feature_FMA4_Usable usable ++#define feature_VAES_Usable usable ++#define feature_VPCLMULQDQ_Usable usable ++#define feature_XOP_Usable usable ++#define feature_XSAVEC_Usable usable ++#define feature_F16C_Usable usable ++#define feature_AVX512_VP2INTERSECT_Usable usable ++#define feature_AVX512_BF16_Usable usable ++#define feature_PKU_Usable usable + + /* CPU features. */ + +@@ -494,17 +332,26 @@ extern const struct cpu_features *__get_cpu_features (void) + #define bit_cpu_CLDEMOTE (1u << 25) + #define bit_cpu_MOVDIRI (1u << 27) + #define bit_cpu_MOVDIR64B (1u << 28) ++#define bit_cpu_ENQCMD (1u << 29) + #define bit_cpu_SGX_LC (1u << 30) ++#define bit_cpu_PKS (1u << 31) + + /* EDX. */ + #define bit_cpu_AVX512_4VNNIW (1u << 2) + #define bit_cpu_AVX512_4FMAPS (1u << 3) + #define bit_cpu_FSRM (1u << 4) ++#define bit_cpu_AVX512_VP2INTERSECT (1u << 8) ++#define bit_cpu_MD_CLEAR (1u << 10) ++#define bit_cpu_SERIALIZE (1u << 14) ++#define bit_cpu_HYBRID (1u << 15) ++#define bit_cpu_TSXLDTRK (1u << 16) + #define bit_cpu_PCONFIG (1u << 18) + #define bit_cpu_IBT (1u << 20) + #define bit_cpu_IBRS_IBPB (1u << 26) + #define bit_cpu_STIBP (1u << 27) +-#define bit_cpu_CAPABILITIES (1u << 29) ++#define bit_cpu_L1D_FLUSH (1u << 28) ++#define bit_cpu_ARCH_CAPABILITIES (1u << 29) ++#define bit_cpu_CORE_CAPABILITIES (1u << 30) + #define bit_cpu_SSBD (1u << 31) + + /* COMMON_CPUID_INDEX_80000001. */ +@@ -545,6 +392,11 @@ extern const struct cpu_features *__get_cpu_features (void) + /* EBX. */ + #define bit_cpu_WBNOINVD (1u << 9) + ++/* COMMON_CPUID_INDEX_7_ECX_1. */ ++ ++/* EAX. */ ++#define bit_cpu_AVX512_BF16 (1u << 5) ++ + /* COMMON_CPUID_INDEX_1. */ + + /* ECX. */ +@@ -662,17 +514,26 @@ extern const struct cpu_features *__get_cpu_features (void) + #define index_cpu_CLDEMOTE COMMON_CPUID_INDEX_7 + #define index_cpu_MOVDIRI COMMON_CPUID_INDEX_7 + #define index_cpu_MOVDIR64B COMMON_CPUID_INDEX_7 ++#define index_cpu_ENQCMD COMMON_CPUID_INDEX_7 + #define index_cpu_SGX_LC COMMON_CPUID_INDEX_7 ++#define index_cpu_PKS COMMON_CPUID_INDEX_7 + + /* EDX. */ + #define index_cpu_AVX512_4VNNIW COMMON_CPUID_INDEX_7 + #define index_cpu_AVX512_4FMAPS COMMON_CPUID_INDEX_7 + #define index_cpu_FSRM COMMON_CPUID_INDEX_7 ++#define index_cpu_AVX512_VP2INTERSECT COMMON_CPUID_INDEX_7 ++#define index_cpu_MD_CLEAR COMMON_CPUID_INDEX_7 ++#define index_cpu_SERIALIZE COMMON_CPUID_INDEX_7 ++#define index_cpu_HYBRID COMMON_CPUID_INDEX_7 ++#define index_cpu_TSXLDTRK COMMON_CPUID_INDEX_7 + #define index_cpu_PCONFIG COMMON_CPUID_INDEX_7 + #define index_cpu_IBT COMMON_CPUID_INDEX_7 + #define index_cpu_IBRS_IBPB COMMON_CPUID_INDEX_7 + #define index_cpu_STIBP COMMON_CPUID_INDEX_7 +-#define index_cpu_CAPABILITIES COMMON_CPUID_INDEX_7 ++#define index_cpu_L1D_FLUSH COMMON_CPUID_INDEX_7 ++#define index_cpu_ARCH_CAPABILITIES COMMON_CPUID_INDEX_7 ++#define index_cpu_CORE_CAPABILITIES COMMON_CPUID_INDEX_7 + #define index_cpu_SSBD COMMON_CPUID_INDEX_7 + + /* COMMON_CPUID_INDEX_80000001. */ +@@ -713,6 +574,11 @@ extern const struct cpu_features *__get_cpu_features (void) + /* EBX. */ + #define index_cpu_WBNOINVD COMMON_CPUID_INDEX_80000008 + ++/* COMMON_CPUID_INDEX_7_ECX_1. */ ++ ++/* EAX. */ ++#define index_cpu_AVX512_BF16 COMMON_CPUID_INDEX_7_ECX_1 ++ + /* COMMON_CPUID_INDEX_1. */ + + /* ECX. */ +@@ -830,17 +696,26 @@ extern const struct cpu_features *__get_cpu_features (void) + #define reg_CLDEMOTE ecx + #define reg_MOVDIRI ecx + #define reg_MOVDIR64B ecx ++#define reg_ENQCMD ecx + #define reg_SGX_LC ecx ++#define reg_PKS ecx + + /* EDX. */ + #define reg_AVX512_4VNNIW edx + #define reg_AVX512_4FMAPS edx + #define reg_FSRM edx ++#define reg_AVX512_VP2INTERSECT edx ++#define reg_MD_CLEAR edx ++#define reg_SERIALIZE edx ++#define reg_HYBRID edx ++#define reg_TSXLDTRK edx + #define reg_PCONFIG edx + #define reg_IBT edx + #define reg_IBRS_IBPB edx + #define reg_STIBP edx +-#define reg_CAPABILITIES edx ++#define reg_L1D_FLUSH edx ++#define reg_ARCH_CAPABILITIES edx ++#define reg_CORE_CAPABILITIES edx + #define reg_SSBD edx + + /* COMMON_CPUID_INDEX_80000001. */ +@@ -881,6 +756,11 @@ extern const struct cpu_features *__get_cpu_features (void) + /* EBX. */ + #define reg_WBNOINVD ebx + ++/* COMMON_CPUID_INDEX_7_ECX_1. */ ++ ++/* EAX. */ ++#define reg_AVX512_BF16 eax ++ + /* FEATURE_INDEX_2. */ + #define bit_arch_I586 (1u << 0) + #define bit_arch_I686 (1u << 1) +@@ -899,22 +779,39 @@ extern const struct cpu_features *__get_cpu_features (void) + #define bit_arch_Prefer_No_AVX512 (1u << 14) + #define bit_arch_MathVec_Prefer_No_AVX512 (1u << 15) + +-#define index_arch_Fast_Rep_String FEATURE_INDEX_2 +-#define index_arch_Fast_Copy_Backward FEATURE_INDEX_2 +-#define index_arch_Slow_BSF FEATURE_INDEX_2 +-#define index_arch_Fast_Unaligned_Load FEATURE_INDEX_2 +-#define index_arch_Prefer_PMINUB_for_stringop FEATURE_INDEX_2 +-#define index_arch_Fast_Unaligned_Copy FEATURE_INDEX_2 +-#define index_arch_I586 FEATURE_INDEX_2 +-#define index_arch_I686 FEATURE_INDEX_2 +-#define index_arch_Slow_SSE4_2 FEATURE_INDEX_2 +-#define index_arch_AVX_Fast_Unaligned_Load FEATURE_INDEX_2 +-#define index_arch_Prefer_MAP_32BIT_EXEC FEATURE_INDEX_2 +-#define index_arch_Prefer_No_VZEROUPPER FEATURE_INDEX_2 +-#define index_arch_Prefer_ERMS FEATURE_INDEX_2 +-#define index_arch_Prefer_No_AVX512 FEATURE_INDEX_2 +-#define index_arch_MathVec_Prefer_No_AVX512 FEATURE_INDEX_2 +-#define index_arch_Prefer_FSRM FEATURE_INDEX_2 ++#define index_arch_Fast_Rep_String PREFERRED_FEATURE_INDEX_1 ++#define index_arch_Fast_Copy_Backward PREFERRED_FEATURE_INDEX_1 ++#define index_arch_Slow_BSF PREFERRED_FEATURE_INDEX_1 ++#define index_arch_Fast_Unaligned_Load PREFERRED_FEATURE_INDEX_1 ++#define index_arch_Prefer_PMINUB_for_stringop PREFERRED_FEATURE_INDEX_1 ++#define index_arch_Fast_Unaligned_Copy PREFERRED_FEATURE_INDEX_1 ++#define index_arch_I586 PREFERRED_FEATURE_INDEX_1 ++#define index_arch_I686 PREFERRED_FEATURE_INDEX_1 ++#define index_arch_Slow_SSE4_2 PREFERRED_FEATURE_INDEX_1 ++#define index_arch_AVX_Fast_Unaligned_Load PREFERRED_FEATURE_INDEX_1 ++#define index_arch_Prefer_MAP_32BIT_EXEC PREFERRED_FEATURE_INDEX_1 ++#define index_arch_Prefer_No_VZEROUPPER PREFERRED_FEATURE_INDEX_1 ++#define index_arch_Prefer_ERMS PREFERRED_FEATURE_INDEX_1 ++#define index_arch_Prefer_No_AVX512 PREFERRED_FEATURE_INDEX_1 ++#define index_arch_MathVec_Prefer_No_AVX512 PREFERRED_FEATURE_INDEX_1 ++#define index_arch_Prefer_FSRM PREFERRED_FEATURE_INDEX_1 ++ ++#define feature_Fast_Rep_String preferred ++#define feature_Fast_Copy_Backward preferred ++#define feature_Slow_BSF preferred ++#define feature_Fast_Unaligned_Load preferred ++#define feature_Prefer_PMINUB_for_stringop preferred ++#define feature_Fast_Unaligned_Copy preferred ++#define feature_I586 preferred ++#define feature_I686 preferred ++#define feature_Slow_SSE4_2 preferred ++#define feature_AVX_Fast_Unaligned_Load preferred ++#define feature_Prefer_MAP_32BIT_EXEC preferred ++#define feature_Prefer_No_VZEROUPPER preferred ++#define feature_Prefer_ERMS preferred ++#define feature_Prefer_No_AVX512 preferred ++#define feature_MathVec_Prefer_No_AVX512 preferred ++#define feature_Prefer_FSRM preferred + + /* XCR0 Feature flags. */ + #define bit_XMM_state (1u << 1) +diff --git a/sysdeps/x86/cpu-tunables.c b/sysdeps/x86/cpu-tunables.c +index 2e5d37753713e975..012ae48933055eaa 100644 +--- a/sysdeps/x86/cpu-tunables.c ++++ b/sysdeps/x86/cpu-tunables.c +@@ -54,7 +54,7 @@ extern __typeof (memcmp) DEFAULT_MEMCMP; + _Static_assert (sizeof (#name) - 1 == len, #name " != " #len); \ + if (!DEFAULT_MEMCMP (f, #name, len)) \ + { \ +- cpu_features->feature[index_arch_##name] \ ++ cpu_features->feature_##name[index_arch_##name] \ + &= ~bit_arch_##name; \ + break; \ + } +@@ -66,10 +66,10 @@ extern __typeof (memcmp) DEFAULT_MEMCMP; + if (!DEFAULT_MEMCMP (f, #name, len)) \ + { \ + if (disable) \ +- cpu_features->feature[index_arch_##name] \ ++ cpu_features->feature_##name[index_arch_##name] \ + &= ~bit_arch_##name; \ + else \ +- cpu_features->feature[index_arch_##name] \ ++ cpu_features->feature_##name[index_arch_##name] \ + |= bit_arch_##name; \ + break; \ + } +@@ -82,10 +82,10 @@ extern __typeof (memcmp) DEFAULT_MEMCMP; + if (!DEFAULT_MEMCMP (f, #name, len)) \ + { \ + if (disable) \ +- cpu_features->feature[index_arch_##name] \ ++ cpu_features->feature_##name[index_arch_##name] \ + &= ~bit_arch_##name; \ + else if (CPU_FEATURES_ARCH_P (cpu_features, need)) \ +- cpu_features->feature[index_arch_##name] \ ++ cpu_features->feature_##name[index_arch_##name] \ + |= bit_arch_##name; \ + break; \ + } +@@ -98,10 +98,10 @@ extern __typeof (memcmp) DEFAULT_MEMCMP; + if (!DEFAULT_MEMCMP (f, #name, len)) \ + { \ + if (disable) \ +- cpu_features->feature[index_arch_##name] \ ++ cpu_features->feature_##name[index_arch_##name] \ + &= ~bit_arch_##name; \ + else if (CPU_FEATURES_CPU_P (cpu_features, need)) \ +- cpu_features->feature[index_arch_##name] \ ++ cpu_features->feature_##name[index_arch_##name] \ + |= bit_arch_##name; \ + break; \ + } +diff --git a/sysdeps/x86/tst-get-cpu-features.c b/sysdeps/x86/tst-get-cpu-features.c +index 64a7fd6157242bdd..08688ace2a0ae35e 100644 +--- a/sysdeps/x86/tst-get-cpu-features.c ++++ b/sysdeps/x86/tst-get-cpu-features.c +@@ -172,15 +172,24 @@ do_test (void) + CHECK_CPU_FEATURE (CLDEMOTE); + CHECK_CPU_FEATURE (MOVDIRI); + CHECK_CPU_FEATURE (MOVDIR64B); ++ CHECK_CPU_FEATURE (ENQCMD); + CHECK_CPU_FEATURE (SGX_LC); ++ CHECK_CPU_FEATURE (PKS); + CHECK_CPU_FEATURE (AVX512_4VNNIW); + CHECK_CPU_FEATURE (AVX512_4FMAPS); + CHECK_CPU_FEATURE (FSRM); ++ CHECK_CPU_FEATURE (AVX512_VP2INTERSECT); ++ CHECK_CPU_FEATURE (MD_CLEAR); ++ CHECK_CPU_FEATURE (SERIALIZE); ++ CHECK_CPU_FEATURE (HYBRID); ++ CHECK_CPU_FEATURE (TSXLDTRK); + CHECK_CPU_FEATURE (PCONFIG); + CHECK_CPU_FEATURE (IBT); + CHECK_CPU_FEATURE (IBRS_IBPB); + CHECK_CPU_FEATURE (STIBP); +- CHECK_CPU_FEATURE (CAPABILITIES); ++ CHECK_CPU_FEATURE (L1D_FLUSH); ++ CHECK_CPU_FEATURE (ARCH_CAPABILITIES); ++ CHECK_CPU_FEATURE (CORE_CAPABILITIES); + CHECK_CPU_FEATURE (SSBD); + CHECK_CPU_FEATURE (LAHF64_SAHF64); + CHECK_CPU_FEATURE (SVM); +@@ -202,84 +211,36 @@ do_test (void) + CHECK_CPU_FEATURE (XSAVES); + CHECK_CPU_FEATURE (INVARIANT_TSC); + CHECK_CPU_FEATURE (WBNOINVD); ++ CHECK_CPU_FEATURE (AVX512_BF16); + + printf ("Usable CPU features:\n"); +- CHECK_CPU_FEATURE_USABLE (SSE3); +- CHECK_CPU_FEATURE_USABLE (PCLMULQDQ); +- CHECK_CPU_FEATURE_USABLE (SSSE3); + CHECK_CPU_FEATURE_USABLE (FMA); +- CHECK_CPU_FEATURE_USABLE (CMPXCHG16B); +- CHECK_CPU_FEATURE_USABLE (SSE4_1); +- CHECK_CPU_FEATURE_USABLE (SSE4_2); +- CHECK_CPU_FEATURE_USABLE (MOVBE); +- CHECK_CPU_FEATURE_USABLE (POPCNT); +- CHECK_CPU_FEATURE_USABLE (AES); +- CHECK_CPU_FEATURE_USABLE (XSAVE); +- CHECK_CPU_FEATURE_USABLE (OSXSAVE); + CHECK_CPU_FEATURE_USABLE (AVX); + CHECK_CPU_FEATURE_USABLE (F16C); +- CHECK_CPU_FEATURE_USABLE (RDRAND); +- CHECK_CPU_FEATURE_USABLE (FPU); +- CHECK_CPU_FEATURE_USABLE (TSC); +- CHECK_CPU_FEATURE_USABLE (MSR); +- CHECK_CPU_FEATURE_USABLE (CX8); +- CHECK_CPU_FEATURE_USABLE (SEP); +- CHECK_CPU_FEATURE_USABLE (CMOV); +- CHECK_CPU_FEATURE_USABLE (CLFSH); +- CHECK_CPU_FEATURE_USABLE (MMX); +- CHECK_CPU_FEATURE_USABLE (FXSR); +- CHECK_CPU_FEATURE_USABLE (SSE); +- CHECK_CPU_FEATURE_USABLE (SSE2); +- CHECK_CPU_FEATURE_USABLE (FSGSBASE); +- CHECK_CPU_FEATURE_USABLE (BMI1); +- CHECK_CPU_FEATURE_USABLE (HLE); + CHECK_CPU_FEATURE_USABLE (AVX2); +- CHECK_CPU_FEATURE_USABLE (BMI2); +- CHECK_CPU_FEATURE_USABLE (ERMS); + CHECK_CPU_FEATURE_USABLE (AVX512F); + CHECK_CPU_FEATURE_USABLE (AVX512DQ); +- CHECK_CPU_FEATURE_USABLE (RDSEED); +- CHECK_CPU_FEATURE_USABLE (ADX); + CHECK_CPU_FEATURE_USABLE (AVX512_IFMA); +- CHECK_CPU_FEATURE_USABLE (CLFLUSHOPT); +- CHECK_CPU_FEATURE_USABLE (CLWB); + CHECK_CPU_FEATURE_USABLE (AVX512PF); + CHECK_CPU_FEATURE_USABLE (AVX512ER); + CHECK_CPU_FEATURE_USABLE (AVX512CD); +- CHECK_CPU_FEATURE_USABLE (SHA); + CHECK_CPU_FEATURE_USABLE (AVX512BW); + CHECK_CPU_FEATURE_USABLE (AVX512VL); +- CHECK_CPU_FEATURE_USABLE (PREFETCHWT1); + CHECK_CPU_FEATURE_USABLE (AVX512_VBMI); ++ CHECK_CPU_FEATURE_USABLE (PKU); + CHECK_CPU_FEATURE_USABLE (AVX512_VBMI2); +- CHECK_CPU_FEATURE_USABLE (GFNI); + CHECK_CPU_FEATURE_USABLE (VAES); + CHECK_CPU_FEATURE_USABLE (VPCLMULQDQ); + CHECK_CPU_FEATURE_USABLE (AVX512_VNNI); + CHECK_CPU_FEATURE_USABLE (AVX512_BITALG); + CHECK_CPU_FEATURE_USABLE (AVX512_VPOPCNTDQ); +- CHECK_CPU_FEATURE_USABLE (RDPID); +- CHECK_CPU_FEATURE_USABLE (CLDEMOTE); +- CHECK_CPU_FEATURE_USABLE (MOVDIRI); +- CHECK_CPU_FEATURE_USABLE (MOVDIR64B); + CHECK_CPU_FEATURE_USABLE (AVX512_4VNNIW); + CHECK_CPU_FEATURE_USABLE (AVX512_4FMAPS); +- CHECK_CPU_FEATURE_USABLE (FSRM); +- CHECK_CPU_FEATURE_USABLE (LAHF64_SAHF64); +- CHECK_CPU_FEATURE_USABLE (LZCNT); +- CHECK_CPU_FEATURE_USABLE (SSE4A); +- CHECK_CPU_FEATURE_USABLE (PREFETCHW); ++ CHECK_CPU_FEATURE_USABLE (AVX512_VP2INTERSECT); + CHECK_CPU_FEATURE_USABLE (XOP); + CHECK_CPU_FEATURE_USABLE (FMA4); +- CHECK_CPU_FEATURE_USABLE (TBM); +- CHECK_CPU_FEATURE_USABLE (SYSCALL_SYSRET); +- CHECK_CPU_FEATURE_USABLE (RDTSCP); +- CHECK_CPU_FEATURE_USABLE (XSAVEOPT); + CHECK_CPU_FEATURE_USABLE (XSAVEC); +- CHECK_CPU_FEATURE_USABLE (XGETBV_ECX_1); +- CHECK_CPU_FEATURE_USABLE (XSAVES); +- CHECK_CPU_FEATURE_USABLE (INVARIANT_TSC); +- CHECK_CPU_FEATURE_USABLE (WBNOINVD); ++ CHECK_CPU_FEATURE_USABLE (AVX512_BF16); + + return 0; + } diff --git a/SOURCES/glibc-rh1817513-67.patch b/SOURCES/glibc-rh1817513-67.patch new file mode 100644 index 0000000..9e331ec --- /dev/null +++ b/SOURCES/glibc-rh1817513-67.patch @@ -0,0 +1,19 @@ +commit 6f3331f26d2ee5d210ba768389828c391750f7a0 +Author: Florian Weimer +Date: Wed Jun 24 11:02:33 2020 +0200 + + elf: Include in because bool is used + +diff --git a/elf/dl-tunables.h b/elf/dl-tunables.h +index 928b30dde9fa0489..7f181f3316cd9fc1 100644 +--- a/elf/dl-tunables.h ++++ b/elf/dl-tunables.h +@@ -21,6 +21,8 @@ + #ifndef _TUNABLES_H_ + #define _TUNABLES_H_ + ++#include ++ + #if !HAVE_TUNABLES + static inline void + __always_inline diff --git a/SOURCES/glibc-rh1817513-68.patch b/SOURCES/glibc-rh1817513-68.patch new file mode 100644 index 0000000..5ba0d6a --- /dev/null +++ b/SOURCES/glibc-rh1817513-68.patch @@ -0,0 +1,22 @@ +commit 2034c70e64b31e48140c8e31c5ae839af5ccb6eb +Author: Florian Weimer +Date: Thu Jun 25 16:51:03 2020 +0200 + + elf: Include (for size_t), in + + Reviewed-by: Carlos O'Donell + +diff --git a/sysdeps/generic/ldconfig.h b/sysdeps/generic/ldconfig.h +index 59e20dc3ef790125..6774212110d23eae 100644 +--- a/sysdeps/generic/ldconfig.h ++++ b/sysdeps/generic/ldconfig.h +@@ -19,7 +19,9 @@ + #ifndef _LDCONFIG_H + #define _LDCONFIG_H + ++#include + #include ++#include + + #define FLAG_ANY -1 + #define FLAG_TYPE_MASK 0x00ff diff --git a/SOURCES/glibc-rh1817513-69.patch b/SOURCES/glibc-rh1817513-69.patch new file mode 100644 index 0000000..9d668b3 --- /dev/null +++ b/SOURCES/glibc-rh1817513-69.patch @@ -0,0 +1,144 @@ +commit 4fdd4d41a17dda26c854ed935658154a17d4b906 +Author: H.J. Lu +Date: Thu Jun 25 15:12:57 2020 -0700 + + x86: Detect Intel Advanced Matrix Extensions + + Intel Advanced Matrix Extensions (Intel AMX) is a new programming + paradigm consisting of two components: a set of 2-dimensional registers + (tiles) representing sub-arrays from a larger 2-dimensional memory image, + and accelerators able to operate on tiles. Intel AMX is an extensible + architecture. New accelerators can be added and the existing accelerator + may be enhanced to provide higher performance. The initial features are + AMX-BF16, AMX-TILE and AMX-INT8, which are usable only if the operating + system supports both XTILECFG state and XTILEDATA state. + + Add AMX-BF16, AMX-TILE and AMX-INT8 support to HAS_CPU_FEATURE and + CPU_FEATURE_USABLE. + +diff --git a/sysdeps/x86/cpu-features.c b/sysdeps/x86/cpu-features.c +index 7b2a5bc3ed27ec39..21565474839efffc 100644 +--- a/sysdeps/x86/cpu-features.c ++++ b/sysdeps/x86/cpu-features.c +@@ -239,6 +239,24 @@ get_common_indices (struct cpu_features *cpu_features, + } + } + ++ /* Are XTILECFG and XTILEDATA states usable? */ ++ if ((xcrlow & (bit_XTILECFG_state | bit_XTILEDATA_state)) ++ == (bit_XTILECFG_state | bit_XTILEDATA_state)) ++ { ++ /* Determine if AMX_BF16 is usable. */ ++ if (CPU_FEATURES_CPU_P (cpu_features, AMX_BF16)) ++ cpu_features->usable[index_arch_AMX_BF16_Usable] ++ |= bit_arch_AMX_BF16_Usable; ++ /* Determine if AMX_TILE is usable. */ ++ if (CPU_FEATURES_CPU_P (cpu_features, AMX_TILE)) ++ cpu_features->usable[index_arch_AMX_TILE_Usable] ++ |= bit_arch_AMX_TILE_Usable; ++ /* Determine if AMX_INT8 is usable. */ ++ if (CPU_FEATURES_CPU_P (cpu_features, AMX_INT8)) ++ cpu_features->usable[index_arch_AMX_INT8_Usable] ++ |= bit_arch_AMX_INT8_Usable; ++ } ++ + /* For _dl_runtime_resolve, set xsave_state_size to xsave area + size + integer register save size and align it to 64 bytes. */ + if (cpu_features->basic.max_cpuid >= 0xd) +diff --git a/sysdeps/x86/cpu-features.h b/sysdeps/x86/cpu-features.h +index 41c3855e94d16b49..7c46242aad69d427 100644 +--- a/sysdeps/x86/cpu-features.h ++++ b/sysdeps/x86/cpu-features.h +@@ -156,6 +156,9 @@ extern const struct cpu_features *__get_cpu_features (void) + #define bit_arch_AVX512_VP2INTERSECT_Usable (1u << 24) + #define bit_arch_AVX512_BF16_Usable (1u << 25) + #define bit_arch_PKU_Usable (1u << 26) ++#define bit_arch_AMX_BF16_Usable (1u << 27) ++#define bit_arch_AMX_TILE_Usable (1u << 28) ++#define bit_arch_AMX_INT8_Usable (1u << 29) + + #define index_arch_AVX_Usable USABLE_FEATURE_INDEX_1 + #define index_arch_AVX2_Usable USABLE_FEATURE_INDEX_1 +@@ -184,6 +187,9 @@ extern const struct cpu_features *__get_cpu_features (void) + #define index_arch_AVX512_VP2INTERSECT_Usable USABLE_FEATURE_INDEX_1 + #define index_arch_AVX512_BF16_Usable USABLE_FEATURE_INDEX_1 + #define index_arch_PKU_Usable USABLE_FEATURE_INDEX_1 ++#define index_arch_AMX_BF16_Usable USABLE_FEATURE_INDEX_1 ++#define index_arch_AMX_TILE_Usable USABLE_FEATURE_INDEX_1 ++#define index_arch_AMX_INT8_Usable USABLE_FEATURE_INDEX_1 + + #define feature_AVX_Usable usable + #define feature_AVX2_Usable usable +@@ -212,6 +218,9 @@ extern const struct cpu_features *__get_cpu_features (void) + #define feature_AVX512_VP2INTERSECT_Usable usable + #define feature_AVX512_BF16_Usable usable + #define feature_PKU_Usable usable ++#define feature_AMX_BF16_Usable usable ++#define feature_AMX_TILE_Usable usable ++#define feature_AMX_INT8_Usable usable + + /* CPU features. */ + +@@ -347,6 +356,9 @@ extern const struct cpu_features *__get_cpu_features (void) + #define bit_cpu_TSXLDTRK (1u << 16) + #define bit_cpu_PCONFIG (1u << 18) + #define bit_cpu_IBT (1u << 20) ++#define bit_cpu_AMX_BF16 (1u << 22) ++#define bit_cpu_AMX_TILE (1u << 24) ++#define bit_cpu_AMX_INT8 (1u << 25) + #define bit_cpu_IBRS_IBPB (1u << 26) + #define bit_cpu_STIBP (1u << 27) + #define bit_cpu_L1D_FLUSH (1u << 28) +@@ -529,6 +541,9 @@ extern const struct cpu_features *__get_cpu_features (void) + #define index_cpu_TSXLDTRK COMMON_CPUID_INDEX_7 + #define index_cpu_PCONFIG COMMON_CPUID_INDEX_7 + #define index_cpu_IBT COMMON_CPUID_INDEX_7 ++#define index_cpu_AMX_BF16 COMMON_CPUID_INDEX_7 ++#define index_cpu_AMX_TILE COMMON_CPUID_INDEX_7 ++#define index_cpu_AMX_INT8 COMMON_CPUID_INDEX_7 + #define index_cpu_IBRS_IBPB COMMON_CPUID_INDEX_7 + #define index_cpu_STIBP COMMON_CPUID_INDEX_7 + #define index_cpu_L1D_FLUSH COMMON_CPUID_INDEX_7 +@@ -711,6 +726,9 @@ extern const struct cpu_features *__get_cpu_features (void) + #define reg_TSXLDTRK edx + #define reg_PCONFIG edx + #define reg_IBT edx ++#define reg_AMX_BF16 edx ++#define reg_AMX_TILE edx ++#define reg_AMX_INT8 edx + #define reg_IBRS_IBPB edx + #define reg_STIBP edx + #define reg_L1D_FLUSH edx +@@ -819,6 +837,8 @@ extern const struct cpu_features *__get_cpu_features (void) + #define bit_Opmask_state (1u << 5) + #define bit_ZMM0_15_state (1u << 6) + #define bit_ZMM16_31_state (1u << 7) ++#define bit_XTILECFG_state (1u << 17) ++#define bit_XTILEDATA_state (1u << 18) + + # if defined (_LIBC) && !IS_IN (nonlib) + /* Unused for x86. */ +diff --git a/sysdeps/x86/tst-get-cpu-features.c b/sysdeps/x86/tst-get-cpu-features.c +index 08688ace2a0ae35e..c4d91be3a48de886 100644 +--- a/sysdeps/x86/tst-get-cpu-features.c ++++ b/sysdeps/x86/tst-get-cpu-features.c +@@ -185,6 +185,9 @@ do_test (void) + CHECK_CPU_FEATURE (TSXLDTRK); + CHECK_CPU_FEATURE (PCONFIG); + CHECK_CPU_FEATURE (IBT); ++ CHECK_CPU_FEATURE (AMX_BF16); ++ CHECK_CPU_FEATURE (AMX_TILE); ++ CHECK_CPU_FEATURE (AMX_INT8); + CHECK_CPU_FEATURE (IBRS_IBPB); + CHECK_CPU_FEATURE (STIBP); + CHECK_CPU_FEATURE (L1D_FLUSH); +@@ -237,6 +240,9 @@ do_test (void) + CHECK_CPU_FEATURE_USABLE (AVX512_4VNNIW); + CHECK_CPU_FEATURE_USABLE (AVX512_4FMAPS); + CHECK_CPU_FEATURE_USABLE (AVX512_VP2INTERSECT); ++ CHECK_CPU_FEATURE_USABLE (AMX_BF16); ++ CHECK_CPU_FEATURE_USABLE (AMX_TILE); ++ CHECK_CPU_FEATURE_USABLE (AMX_INT8); + CHECK_CPU_FEATURE_USABLE (XOP); + CHECK_CPU_FEATURE_USABLE (FMA4); + CHECK_CPU_FEATURE_USABLE (XSAVEC); diff --git a/SOURCES/glibc-rh1817513-7.patch b/SOURCES/glibc-rh1817513-7.patch new file mode 100644 index 0000000..57228a8 --- /dev/null +++ b/SOURCES/glibc-rh1817513-7.patch @@ -0,0 +1,54 @@ +commit 221e4babca17b363df2c56e839572e9f7ab7d127 +Author: Joseph Myers +Date: Wed Sep 12 20:31:24 2018 +0000 + + Include most of elf/ modules-names in modules-names-tests. + + I'm testing a patch to let the compiler expand calls to floor in libm + as built-in function calls as much as possible, instead of calling + __floor, so that no architecture-specific __floor inlines are needed, + and then to arrange for non-inlined calls to end up calling __floor, + as done with sqrt and __ieee754_sqrt. + + This shows up elf/tst-relsort1mod2.c calling floor, which must not be + converted to a call to __floor. Now, while an IS_IN (libm) + conditional could be added to the existing conditionals on such + redirections in include/math.h, the _ISOMAC conditional ought to + suffice (code in other glibc libraries shouldn't be calling floor or + sqrt anyway, as they aren't provided in libc and the other libraries + don't link with libm). But while tests are mostly now built with + _ISOMAC defined, test modules in modules-names aren't unless also + listed in modules-names-tests. + + As far as I can see, all the modules in modules-names in elf/ are in + fact parts of tests and so listing them in modules-names-tests is + appropriate, so they get built with something closer to the headers + used for user code, except in a few cases that actually rely on + something from internal headers. This patch duly sets + modules-names-tests there accordingly (filtering out those tests that + fail to build without internal headers). + + Tested for x86_64, and with build-many-glibcs.py. + + * elf/Makefile (modules-names-tests): New variable. + +Conflicts: + elf/Makefile + (Different backport order for tests.) + +diff --git a/elf/Makefile b/elf/Makefile +index b4b618ce62a9e6df..89dff92adfc417f5 100644 +--- a/elf/Makefile ++++ b/elf/Makefile +@@ -306,6 +306,11 @@ modules-names = testobj1 testobj2 testobj3 testobj4 testobj5 testobj6 \ + tst-dlopenfailmod3 \ + tst-filterobj-flt tst-filterobj-aux tst-filterobj-filtee + ++# Most modules build with _ISOMAC defined, but those filtered out ++# depend on internal headers. ++modules-names-tests = $(filter-out ifuncmod% tst-libc_dlvsym-dso tst-tlsmod%,\ ++ $(modules-names)) ++ + ifeq (yes,$(have-mtls-dialect-gnu2)) + tests += tst-gnu2-tls1 + modules-names += tst-gnu2-tls1mod diff --git a/SOURCES/glibc-rh1817513-70.patch b/SOURCES/glibc-rh1817513-70.patch new file mode 100644 index 0000000..8960178 --- /dev/null +++ b/SOURCES/glibc-rh1817513-70.patch @@ -0,0 +1,21 @@ +commit f8b4630ef673486c2c77bd291a08ef132981e149 +Author: H.J. Lu +Date: Mon Jul 6 06:38:05 2020 -0700 + + x86: Correct bit_cpu_CLFSH [BZ #26208] + + bit_cpu_CLFSH should be (1u << 19), not (1u << 20). + +diff --git a/sysdeps/x86/cpu-features.h b/sysdeps/x86/cpu-features.h +index 7c46242aad69d427..535b3cb2d25b245b 100644 +--- a/sysdeps/x86/cpu-features.h ++++ b/sysdeps/x86/cpu-features.h +@@ -277,7 +277,7 @@ extern const struct cpu_features *__get_cpu_features (void) + #define bit_cpu_PAT (1u << 16) + #define bit_cpu_PSE_36 (1u << 17) + #define bit_cpu_PSN (1u << 18) +-#define bit_cpu_CLFSH (1u << 20) ++#define bit_cpu_CLFSH (1u << 19) + #define bit_cpu_DS (1u << 21) + #define bit_cpu_ACPI (1u << 22) + #define bit_cpu_MMX (1u << 23) diff --git a/SOURCES/glibc-rh1817513-71.patch b/SOURCES/glibc-rh1817513-71.patch new file mode 100644 index 0000000..1a5fcdd --- /dev/null +++ b/SOURCES/glibc-rh1817513-71.patch @@ -0,0 +1,51 @@ +commit 28c13ae5bbc81aa2ae67890ce53e65257d4703a4 +Author: H.J. Lu +Date: Mon Jul 6 06:57:08 2020 -0700 + + x86: Detect Extended Feature Disable (XFD) + + An extension called extended feature disable (XFD) is an extension added + for Intel AMX to the XSAVE feature set that allows an operating system + to enable a feature while preventing specific user threads from using + the feature. + +diff --git a/sysdeps/x86/cpu-features.h b/sysdeps/x86/cpu-features.h +index 535b3cb2d25b245b..e7ea9e8ece3e8211 100644 +--- a/sysdeps/x86/cpu-features.h ++++ b/sysdeps/x86/cpu-features.h +@@ -393,6 +393,7 @@ extern const struct cpu_features *__get_cpu_features (void) + #define bit_cpu_XSAVEC (1u << 1) + #define bit_cpu_XGETBV_ECX_1 (1u << 2) + #define bit_cpu_XSAVES (1u << 3) ++#define bit_cpu_XFD (1u << 4) + + /* COMMON_CPUID_INDEX_80000007. */ + +@@ -578,6 +579,7 @@ extern const struct cpu_features *__get_cpu_features (void) + #define index_cpu_XSAVEC COMMON_CPUID_INDEX_D_ECX_1 + #define index_cpu_XGETBV_ECX_1 COMMON_CPUID_INDEX_D_ECX_1 + #define index_cpu_XSAVES COMMON_CPUID_INDEX_D_ECX_1 ++#define index_cpu_XFD COMMON_CPUID_INDEX_D_ECX_1 + + /* COMMON_CPUID_INDEX_80000007. */ + +@@ -763,6 +765,7 @@ extern const struct cpu_features *__get_cpu_features (void) + #define reg_XSAVEC eax + #define reg_XGETBV_ECX_1 eax + #define reg_XSAVES eax ++#define reg_XFD eax + + /* COMMON_CPUID_INDEX_80000007. */ + +diff --git a/sysdeps/x86/tst-get-cpu-features.c b/sysdeps/x86/tst-get-cpu-features.c +index c4d91be3a48de886..c56f309ba0736c0d 100644 +--- a/sysdeps/x86/tst-get-cpu-features.c ++++ b/sysdeps/x86/tst-get-cpu-features.c +@@ -212,6 +212,7 @@ do_test (void) + CHECK_CPU_FEATURE (XSAVEC); + CHECK_CPU_FEATURE (XGETBV_ECX_1); + CHECK_CPU_FEATURE (XSAVES); ++ CHECK_CPU_FEATURE (XFD); + CHECK_CPU_FEATURE (INVARIANT_TSC); + CHECK_CPU_FEATURE (WBNOINVD); + CHECK_CPU_FEATURE (AVX512_BF16); diff --git a/SOURCES/glibc-rh1817513-72.patch b/SOURCES/glibc-rh1817513-72.patch new file mode 100644 index 0000000..fde1130 --- /dev/null +++ b/SOURCES/glibc-rh1817513-72.patch @@ -0,0 +1,235 @@ +commit 3f4b61a0b8de67ef9f20737919c713ddfc4bd620 +Author: H.J. Lu +Date: Mon Jul 6 11:48:09 2020 -0700 + + x86: Add thresholds for "rep movsb/stosb" to tunables + + Add x86_rep_movsb_threshold and x86_rep_stosb_threshold to tunables + to update thresholds for "rep movsb" and "rep stosb" at run-time. + + Note that the user specified threshold for "rep movsb" smaller than + the minimum threshold will be ignored. + + Reviewed-by: Carlos O'Donell + +Conflicts: + sysdeps/x86/cacheinfo.c + (Previous backport of the shared cache computation fix.) + +diff --git a/manual/tunables.texi b/manual/tunables.texi +index ef10d2872cfc244e..55d5dfb14db4dfb8 100644 +--- a/manual/tunables.texi ++++ b/manual/tunables.texi +@@ -373,6 +373,22 @@ like memmove and memcpy. + This tunable is specific to i386 and x86-64. + @end deftp + ++@deftp Tunable glibc.cpu.x86_rep_movsb_threshold ++The @code{glibc.cpu.x86_rep_movsb_threshold} tunable allows the user to ++set threshold in bytes to start using "rep movsb". The value must be ++greater than zero, and currently defaults to 2048 bytes. ++ ++This tunable is specific to i386 and x86-64. ++@end deftp ++ ++@deftp Tunable glibc.cpu.x86_rep_stosb_threshold ++The @code{glibc.cpu.x86_rep_stosb_threshold} tunable allows the user to ++set threshold in bytes to start using "rep stosb". The value must be ++greater than zero, and currently defaults to 2048 bytes. ++ ++This tunable is specific to i386 and x86-64. ++@end deftp ++ + @deftp Tunable glibc.cpu.x86_ibt + The @code{glibc.cpu.x86_ibt} tunable allows the user to control how + indirect branch tracking (IBT) should be enabled. Accepted values are +diff --git a/sysdeps/x86/cacheinfo.c b/sysdeps/x86/cacheinfo.c +index aa7cb705d546bcd0..c741a69fb19a1e95 100644 +--- a/sysdeps/x86/cacheinfo.c ++++ b/sysdeps/x86/cacheinfo.c +@@ -530,6 +530,12 @@ long int __x86_raw_shared_cache_size attribute_hidden = 1024 * 1024; + /* Threshold to use non temporal store. */ + long int __x86_shared_non_temporal_threshold attribute_hidden; + ++/* Threshold to use Enhanced REP MOVSB. */ ++long int __x86_rep_movsb_threshold attribute_hidden = 2048; ++ ++/* Threshold to use Enhanced REP STOSB. */ ++long int __x86_rep_stosb_threshold attribute_hidden = 2048; ++ + #ifndef DISABLE_PREFETCHW + /* PREFETCHW support flag for use in memory and string routines. */ + int __x86_prefetchw attribute_hidden; +@@ -892,6 +898,36 @@ init_cacheinfo (void) + = (cpu_features->non_temporal_threshold != 0 + ? cpu_features->non_temporal_threshold + : __x86_shared_cache_size * 3 / 4); ++ ++ /* NB: The REP MOVSB threshold must be greater than VEC_SIZE * 8. */ ++ unsigned int minimum_rep_movsb_threshold; ++ /* NB: The default REP MOVSB threshold is 2048 * (VEC_SIZE / 16). */ ++ unsigned int rep_movsb_threshold; ++ if (CPU_FEATURES_ARCH_P (cpu_features, AVX512F_Usable) ++ && !CPU_FEATURES_ARCH_P (cpu_features, Prefer_No_AVX512)) ++ { ++ rep_movsb_threshold = 2048 * (64 / 16); ++ minimum_rep_movsb_threshold = 64 * 8; ++ } ++ else if (CPU_FEATURES_ARCH_P (cpu_features, ++ AVX_Fast_Unaligned_Load)) ++ { ++ rep_movsb_threshold = 2048 * (32 / 16); ++ minimum_rep_movsb_threshold = 32 * 8; ++ } ++ else ++ { ++ rep_movsb_threshold = 2048 * (16 / 16); ++ minimum_rep_movsb_threshold = 16 * 8; ++ } ++ if (cpu_features->rep_movsb_threshold > minimum_rep_movsb_threshold) ++ __x86_rep_movsb_threshold = cpu_features->rep_movsb_threshold; ++ else ++ __x86_rep_movsb_threshold = rep_movsb_threshold; ++ ++# if HAVE_TUNABLES ++ __x86_rep_stosb_threshold = cpu_features->rep_stosb_threshold; ++# endif + } + + #endif +diff --git a/sysdeps/x86/cpu-features.c b/sysdeps/x86/cpu-features.c +index 21565474839efffc..ad470f79ef7769fc 100644 +--- a/sysdeps/x86/cpu-features.c ++++ b/sysdeps/x86/cpu-features.c +@@ -605,6 +605,10 @@ no_cpuid: + TUNABLE_GET (hwcaps, tunable_val_t *, TUNABLE_CALLBACK (set_hwcaps)); + cpu_features->non_temporal_threshold + = TUNABLE_GET (x86_non_temporal_threshold, long int, NULL); ++ cpu_features->rep_movsb_threshold ++ = TUNABLE_GET (x86_rep_movsb_threshold, long int, NULL); ++ cpu_features->rep_stosb_threshold ++ = TUNABLE_GET (x86_rep_stosb_threshold, long int, NULL); + cpu_features->data_cache_size + = TUNABLE_GET (x86_data_cache_size, long int, NULL); + cpu_features->shared_cache_size +diff --git a/sysdeps/x86/cpu-features.h b/sysdeps/x86/cpu-features.h +index e7ea9e8ece3e8211..0f19c64352c4d7f1 100644 +--- a/sysdeps/x86/cpu-features.h ++++ b/sysdeps/x86/cpu-features.h +@@ -102,6 +102,10 @@ struct cpu_features + unsigned long int shared_cache_size; + /* Threshold to use non temporal store. */ + unsigned long int non_temporal_threshold; ++ /* Threshold to use "rep movsb". */ ++ unsigned long int rep_movsb_threshold; ++ /* Threshold to use "rep stosb". */ ++ unsigned long int rep_stosb_threshold; + }; + + /* Used from outside of glibc to get access to the CPU features +diff --git a/sysdeps/x86/dl-tunables.list b/sysdeps/x86/dl-tunables.list +index 2a457d0eec9c3122..e066313a1d1dd009 100644 +--- a/sysdeps/x86/dl-tunables.list ++++ b/sysdeps/x86/dl-tunables.list +@@ -30,6 +30,30 @@ glibc { + x86_non_temporal_threshold { + type: SIZE_T + } ++ x86_rep_movsb_threshold { ++ type: SIZE_T ++ # Since there is overhead to set up REP MOVSB operation, REP MOVSB ++ # isn't faster on short data. The memcpy micro benchmark in glibc ++ # shows that 2KB is the approximate value above which REP MOVSB ++ # becomes faster than SSE2 optimization on processors with Enhanced ++ # REP MOVSB. Since larger register size can move more data with a ++ # single load and store, the threshold is higher with larger register ++ # size. Note: Since the REP MOVSB threshold must be greater than 8 ++ # times of vector size, the minium value must be updated at run-time. ++ minval: 1 ++ default: 2048 ++ } ++ x86_rep_stosb_threshold { ++ type: SIZE_T ++ # Since there is overhead to set up REP STOSB operation, REP STOSB ++ # isn't faster on short data. The memset micro benchmark in glibc ++ # shows that 2KB is the approximate value above which REP STOSB ++ # becomes faster on processors with Enhanced REP STOSB. Since the ++ # stored value is fixed, larger register size has minimal impact ++ # on threshold. ++ minval: 1 ++ default: 2048 ++ } + x86_data_cache_size { + type: SIZE_T + } +diff --git a/sysdeps/x86_64/multiarch/memmove-vec-unaligned-erms.S b/sysdeps/x86_64/multiarch/memmove-vec-unaligned-erms.S +index e2ede45e9f68791b..c952576cfdf6e3e6 100644 +--- a/sysdeps/x86_64/multiarch/memmove-vec-unaligned-erms.S ++++ b/sysdeps/x86_64/multiarch/memmove-vec-unaligned-erms.S +@@ -56,17 +56,6 @@ + # endif + #endif + +-/* Threshold to use Enhanced REP MOVSB. Since there is overhead to set +- up REP MOVSB operation, REP MOVSB isn't faster on short data. The +- memcpy micro benchmark in glibc shows that 2KB is the approximate +- value above which REP MOVSB becomes faster than SSE2 optimization +- on processors with Enhanced REP MOVSB. Since larger register size +- can move more data with a single load and store, the threshold is +- higher with larger register size. */ +-#ifndef REP_MOVSB_THRESHOLD +-# define REP_MOVSB_THRESHOLD (2048 * (VEC_SIZE / 16)) +-#endif +- + #ifndef PREFETCH + # define PREFETCH(addr) prefetcht0 addr + #endif +@@ -245,9 +234,6 @@ L(movsb): + leaq (%rsi,%rdx), %r9 + cmpq %r9, %rdi + /* Avoid slow backward REP MOVSB. */ +-# if REP_MOVSB_THRESHOLD <= (VEC_SIZE * 8) +-# error Unsupported REP_MOVSB_THRESHOLD and VEC_SIZE! +-# endif + jb L(more_8x_vec_backward) + 1: + movq %rdx, %rcx +@@ -323,7 +309,7 @@ L(between_2_3): + + #if defined USE_MULTIARCH && IS_IN (libc) + L(movsb_more_2x_vec): +- cmpq $REP_MOVSB_THRESHOLD, %rdx ++ cmp __x86_rep_movsb_threshold(%rip), %RDX_LP + ja L(movsb) + #endif + L(more_2x_vec): +diff --git a/sysdeps/x86_64/multiarch/memset-vec-unaligned-erms.S b/sysdeps/x86_64/multiarch/memset-vec-unaligned-erms.S +index dc9cb88b37a5477a..270a1d49b34be9f5 100644 +--- a/sysdeps/x86_64/multiarch/memset-vec-unaligned-erms.S ++++ b/sysdeps/x86_64/multiarch/memset-vec-unaligned-erms.S +@@ -58,16 +58,6 @@ + # endif + #endif + +-/* Threshold to use Enhanced REP STOSB. Since there is overhead to set +- up REP STOSB operation, REP STOSB isn't faster on short data. The +- memset micro benchmark in glibc shows that 2KB is the approximate +- value above which REP STOSB becomes faster on processors with +- Enhanced REP STOSB. Since the stored value is fixed, larger register +- size has minimal impact on threshold. */ +-#ifndef REP_STOSB_THRESHOLD +-# define REP_STOSB_THRESHOLD 2048 +-#endif +- + #ifndef SECTION + # error SECTION is not defined! + #endif +@@ -173,7 +163,7 @@ ENTRY (MEMSET_SYMBOL (__memset, unaligned_erms)) + ret + + L(stosb_more_2x_vec): +- cmpq $REP_STOSB_THRESHOLD, %rdx ++ cmp __x86_rep_stosb_threshold(%rip), %RDX_LP + ja L(stosb) + #endif + L(more_2x_vec): diff --git a/SOURCES/glibc-rh1817513-73.patch b/SOURCES/glibc-rh1817513-73.patch new file mode 100644 index 0000000..adb3c93 --- /dev/null +++ b/SOURCES/glibc-rh1817513-73.patch @@ -0,0 +1,289 @@ +commit 0c7b002fac12dcb2f53ba83ee56bb3b5d2439447 +Author: Szabolcs Nagy +Date: Tue Jun 9 09:57:28 2020 +0100 + + rtld: Add rtld.nns tunable for the number of supported namespaces + + TLS_STATIC_SURPLUS is 1664 bytes currently which is not enough to + support DL_NNS (== 16) number of dynamic link namespaces, if we + assume 192 bytes of TLS are reserved for libc use and 144 bytes + are reserved for other system libraries that use IE TLS. + + A new tunable is introduced to control the number of supported + namespaces and to adjust the surplus static TLS size as follows: + + surplus_tls = 192 * (rtld.nns-1) + 144 * rtld.nns + 512 + + The default is rtld.nns == 4 and then the surplus TLS size is the + same as before, so the behaviour is unchanged by default. If an + application creates more namespaces than the rtld.nns setting + allows, then it is not guaranteed to work, but the limit is not + checked. So existing usage will continue to work, but in the + future if an application creates more than 4 dynamic link + namespaces then the tunable will need to be set. + + In this patch DL_NNS is a fixed value and provides a maximum to + the rtld.nns setting. + + Static linking used fixed 2048 bytes surplus TLS, this is changed + so the same contract is used as for dynamic linking. With static + linking DL_NNS == 1 so rtld.nns tunable is forced to 1, so by + default the surplus TLS is reduced to 144 + 512 = 656 bytes. This + change is not expected to cause problems. + + Tested on aarch64-linux-gnu and x86_64-linux-gnu. + + Reviewed-by: Carlos O'Donell + +Conflicts: + elf/dl-tls.c + (Different per-namespace TLS reservation defaults before + this backport.) + +diff --git a/csu/libc-tls.c b/csu/libc-tls.c +index 28a79441cde379f7..08ed2b988b58ac6c 100644 +--- a/csu/libc-tls.c ++++ b/csu/libc-tls.c +@@ -52,13 +52,16 @@ bool _dl_tls_dtv_gaps; + struct dtv_slotinfo_list *_dl_tls_dtv_slotinfo_list; + /* Number of modules in the static TLS block. */ + size_t _dl_tls_static_nelem; +-/* Size of the static TLS block. Giving this initialized value +- preallocates some surplus bytes in the static TLS area. */ +-size_t _dl_tls_static_size = 2048; ++/* Size of the static TLS block. */ ++size_t _dl_tls_static_size; + /* Size actually allocated in the static TLS block. */ + size_t _dl_tls_static_used; + /* Alignment requirement of the static TLS block. */ + size_t _dl_tls_static_align; ++/* Size of surplus space in the static TLS area for dynamically ++ loaded modules with IE-model TLS or for TLSDESC optimization. ++ See comments in elf/dl-tls.c where it is initialized. */ ++size_t _dl_tls_static_surplus; + + /* Generation counter for the dtv. */ + size_t _dl_tls_generation; +@@ -87,10 +90,8 @@ init_slotinfo (void) + static void + init_static_tls (size_t memsz, size_t align) + { +- /* That is the size of the TLS memory for this object. The initialized +- value of _dl_tls_static_size is provided by dl-open.c to request some +- surplus that permits dynamic loading of modules with IE-model TLS. */ +- GL(dl_tls_static_size) = roundup (memsz + GL(dl_tls_static_size), ++ /* That is the size of the TLS memory for this object. */ ++ GL(dl_tls_static_size) = roundup (memsz + GLRO(dl_tls_static_surplus), + TLS_TCB_ALIGN); + #if TLS_TCB_AT_TP + GL(dl_tls_static_size) += TLS_TCB_SIZE; +@@ -131,25 +132,24 @@ __libc_setup_tls (void) + break; + } + ++ /* Calculate the size of the static TLS surplus. */ ++ _dl_tls_static_surplus_init (); ++ + /* We have to set up the TCB block which also (possibly) contains + 'errno'. Therefore we avoid 'malloc' which might touch 'errno'. + Instead we use 'sbrk' which would only uses 'errno' if it fails. + In this case we are right away out of memory and the user gets +- what she/he deserves. +- +- The initialized value of _dl_tls_static_size is provided by dl-open.c +- to request some surplus that permits dynamic loading of modules with +- IE-model TLS. */ ++ what she/he deserves. */ + #if TLS_TCB_AT_TP + /* Align the TCB offset to the maximum alignment, as + _dl_allocate_tls_storage (in elf/dl-tls.c) does using __libc_memalign + and dl_tls_static_align. */ +- tcb_offset = roundup (memsz + GL(dl_tls_static_size), max_align); ++ tcb_offset = roundup (memsz + GLRO(dl_tls_static_surplus), max_align); + tlsblock = __sbrk (tcb_offset + TLS_INIT_TCB_SIZE + max_align); + #elif TLS_DTV_AT_TP + tcb_offset = roundup (TLS_INIT_TCB_SIZE, align ?: 1); + tlsblock = __sbrk (tcb_offset + memsz + max_align +- + TLS_PRE_TCB_SIZE + GL(dl_tls_static_size)); ++ + TLS_PRE_TCB_SIZE + GLRO(dl_tls_static_surplus)); + tlsblock += TLS_PRE_TCB_SIZE; + #else + /* In case a model with a different layout for the TCB and DTV +diff --git a/elf/dl-tls.c b/elf/dl-tls.c +index a2def280b7096960..ef57a21391bb36fa 100644 +--- a/elf/dl-tls.c ++++ b/elf/dl-tls.c +@@ -29,10 +29,54 @@ + #include + #include + +-/* Amount of excess space to allocate in the static TLS area +- to allow dynamic loading of modules defining IE-model TLS data. */ +-#define TLS_STATIC_SURPLUS 64 + DL_NNS * 100 ++#define TUNABLE_NAMESPACE rtld ++#include ++ ++/* Surplus static TLS, GLRO(dl_tls_static_surplus), is used for ++ ++ - IE TLS in libc.so for all dlmopen namespaces except in the initial ++ one where libc.so is not loaded dynamically but at startup time, ++ - IE TLS in other libraries which may be dynamically loaded even in the ++ initial namespace, ++ - and optionally for optimizing dynamic TLS access. ++ ++ The maximum number of namespaces is DL_NNS, but to support that many ++ namespaces correctly the static TLS allocation should be significantly ++ increased, which may cause problems with small thread stacks due to the ++ way static TLS is accounted (bug 11787). ++ ++ So there is a rtld.nns tunable limit on the number of supported namespaces ++ that affects the size of the static TLS and by default it's small enough ++ not to cause problems with existing applications. The limit is not ++ enforced or checked: it is the user's responsibility to increase rtld.nns ++ if more dlmopen namespaces are used. */ ++ ++/* Size of initial-exec TLS in libc.so. */ ++#define LIBC_IE_TLS 192 ++/* Size of initial-exec TLS in libraries other than libc.so. ++ This should be large enough to cover runtime libraries of the ++ compiler such as libgomp and libraries in libc other than libc.so. */ ++#define OTHER_IE_TLS 144 ++/* Size of additional surplus TLS, placeholder for TLS optimizations. */ ++#define OPT_SURPLUS_TLS 512 + ++void ++_dl_tls_static_surplus_init (void) ++{ ++ size_t nns; ++ ++#if HAVE_TUNABLES ++ nns = TUNABLE_GET (nns, size_t, NULL); ++#else ++ /* Default values of the tunables. */ ++ nns = 4; ++#endif ++ if (nns > DL_NNS) ++ nns = DL_NNS; ++ GLRO(dl_tls_static_surplus) = ((nns - 1) * LIBC_IE_TLS ++ + nns * OTHER_IE_TLS ++ + OPT_SURPLUS_TLS); ++} + + /* Out-of-memory handler. */ + static void +@@ -218,7 +262,8 @@ _dl_determine_tlsoffset (void) + } + + GL(dl_tls_static_used) = offset; +- GL(dl_tls_static_size) = (roundup (offset + TLS_STATIC_SURPLUS, max_align) ++ GL(dl_tls_static_size) = (roundup (offset + GLRO(dl_tls_static_surplus), ++ max_align) + + TLS_TCB_SIZE); + #elif TLS_DTV_AT_TP + /* The TLS blocks start right after the TCB. */ +@@ -262,7 +307,7 @@ _dl_determine_tlsoffset (void) + } + + GL(dl_tls_static_used) = offset; +- GL(dl_tls_static_size) = roundup (offset + TLS_STATIC_SURPLUS, ++ GL(dl_tls_static_size) = roundup (offset + GLRO(dl_tls_static_surplus), + TLS_TCB_ALIGN); + #else + # error "Either TLS_TCB_AT_TP or TLS_DTV_AT_TP must be defined" +diff --git a/elf/dl-tunables.list b/elf/dl-tunables.list +index b7cc79f8bfe0a7c6..7337fb85062c91a7 100644 +--- a/elf/dl-tunables.list ++++ b/elf/dl-tunables.list +@@ -126,4 +126,13 @@ glibc { + default: 3 + } + } ++ ++ rtld { ++ nns { ++ type: SIZE_T ++ minval: 1 ++ maxval: 16 ++ default: 4 ++ } ++ } + } +diff --git a/elf/rtld.c b/elf/rtld.c +index 772aff5160359b7b..a440741f4c1b3c91 100644 +--- a/elf/rtld.c ++++ b/elf/rtld.c +@@ -776,6 +776,9 @@ init_tls (void) + } + assert (i == GL(dl_tls_max_dtv_idx)); + ++ /* Calculate the size of the static TLS surplus. */ ++ _dl_tls_static_surplus_init (); ++ + /* Compute the TLS offsets for the various blocks. */ + _dl_determine_tlsoffset (); + +diff --git a/manual/tunables.texi b/manual/tunables.texi +index 55d5dfb14db4dfb8..e092b8e81a18d739 100644 +--- a/manual/tunables.texi ++++ b/manual/tunables.texi +@@ -31,6 +31,7 @@ their own namespace. + @menu + * Tunable names:: The structure of a tunable name + * Memory Allocation Tunables:: Tunables in the memory allocation subsystem ++* Dynamic Linking Tunables:: Tunables in the dynamic linking subsystem + * Elision Tunables:: Tunables in elision subsystem + * Hardware Capability Tunables:: Tunables that modify the hardware + capabilities seen by @theglibc{} +@@ -225,6 +226,26 @@ pointer, so add 4 on 32-bit systems or 8 on 64-bit systems to the size + passed to @code{malloc} for the largest bin size to enable. + @end deftp + ++@node Dynamic Linking Tunables ++@section Dynamic Linking Tunables ++@cindex dynamic linking tunables ++@cindex rtld tunables ++ ++@deftp {Tunable namespace} glibc.rtld ++Dynamic linker behavior can be modified by setting the ++following tunables in the @code{rtld} namespace: ++@end deftp ++ ++@deftp Tunable glibc.rtld.nns ++Sets the number of supported dynamic link namespaces (see @code{dlmopen}). ++Currently this limit can be set between 1 and 16 inclusive, the default is 4. ++Each link namespace consumes some memory in all thread, and thus raising the ++limit will increase the amount of memory each thread uses. Raising the limit ++is useful when your application uses more than 4 dynamic linker audit modules ++e.g. @env{LD_AUDIT}, or will use more than 4 dynamic link namespaces as created ++by @code{dlmopen} with an lmid argument of @code{LM_ID_NEWLM}. ++@end deftp ++ + @node Elision Tunables + @section Elision Tunables + @cindex elision tunables +diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h +index ccec08929e4ad4e7..e54105848c3cb7d1 100644 +--- a/sysdeps/generic/ldsodefs.h ++++ b/sysdeps/generic/ldsodefs.h +@@ -582,6 +582,11 @@ struct rtld_global_ro + binaries, don't honor for PIEs). */ + EXTERN ElfW(Addr) _dl_use_load_bias; + ++ /* Size of surplus space in the static TLS area for dynamically ++ loaded modules with IE-model TLS or for TLSDESC optimization. ++ See comments in elf/dl-tls.c where it is initialized. */ ++ EXTERN size_t _dl_tls_static_surplus; ++ + /* Name of the shared object to be profiled (if any). */ + EXTERN const char *_dl_profile; + /* Filename of the output file. */ +@@ -1099,6 +1104,9 @@ extern size_t _dl_count_modids (void) attribute_hidden; + /* Calculate offset of the TLS blocks in the static TLS block. */ + extern void _dl_determine_tlsoffset (void) attribute_hidden; + ++/* Calculate the size of the static TLS surplus. */ ++void _dl_tls_static_surplus_init (void) attribute_hidden; ++ + #ifndef SHARED + /* Set up the TCB for statically linked applications. This is called + early during startup because we always use TLS (for errno and the diff --git a/SOURCES/glibc-rh1817513-74.patch b/SOURCES/glibc-rh1817513-74.patch new file mode 100644 index 0000000..8281192 --- /dev/null +++ b/SOURCES/glibc-rh1817513-74.patch @@ -0,0 +1,205 @@ +commit 17796419b5fd694348cceb65c3f77601faae082c +Author: Szabolcs Nagy +Date: Tue Jul 7 10:49:11 2020 +0100 + + rtld: Account static TLS surplus for audit modules + + The new static TLS surplus size computation is + + surplus_tls = 192 * (nns-1) + 144 * nns + 512 + + where nns is controlled via the rtld.nns tunable. This commit + accounts audit modules too so nns = rtld.nns + audit modules. + + rtld.nns should only include the namespaces required by the + application, namespaces for audit modules are accounted on top + of that so audit modules don't use up the static TLS that is + reserved for the application. This allows loading many audit + modules without tuning rtld.nns or using up static TLS, and it + fixes + + FAIL: elf/tst-auditmany + + Note that DL_NNS is currently a hard upper limit for nns, and + if rtld.nns + audit modules go over the limit that's a fatal + error. By default rtld.nns is 4 which allows 12 audit modules. + + Counting the audit modules is based on existing audit string + parsing code, we cannot use GLRO(dl_naudit) before the modules + are actually loaded. + +Conflicts: + elf/rtld.c + (Caused by glibc-fedora-__libc_multiple_libcs.patch.) + +diff --git a/csu/libc-tls.c b/csu/libc-tls.c +index 08ed2b988b58ac6c..6f2a47dc86222407 100644 +--- a/csu/libc-tls.c ++++ b/csu/libc-tls.c +@@ -132,8 +132,8 @@ __libc_setup_tls (void) + break; + } + +- /* Calculate the size of the static TLS surplus. */ +- _dl_tls_static_surplus_init (); ++ /* Calculate the size of the static TLS surplus, with 0 auditors. */ ++ _dl_tls_static_surplus_init (0); + + /* We have to set up the TCB block which also (possibly) contains + 'errno'. Therefore we avoid 'malloc' which might touch 'errno'. +diff --git a/elf/dl-tls.c b/elf/dl-tls.c +index ef57a21391bb36fa..cfda76f6de96df57 100644 +--- a/elf/dl-tls.c ++++ b/elf/dl-tls.c +@@ -49,7 +49,10 @@ + that affects the size of the static TLS and by default it's small enough + not to cause problems with existing applications. The limit is not + enforced or checked: it is the user's responsibility to increase rtld.nns +- if more dlmopen namespaces are used. */ ++ if more dlmopen namespaces are used. ++ ++ Audit modules use their own namespaces, they are not included in rtld.nns, ++ but come on top when computing the number of namespaces. */ + + /* Size of initial-exec TLS in libc.so. */ + #define LIBC_IE_TLS 192 +@@ -60,8 +63,11 @@ + /* Size of additional surplus TLS, placeholder for TLS optimizations. */ + #define OPT_SURPLUS_TLS 512 + ++/* Calculate the size of the static TLS surplus, when the given ++ number of audit modules are loaded. Must be called after the ++ number of audit modules is known and before static TLS allocation. */ + void +-_dl_tls_static_surplus_init (void) ++_dl_tls_static_surplus_init (size_t naudit) + { + size_t nns; + +@@ -73,6 +79,11 @@ _dl_tls_static_surplus_init (void) + #endif + if (nns > DL_NNS) + nns = DL_NNS; ++ if (DL_NNS - nns < naudit) ++ _dl_fatal_printf ("Failed loading %lu audit modules, %lu are supported.\n", ++ (unsigned long) naudit, (unsigned long) (DL_NNS - nns)); ++ nns += naudit; ++ + GLRO(dl_tls_static_surplus) = ((nns - 1) * LIBC_IE_TLS + + nns * OTHER_IE_TLS + + OPT_SURPLUS_TLS); +diff --git a/elf/rtld.c b/elf/rtld.c +index a440741f4c1b3c91..67441ac6f252350e 100644 +--- a/elf/rtld.c ++++ b/elf/rtld.c +@@ -297,6 +297,23 @@ audit_list_next (struct audit_list *list) + } + } + ++/* Count audit modules before they are loaded so GLRO(dl_naudit) ++ is not yet usable. */ ++static size_t ++audit_list_count (struct audit_list *list) ++{ ++ /* Restore the audit_list iterator state at the end. */ ++ const char *saved_tail = list->current_tail; ++ size_t naudit = 0; ++ ++ assert (list->current_index == 0); ++ while (audit_list_next (list) != NULL) ++ naudit++; ++ list->current_tail = saved_tail; ++ list->current_index = 0; ++ return naudit; ++} ++ + /* Set nonzero during loading and initialization of executable and + libraries, cleared before the executable's entry point runs. This + must not be initialized to nonzero, because the unused dynamic +@@ -734,7 +751,7 @@ match_version (const char *string, struct link_map *map) + static bool tls_init_tp_called; + + static void * +-init_tls (void) ++init_tls (size_t naudit) + { + /* Number of elements in the static TLS block. */ + GL(dl_tls_static_nelem) = GL(dl_tls_max_dtv_idx); +@@ -777,7 +794,7 @@ init_tls (void) + assert (i == GL(dl_tls_max_dtv_idx)); + + /* Calculate the size of the static TLS surplus. */ +- _dl_tls_static_surplus_init (); ++ _dl_tls_static_surplus_init (naudit); + + /* Compute the TLS offsets for the various blocks. */ + _dl_determine_tlsoffset (); +@@ -1659,9 +1676,11 @@ ERROR: '%s': cannot process note segment.\n", _dl_argv[0]); + bool need_security_init = true; + if (audit_list.length > 0) + { ++ size_t naudit = audit_list_count (&audit_list); ++ + /* Since we start using the auditing DSOs right away we need to + initialize the data structures now. */ +- tcbp = init_tls (); ++ tcbp = init_tls (naudit); + + /* Initialize security features. We need to do it this early + since otherwise the constructors of the audit libraries will +@@ -1671,6 +1690,10 @@ ERROR: '%s': cannot process note segment.\n", _dl_argv[0]); + need_security_init = false; + + load_audit_modules (main_map, &audit_list); ++ ++ /* The count based on audit strings may overestimate the number ++ of audit modules that got loaded, but not underestimate. */ ++ assert (GLRO(dl_naudit) <= naudit); + } + + /* Keep track of the currently loaded modules to count how many +@@ -1914,7 +1937,7 @@ ERROR: '%s': cannot process note segment.\n", _dl_argv[0]); + multiple threads (from a non-TLS-using libpthread). */ + bool was_tls_init_tp_called = tls_init_tp_called; + if (tcbp == NULL) +- tcbp = init_tls (); ++ tcbp = init_tls (0); + + if (__glibc_likely (need_security_init)) + /* Initialize security features. But only if we have not done it +diff --git a/manual/tunables.texi b/manual/tunables.texi +index e092b8e81a18d739..e6a3e9a2cf5c959c 100644 +--- a/manual/tunables.texi ++++ b/manual/tunables.texi +@@ -241,9 +241,12 @@ Sets the number of supported dynamic link namespaces (see @code{dlmopen}). + Currently this limit can be set between 1 and 16 inclusive, the default is 4. + Each link namespace consumes some memory in all thread, and thus raising the + limit will increase the amount of memory each thread uses. Raising the limit +-is useful when your application uses more than 4 dynamic linker audit modules +-e.g. @env{LD_AUDIT}, or will use more than 4 dynamic link namespaces as created +-by @code{dlmopen} with an lmid argument of @code{LM_ID_NEWLM}. ++is useful when your application uses more than 4 dynamic link namespaces as ++created by @code{dlmopen} with an lmid argument of @code{LM_ID_NEWLM}. ++Dynamic linker audit modules are loaded in their own dynamic link namespaces, ++but they are not accounted for in @code{glibc.rtld.nns}. They implicitly ++increase the per-thread memory usage as necessary, so this tunable does ++not need to be changed to allow many audit modules e.g. via @env{LD_AUDIT}. + @end deftp + + @node Elision Tunables +diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h +index e54105848c3cb7d1..293f3ab5a496afdf 100644 +--- a/sysdeps/generic/ldsodefs.h ++++ b/sysdeps/generic/ldsodefs.h +@@ -1104,8 +1104,9 @@ extern size_t _dl_count_modids (void) attribute_hidden; + /* Calculate offset of the TLS blocks in the static TLS block. */ + extern void _dl_determine_tlsoffset (void) attribute_hidden; + +-/* Calculate the size of the static TLS surplus. */ +-void _dl_tls_static_surplus_init (void) attribute_hidden; ++/* Calculate the size of the static TLS surplus, when the given ++ number of audit modules are loaded. */ ++void _dl_tls_static_surplus_init (size_t naudit) attribute_hidden; + + #ifndef SHARED + /* Set up the TCB for statically linked applications. This is called diff --git a/SOURCES/glibc-rh1817513-75.patch b/SOURCES/glibc-rh1817513-75.patch new file mode 100644 index 0000000..1c9577d --- /dev/null +++ b/SOURCES/glibc-rh1817513-75.patch @@ -0,0 +1,115 @@ +commit 9016b6f3893789ddfbd978aa572b46b3d3ce762f +Author: H.J. Lu +Date: Sat Jul 11 09:04:34 2020 -0700 + + x86: Remove the unused __x86_prefetchw + + Since + + commit c867597bff2562180a18da4b8dba89d24e8b65c4 + Author: H.J. Lu + Date: Wed Jun 8 13:57:50 2016 -0700 + + X86-64: Remove previous default/SSE2/AVX2 memcpy/memmove + + removed the only usage of __x86_prefetchw, we can remove the unused + __x86_prefetchw. + +Conflicts: + sysdeps/x86/cacheinfo.c + (Different backport order downstream, related to cache + comptuation. Also had to remove the now-unused eax variable.) + +diff --git a/sysdeps/i386/Makefile b/sysdeps/i386/Makefile +index c0a4fe15d47bff1c..41b345c6c6274c01 100644 +--- a/sysdeps/i386/Makefile ++++ b/sysdeps/i386/Makefile +@@ -13,10 +13,6 @@ ifeq ($(subdir),math) + CFLAGS-e_gamma_r.c += -DMATH_SET_BOTH_ROUNDING_MODES + endif + +-ifeq ($(subdir),string) +-sysdep_routines += cacheinfo +-endif +- + ifeq ($(subdir),gmon) + sysdep_routines += i386-mcount + endif +diff --git a/sysdeps/i386/cacheinfo.c b/sysdeps/i386/cacheinfo.c +deleted file mode 100644 +index f15fe0779afebb8f..0000000000000000 +--- a/sysdeps/i386/cacheinfo.c ++++ /dev/null +@@ -1,3 +0,0 @@ +-#define DISABLE_PREFETCHW +- +-#include +diff --git a/sysdeps/x86/Makefile b/sysdeps/x86/Makefile +index a936134a577e42a5..962bbcb07eba1259 100644 +--- a/sysdeps/x86/Makefile ++++ b/sysdeps/x86/Makefile +@@ -14,6 +14,10 @@ gen-as-const-headers += jmp_buf-ssp.sym + sysdep_routines += __longjmp_cancel + endif + ++ifeq ($(subdir),string) ++sysdep_routines += cacheinfo ++endif ++ + ifneq ($(enable-cet),no) + ifeq ($(subdir),elf) + sysdep-dl-routines += dl-cet +diff --git a/sysdeps/x86/cacheinfo.c b/sysdeps/x86/cacheinfo.c +index c741a69fb19a1e95..f4edbc0103beb435 100644 +--- a/sysdeps/x86/cacheinfo.c ++++ b/sysdeps/x86/cacheinfo.c +@@ -536,11 +536,6 @@ long int __x86_rep_movsb_threshold attribute_hidden = 2048; + /* Threshold to use Enhanced REP STOSB. */ + long int __x86_rep_stosb_threshold attribute_hidden = 2048; + +-#ifndef DISABLE_PREFETCHW +-/* PREFETCHW support flag for use in memory and string routines. */ +-int __x86_prefetchw attribute_hidden; +-#endif +- + + static void + get_common_cache_info (long int *shared_ptr, unsigned int *threads_ptr, +@@ -765,7 +760,6 @@ __attribute__((constructor)) + init_cacheinfo (void) + { + /* Find out what brand of processor. */ +- unsigned int eax; + unsigned int ebx; + unsigned int ecx; + unsigned int edx; +@@ -846,16 +840,6 @@ init_cacheinfo (void) + shared += core; + } + } +- +-#ifndef DISABLE_PREFETCHW +- if (max_cpuid_ex >= 0x80000001) +- { +- __cpuid (0x80000001, eax, ebx, ecx, edx); +- /* PREFETCHW || 3DNow! */ +- if ((ecx & 0x100) || (edx & 0x80000000)) +- __x86_prefetchw = -1; +- } +-#endif + } + + if (cpu_features->data_cache_size != 0) +diff --git a/sysdeps/x86_64/Makefile b/sysdeps/x86_64/Makefile +index d51cf03ac92ebcc2..e3bb45d78811d70f 100644 +--- a/sysdeps/x86_64/Makefile ++++ b/sysdeps/x86_64/Makefile +@@ -18,7 +18,7 @@ tests += tst-mallocalign1 + endif + + ifeq ($(subdir),string) +-sysdep_routines += cacheinfo strcasecmp_l-nonascii strncase_l-nonascii ++sysdep_routines += strcasecmp_l-nonascii strncase_l-nonascii + gen-as-const-headers += locale-defines.sym + endif + diff --git a/SOURCES/glibc-rh1817513-76.patch b/SOURCES/glibc-rh1817513-76.patch new file mode 100644 index 0000000..c241cbf --- /dev/null +++ b/SOURCES/glibc-rh1817513-76.patch @@ -0,0 +1,34 @@ +commit 43530ba1dc4fccd438fefa26f50977ff6bf284c7 +Author: H.J. Lu +Date: Sat Jul 11 10:03:05 2020 -0700 + + x86: Remove __ASSEMBLER__ check in init-arch.h + + Since + + commit 430388d5dc0e1861b869096f4f5d946d7d74232a + Author: H.J. Lu + Date: Fri Aug 3 08:04:49 2018 -0700 + + x86: Don't include in assembly codes + + removed all usages of from assembly codes, we can remove + __ASSEMBLER__ check in init-arch.h. + +diff --git a/sysdeps/x86/init-arch.h b/sysdeps/x86/init-arch.h +index bc860fcd69a605b3..63a7f8562010e5e2 100644 +--- a/sysdeps/x86/init-arch.h ++++ b/sysdeps/x86/init-arch.h +@@ -15,11 +15,7 @@ + License along with the GNU C Library; if not, see + . */ + +-#ifdef __ASSEMBLER__ +-# include +-#else +-# include +-#endif ++#include + #include + #include + diff --git a/SOURCES/glibc-rh1817513-77.patch b/SOURCES/glibc-rh1817513-77.patch new file mode 100644 index 0000000..10ed7a3 --- /dev/null +++ b/SOURCES/glibc-rh1817513-77.patch @@ -0,0 +1,3679 @@ +commit 107e6a3c2212ba7a3a4ec7cae8d82d73f7c95d0b +Author: H.J. Lu +Date: Mon Jun 29 16:36:08 2020 -0700 + + x86: Support usable check for all CPU features + + Support usable check for all CPU features with the following changes: + + 1. Change struct cpu_features to + + struct cpuid_features + { + struct cpuid_registers cpuid; + struct cpuid_registers usable; + }; + + struct cpu_features + { + struct cpu_features_basic basic; + struct cpuid_features features[COMMON_CPUID_INDEX_MAX]; + unsigned int preferred[PREFERRED_FEATURE_INDEX_MAX]; + ... + }; + + so that there is a usable bit for each cpuid bit. + 2. After the cpuid bits have been initialized, copy the known bits to the + usable bits. EAX/EBX from INDEX_1 and EAX from INDEX_7 aren't used for + CPU feature detection. + 3. Clear the usable bits which require OS support. + 4. If the feature is supported by OS, copy its cpuid bit to its usable + bit. + 5. Replace HAS_CPU_FEATURE and CPU_FEATURES_CPU_P with CPU_FEATURE_USABLE + and CPU_FEATURE_USABLE_P to check if a feature is usable. + 6. Add DEPR_FPU_CS_DS for INDEX_7_EBX_13. + 7. Unset MPX feature since it has been deprecated. + + The results are + + 1. If the feature is known and doesn't requre OS support, its usable bit + is copied from the cpuid bit. + 2. Otherwise, its usable bit is copied from the cpuid bit only if the + feature is known to supported by OS. + 3. CPU_FEATURE_USABLE/CPU_FEATURE_USABLE_P are used to check if the + feature can be used. + 4. HAS_CPU_FEATURE/CPU_FEATURE_CPU_P are used to check if CPU supports + the feature. + +diff --git a/sysdeps/i386/fpu/fclrexcpt.c b/sysdeps/i386/fpu/fclrexcpt.c +index 8463b102e7b79f07..9eff917e88235c64 100644 +--- a/sysdeps/i386/fpu/fclrexcpt.c ++++ b/sysdeps/i386/fpu/fclrexcpt.c +@@ -41,7 +41,7 @@ __feclearexcept (int excepts) + __asm__ ("fldenv %0" : : "m" (*&temp)); + + /* If the CPU supports SSE, we clear the MXCSR as well. */ +- if (HAS_CPU_FEATURE (SSE)) ++ if (CPU_FEATURE_USABLE (SSE)) + { + unsigned int xnew_exc; + +diff --git a/sysdeps/i386/fpu/fedisblxcpt.c b/sysdeps/i386/fpu/fedisblxcpt.c +index e2738e6d6c8304fe..3b5436018d08a269 100644 +--- a/sysdeps/i386/fpu/fedisblxcpt.c ++++ b/sysdeps/i386/fpu/fedisblxcpt.c +@@ -38,7 +38,7 @@ fedisableexcept (int excepts) + __asm__ ("fldcw %0" : : "m" (*&new_exc)); + + /* If the CPU supports SSE we set the MXCSR as well. */ +- if (HAS_CPU_FEATURE (SSE)) ++ if (CPU_FEATURE_USABLE (SSE)) + { + unsigned int xnew_exc; + +diff --git a/sysdeps/i386/fpu/feenablxcpt.c b/sysdeps/i386/fpu/feenablxcpt.c +index a4d986266636835b..88f46f6078e12e2c 100644 +--- a/sysdeps/i386/fpu/feenablxcpt.c ++++ b/sysdeps/i386/fpu/feenablxcpt.c +@@ -38,7 +38,7 @@ feenableexcept (int excepts) + __asm__ ("fldcw %0" : : "m" (*&new_exc)); + + /* If the CPU supports SSE we set the MXCSR as well. */ +- if (HAS_CPU_FEATURE (SSE)) ++ if (CPU_FEATURE_USABLE (SSE)) + { + unsigned int xnew_exc; + +diff --git a/sysdeps/i386/fpu/fegetenv.c b/sysdeps/i386/fpu/fegetenv.c +index 2a1a8507bac9bfa5..2a800fb6d6e856f3 100644 +--- a/sysdeps/i386/fpu/fegetenv.c ++++ b/sysdeps/i386/fpu/fegetenv.c +@@ -31,7 +31,7 @@ __fegetenv (fenv_t *envp) + would block all exceptions. */ + __asm__ ("fldenv %0" : : "m" (*envp)); + +- if (HAS_CPU_FEATURE (SSE)) ++ if (CPU_FEATURE_USABLE (SSE)) + __asm__ ("stmxcsr %0" : "=m" (envp->__eip)); + + /* Success. */ +diff --git a/sysdeps/i386/fpu/fegetmode.c b/sysdeps/i386/fpu/fegetmode.c +index 86de9f5548f4b0b4..b01ca64fc9187b10 100644 +--- a/sysdeps/i386/fpu/fegetmode.c ++++ b/sysdeps/i386/fpu/fegetmode.c +@@ -26,7 +26,7 @@ int + fegetmode (femode_t *modep) + { + _FPU_GETCW (modep->__control_word); +- if (HAS_CPU_FEATURE (SSE)) ++ if (CPU_FEATURE_USABLE (SSE)) + __asm__ ("stmxcsr %0" : "=m" (modep->__mxcsr)); + return 0; + } +diff --git a/sysdeps/i386/fpu/feholdexcpt.c b/sysdeps/i386/fpu/feholdexcpt.c +index 270554df31928cda..e2f3f97b9494f900 100644 +--- a/sysdeps/i386/fpu/feholdexcpt.c ++++ b/sysdeps/i386/fpu/feholdexcpt.c +@@ -30,7 +30,7 @@ __feholdexcept (fenv_t *envp) + __asm__ volatile ("fnstenv %0; fnclex" : "=m" (*envp)); + + /* If the CPU supports SSE we set the MXCSR as well. */ +- if (HAS_CPU_FEATURE (SSE)) ++ if (CPU_FEATURE_USABLE (SSE)) + { + unsigned int xwork; + +diff --git a/sysdeps/i386/fpu/fesetenv.c b/sysdeps/i386/fpu/fesetenv.c +index 6df6849da4007a45..5c8bf1f71a474aa9 100644 +--- a/sysdeps/i386/fpu/fesetenv.c ++++ b/sysdeps/i386/fpu/fesetenv.c +@@ -79,7 +79,7 @@ __fesetenv (const fenv_t *envp) + + __asm__ ("fldenv %0" : : "m" (temp)); + +- if (HAS_CPU_FEATURE (SSE)) ++ if (CPU_FEATURE_USABLE (SSE)) + { + unsigned int mxcsr; + __asm__ ("stmxcsr %0" : "=m" (mxcsr)); +diff --git a/sysdeps/i386/fpu/fesetmode.c b/sysdeps/i386/fpu/fesetmode.c +index 9aad6ea99f810786..35881b6adf5b0aed 100644 +--- a/sysdeps/i386/fpu/fesetmode.c ++++ b/sysdeps/i386/fpu/fesetmode.c +@@ -35,7 +35,7 @@ fesetmode (const femode_t *modep) + else + cw = modep->__control_word; + _FPU_SETCW (cw); +- if (HAS_CPU_FEATURE (SSE)) ++ if (CPU_FEATURE_USABLE (SSE)) + { + unsigned int mxcsr; + __asm__ ("stmxcsr %0" : "=m" (mxcsr)); +diff --git a/sysdeps/i386/fpu/fesetround.c b/sysdeps/i386/fpu/fesetround.c +index d260046c65d0aba0..5d38b6b8624bdaef 100644 +--- a/sysdeps/i386/fpu/fesetround.c ++++ b/sysdeps/i386/fpu/fesetround.c +@@ -37,7 +37,7 @@ __fesetround (int round) + __asm__ ("fldcw %0" : : "m" (*&cw)); + + /* If the CPU supports SSE we set the MXCSR as well. */ +- if (HAS_CPU_FEATURE (SSE)) ++ if (CPU_FEATURE_USABLE (SSE)) + { + unsigned int xcw; + +diff --git a/sysdeps/i386/fpu/feupdateenv.c b/sysdeps/i386/fpu/feupdateenv.c +index db3ff96dfa8336ec..1246b21e30740922 100644 +--- a/sysdeps/i386/fpu/feupdateenv.c ++++ b/sysdeps/i386/fpu/feupdateenv.c +@@ -32,7 +32,7 @@ __feupdateenv (const fenv_t *envp) + __asm__ ("fnstsw %0" : "=m" (*&temp)); + + /* If the CPU supports SSE we test the MXCSR as well. */ +- if (HAS_CPU_FEATURE (SSE)) ++ if (CPU_FEATURE_USABLE (SSE)) + __asm__ ("stmxcsr %0" : "=m" (*&xtemp)); + + temp = (temp | xtemp) & FE_ALL_EXCEPT; +diff --git a/sysdeps/i386/fpu/fgetexcptflg.c b/sysdeps/i386/fpu/fgetexcptflg.c +index 39d1f7df3aa24b25..acb2ae15ea681c13 100644 +--- a/sysdeps/i386/fpu/fgetexcptflg.c ++++ b/sysdeps/i386/fpu/fgetexcptflg.c +@@ -34,7 +34,7 @@ __fegetexceptflag (fexcept_t *flagp, int excepts) + *flagp = temp & excepts & FE_ALL_EXCEPT; + + /* If the CPU supports SSE, we clear the MXCSR as well. */ +- if (HAS_CPU_FEATURE (SSE)) ++ if (CPU_FEATURE_USABLE (SSE)) + { + unsigned int sse_exc; + +diff --git a/sysdeps/i386/fpu/fsetexcptflg.c b/sysdeps/i386/fpu/fsetexcptflg.c +index 21e70251cfbf8a73..caa15c0cf105a9bc 100644 +--- a/sysdeps/i386/fpu/fsetexcptflg.c ++++ b/sysdeps/i386/fpu/fsetexcptflg.c +@@ -41,7 +41,7 @@ __fesetexceptflag (const fexcept_t *flagp, int excepts) + __asm__ ("fldenv %0" : : "m" (*&temp)); + + /* If the CPU supports SSE, we set the MXCSR as well. */ +- if (HAS_CPU_FEATURE (SSE)) ++ if (CPU_FEATURE_USABLE (SSE)) + { + unsigned int xnew_exc; + +diff --git a/sysdeps/i386/fpu/ftestexcept.c b/sysdeps/i386/fpu/ftestexcept.c +index c1b5e90356bae9da..06d6134e0d85eeef 100644 +--- a/sysdeps/i386/fpu/ftestexcept.c ++++ b/sysdeps/i386/fpu/ftestexcept.c +@@ -32,7 +32,7 @@ fetestexcept (int excepts) + __asm__ ("fnstsw %0" : "=a" (temp)); + + /* If the CPU supports SSE we test the MXCSR as well. */ +- if (HAS_CPU_FEATURE (SSE)) ++ if (CPU_FEATURE_USABLE (SSE)) + __asm__ ("stmxcsr %0" : "=m" (*&xtemp)); + + return (temp | xtemp) & excepts & FE_ALL_EXCEPT; +diff --git a/sysdeps/i386/i686/fpu/multiarch/s_cosf.c b/sysdeps/i386/i686/fpu/multiarch/s_cosf.c +index a4556a478d16974a..c31592f238d67916 100644 +--- a/sysdeps/i386/i686/fpu/multiarch/s_cosf.c ++++ b/sysdeps/i386/i686/fpu/multiarch/s_cosf.c +@@ -23,7 +23,7 @@ extern float __cosf_sse2 (float); + extern float __cosf_ia32 (float); + float __cosf (float); + +-libm_ifunc (__cosf, HAS_CPU_FEATURE (SSE2) ? __cosf_sse2 : __cosf_ia32); ++libm_ifunc (__cosf, CPU_FEATURE_USABLE (SSE2) ? __cosf_sse2 : __cosf_ia32); + libm_alias_float (__cos, cos); + + #define COSF __cosf_ia32 +diff --git a/sysdeps/i386/i686/fpu/multiarch/s_sincosf.c b/sysdeps/i386/i686/fpu/multiarch/s_sincosf.c +index 5f21f5c0eda20fd1..116c541dba54dd16 100644 +--- a/sysdeps/i386/i686/fpu/multiarch/s_sincosf.c ++++ b/sysdeps/i386/i686/fpu/multiarch/s_sincosf.c +@@ -24,7 +24,7 @@ extern void __sincosf_ia32 (float, float *, float *); + void __sincosf (float, float *, float *); + + libm_ifunc (__sincosf, +- HAS_CPU_FEATURE (SSE2) ? __sincosf_sse2 : __sincosf_ia32); ++ CPU_FEATURE_USABLE (SSE2) ? __sincosf_sse2 : __sincosf_ia32); + libm_alias_float (__sincos, sincos); + + #define SINCOSF __sincosf_ia32 +diff --git a/sysdeps/i386/i686/fpu/multiarch/s_sinf.c b/sysdeps/i386/i686/fpu/multiarch/s_sinf.c +index 80a7ffaa1e36b492..63abd34c21a1c83f 100644 +--- a/sysdeps/i386/i686/fpu/multiarch/s_sinf.c ++++ b/sysdeps/i386/i686/fpu/multiarch/s_sinf.c +@@ -23,7 +23,7 @@ extern float __sinf_sse2 (float); + extern float __sinf_ia32 (float); + float __sinf (float); + +-libm_ifunc (__sinf, HAS_CPU_FEATURE (SSE2) ? __sinf_sse2 : __sinf_ia32); ++libm_ifunc (__sinf, CPU_FEATURE_USABLE (SSE2) ? __sinf_sse2 : __sinf_ia32); + libm_alias_float (__sin, sin); + #define SINF __sinf_ia32 + #include +diff --git a/sysdeps/i386/i686/multiarch/ifunc-impl-list.c b/sysdeps/i386/i686/multiarch/ifunc-impl-list.c +index a926b04acdfbb889..06e7231d94e21c02 100644 +--- a/sysdeps/i386/i686/multiarch/ifunc-impl-list.c ++++ b/sysdeps/i386/i686/multiarch/ifunc-impl-list.c +@@ -38,35 +38,35 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + + /* Support sysdeps/i386/i686/multiarch/bcopy.S. */ + IFUNC_IMPL (i, name, bcopy, +- IFUNC_IMPL_ADD (array, i, bcopy, HAS_CPU_FEATURE (SSSE3), ++ IFUNC_IMPL_ADD (array, i, bcopy, CPU_FEATURE_USABLE (SSSE3), + __bcopy_ssse3_rep) +- IFUNC_IMPL_ADD (array, i, bcopy, HAS_CPU_FEATURE (SSSE3), ++ IFUNC_IMPL_ADD (array, i, bcopy, CPU_FEATURE_USABLE (SSSE3), + __bcopy_ssse3) +- IFUNC_IMPL_ADD (array, i, bcopy, HAS_CPU_FEATURE (SSE2), ++ IFUNC_IMPL_ADD (array, i, bcopy, CPU_FEATURE_USABLE (SSE2), + __bcopy_sse2_unaligned) + IFUNC_IMPL_ADD (array, i, bcopy, 1, __bcopy_ia32)) + + /* Support sysdeps/i386/i686/multiarch/bzero.S. */ + IFUNC_IMPL (i, name, bzero, +- IFUNC_IMPL_ADD (array, i, bzero, HAS_CPU_FEATURE (SSE2), ++ IFUNC_IMPL_ADD (array, i, bzero, CPU_FEATURE_USABLE (SSE2), + __bzero_sse2_rep) +- IFUNC_IMPL_ADD (array, i, bzero, HAS_CPU_FEATURE (SSE2), ++ IFUNC_IMPL_ADD (array, i, bzero, CPU_FEATURE_USABLE (SSE2), + __bzero_sse2) + IFUNC_IMPL_ADD (array, i, bzero, 1, __bzero_ia32)) + + /* Support sysdeps/i386/i686/multiarch/memchr.S. */ + IFUNC_IMPL (i, name, memchr, +- IFUNC_IMPL_ADD (array, i, memchr, HAS_CPU_FEATURE (SSE2), ++ IFUNC_IMPL_ADD (array, i, memchr, CPU_FEATURE_USABLE (SSE2), + __memchr_sse2_bsf) +- IFUNC_IMPL_ADD (array, i, memchr, HAS_CPU_FEATURE (SSE2), ++ IFUNC_IMPL_ADD (array, i, memchr, CPU_FEATURE_USABLE (SSE2), + __memchr_sse2) + IFUNC_IMPL_ADD (array, i, memchr, 1, __memchr_ia32)) + + /* Support sysdeps/i386/i686/multiarch/memcmp.S. */ + IFUNC_IMPL (i, name, memcmp, +- IFUNC_IMPL_ADD (array, i, memcmp, HAS_CPU_FEATURE (SSE4_2), ++ IFUNC_IMPL_ADD (array, i, memcmp, CPU_FEATURE_USABLE (SSE4_2), + __memcmp_sse4_2) +- IFUNC_IMPL_ADD (array, i, memcmp, HAS_CPU_FEATURE (SSSE3), ++ IFUNC_IMPL_ADD (array, i, memcmp, CPU_FEATURE_USABLE (SSSE3), + __memcmp_ssse3) + IFUNC_IMPL_ADD (array, i, memcmp, 1, __memcmp_ia32)) + +@@ -74,13 +74,13 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + /* Support sysdeps/i386/i686/multiarch/memmove_chk.S. */ + IFUNC_IMPL (i, name, __memmove_chk, + IFUNC_IMPL_ADD (array, i, __memmove_chk, +- HAS_CPU_FEATURE (SSSE3), ++ CPU_FEATURE_USABLE (SSSE3), + __memmove_chk_ssse3_rep) + IFUNC_IMPL_ADD (array, i, __memmove_chk, +- HAS_CPU_FEATURE (SSSE3), ++ CPU_FEATURE_USABLE (SSSE3), + __memmove_chk_ssse3) + IFUNC_IMPL_ADD (array, i, __memmove_chk, +- HAS_CPU_FEATURE (SSE2), ++ CPU_FEATURE_USABLE (SSE2), + __memmove_chk_sse2_unaligned) + IFUNC_IMPL_ADD (array, i, __memmove_chk, 1, + __memmove_chk_ia32)) +@@ -88,19 +88,19 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + + /* Support sysdeps/i386/i686/multiarch/memmove.S. */ + IFUNC_IMPL (i, name, memmove, +- IFUNC_IMPL_ADD (array, i, memmove, HAS_CPU_FEATURE (SSSE3), ++ IFUNC_IMPL_ADD (array, i, memmove, CPU_FEATURE_USABLE (SSSE3), + __memmove_ssse3_rep) +- IFUNC_IMPL_ADD (array, i, memmove, HAS_CPU_FEATURE (SSSE3), ++ IFUNC_IMPL_ADD (array, i, memmove, CPU_FEATURE_USABLE (SSSE3), + __memmove_ssse3) +- IFUNC_IMPL_ADD (array, i, memmove, HAS_CPU_FEATURE (SSE2), ++ IFUNC_IMPL_ADD (array, i, memmove, CPU_FEATURE_USABLE (SSE2), + __memmove_sse2_unaligned) + IFUNC_IMPL_ADD (array, i, memmove, 1, __memmove_ia32)) + + /* Support sysdeps/i386/i686/multiarch/memrchr.S. */ + IFUNC_IMPL (i, name, memrchr, +- IFUNC_IMPL_ADD (array, i, memrchr, HAS_CPU_FEATURE (SSE2), ++ IFUNC_IMPL_ADD (array, i, memrchr, CPU_FEATURE_USABLE (SSE2), + __memrchr_sse2_bsf) +- IFUNC_IMPL_ADD (array, i, memrchr, HAS_CPU_FEATURE (SSE2), ++ IFUNC_IMPL_ADD (array, i, memrchr, CPU_FEATURE_USABLE (SSE2), + __memrchr_sse2) + IFUNC_IMPL_ADD (array, i, memrchr, 1, __memrchr_ia32)) + +@@ -108,10 +108,10 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + /* Support sysdeps/i386/i686/multiarch/memset_chk.S. */ + IFUNC_IMPL (i, name, __memset_chk, + IFUNC_IMPL_ADD (array, i, __memset_chk, +- HAS_CPU_FEATURE (SSE2), ++ CPU_FEATURE_USABLE (SSE2), + __memset_chk_sse2_rep) + IFUNC_IMPL_ADD (array, i, __memset_chk, +- HAS_CPU_FEATURE (SSE2), ++ CPU_FEATURE_USABLE (SSE2), + __memset_chk_sse2) + IFUNC_IMPL_ADD (array, i, __memset_chk, 1, + __memset_chk_ia32)) +@@ -119,102 +119,102 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + + /* Support sysdeps/i386/i686/multiarch/memset.S. */ + IFUNC_IMPL (i, name, memset, +- IFUNC_IMPL_ADD (array, i, memset, HAS_CPU_FEATURE (SSE2), ++ IFUNC_IMPL_ADD (array, i, memset, CPU_FEATURE_USABLE (SSE2), + __memset_sse2_rep) +- IFUNC_IMPL_ADD (array, i, memset, HAS_CPU_FEATURE (SSE2), ++ IFUNC_IMPL_ADD (array, i, memset, CPU_FEATURE_USABLE (SSE2), + __memset_sse2) + IFUNC_IMPL_ADD (array, i, memset, 1, __memset_ia32)) + + /* Support sysdeps/i386/i686/multiarch/rawmemchr.S. */ + IFUNC_IMPL (i, name, rawmemchr, +- IFUNC_IMPL_ADD (array, i, rawmemchr, HAS_CPU_FEATURE (SSE2), ++ IFUNC_IMPL_ADD (array, i, rawmemchr, CPU_FEATURE_USABLE (SSE2), + __rawmemchr_sse2_bsf) +- IFUNC_IMPL_ADD (array, i, rawmemchr, HAS_CPU_FEATURE (SSE2), ++ IFUNC_IMPL_ADD (array, i, rawmemchr, CPU_FEATURE_USABLE (SSE2), + __rawmemchr_sse2) + IFUNC_IMPL_ADD (array, i, rawmemchr, 1, __rawmemchr_ia32)) + + /* Support sysdeps/i386/i686/multiarch/stpncpy.S. */ + IFUNC_IMPL (i, name, stpncpy, +- IFUNC_IMPL_ADD (array, i, stpncpy, HAS_CPU_FEATURE (SSSE3), ++ IFUNC_IMPL_ADD (array, i, stpncpy, CPU_FEATURE_USABLE (SSSE3), + __stpncpy_ssse3) +- IFUNC_IMPL_ADD (array, i, stpncpy, HAS_CPU_FEATURE (SSE2), ++ IFUNC_IMPL_ADD (array, i, stpncpy, CPU_FEATURE_USABLE (SSE2), + __stpncpy_sse2) + IFUNC_IMPL_ADD (array, i, stpncpy, 1, __stpncpy_ia32)) + + /* Support sysdeps/i386/i686/multiarch/stpcpy.S. */ + IFUNC_IMPL (i, name, stpcpy, +- IFUNC_IMPL_ADD (array, i, stpcpy, HAS_CPU_FEATURE (SSSE3), ++ IFUNC_IMPL_ADD (array, i, stpcpy, CPU_FEATURE_USABLE (SSSE3), + __stpcpy_ssse3) +- IFUNC_IMPL_ADD (array, i, stpcpy, HAS_CPU_FEATURE (SSE2), ++ IFUNC_IMPL_ADD (array, i, stpcpy, CPU_FEATURE_USABLE (SSE2), + __stpcpy_sse2) + IFUNC_IMPL_ADD (array, i, stpcpy, 1, __stpcpy_ia32)) + + /* Support sysdeps/i386/i686/multiarch/strcasecmp.S. */ + IFUNC_IMPL (i, name, strcasecmp, + IFUNC_IMPL_ADD (array, i, strcasecmp, +- HAS_CPU_FEATURE (SSE4_2), ++ CPU_FEATURE_USABLE (SSE4_2), + __strcasecmp_sse4_2) + IFUNC_IMPL_ADD (array, i, strcasecmp, +- HAS_CPU_FEATURE (SSSE3), ++ CPU_FEATURE_USABLE (SSSE3), + __strcasecmp_ssse3) + IFUNC_IMPL_ADD (array, i, strcasecmp, 1, __strcasecmp_ia32)) + + /* Support sysdeps/i386/i686/multiarch/strcasecmp_l.S. */ + IFUNC_IMPL (i, name, strcasecmp_l, + IFUNC_IMPL_ADD (array, i, strcasecmp_l, +- HAS_CPU_FEATURE (SSE4_2), ++ CPU_FEATURE_USABLE (SSE4_2), + __strcasecmp_l_sse4_2) + IFUNC_IMPL_ADD (array, i, strcasecmp_l, +- HAS_CPU_FEATURE (SSSE3), ++ CPU_FEATURE_USABLE (SSSE3), + __strcasecmp_l_ssse3) + IFUNC_IMPL_ADD (array, i, strcasecmp_l, 1, + __strcasecmp_l_ia32)) + + /* Support sysdeps/i386/i686/multiarch/strcat.S. */ + IFUNC_IMPL (i, name, strcat, +- IFUNC_IMPL_ADD (array, i, strcat, HAS_CPU_FEATURE (SSSE3), ++ IFUNC_IMPL_ADD (array, i, strcat, CPU_FEATURE_USABLE (SSSE3), + __strcat_ssse3) +- IFUNC_IMPL_ADD (array, i, strcat, HAS_CPU_FEATURE (SSE2), ++ IFUNC_IMPL_ADD (array, i, strcat, CPU_FEATURE_USABLE (SSE2), + __strcat_sse2) + IFUNC_IMPL_ADD (array, i, strcat, 1, __strcat_ia32)) + + /* Support sysdeps/i386/i686/multiarch/strchr.S. */ + IFUNC_IMPL (i, name, strchr, +- IFUNC_IMPL_ADD (array, i, strchr, HAS_CPU_FEATURE (SSE2), ++ IFUNC_IMPL_ADD (array, i, strchr, CPU_FEATURE_USABLE (SSE2), + __strchr_sse2_bsf) +- IFUNC_IMPL_ADD (array, i, strchr, HAS_CPU_FEATURE (SSE2), ++ IFUNC_IMPL_ADD (array, i, strchr, CPU_FEATURE_USABLE (SSE2), + __strchr_sse2) + IFUNC_IMPL_ADD (array, i, strchr, 1, __strchr_ia32)) + + /* Support sysdeps/i386/i686/multiarch/strcmp.S. */ + IFUNC_IMPL (i, name, strcmp, +- IFUNC_IMPL_ADD (array, i, strcmp, HAS_CPU_FEATURE (SSE4_2), ++ IFUNC_IMPL_ADD (array, i, strcmp, CPU_FEATURE_USABLE (SSE4_2), + __strcmp_sse4_2) +- IFUNC_IMPL_ADD (array, i, strcmp, HAS_CPU_FEATURE (SSSE3), ++ IFUNC_IMPL_ADD (array, i, strcmp, CPU_FEATURE_USABLE (SSSE3), + __strcmp_ssse3) + IFUNC_IMPL_ADD (array, i, strcmp, 1, __strcmp_ia32)) + + /* Support sysdeps/i386/i686/multiarch/strcpy.S. */ + IFUNC_IMPL (i, name, strcpy, +- IFUNC_IMPL_ADD (array, i, strcpy, HAS_CPU_FEATURE (SSSE3), ++ IFUNC_IMPL_ADD (array, i, strcpy, CPU_FEATURE_USABLE (SSSE3), + __strcpy_ssse3) +- IFUNC_IMPL_ADD (array, i, strcpy, HAS_CPU_FEATURE (SSE2), ++ IFUNC_IMPL_ADD (array, i, strcpy, CPU_FEATURE_USABLE (SSE2), + __strcpy_sse2) + IFUNC_IMPL_ADD (array, i, strcpy, 1, __strcpy_ia32)) + + /* Support sysdeps/i386/i686/multiarch/strcspn.S. */ + IFUNC_IMPL (i, name, strcspn, +- IFUNC_IMPL_ADD (array, i, strcspn, HAS_CPU_FEATURE (SSE4_2), ++ IFUNC_IMPL_ADD (array, i, strcspn, CPU_FEATURE_USABLE (SSE4_2), + __strcspn_sse42) + IFUNC_IMPL_ADD (array, i, strcspn, 1, __strcspn_ia32)) + + /* Support sysdeps/i386/i686/multiarch/strncase.S. */ + IFUNC_IMPL (i, name, strncasecmp, + IFUNC_IMPL_ADD (array, i, strncasecmp, +- HAS_CPU_FEATURE (SSE4_2), ++ CPU_FEATURE_USABLE (SSE4_2), + __strncasecmp_sse4_2) + IFUNC_IMPL_ADD (array, i, strncasecmp, +- HAS_CPU_FEATURE (SSSE3), ++ CPU_FEATURE_USABLE (SSSE3), + __strncasecmp_ssse3) + IFUNC_IMPL_ADD (array, i, strncasecmp, 1, + __strncasecmp_ia32)) +@@ -222,91 +222,91 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + /* Support sysdeps/i386/i686/multiarch/strncase_l.S. */ + IFUNC_IMPL (i, name, strncasecmp_l, + IFUNC_IMPL_ADD (array, i, strncasecmp_l, +- HAS_CPU_FEATURE (SSE4_2), ++ CPU_FEATURE_USABLE (SSE4_2), + __strncasecmp_l_sse4_2) + IFUNC_IMPL_ADD (array, i, strncasecmp_l, +- HAS_CPU_FEATURE (SSSE3), ++ CPU_FEATURE_USABLE (SSSE3), + __strncasecmp_l_ssse3) + IFUNC_IMPL_ADD (array, i, strncasecmp_l, 1, + __strncasecmp_l_ia32)) + + /* Support sysdeps/i386/i686/multiarch/strncat.S. */ + IFUNC_IMPL (i, name, strncat, +- IFUNC_IMPL_ADD (array, i, strncat, HAS_CPU_FEATURE (SSSE3), ++ IFUNC_IMPL_ADD (array, i, strncat, CPU_FEATURE_USABLE (SSSE3), + __strncat_ssse3) +- IFUNC_IMPL_ADD (array, i, strncat, HAS_CPU_FEATURE (SSE2), ++ IFUNC_IMPL_ADD (array, i, strncat, CPU_FEATURE_USABLE (SSE2), + __strncat_sse2) + IFUNC_IMPL_ADD (array, i, strncat, 1, __strncat_ia32)) + + /* Support sysdeps/i386/i686/multiarch/strncpy.S. */ + IFUNC_IMPL (i, name, strncpy, +- IFUNC_IMPL_ADD (array, i, strncpy, HAS_CPU_FEATURE (SSSE3), ++ IFUNC_IMPL_ADD (array, i, strncpy, CPU_FEATURE_USABLE (SSSE3), + __strncpy_ssse3) +- IFUNC_IMPL_ADD (array, i, strncpy, HAS_CPU_FEATURE (SSE2), ++ IFUNC_IMPL_ADD (array, i, strncpy, CPU_FEATURE_USABLE (SSE2), + __strncpy_sse2) + IFUNC_IMPL_ADD (array, i, strncpy, 1, __strncpy_ia32)) + + /* Support sysdeps/i386/i686/multiarch/strnlen.S. */ + IFUNC_IMPL (i, name, strnlen, +- IFUNC_IMPL_ADD (array, i, strnlen, HAS_CPU_FEATURE (SSE2), ++ IFUNC_IMPL_ADD (array, i, strnlen, CPU_FEATURE_USABLE (SSE2), + __strnlen_sse2) + IFUNC_IMPL_ADD (array, i, strnlen, 1, __strnlen_ia32)) + + /* Support sysdeps/i386/i686/multiarch/strpbrk.S. */ + IFUNC_IMPL (i, name, strpbrk, +- IFUNC_IMPL_ADD (array, i, strpbrk, HAS_CPU_FEATURE (SSE4_2), ++ IFUNC_IMPL_ADD (array, i, strpbrk, CPU_FEATURE_USABLE (SSE4_2), + __strpbrk_sse42) + IFUNC_IMPL_ADD (array, i, strpbrk, 1, __strpbrk_ia32)) + + /* Support sysdeps/i386/i686/multiarch/strrchr.S. */ + IFUNC_IMPL (i, name, strrchr, +- IFUNC_IMPL_ADD (array, i, strrchr, HAS_CPU_FEATURE (SSE2), ++ IFUNC_IMPL_ADD (array, i, strrchr, CPU_FEATURE_USABLE (SSE2), + __strrchr_sse2_bsf) +- IFUNC_IMPL_ADD (array, i, strrchr, HAS_CPU_FEATURE (SSE2), ++ IFUNC_IMPL_ADD (array, i, strrchr, CPU_FEATURE_USABLE (SSE2), + __strrchr_sse2) + IFUNC_IMPL_ADD (array, i, strrchr, 1, __strrchr_ia32)) + + /* Support sysdeps/i386/i686/multiarch/strspn.S. */ + IFUNC_IMPL (i, name, strspn, +- IFUNC_IMPL_ADD (array, i, strspn, HAS_CPU_FEATURE (SSE4_2), ++ IFUNC_IMPL_ADD (array, i, strspn, CPU_FEATURE_USABLE (SSE4_2), + __strspn_sse42) + IFUNC_IMPL_ADD (array, i, strspn, 1, __strspn_ia32)) + + /* Support sysdeps/i386/i686/multiarch/wcschr.S. */ + IFUNC_IMPL (i, name, wcschr, +- IFUNC_IMPL_ADD (array, i, wcschr, HAS_CPU_FEATURE (SSE2), ++ IFUNC_IMPL_ADD (array, i, wcschr, CPU_FEATURE_USABLE (SSE2), + __wcschr_sse2) + IFUNC_IMPL_ADD (array, i, wcschr, 1, __wcschr_ia32)) + + /* Support sysdeps/i386/i686/multiarch/wcscmp.S. */ + IFUNC_IMPL (i, name, wcscmp, +- IFUNC_IMPL_ADD (array, i, wcscmp, HAS_CPU_FEATURE (SSE2), ++ IFUNC_IMPL_ADD (array, i, wcscmp, CPU_FEATURE_USABLE (SSE2), + __wcscmp_sse2) + IFUNC_IMPL_ADD (array, i, wcscmp, 1, __wcscmp_ia32)) + + /* Support sysdeps/i386/i686/multiarch/wcscpy.S. */ + IFUNC_IMPL (i, name, wcscpy, +- IFUNC_IMPL_ADD (array, i, wcscpy, HAS_CPU_FEATURE (SSSE3), ++ IFUNC_IMPL_ADD (array, i, wcscpy, CPU_FEATURE_USABLE (SSSE3), + __wcscpy_ssse3) + IFUNC_IMPL_ADD (array, i, wcscpy, 1, __wcscpy_ia32)) + + /* Support sysdeps/i386/i686/multiarch/wcslen.S. */ + IFUNC_IMPL (i, name, wcslen, +- IFUNC_IMPL_ADD (array, i, wcslen, HAS_CPU_FEATURE (SSE2), ++ IFUNC_IMPL_ADD (array, i, wcslen, CPU_FEATURE_USABLE (SSE2), + __wcslen_sse2) + IFUNC_IMPL_ADD (array, i, wcslen, 1, __wcslen_ia32)) + + /* Support sysdeps/i386/i686/multiarch/wcsrchr.S. */ + IFUNC_IMPL (i, name, wcsrchr, +- IFUNC_IMPL_ADD (array, i, wcsrchr, HAS_CPU_FEATURE (SSE2), ++ IFUNC_IMPL_ADD (array, i, wcsrchr, CPU_FEATURE_USABLE (SSE2), + __wcsrchr_sse2) + IFUNC_IMPL_ADD (array, i, wcsrchr, 1, __wcsrchr_ia32)) + + /* Support sysdeps/i386/i686/multiarch/wmemcmp.S. */ + IFUNC_IMPL (i, name, wmemcmp, +- IFUNC_IMPL_ADD (array, i, wmemcmp, HAS_CPU_FEATURE (SSE4_2), ++ IFUNC_IMPL_ADD (array, i, wmemcmp, CPU_FEATURE_USABLE (SSE4_2), + __wmemcmp_sse4_2) +- IFUNC_IMPL_ADD (array, i, wmemcmp, HAS_CPU_FEATURE (SSSE3), ++ IFUNC_IMPL_ADD (array, i, wmemcmp, CPU_FEATURE_USABLE (SSSE3), + __wmemcmp_ssse3) + IFUNC_IMPL_ADD (array, i, wmemcmp, 1, __wmemcmp_ia32)) + +@@ -314,64 +314,64 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + /* Support sysdeps/i386/i686/multiarch/memcpy_chk.S. */ + IFUNC_IMPL (i, name, __memcpy_chk, + IFUNC_IMPL_ADD (array, i, __memcpy_chk, +- HAS_CPU_FEATURE (SSSE3), ++ CPU_FEATURE_USABLE (SSSE3), + __memcpy_chk_ssse3_rep) + IFUNC_IMPL_ADD (array, i, __memcpy_chk, +- HAS_CPU_FEATURE (SSSE3), ++ CPU_FEATURE_USABLE (SSSE3), + __memcpy_chk_ssse3) + IFUNC_IMPL_ADD (array, i, __memcpy_chk, +- HAS_CPU_FEATURE (SSE2), ++ CPU_FEATURE_USABLE (SSE2), + __memcpy_chk_sse2_unaligned) + IFUNC_IMPL_ADD (array, i, __memcpy_chk, 1, + __memcpy_chk_ia32)) + + /* Support sysdeps/i386/i686/multiarch/memcpy.S. */ + IFUNC_IMPL (i, name, memcpy, +- IFUNC_IMPL_ADD (array, i, memcpy, HAS_CPU_FEATURE (SSSE3), ++ IFUNC_IMPL_ADD (array, i, memcpy, CPU_FEATURE_USABLE (SSSE3), + __memcpy_ssse3_rep) +- IFUNC_IMPL_ADD (array, i, memcpy, HAS_CPU_FEATURE (SSSE3), ++ IFUNC_IMPL_ADD (array, i, memcpy, CPU_FEATURE_USABLE (SSSE3), + __memcpy_ssse3) +- IFUNC_IMPL_ADD (array, i, memcpy, HAS_CPU_FEATURE (SSE2), ++ IFUNC_IMPL_ADD (array, i, memcpy, CPU_FEATURE_USABLE (SSE2), + __memcpy_sse2_unaligned) + IFUNC_IMPL_ADD (array, i, memcpy, 1, __memcpy_ia32)) + + /* Support sysdeps/i386/i686/multiarch/mempcpy_chk.S. */ + IFUNC_IMPL (i, name, __mempcpy_chk, + IFUNC_IMPL_ADD (array, i, __mempcpy_chk, +- HAS_CPU_FEATURE (SSSE3), ++ CPU_FEATURE_USABLE (SSSE3), + __mempcpy_chk_ssse3_rep) + IFUNC_IMPL_ADD (array, i, __mempcpy_chk, +- HAS_CPU_FEATURE (SSSE3), ++ CPU_FEATURE_USABLE (SSSE3), + __mempcpy_chk_ssse3) + IFUNC_IMPL_ADD (array, i, __mempcpy_chk, +- HAS_CPU_FEATURE (SSE2), ++ CPU_FEATURE_USABLE (SSE2), + __mempcpy_chk_sse2_unaligned) + IFUNC_IMPL_ADD (array, i, __mempcpy_chk, 1, + __mempcpy_chk_ia32)) + + /* Support sysdeps/i386/i686/multiarch/mempcpy.S. */ + IFUNC_IMPL (i, name, mempcpy, +- IFUNC_IMPL_ADD (array, i, mempcpy, HAS_CPU_FEATURE (SSSE3), ++ IFUNC_IMPL_ADD (array, i, mempcpy, CPU_FEATURE_USABLE (SSSE3), + __mempcpy_ssse3_rep) +- IFUNC_IMPL_ADD (array, i, mempcpy, HAS_CPU_FEATURE (SSSE3), ++ IFUNC_IMPL_ADD (array, i, mempcpy, CPU_FEATURE_USABLE (SSSE3), + __mempcpy_ssse3) +- IFUNC_IMPL_ADD (array, i, mempcpy, HAS_CPU_FEATURE (SSE2), ++ IFUNC_IMPL_ADD (array, i, mempcpy, CPU_FEATURE_USABLE (SSE2), + __mempcpy_sse2_unaligned) + IFUNC_IMPL_ADD (array, i, mempcpy, 1, __mempcpy_ia32)) + + /* Support sysdeps/i386/i686/multiarch/strlen.S. */ + IFUNC_IMPL (i, name, strlen, +- IFUNC_IMPL_ADD (array, i, strlen, HAS_CPU_FEATURE (SSE2), ++ IFUNC_IMPL_ADD (array, i, strlen, CPU_FEATURE_USABLE (SSE2), + __strlen_sse2_bsf) +- IFUNC_IMPL_ADD (array, i, strlen, HAS_CPU_FEATURE (SSE2), ++ IFUNC_IMPL_ADD (array, i, strlen, CPU_FEATURE_USABLE (SSE2), + __strlen_sse2) + IFUNC_IMPL_ADD (array, i, strlen, 1, __strlen_ia32)) + + /* Support sysdeps/i386/i686/multiarch/strncmp.S. */ + IFUNC_IMPL (i, name, strncmp, +- IFUNC_IMPL_ADD (array, i, strncmp, HAS_CPU_FEATURE (SSE4_2), ++ IFUNC_IMPL_ADD (array, i, strncmp, CPU_FEATURE_USABLE (SSE4_2), + __strncmp_sse4_2) +- IFUNC_IMPL_ADD (array, i, strncmp, HAS_CPU_FEATURE (SSSE3), ++ IFUNC_IMPL_ADD (array, i, strncmp, CPU_FEATURE_USABLE (SSSE3), + __strncmp_ssse3) + IFUNC_IMPL_ADD (array, i, strncmp, 1, __strncmp_ia32)) + #endif +diff --git a/sysdeps/i386/i686/multiarch/ifunc-memmove.h b/sysdeps/i386/i686/multiarch/ifunc-memmove.h +index f0e97561784a82d5..cd4333f84b114552 100644 +--- a/sysdeps/i386/i686/multiarch/ifunc-memmove.h ++++ b/sysdeps/i386/i686/multiarch/ifunc-memmove.h +@@ -33,7 +33,7 @@ IFUNC_SELECTOR (void) + if (CPU_FEATURES_ARCH_P (cpu_features, Fast_Unaligned_Load)) + return OPTIMIZE (sse2_unaligned); + +- if (CPU_FEATURES_CPU_P (cpu_features, SSSE3)) ++ if (CPU_FEATURE_USABLE_P (cpu_features, SSSE3)) + { + if (CPU_FEATURES_ARCH_P (cpu_features, Fast_Rep_String)) + return OPTIMIZE (ssse3_rep); +diff --git a/sysdeps/i386/i686/multiarch/ifunc-memset.h b/sysdeps/i386/i686/multiarch/ifunc-memset.h +index e96609439aef30d1..6cf96ebcd480dba4 100644 +--- a/sysdeps/i386/i686/multiarch/ifunc-memset.h ++++ b/sysdeps/i386/i686/multiarch/ifunc-memset.h +@@ -28,7 +28,7 @@ IFUNC_SELECTOR (void) + { + const struct cpu_features* cpu_features = __get_cpu_features (); + +- if (CPU_FEATURES_CPU_P (cpu_features, SSE2)) ++ if (CPU_FEATURE_USABLE_P (cpu_features, SSE2)) + { + if (CPU_FEATURES_ARCH_P (cpu_features, Fast_Rep_String)) + return OPTIMIZE (sse2_rep); +diff --git a/sysdeps/i386/i686/multiarch/ifunc-sse2-bsf.h b/sysdeps/i386/i686/multiarch/ifunc-sse2-bsf.h +index f5e7f1b846c28454..de30f004db53f227 100644 +--- a/sysdeps/i386/i686/multiarch/ifunc-sse2-bsf.h ++++ b/sysdeps/i386/i686/multiarch/ifunc-sse2-bsf.h +@@ -28,7 +28,7 @@ IFUNC_SELECTOR (void) + { + const struct cpu_features* cpu_features = __get_cpu_features (); + +- if (CPU_FEATURES_CPU_P (cpu_features, SSE2)) ++ if (CPU_FEATURE_USABLE_P (cpu_features, SSE2)) + { + if (CPU_FEATURES_ARCH_P (cpu_features, Slow_BSF)) + return OPTIMIZE (sse2); +diff --git a/sysdeps/i386/i686/multiarch/ifunc-sse2-ssse3.h b/sysdeps/i386/i686/multiarch/ifunc-sse2-ssse3.h +index a33fe44f504bd178..299d73e3144698d7 100644 +--- a/sysdeps/i386/i686/multiarch/ifunc-sse2-ssse3.h ++++ b/sysdeps/i386/i686/multiarch/ifunc-sse2-ssse3.h +@@ -29,11 +29,11 @@ IFUNC_SELECTOR (void) + { + const struct cpu_features* cpu_features = __get_cpu_features (); + +- if (CPU_FEATURES_CPU_P (cpu_features, SSE2) ++ if (CPU_FEATURE_USABLE_P (cpu_features, SSE2) + && CPU_FEATURES_ARCH_P (cpu_features, Fast_Rep_String)) + return OPTIMIZE (sse2); + +- if (CPU_FEATURES_CPU_P (cpu_features, SSSE3)) ++ if (CPU_FEATURE_USABLE_P (cpu_features, SSSE3)) + return OPTIMIZE (ssse3); + + return OPTIMIZE (ia32); +diff --git a/sysdeps/i386/i686/multiarch/ifunc-sse2.h b/sysdeps/i386/i686/multiarch/ifunc-sse2.h +index 706c0329c9a76573..e1ba025299037bfb 100644 +--- a/sysdeps/i386/i686/multiarch/ifunc-sse2.h ++++ b/sysdeps/i386/i686/multiarch/ifunc-sse2.h +@@ -27,7 +27,7 @@ IFUNC_SELECTOR (void) + { + const struct cpu_features* cpu_features = __get_cpu_features (); + +- if (CPU_FEATURES_CPU_P (cpu_features, SSE2)) ++ if (CPU_FEATURE_USABLE_P (cpu_features, SSE2)) + return OPTIMIZE (sse2); + + return OPTIMIZE (ia32); +diff --git a/sysdeps/i386/i686/multiarch/ifunc-sse4_2.h b/sysdeps/i386/i686/multiarch/ifunc-sse4_2.h +index de7fa2f185ad9a59..641cec2ced510524 100644 +--- a/sysdeps/i386/i686/multiarch/ifunc-sse4_2.h ++++ b/sysdeps/i386/i686/multiarch/ifunc-sse4_2.h +@@ -27,7 +27,7 @@ IFUNC_SELECTOR (void) + { + const struct cpu_features* cpu_features = __get_cpu_features (); + +- if (CPU_FEATURES_CPU_P (cpu_features, SSE4_2)) ++ if (CPU_FEATURE_USABLE_P (cpu_features, SSE4_2)) + return OPTIMIZE (sse42); + + return OPTIMIZE (ia32); +diff --git a/sysdeps/i386/i686/multiarch/ifunc-ssse3-sse4_2.h b/sysdeps/i386/i686/multiarch/ifunc-ssse3-sse4_2.h +index bd772a9298ab7d6b..6b2b461e47e94b66 100644 +--- a/sysdeps/i386/i686/multiarch/ifunc-ssse3-sse4_2.h ++++ b/sysdeps/i386/i686/multiarch/ifunc-ssse3-sse4_2.h +@@ -29,10 +29,10 @@ IFUNC_SELECTOR (void) + { + const struct cpu_features* cpu_features = __get_cpu_features (); + +- if (CPU_FEATURES_CPU_P (cpu_features, SSE4_2)) ++ if (CPU_FEATURE_USABLE_P (cpu_features, SSE4_2)) + return OPTIMIZE (sse4_2); + +- if (CPU_FEATURES_CPU_P (cpu_features, SSSE3)) ++ if (CPU_FEATURE_USABLE_P (cpu_features, SSSE3)) + return OPTIMIZE (ssse3); + + return OPTIMIZE (ia32); +diff --git a/sysdeps/i386/i686/multiarch/s_fma.c b/sysdeps/i386/i686/multiarch/s_fma.c +index 7f39f5fdc972fcc7..0cf6e41b03043911 100644 +--- a/sysdeps/i386/i686/multiarch/s_fma.c ++++ b/sysdeps/i386/i686/multiarch/s_fma.c +@@ -27,7 +27,7 @@ extern double __fma_ia32 (double x, double y, double z) attribute_hidden; + extern double __fma_fma (double x, double y, double z) attribute_hidden; + + libm_ifunc (__fma, +- HAS_ARCH_FEATURE (FMA_Usable) ? __fma_fma : __fma_ia32); ++ CPU_FEATURE_USABLE (FMA) ? __fma_fma : __fma_ia32); + libm_alias_double (__fma, fma) + + #define __fma __fma_ia32 +diff --git a/sysdeps/i386/i686/multiarch/s_fmaf.c b/sysdeps/i386/i686/multiarch/s_fmaf.c +index 1ebb6e975ee86f54..638cd5b10ba57592 100644 +--- a/sysdeps/i386/i686/multiarch/s_fmaf.c ++++ b/sysdeps/i386/i686/multiarch/s_fmaf.c +@@ -27,7 +27,7 @@ extern float __fmaf_ia32 (float x, float y, float z) attribute_hidden; + extern float __fmaf_fma (float x, float y, float z) attribute_hidden; + + libm_ifunc (__fmaf, +- HAS_ARCH_FEATURE (FMA_Usable) ? __fmaf_fma : __fmaf_ia32); ++ CPU_FEATURE_USABLE (FMA) ? __fmaf_fma : __fmaf_ia32); + libm_alias_float (__fma, fma) + + #define __fmaf __fmaf_ia32 +diff --git a/sysdeps/i386/i686/multiarch/wcscpy.c b/sysdeps/i386/i686/multiarch/wcscpy.c +index be89ab81b066d463..ea149b0d3af357f2 100644 +--- a/sysdeps/i386/i686/multiarch/wcscpy.c ++++ b/sysdeps/i386/i686/multiarch/wcscpy.c +@@ -34,7 +34,7 @@ IFUNC_SELECTOR (void) + { + const struct cpu_features* cpu_features = __get_cpu_features (); + +- if (CPU_FEATURES_CPU_P (cpu_features, SSSE3)) ++ if (CPU_FEATURE_USABLE_P (cpu_features, SSSE3)) + return OPTIMIZE (ssse3); + + return OPTIMIZE (ia32); +diff --git a/sysdeps/i386/setfpucw.c b/sysdeps/i386/setfpucw.c +index 931302bcd03d221b..3fa2651d46a70ab6 100644 +--- a/sysdeps/i386/setfpucw.c ++++ b/sysdeps/i386/setfpucw.c +@@ -39,7 +39,7 @@ __setfpucw (fpu_control_t set) + __asm__ ("fldcw %0" : : "m" (*&cw)); + + /* If the CPU supports SSE, we set the MXCSR as well. */ +- if (HAS_CPU_FEATURE (SSE)) ++ if (CPU_FEATURE_USABLE (SSE)) + { + unsigned int xnew_exc; + +diff --git a/sysdeps/unix/sysv/linux/x86/elision-conf.c b/sysdeps/unix/sysv/linux/x86/elision-conf.c +index 22af294426596add..bdfc514a238f92a8 100644 +--- a/sysdeps/unix/sysv/linux/x86/elision-conf.c ++++ b/sysdeps/unix/sysv/linux/x86/elision-conf.c +@@ -64,7 +64,7 @@ do_set_elision_enable (int32_t elision_enable) + if __libc_enable_secure isn't enabled since elision_enable will be set + according to the default, which is disabled. */ + if (elision_enable == 1) +- __pthread_force_elision = HAS_CPU_FEATURE (RTM) ? 1 : 0; ++ __pthread_force_elision = CPU_FEATURE_USABLE (RTM) ? 1 : 0; + } + + /* The pthread->elision_enable tunable is 0 or 1 indicating that elision +diff --git a/sysdeps/x86/cacheinfo.c b/sysdeps/x86/cacheinfo.c +index f4edbc0103beb435..fdfe2684759d968c 100644 +--- a/sysdeps/x86/cacheinfo.c ++++ b/sysdeps/x86/cacheinfo.c +@@ -583,7 +583,7 @@ get_common_cache_info (long int *shared_ptr, unsigned int *threads_ptr, + + /* A value of 0 for the HTT bit indicates there is only a single + logical processor. */ +- if (HAS_CPU_FEATURE (HTT)) ++ if (CPU_FEATURE_USABLE (HTT)) + { + /* Figure out the number of logical threads that share the + highest cache level. */ +@@ -732,7 +732,7 @@ intel_bug_no_cache_info: + /* Assume that all logical threads share the highest cache + level. */ + threads +- = ((cpu_features->cpuid[COMMON_CPUID_INDEX_1].ebx ++ = ((cpu_features->features[COMMON_CPUID_INDEX_1].cpuid.ebx + >> 16) & 0xff); + } + +@@ -887,14 +887,14 @@ init_cacheinfo (void) + unsigned int minimum_rep_movsb_threshold; + /* NB: The default REP MOVSB threshold is 2048 * (VEC_SIZE / 16). */ + unsigned int rep_movsb_threshold; +- if (CPU_FEATURES_ARCH_P (cpu_features, AVX512F_Usable) +- && !CPU_FEATURES_ARCH_P (cpu_features, Prefer_No_AVX512)) ++ if (CPU_FEATURE_USABLE_P (cpu_features, AVX512F) ++ && !CPU_FEATURE_PREFERRED_P (cpu_features, Prefer_No_AVX512)) + { + rep_movsb_threshold = 2048 * (64 / 16); + minimum_rep_movsb_threshold = 64 * 8; + } +- else if (CPU_FEATURES_ARCH_P (cpu_features, +- AVX_Fast_Unaligned_Load)) ++ else if (CPU_FEATURE_PREFERRED_P (cpu_features, ++ AVX_Fast_Unaligned_Load)) + { + rep_movsb_threshold = 2048 * (32 / 16); + minimum_rep_movsb_threshold = 32 * 8; +diff --git a/sysdeps/x86/cpu-features.c b/sysdeps/x86/cpu-features.c +index ad470f79ef7769fc..f13a1df4555c7000 100644 +--- a/sysdeps/x86/cpu-features.c ++++ b/sysdeps/x86/cpu-features.c +@@ -42,73 +42,109 @@ extern void TUNABLE_CALLBACK (set_x86_shstk) (tunable_val_t *) + #endif + + static void +-get_extended_indices (struct cpu_features *cpu_features) ++update_usable (struct cpu_features *cpu_features) + { +- unsigned int eax, ebx, ecx, edx; +- __cpuid (0x80000000, eax, ebx, ecx, edx); +- if (eax >= 0x80000001) +- __cpuid (0x80000001, +- cpu_features->cpuid[COMMON_CPUID_INDEX_80000001].eax, +- cpu_features->cpuid[COMMON_CPUID_INDEX_80000001].ebx, +- cpu_features->cpuid[COMMON_CPUID_INDEX_80000001].ecx, +- cpu_features->cpuid[COMMON_CPUID_INDEX_80000001].edx); +- if (eax >= 0x80000007) +- __cpuid (0x80000007, +- cpu_features->cpuid[COMMON_CPUID_INDEX_80000007].eax, +- cpu_features->cpuid[COMMON_CPUID_INDEX_80000007].ebx, +- cpu_features->cpuid[COMMON_CPUID_INDEX_80000007].ecx, +- cpu_features->cpuid[COMMON_CPUID_INDEX_80000007].edx); +- if (eax >= 0x80000008) +- __cpuid (0x80000008, +- cpu_features->cpuid[COMMON_CPUID_INDEX_80000008].eax, +- cpu_features->cpuid[COMMON_CPUID_INDEX_80000008].ebx, +- cpu_features->cpuid[COMMON_CPUID_INDEX_80000008].ecx, +- cpu_features->cpuid[COMMON_CPUID_INDEX_80000008].edx); +-} +- +-static void +-get_common_indices (struct cpu_features *cpu_features, +- unsigned int *family, unsigned int *model, +- unsigned int *extended_model, unsigned int *stepping) +-{ +- if (family) +- { +- unsigned int eax; +- __cpuid (1, eax, cpu_features->cpuid[COMMON_CPUID_INDEX_1].ebx, +- cpu_features->cpuid[COMMON_CPUID_INDEX_1].ecx, +- cpu_features->cpuid[COMMON_CPUID_INDEX_1].edx); +- cpu_features->cpuid[COMMON_CPUID_INDEX_1].eax = eax; +- *family = (eax >> 8) & 0x0f; +- *model = (eax >> 4) & 0x0f; +- *extended_model = (eax >> 12) & 0xf0; +- *stepping = eax & 0x0f; +- if (*family == 0x0f) +- { +- *family += (eax >> 20) & 0xff; +- *model += *extended_model; +- } +- } +- +- if (cpu_features->basic.max_cpuid >= 7) +- { +- __cpuid_count (7, 0, +- cpu_features->cpuid[COMMON_CPUID_INDEX_7].eax, +- cpu_features->cpuid[COMMON_CPUID_INDEX_7].ebx, +- cpu_features->cpuid[COMMON_CPUID_INDEX_7].ecx, +- cpu_features->cpuid[COMMON_CPUID_INDEX_7].edx); +- __cpuid_count (7, 1, +- cpu_features->cpuid[COMMON_CPUID_INDEX_7_ECX_1].eax, +- cpu_features->cpuid[COMMON_CPUID_INDEX_7_ECX_1].ebx, +- cpu_features->cpuid[COMMON_CPUID_INDEX_7_ECX_1].ecx, +- cpu_features->cpuid[COMMON_CPUID_INDEX_7_ECX_1].edx); +- } +- +- if (cpu_features->basic.max_cpuid >= 0xd) +- __cpuid_count (0xd, 1, +- cpu_features->cpuid[COMMON_CPUID_INDEX_D_ECX_1].eax, +- cpu_features->cpuid[COMMON_CPUID_INDEX_D_ECX_1].ebx, +- cpu_features->cpuid[COMMON_CPUID_INDEX_D_ECX_1].ecx, +- cpu_features->cpuid[COMMON_CPUID_INDEX_D_ECX_1].edx); ++ /* Before COMMON_CPUID_INDEX_80000001, copy the cpuid array elements to ++ the usable array. */ ++ unsigned int i; ++ for (i = 0; i < COMMON_CPUID_INDEX_80000001; i++) ++ cpu_features->features[i].usable = cpu_features->features[i].cpuid; ++ ++ /* Before COMMON_CPUID_INDEX_80000001, clear the unknown usable bits ++ and the always zero bits. */ ++ CPU_FEATURE_UNSET (cpu_features, INDEX_1_ECX_16); ++ CPU_FEATURE_UNSET (cpu_features, INDEX_1_ECX_31); ++ CPU_FEATURE_UNSET (cpu_features, INDEX_1_EDX_10); ++ CPU_FEATURE_UNSET (cpu_features, INDEX_1_EDX_20); ++ CPU_FEATURE_UNSET (cpu_features, INDEX_1_EDX_30); ++ CPU_FEATURE_UNSET (cpu_features, INDEX_7_EBX_6); ++ CPU_FEATURE_UNSET (cpu_features, INDEX_7_EBX_22); ++ CPU_FEATURE_UNSET (cpu_features, INDEX_7_ECX_13); ++ CPU_FEATURE_UNSET (cpu_features, INDEX_7_ECX_15); ++ CPU_FEATURE_UNSET (cpu_features, INDEX_7_ECX_16); ++ CPU_FEATURE_UNSET (cpu_features, INDEX_7_ECX_23); ++ CPU_FEATURE_UNSET (cpu_features, INDEX_7_ECX_24); ++ CPU_FEATURE_UNSET (cpu_features, INDEX_7_ECX_26); ++ CPU_FEATURE_UNSET (cpu_features, INDEX_7_EDX_0); ++ CPU_FEATURE_UNSET (cpu_features, INDEX_7_EDX_1); ++ CPU_FEATURE_UNSET (cpu_features, INDEX_7_EDX_5); ++ CPU_FEATURE_UNSET (cpu_features, INDEX_7_EDX_6); ++ CPU_FEATURE_UNSET (cpu_features, INDEX_7_EDX_7); ++ CPU_FEATURE_UNSET (cpu_features, INDEX_7_EDX_9); ++ CPU_FEATURE_UNSET (cpu_features, INDEX_7_EDX_11); ++ CPU_FEATURE_UNSET (cpu_features, INDEX_7_EDX_12); ++ CPU_FEATURE_UNSET (cpu_features, INDEX_7_EDX_13); ++ CPU_FEATURE_UNSET (cpu_features, INDEX_7_EDX_17); ++ CPU_FEATURE_UNSET (cpu_features, INDEX_7_EDX_19); ++ CPU_FEATURE_UNSET (cpu_features, INDEX_7_EDX_21); ++ CPU_FEATURE_UNSET (cpu_features, INDEX_7_EDX_23); ++ ++ /* EAX/EBX from COMMON_CPUID_INDEX_1 and EAX from COMMON_CPUID_INDEX_7 ++ aren't used for CPU feature detection. */ ++ cpu_features->features[COMMON_CPUID_INDEX_1].usable.eax = 0; ++ cpu_features->features[COMMON_CPUID_INDEX_1].usable.ebx = 0; ++ cpu_features->features[COMMON_CPUID_INDEX_7].usable.eax = 0; ++ ++ /* Starting from COMMON_CPUID_INDEX_80000001, copy the cpuid bits to ++ usable bits. */ ++ CPU_FEATURE_SET_USABLE (cpu_features, LAHF64_SAHF64); ++ CPU_FEATURE_SET_USABLE (cpu_features, SVM); ++ CPU_FEATURE_SET_USABLE (cpu_features, LZCNT); ++ CPU_FEATURE_SET_USABLE (cpu_features, SSE4A); ++ CPU_FEATURE_SET_USABLE (cpu_features, PREFETCHW); ++ CPU_FEATURE_SET_USABLE (cpu_features, XOP); ++ CPU_FEATURE_SET_USABLE (cpu_features, LWP); ++ CPU_FEATURE_SET_USABLE (cpu_features, FMA4); ++ CPU_FEATURE_SET_USABLE (cpu_features, TBM); ++ CPU_FEATURE_SET_USABLE (cpu_features, SYSCALL_SYSRET); ++ CPU_FEATURE_SET_USABLE (cpu_features, NX); ++ CPU_FEATURE_SET_USABLE (cpu_features, PAGE1GB); ++ CPU_FEATURE_SET_USABLE (cpu_features, RDTSCP); ++ CPU_FEATURE_SET_USABLE (cpu_features, LM); ++ CPU_FEATURE_SET_USABLE (cpu_features, XSAVEOPT); ++ CPU_FEATURE_SET_USABLE (cpu_features, XSAVEC); ++ CPU_FEATURE_SET_USABLE (cpu_features, XGETBV_ECX_1); ++ CPU_FEATURE_SET_USABLE (cpu_features, XSAVES); ++ CPU_FEATURE_SET_USABLE (cpu_features, XFD); ++ CPU_FEATURE_SET_USABLE (cpu_features, INVARIANT_TSC); ++ CPU_FEATURE_SET_USABLE (cpu_features, WBNOINVD); ++ CPU_FEATURE_SET_USABLE (cpu_features, AVX512_BF16); ++ ++ /* MPX has been deprecated. */ ++ CPU_FEATURE_UNSET (cpu_features, MPX); ++ ++ /* Clear the usable bits which require OS support. */ ++ CPU_FEATURE_UNSET (cpu_features, FMA); ++ CPU_FEATURE_UNSET (cpu_features, AVX); ++ CPU_FEATURE_UNSET (cpu_features, F16C); ++ CPU_FEATURE_UNSET (cpu_features, AVX2); ++ CPU_FEATURE_UNSET (cpu_features, AVX512F); ++ CPU_FEATURE_UNSET (cpu_features, AVX512DQ); ++ CPU_FEATURE_UNSET (cpu_features, AVX512_IFMA); ++ CPU_FEATURE_UNSET (cpu_features, AVX512PF); ++ CPU_FEATURE_UNSET (cpu_features, AVX512ER); ++ CPU_FEATURE_UNSET (cpu_features, AVX512CD); ++ CPU_FEATURE_UNSET (cpu_features, AVX512BW); ++ CPU_FEATURE_UNSET (cpu_features, AVX512VL); ++ CPU_FEATURE_UNSET (cpu_features, AVX512_VBMI); ++ CPU_FEATURE_UNSET (cpu_features, PKU); ++ CPU_FEATURE_UNSET (cpu_features, AVX512_VBMI2); ++ CPU_FEATURE_UNSET (cpu_features, VAES); ++ CPU_FEATURE_UNSET (cpu_features, VPCLMULQDQ); ++ CPU_FEATURE_UNSET (cpu_features, AVX512_VNNI); ++ CPU_FEATURE_UNSET (cpu_features, AVX512_BITALG); ++ CPU_FEATURE_UNSET (cpu_features, AVX512_VPOPCNTDQ); ++ CPU_FEATURE_UNSET (cpu_features, AVX512_4VNNIW); ++ CPU_FEATURE_UNSET (cpu_features, AVX512_4FMAPS); ++ CPU_FEATURE_UNSET (cpu_features, AVX512_VP2INTERSECT); ++ CPU_FEATURE_UNSET (cpu_features, AMX_BF16); ++ CPU_FEATURE_UNSET (cpu_features, AMX_TILE); ++ CPU_FEATURE_UNSET (cpu_features, AMX_INT8); ++ CPU_FEATURE_UNSET (cpu_features, XOP); ++ CPU_FEATURE_UNSET (cpu_features, FMA4); ++ CPU_FEATURE_UNSET (cpu_features, XSAVEC); ++ CPU_FEATURE_UNSET (cpu_features, XFD); ++ CPU_FEATURE_UNSET (cpu_features, AVX512_BF16); + + /* Can we call xgetbv? */ + if (CPU_FEATURES_CPU_P (cpu_features, OSXSAVE)) +@@ -123,40 +159,28 @@ get_common_indices (struct cpu_features *cpu_features, + /* Determine if AVX is usable. */ + if (CPU_FEATURES_CPU_P (cpu_features, AVX)) + { +- cpu_features->usable[index_arch_AVX_Usable] +- |= bit_arch_AVX_Usable; ++ CPU_FEATURE_SET (cpu_features, AVX); + /* The following features depend on AVX being usable. */ + /* Determine if AVX2 is usable. */ + if (CPU_FEATURES_CPU_P (cpu_features, AVX2)) +- { +- cpu_features->usable[index_arch_AVX2_Usable] +- |= bit_arch_AVX2_Usable; +- +- /* Unaligned load with 256-bit AVX registers are faster on +- Intel/AMD processors with AVX2. */ +- cpu_features->preferred[index_arch_AVX_Fast_Unaligned_Load] +- |= bit_arch_AVX_Fast_Unaligned_Load; +- } ++ { ++ CPU_FEATURE_SET (cpu_features, AVX2); ++ ++ /* Unaligned load with 256-bit AVX registers are faster ++ on Intel/AMD processors with AVX2. */ ++ cpu_features->preferred[index_arch_AVX_Fast_Unaligned_Load] ++ |= bit_arch_AVX_Fast_Unaligned_Load; ++ } + /* Determine if FMA is usable. */ +- if (CPU_FEATURES_CPU_P (cpu_features, FMA)) +- cpu_features->usable[index_arch_FMA_Usable] +- |= bit_arch_FMA_Usable; ++ CPU_FEATURE_SET_USABLE (cpu_features, FMA); + /* Determine if VAES is usable. */ +- if (CPU_FEATURES_CPU_P (cpu_features, VAES)) +- cpu_features->usable[index_arch_VAES_Usable] +- |= bit_arch_VAES_Usable; ++ CPU_FEATURE_SET_USABLE (cpu_features, VAES); + /* Determine if VPCLMULQDQ is usable. */ +- if (CPU_FEATURES_CPU_P (cpu_features, VPCLMULQDQ)) +- cpu_features->usable[index_arch_VPCLMULQDQ_Usable] +- |= bit_arch_VPCLMULQDQ_Usable; ++ CPU_FEATURE_SET_USABLE (cpu_features, VPCLMULQDQ); + /* Determine if XOP is usable. */ +- if (CPU_FEATURES_CPU_P (cpu_features, XOP)) +- cpu_features->usable[index_arch_XOP_Usable] +- |= bit_arch_XOP_Usable; ++ CPU_FEATURE_SET_USABLE (cpu_features, XOP); + /* Determine if F16C is usable. */ +- if (CPU_FEATURES_CPU_P (cpu_features, F16C)) +- cpu_features->usable[index_arch_F16C_Usable] +- |= bit_arch_F16C_Usable; ++ CPU_FEATURE_SET_USABLE (cpu_features, F16C); + } + + /* Check if OPMASK state, upper 256-bit of ZMM0-ZMM15 and +@@ -168,73 +192,41 @@ get_common_indices (struct cpu_features *cpu_features, + /* Determine if AVX512F is usable. */ + if (CPU_FEATURES_CPU_P (cpu_features, AVX512F)) + { +- cpu_features->usable[index_arch_AVX512F_Usable] +- |= bit_arch_AVX512F_Usable; ++ CPU_FEATURE_SET (cpu_features, AVX512F); + /* Determine if AVX512CD is usable. */ +- if (CPU_FEATURES_CPU_P (cpu_features, AVX512CD)) +- cpu_features->usable[index_arch_AVX512CD_Usable] +- |= bit_arch_AVX512CD_Usable; ++ CPU_FEATURE_SET_USABLE (cpu_features, AVX512CD); + /* Determine if AVX512ER is usable. */ +- if (CPU_FEATURES_CPU_P (cpu_features, AVX512ER)) +- cpu_features->usable[index_arch_AVX512ER_Usable] +- |= bit_arch_AVX512ER_Usable; ++ CPU_FEATURE_SET_USABLE (cpu_features, AVX512ER); + /* Determine if AVX512PF is usable. */ +- if (CPU_FEATURES_CPU_P (cpu_features, AVX512PF)) +- cpu_features->usable[index_arch_AVX512PF_Usable] +- |= bit_arch_AVX512PF_Usable; ++ CPU_FEATURE_SET_USABLE (cpu_features, AVX512PF); + /* Determine if AVX512VL is usable. */ +- if (CPU_FEATURES_CPU_P (cpu_features, AVX512VL)) +- cpu_features->usable[index_arch_AVX512VL_Usable] +- |= bit_arch_AVX512VL_Usable; ++ CPU_FEATURE_SET_USABLE (cpu_features, AVX512VL); + /* Determine if AVX512DQ is usable. */ +- if (CPU_FEATURES_CPU_P (cpu_features, AVX512DQ)) +- cpu_features->usable[index_arch_AVX512DQ_Usable] +- |= bit_arch_AVX512DQ_Usable; ++ CPU_FEATURE_SET_USABLE (cpu_features, AVX512DQ); + /* Determine if AVX512BW is usable. */ +- if (CPU_FEATURES_CPU_P (cpu_features, AVX512BW)) +- cpu_features->usable[index_arch_AVX512BW_Usable] +- |= bit_arch_AVX512BW_Usable; ++ CPU_FEATURE_SET_USABLE (cpu_features, AVX512BW); + /* Determine if AVX512_4FMAPS is usable. */ +- if (CPU_FEATURES_CPU_P (cpu_features, AVX512_4FMAPS)) +- cpu_features->usable[index_arch_AVX512_4FMAPS_Usable] +- |= bit_arch_AVX512_4FMAPS_Usable; ++ CPU_FEATURE_SET_USABLE (cpu_features, AVX512_4FMAPS); + /* Determine if AVX512_4VNNIW is usable. */ +- if (CPU_FEATURES_CPU_P (cpu_features, AVX512_4VNNIW)) +- cpu_features->usable[index_arch_AVX512_4VNNIW_Usable] +- |= bit_arch_AVX512_4VNNIW_Usable; ++ CPU_FEATURE_SET_USABLE (cpu_features, AVX512_4VNNIW); + /* Determine if AVX512_BITALG is usable. */ +- if (CPU_FEATURES_CPU_P (cpu_features, AVX512_BITALG)) +- cpu_features->usable[index_arch_AVX512_BITALG_Usable] +- |= bit_arch_AVX512_BITALG_Usable; ++ CPU_FEATURE_SET_USABLE (cpu_features, AVX512_BITALG); + /* Determine if AVX512_IFMA is usable. */ +- if (CPU_FEATURES_CPU_P (cpu_features, AVX512_IFMA)) +- cpu_features->usable[index_arch_AVX512_IFMA_Usable] +- |= bit_arch_AVX512_IFMA_Usable; ++ CPU_FEATURE_SET_USABLE (cpu_features, AVX512_IFMA); + /* Determine if AVX512_VBMI is usable. */ +- if (CPU_FEATURES_CPU_P (cpu_features, AVX512_VBMI)) +- cpu_features->usable[index_arch_AVX512_VBMI_Usable] +- |= bit_arch_AVX512_VBMI_Usable; ++ CPU_FEATURE_SET_USABLE (cpu_features, AVX512_VBMI); + /* Determine if AVX512_VBMI2 is usable. */ +- if (CPU_FEATURES_CPU_P (cpu_features, AVX512_VBMI2)) +- cpu_features->usable[index_arch_AVX512_VBMI2_Usable] +- |= bit_arch_AVX512_VBMI2_Usable; ++ CPU_FEATURE_SET_USABLE (cpu_features, AVX512_VBMI2); + /* Determine if is AVX512_VNNI usable. */ +- if (CPU_FEATURES_CPU_P (cpu_features, AVX512_VNNI)) +- cpu_features->usable[index_arch_AVX512_VNNI_Usable] +- |= bit_arch_AVX512_VNNI_Usable; ++ CPU_FEATURE_SET_USABLE (cpu_features, AVX512_VNNI); + /* Determine if AVX512_VPOPCNTDQ is usable. */ +- if (CPU_FEATURES_CPU_P (cpu_features, AVX512_VPOPCNTDQ)) +- cpu_features->usable[index_arch_AVX512_VPOPCNTDQ_Usable] +- |= bit_arch_AVX512_VPOPCNTDQ_Usable; ++ CPU_FEATURE_SET_USABLE (cpu_features, ++ AVX512_VPOPCNTDQ); + /* Determine if AVX512_VP2INTERSECT is usable. */ +- if (CPU_FEATURES_CPU_P (cpu_features, +- AVX512_VP2INTERSECT)) +- cpu_features->usable[index_arch_AVX512_VP2INTERSECT_Usable] +- |= bit_arch_AVX512_VP2INTERSECT_Usable; ++ CPU_FEATURE_SET_USABLE (cpu_features, ++ AVX512_VP2INTERSECT); + /* Determine if AVX512_BF16 is usable. */ +- if (CPU_FEATURES_CPU_P (cpu_features, AVX512_BF16)) +- cpu_features->usable[index_arch_AVX512_BF16_Usable] +- |= bit_arch_AVX512_BF16_Usable; ++ CPU_FEATURE_SET_USABLE (cpu_features, AVX512_BF16); + } + } + } +@@ -244,19 +236,17 @@ get_common_indices (struct cpu_features *cpu_features, + == (bit_XTILECFG_state | bit_XTILEDATA_state)) + { + /* Determine if AMX_BF16 is usable. */ +- if (CPU_FEATURES_CPU_P (cpu_features, AMX_BF16)) +- cpu_features->usable[index_arch_AMX_BF16_Usable] +- |= bit_arch_AMX_BF16_Usable; ++ CPU_FEATURE_SET_USABLE (cpu_features, AMX_BF16); + /* Determine if AMX_TILE is usable. */ +- if (CPU_FEATURES_CPU_P (cpu_features, AMX_TILE)) +- cpu_features->usable[index_arch_AMX_TILE_Usable] +- |= bit_arch_AMX_TILE_Usable; ++ CPU_FEATURE_SET_USABLE (cpu_features, AMX_TILE); + /* Determine if AMX_INT8 is usable. */ +- if (CPU_FEATURES_CPU_P (cpu_features, AMX_INT8)) +- cpu_features->usable[index_arch_AMX_INT8_Usable] +- |= bit_arch_AMX_INT8_Usable; ++ CPU_FEATURE_SET_USABLE (cpu_features, AMX_INT8); + } + ++ ++ /* XFD is usable only when OSXSAVE is enabled. */ ++ CPU_FEATURE_SET_USABLE (cpu_features, XFD); ++ + /* For _dl_runtime_resolve, set xsave_state_size to xsave area + size + integer register save size and align it to 64 bytes. */ + if (cpu_features->basic.max_cpuid >= 0xd) +@@ -318,8 +308,7 @@ get_common_indices (struct cpu_features *cpu_features, + { + cpu_features->xsave_state_size + = ALIGN_UP (size + STATE_SAVE_OFFSET, 64); +- cpu_features->usable[index_arch_XSAVEC_Usable] +- |= bit_arch_XSAVEC_Usable; ++ CPU_FEATURE_SET (cpu_features, XSAVEC); + } + } + } +@@ -328,8 +317,79 @@ get_common_indices (struct cpu_features *cpu_features, + + /* Determine if PKU is usable. */ + if (CPU_FEATURES_CPU_P (cpu_features, OSPKE)) +- cpu_features->usable[index_arch_PKU_Usable] +- |= bit_arch_PKU_Usable; ++ CPU_FEATURE_SET (cpu_features, PKU); ++} ++ ++static void ++get_extended_indices (struct cpu_features *cpu_features) ++{ ++ unsigned int eax, ebx, ecx, edx; ++ __cpuid (0x80000000, eax, ebx, ecx, edx); ++ if (eax >= 0x80000001) ++ __cpuid (0x80000001, ++ cpu_features->features[COMMON_CPUID_INDEX_80000001].cpuid.eax, ++ cpu_features->features[COMMON_CPUID_INDEX_80000001].cpuid.ebx, ++ cpu_features->features[COMMON_CPUID_INDEX_80000001].cpuid.ecx, ++ cpu_features->features[COMMON_CPUID_INDEX_80000001].cpuid.edx); ++ if (eax >= 0x80000007) ++ __cpuid (0x80000007, ++ cpu_features->features[COMMON_CPUID_INDEX_80000007].cpuid.eax, ++ cpu_features->features[COMMON_CPUID_INDEX_80000007].cpuid.ebx, ++ cpu_features->features[COMMON_CPUID_INDEX_80000007].cpuid.ecx, ++ cpu_features->features[COMMON_CPUID_INDEX_80000007].cpuid.edx); ++ if (eax >= 0x80000008) ++ __cpuid (0x80000008, ++ cpu_features->features[COMMON_CPUID_INDEX_80000008].cpuid.eax, ++ cpu_features->features[COMMON_CPUID_INDEX_80000008].cpuid.ebx, ++ cpu_features->features[COMMON_CPUID_INDEX_80000008].cpuid.ecx, ++ cpu_features->features[COMMON_CPUID_INDEX_80000008].cpuid.edx); ++} ++ ++static void ++get_common_indices (struct cpu_features *cpu_features, ++ unsigned int *family, unsigned int *model, ++ unsigned int *extended_model, unsigned int *stepping) ++{ ++ if (family) ++ { ++ unsigned int eax; ++ __cpuid (1, eax, ++ cpu_features->features[COMMON_CPUID_INDEX_1].cpuid.ebx, ++ cpu_features->features[COMMON_CPUID_INDEX_1].cpuid.ecx, ++ cpu_features->features[COMMON_CPUID_INDEX_1].cpuid.edx); ++ cpu_features->features[COMMON_CPUID_INDEX_1].cpuid.eax = eax; ++ *family = (eax >> 8) & 0x0f; ++ *model = (eax >> 4) & 0x0f; ++ *extended_model = (eax >> 12) & 0xf0; ++ *stepping = eax & 0x0f; ++ if (*family == 0x0f) ++ { ++ *family += (eax >> 20) & 0xff; ++ *model += *extended_model; ++ } ++ } ++ ++ if (cpu_features->basic.max_cpuid >= 7) ++ { ++ __cpuid_count (7, 0, ++ cpu_features->features[COMMON_CPUID_INDEX_7].cpuid.eax, ++ cpu_features->features[COMMON_CPUID_INDEX_7].cpuid.ebx, ++ cpu_features->features[COMMON_CPUID_INDEX_7].cpuid.ecx, ++ cpu_features->features[COMMON_CPUID_INDEX_7].cpuid.edx); ++ __cpuid_count (7, 1, ++ cpu_features->features[COMMON_CPUID_INDEX_7_ECX_1].cpuid.eax, ++ cpu_features->features[COMMON_CPUID_INDEX_7_ECX_1].cpuid.ebx, ++ cpu_features->features[COMMON_CPUID_INDEX_7_ECX_1].cpuid.ecx, ++ cpu_features->features[COMMON_CPUID_INDEX_7_ECX_1].cpuid.edx); ++ } ++ ++ if (cpu_features->basic.max_cpuid >= 0xd) ++ __cpuid_count (0xd, 1, ++ cpu_features->features[COMMON_CPUID_INDEX_D_ECX_1].cpuid.eax, ++ cpu_features->features[COMMON_CPUID_INDEX_D_ECX_1].cpuid.ebx, ++ cpu_features->features[COMMON_CPUID_INDEX_D_ECX_1].cpuid.ecx, ++ cpu_features->features[COMMON_CPUID_INDEX_D_ECX_1].cpuid.edx); ++ + } + + _Static_assert (((index_arch_Fast_Unaligned_Load +@@ -353,8 +413,6 @@ init_cpu_features (struct cpu_features *cpu_features) + unsigned int stepping = 0; + enum cpu_features_kind kind; + +- cpu_features->usable_p = cpu_features->usable; +- + #if !HAS_CPUID + if (__get_cpuid_max (0, 0) == 0) + { +@@ -377,6 +435,8 @@ init_cpu_features (struct cpu_features *cpu_features) + + get_extended_indices (cpu_features); + ++ update_usable (cpu_features); ++ + if (family == 0x06) + { + model += extended_model; +@@ -473,7 +533,7 @@ init_cpu_features (struct cpu_features *cpu_features) + with stepping >= 4) to avoid TSX on kernels that weren't + updated with the latest microcode package (which disables + broken feature by default). */ +- cpu_features->cpuid[index_cpu_RTM].reg_RTM &= ~bit_cpu_RTM; ++ CPU_FEATURE_UNSET (cpu_features, RTM); + break; + } + } +@@ -501,15 +561,15 @@ init_cpu_features (struct cpu_features *cpu_features) + + get_extended_indices (cpu_features); + +- ecx = cpu_features->cpuid[COMMON_CPUID_INDEX_1].ecx; ++ update_usable (cpu_features); + +- if (HAS_ARCH_FEATURE (AVX_Usable)) ++ ecx = cpu_features->features[COMMON_CPUID_INDEX_1].cpuid.ecx; ++ ++ if (CPU_FEATURE_USABLE_P (cpu_features, AVX)) + { + /* Since the FMA4 bit is in COMMON_CPUID_INDEX_80000001 and + FMA4 requires AVX, determine if FMA4 is usable here. */ +- if (CPU_FEATURES_CPU_P (cpu_features, FMA4)) +- cpu_features->usable[index_arch_FMA4_Usable] +- |= bit_arch_FMA4_Usable; ++ CPU_FEATURE_SET_USABLE (cpu_features, FMA4); + } + + if (family == 0x15) +@@ -540,13 +600,15 @@ init_cpu_features (struct cpu_features *cpu_features) + + get_extended_indices (cpu_features); + ++ update_usable (cpu_features); ++ + model += extended_model; + if (family == 0x6) + { + if (model == 0xf || model == 0x19) + { +- cpu_features->usable[index_arch_AVX_Usable] +- &= ~(bit_arch_AVX_Usable | bit_arch_AVX2_Usable); ++ CPU_FEATURE_UNSET (cpu_features, AVX); ++ CPU_FEATURE_UNSET (cpu_features, AVX2); + + cpu_features->preferred[index_arch_Slow_SSE4_2] + |= bit_arch_Slow_SSE4_2; +@@ -559,8 +621,8 @@ init_cpu_features (struct cpu_features *cpu_features) + { + if (model == 0x1b) + { +- cpu_features->usable[index_arch_AVX_Usable] +- &= ~(bit_arch_AVX_Usable | bit_arch_AVX2_Usable); ++ CPU_FEATURE_UNSET (cpu_features, AVX); ++ CPU_FEATURE_UNSET (cpu_features, AVX2); + + cpu_features->preferred[index_arch_Slow_SSE4_2] + |= bit_arch_Slow_SSE4_2; +@@ -570,8 +632,8 @@ init_cpu_features (struct cpu_features *cpu_features) + } + else if (model == 0x3b) + { +- cpu_features->usable[index_arch_AVX_Usable] +- &= ~(bit_arch_AVX_Usable | bit_arch_AVX2_Usable); ++ CPU_FEATURE_UNSET (cpu_features, AVX); ++ CPU_FEATURE_UNSET (cpu_features, AVX2); + + cpu_features->preferred[index_arch_AVX_Fast_Unaligned_Load] + &= ~bit_arch_AVX_Fast_Unaligned_Load; +@@ -582,6 +644,7 @@ init_cpu_features (struct cpu_features *cpu_features) + { + kind = arch_kind_other; + get_common_indices (cpu_features, NULL, NULL, NULL, NULL); ++ update_usable (cpu_features); + } + + /* Support i586 if CX8 is available. */ +@@ -628,31 +691,30 @@ no_cpuid: + { + const char *platform = NULL; + +- if (CPU_FEATURES_ARCH_P (cpu_features, AVX512F_Usable) +- && CPU_FEATURES_CPU_P (cpu_features, AVX512CD)) ++ if (CPU_FEATURE_USABLE_P (cpu_features, AVX512CD)) + { +- if (CPU_FEATURES_CPU_P (cpu_features, AVX512ER)) ++ if (CPU_FEATURE_USABLE_P (cpu_features, AVX512ER)) + { +- if (CPU_FEATURES_CPU_P (cpu_features, AVX512PF)) ++ if (CPU_FEATURE_USABLE_P (cpu_features, AVX512PF)) + platform = "xeon_phi"; + } + else + { +- if (CPU_FEATURES_CPU_P (cpu_features, AVX512BW) +- && CPU_FEATURES_CPU_P (cpu_features, AVX512DQ) +- && CPU_FEATURES_CPU_P (cpu_features, AVX512VL)) ++ if (CPU_FEATURE_USABLE_P (cpu_features, AVX512BW) ++ && CPU_FEATURE_USABLE_P (cpu_features, AVX512DQ) ++ && CPU_FEATURE_USABLE_P (cpu_features, AVX512VL)) + GLRO(dl_hwcap) |= HWCAP_X86_AVX512_1; + } + } + + if (platform == NULL +- && CPU_FEATURES_ARCH_P (cpu_features, AVX2_Usable) +- && CPU_FEATURES_ARCH_P (cpu_features, FMA_Usable) +- && CPU_FEATURES_CPU_P (cpu_features, BMI1) +- && CPU_FEATURES_CPU_P (cpu_features, BMI2) +- && CPU_FEATURES_CPU_P (cpu_features, LZCNT) +- && CPU_FEATURES_CPU_P (cpu_features, MOVBE) +- && CPU_FEATURES_CPU_P (cpu_features, POPCNT)) ++ && CPU_FEATURE_USABLE_P (cpu_features, AVX2) ++ && CPU_FEATURE_USABLE_P (cpu_features, FMA) ++ && CPU_FEATURE_USABLE_P (cpu_features, BMI1) ++ && CPU_FEATURE_USABLE_P (cpu_features, BMI2) ++ && CPU_FEATURE_USABLE_P (cpu_features, LZCNT) ++ && CPU_FEATURE_USABLE_P (cpu_features, MOVBE) ++ && CPU_FEATURE_USABLE_P (cpu_features, POPCNT)) + platform = "haswell"; + + if (platform != NULL) +@@ -660,7 +722,7 @@ no_cpuid: + } + #else + GLRO(dl_hwcap) = 0; +- if (CPU_FEATURES_CPU_P (cpu_features, SSE2)) ++ if (CPU_FEATURE_USABLE_P (cpu_features, SSE2)) + GLRO(dl_hwcap) |= HWCAP_X86_SSE2; + + if (CPU_FEATURES_ARCH_P (cpu_features, I686)) +@@ -695,9 +757,9 @@ no_cpuid: + GLIBC_TUNABLES=glibc.cpu.hwcaps=-IBT,-SHSTK + */ + unsigned int cet_feature = 0; +- if (!HAS_CPU_FEATURE (IBT)) ++ if (!CPU_FEATURE_USABLE (IBT)) + cet_feature |= GNU_PROPERTY_X86_FEATURE_1_IBT; +- if (!HAS_CPU_FEATURE (SHSTK)) ++ if (!CPU_FEATURE_USABLE (SHSTK)) + cet_feature |= GNU_PROPERTY_X86_FEATURE_1_SHSTK; + + if (cet_feature) +diff --git a/sysdeps/x86/cpu-features.h b/sysdeps/x86/cpu-features.h +index 0f19c64352c4d7f1..21708c028a12dbb2 100644 +--- a/sysdeps/x86/cpu-features.h ++++ b/sysdeps/x86/cpu-features.h +@@ -18,15 +18,6 @@ + #ifndef cpu_features_h + #define cpu_features_h + +-enum +-{ +- /* The integer bit array index for the first set of usable feature +- bits. */ +- USABLE_FEATURE_INDEX_1 = 0, +- /* The current maximum size of the feature integer bit array. */ +- USABLE_FEATURE_INDEX_MAX +-}; +- + enum + { + /* The integer bit array index for the first set of preferred feature +@@ -57,6 +48,12 @@ struct cpuid_registers + unsigned int edx; + }; + ++struct cpuid_features ++{ ++ struct cpuid_registers cpuid; ++ struct cpuid_registers usable; ++}; ++ + enum cpu_features_kind + { + arch_kind_unknown = 0, +@@ -78,9 +75,7 @@ struct cpu_features_basic + struct cpu_features + { + struct cpu_features_basic basic; +- unsigned int *usable_p; +- struct cpuid_registers cpuid[COMMON_CPUID_INDEX_MAX]; +- unsigned int usable[USABLE_FEATURE_INDEX_MAX]; ++ struct cpuid_features features[COMMON_CPUID_INDEX_MAX]; + unsigned int preferred[PREFERRED_FEATURE_INDEX_MAX]; + /* The state size for XSAVEC or XSAVE. The type must be unsigned long + int so that we use +@@ -91,7 +86,7 @@ struct cpu_features + unsigned long int xsave_state_size; + /* The full state size for XSAVE when XSAVEC is disabled by + +- GLIBC_TUNABLES=glibc.cpu.hwcaps=-XSAVEC_Usable ++ GLIBC_TUNABLES=glibc.cpu.hwcaps=-XSAVEC + */ + unsigned int xsave_state_full_size; + /* Data cache size for use in memory and string routines, typically +@@ -114,117 +109,40 @@ extern const struct cpu_features *__get_cpu_features (void) + __attribute__ ((const)); + + /* Only used directly in cpu-features.c. */ +-# define CPU_FEATURES_CPU_P(ptr, name) \ +- ((ptr->cpuid[index_cpu_##name].reg_##name & (bit_cpu_##name)) != 0) +-# define CPU_FEATURES_ARCH_P(ptr, name) \ +- ((ptr->feature_##name[index_arch_##name] & (bit_arch_##name)) != 0) ++#define CPU_FEATURE_CHECK_P(ptr, name, check) \ ++ ((ptr->features[index_cpu_##name].check.reg_##name \ ++ & bit_cpu_##name) != 0) ++#define CPU_FEATURE_SET(ptr, name) \ ++ ptr->features[index_cpu_##name].usable.reg_##name |= bit_cpu_##name; ++#define CPU_FEATURE_UNSET(ptr, name) \ ++ ptr->features[index_cpu_##name].usable.reg_##name &= ~bit_cpu_##name; ++#define CPU_FEATURE_SET_USABLE(ptr, name) \ ++ ptr->features[index_cpu_##name].usable.reg_##name \ ++ |= ptr->features[index_cpu_##name].cpuid.reg_##name & bit_cpu_##name; ++#define CPU_FEATURE_PREFERRED_P(ptr, name) \ ++ ((ptr->preferred[index_arch_##name] & bit_arch_##name) != 0) ++#define CPU_FEATURE_CPU_P(ptr, name) \ ++ CPU_FEATURE_CHECK_P (ptr, name, cpuid) ++#define CPU_FEATURE_USABLE_P(ptr, name) \ ++ CPU_FEATURE_CHECK_P (ptr, name, usable) + + /* HAS_CPU_FEATURE evaluates to true if CPU supports the feature. */ + #define HAS_CPU_FEATURE(name) \ +- CPU_FEATURES_CPU_P (__get_cpu_features (), name) +-/* HAS_ARCH_FEATURE evaluates to true if we may use the feature at +- runtime. */ +-# define HAS_ARCH_FEATURE(name) \ +- CPU_FEATURES_ARCH_P (__get_cpu_features (), name) ++ CPU_FEATURE_CPU_P (__get_cpu_features (), name) + /* CPU_FEATURE_USABLE evaluates to true if the feature is usable. */ + #define CPU_FEATURE_USABLE(name) \ +- HAS_ARCH_FEATURE (name##_Usable) +- +-/* Architecture features. */ +- +-/* USABLE_FEATURE_INDEX_1. */ +-#define bit_arch_AVX_Usable (1u << 0) +-#define bit_arch_AVX2_Usable (1u << 1) +-#define bit_arch_AVX512F_Usable (1u << 2) +-#define bit_arch_AVX512CD_Usable (1u << 3) +-#define bit_arch_AVX512ER_Usable (1u << 4) +-#define bit_arch_AVX512PF_Usable (1u << 5) +-#define bit_arch_AVX512VL_Usable (1u << 6) +-#define bit_arch_AVX512DQ_Usable (1u << 7) +-#define bit_arch_AVX512BW_Usable (1u << 8) +-#define bit_arch_AVX512_4FMAPS_Usable (1u << 9) +-#define bit_arch_AVX512_4VNNIW_Usable (1u << 10) +-#define bit_arch_AVX512_BITALG_Usable (1u << 11) +-#define bit_arch_AVX512_IFMA_Usable (1u << 12) +-#define bit_arch_AVX512_VBMI_Usable (1u << 13) +-#define bit_arch_AVX512_VBMI2_Usable (1u << 14) +-#define bit_arch_AVX512_VNNI_Usable (1u << 15) +-#define bit_arch_AVX512_VPOPCNTDQ_Usable (1u << 16) +-#define bit_arch_FMA_Usable (1u << 17) +-#define bit_arch_FMA4_Usable (1u << 18) +-#define bit_arch_VAES_Usable (1u << 19) +-#define bit_arch_VPCLMULQDQ_Usable (1u << 20) +-#define bit_arch_XOP_Usable (1u << 21) +-#define bit_arch_XSAVEC_Usable (1u << 22) +-#define bit_arch_F16C_Usable (1u << 23) +-#define bit_arch_AVX512_VP2INTERSECT_Usable (1u << 24) +-#define bit_arch_AVX512_BF16_Usable (1u << 25) +-#define bit_arch_PKU_Usable (1u << 26) +-#define bit_arch_AMX_BF16_Usable (1u << 27) +-#define bit_arch_AMX_TILE_Usable (1u << 28) +-#define bit_arch_AMX_INT8_Usable (1u << 29) +- +-#define index_arch_AVX_Usable USABLE_FEATURE_INDEX_1 +-#define index_arch_AVX2_Usable USABLE_FEATURE_INDEX_1 +-#define index_arch_AVX512F_Usable USABLE_FEATURE_INDEX_1 +-#define index_arch_AVX512CD_Usable USABLE_FEATURE_INDEX_1 +-#define index_arch_AVX512ER_Usable USABLE_FEATURE_INDEX_1 +-#define index_arch_AVX512PF_Usable USABLE_FEATURE_INDEX_1 +-#define index_arch_AVX512VL_Usable USABLE_FEATURE_INDEX_1 +-#define index_arch_AVX512BW_Usable USABLE_FEATURE_INDEX_1 +-#define index_arch_AVX512DQ_Usable USABLE_FEATURE_INDEX_1 +-#define index_arch_AVX512_4FMAPS_Usable USABLE_FEATURE_INDEX_1 +-#define index_arch_AVX512_4VNNIW_Usable USABLE_FEATURE_INDEX_1 +-#define index_arch_AVX512_BITALG_Usable USABLE_FEATURE_INDEX_1 +-#define index_arch_AVX512_IFMA_Usable USABLE_FEATURE_INDEX_1 +-#define index_arch_AVX512_VBMI_Usable USABLE_FEATURE_INDEX_1 +-#define index_arch_AVX512_VBMI2_Usable USABLE_FEATURE_INDEX_1 +-#define index_arch_AVX512_VNNI_Usable USABLE_FEATURE_INDEX_1 +-#define index_arch_AVX512_VPOPCNTDQ_Usable USABLE_FEATURE_INDEX_1 +-#define index_arch_FMA_Usable USABLE_FEATURE_INDEX_1 +-#define index_arch_FMA4_Usable USABLE_FEATURE_INDEX_1 +-#define index_arch_VAES_Usable USABLE_FEATURE_INDEX_1 +-#define index_arch_VPCLMULQDQ_Usable USABLE_FEATURE_INDEX_1 +-#define index_arch_XOP_Usable USABLE_FEATURE_INDEX_1 +-#define index_arch_XSAVEC_Usable USABLE_FEATURE_INDEX_1 +-#define index_arch_F16C_Usable USABLE_FEATURE_INDEX_1 +-#define index_arch_AVX512_VP2INTERSECT_Usable USABLE_FEATURE_INDEX_1 +-#define index_arch_AVX512_BF16_Usable USABLE_FEATURE_INDEX_1 +-#define index_arch_PKU_Usable USABLE_FEATURE_INDEX_1 +-#define index_arch_AMX_BF16_Usable USABLE_FEATURE_INDEX_1 +-#define index_arch_AMX_TILE_Usable USABLE_FEATURE_INDEX_1 +-#define index_arch_AMX_INT8_Usable USABLE_FEATURE_INDEX_1 +- +-#define feature_AVX_Usable usable +-#define feature_AVX2_Usable usable +-#define feature_AVX512F_Usable usable +-#define feature_AVX512CD_Usable usable +-#define feature_AVX512ER_Usable usable +-#define feature_AVX512PF_Usable usable +-#define feature_AVX512VL_Usable usable +-#define feature_AVX512BW_Usable usable +-#define feature_AVX512DQ_Usable usable +-#define feature_AVX512_4FMAPS_Usable usable +-#define feature_AVX512_4VNNIW_Usable usable +-#define feature_AVX512_BITALG_Usable usable +-#define feature_AVX512_IFMA_Usable usable +-#define feature_AVX512_VBMI_Usable usable +-#define feature_AVX512_VBMI2_Usable usable +-#define feature_AVX512_VNNI_Usable usable +-#define feature_AVX512_VPOPCNTDQ_Usable usable +-#define feature_FMA_Usable usable +-#define feature_FMA4_Usable usable +-#define feature_VAES_Usable usable +-#define feature_VPCLMULQDQ_Usable usable +-#define feature_XOP_Usable usable +-#define feature_XSAVEC_Usable usable +-#define feature_F16C_Usable usable +-#define feature_AVX512_VP2INTERSECT_Usable usable +-#define feature_AVX512_BF16_Usable usable +-#define feature_PKU_Usable usable +-#define feature_AMX_BF16_Usable usable +-#define feature_AMX_TILE_Usable usable +-#define feature_AMX_INT8_Usable usable ++ CPU_FEATURE_USABLE_P (__get_cpu_features (), name) ++/* CPU_FEATURE_PREFER evaluates to true if we prefer the feature at ++ runtime. */ ++#define CPU_FEATURE_PREFERRED(name) \ ++ CPU_FEATURE_PREFERRED_P(__get_cpu_features (), name) ++ ++#define CPU_FEATURES_CPU_P(ptr, name) \ ++ CPU_FEATURE_CPU_P (ptr, name) ++#define CPU_FEATURES_ARCH_P(ptr, name) \ ++ CPU_FEATURE_PREFERRED_P (ptr, name) ++#define HAS_ARCH_FEATURE(name) \ ++ CPU_FEATURE_PREFERRED (name) + + /* CPU features. */ + +@@ -247,6 +165,7 @@ extern const struct cpu_features *__get_cpu_features (void) + #define bit_cpu_CMPXCHG16B (1u << 13) + #define bit_cpu_XTPRUPDCTRL (1u << 14) + #define bit_cpu_PDCM (1u << 15) ++#define bit_cpu_INDEX_1_ECX_16 (1u << 16) + #define bit_cpu_PCID (1u << 17) + #define bit_cpu_DCA (1u << 18) + #define bit_cpu_SSE4_1 (1u << 19) +@@ -261,6 +180,7 @@ extern const struct cpu_features *__get_cpu_features (void) + #define bit_cpu_AVX (1u << 28) + #define bit_cpu_F16C (1u << 29) + #define bit_cpu_RDRAND (1u << 30) ++#define bit_cpu_INDEX_1_ECX_31 (1u << 31) + + /* EDX. */ + #define bit_cpu_FPU (1u << 0) +@@ -273,6 +193,7 @@ extern const struct cpu_features *__get_cpu_features (void) + #define bit_cpu_MCE (1u << 7) + #define bit_cpu_CX8 (1u << 8) + #define bit_cpu_APIC (1u << 9) ++#define bit_cpu_INDEX_1_EDX_10 (1u << 10) + #define bit_cpu_SEP (1u << 11) + #define bit_cpu_MTRR (1u << 12) + #define bit_cpu_PGE (1u << 13) +@@ -282,6 +203,7 @@ extern const struct cpu_features *__get_cpu_features (void) + #define bit_cpu_PSE_36 (1u << 17) + #define bit_cpu_PSN (1u << 18) + #define bit_cpu_CLFSH (1u << 19) ++#define bit_cpu_INDEX_1_EDX_20 (1u << 20) + #define bit_cpu_DS (1u << 21) + #define bit_cpu_ACPI (1u << 22) + #define bit_cpu_MMX (1u << 23) +@@ -291,6 +213,7 @@ extern const struct cpu_features *__get_cpu_features (void) + #define bit_cpu_SS (1u << 27) + #define bit_cpu_HTT (1u << 28) + #define bit_cpu_TM (1u << 29) ++#define bit_cpu_INDEX_1_EDX_30 (1u << 30) + #define bit_cpu_PBE (1u << 31) + + /* COMMON_CPUID_INDEX_7. */ +@@ -302,12 +225,14 @@ extern const struct cpu_features *__get_cpu_features (void) + #define bit_cpu_BMI1 (1u << 3) + #define bit_cpu_HLE (1u << 4) + #define bit_cpu_AVX2 (1u << 5) ++#define bit_cpu_INDEX_7_EBX_6 (1u << 6) + #define bit_cpu_SMEP (1u << 7) + #define bit_cpu_BMI2 (1u << 8) + #define bit_cpu_ERMS (1u << 9) + #define bit_cpu_INVPCID (1u << 10) + #define bit_cpu_RTM (1u << 11) + #define bit_cpu_PQM (1u << 12) ++#define bit_cpu_DEPR_FPU_CS_DS (1u << 13) + #define bit_cpu_MPX (1u << 14) + #define bit_cpu_PQE (1u << 15) + #define bit_cpu_AVX512F (1u << 16) +@@ -316,6 +241,7 @@ extern const struct cpu_features *__get_cpu_features (void) + #define bit_cpu_ADX (1u << 19) + #define bit_cpu_SMAP (1u << 20) + #define bit_cpu_AVX512_IFMA (1u << 21) ++#define bit_cpu_INDEX_7_EBX_22 (1u << 22) + #define bit_cpu_CLFLUSHOPT (1u << 23) + #define bit_cpu_CLWB (1u << 24) + #define bit_cpu_TRACE (1u << 25) +@@ -340,9 +266,17 @@ extern const struct cpu_features *__get_cpu_features (void) + #define bit_cpu_VPCLMULQDQ (1u << 10) + #define bit_cpu_AVX512_VNNI (1u << 11) + #define bit_cpu_AVX512_BITALG (1u << 12) ++#define bit_cpu_INDEX_7_ECX_13 (1u << 13) + #define bit_cpu_AVX512_VPOPCNTDQ (1u << 14) ++#define bit_cpu_INDEX_7_ECX_15 (1u << 15) ++#define bit_cpu_INDEX_7_ECX_16 (1u << 16) ++/* Note: Bits 17-21: The value of MAWAU used by the BNDLDX and BNDSTX ++ instructions in 64-bit mode. */ + #define bit_cpu_RDPID (1u << 22) ++#define bit_cpu_INDEX_7_ECX_23 (1u << 23) ++#define bit_cpu_INDEX_7_ECX_24 (1u << 24) + #define bit_cpu_CLDEMOTE (1u << 25) ++#define bit_cpu_INDEX_7_ECX_26 (1u << 26) + #define bit_cpu_MOVDIRI (1u << 27) + #define bit_cpu_MOVDIR64B (1u << 28) + #define bit_cpu_ENQCMD (1u << 29) +@@ -350,17 +284,30 @@ extern const struct cpu_features *__get_cpu_features (void) + #define bit_cpu_PKS (1u << 31) + + /* EDX. */ ++#define bit_cpu_INDEX_7_EDX_0 (1u << 0) ++#define bit_cpu_INDEX_7_EDX_1 (1u << 1) + #define bit_cpu_AVX512_4VNNIW (1u << 2) + #define bit_cpu_AVX512_4FMAPS (1u << 3) + #define bit_cpu_FSRM (1u << 4) ++#define bit_cpu_INDEX_7_EDX_5 (1u << 5) ++#define bit_cpu_INDEX_7_EDX_6 (1u << 6) ++#define bit_cpu_INDEX_7_EDX_7 (1u << 7) + #define bit_cpu_AVX512_VP2INTERSECT (1u << 8) ++#define bit_cpu_INDEX_7_EDX_9 (1u << 9) + #define bit_cpu_MD_CLEAR (1u << 10) ++#define bit_cpu_INDEX_7_EDX_11 (1u << 11) ++#define bit_cpu_INDEX_7_EDX_12 (1u << 12) ++#define bit_cpu_INDEX_7_EDX_13 (1u << 13) + #define bit_cpu_SERIALIZE (1u << 14) + #define bit_cpu_HYBRID (1u << 15) + #define bit_cpu_TSXLDTRK (1u << 16) ++#define bit_cpu_INDEX_7_EDX_17 (1u << 17) + #define bit_cpu_PCONFIG (1u << 18) ++#define bit_cpu_INDEX_7_EDX_19 (1u << 19) + #define bit_cpu_IBT (1u << 20) ++#define bit_cpu_INDEX_7_EDX_21 (1u << 21) + #define bit_cpu_AMX_BF16 (1u << 22) ++#define bit_cpu_INDEX_7_EDX_23 (1u << 23) + #define bit_cpu_AMX_TILE (1u << 24) + #define bit_cpu_AMX_INT8 (1u << 25) + #define bit_cpu_IBRS_IBPB (1u << 26) +@@ -433,6 +380,7 @@ extern const struct cpu_features *__get_cpu_features (void) + #define index_cpu_CMPXCHG16B COMMON_CPUID_INDEX_1 + #define index_cpu_XTPRUPDCTRL COMMON_CPUID_INDEX_1 + #define index_cpu_PDCM COMMON_CPUID_INDEX_1 ++#define index_cpu_INDEX_1_ECX_16 COMMON_CPUID_INDEX_1 + #define index_cpu_PCID COMMON_CPUID_INDEX_1 + #define index_cpu_DCA COMMON_CPUID_INDEX_1 + #define index_cpu_SSE4_1 COMMON_CPUID_INDEX_1 +@@ -447,6 +395,7 @@ extern const struct cpu_features *__get_cpu_features (void) + #define index_cpu_AVX COMMON_CPUID_INDEX_1 + #define index_cpu_F16C COMMON_CPUID_INDEX_1 + #define index_cpu_RDRAND COMMON_CPUID_INDEX_1 ++#define index_cpu_INDEX_1_ECX_31 COMMON_CPUID_INDEX_1 + + /* ECX. */ + #define index_cpu_FPU COMMON_CPUID_INDEX_1 +@@ -459,6 +408,7 @@ extern const struct cpu_features *__get_cpu_features (void) + #define index_cpu_MCE COMMON_CPUID_INDEX_1 + #define index_cpu_CX8 COMMON_CPUID_INDEX_1 + #define index_cpu_APIC COMMON_CPUID_INDEX_1 ++#define index_cpu_INDEX_1_EDX_10 COMMON_CPUID_INDEX_1 + #define index_cpu_SEP COMMON_CPUID_INDEX_1 + #define index_cpu_MTRR COMMON_CPUID_INDEX_1 + #define index_cpu_PGE COMMON_CPUID_INDEX_1 +@@ -468,6 +418,7 @@ extern const struct cpu_features *__get_cpu_features (void) + #define index_cpu_PSE_36 COMMON_CPUID_INDEX_1 + #define index_cpu_PSN COMMON_CPUID_INDEX_1 + #define index_cpu_CLFSH COMMON_CPUID_INDEX_1 ++#define index_cpu_INDEX_1_EDX_20 COMMON_CPUID_INDEX_1 + #define index_cpu_DS COMMON_CPUID_INDEX_1 + #define index_cpu_ACPI COMMON_CPUID_INDEX_1 + #define index_cpu_MMX COMMON_CPUID_INDEX_1 +@@ -477,6 +428,7 @@ extern const struct cpu_features *__get_cpu_features (void) + #define index_cpu_SS COMMON_CPUID_INDEX_1 + #define index_cpu_HTT COMMON_CPUID_INDEX_1 + #define index_cpu_TM COMMON_CPUID_INDEX_1 ++#define index_cpu_INDEX_1_EDX_30 COMMON_CPUID_INDEX_1 + #define index_cpu_PBE COMMON_CPUID_INDEX_1 + + /* COMMON_CPUID_INDEX_7. */ +@@ -488,12 +440,14 @@ extern const struct cpu_features *__get_cpu_features (void) + #define index_cpu_BMI1 COMMON_CPUID_INDEX_7 + #define index_cpu_HLE COMMON_CPUID_INDEX_7 + #define index_cpu_AVX2 COMMON_CPUID_INDEX_7 ++#define index_cpu_INDEX_7_EBX_6 COMMON_CPUID_INDEX_7 + #define index_cpu_SMEP COMMON_CPUID_INDEX_7 + #define index_cpu_BMI2 COMMON_CPUID_INDEX_7 + #define index_cpu_ERMS COMMON_CPUID_INDEX_7 + #define index_cpu_INVPCID COMMON_CPUID_INDEX_7 + #define index_cpu_RTM COMMON_CPUID_INDEX_7 + #define index_cpu_PQM COMMON_CPUID_INDEX_7 ++#define index_cpu_DEPR_FPU_CS_DS COMMON_CPUID_INDEX_7 + #define index_cpu_MPX COMMON_CPUID_INDEX_7 + #define index_cpu_PQE COMMON_CPUID_INDEX_7 + #define index_cpu_AVX512F COMMON_CPUID_INDEX_7 +@@ -502,6 +456,7 @@ extern const struct cpu_features *__get_cpu_features (void) + #define index_cpu_ADX COMMON_CPUID_INDEX_7 + #define index_cpu_SMAP COMMON_CPUID_INDEX_7 + #define index_cpu_AVX512_IFMA COMMON_CPUID_INDEX_7 ++#define index_cpu_INDEX_7_EBX_22 COMMON_CPUID_INDEX_7 + #define index_cpu_CLFLUSHOPT COMMON_CPUID_INDEX_7 + #define index_cpu_CLWB COMMON_CPUID_INDEX_7 + #define index_cpu_TRACE COMMON_CPUID_INDEX_7 +@@ -526,9 +481,15 @@ extern const struct cpu_features *__get_cpu_features (void) + #define index_cpu_VPCLMULQDQ COMMON_CPUID_INDEX_7 + #define index_cpu_AVX512_VNNI COMMON_CPUID_INDEX_7 + #define index_cpu_AVX512_BITALG COMMON_CPUID_INDEX_7 ++#define index_cpu_INDEX_7_ECX_13 COMMON_CPUID_INDEX_7 + #define index_cpu_AVX512_VPOPCNTDQ COMMON_CPUID_INDEX_7 ++#define index_cpu_INDEX_7_ECX_15 COMMON_CPUID_INDEX_7 ++#define index_cpu_INDEX_7_ECX_16 COMMON_CPUID_INDEX_7 + #define index_cpu_RDPID COMMON_CPUID_INDEX_7 ++#define index_cpu_INDEX_7_ECX_23 COMMON_CPUID_INDEX_7 ++#define index_cpu_INDEX_7_ECX_24 COMMON_CPUID_INDEX_7 + #define index_cpu_CLDEMOTE COMMON_CPUID_INDEX_7 ++#define index_cpu_INDEX_7_ECX_26 COMMON_CPUID_INDEX_7 + #define index_cpu_MOVDIRI COMMON_CPUID_INDEX_7 + #define index_cpu_MOVDIR64B COMMON_CPUID_INDEX_7 + #define index_cpu_ENQCMD COMMON_CPUID_INDEX_7 +@@ -536,17 +497,30 @@ extern const struct cpu_features *__get_cpu_features (void) + #define index_cpu_PKS COMMON_CPUID_INDEX_7 + + /* EDX. */ ++#define index_cpu_INDEX_7_EDX_0 COMMON_CPUID_INDEX_7 ++#define index_cpu_INDEX_7_EDX_1 COMMON_CPUID_INDEX_7 + #define index_cpu_AVX512_4VNNIW COMMON_CPUID_INDEX_7 + #define index_cpu_AVX512_4FMAPS COMMON_CPUID_INDEX_7 + #define index_cpu_FSRM COMMON_CPUID_INDEX_7 ++#define index_cpu_INDEX_7_EDX_5 COMMON_CPUID_INDEX_7 ++#define index_cpu_INDEX_7_EDX_6 COMMON_CPUID_INDEX_7 ++#define index_cpu_INDEX_7_EDX_7 COMMON_CPUID_INDEX_7 + #define index_cpu_AVX512_VP2INTERSECT COMMON_CPUID_INDEX_7 ++#define index_cpu_INDEX_7_EDX_9 COMMON_CPUID_INDEX_7 + #define index_cpu_MD_CLEAR COMMON_CPUID_INDEX_7 ++#define index_cpu_INDEX_7_EDX_11 COMMON_CPUID_INDEX_7 ++#define index_cpu_INDEX_7_EDX_12 COMMON_CPUID_INDEX_7 ++#define index_cpu_INDEX_7_EDX_13 COMMON_CPUID_INDEX_7 + #define index_cpu_SERIALIZE COMMON_CPUID_INDEX_7 + #define index_cpu_HYBRID COMMON_CPUID_INDEX_7 + #define index_cpu_TSXLDTRK COMMON_CPUID_INDEX_7 ++#define index_cpu_INDEX_7_EDX_17 COMMON_CPUID_INDEX_7 + #define index_cpu_PCONFIG COMMON_CPUID_INDEX_7 ++#define index_cpu_INDEX_7_EDX_19 COMMON_CPUID_INDEX_7 + #define index_cpu_IBT COMMON_CPUID_INDEX_7 ++#define index_cpu_INDEX_7_EDX_21 COMMON_CPUID_INDEX_7 + #define index_cpu_AMX_BF16 COMMON_CPUID_INDEX_7 ++#define index_cpu_INDEX_7_EDX_23 COMMON_CPUID_INDEX_7 + #define index_cpu_AMX_TILE COMMON_CPUID_INDEX_7 + #define index_cpu_AMX_INT8 COMMON_CPUID_INDEX_7 + #define index_cpu_IBRS_IBPB COMMON_CPUID_INDEX_7 +@@ -619,6 +593,7 @@ extern const struct cpu_features *__get_cpu_features (void) + #define reg_CMPXCHG16B ecx + #define reg_XTPRUPDCTRL ecx + #define reg_PDCM ecx ++#define reg_INDEX_1_ECX_16 ecx + #define reg_PCID ecx + #define reg_DCA ecx + #define reg_SSE4_1 ecx +@@ -633,6 +608,7 @@ extern const struct cpu_features *__get_cpu_features (void) + #define reg_AVX ecx + #define reg_F16C ecx + #define reg_RDRAND ecx ++#define reg_INDEX_1_ECX_31 ecx + + /* EDX. */ + #define reg_FPU edx +@@ -645,6 +621,7 @@ extern const struct cpu_features *__get_cpu_features (void) + #define reg_MCE edx + #define reg_CX8 edx + #define reg_APIC edx ++#define reg_INDEX_1_EDX_10 edx + #define reg_SEP edx + #define reg_MTRR edx + #define reg_PGE edx +@@ -654,6 +631,7 @@ extern const struct cpu_features *__get_cpu_features (void) + #define reg_PSE_36 edx + #define reg_PSN edx + #define reg_CLFSH edx ++#define reg_INDEX_1_EDX_20 edx + #define reg_DS edx + #define reg_ACPI edx + #define reg_MMX edx +@@ -663,6 +641,7 @@ extern const struct cpu_features *__get_cpu_features (void) + #define reg_SS edx + #define reg_HTT edx + #define reg_TM edx ++#define reg_INDEX_1_EDX_30 edx + #define reg_PBE edx + + /* COMMON_CPUID_INDEX_7. */ +@@ -675,11 +654,13 @@ extern const struct cpu_features *__get_cpu_features (void) + #define reg_HLE ebx + #define reg_BMI2 ebx + #define reg_AVX2 ebx ++#define reg_INDEX_7_EBX_6 ebx + #define reg_SMEP ebx + #define reg_ERMS ebx + #define reg_INVPCID ebx + #define reg_RTM ebx + #define reg_PQM ebx ++#define reg_DEPR_FPU_CS_DS ebx + #define reg_MPX ebx + #define reg_PQE ebx + #define reg_AVX512F ebx +@@ -688,6 +669,7 @@ extern const struct cpu_features *__get_cpu_features (void) + #define reg_ADX ebx + #define reg_SMAP ebx + #define reg_AVX512_IFMA ebx ++#define reg_INDEX_7_EBX_22 ebx + #define reg_CLFLUSHOPT ebx + #define reg_CLWB ebx + #define reg_TRACE ebx +@@ -712,9 +694,15 @@ extern const struct cpu_features *__get_cpu_features (void) + #define reg_VPCLMULQDQ ecx + #define reg_AVX512_VNNI ecx + #define reg_AVX512_BITALG ecx ++#define reg_INDEX_7_ECX_13 ecx + #define reg_AVX512_VPOPCNTDQ ecx ++#define reg_INDEX_7_ECX_15 ecx ++#define reg_INDEX_7_ECX_16 ecx + #define reg_RDPID ecx ++#define reg_INDEX_7_ECX_23 ecx ++#define reg_INDEX_7_ECX_24 ecx + #define reg_CLDEMOTE ecx ++#define reg_INDEX_7_ECX_26 ecx + #define reg_MOVDIRI ecx + #define reg_MOVDIR64B ecx + #define reg_ENQCMD ecx +@@ -722,17 +710,30 @@ extern const struct cpu_features *__get_cpu_features (void) + #define reg_PKS ecx + + /* EDX. */ ++#define reg_INDEX_7_EDX_0 edx ++#define reg_INDEX_7_EDX_1 edx + #define reg_AVX512_4VNNIW edx + #define reg_AVX512_4FMAPS edx + #define reg_FSRM edx ++#define reg_INDEX_7_EDX_5 edx ++#define reg_INDEX_7_EDX_6 edx ++#define reg_INDEX_7_EDX_7 edx + #define reg_AVX512_VP2INTERSECT edx ++#define reg_INDEX_7_EDX_9 edx + #define reg_MD_CLEAR edx ++#define reg_INDEX_7_EDX_11 edx ++#define reg_INDEX_7_EDX_12 edx ++#define reg_INDEX_7_EDX_13 edx + #define reg_SERIALIZE edx + #define reg_HYBRID edx + #define reg_TSXLDTRK edx ++#define reg_INDEX_7_EDX_17 edx + #define reg_PCONFIG edx ++#define reg_INDEX_7_EDX_19 edx + #define reg_IBT edx ++#define reg_INDEX_7_EDX_21 edx + #define reg_AMX_BF16 edx ++#define reg_INDEX_7_EDX_23 edx + #define reg_AMX_TILE edx + #define reg_AMX_INT8 edx + #define reg_IBRS_IBPB edx +@@ -821,23 +822,6 @@ extern const struct cpu_features *__get_cpu_features (void) + #define index_arch_MathVec_Prefer_No_AVX512 PREFERRED_FEATURE_INDEX_1 + #define index_arch_Prefer_FSRM PREFERRED_FEATURE_INDEX_1 + +-#define feature_Fast_Rep_String preferred +-#define feature_Fast_Copy_Backward preferred +-#define feature_Slow_BSF preferred +-#define feature_Fast_Unaligned_Load preferred +-#define feature_Prefer_PMINUB_for_stringop preferred +-#define feature_Fast_Unaligned_Copy preferred +-#define feature_I586 preferred +-#define feature_I686 preferred +-#define feature_Slow_SSE4_2 preferred +-#define feature_AVX_Fast_Unaligned_Load preferred +-#define feature_Prefer_MAP_32BIT_EXEC preferred +-#define feature_Prefer_No_VZEROUPPER preferred +-#define feature_Prefer_ERMS preferred +-#define feature_Prefer_No_AVX512 preferred +-#define feature_MathVec_Prefer_No_AVX512 preferred +-#define feature_Prefer_FSRM preferred +- + /* XCR0 Feature flags. */ + #define bit_XMM_state (1u << 1) + #define bit_YMM_state (1u << 2) +@@ -851,8 +835,6 @@ extern const struct cpu_features *__get_cpu_features (void) + /* Unused for x86. */ + # define INIT_ARCH() + # define __get_cpu_features() (&GLRO(dl_x86_cpu_features)) +-# define x86_get_cpuid_registers(i) \ +- (&(GLRO(dl_x86_cpu_features).cpuid[i])) + # endif + + #ifdef __x86_64__ +diff --git a/sysdeps/x86/cpu-tunables.c b/sysdeps/x86/cpu-tunables.c +index 012ae48933055eaa..0728023007a0f423 100644 +--- a/sysdeps/x86/cpu-tunables.c ++++ b/sysdeps/x86/cpu-tunables.c +@@ -43,66 +43,45 @@ extern __typeof (memcmp) DEFAULT_MEMCMP; + _Static_assert (sizeof (#name) - 1 == len, #name " != " #len); \ + if (!DEFAULT_MEMCMP (f, #name, len)) \ + { \ +- cpu_features->cpuid[index_cpu_##name].reg_##name \ +- &= ~bit_cpu_##name; \ ++ CPU_FEATURE_UNSET (cpu_features, name) \ + break; \ + } + +-/* Disable an ARCH feature NAME. We don't enable an ARCH feature which +- isn't available. */ +-# define CHECK_GLIBC_IFUNC_ARCH_OFF(f, cpu_features, name, len) \ ++/* Disable a preferred feature NAME. We don't enable a preferred feature ++ which isn't available. */ ++# define CHECK_GLIBC_IFUNC_PREFERRED_OFF(f, cpu_features, name, len) \ + _Static_assert (sizeof (#name) - 1 == len, #name " != " #len); \ + if (!DEFAULT_MEMCMP (f, #name, len)) \ + { \ +- cpu_features->feature_##name[index_arch_##name] \ ++ cpu_features->preferred[index_arch_##name] \ + &= ~bit_arch_##name; \ + break; \ + } + +-/* Enable/disable an ARCH feature NAME. */ +-# define CHECK_GLIBC_IFUNC_ARCH_BOTH(f, cpu_features, name, disable, \ +- len) \ ++/* Enable/disable a preferred feature NAME. */ ++# define CHECK_GLIBC_IFUNC_PREFERRED_BOTH(f, cpu_features, name, \ ++ disable, len) \ + _Static_assert (sizeof (#name) - 1 == len, #name " != " #len); \ + if (!DEFAULT_MEMCMP (f, #name, len)) \ + { \ + if (disable) \ +- cpu_features->feature_##name[index_arch_##name] \ +- &= ~bit_arch_##name; \ ++ cpu_features->preferred[index_arch_##name] &= ~bit_arch_##name; \ + else \ +- cpu_features->feature_##name[index_arch_##name] \ +- |= bit_arch_##name; \ ++ cpu_features->preferred[index_arch_##name] |= bit_arch_##name; \ + break; \ + } + +-/* Enable/disable an ARCH feature NAME. Enable an ARCH feature only +- if the ARCH feature NEED is also enabled. */ +-# define CHECK_GLIBC_IFUNC_ARCH_NEED_ARCH_BOTH(f, cpu_features, name, \ ++/* Enable/disable a preferred feature NAME. Enable a preferred feature ++ only if the feature NEED is usable. */ ++# define CHECK_GLIBC_IFUNC_PREFERRED_NEED_BOTH(f, cpu_features, name, \ + need, disable, len) \ + _Static_assert (sizeof (#name) - 1 == len, #name " != " #len); \ + if (!DEFAULT_MEMCMP (f, #name, len)) \ + { \ + if (disable) \ +- cpu_features->feature_##name[index_arch_##name] \ +- &= ~bit_arch_##name; \ +- else if (CPU_FEATURES_ARCH_P (cpu_features, need)) \ +- cpu_features->feature_##name[index_arch_##name] \ +- |= bit_arch_##name; \ +- break; \ +- } +- +-/* Enable/disable an ARCH feature NAME. Enable an ARCH feature only +- if the CPU feature NEED is also enabled. */ +-# define CHECK_GLIBC_IFUNC_ARCH_NEED_CPU_BOTH(f, cpu_features, name, \ +- need, disable, len) \ +- _Static_assert (sizeof (#name) - 1 == len, #name " != " #len); \ +- if (!DEFAULT_MEMCMP (f, #name, len)) \ +- { \ +- if (disable) \ +- cpu_features->feature_##name[index_arch_##name] \ +- &= ~bit_arch_##name; \ +- else if (CPU_FEATURES_CPU_P (cpu_features, need)) \ +- cpu_features->feature_##name[index_arch_##name] \ +- |= bit_arch_##name; \ ++ cpu_features->preferred[index_arch_##name] &= ~bit_arch_##name; \ ++ else if (CPU_FEATURE_USABLE_P (cpu_features, need)) \ ++ cpu_features->preferred[index_arch_##name] |= bit_arch_##name; \ + break; \ + } + +@@ -178,8 +157,8 @@ TUNABLE_CALLBACK (set_hwcaps) (tunable_val_t *valp) + CHECK_GLIBC_IFUNC_CPU_OFF (n, cpu_features, ERMS, 4); + CHECK_GLIBC_IFUNC_CPU_OFF (n, cpu_features, FMA4, 4); + CHECK_GLIBC_IFUNC_CPU_OFF (n, cpu_features, SSE2, 4); +- CHECK_GLIBC_IFUNC_ARCH_OFF (n, cpu_features, I586, 4); +- CHECK_GLIBC_IFUNC_ARCH_OFF (n, cpu_features, I686, 4); ++ CHECK_GLIBC_IFUNC_PREFERRED_OFF (n, cpu_features, I586, 4); ++ CHECK_GLIBC_IFUNC_PREFERRED_OFF (n, cpu_features, I686, 4); + } + break; + case 5: +@@ -197,6 +176,13 @@ TUNABLE_CALLBACK (set_hwcaps) (tunable_val_t *valp) + CHECK_GLIBC_IFUNC_CPU_OFF (n, cpu_features, POPCNT, 6); + CHECK_GLIBC_IFUNC_CPU_OFF (n, cpu_features, SSE4_1, 6); + CHECK_GLIBC_IFUNC_CPU_OFF (n, cpu_features, SSE4_2, 6); ++ if (!DEFAULT_MEMCMP (n, "XSAVEC", 6)) ++ { ++ /* Update xsave_state_size to XSAVE state size. */ ++ cpu_features->xsave_state_size ++ = cpu_features->xsave_state_full_size; ++ CPU_FEATURE_UNSET (cpu_features, XSAVEC); ++ } + } + break; + case 7: +@@ -216,115 +202,85 @@ TUNABLE_CALLBACK (set_hwcaps) (tunable_val_t *valp) + CHECK_GLIBC_IFUNC_CPU_OFF (n, cpu_features, AVX512PF, 8); + CHECK_GLIBC_IFUNC_CPU_OFF (n, cpu_features, AVX512VL, 8); + } +- CHECK_GLIBC_IFUNC_ARCH_BOTH (n, cpu_features, Slow_BSF, +- disable, 8); +- break; +- case 10: +- if (disable) +- { +- CHECK_GLIBC_IFUNC_ARCH_OFF (n, cpu_features, AVX_Usable, +- 10); +- CHECK_GLIBC_IFUNC_ARCH_OFF (n, cpu_features, FMA_Usable, +- 10); +- } ++ CHECK_GLIBC_IFUNC_PREFERRED_BOTH (n, cpu_features, Slow_BSF, ++ disable, 8); + break; + case 11: +- if (disable) + { +- CHECK_GLIBC_IFUNC_ARCH_OFF (n, cpu_features, AVX2_Usable, +- 11); +- CHECK_GLIBC_IFUNC_ARCH_OFF (n, cpu_features, FMA4_Usable, +- 11); +- } +- CHECK_GLIBC_IFUNC_ARCH_BOTH (n, cpu_features, Prefer_ERMS, +- disable, 11); +- CHECK_GLIBC_IFUNC_ARCH_NEED_CPU_BOTH (n, cpu_features, +- Slow_SSE4_2, SSE4_2, ++ CHECK_GLIBC_IFUNC_PREFERRED_BOTH (n, cpu_features, ++ Prefer_ERMS, + disable, 11); +- CHECK_GLIBC_IFUNC_ARCH_BOTH (n, cpu_features, Prefer_FSRM, +- disable, 11); +- break; +- case 13: +- if (disable) +- { +- /* Update xsave_state_size to XSAVE state size. */ +- cpu_features->xsave_state_size +- = cpu_features->xsave_state_full_size; +- CHECK_GLIBC_IFUNC_ARCH_OFF (n, cpu_features, +- XSAVEC_Usable, 13); +- } +- break; +- case 14: +- if (disable) +- { +- CHECK_GLIBC_IFUNC_ARCH_OFF (n, cpu_features, +- AVX512F_Usable, 14); ++ CHECK_GLIBC_IFUNC_PREFERRED_BOTH (n, cpu_features, ++ Prefer_FSRM, ++ disable, 11); ++ CHECK_GLIBC_IFUNC_PREFERRED_NEED_BOTH (n, cpu_features, ++ Slow_SSE4_2, ++ SSE4_2, ++ disable, 11); + } + break; + case 15: +- if (disable) + { +- CHECK_GLIBC_IFUNC_ARCH_OFF (n, cpu_features, +- AVX512DQ_Usable, 15); ++ CHECK_GLIBC_IFUNC_PREFERRED_BOTH (n, cpu_features, ++ Fast_Rep_String, ++ disable, 15); + } +- CHECK_GLIBC_IFUNC_ARCH_BOTH (n, cpu_features, Fast_Rep_String, +- disable, 15); + break; + case 16: + { +- CHECK_GLIBC_IFUNC_ARCH_NEED_ARCH_BOTH +- (n, cpu_features, Prefer_No_AVX512, AVX512F_Usable, ++ CHECK_GLIBC_IFUNC_PREFERRED_NEED_BOTH ++ (n, cpu_features, Prefer_No_AVX512, AVX512F, + disable, 16); + } + break; + case 18: + { +- CHECK_GLIBC_IFUNC_ARCH_BOTH (n, cpu_features, +- Fast_Copy_Backward, disable, +- 18); ++ CHECK_GLIBC_IFUNC_PREFERRED_BOTH (n, cpu_features, ++ Fast_Copy_Backward, ++ disable, 18); + } + break; + case 19: + { +- CHECK_GLIBC_IFUNC_ARCH_BOTH (n, cpu_features, +- Fast_Unaligned_Load, disable, +- 19); +- CHECK_GLIBC_IFUNC_ARCH_BOTH (n, cpu_features, +- Fast_Unaligned_Copy, disable, +- 19); ++ CHECK_GLIBC_IFUNC_PREFERRED_BOTH (n, cpu_features, ++ Fast_Unaligned_Load, ++ disable, 19); ++ CHECK_GLIBC_IFUNC_PREFERRED_BOTH (n, cpu_features, ++ Fast_Unaligned_Copy, ++ disable, 19); + } + break; + case 20: + { +- CHECK_GLIBC_IFUNC_ARCH_NEED_ARCH_BOTH +- (n, cpu_features, Prefer_No_VZEROUPPER, AVX_Usable, +- disable, 20); ++ CHECK_GLIBC_IFUNC_PREFERRED_NEED_BOTH ++ (n, cpu_features, Prefer_No_VZEROUPPER, AVX, disable, ++ 20); + } + break; + case 21: + { +- CHECK_GLIBC_IFUNC_ARCH_BOTH (n, cpu_features, +- Prefer_MAP_32BIT_EXEC, disable, +- 21); ++ CHECK_GLIBC_IFUNC_PREFERRED_BOTH (n, cpu_features, ++ Prefer_MAP_32BIT_EXEC, ++ disable, 21); + } + break; + case 23: + { +- CHECK_GLIBC_IFUNC_ARCH_NEED_ARCH_BOTH +- (n, cpu_features, AVX_Fast_Unaligned_Load, AVX_Usable, ++ CHECK_GLIBC_IFUNC_PREFERRED_NEED_BOTH ++ (n, cpu_features, AVX_Fast_Unaligned_Load, AVX, + disable, 23); + } + break; + case 24: + { +- CHECK_GLIBC_IFUNC_ARCH_NEED_ARCH_BOTH +- (n, cpu_features, MathVec_Prefer_No_AVX512, +- AVX512F_Usable, disable, 24); ++ CHECK_GLIBC_IFUNC_PREFERRED_NEED_BOTH ++ (n, cpu_features, MathVec_Prefer_No_AVX512, AVX512F, ++ disable, 24); + } + break; + case 26: + { +- CHECK_GLIBC_IFUNC_ARCH_NEED_CPU_BOTH ++ CHECK_GLIBC_IFUNC_PREFERRED_NEED_BOTH + (n, cpu_features, Prefer_PMINUB_for_stringop, SSE2, + disable, 26); + } +diff --git a/sysdeps/x86/dl-cet.c b/sysdeps/x86/dl-cet.c +index d481bddc27e5d7cc..11ff0618fae7230f 100644 +--- a/sysdeps/x86/dl-cet.c ++++ b/sysdeps/x86/dl-cet.c +@@ -74,10 +74,10 @@ dl_cet_check (struct link_map *m, const char *program) + + GLIBC_TUNABLES=glibc.cpu.hwcaps=-IBT,-SHSTK + */ +- enable_ibt &= (HAS_CPU_FEATURE (IBT) ++ enable_ibt &= (CPU_FEATURE_USABLE (IBT) + && (enable_ibt_type == cet_always_on + || (m->l_cet & lc_ibt) != 0)); +- enable_shstk &= (HAS_CPU_FEATURE (SHSTK) ++ enable_shstk &= (CPU_FEATURE_USABLE (SHSTK) + && (enable_shstk_type == cet_always_on + || (m->l_cet & lc_shstk) != 0)); + } +diff --git a/sysdeps/x86/tst-get-cpu-features.c b/sysdeps/x86/tst-get-cpu-features.c +index c56f309ba0736c0d..85ec9d5a091e2c88 100644 +--- a/sysdeps/x86/tst-get-cpu-features.c ++++ b/sysdeps/x86/tst-get-cpu-features.c +@@ -137,6 +137,7 @@ do_test (void) + CHECK_CPU_FEATURE (INVPCID); + CHECK_CPU_FEATURE (RTM); + CHECK_CPU_FEATURE (PQM); ++ CHECK_CPU_FEATURE (DEPR_FPU_CS_DS); + CHECK_CPU_FEATURE (MPX); + CHECK_CPU_FEATURE (PQE); + CHECK_CPU_FEATURE (AVX512F); +@@ -218,35 +219,156 @@ do_test (void) + CHECK_CPU_FEATURE (AVX512_BF16); + + printf ("Usable CPU features:\n"); ++ CHECK_CPU_FEATURE_USABLE (SSE3); ++ CHECK_CPU_FEATURE_USABLE (PCLMULQDQ); ++ CHECK_CPU_FEATURE_USABLE (DTES64); ++ CHECK_CPU_FEATURE_USABLE (MONITOR); ++ CHECK_CPU_FEATURE_USABLE (DS_CPL); ++ CHECK_CPU_FEATURE_USABLE (VMX); ++ CHECK_CPU_FEATURE_USABLE (SMX); ++ CHECK_CPU_FEATURE_USABLE (EST); ++ CHECK_CPU_FEATURE_USABLE (TM2); ++ CHECK_CPU_FEATURE_USABLE (SSSE3); ++ CHECK_CPU_FEATURE_USABLE (CNXT_ID); ++ CHECK_CPU_FEATURE_USABLE (SDBG); + CHECK_CPU_FEATURE_USABLE (FMA); ++ CHECK_CPU_FEATURE_USABLE (CMPXCHG16B); ++ CHECK_CPU_FEATURE_USABLE (XTPRUPDCTRL); ++ CHECK_CPU_FEATURE_USABLE (PDCM); ++ CHECK_CPU_FEATURE_USABLE (PCID); ++ CHECK_CPU_FEATURE_USABLE (DCA); ++ CHECK_CPU_FEATURE_USABLE (SSE4_1); ++ CHECK_CPU_FEATURE_USABLE (SSE4_2); ++ CHECK_CPU_FEATURE_USABLE (X2APIC); ++ CHECK_CPU_FEATURE_USABLE (MOVBE); ++ CHECK_CPU_FEATURE_USABLE (POPCNT); ++ CHECK_CPU_FEATURE_USABLE (TSC_DEADLINE); ++ CHECK_CPU_FEATURE_USABLE (AES); ++ CHECK_CPU_FEATURE_USABLE (XSAVE); ++ CHECK_CPU_FEATURE_USABLE (OSXSAVE); + CHECK_CPU_FEATURE_USABLE (AVX); + CHECK_CPU_FEATURE_USABLE (F16C); ++ CHECK_CPU_FEATURE_USABLE (RDRAND); ++ CHECK_CPU_FEATURE_USABLE (FPU); ++ CHECK_CPU_FEATURE_USABLE (VME); ++ CHECK_CPU_FEATURE_USABLE (DE); ++ CHECK_CPU_FEATURE_USABLE (PSE); ++ CHECK_CPU_FEATURE_USABLE (TSC); ++ CHECK_CPU_FEATURE_USABLE (MSR); ++ CHECK_CPU_FEATURE_USABLE (PAE); ++ CHECK_CPU_FEATURE_USABLE (MCE); ++ CHECK_CPU_FEATURE_USABLE (CX8); ++ CHECK_CPU_FEATURE_USABLE (APIC); ++ CHECK_CPU_FEATURE_USABLE (SEP); ++ CHECK_CPU_FEATURE_USABLE (MTRR); ++ CHECK_CPU_FEATURE_USABLE (PGE); ++ CHECK_CPU_FEATURE_USABLE (MCA); ++ CHECK_CPU_FEATURE_USABLE (CMOV); ++ CHECK_CPU_FEATURE_USABLE (PAT); ++ CHECK_CPU_FEATURE_USABLE (PSE_36); ++ CHECK_CPU_FEATURE_USABLE (PSN); ++ CHECK_CPU_FEATURE_USABLE (CLFSH); ++ CHECK_CPU_FEATURE_USABLE (DS); ++ CHECK_CPU_FEATURE_USABLE (ACPI); ++ CHECK_CPU_FEATURE_USABLE (MMX); ++ CHECK_CPU_FEATURE_USABLE (FXSR); ++ CHECK_CPU_FEATURE_USABLE (SSE); ++ CHECK_CPU_FEATURE_USABLE (SSE2); ++ CHECK_CPU_FEATURE_USABLE (SS); ++ CHECK_CPU_FEATURE_USABLE (HTT); ++ CHECK_CPU_FEATURE_USABLE (TM); ++ CHECK_CPU_FEATURE_USABLE (PBE); ++ CHECK_CPU_FEATURE_USABLE (FSGSBASE); ++ CHECK_CPU_FEATURE_USABLE (TSC_ADJUST); ++ CHECK_CPU_FEATURE_USABLE (SGX); ++ CHECK_CPU_FEATURE_USABLE (BMI1); ++ CHECK_CPU_FEATURE_USABLE (HLE); + CHECK_CPU_FEATURE_USABLE (AVX2); ++ CHECK_CPU_FEATURE_USABLE (SMEP); ++ CHECK_CPU_FEATURE_USABLE (BMI2); ++ CHECK_CPU_FEATURE_USABLE (ERMS); ++ CHECK_CPU_FEATURE_USABLE (INVPCID); ++ CHECK_CPU_FEATURE_USABLE (RTM); ++ CHECK_CPU_FEATURE_USABLE (PQM); ++ CHECK_CPU_FEATURE_USABLE (DEPR_FPU_CS_DS); ++ CHECK_CPU_FEATURE_USABLE (MPX); ++ CHECK_CPU_FEATURE_USABLE (PQE); + CHECK_CPU_FEATURE_USABLE (AVX512F); + CHECK_CPU_FEATURE_USABLE (AVX512DQ); ++ CHECK_CPU_FEATURE_USABLE (RDSEED); ++ CHECK_CPU_FEATURE_USABLE (ADX); ++ CHECK_CPU_FEATURE_USABLE (SMAP); + CHECK_CPU_FEATURE_USABLE (AVX512_IFMA); ++ CHECK_CPU_FEATURE_USABLE (CLFLUSHOPT); ++ CHECK_CPU_FEATURE_USABLE (CLWB); ++ CHECK_CPU_FEATURE_USABLE (TRACE); + CHECK_CPU_FEATURE_USABLE (AVX512PF); + CHECK_CPU_FEATURE_USABLE (AVX512ER); + CHECK_CPU_FEATURE_USABLE (AVX512CD); ++ CHECK_CPU_FEATURE_USABLE (SHA); + CHECK_CPU_FEATURE_USABLE (AVX512BW); + CHECK_CPU_FEATURE_USABLE (AVX512VL); ++ CHECK_CPU_FEATURE_USABLE (PREFETCHWT1); + CHECK_CPU_FEATURE_USABLE (AVX512_VBMI); ++ CHECK_CPU_FEATURE_USABLE (UMIP); + CHECK_CPU_FEATURE_USABLE (PKU); ++ CHECK_CPU_FEATURE_USABLE (OSPKE); ++ CHECK_CPU_FEATURE_USABLE (WAITPKG); + CHECK_CPU_FEATURE_USABLE (AVX512_VBMI2); ++ CHECK_CPU_FEATURE_USABLE (SHSTK); ++ CHECK_CPU_FEATURE_USABLE (GFNI); + CHECK_CPU_FEATURE_USABLE (VAES); + CHECK_CPU_FEATURE_USABLE (VPCLMULQDQ); + CHECK_CPU_FEATURE_USABLE (AVX512_VNNI); + CHECK_CPU_FEATURE_USABLE (AVX512_BITALG); + CHECK_CPU_FEATURE_USABLE (AVX512_VPOPCNTDQ); ++ CHECK_CPU_FEATURE_USABLE (RDPID); ++ CHECK_CPU_FEATURE_USABLE (CLDEMOTE); ++ CHECK_CPU_FEATURE_USABLE (MOVDIRI); ++ CHECK_CPU_FEATURE_USABLE (MOVDIR64B); ++ CHECK_CPU_FEATURE_USABLE (ENQCMD); ++ CHECK_CPU_FEATURE_USABLE (SGX_LC); ++ CHECK_CPU_FEATURE_USABLE (PKS); + CHECK_CPU_FEATURE_USABLE (AVX512_4VNNIW); + CHECK_CPU_FEATURE_USABLE (AVX512_4FMAPS); ++ CHECK_CPU_FEATURE_USABLE (FSRM); + CHECK_CPU_FEATURE_USABLE (AVX512_VP2INTERSECT); ++ CHECK_CPU_FEATURE_USABLE (MD_CLEAR); ++ CHECK_CPU_FEATURE_USABLE (SERIALIZE); ++ CHECK_CPU_FEATURE_USABLE (HYBRID); ++ CHECK_CPU_FEATURE_USABLE (TSXLDTRK); ++ CHECK_CPU_FEATURE_USABLE (PCONFIG); ++ CHECK_CPU_FEATURE_USABLE (IBT); + CHECK_CPU_FEATURE_USABLE (AMX_BF16); + CHECK_CPU_FEATURE_USABLE (AMX_TILE); + CHECK_CPU_FEATURE_USABLE (AMX_INT8); ++ CHECK_CPU_FEATURE_USABLE (IBRS_IBPB); ++ CHECK_CPU_FEATURE_USABLE (STIBP); ++ CHECK_CPU_FEATURE_USABLE (L1D_FLUSH); ++ CHECK_CPU_FEATURE_USABLE (ARCH_CAPABILITIES); ++ CHECK_CPU_FEATURE_USABLE (CORE_CAPABILITIES); ++ CHECK_CPU_FEATURE_USABLE (SSBD); ++ CHECK_CPU_FEATURE_USABLE (LAHF64_SAHF64); ++ CHECK_CPU_FEATURE_USABLE (SVM); ++ CHECK_CPU_FEATURE_USABLE (LZCNT); ++ CHECK_CPU_FEATURE_USABLE (SSE4A); ++ CHECK_CPU_FEATURE_USABLE (PREFETCHW); + CHECK_CPU_FEATURE_USABLE (XOP); ++ CHECK_CPU_FEATURE_USABLE (LWP); + CHECK_CPU_FEATURE_USABLE (FMA4); ++ CHECK_CPU_FEATURE_USABLE (TBM); ++ CHECK_CPU_FEATURE_USABLE (SYSCALL_SYSRET); ++ CHECK_CPU_FEATURE_USABLE (NX); ++ CHECK_CPU_FEATURE_USABLE (PAGE1GB); ++ CHECK_CPU_FEATURE_USABLE (RDTSCP); ++ CHECK_CPU_FEATURE_USABLE (LM); ++ CHECK_CPU_FEATURE_USABLE (XSAVEOPT); + CHECK_CPU_FEATURE_USABLE (XSAVEC); ++ CHECK_CPU_FEATURE_USABLE (XGETBV_ECX_1); ++ CHECK_CPU_FEATURE_USABLE (XSAVES); ++ CHECK_CPU_FEATURE_USABLE (XFD); ++ CHECK_CPU_FEATURE_USABLE (INVARIANT_TSC); ++ CHECK_CPU_FEATURE_USABLE (WBNOINVD); + CHECK_CPU_FEATURE_USABLE (AVX512_BF16); + + return 0; +diff --git a/sysdeps/x86_64/Makefile b/sysdeps/x86_64/Makefile +index e3bb45d78811d70f..42b97c5cc73892cc 100644 +--- a/sysdeps/x86_64/Makefile ++++ b/sysdeps/x86_64/Makefile +@@ -57,7 +57,7 @@ modules-names += x86_64/tst-x86_64mod-1 + LDFLAGS-tst-x86_64mod-1.so = -Wl,-soname,tst-x86_64mod-1.so + ifneq (no,$(have-tunables)) + # Test the state size for XSAVE when XSAVEC is disabled. +-tst-x86_64-1-ENV = GLIBC_TUNABLES=glibc.cpu.hwcaps=-XSAVEC_Usable ++tst-x86_64-1-ENV = GLIBC_TUNABLES=glibc.cpu.hwcaps=-XSAVEC + endif + + $(objpfx)tst-x86_64-1: $(objpfx)x86_64/tst-x86_64mod-1.so +@@ -71,10 +71,10 @@ CFLAGS-tst-platformmod-2.c = -mno-avx + LDFLAGS-tst-platformmod-2.so = -Wl,-soname,tst-platformmod-2.so + $(objpfx)tst-platform-1: $(objpfx)tst-platformmod-1.so + $(objpfx)tst-platform-1.out: $(objpfx)x86_64/tst-platformmod-2.so +-# Turn off AVX512F_Usable and AVX2_Usable so that GLRO(dl_platform) is ++# Turn off AVX512F and AVX2 so that GLRO(dl_platform) is + # always set to x86_64. + tst-platform-1-ENV = LD_PRELOAD=$(objpfx)\$$PLATFORM/tst-platformmod-2.so \ +- GLIBC_TUNABLES=glibc.cpu.hwcaps=-AVX512F_Usable,-AVX2_Usable ++ GLIBC_TUNABLES=glibc.cpu.hwcaps=-AVX512F,-AVX2 + endif + + tests += tst-audit3 tst-audit4 tst-audit5 tst-audit6 tst-audit7 \ +diff --git a/sysdeps/x86_64/dl-machine.h b/sysdeps/x86_64/dl-machine.h +index 23afb3c05dbe17d6..d58298d787ef352c 100644 +--- a/sysdeps/x86_64/dl-machine.h ++++ b/sysdeps/x86_64/dl-machine.h +@@ -99,9 +99,9 @@ elf_machine_runtime_setup (struct link_map *l, int lazy, int profile) + end in this function. */ + if (__glibc_unlikely (profile)) + { +- if (HAS_ARCH_FEATURE (AVX512F_Usable)) ++ if (CPU_FEATURE_USABLE (AVX512F)) + *(ElfW(Addr) *) (got + 2) = (ElfW(Addr)) &_dl_runtime_profile_avx512; +- else if (HAS_ARCH_FEATURE (AVX_Usable)) ++ else if (CPU_FEATURE_USABLE (AVX)) + *(ElfW(Addr) *) (got + 2) = (ElfW(Addr)) &_dl_runtime_profile_avx; + else + *(ElfW(Addr) *) (got + 2) = (ElfW(Addr)) &_dl_runtime_profile_sse; +@@ -119,7 +119,7 @@ elf_machine_runtime_setup (struct link_map *l, int lazy, int profile) + the resolved address. */ + if (GLRO(dl_x86_cpu_features).xsave_state_size != 0) + *(ElfW(Addr) *) (got + 2) +- = (HAS_ARCH_FEATURE (XSAVEC_Usable) ++ = (CPU_FEATURE_USABLE (XSAVEC) + ? (ElfW(Addr)) &_dl_runtime_resolve_xsavec + : (ElfW(Addr)) &_dl_runtime_resolve_xsave); + else +diff --git a/sysdeps/x86_64/fpu/math-tests-arch.h b/sysdeps/x86_64/fpu/math-tests-arch.h +index a5df133292ce39b0..61955d70863321fd 100644 +--- a/sysdeps/x86_64/fpu/math-tests-arch.h ++++ b/sysdeps/x86_64/fpu/math-tests-arch.h +@@ -24,7 +24,7 @@ + # define CHECK_ARCH_EXT \ + do \ + { \ +- if (!HAS_ARCH_FEATURE (AVX_Usable)) return; \ ++ if (!CPU_FEATURE_USABLE (AVX)) return; \ + } \ + while (0) + +@@ -34,7 +34,7 @@ + # define CHECK_ARCH_EXT \ + do \ + { \ +- if (!HAS_ARCH_FEATURE (AVX2_Usable)) return; \ ++ if (!CPU_FEATURE_USABLE (AVX2)) return; \ + } \ + while (0) + +@@ -44,7 +44,7 @@ + # define CHECK_ARCH_EXT \ + do \ + { \ +- if (!HAS_ARCH_FEATURE (AVX512F_Usable)) return; \ ++ if (!CPU_FEATURE_USABLE (AVX512F)) return; \ + } \ + while (0) + +diff --git a/sysdeps/x86_64/fpu/multiarch/ifunc-avx-fma4.h b/sysdeps/x86_64/fpu/multiarch/ifunc-avx-fma4.h +index a5f9375afc683663..399ed90362f476b7 100644 +--- a/sysdeps/x86_64/fpu/multiarch/ifunc-avx-fma4.h ++++ b/sysdeps/x86_64/fpu/multiarch/ifunc-avx-fma4.h +@@ -29,14 +29,14 @@ IFUNC_SELECTOR (void) + { + const struct cpu_features* cpu_features = __get_cpu_features (); + +- if (CPU_FEATURES_ARCH_P (cpu_features, FMA_Usable) +- && CPU_FEATURES_ARCH_P (cpu_features, AVX2_Usable)) ++ if (CPU_FEATURE_USABLE_P (cpu_features, FMA) ++ && CPU_FEATURE_USABLE_P (cpu_features, AVX2)) + return OPTIMIZE (fma); + +- if (CPU_FEATURES_ARCH_P (cpu_features, FMA4_Usable)) ++ if (CPU_FEATURE_USABLE_P (cpu_features, FMA4)) + return OPTIMIZE (fma4); + +- if (CPU_FEATURES_ARCH_P (cpu_features, AVX_Usable)) ++ if (CPU_FEATURE_USABLE_P (cpu_features, AVX)) + return OPTIMIZE (avx); + + return OPTIMIZE (sse2); +diff --git a/sysdeps/x86_64/fpu/multiarch/ifunc-fma.h b/sysdeps/x86_64/fpu/multiarch/ifunc-fma.h +index 63a8cd221fb34e28..c6717d65dfd160e7 100644 +--- a/sysdeps/x86_64/fpu/multiarch/ifunc-fma.h ++++ b/sysdeps/x86_64/fpu/multiarch/ifunc-fma.h +@@ -26,8 +26,8 @@ IFUNC_SELECTOR (void) + { + const struct cpu_features* cpu_features = __get_cpu_features (); + +- if (CPU_FEATURES_ARCH_P (cpu_features, FMA_Usable) +- && CPU_FEATURES_ARCH_P (cpu_features, AVX2_Usable)) ++ if (CPU_FEATURE_USABLE_P (cpu_features, FMA) ++ && CPU_FEATURE_USABLE_P (cpu_features, AVX2)) + return OPTIMIZE (fma); + + return OPTIMIZE (sse2); +diff --git a/sysdeps/x86_64/fpu/multiarch/ifunc-fma4.h b/sysdeps/x86_64/fpu/multiarch/ifunc-fma4.h +index a2526a2ee0e55e18..76c677198dac5cb0 100644 +--- a/sysdeps/x86_64/fpu/multiarch/ifunc-fma4.h ++++ b/sysdeps/x86_64/fpu/multiarch/ifunc-fma4.h +@@ -28,11 +28,11 @@ IFUNC_SELECTOR (void) + { + const struct cpu_features* cpu_features = __get_cpu_features (); + +- if (CPU_FEATURES_ARCH_P (cpu_features, FMA_Usable) +- && CPU_FEATURES_ARCH_P (cpu_features, AVX2_Usable)) ++ if (CPU_FEATURE_USABLE_P (cpu_features, FMA) ++ && CPU_FEATURE_USABLE_P (cpu_features, AVX2)) + return OPTIMIZE (fma); + +- if (CPU_FEATURES_ARCH_P (cpu_features, FMA4_Usable)) ++ if (CPU_FEATURE_USABLE_P (cpu_features, FMA)) + return OPTIMIZE (fma4); + + return OPTIMIZE (sse2); +diff --git a/sysdeps/x86_64/fpu/multiarch/ifunc-mathvec-avx2.h b/sysdeps/x86_64/fpu/multiarch/ifunc-mathvec-avx2.h +index bd2d32e4186c11e3..d84d82a3a22f0e86 100644 +--- a/sysdeps/x86_64/fpu/multiarch/ifunc-mathvec-avx2.h ++++ b/sysdeps/x86_64/fpu/multiarch/ifunc-mathvec-avx2.h +@@ -31,8 +31,8 @@ IFUNC_SELECTOR (void) + { + const struct cpu_features* cpu_features = __get_cpu_features (); + +- if (CPU_FEATURES_ARCH_P (cpu_features, FMA_Usable) +- && CPU_FEATURES_ARCH_P (cpu_features, AVX2_Usable)) ++ if (CPU_FEATURE_USABLE_P (cpu_features, FMA) ++ && CPU_FEATURE_USABLE_P (cpu_features, AVX2)) + return OPTIMIZE (avx2); + + return OPTIMIZE (sse_wrapper); +diff --git a/sysdeps/x86_64/fpu/multiarch/ifunc-mathvec-avx512.h b/sysdeps/x86_64/fpu/multiarch/ifunc-mathvec-avx512.h +index 174e462cfbcfa0a5..a2d9972e5a02b87c 100644 +--- a/sysdeps/x86_64/fpu/multiarch/ifunc-mathvec-avx512.h ++++ b/sysdeps/x86_64/fpu/multiarch/ifunc-mathvec-avx512.h +@@ -34,10 +34,10 @@ IFUNC_SELECTOR (void) + + if (!CPU_FEATURES_ARCH_P (cpu_features, MathVec_Prefer_No_AVX512)) + { +- if (CPU_FEATURES_ARCH_P (cpu_features, AVX512DQ_Usable)) ++ if (CPU_FEATURE_USABLE_P (cpu_features, AVX512DQ)) + return OPTIMIZE (skx); + +- if (CPU_FEATURES_ARCH_P (cpu_features, AVX512F_Usable)) ++ if (CPU_FEATURE_USABLE_P (cpu_features, AVX512F)) + return OPTIMIZE (knl); + } + +diff --git a/sysdeps/x86_64/fpu/multiarch/ifunc-mathvec-sse4_1.h b/sysdeps/x86_64/fpu/multiarch/ifunc-mathvec-sse4_1.h +index c1e70ebfc1b424e6..64d03f6cb1caa9b7 100644 +--- a/sysdeps/x86_64/fpu/multiarch/ifunc-mathvec-sse4_1.h ++++ b/sysdeps/x86_64/fpu/multiarch/ifunc-mathvec-sse4_1.h +@@ -31,7 +31,7 @@ IFUNC_SELECTOR (void) + { + const struct cpu_features* cpu_features = __get_cpu_features (); + +- if (CPU_FEATURES_CPU_P (cpu_features, SSE4_1)) ++ if (CPU_FEATURE_USABLE_P (cpu_features, SSE4_1)) + return OPTIMIZE (sse4); + + return OPTIMIZE (sse2); +diff --git a/sysdeps/x86_64/fpu/multiarch/ifunc-sse4_1.h b/sysdeps/x86_64/fpu/multiarch/ifunc-sse4_1.h +index a8710ba80226f13f..81bca1c9ecde9fb7 100644 +--- a/sysdeps/x86_64/fpu/multiarch/ifunc-sse4_1.h ++++ b/sysdeps/x86_64/fpu/multiarch/ifunc-sse4_1.h +@@ -26,7 +26,7 @@ IFUNC_SELECTOR (void) + { + const struct cpu_features* cpu_features = __get_cpu_features (); + +- if (CPU_FEATURES_CPU_P (cpu_features, SSE4_1)) ++ if (CPU_FEATURE_USABLE_P (cpu_features, SSE4_1)) + return OPTIMIZE (sse41); + + return OPTIMIZE (c); +diff --git a/sysdeps/x86_64/fpu/multiarch/s_fma.c b/sysdeps/x86_64/fpu/multiarch/s_fma.c +index 875c76d3727e6d3c..9ea8d368d08220a9 100644 +--- a/sysdeps/x86_64/fpu/multiarch/s_fma.c ++++ b/sysdeps/x86_64/fpu/multiarch/s_fma.c +@@ -41,8 +41,8 @@ __fma_fma4 (double x, double y, double z) + } + + +-libm_ifunc (__fma, HAS_ARCH_FEATURE (FMA_Usable) +- ? __fma_fma3 : (HAS_ARCH_FEATURE (FMA4_Usable) ++libm_ifunc (__fma, CPU_FEATURE_USABLE (FMA) ++ ? __fma_fma3 : (CPU_FEATURE_USABLE (FMA4) + ? __fma_fma4 : __fma_sse2)); + libm_alias_double (__fma, fma) + +diff --git a/sysdeps/x86_64/fpu/multiarch/s_fmaf.c b/sysdeps/x86_64/fpu/multiarch/s_fmaf.c +index 5f4c2ec0be15c2dc..33e64ef8d1a03269 100644 +--- a/sysdeps/x86_64/fpu/multiarch/s_fmaf.c ++++ b/sysdeps/x86_64/fpu/multiarch/s_fmaf.c +@@ -40,8 +40,8 @@ __fmaf_fma4 (float x, float y, float z) + } + + +-libm_ifunc (__fmaf, HAS_ARCH_FEATURE (FMA_Usable) +- ? __fmaf_fma3 : (HAS_ARCH_FEATURE (FMA4_Usable) ++libm_ifunc (__fmaf, CPU_FEATURE_USABLE (FMA) ++ ? __fmaf_fma3 : (CPU_FEATURE_USABLE (FMA4) + ? __fmaf_fma4 : __fmaf_sse2)); + libm_alias_float (__fma, fma) + +diff --git a/sysdeps/x86_64/multiarch/ifunc-avx2.h b/sysdeps/x86_64/multiarch/ifunc-avx2.h +index 9cab837642b7af21..5c88640a2d901ec6 100644 +--- a/sysdeps/x86_64/multiarch/ifunc-avx2.h ++++ b/sysdeps/x86_64/multiarch/ifunc-avx2.h +@@ -28,7 +28,7 @@ IFUNC_SELECTOR (void) + const struct cpu_features* cpu_features = __get_cpu_features (); + + if (!CPU_FEATURES_ARCH_P (cpu_features, Prefer_No_VZEROUPPER) +- && CPU_FEATURES_ARCH_P (cpu_features, AVX2_Usable) ++ && CPU_FEATURE_USABLE_P (cpu_features, AVX2) + && CPU_FEATURES_ARCH_P (cpu_features, AVX_Fast_Unaligned_Load)) + return OPTIMIZE (avx2); + +diff --git a/sysdeps/x86_64/multiarch/ifunc-impl-list.c b/sysdeps/x86_64/multiarch/ifunc-impl-list.c +index 8b55bb6954000cc2..fe13505ca1ac7ef0 100644 +--- a/sysdeps/x86_64/multiarch/ifunc-impl-list.c ++++ b/sysdeps/x86_64/multiarch/ifunc-impl-list.c +@@ -41,19 +41,19 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + /* Support sysdeps/x86_64/multiarch/memchr.c. */ + IFUNC_IMPL (i, name, memchr, + IFUNC_IMPL_ADD (array, i, memchr, +- HAS_ARCH_FEATURE (AVX2_Usable), ++ CPU_FEATURE_USABLE (AVX2), + __memchr_avx2) + IFUNC_IMPL_ADD (array, i, memchr, 1, __memchr_sse2)) + + /* Support sysdeps/x86_64/multiarch/memcmp.c. */ + IFUNC_IMPL (i, name, memcmp, + IFUNC_IMPL_ADD (array, i, memcmp, +- (HAS_ARCH_FEATURE (AVX2_Usable) +- && HAS_CPU_FEATURE (MOVBE)), ++ (CPU_FEATURE_USABLE (AVX2) ++ && CPU_FEATURE_USABLE (MOVBE)), + __memcmp_avx2_movbe) +- IFUNC_IMPL_ADD (array, i, memcmp, HAS_CPU_FEATURE (SSE4_1), ++ IFUNC_IMPL_ADD (array, i, memcmp, CPU_FEATURE_USABLE (SSE4_1), + __memcmp_sse4_1) +- IFUNC_IMPL_ADD (array, i, memcmp, HAS_CPU_FEATURE (SSSE3), ++ IFUNC_IMPL_ADD (array, i, memcmp, CPU_FEATURE_USABLE (SSSE3), + __memcmp_ssse3) + IFUNC_IMPL_ADD (array, i, memcmp, 1, __memcmp_sse2)) + +@@ -61,25 +61,25 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + /* Support sysdeps/x86_64/multiarch/memmove_chk.c. */ + IFUNC_IMPL (i, name, __memmove_chk, + IFUNC_IMPL_ADD (array, i, __memmove_chk, +- HAS_ARCH_FEATURE (AVX512F_Usable), ++ CPU_FEATURE_USABLE (AVX512F), + __memmove_chk_avx512_no_vzeroupper) + IFUNC_IMPL_ADD (array, i, __memmove_chk, +- HAS_ARCH_FEATURE (AVX512F_Usable), ++ CPU_FEATURE_USABLE (AVX512F), + __memmove_chk_avx512_unaligned) + IFUNC_IMPL_ADD (array, i, __memmove_chk, +- HAS_ARCH_FEATURE (AVX512F_Usable), ++ CPU_FEATURE_USABLE (AVX512F), + __memmove_chk_avx512_unaligned_erms) + IFUNC_IMPL_ADD (array, i, __memmove_chk, +- HAS_ARCH_FEATURE (AVX_Usable), ++ CPU_FEATURE_USABLE (AVX), + __memmove_chk_avx_unaligned) + IFUNC_IMPL_ADD (array, i, __memmove_chk, +- HAS_ARCH_FEATURE (AVX_Usable), ++ CPU_FEATURE_USABLE (AVX), + __memmove_chk_avx_unaligned_erms) + IFUNC_IMPL_ADD (array, i, __memmove_chk, +- HAS_CPU_FEATURE (SSSE3), ++ CPU_FEATURE_USABLE (SSSE3), + __memmove_chk_ssse3_back) + IFUNC_IMPL_ADD (array, i, __memmove_chk, +- HAS_CPU_FEATURE (SSSE3), ++ CPU_FEATURE_USABLE (SSSE3), + __memmove_chk_ssse3) + IFUNC_IMPL_ADD (array, i, __memmove_chk, 1, + __memmove_chk_sse2_unaligned) +@@ -92,23 +92,23 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + /* Support sysdeps/x86_64/multiarch/memmove.c. */ + IFUNC_IMPL (i, name, memmove, + IFUNC_IMPL_ADD (array, i, memmove, +- HAS_ARCH_FEATURE (AVX_Usable), ++ CPU_FEATURE_USABLE (AVX), + __memmove_avx_unaligned) + IFUNC_IMPL_ADD (array, i, memmove, +- HAS_ARCH_FEATURE (AVX_Usable), ++ CPU_FEATURE_USABLE (AVX), + __memmove_avx_unaligned_erms) + IFUNC_IMPL_ADD (array, i, memmove, +- HAS_ARCH_FEATURE (AVX512F_Usable), ++ CPU_FEATURE_USABLE (AVX512F), + __memmove_avx512_no_vzeroupper) + IFUNC_IMPL_ADD (array, i, memmove, +- HAS_ARCH_FEATURE (AVX512F_Usable), ++ CPU_FEATURE_USABLE (AVX512F), + __memmove_avx512_unaligned) + IFUNC_IMPL_ADD (array, i, memmove, +- HAS_ARCH_FEATURE (AVX512F_Usable), ++ CPU_FEATURE_USABLE (AVX512F), + __memmove_avx512_unaligned_erms) +- IFUNC_IMPL_ADD (array, i, memmove, HAS_CPU_FEATURE (SSSE3), ++ IFUNC_IMPL_ADD (array, i, memmove, CPU_FEATURE_USABLE (SSSE3), + __memmove_ssse3_back) +- IFUNC_IMPL_ADD (array, i, memmove, HAS_CPU_FEATURE (SSSE3), ++ IFUNC_IMPL_ADD (array, i, memmove, CPU_FEATURE_USABLE (SSSE3), + __memmove_ssse3) + IFUNC_IMPL_ADD (array, i, memmove, 1, __memmove_erms) + IFUNC_IMPL_ADD (array, i, memmove, 1, +@@ -119,7 +119,7 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + /* Support sysdeps/x86_64/multiarch/memrchr.c. */ + IFUNC_IMPL (i, name, memrchr, + IFUNC_IMPL_ADD (array, i, memrchr, +- HAS_ARCH_FEATURE (AVX2_Usable), ++ CPU_FEATURE_USABLE (AVX2), + __memrchr_avx2) + IFUNC_IMPL_ADD (array, i, memrchr, 1, __memrchr_sse2)) + +@@ -133,19 +133,19 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + IFUNC_IMPL_ADD (array, i, __memset_chk, 1, + __memset_chk_sse2_unaligned_erms) + IFUNC_IMPL_ADD (array, i, __memset_chk, +- HAS_ARCH_FEATURE (AVX2_Usable), ++ CPU_FEATURE_USABLE (AVX2), + __memset_chk_avx2_unaligned) + IFUNC_IMPL_ADD (array, i, __memset_chk, +- HAS_ARCH_FEATURE (AVX2_Usable), ++ CPU_FEATURE_USABLE (AVX2), + __memset_chk_avx2_unaligned_erms) + IFUNC_IMPL_ADD (array, i, __memset_chk, +- HAS_ARCH_FEATURE (AVX512F_Usable), ++ CPU_FEATURE_USABLE (AVX512F), + __memset_chk_avx512_unaligned_erms) + IFUNC_IMPL_ADD (array, i, __memset_chk, +- HAS_ARCH_FEATURE (AVX512F_Usable), ++ CPU_FEATURE_USABLE (AVX512F), + __memset_chk_avx512_unaligned) + IFUNC_IMPL_ADD (array, i, __memset_chk, +- HAS_ARCH_FEATURE (AVX512F_Usable), ++ CPU_FEATURE_USABLE (AVX512F), + __memset_chk_avx512_no_vzeroupper) + ) + #endif +@@ -158,48 +158,48 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + __memset_sse2_unaligned_erms) + IFUNC_IMPL_ADD (array, i, memset, 1, __memset_erms) + IFUNC_IMPL_ADD (array, i, memset, +- HAS_ARCH_FEATURE (AVX2_Usable), ++ CPU_FEATURE_USABLE (AVX2), + __memset_avx2_unaligned) + IFUNC_IMPL_ADD (array, i, memset, +- HAS_ARCH_FEATURE (AVX2_Usable), ++ CPU_FEATURE_USABLE (AVX2), + __memset_avx2_unaligned_erms) + IFUNC_IMPL_ADD (array, i, memset, +- HAS_ARCH_FEATURE (AVX512F_Usable), ++ CPU_FEATURE_USABLE (AVX512F), + __memset_avx512_unaligned_erms) + IFUNC_IMPL_ADD (array, i, memset, +- HAS_ARCH_FEATURE (AVX512F_Usable), ++ CPU_FEATURE_USABLE (AVX512F), + __memset_avx512_unaligned) + IFUNC_IMPL_ADD (array, i, memset, +- HAS_ARCH_FEATURE (AVX512F_Usable), ++ CPU_FEATURE_USABLE (AVX512F), + __memset_avx512_no_vzeroupper) + ) + + /* Support sysdeps/x86_64/multiarch/rawmemchr.c. */ + IFUNC_IMPL (i, name, rawmemchr, + IFUNC_IMPL_ADD (array, i, rawmemchr, +- HAS_ARCH_FEATURE (AVX2_Usable), ++ CPU_FEATURE_USABLE (AVX2), + __rawmemchr_avx2) + IFUNC_IMPL_ADD (array, i, rawmemchr, 1, __rawmemchr_sse2)) + + /* Support sysdeps/x86_64/multiarch/strlen.c. */ + IFUNC_IMPL (i, name, strlen, + IFUNC_IMPL_ADD (array, i, strlen, +- HAS_ARCH_FEATURE (AVX2_Usable), ++ CPU_FEATURE_USABLE (AVX2), + __strlen_avx2) + IFUNC_IMPL_ADD (array, i, strlen, 1, __strlen_sse2)) + + /* Support sysdeps/x86_64/multiarch/strnlen.c. */ + IFUNC_IMPL (i, name, strnlen, + IFUNC_IMPL_ADD (array, i, strnlen, +- HAS_ARCH_FEATURE (AVX2_Usable), ++ CPU_FEATURE_USABLE (AVX2), + __strnlen_avx2) + IFUNC_IMPL_ADD (array, i, strnlen, 1, __strnlen_sse2)) + + /* Support sysdeps/x86_64/multiarch/stpncpy.c. */ + IFUNC_IMPL (i, name, stpncpy, +- IFUNC_IMPL_ADD (array, i, stpncpy, HAS_CPU_FEATURE (SSSE3), ++ IFUNC_IMPL_ADD (array, i, stpncpy, CPU_FEATURE_USABLE (SSSE3), + __stpncpy_ssse3) +- IFUNC_IMPL_ADD (array, i, stpncpy, HAS_ARCH_FEATURE (AVX2_Usable), ++ IFUNC_IMPL_ADD (array, i, stpncpy, CPU_FEATURE_USABLE (AVX2), + __stpncpy_avx2) + IFUNC_IMPL_ADD (array, i, stpncpy, 1, + __stpncpy_sse2_unaligned) +@@ -207,9 +207,9 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + + /* Support sysdeps/x86_64/multiarch/stpcpy.c. */ + IFUNC_IMPL (i, name, stpcpy, +- IFUNC_IMPL_ADD (array, i, stpcpy, HAS_CPU_FEATURE (SSSE3), ++ IFUNC_IMPL_ADD (array, i, stpcpy, CPU_FEATURE_USABLE (SSSE3), + __stpcpy_ssse3) +- IFUNC_IMPL_ADD (array, i, stpcpy, HAS_ARCH_FEATURE (AVX2_Usable), ++ IFUNC_IMPL_ADD (array, i, stpcpy, CPU_FEATURE_USABLE (AVX2), + __stpcpy_avx2) + IFUNC_IMPL_ADD (array, i, stpcpy, 1, __stpcpy_sse2_unaligned) + IFUNC_IMPL_ADD (array, i, stpcpy, 1, __stpcpy_sse2)) +@@ -217,35 +217,35 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + /* Support sysdeps/x86_64/multiarch/strcasecmp_l.c. */ + IFUNC_IMPL (i, name, strcasecmp, + IFUNC_IMPL_ADD (array, i, strcasecmp, +- HAS_ARCH_FEATURE (AVX_Usable), ++ CPU_FEATURE_USABLE (AVX), + __strcasecmp_avx) + IFUNC_IMPL_ADD (array, i, strcasecmp, +- HAS_CPU_FEATURE (SSE4_2), ++ CPU_FEATURE_USABLE (SSE4_2), + __strcasecmp_sse42) + IFUNC_IMPL_ADD (array, i, strcasecmp, +- HAS_CPU_FEATURE (SSSE3), ++ CPU_FEATURE_USABLE (SSSE3), + __strcasecmp_ssse3) + IFUNC_IMPL_ADD (array, i, strcasecmp, 1, __strcasecmp_sse2)) + + /* Support sysdeps/x86_64/multiarch/strcasecmp_l.c. */ + IFUNC_IMPL (i, name, strcasecmp_l, + IFUNC_IMPL_ADD (array, i, strcasecmp_l, +- HAS_ARCH_FEATURE (AVX_Usable), ++ CPU_FEATURE_USABLE (AVX), + __strcasecmp_l_avx) + IFUNC_IMPL_ADD (array, i, strcasecmp_l, +- HAS_CPU_FEATURE (SSE4_2), ++ CPU_FEATURE_USABLE (SSE4_2), + __strcasecmp_l_sse42) + IFUNC_IMPL_ADD (array, i, strcasecmp_l, +- HAS_CPU_FEATURE (SSSE3), ++ CPU_FEATURE_USABLE (SSSE3), + __strcasecmp_l_ssse3) + IFUNC_IMPL_ADD (array, i, strcasecmp_l, 1, + __strcasecmp_l_sse2)) + + /* Support sysdeps/x86_64/multiarch/strcat.c. */ + IFUNC_IMPL (i, name, strcat, +- IFUNC_IMPL_ADD (array, i, strcat, HAS_ARCH_FEATURE (AVX2_Usable), ++ IFUNC_IMPL_ADD (array, i, strcat, CPU_FEATURE_USABLE (AVX2), + __strcat_avx2) +- IFUNC_IMPL_ADD (array, i, strcat, HAS_CPU_FEATURE (SSSE3), ++ IFUNC_IMPL_ADD (array, i, strcat, CPU_FEATURE_USABLE (SSSE3), + __strcat_ssse3) + IFUNC_IMPL_ADD (array, i, strcat, 1, __strcat_sse2_unaligned) + IFUNC_IMPL_ADD (array, i, strcat, 1, __strcat_sse2)) +@@ -253,7 +253,7 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + /* Support sysdeps/x86_64/multiarch/strchr.c. */ + IFUNC_IMPL (i, name, strchr, + IFUNC_IMPL_ADD (array, i, strchr, +- HAS_ARCH_FEATURE (AVX2_Usable), ++ CPU_FEATURE_USABLE (AVX2), + __strchr_avx2) + IFUNC_IMPL_ADD (array, i, strchr, 1, __strchr_sse2_no_bsf) + IFUNC_IMPL_ADD (array, i, strchr, 1, __strchr_sse2)) +@@ -261,54 +261,54 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + /* Support sysdeps/x86_64/multiarch/strchrnul.c. */ + IFUNC_IMPL (i, name, strchrnul, + IFUNC_IMPL_ADD (array, i, strchrnul, +- HAS_ARCH_FEATURE (AVX2_Usable), ++ CPU_FEATURE_USABLE (AVX2), + __strchrnul_avx2) + IFUNC_IMPL_ADD (array, i, strchrnul, 1, __strchrnul_sse2)) + + /* Support sysdeps/x86_64/multiarch/strrchr.c. */ + IFUNC_IMPL (i, name, strrchr, + IFUNC_IMPL_ADD (array, i, strrchr, +- HAS_ARCH_FEATURE (AVX2_Usable), ++ CPU_FEATURE_USABLE (AVX2), + __strrchr_avx2) + IFUNC_IMPL_ADD (array, i, strrchr, 1, __strrchr_sse2)) + + /* Support sysdeps/x86_64/multiarch/strcmp.c. */ + IFUNC_IMPL (i, name, strcmp, + IFUNC_IMPL_ADD (array, i, strcmp, +- HAS_ARCH_FEATURE (AVX2_Usable), ++ CPU_FEATURE_USABLE (AVX2), + __strcmp_avx2) +- IFUNC_IMPL_ADD (array, i, strcmp, HAS_CPU_FEATURE (SSE4_2), ++ IFUNC_IMPL_ADD (array, i, strcmp, CPU_FEATURE_USABLE (SSE4_2), + __strcmp_sse42) +- IFUNC_IMPL_ADD (array, i, strcmp, HAS_CPU_FEATURE (SSSE3), ++ IFUNC_IMPL_ADD (array, i, strcmp, CPU_FEATURE_USABLE (SSSE3), + __strcmp_ssse3) + IFUNC_IMPL_ADD (array, i, strcmp, 1, __strcmp_sse2_unaligned) + IFUNC_IMPL_ADD (array, i, strcmp, 1, __strcmp_sse2)) + + /* Support sysdeps/x86_64/multiarch/strcpy.c. */ + IFUNC_IMPL (i, name, strcpy, +- IFUNC_IMPL_ADD (array, i, strcpy, HAS_ARCH_FEATURE (AVX2_Usable), ++ IFUNC_IMPL_ADD (array, i, strcpy, CPU_FEATURE_USABLE (AVX2), + __strcpy_avx2) +- IFUNC_IMPL_ADD (array, i, strcpy, HAS_CPU_FEATURE (SSSE3), ++ IFUNC_IMPL_ADD (array, i, strcpy, CPU_FEATURE_USABLE (SSSE3), + __strcpy_ssse3) + IFUNC_IMPL_ADD (array, i, strcpy, 1, __strcpy_sse2_unaligned) + IFUNC_IMPL_ADD (array, i, strcpy, 1, __strcpy_sse2)) + + /* Support sysdeps/x86_64/multiarch/strcspn.c. */ + IFUNC_IMPL (i, name, strcspn, +- IFUNC_IMPL_ADD (array, i, strcspn, HAS_CPU_FEATURE (SSE4_2), ++ IFUNC_IMPL_ADD (array, i, strcspn, CPU_FEATURE_USABLE (SSE4_2), + __strcspn_sse42) + IFUNC_IMPL_ADD (array, i, strcspn, 1, __strcspn_sse2)) + + /* Support sysdeps/x86_64/multiarch/strncase_l.c. */ + IFUNC_IMPL (i, name, strncasecmp, + IFUNC_IMPL_ADD (array, i, strncasecmp, +- HAS_ARCH_FEATURE (AVX_Usable), ++ CPU_FEATURE_USABLE (AVX), + __strncasecmp_avx) + IFUNC_IMPL_ADD (array, i, strncasecmp, +- HAS_CPU_FEATURE (SSE4_2), ++ CPU_FEATURE_USABLE (SSE4_2), + __strncasecmp_sse42) + IFUNC_IMPL_ADD (array, i, strncasecmp, +- HAS_CPU_FEATURE (SSSE3), ++ CPU_FEATURE_USABLE (SSSE3), + __strncasecmp_ssse3) + IFUNC_IMPL_ADD (array, i, strncasecmp, 1, + __strncasecmp_sse2)) +@@ -316,22 +316,22 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + /* Support sysdeps/x86_64/multiarch/strncase_l.c. */ + IFUNC_IMPL (i, name, strncasecmp_l, + IFUNC_IMPL_ADD (array, i, strncasecmp_l, +- HAS_ARCH_FEATURE (AVX_Usable), ++ CPU_FEATURE_USABLE (AVX), + __strncasecmp_l_avx) + IFUNC_IMPL_ADD (array, i, strncasecmp_l, +- HAS_CPU_FEATURE (SSE4_2), ++ CPU_FEATURE_USABLE (SSE4_2), + __strncasecmp_l_sse42) + IFUNC_IMPL_ADD (array, i, strncasecmp_l, +- HAS_CPU_FEATURE (SSSE3), ++ CPU_FEATURE_USABLE (SSSE3), + __strncasecmp_l_ssse3) + IFUNC_IMPL_ADD (array, i, strncasecmp_l, 1, + __strncasecmp_l_sse2)) + + /* Support sysdeps/x86_64/multiarch/strncat.c. */ + IFUNC_IMPL (i, name, strncat, +- IFUNC_IMPL_ADD (array, i, strncat, HAS_ARCH_FEATURE (AVX2_Usable), ++ IFUNC_IMPL_ADD (array, i, strncat, CPU_FEATURE_USABLE (AVX2), + __strncat_avx2) +- IFUNC_IMPL_ADD (array, i, strncat, HAS_CPU_FEATURE (SSSE3), ++ IFUNC_IMPL_ADD (array, i, strncat, CPU_FEATURE_USABLE (SSSE3), + __strncat_ssse3) + IFUNC_IMPL_ADD (array, i, strncat, 1, + __strncat_sse2_unaligned) +@@ -339,9 +339,9 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + + /* Support sysdeps/x86_64/multiarch/strncpy.c. */ + IFUNC_IMPL (i, name, strncpy, +- IFUNC_IMPL_ADD (array, i, strncpy, HAS_ARCH_FEATURE (AVX2_Usable), ++ IFUNC_IMPL_ADD (array, i, strncpy, CPU_FEATURE_USABLE (AVX2), + __strncpy_avx2) +- IFUNC_IMPL_ADD (array, i, strncpy, HAS_CPU_FEATURE (SSSE3), ++ IFUNC_IMPL_ADD (array, i, strncpy, CPU_FEATURE_USABLE (SSSE3), + __strncpy_ssse3) + IFUNC_IMPL_ADD (array, i, strncpy, 1, + __strncpy_sse2_unaligned) +@@ -349,14 +349,14 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + + /* Support sysdeps/x86_64/multiarch/strpbrk.c. */ + IFUNC_IMPL (i, name, strpbrk, +- IFUNC_IMPL_ADD (array, i, strpbrk, HAS_CPU_FEATURE (SSE4_2), ++ IFUNC_IMPL_ADD (array, i, strpbrk, CPU_FEATURE_USABLE (SSE4_2), + __strpbrk_sse42) + IFUNC_IMPL_ADD (array, i, strpbrk, 1, __strpbrk_sse2)) + + + /* Support sysdeps/x86_64/multiarch/strspn.c. */ + IFUNC_IMPL (i, name, strspn, +- IFUNC_IMPL_ADD (array, i, strspn, HAS_CPU_FEATURE (SSE4_2), ++ IFUNC_IMPL_ADD (array, i, strspn, CPU_FEATURE_USABLE (SSE4_2), + __strspn_sse42) + IFUNC_IMPL_ADD (array, i, strspn, 1, __strspn_sse2)) + +@@ -368,70 +368,70 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + /* Support sysdeps/x86_64/multiarch/wcschr.c. */ + IFUNC_IMPL (i, name, wcschr, + IFUNC_IMPL_ADD (array, i, wcschr, +- HAS_ARCH_FEATURE (AVX2_Usable), ++ CPU_FEATURE_USABLE (AVX2), + __wcschr_avx2) + IFUNC_IMPL_ADD (array, i, wcschr, 1, __wcschr_sse2)) + + /* Support sysdeps/x86_64/multiarch/wcsrchr.c. */ + IFUNC_IMPL (i, name, wcsrchr, + IFUNC_IMPL_ADD (array, i, wcsrchr, +- HAS_ARCH_FEATURE (AVX2_Usable), ++ CPU_FEATURE_USABLE (AVX2), + __wcsrchr_avx2) + IFUNC_IMPL_ADD (array, i, wcsrchr, 1, __wcsrchr_sse2)) + + /* Support sysdeps/x86_64/multiarch/wcscmp.c. */ + IFUNC_IMPL (i, name, wcscmp, + IFUNC_IMPL_ADD (array, i, wcscmp, +- HAS_ARCH_FEATURE (AVX2_Usable), ++ CPU_FEATURE_USABLE (AVX2), + __wcscmp_avx2) + IFUNC_IMPL_ADD (array, i, wcscmp, 1, __wcscmp_sse2)) + + /* Support sysdeps/x86_64/multiarch/wcsncmp.c. */ + IFUNC_IMPL (i, name, wcsncmp, + IFUNC_IMPL_ADD (array, i, wcsncmp, +- HAS_ARCH_FEATURE (AVX2_Usable), ++ CPU_FEATURE_USABLE (AVX2), + __wcsncmp_avx2) + IFUNC_IMPL_ADD (array, i, wcsncmp, 1, __wcsncmp_sse2)) + + /* Support sysdeps/x86_64/multiarch/wcscpy.c. */ + IFUNC_IMPL (i, name, wcscpy, +- IFUNC_IMPL_ADD (array, i, wcscpy, HAS_CPU_FEATURE (SSSE3), ++ IFUNC_IMPL_ADD (array, i, wcscpy, CPU_FEATURE_USABLE (SSSE3), + __wcscpy_ssse3) + IFUNC_IMPL_ADD (array, i, wcscpy, 1, __wcscpy_sse2)) + + /* Support sysdeps/x86_64/multiarch/wcslen.c. */ + IFUNC_IMPL (i, name, wcslen, + IFUNC_IMPL_ADD (array, i, wcslen, +- HAS_ARCH_FEATURE (AVX2_Usable), ++ CPU_FEATURE_USABLE (AVX2), + __wcslen_avx2) + IFUNC_IMPL_ADD (array, i, wcslen, 1, __wcslen_sse2)) + + /* Support sysdeps/x86_64/multiarch/wcsnlen.c. */ + IFUNC_IMPL (i, name, wcsnlen, + IFUNC_IMPL_ADD (array, i, wcsnlen, +- HAS_ARCH_FEATURE (AVX2_Usable), ++ CPU_FEATURE_USABLE (AVX2), + __wcsnlen_avx2) + IFUNC_IMPL_ADD (array, i, wcsnlen, +- HAS_CPU_FEATURE (SSE4_1), ++ CPU_FEATURE_USABLE (SSE4_1), + __wcsnlen_sse4_1) + IFUNC_IMPL_ADD (array, i, wcsnlen, 1, __wcsnlen_sse2)) + + /* Support sysdeps/x86_64/multiarch/wmemchr.c. */ + IFUNC_IMPL (i, name, wmemchr, + IFUNC_IMPL_ADD (array, i, wmemchr, +- HAS_ARCH_FEATURE (AVX2_Usable), ++ CPU_FEATURE_USABLE (AVX2), + __wmemchr_avx2) + IFUNC_IMPL_ADD (array, i, wmemchr, 1, __wmemchr_sse2)) + + /* Support sysdeps/x86_64/multiarch/wmemcmp.c. */ + IFUNC_IMPL (i, name, wmemcmp, + IFUNC_IMPL_ADD (array, i, wmemcmp, +- (HAS_ARCH_FEATURE (AVX2_Usable) +- && HAS_CPU_FEATURE (MOVBE)), ++ (CPU_FEATURE_USABLE (AVX2) ++ && CPU_FEATURE_USABLE (MOVBE)), + __wmemcmp_avx2_movbe) +- IFUNC_IMPL_ADD (array, i, wmemcmp, HAS_CPU_FEATURE (SSE4_1), ++ IFUNC_IMPL_ADD (array, i, wmemcmp, CPU_FEATURE_USABLE (SSE4_1), + __wmemcmp_sse4_1) +- IFUNC_IMPL_ADD (array, i, wmemcmp, HAS_CPU_FEATURE (SSSE3), ++ IFUNC_IMPL_ADD (array, i, wmemcmp, CPU_FEATURE_USABLE (SSSE3), + __wmemcmp_ssse3) + IFUNC_IMPL_ADD (array, i, wmemcmp, 1, __wmemcmp_sse2)) + +@@ -440,35 +440,35 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + IFUNC_IMPL_ADD (array, i, wmemset, 1, + __wmemset_sse2_unaligned) + IFUNC_IMPL_ADD (array, i, wmemset, +- HAS_ARCH_FEATURE (AVX2_Usable), ++ CPU_FEATURE_USABLE (AVX2), + __wmemset_avx2_unaligned) + IFUNC_IMPL_ADD (array, i, wmemset, +- HAS_ARCH_FEATURE (AVX512F_Usable), ++ CPU_FEATURE_USABLE (AVX512F), + __wmemset_avx512_unaligned)) + + #ifdef SHARED + /* Support sysdeps/x86_64/multiarch/memcpy_chk.c. */ + IFUNC_IMPL (i, name, __memcpy_chk, + IFUNC_IMPL_ADD (array, i, __memcpy_chk, +- HAS_ARCH_FEATURE (AVX512F_Usable), ++ CPU_FEATURE_USABLE (AVX512F), + __memcpy_chk_avx512_no_vzeroupper) + IFUNC_IMPL_ADD (array, i, __memcpy_chk, +- HAS_ARCH_FEATURE (AVX512F_Usable), ++ CPU_FEATURE_USABLE (AVX512F), + __memcpy_chk_avx512_unaligned) + IFUNC_IMPL_ADD (array, i, __memcpy_chk, +- HAS_ARCH_FEATURE (AVX512F_Usable), ++ CPU_FEATURE_USABLE (AVX512F), + __memcpy_chk_avx512_unaligned_erms) + IFUNC_IMPL_ADD (array, i, __memcpy_chk, +- HAS_ARCH_FEATURE (AVX_Usable), ++ CPU_FEATURE_USABLE (AVX), + __memcpy_chk_avx_unaligned) + IFUNC_IMPL_ADD (array, i, __memcpy_chk, +- HAS_ARCH_FEATURE (AVX_Usable), ++ CPU_FEATURE_USABLE (AVX), + __memcpy_chk_avx_unaligned_erms) + IFUNC_IMPL_ADD (array, i, __memcpy_chk, +- HAS_CPU_FEATURE (SSSE3), ++ CPU_FEATURE_USABLE (SSSE3), + __memcpy_chk_ssse3_back) + IFUNC_IMPL_ADD (array, i, __memcpy_chk, +- HAS_CPU_FEATURE (SSSE3), ++ CPU_FEATURE_USABLE (SSSE3), + __memcpy_chk_ssse3) + IFUNC_IMPL_ADD (array, i, __memcpy_chk, 1, + __memcpy_chk_sse2_unaligned) +@@ -481,23 +481,23 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + /* Support sysdeps/x86_64/multiarch/memcpy.c. */ + IFUNC_IMPL (i, name, memcpy, + IFUNC_IMPL_ADD (array, i, memcpy, +- HAS_ARCH_FEATURE (AVX_Usable), ++ CPU_FEATURE_USABLE (AVX), + __memcpy_avx_unaligned) + IFUNC_IMPL_ADD (array, i, memcpy, +- HAS_ARCH_FEATURE (AVX_Usable), ++ CPU_FEATURE_USABLE (AVX), + __memcpy_avx_unaligned_erms) +- IFUNC_IMPL_ADD (array, i, memcpy, HAS_CPU_FEATURE (SSSE3), ++ IFUNC_IMPL_ADD (array, i, memcpy, CPU_FEATURE_USABLE (SSSE3), + __memcpy_ssse3_back) +- IFUNC_IMPL_ADD (array, i, memcpy, HAS_CPU_FEATURE (SSSE3), ++ IFUNC_IMPL_ADD (array, i, memcpy, CPU_FEATURE_USABLE (SSSE3), + __memcpy_ssse3) + IFUNC_IMPL_ADD (array, i, memcpy, +- HAS_ARCH_FEATURE (AVX512F_Usable), ++ CPU_FEATURE_USABLE (AVX512F), + __memcpy_avx512_no_vzeroupper) + IFUNC_IMPL_ADD (array, i, memcpy, +- HAS_ARCH_FEATURE (AVX512F_Usable), ++ CPU_FEATURE_USABLE (AVX512F), + __memcpy_avx512_unaligned) + IFUNC_IMPL_ADD (array, i, memcpy, +- HAS_ARCH_FEATURE (AVX512F_Usable), ++ CPU_FEATURE_USABLE (AVX512F), + __memcpy_avx512_unaligned_erms) + IFUNC_IMPL_ADD (array, i, memcpy, 1, __memcpy_sse2_unaligned) + IFUNC_IMPL_ADD (array, i, memcpy, 1, +@@ -508,25 +508,25 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + /* Support sysdeps/x86_64/multiarch/mempcpy_chk.c. */ + IFUNC_IMPL (i, name, __mempcpy_chk, + IFUNC_IMPL_ADD (array, i, __mempcpy_chk, +- HAS_ARCH_FEATURE (AVX512F_Usable), ++ CPU_FEATURE_USABLE (AVX512F), + __mempcpy_chk_avx512_no_vzeroupper) + IFUNC_IMPL_ADD (array, i, __mempcpy_chk, +- HAS_ARCH_FEATURE (AVX512F_Usable), ++ CPU_FEATURE_USABLE (AVX512F), + __mempcpy_chk_avx512_unaligned) + IFUNC_IMPL_ADD (array, i, __mempcpy_chk, +- HAS_ARCH_FEATURE (AVX512F_Usable), ++ CPU_FEATURE_USABLE (AVX512F), + __mempcpy_chk_avx512_unaligned_erms) + IFUNC_IMPL_ADD (array, i, __mempcpy_chk, +- HAS_ARCH_FEATURE (AVX_Usable), ++ CPU_FEATURE_USABLE (AVX), + __mempcpy_chk_avx_unaligned) + IFUNC_IMPL_ADD (array, i, __mempcpy_chk, +- HAS_ARCH_FEATURE (AVX_Usable), ++ CPU_FEATURE_USABLE (AVX), + __mempcpy_chk_avx_unaligned_erms) + IFUNC_IMPL_ADD (array, i, __mempcpy_chk, +- HAS_CPU_FEATURE (SSSE3), ++ CPU_FEATURE_USABLE (SSSE3), + __mempcpy_chk_ssse3_back) + IFUNC_IMPL_ADD (array, i, __mempcpy_chk, +- HAS_CPU_FEATURE (SSSE3), ++ CPU_FEATURE_USABLE (SSSE3), + __mempcpy_chk_ssse3) + IFUNC_IMPL_ADD (array, i, __mempcpy_chk, 1, + __mempcpy_chk_sse2_unaligned) +@@ -539,23 +539,23 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + /* Support sysdeps/x86_64/multiarch/mempcpy.c. */ + IFUNC_IMPL (i, name, mempcpy, + IFUNC_IMPL_ADD (array, i, mempcpy, +- HAS_ARCH_FEATURE (AVX512F_Usable), ++ CPU_FEATURE_USABLE (AVX512F), + __mempcpy_avx512_no_vzeroupper) + IFUNC_IMPL_ADD (array, i, mempcpy, +- HAS_ARCH_FEATURE (AVX512F_Usable), ++ CPU_FEATURE_USABLE (AVX512F), + __mempcpy_avx512_unaligned) + IFUNC_IMPL_ADD (array, i, mempcpy, +- HAS_ARCH_FEATURE (AVX512F_Usable), ++ CPU_FEATURE_USABLE (AVX512F), + __mempcpy_avx512_unaligned_erms) + IFUNC_IMPL_ADD (array, i, mempcpy, +- HAS_ARCH_FEATURE (AVX_Usable), ++ CPU_FEATURE_USABLE (AVX), + __mempcpy_avx_unaligned) + IFUNC_IMPL_ADD (array, i, mempcpy, +- HAS_ARCH_FEATURE (AVX_Usable), ++ CPU_FEATURE_USABLE (AVX), + __mempcpy_avx_unaligned_erms) +- IFUNC_IMPL_ADD (array, i, mempcpy, HAS_CPU_FEATURE (SSSE3), ++ IFUNC_IMPL_ADD (array, i, mempcpy, CPU_FEATURE_USABLE (SSSE3), + __mempcpy_ssse3_back) +- IFUNC_IMPL_ADD (array, i, mempcpy, HAS_CPU_FEATURE (SSSE3), ++ IFUNC_IMPL_ADD (array, i, mempcpy, CPU_FEATURE_USABLE (SSSE3), + __mempcpy_ssse3) + IFUNC_IMPL_ADD (array, i, mempcpy, 1, + __mempcpy_sse2_unaligned) +@@ -566,11 +566,11 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + /* Support sysdeps/x86_64/multiarch/strncmp.c. */ + IFUNC_IMPL (i, name, strncmp, + IFUNC_IMPL_ADD (array, i, strncmp, +- HAS_ARCH_FEATURE (AVX2_Usable), ++ CPU_FEATURE_USABLE (AVX2), + __strncmp_avx2) +- IFUNC_IMPL_ADD (array, i, strncmp, HAS_CPU_FEATURE (SSE4_2), ++ IFUNC_IMPL_ADD (array, i, strncmp, CPU_FEATURE_USABLE (SSE4_2), + __strncmp_sse42) +- IFUNC_IMPL_ADD (array, i, strncmp, HAS_CPU_FEATURE (SSSE3), ++ IFUNC_IMPL_ADD (array, i, strncmp, CPU_FEATURE_USABLE (SSSE3), + __strncmp_ssse3) + IFUNC_IMPL_ADD (array, i, strncmp, 1, __strncmp_sse2)) + +@@ -580,10 +580,10 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + IFUNC_IMPL_ADD (array, i, __wmemset_chk, 1, + __wmemset_chk_sse2_unaligned) + IFUNC_IMPL_ADD (array, i, __wmemset_chk, +- HAS_ARCH_FEATURE (AVX2_Usable), ++ CPU_FEATURE_USABLE (AVX2), + __wmemset_chk_avx2_unaligned) + IFUNC_IMPL_ADD (array, i, __wmemset_chk, +- HAS_ARCH_FEATURE (AVX512F_Usable), ++ CPU_FEATURE_USABLE (AVX512F), + __wmemset_chk_avx512_unaligned)) + #endif + +diff --git a/sysdeps/x86_64/multiarch/ifunc-memcmp.h b/sysdeps/x86_64/multiarch/ifunc-memcmp.h +index bf5ab8eb7ffd0002..6c1f3153579d19c4 100644 +--- a/sysdeps/x86_64/multiarch/ifunc-memcmp.h ++++ b/sysdeps/x86_64/multiarch/ifunc-memcmp.h +@@ -30,15 +30,15 @@ IFUNC_SELECTOR (void) + const struct cpu_features* cpu_features = __get_cpu_features (); + + if (!CPU_FEATURES_ARCH_P (cpu_features, Prefer_No_VZEROUPPER) +- && CPU_FEATURES_ARCH_P (cpu_features, AVX2_Usable) +- && CPU_FEATURES_CPU_P (cpu_features, MOVBE) ++ && CPU_FEATURE_USABLE_P (cpu_features, AVX2) ++ && CPU_FEATURE_USABLE_P (cpu_features, MOVBE) + && CPU_FEATURES_ARCH_P (cpu_features, AVX_Fast_Unaligned_Load)) + return OPTIMIZE (avx2_movbe); + +- if (CPU_FEATURES_CPU_P (cpu_features, SSE4_1)) ++ if (CPU_FEATURE_USABLE_P (cpu_features, SSE4_1)) + return OPTIMIZE (sse4_1); + +- if (CPU_FEATURES_CPU_P (cpu_features, SSSE3)) ++ if (CPU_FEATURE_USABLE_P (cpu_features, SSSE3)) + return OPTIMIZE (ssse3); + + return OPTIMIZE (sse2); +diff --git a/sysdeps/x86_64/multiarch/ifunc-memmove.h b/sysdeps/x86_64/multiarch/ifunc-memmove.h +index 5b1eb1c92c2f199b..5e5f02994531ec14 100644 +--- a/sysdeps/x86_64/multiarch/ifunc-memmove.h ++++ b/sysdeps/x86_64/multiarch/ifunc-memmove.h +@@ -45,13 +45,13 @@ IFUNC_SELECTOR (void) + || CPU_FEATURES_ARCH_P (cpu_features, Prefer_FSRM)) + return OPTIMIZE (erms); + +- if (CPU_FEATURES_ARCH_P (cpu_features, AVX512F_Usable) ++ if (CPU_FEATURE_USABLE_P (cpu_features, AVX512F) + && !CPU_FEATURES_ARCH_P (cpu_features, Prefer_No_AVX512)) + { + if (CPU_FEATURES_ARCH_P (cpu_features, Prefer_No_VZEROUPPER)) + return OPTIMIZE (avx512_no_vzeroupper); + +- if (CPU_FEATURES_CPU_P (cpu_features, ERMS)) ++ if (CPU_FEATURE_USABLE_P (cpu_features, ERMS)) + return OPTIMIZE (avx512_unaligned_erms); + + return OPTIMIZE (avx512_unaligned); +@@ -59,16 +59,16 @@ IFUNC_SELECTOR (void) + + if (CPU_FEATURES_ARCH_P (cpu_features, AVX_Fast_Unaligned_Load)) + { +- if (CPU_FEATURES_CPU_P (cpu_features, ERMS)) ++ if (CPU_FEATURE_USABLE_P (cpu_features, ERMS)) + return OPTIMIZE (avx_unaligned_erms); + + return OPTIMIZE (avx_unaligned); + } + +- if (!CPU_FEATURES_CPU_P (cpu_features, SSSE3) ++ if (!CPU_FEATURE_USABLE_P (cpu_features, SSSE3) + || CPU_FEATURES_ARCH_P (cpu_features, Fast_Unaligned_Copy)) + { +- if (CPU_FEATURES_CPU_P (cpu_features, ERMS)) ++ if (CPU_FEATURE_USABLE_P (cpu_features, ERMS)) + return OPTIMIZE (sse2_unaligned_erms); + + return OPTIMIZE (sse2_unaligned); +diff --git a/sysdeps/x86_64/multiarch/ifunc-memset.h b/sysdeps/x86_64/multiarch/ifunc-memset.h +index 19b5ae676c2d5d53..708bd72e2c3d3963 100644 +--- a/sysdeps/x86_64/multiarch/ifunc-memset.h ++++ b/sysdeps/x86_64/multiarch/ifunc-memset.h +@@ -42,27 +42,27 @@ IFUNC_SELECTOR (void) + if (CPU_FEATURES_ARCH_P (cpu_features, Prefer_ERMS)) + return OPTIMIZE (erms); + +- if (CPU_FEATURES_ARCH_P (cpu_features, AVX512F_Usable) ++ if (CPU_FEATURE_USABLE_P (cpu_features, AVX512F) + && !CPU_FEATURES_ARCH_P (cpu_features, Prefer_No_AVX512)) + { + if (CPU_FEATURES_ARCH_P (cpu_features, Prefer_No_VZEROUPPER)) + return OPTIMIZE (avx512_no_vzeroupper); + +- if (CPU_FEATURES_CPU_P (cpu_features, ERMS)) ++ if (CPU_FEATURE_USABLE_P (cpu_features, ERMS)) + return OPTIMIZE (avx512_unaligned_erms); + + return OPTIMIZE (avx512_unaligned); + } + +- if (CPU_FEATURES_ARCH_P (cpu_features, AVX2_Usable)) ++ if (CPU_FEATURE_USABLE_P (cpu_features, AVX2)) + { +- if (CPU_FEATURES_CPU_P (cpu_features, ERMS)) ++ if (CPU_FEATURE_USABLE_P (cpu_features, ERMS)) + return OPTIMIZE (avx2_unaligned_erms); + else + return OPTIMIZE (avx2_unaligned); + } + +- if (CPU_FEATURES_CPU_P (cpu_features, ERMS)) ++ if (CPU_FEATURE_USABLE_P (cpu_features, ERMS)) + return OPTIMIZE (sse2_unaligned_erms); + + return OPTIMIZE (sse2_unaligned); +diff --git a/sysdeps/x86_64/multiarch/ifunc-sse4_2.h b/sysdeps/x86_64/multiarch/ifunc-sse4_2.h +index f2b791cccf12c425..73383f4b583b29c8 100644 +--- a/sysdeps/x86_64/multiarch/ifunc-sse4_2.h ++++ b/sysdeps/x86_64/multiarch/ifunc-sse4_2.h +@@ -27,7 +27,7 @@ IFUNC_SELECTOR (void) + { + const struct cpu_features* cpu_features = __get_cpu_features (); + +- if (CPU_FEATURES_CPU_P (cpu_features, SSE4_2)) ++ if (CPU_FEATURE_USABLE_P (cpu_features, SSE4_2)) + return OPTIMIZE (sse42); + + return OPTIMIZE (sse2); +diff --git a/sysdeps/x86_64/multiarch/ifunc-strcasecmp.h b/sysdeps/x86_64/multiarch/ifunc-strcasecmp.h +index 1ca170b663a4e65c..6a4bb07849a11f51 100644 +--- a/sysdeps/x86_64/multiarch/ifunc-strcasecmp.h ++++ b/sysdeps/x86_64/multiarch/ifunc-strcasecmp.h +@@ -29,14 +29,14 @@ IFUNC_SELECTOR (void) + { + const struct cpu_features* cpu_features = __get_cpu_features (); + +- if (CPU_FEATURES_ARCH_P (cpu_features, AVX_Usable)) ++ if (CPU_FEATURE_USABLE_P (cpu_features, AVX)) + return OPTIMIZE (avx); + +- if (CPU_FEATURES_CPU_P (cpu_features, SSE4_2) ++ if (CPU_FEATURE_USABLE_P (cpu_features, SSE4_2) + && !CPU_FEATURES_ARCH_P (cpu_features, Slow_SSE4_2)) + return OPTIMIZE (sse42); + +- if (CPU_FEATURES_CPU_P (cpu_features, SSSE3)) ++ if (CPU_FEATURE_USABLE_P (cpu_features, SSSE3)) + return OPTIMIZE (ssse3); + + return OPTIMIZE (sse2); +diff --git a/sysdeps/x86_64/multiarch/ifunc-strcpy.h b/sysdeps/x86_64/multiarch/ifunc-strcpy.h +index 4f2286fefccda069..100dca5cde0ecac5 100644 +--- a/sysdeps/x86_64/multiarch/ifunc-strcpy.h ++++ b/sysdeps/x86_64/multiarch/ifunc-strcpy.h +@@ -32,14 +32,14 @@ IFUNC_SELECTOR (void) + const struct cpu_features* cpu_features = __get_cpu_features (); + + if (!CPU_FEATURES_ARCH_P (cpu_features, Prefer_No_VZEROUPPER) +- && CPU_FEATURES_ARCH_P (cpu_features, AVX2_Usable) ++ && CPU_FEATURE_USABLE_P (cpu_features, AVX2) + && CPU_FEATURES_ARCH_P (cpu_features, AVX_Fast_Unaligned_Load)) + return OPTIMIZE (avx2); + + if (CPU_FEATURES_ARCH_P (cpu_features, Fast_Unaligned_Load)) + return OPTIMIZE (sse2_unaligned); + +- if (CPU_FEATURES_CPU_P (cpu_features, SSSE3)) ++ if (CPU_FEATURE_USABLE_P (cpu_features, SSSE3)) + return OPTIMIZE (ssse3); + + return OPTIMIZE (sse2); +diff --git a/sysdeps/x86_64/multiarch/ifunc-wmemset.h b/sysdeps/x86_64/multiarch/ifunc-wmemset.h +index 2f1085f5fc483c70..eb2422104751b235 100644 +--- a/sysdeps/x86_64/multiarch/ifunc-wmemset.h ++++ b/sysdeps/x86_64/multiarch/ifunc-wmemset.h +@@ -28,10 +28,10 @@ IFUNC_SELECTOR (void) + const struct cpu_features* cpu_features = __get_cpu_features (); + + if (!CPU_FEATURES_ARCH_P (cpu_features, Prefer_No_VZEROUPPER) +- && CPU_FEATURES_ARCH_P (cpu_features, AVX2_Usable) ++ && CPU_FEATURE_USABLE_P (cpu_features, AVX2) + && CPU_FEATURES_ARCH_P (cpu_features, AVX_Fast_Unaligned_Load)) + { +- if (CPU_FEATURES_ARCH_P (cpu_features, AVX512F_Usable) ++ if (CPU_FEATURE_USABLE_P (cpu_features, AVX512F) + && !CPU_FEATURES_ARCH_P (cpu_features, Prefer_No_AVX512)) + return OPTIMIZE (avx512_unaligned); + else +diff --git a/sysdeps/x86_64/multiarch/sched_cpucount.c b/sysdeps/x86_64/multiarch/sched_cpucount.c +index 7949119dcdb5a94b..b38ff37c6511ca1b 100644 +--- a/sysdeps/x86_64/multiarch/sched_cpucount.c ++++ b/sysdeps/x86_64/multiarch/sched_cpucount.c +@@ -33,4 +33,4 @@ + #undef __sched_cpucount + + libc_ifunc (__sched_cpucount, +- HAS_CPU_FEATURE (POPCNT) ? popcount_cpucount : generic_cpucount); ++ CPU_FEATURE_USABLE (POPCNT) ? popcount_cpucount : generic_cpucount); +diff --git a/sysdeps/x86_64/multiarch/strchr.c b/sysdeps/x86_64/multiarch/strchr.c +index 76d64fb378e9bbac..329547132c3a301b 100644 +--- a/sysdeps/x86_64/multiarch/strchr.c ++++ b/sysdeps/x86_64/multiarch/strchr.c +@@ -36,7 +36,7 @@ IFUNC_SELECTOR (void) + const struct cpu_features* cpu_features = __get_cpu_features (); + + if (!CPU_FEATURES_ARCH_P (cpu_features, Prefer_No_VZEROUPPER) +- && CPU_FEATURES_ARCH_P (cpu_features, AVX2_Usable) ++ && CPU_FEATURE_USABLE_P (cpu_features, AVX2) + && CPU_FEATURES_ARCH_P (cpu_features, AVX_Fast_Unaligned_Load)) + return OPTIMIZE (avx2); + +diff --git a/sysdeps/x86_64/multiarch/strcmp.c b/sysdeps/x86_64/multiarch/strcmp.c +index b903e418df151ec1..3f433fbccf9e7121 100644 +--- a/sysdeps/x86_64/multiarch/strcmp.c ++++ b/sysdeps/x86_64/multiarch/strcmp.c +@@ -37,14 +37,14 @@ IFUNC_SELECTOR (void) + const struct cpu_features* cpu_features = __get_cpu_features (); + + if (!CPU_FEATURES_ARCH_P (cpu_features, Prefer_No_VZEROUPPER) +- && CPU_FEATURES_ARCH_P (cpu_features, AVX2_Usable) ++ && CPU_FEATURE_USABLE_P (cpu_features, AVX2) + && CPU_FEATURES_ARCH_P (cpu_features, AVX_Fast_Unaligned_Load)) + return OPTIMIZE (avx2); + + if (CPU_FEATURES_ARCH_P (cpu_features, Fast_Unaligned_Load)) + return OPTIMIZE (sse2_unaligned); + +- if (CPU_FEATURES_CPU_P (cpu_features, SSSE3)) ++ if (CPU_FEATURE_USABLE_P (cpu_features, SSSE3)) + return OPTIMIZE (ssse3); + + return OPTIMIZE (sse2); +diff --git a/sysdeps/x86_64/multiarch/strncmp.c b/sysdeps/x86_64/multiarch/strncmp.c +index 02b6d0b6f5717e2a..686d654f3da84379 100644 +--- a/sysdeps/x86_64/multiarch/strncmp.c ++++ b/sysdeps/x86_64/multiarch/strncmp.c +@@ -37,15 +37,15 @@ IFUNC_SELECTOR (void) + const struct cpu_features* cpu_features = __get_cpu_features (); + + if (!CPU_FEATURES_ARCH_P (cpu_features, Prefer_No_VZEROUPPER) +- && CPU_FEATURES_ARCH_P (cpu_features, AVX2_Usable) ++ && CPU_FEATURE_USABLE_P (cpu_features, AVX2) + && CPU_FEATURES_ARCH_P (cpu_features, AVX_Fast_Unaligned_Load)) + return OPTIMIZE (avx2); + +- if (CPU_FEATURES_CPU_P (cpu_features, SSE4_2) ++ if (CPU_FEATURE_USABLE_P (cpu_features, SSE4_2) + && !CPU_FEATURES_ARCH_P (cpu_features, Slow_SSE4_2)) + return OPTIMIZE (sse42); + +- if (CPU_FEATURES_CPU_P (cpu_features, SSSE3)) ++ if (CPU_FEATURE_USABLE_P (cpu_features, SSSE3)) + return OPTIMIZE (ssse3); + + return OPTIMIZE (sse2); +diff --git a/sysdeps/x86_64/multiarch/test-multiarch.c b/sysdeps/x86_64/multiarch/test-multiarch.c +index 417147c3d5f325a5..cc2ea56a6753402d 100644 +--- a/sysdeps/x86_64/multiarch/test-multiarch.c ++++ b/sysdeps/x86_64/multiarch/test-multiarch.c +@@ -75,18 +75,18 @@ do_test (int argc, char **argv) + int fails; + + get_cpuinfo (); +- fails = check_proc ("avx", HAS_ARCH_FEATURE (AVX_Usable), +- "HAS_ARCH_FEATURE (AVX_Usable)"); +- fails += check_proc ("fma4", HAS_ARCH_FEATURE (FMA4_Usable), +- "HAS_ARCH_FEATURE (FMA4_Usable)"); +- fails += check_proc ("sse4_2", HAS_CPU_FEATURE (SSE4_2), +- "HAS_CPU_FEATURE (SSE4_2)"); +- fails += check_proc ("sse4_1", HAS_CPU_FEATURE (SSE4_1) +- , "HAS_CPU_FEATURE (SSE4_1)"); +- fails += check_proc ("ssse3", HAS_CPU_FEATURE (SSSE3), +- "HAS_CPU_FEATURE (SSSE3)"); +- fails += check_proc ("popcnt", HAS_CPU_FEATURE (POPCNT), +- "HAS_CPU_FEATURE (POPCNT)"); ++ fails = check_proc ("avx", CPU_FEATURE_USABLE (AVX), ++ "CPU_FEATURE_USABLE (AVX)"); ++ fails += check_proc ("fma4", CPU_FEATURE_USABLE (FMA4), ++ "CPU_FEATURE_USABLE (FMA4)"); ++ fails += check_proc ("sse4_2", CPU_FEATURE_USABLE (SSE4_2), ++ "CPU_FEATURE_USABLE (SSE4_2)"); ++ fails += check_proc ("sse4_1", CPU_FEATURE_USABLE (SSE4_1) ++ , "CPU_FEATURE_USABLE (SSE4_1)"); ++ fails += check_proc ("ssse3", CPU_FEATURE_USABLE (SSSE3), ++ "CPU_FEATURE_USABLE (SSSE3)"); ++ fails += check_proc ("popcnt", CPU_FEATURE_USABLE (POPCNT), ++ "CPU_FEATURE_USABLE (POPCNT)"); + + printf ("%d differences between /proc/cpuinfo and glibc code.\n", fails); + +diff --git a/sysdeps/x86_64/multiarch/wcscpy.c b/sysdeps/x86_64/multiarch/wcscpy.c +index f23b1fd853a4dcb4..8fffb5c3163ab3e4 100644 +--- a/sysdeps/x86_64/multiarch/wcscpy.c ++++ b/sysdeps/x86_64/multiarch/wcscpy.c +@@ -34,7 +34,7 @@ IFUNC_SELECTOR (void) + { + const struct cpu_features* cpu_features = __get_cpu_features (); + +- if (CPU_FEATURES_CPU_P (cpu_features, SSSE3)) ++ if (CPU_FEATURE_USABLE_P (cpu_features, SSSE3)) + return OPTIMIZE (ssse3); + + return OPTIMIZE (sse2); +diff --git a/sysdeps/x86_64/multiarch/wcsnlen.c b/sysdeps/x86_64/multiarch/wcsnlen.c +index bd376057e3e26ed6..b3144c938df70b1e 100644 +--- a/sysdeps/x86_64/multiarch/wcsnlen.c ++++ b/sysdeps/x86_64/multiarch/wcsnlen.c +@@ -36,11 +36,11 @@ IFUNC_SELECTOR (void) + const struct cpu_features* cpu_features = __get_cpu_features (); + + if (!CPU_FEATURES_ARCH_P (cpu_features, Prefer_No_VZEROUPPER) +- && CPU_FEATURES_ARCH_P (cpu_features, AVX2_Usable) ++ && CPU_FEATURE_USABLE_P (cpu_features, AVX2) + && CPU_FEATURES_ARCH_P (cpu_features, AVX_Fast_Unaligned_Load)) + return OPTIMIZE (avx2); + +- if (CPU_FEATURES_CPU_P (cpu_features, SSE4_1)) ++ if (CPU_FEATURE_USABLE_P (cpu_features, SSE4_1)) + return OPTIMIZE (sse4_1); + + return OPTIMIZE (sse2); diff --git a/SOURCES/glibc-rh1817513-78.patch b/SOURCES/glibc-rh1817513-78.patch new file mode 100644 index 0000000..2395513 --- /dev/null +++ b/SOURCES/glibc-rh1817513-78.patch @@ -0,0 +1,75 @@ +commit 94b63e66206a9ad38872a9136a623ce73cf7c858 +Author: Florian Weimer +Date: Thu Feb 7 09:02:00 2019 +0100 + + support: Implement xdlmopen + + Put xdlmopen into its own file, to avoid disturbing static linking + tests (where dlmopen pulls in additional code). + +diff --git a/support/Makefile b/support/Makefile +index 5808a42dce87151f..895b83a426369b0c 100644 +--- a/support/Makefile ++++ b/support/Makefile +@@ -86,6 +86,7 @@ libsupport-routines = \ + xconnect \ + xcopy_file_range \ + xdlfcn \ ++ xdlmopen \ + xdup2 \ + xfclose \ + xfopen \ +diff --git a/support/xdlfcn.h b/support/xdlfcn.h +index ab1cbb3cb9bb1cc7..a53fb61b133af5c3 100644 +--- a/support/xdlfcn.h ++++ b/support/xdlfcn.h +@@ -25,11 +25,11 @@ __BEGIN_DECLS + + /* Each of these terminates process on failure with relevant error message. */ + void *xdlopen (const char *filename, int flags); ++void *xdlmopen (Lmid_t lmid, const char *filename, int flags); + void *xdlsym (void *handle, const char *symbol); + void *xdlvsym (void *handle, const char *symbol, const char *version); + void xdlclose (void *handle); + +- + __END_DECLS + + #endif /* SUPPORT_DLOPEN_H */ +diff --git a/support/xdlmopen.c b/support/xdlmopen.c +new file mode 100644 +index 0000000000000000..9a39ba8801eb1617 +--- /dev/null ++++ b/support/xdlmopen.c +@@ -0,0 +1,31 @@ ++/* dlmopen with error checking. ++ Copyright (C) 2017-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, see ++ . */ ++ ++#include ++#include ++ ++void * ++xdlmopen (Lmid_t lmid, const char *filename, int flags) ++{ ++ void *dso = dlmopen (lmid, filename, flags); ++ ++ if (dso == NULL) ++ FAIL_EXIT1 ("error: dlmopen: %s\n", dlerror ()); ++ ++ return dso; ++} diff --git a/SOURCES/glibc-rh1817513-79.patch b/SOURCES/glibc-rh1817513-79.patch new file mode 100644 index 0000000..5b1cb3a --- /dev/null +++ b/SOURCES/glibc-rh1817513-79.patch @@ -0,0 +1,642 @@ +commit ffb17e7ba3a5ba9632cee97330b325072fbe41dd +Author: Szabolcs Nagy +Date: Wed Jun 10 13:40:40 2020 +0100 + + rtld: Avoid using up static TLS surplus for optimizations [BZ #25051] + + On some targets static TLS surplus area can be used opportunistically + for dynamically loaded modules such that the TLS access then becomes + faster (TLSDESC and powerpc TLS optimization). However we don't want + all surplus TLS to be used for this optimization because dynamically + loaded modules with initial-exec model TLS can only use surplus TLS. + + The new contract for surplus static TLS use is: + + - libc.so can have up to 192 bytes of IE TLS, + - other system libraries together can have up to 144 bytes of IE TLS. + - Some "optional" static TLS is available for opportunistic use. + + The optional TLS is now tunable: rtld.optional_static_tls, so users + can directly affect the allocated static TLS size. (Note that module + unloading with dlclose does not reclaim static TLS. After the optional + TLS runs out, TLS access is no longer optimized to use static TLS.) + + The default setting of rtld.optional_static_tls is 512 so the surplus + TLS is 3*192 + 4*144 + 512 = 1664 by default, the same as before. + + Fixes BZ #25051. + + Tested on aarch64-linux-gnu and x86_64-linux-gnu. + + Reviewed-by: Carlos O'Donell + +Conflicts: + elf/Makefile + (Missing __libc_single_threaded downstream.) + +diff --git a/csu/libc-tls.c b/csu/libc-tls.c +index 6f2a47dc86222407..76aa1b98ea059a43 100644 +--- a/csu/libc-tls.c ++++ b/csu/libc-tls.c +@@ -62,6 +62,9 @@ size_t _dl_tls_static_align; + loaded modules with IE-model TLS or for TLSDESC optimization. + See comments in elf/dl-tls.c where it is initialized. */ + size_t _dl_tls_static_surplus; ++/* Remaining amount of static TLS that may be used for optimizing ++ dynamic TLS access (e.g. with TLSDESC). */ ++size_t _dl_tls_static_optional; + + /* Generation counter for the dtv. */ + size_t _dl_tls_generation; +diff --git a/elf/Makefile b/elf/Makefile +index cbced7605ebe2443..8b96bfefd852b79f 100644 +--- a/elf/Makefile ++++ b/elf/Makefile +@@ -197,7 +197,8 @@ tests += restest1 preloadtest loadfail multiload origtest resolvfail \ + 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-audit14 tst-audit15 tst-audit16 \ ++ tst-tls-ie tst-tls-ie-dlmopen + # reldep9 + tests-internal += loadtest unload unload2 circleload1 \ + neededtest neededtest2 neededtest3 neededtest4 \ +@@ -313,7 +314,10 @@ modules-names = testobj1 testobj2 testobj3 testobj4 testobj5 testobj6 \ + 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-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 + + # Most modules build with _ISOMAC defined, but those filtered out + # depend on internal headers. +@@ -1690,3 +1694,23 @@ $(objpfx)tst-auxobj: $(objpfx)tst-filterobj-aux.so + $(objpfx)tst-auxobj-dlopen: $(libdl) + $(objpfx)tst-auxobj.out: $(objpfx)tst-filterobj-filtee.so + $(objpfx)tst-auxobj-dlopen.out: $(objpfx)tst-filterobj-filtee.so ++ ++$(objpfx)tst-tls-ie: $(libdl) $(shared-thread-library) ++$(objpfx)tst-tls-ie.out: \ ++ $(objpfx)tst-tls-ie-mod0.so \ ++ $(objpfx)tst-tls-ie-mod1.so \ ++ $(objpfx)tst-tls-ie-mod2.so \ ++ $(objpfx)tst-tls-ie-mod3.so \ ++ $(objpfx)tst-tls-ie-mod4.so \ ++ $(objpfx)tst-tls-ie-mod5.so \ ++ $(objpfx)tst-tls-ie-mod6.so ++ ++$(objpfx)tst-tls-ie-dlmopen: $(libdl) $(shared-thread-library) ++$(objpfx)tst-tls-ie-dlmopen.out: \ ++ $(objpfx)tst-tls-ie-mod0.so \ ++ $(objpfx)tst-tls-ie-mod1.so \ ++ $(objpfx)tst-tls-ie-mod2.so \ ++ $(objpfx)tst-tls-ie-mod3.so \ ++ $(objpfx)tst-tls-ie-mod4.so \ ++ $(objpfx)tst-tls-ie-mod5.so \ ++ $(objpfx)tst-tls-ie-mod6.so +diff --git a/elf/dl-reloc.c b/elf/dl-reloc.c +index afeace4d3e49180c..c6139b89d4ecddc8 100644 +--- a/elf/dl-reloc.c ++++ b/elf/dl-reloc.c +@@ -39,13 +39,16 @@ + /* We are trying to perform a static TLS relocation in MAP, but it was + dynamically loaded. This can only work if there is enough surplus in + the static TLS area already allocated for each running thread. If this +- object's TLS segment is too big to fit, we fail. If it fits, +- we set MAP->l_tls_offset and return. +- This function intentionally does not return any value but signals error +- directly, as static TLS should be rare and code handling it should +- not be inlined as much as possible. */ ++ object's TLS segment is too big to fit, we fail with -1. If it fits, ++ we set MAP->l_tls_offset and return 0. ++ A portion of the surplus static TLS can be optionally used to optimize ++ dynamic TLS access (with TLSDESC or powerpc TLS optimizations). ++ If OPTIONAL is true then TLS is allocated for such optimization and ++ the caller must have a fallback in case the optional portion of surplus ++ TLS runs out. If OPTIONAL is false then the entire surplus TLS area is ++ considered and the allocation only fails if that runs out. */ + int +-_dl_try_allocate_static_tls (struct link_map *map) ++_dl_try_allocate_static_tls (struct link_map *map, bool optional) + { + /* If we've already used the variable with dynamic access, or if the + alignment requirements are too high, fail. */ +@@ -68,8 +71,14 @@ _dl_try_allocate_static_tls (struct link_map *map) + + size_t n = (freebytes - blsize) / map->l_tls_align; + +- size_t offset = GL(dl_tls_static_used) + (freebytes - n * map->l_tls_align +- - map->l_tls_firstbyte_offset); ++ /* Account optional static TLS surplus usage. */ ++ size_t use = freebytes - n * map->l_tls_align - map->l_tls_firstbyte_offset; ++ if (optional && use > GL(dl_tls_static_optional)) ++ goto fail; ++ else if (optional) ++ GL(dl_tls_static_optional) -= use; ++ ++ size_t offset = GL(dl_tls_static_used) + use; + + map->l_tls_offset = GL(dl_tls_static_used) = offset; + #elif TLS_DTV_AT_TP +@@ -83,6 +92,13 @@ _dl_try_allocate_static_tls (struct link_map *map) + if (used > GL(dl_tls_static_size)) + goto fail; + ++ /* Account optional static TLS surplus usage. */ ++ size_t use = used - GL(dl_tls_static_used); ++ if (optional && use > GL(dl_tls_static_optional)) ++ goto fail; ++ else if (optional) ++ GL(dl_tls_static_optional) -= use; ++ + map->l_tls_offset = offset; + map->l_tls_firstbyte_offset = GL(dl_tls_static_used); + GL(dl_tls_static_used) = used; +@@ -110,12 +126,15 @@ _dl_try_allocate_static_tls (struct link_map *map) + return 0; + } + ++/* This function intentionally does not return any value but signals error ++ directly, as static TLS should be rare and code handling it should ++ not be inlined as much as possible. */ + void + __attribute_noinline__ + _dl_allocate_static_tls (struct link_map *map) + { + if (map->l_tls_offset == FORCED_DYNAMIC_TLS_OFFSET +- || _dl_try_allocate_static_tls (map)) ++ || _dl_try_allocate_static_tls (map, false)) + { + _dl_signal_error (0, map->l_name, NULL, N_("\ + cannot allocate memory in static TLS block")); +diff --git a/elf/dl-tls.c b/elf/dl-tls.c +index cfda76f6de96df57..4f8c35b7d37bfc18 100644 +--- a/elf/dl-tls.c ++++ b/elf/dl-tls.c +@@ -60,8 +60,6 @@ + This should be large enough to cover runtime libraries of the + compiler such as libgomp and libraries in libc other than libc.so. */ + #define OTHER_IE_TLS 144 +-/* Size of additional surplus TLS, placeholder for TLS optimizations. */ +-#define OPT_SURPLUS_TLS 512 + + /* Calculate the size of the static TLS surplus, when the given + number of audit modules are loaded. Must be called after the +@@ -69,13 +67,15 @@ + void + _dl_tls_static_surplus_init (size_t naudit) + { +- size_t nns; ++ size_t nns, opt_tls; + + #if HAVE_TUNABLES + nns = TUNABLE_GET (nns, size_t, NULL); ++ opt_tls = TUNABLE_GET (optional_static_tls, size_t, NULL); + #else + /* Default values of the tunables. */ + nns = 4; ++ opt_tls = 512; + #endif + if (nns > DL_NNS) + nns = DL_NNS; +@@ -84,9 +84,10 @@ _dl_tls_static_surplus_init (size_t naudit) + (unsigned long) naudit, (unsigned long) (DL_NNS - nns)); + nns += naudit; + ++ GL(dl_tls_static_optional) = opt_tls; + GLRO(dl_tls_static_surplus) = ((nns - 1) * LIBC_IE_TLS + + nns * OTHER_IE_TLS +- + OPT_SURPLUS_TLS); ++ + opt_tls); + } + + /* Out-of-memory handler. */ +diff --git a/elf/dl-tunables.list b/elf/dl-tunables.list +index 7337fb85062c91a7..6408a8e5ae92d2c6 100644 +--- a/elf/dl-tunables.list ++++ b/elf/dl-tunables.list +@@ -134,5 +134,10 @@ glibc { + maxval: 16 + default: 4 + } ++ optional_static_tls { ++ type: SIZE_T ++ minval: 0 ++ default: 512 ++ } + } + } +diff --git a/elf/dynamic-link.h b/elf/dynamic-link.h +index 9e9d5a3b28bc06c5..2fc3c91b7defe84e 100644 +--- a/elf/dynamic-link.h ++++ b/elf/dynamic-link.h +@@ -40,9 +40,10 @@ + (__builtin_expect ((sym_map)->l_tls_offset \ + != FORCED_DYNAMIC_TLS_OFFSET, 1) \ + && (__builtin_expect ((sym_map)->l_tls_offset != NO_TLS_OFFSET, 1) \ +- || _dl_try_allocate_static_tls (sym_map) == 0)) ++ || _dl_try_allocate_static_tls (sym_map, true) == 0)) + +-int _dl_try_allocate_static_tls (struct link_map *map) attribute_hidden; ++int _dl_try_allocate_static_tls (struct link_map *map, bool optional) ++ attribute_hidden; + + #include + +diff --git a/elf/tst-tls-ie-dlmopen.c b/elf/tst-tls-ie-dlmopen.c +new file mode 100644 +index 0000000000000000..c7b5c688e362c861 +--- /dev/null ++++ b/elf/tst-tls-ie-dlmopen.c +@@ -0,0 +1,112 @@ ++/* Test dlopen of modules with initial-exec TLS after dlmopen. ++ Copyright (C) 2016-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 ++ . */ ++ ++/* This test tries to check that surplus static TLS is not used up for ++ dynamic TLS optimizations and 4*144 = 576 bytes of static TLS is ++ still available for dlopening modules with initial-exec TLS after 3 ++ new dlmopen namespaces are created. It depends on rtld.nns=4 and ++ rtld.optional_static_tls=512 tunable settings. */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++static int do_test (void); ++#include ++#include ++#include ++#include ++ ++/* Have some big TLS in the main exe: should not use surplus TLS. */ ++__thread char maintls[1000]; ++ ++static pthread_barrier_t barrier; ++ ++/* Forces multi-threaded behaviour. */ ++static void * ++blocked_thread_func (void *closure) ++{ ++ xpthread_barrier_wait (&barrier); ++ /* TLS load and access tests run here in the main thread. */ ++ xpthread_barrier_wait (&barrier); ++ return NULL; ++} ++ ++static void * ++load_and_access (Lmid_t lmid, const char *mod, const char *func) ++{ ++ /* Load module with TLS. */ ++ void *p = xdlmopen (lmid, mod, RTLD_NOW); ++ /* Access the TLS variable to ensure it is allocated. */ ++ void (*f) (void) = (void (*) (void))xdlsym (p, func); ++ f (); ++ return p; ++} ++ ++static int ++do_test (void) ++{ ++ void *mods[5]; ++ ++ { ++ int ret = pthread_barrier_init (&barrier, NULL, 2); ++ if (ret != 0) ++ { ++ errno = ret; ++ printf ("error: pthread_barrier_init: %m\n"); ++ exit (1); ++ } ++ } ++ ++ pthread_t blocked_thread = xpthread_create (NULL, blocked_thread_func, NULL); ++ xpthread_barrier_wait (&barrier); ++ ++ printf ("maintls[%zu]:\t %p .. %p\n", ++ sizeof maintls, maintls, maintls + sizeof maintls); ++ memset (maintls, 1, sizeof maintls); ++ ++ /* Load modules with dynamic TLS (use surplus static TLS for libc ++ in new namespaces and may be for TLS optimizations too). */ ++ mods[0] = load_and_access (LM_ID_BASE, "tst-tls-ie-mod0.so", "access0"); ++ mods[1] = load_and_access (LM_ID_NEWLM, "tst-tls-ie-mod1.so", "access1"); ++ mods[2] = load_and_access (LM_ID_NEWLM, "tst-tls-ie-mod2.so", "access2"); ++ mods[3] = load_and_access (LM_ID_NEWLM, "tst-tls-ie-mod3.so", "access3"); ++ /* Load modules with initial-exec TLS (can only use surplus static TLS). */ ++ mods[4] = load_and_access (LM_ID_BASE, "tst-tls-ie-mod6.so", "access6"); ++ ++ /* Here 576 bytes + 3 * libc use of surplus static TLS is in use so less ++ than 1024 bytes are available (exact number depends on TLS optimizations ++ and the libc TLS use). */ ++ printf ("The next dlmopen should fail...\n"); ++ void *p = dlmopen (LM_ID_BASE, "tst-tls-ie-mod4.so", RTLD_NOW); ++ if (p != NULL) ++ FAIL_EXIT1 ("error: expected dlmopen to fail because there is " ++ "not enough surplus static TLS.\n"); ++ printf ("...OK failed with: %s.\n", dlerror ()); ++ ++ xpthread_barrier_wait (&barrier); ++ xpthread_join (blocked_thread); ++ ++ /* Close the modules. */ ++ for (int i = 0; i < 5; ++i) ++ xdlclose (mods[i]); ++ ++ return 0; ++} +diff --git a/elf/tst-tls-ie-mod.h b/elf/tst-tls-ie-mod.h +new file mode 100644 +index 0000000000000000..46b362a9b783d214 +--- /dev/null ++++ b/elf/tst-tls-ie-mod.h +@@ -0,0 +1,40 @@ ++/* Module with specified TLS size and model. ++ 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 ++ . */ ++ ++/* This file is parameterized by macros N, SIZE and MODEL. */ ++ ++#include ++#include ++ ++#define CONCATX(x, y) x ## y ++#define CONCAT(x, y) CONCATX (x, y) ++#define STRX(x) #x ++#define STR(x) STRX (x) ++ ++#define VAR CONCAT (var, N) ++ ++__attribute__ ((aligned (8), tls_model (MODEL))) ++__thread char VAR[SIZE]; ++ ++void ++CONCAT (access, N) (void) ++{ ++ printf (STR (VAR) "[%d]:\t %p .. %p " MODEL "\n", SIZE, VAR, VAR + SIZE); ++ fflush (stdout); ++ memset (VAR, 1, SIZE); ++} +diff --git a/elf/tst-tls-ie-mod0.c b/elf/tst-tls-ie-mod0.c +new file mode 100644 +index 0000000000000000..2450686e400e1141 +--- /dev/null ++++ b/elf/tst-tls-ie-mod0.c +@@ -0,0 +1,4 @@ ++#define N 0 ++#define SIZE 480 ++#define MODEL "global-dynamic" ++#include "tst-tls-ie-mod.h" +diff --git a/elf/tst-tls-ie-mod1.c b/elf/tst-tls-ie-mod1.c +new file mode 100644 +index 0000000000000000..849ff91e53b0a518 +--- /dev/null ++++ b/elf/tst-tls-ie-mod1.c +@@ -0,0 +1,4 @@ ++#define N 1 ++#define SIZE 120 ++#define MODEL "global-dynamic" ++#include "tst-tls-ie-mod.h" +diff --git a/elf/tst-tls-ie-mod2.c b/elf/tst-tls-ie-mod2.c +new file mode 100644 +index 0000000000000000..23915ab67bab0ada +--- /dev/null ++++ b/elf/tst-tls-ie-mod2.c +@@ -0,0 +1,4 @@ ++#define N 2 ++#define SIZE 24 ++#define MODEL "global-dynamic" ++#include "tst-tls-ie-mod.h" +diff --git a/elf/tst-tls-ie-mod3.c b/elf/tst-tls-ie-mod3.c +new file mode 100644 +index 0000000000000000..5395f844a5999ea9 +--- /dev/null ++++ b/elf/tst-tls-ie-mod3.c +@@ -0,0 +1,4 @@ ++#define N 3 ++#define SIZE 16 ++#define MODEL "global-dynamic" ++#include "tst-tls-ie-mod.h" +diff --git a/elf/tst-tls-ie-mod4.c b/elf/tst-tls-ie-mod4.c +new file mode 100644 +index 0000000000000000..93ac2eacae292d86 +--- /dev/null ++++ b/elf/tst-tls-ie-mod4.c +@@ -0,0 +1,4 @@ ++#define N 4 ++#define SIZE 1024 ++#define MODEL "initial-exec" ++#include "tst-tls-ie-mod.h" +diff --git a/elf/tst-tls-ie-mod5.c b/elf/tst-tls-ie-mod5.c +new file mode 100644 +index 0000000000000000..84b3fd285b5b5a3e +--- /dev/null ++++ b/elf/tst-tls-ie-mod5.c +@@ -0,0 +1,4 @@ ++#define N 5 ++#define SIZE 128 ++#define MODEL "initial-exec" ++#include "tst-tls-ie-mod.h" +diff --git a/elf/tst-tls-ie-mod6.c b/elf/tst-tls-ie-mod6.c +new file mode 100644 +index 0000000000000000..c736bf0684f3b08f +--- /dev/null ++++ b/elf/tst-tls-ie-mod6.c +@@ -0,0 +1,4 @@ ++#define N 6 ++#define SIZE 576 ++#define MODEL "initial-exec" ++#include "tst-tls-ie-mod.h" +diff --git a/elf/tst-tls-ie.c b/elf/tst-tls-ie.c +new file mode 100644 +index 0000000000000000..2dc0894480417389 +--- /dev/null ++++ b/elf/tst-tls-ie.c +@@ -0,0 +1,111 @@ ++/* Test dlopen of modules with initial-exec TLS. ++ Copyright (C) 2016-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 ++ . */ ++ ++/* This test tries to check that surplus static TLS is not used up for ++ dynamic TLS optimizations and 3*192 + 4*144 = 1152 bytes of static ++ TLS is available for dlopening modules with initial-exec TLS. It ++ depends on rtld.nns=4 and rtld.optional_static_tls=512 tunable setting. */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++static int do_test (void); ++#include ++#include ++#include ++#include ++ ++/* Have some big TLS in the main exe: should not use surplus TLS. */ ++__thread char maintls[1000]; ++ ++static pthread_barrier_t barrier; ++ ++/* Forces multi-threaded behaviour. */ ++static void * ++blocked_thread_func (void *closure) ++{ ++ xpthread_barrier_wait (&barrier); ++ /* TLS load and access tests run here in the main thread. */ ++ xpthread_barrier_wait (&barrier); ++ return NULL; ++} ++ ++static void * ++load_and_access (const char *mod, const char *func) ++{ ++ /* Load module with TLS. */ ++ void *p = xdlopen (mod, RTLD_NOW); ++ /* Access the TLS variable to ensure it is allocated. */ ++ void (*f) (void) = (void (*) (void))xdlsym (p, func); ++ f (); ++ return p; ++} ++ ++static int ++do_test (void) ++{ ++ void *mods[6]; ++ ++ { ++ int ret = pthread_barrier_init (&barrier, NULL, 2); ++ if (ret != 0) ++ { ++ errno = ret; ++ printf ("error: pthread_barrier_init: %m\n"); ++ exit (1); ++ } ++ } ++ ++ pthread_t blocked_thread = xpthread_create (NULL, blocked_thread_func, NULL); ++ xpthread_barrier_wait (&barrier); ++ ++ printf ("maintls[%zu]:\t %p .. %p\n", ++ sizeof maintls, maintls, maintls + sizeof maintls); ++ memset (maintls, 1, sizeof maintls); ++ ++ /* Load modules with dynamic TLS (may use surplus static TLS ++ opportunistically). */ ++ mods[0] = load_and_access ("tst-tls-ie-mod0.so", "access0"); ++ mods[1] = load_and_access ("tst-tls-ie-mod1.so", "access1"); ++ mods[2] = load_and_access ("tst-tls-ie-mod2.so", "access2"); ++ mods[3] = load_and_access ("tst-tls-ie-mod3.so", "access3"); ++ /* Load modules with initial-exec TLS (can only use surplus static TLS). */ ++ mods[4] = load_and_access ("tst-tls-ie-mod4.so", "access4"); ++ mods[5] = load_and_access ("tst-tls-ie-mod5.so", "access5"); ++ ++ /* Here 1152 bytes of surplus static TLS is in use and at most 512 bytes ++ are available (depending on TLS optimizations). */ ++ printf ("The next dlopen should fail...\n"); ++ void *p = dlopen ("tst-tls-ie-mod6.so", RTLD_NOW); ++ if (p != NULL) ++ FAIL_EXIT1 ("error: expected dlopen to fail because there is " ++ "not enough surplus static TLS.\n"); ++ printf ("...OK failed with: %s.\n", dlerror ()); ++ ++ xpthread_barrier_wait (&barrier); ++ xpthread_join (blocked_thread); ++ ++ /* Close the modules. */ ++ for (int i = 0; i < 6; ++i) ++ xdlclose (mods[i]); ++ ++ return 0; ++} +diff --git a/manual/tunables.texi b/manual/tunables.texi +index e6a3e9a2cf5c959c..bd737b5d57080462 100644 +--- a/manual/tunables.texi ++++ b/manual/tunables.texi +@@ -249,6 +249,23 @@ increase the per-thread memory usage as necessary, so this tunable does + not need to be changed to allow many audit modules e.g. via @env{LD_AUDIT}. + @end deftp + ++@deftp Tunable glibc.rtld.optional_static_tls ++Sets the amount of surplus static TLS in bytes to allocate at program ++startup. Every thread created allocates this amount of specified surplus ++static TLS. This is a minimum value and additional space may be allocated ++for internal purposes including alignment. Optional static TLS is used for ++optimizing dynamic TLS access for platforms that support such optimizations ++e.g. TLS descriptors or optimized TLS access for POWER (@code{DT_PPC64_OPT} ++and @code{DT_PPC_OPT}). In order to make the best use of such optimizations ++the value should be as many bytes as would be required to hold all TLS ++variables in all dynamic loaded shared libraries. The value cannot be known ++by the dynamic loader because it doesn't know the expected set of shared ++libraries which will be loaded. The existing static TLS space cannot be ++changed once allocated at process startup. The default allocation of ++optional static TLS is 512 bytes and is allocated in every thread. ++@end deftp ++ ++ + @node Elision Tunables + @section Elision Tunables + @cindex elision tunables +diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h +index 293f3ab5a496afdf..37f1915b0c75a020 100644 +--- a/sysdeps/generic/ldsodefs.h ++++ b/sysdeps/generic/ldsodefs.h +@@ -441,6 +441,9 @@ struct rtld_global + EXTERN size_t _dl_tls_static_used; + /* Alignment requirement of the static TLS block. */ + EXTERN size_t _dl_tls_static_align; ++ /* Remaining amount of static TLS that may be used for optimizing ++ dynamic TLS access (e.g. with TLSDESC). */ ++ EXTERN size_t _dl_tls_static_optional; + + /* Number of additional entries in the slotinfo array of each slotinfo + list element. A large number makes it almost certain take we never diff --git a/SOURCES/glibc-rh1817513-8.patch b/SOURCES/glibc-rh1817513-8.patch new file mode 100644 index 0000000..5f82d23 --- /dev/null +++ b/SOURCES/glibc-rh1817513-8.patch @@ -0,0 +1,74 @@ +commit d90c9b1a121295a5e31810b899ab637f68898857 +Author: Joseph Myers +Date: Thu Sep 20 12:43:41 2018 +0000 + + Invert sense of list of i686-class processors in sysdeps/x86/cpu-features.h. + + I noticed that sysdeps/x86/cpu-features.h had conditionals on whether + to define HAS_CPUID, HAS_I586 and HAS_I686 with a long list of + preprocessor macros for i686-and-later processors which however was + out of date. This patch avoids the problem of the list getting out of + date by instead having conditionals on all the (few, old) pre-i686 + processors for which GCC has preprocessor macros, rather than the + (many, expanding list) i686-and-later processors. It seems HAS_I586 + and HAS_I686 are unused so the only effect of these macros being + missing is that 32-bit glibc built for one of these processors would + end up doing runtime detection of CPUID availability. + + i386 builds are prevented by a configure test so there is no need to + allow for them here. __geode__ (no long nops?) and __k6__ (no CMOV, + at least according to GCC) are conservatively handled as i586, not + i686, here (as noted above, this is a theoretical distinction at + present in that only HAS_CPUID appears to be used). + + Tested for x86. + + * sysdeps/x86/cpu-features.h [__geode__ || __k6__]: Handle like + [__i586__ || __pentium__]. + [__i486__]: Handle explicitly. + (HAS_CPUID): Define to 1 if above macros are undefined. + (HAS_I586): Likewise. + (HAS_I686): Likewise. + +diff --git a/sysdeps/x86/cpu-features.h b/sysdeps/x86/cpu-features.h +index d342664c64ab7aa1..fb22d7b9d6226a92 100644 +--- a/sysdeps/x86/cpu-features.h ++++ b/sysdeps/x86/cpu-features.h +@@ -257,30 +257,19 @@ extern const struct cpu_features *__get_cpu_features (void) + + #ifdef __x86_64__ + # define HAS_CPUID 1 +-#elif defined __i586__ || defined __pentium__ ++#elif (defined __i586__ || defined __pentium__ \ ++ || defined __geode__ || defined __k6__) + # define HAS_CPUID 1 + # define HAS_I586 1 + # define HAS_I686 HAS_ARCH_FEATURE (I686) +-#elif (defined __i686__ || defined __pentiumpro__ \ +- || defined __pentium4__ || defined __nocona__ \ +- || defined __atom__ || defined __core2__ \ +- || defined __corei7__ || defined __corei7_avx__ \ +- || defined __core_avx2__ || defined __nehalem__ \ +- || defined __sandybridge__ || defined __haswell__ \ +- || defined __knl__ || defined __bonnell__ \ +- || defined __silvermont__ \ +- || defined __k6__ || defined __k8__ \ +- || defined __athlon__ || defined __amdfam10__ \ +- || defined __bdver1__ || defined __bdver2__ \ +- || defined __bdver3__ || defined __bdver4__ \ +- || defined __btver1__ || defined __btver2__) +-# define HAS_CPUID 1 +-# define HAS_I586 1 +-# define HAS_I686 1 +-#else ++#elif defined __i486__ + # define HAS_CPUID 0 + # define HAS_I586 HAS_ARCH_FEATURE (I586) + # define HAS_I686 HAS_ARCH_FEATURE (I686) ++#else ++# define HAS_CPUID 1 ++# define HAS_I586 1 ++# define HAS_I686 1 + #endif + + #endif /* cpu_features_h */ diff --git a/SOURCES/glibc-rh1817513-80.patch b/SOURCES/glibc-rh1817513-80.patch new file mode 100644 index 0000000..1f83e15 --- /dev/null +++ b/SOURCES/glibc-rh1817513-80.patch @@ -0,0 +1,151 @@ +commit 07ed32f920f0bcb1ddb400e4ed606104756dee32 +Author: Florian Weimer +Date: Mon Jul 20 13:30:45 2020 +0200 + + elf: Change TLS static surplus default back to 1664 + + Make the computation in elf/dl-tls.c more transparent, and add + an explicit test for the historic value. + + Reviewed-by: Carlos O'Donell + +Conflicts: + elf/Makefile + (Missing test backports.) + elf/dl-tls.c + (Missing backport of rseq and its revert.) + +diff --git a/elf/Makefile b/elf/Makefile +index 8b96bfefd852b79f..82b5b4a07495c805 100644 +--- a/elf/Makefile ++++ b/elf/Makefile +@@ -204,7 +204,7 @@ 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-create_format1 tst-tls-surplus + tests-container += tst-pldd + ifeq ($(build-hardcoded-path-in-tests),yes) + tests += tst-dlopen-aout +@@ -1714,3 +1714,5 @@ $(objpfx)tst-tls-ie-dlmopen.out: \ + $(objpfx)tst-tls-ie-mod4.so \ + $(objpfx)tst-tls-ie-mod5.so \ + $(objpfx)tst-tls-ie-mod6.so ++ ++$(objpfx)tst-tls-surplus: $(libdl) +diff --git a/elf/dl-tls.c b/elf/dl-tls.c +index 4f8c35b7d37bfc18..cccf74b33481b866 100644 +--- a/elf/dl-tls.c ++++ b/elf/dl-tls.c +@@ -54,13 +54,37 @@ + Audit modules use their own namespaces, they are not included in rtld.nns, + but come on top when computing the number of namespaces. */ + +-/* Size of initial-exec TLS in libc.so. */ +-#define LIBC_IE_TLS 192 ++/* Size of initial-exec TLS in libc.so. This should be the maximum of ++ observed PT_GNU_TLS sizes across all architectures. Some ++ architectures have lower values due to differences in type sizes ++ and link editor capabilities. */ ++#define LIBC_IE_TLS 144 ++ + /* Size of initial-exec TLS in libraries other than libc.so. + This should be large enough to cover runtime libraries of the + compiler such as libgomp and libraries in libc other than libc.so. */ + #define OTHER_IE_TLS 144 + ++/* Default number of namespaces. */ ++#define DEFAULT_NNS 4 ++ ++/* Default for dl_tls_static_optional. */ ++#define OPTIONAL_TLS 512 ++ ++/* Compute the static TLS surplus based on the namespace count and the ++ TLS space that can be used for optimizations. */ ++static inline int ++tls_static_surplus (int nns, int opt_tls) ++{ ++ return (nns - 1) * LIBC_IE_TLS + nns * OTHER_IE_TLS + opt_tls; ++} ++ ++/* This value is chosen so that with default values for the tunables, ++ the computation of dl_tls_static_surplus in ++ _dl_tls_static_surplus_init yields the historic value 1664, for ++ backwards compatibility. */ ++#define LEGACY_TLS (1664 - tls_static_surplus (DEFAULT_NNS, OPTIONAL_TLS)) ++ + /* Calculate the size of the static TLS surplus, when the given + number of audit modules are loaded. Must be called after the + number of audit modules is known and before static TLS allocation. */ +@@ -74,8 +98,8 @@ _dl_tls_static_surplus_init (size_t naudit) + opt_tls = TUNABLE_GET (optional_static_tls, size_t, NULL); + #else + /* Default values of the tunables. */ +- nns = 4; +- opt_tls = 512; ++ nns = DEFAULT_NNS; ++ opt_tls = OPTIONAL_TLS; + #endif + if (nns > DL_NNS) + nns = DL_NNS; +@@ -85,9 +109,8 @@ _dl_tls_static_surplus_init (size_t naudit) + nns += naudit; + + GL(dl_tls_static_optional) = opt_tls; +- GLRO(dl_tls_static_surplus) = ((nns - 1) * LIBC_IE_TLS +- + nns * OTHER_IE_TLS +- + opt_tls); ++ assert (LEGACY_TLS >= 0); ++ GLRO(dl_tls_static_surplus) = tls_static_surplus (nns, opt_tls) + LEGACY_TLS; + } + + /* Out-of-memory handler. */ +diff --git a/elf/tst-tls-surplus.c b/elf/tst-tls-surplus.c +new file mode 100644 +index 0000000000000000..b0dea0b5ee178ddd +--- /dev/null ++++ b/elf/tst-tls-surplus.c +@@ -0,0 +1,42 @@ ++/* Test size of the static TLS surplus reservation for backwards compatibility. ++ 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 ++ ++static int do_test (void); ++#include ++ ++/* This hack results in a definition of struct rtld_global_ro. Do ++ this after all the other header inclusions, to minimize the ++ impact. */ ++#define SHARED ++#include ++ ++static ++int do_test (void) ++{ ++ /* Avoid introducing a copy relocation due to the hidden alias in ++ ld.so. */ ++ struct rtld_global_ro *glro = xdlsym (NULL, "_rtld_global_ro"); ++ printf ("info: _dl_tls_static_surplus: %zu\n", glro->_dl_tls_static_surplus); ++ /* Hisoric value: 16 * 100 + 64. */ ++ TEST_VERIFY (glro->_dl_tls_static_surplus >= 1664); ++ return 0; ++} diff --git a/SOURCES/glibc-rh1817513-81.patch b/SOURCES/glibc-rh1817513-81.patch new file mode 100644 index 0000000..1a035bc --- /dev/null +++ b/SOURCES/glibc-rh1817513-81.patch @@ -0,0 +1,137 @@ +commit ac3bda9a251f1512650f7b2c10d711c740ee0b78 +Author: H.J. Lu +Date: Wed Aug 5 08:20:52 2020 -0700 + + x86: Rename Intel CPU feature names + + Intel64 and IA-32 Architectures Software Developer’s Manual has changed + the following CPU feature names: + + 1. The CPU feature of Enhanced Intel SpeedStep Technology is renamed + from EST to EIST. + 2. The CPU feature which supports Platform Quality of Service Monitoring + (PQM) capability is changed to Intel Resource Director Technology + (Intel RDT) Monitoring capability, i.e. PQM is renamed to RDT_M. + 3. The CPU feature which supports Platform Quality of Service + Enforcement (PQE) capability is changed to Intel Resource Director + Technology (Intel RDT) Allocation capability, i.e. PQE is renamed to + RDT_A. + +diff --git a/sysdeps/x86/cpu-features.h b/sysdeps/x86/cpu-features.h +index 21708c028a12dbb2..3b401d441b8d370a 100644 +--- a/sysdeps/x86/cpu-features.h ++++ b/sysdeps/x86/cpu-features.h +@@ -156,7 +156,7 @@ extern const struct cpu_features *__get_cpu_features (void) + #define bit_cpu_DS_CPL (1u << 4) + #define bit_cpu_VMX (1u << 5) + #define bit_cpu_SMX (1u << 6) +-#define bit_cpu_EST (1u << 7) ++#define bit_cpu_EIST (1u << 7) + #define bit_cpu_TM2 (1u << 8) + #define bit_cpu_SSSE3 (1u << 9) + #define bit_cpu_CNXT_ID (1u << 10) +@@ -231,10 +231,10 @@ extern const struct cpu_features *__get_cpu_features (void) + #define bit_cpu_ERMS (1u << 9) + #define bit_cpu_INVPCID (1u << 10) + #define bit_cpu_RTM (1u << 11) +-#define bit_cpu_PQM (1u << 12) ++#define bit_cpu_RDT_M (1u << 12) + #define bit_cpu_DEPR_FPU_CS_DS (1u << 13) + #define bit_cpu_MPX (1u << 14) +-#define bit_cpu_PQE (1u << 15) ++#define bit_cpu_RDT_A (1u << 15) + #define bit_cpu_AVX512F (1u << 16) + #define bit_cpu_AVX512DQ (1u << 17) + #define bit_cpu_RDSEED (1u << 18) +@@ -371,7 +371,7 @@ extern const struct cpu_features *__get_cpu_features (void) + #define index_cpu_DS_CPL COMMON_CPUID_INDEX_1 + #define index_cpu_VMX COMMON_CPUID_INDEX_1 + #define index_cpu_SMX COMMON_CPUID_INDEX_1 +-#define index_cpu_EST COMMON_CPUID_INDEX_1 ++#define index_cpu_EIST COMMON_CPUID_INDEX_1 + #define index_cpu_TM2 COMMON_CPUID_INDEX_1 + #define index_cpu_SSSE3 COMMON_CPUID_INDEX_1 + #define index_cpu_CNXT_ID COMMON_CPUID_INDEX_1 +@@ -446,10 +446,10 @@ extern const struct cpu_features *__get_cpu_features (void) + #define index_cpu_ERMS COMMON_CPUID_INDEX_7 + #define index_cpu_INVPCID COMMON_CPUID_INDEX_7 + #define index_cpu_RTM COMMON_CPUID_INDEX_7 +-#define index_cpu_PQM COMMON_CPUID_INDEX_7 ++#define index_cpu_RDT_M COMMON_CPUID_INDEX_7 + #define index_cpu_DEPR_FPU_CS_DS COMMON_CPUID_INDEX_7 + #define index_cpu_MPX COMMON_CPUID_INDEX_7 +-#define index_cpu_PQE COMMON_CPUID_INDEX_7 ++#define index_cpu_RDT_A COMMON_CPUID_INDEX_7 + #define index_cpu_AVX512F COMMON_CPUID_INDEX_7 + #define index_cpu_AVX512DQ COMMON_CPUID_INDEX_7 + #define index_cpu_RDSEED COMMON_CPUID_INDEX_7 +@@ -584,7 +584,7 @@ extern const struct cpu_features *__get_cpu_features (void) + #define reg_DS_CPL ecx + #define reg_VMX ecx + #define reg_SMX ecx +-#define reg_EST ecx ++#define reg_EIST ecx + #define reg_TM2 ecx + #define reg_SSSE3 ecx + #define reg_CNXT_ID ecx +@@ -659,10 +659,10 @@ extern const struct cpu_features *__get_cpu_features (void) + #define reg_ERMS ebx + #define reg_INVPCID ebx + #define reg_RTM ebx +-#define reg_PQM ebx ++#define reg_RDT_M ebx + #define reg_DEPR_FPU_CS_DS ebx + #define reg_MPX ebx +-#define reg_PQE ebx ++#define reg_RDT_A ebx + #define reg_AVX512F ebx + #define reg_AVX512DQ ebx + #define reg_RDSEED ebx +diff --git a/sysdeps/x86/tst-get-cpu-features.c b/sysdeps/x86/tst-get-cpu-features.c +index 85ec9d5a091e2c88..582b125a2dad3f21 100644 +--- a/sysdeps/x86/tst-get-cpu-features.c ++++ b/sysdeps/x86/tst-get-cpu-features.c +@@ -73,7 +73,7 @@ do_test (void) + CHECK_CPU_FEATURE (DS_CPL); + CHECK_CPU_FEATURE (VMX); + CHECK_CPU_FEATURE (SMX); +- CHECK_CPU_FEATURE (EST); ++ CHECK_CPU_FEATURE (EIST); + CHECK_CPU_FEATURE (TM2); + CHECK_CPU_FEATURE (SSSE3); + CHECK_CPU_FEATURE (CNXT_ID); +@@ -136,10 +136,10 @@ do_test (void) + CHECK_CPU_FEATURE (ERMS); + CHECK_CPU_FEATURE (INVPCID); + CHECK_CPU_FEATURE (RTM); +- CHECK_CPU_FEATURE (PQM); ++ CHECK_CPU_FEATURE (RDT_M); + CHECK_CPU_FEATURE (DEPR_FPU_CS_DS); + CHECK_CPU_FEATURE (MPX); +- CHECK_CPU_FEATURE (PQE); ++ CHECK_CPU_FEATURE (RDT_A); + CHECK_CPU_FEATURE (AVX512F); + CHECK_CPU_FEATURE (AVX512DQ); + CHECK_CPU_FEATURE (RDSEED); +@@ -226,7 +226,7 @@ do_test (void) + CHECK_CPU_FEATURE_USABLE (DS_CPL); + CHECK_CPU_FEATURE_USABLE (VMX); + CHECK_CPU_FEATURE_USABLE (SMX); +- CHECK_CPU_FEATURE_USABLE (EST); ++ CHECK_CPU_FEATURE_USABLE (EIST); + CHECK_CPU_FEATURE_USABLE (TM2); + CHECK_CPU_FEATURE_USABLE (SSSE3); + CHECK_CPU_FEATURE_USABLE (CNXT_ID); +@@ -289,10 +289,10 @@ do_test (void) + CHECK_CPU_FEATURE_USABLE (ERMS); + CHECK_CPU_FEATURE_USABLE (INVPCID); + CHECK_CPU_FEATURE_USABLE (RTM); +- CHECK_CPU_FEATURE_USABLE (PQM); ++ CHECK_CPU_FEATURE_USABLE (RDT_M); + CHECK_CPU_FEATURE_USABLE (DEPR_FPU_CS_DS); + CHECK_CPU_FEATURE_USABLE (MPX); +- CHECK_CPU_FEATURE_USABLE (PQE); ++ CHECK_CPU_FEATURE_USABLE (RDT_A); + CHECK_CPU_FEATURE_USABLE (AVX512F); + CHECK_CPU_FEATURE_USABLE (AVX512DQ); + CHECK_CPU_FEATURE_USABLE (RDSEED); diff --git a/SOURCES/glibc-rh1817513-82.patch b/SOURCES/glibc-rh1817513-82.patch new file mode 100644 index 0000000..6a04b8c --- /dev/null +++ b/SOURCES/glibc-rh1817513-82.patch @@ -0,0 +1,178 @@ +commit 04bba1e5d84b6fd8d3a3b006bc240cd5d241ee30 +Author: H.J. Lu +Date: Wed Aug 5 13:51:56 2020 -0700 + + x86: Set CPU usable feature bits conservatively [BZ #26552] + + Set CPU usable feature bits only for CPU features which are usable in + user space and whose usability can be detected from user space, excluding + features like FSGSBASE whose enable bit can only be checked in the kernel. + +diff --git a/sysdeps/x86/cpu-features.c b/sysdeps/x86/cpu-features.c +index f13a1df4555c7000..6954728c47d0126b 100644 +--- a/sysdeps/x86/cpu-features.c ++++ b/sysdeps/x86/cpu-features.c +@@ -44,107 +44,55 @@ extern void TUNABLE_CALLBACK (set_x86_shstk) (tunable_val_t *) + static void + update_usable (struct cpu_features *cpu_features) + { +- /* Before COMMON_CPUID_INDEX_80000001, copy the cpuid array elements to +- the usable array. */ +- unsigned int i; +- for (i = 0; i < COMMON_CPUID_INDEX_80000001; i++) +- cpu_features->features[i].usable = cpu_features->features[i].cpuid; +- +- /* Before COMMON_CPUID_INDEX_80000001, clear the unknown usable bits +- and the always zero bits. */ +- CPU_FEATURE_UNSET (cpu_features, INDEX_1_ECX_16); +- CPU_FEATURE_UNSET (cpu_features, INDEX_1_ECX_31); +- CPU_FEATURE_UNSET (cpu_features, INDEX_1_EDX_10); +- CPU_FEATURE_UNSET (cpu_features, INDEX_1_EDX_20); +- CPU_FEATURE_UNSET (cpu_features, INDEX_1_EDX_30); +- CPU_FEATURE_UNSET (cpu_features, INDEX_7_EBX_6); +- CPU_FEATURE_UNSET (cpu_features, INDEX_7_EBX_22); +- CPU_FEATURE_UNSET (cpu_features, INDEX_7_ECX_13); +- CPU_FEATURE_UNSET (cpu_features, INDEX_7_ECX_15); +- CPU_FEATURE_UNSET (cpu_features, INDEX_7_ECX_16); +- CPU_FEATURE_UNSET (cpu_features, INDEX_7_ECX_23); +- CPU_FEATURE_UNSET (cpu_features, INDEX_7_ECX_24); +- CPU_FEATURE_UNSET (cpu_features, INDEX_7_ECX_26); +- CPU_FEATURE_UNSET (cpu_features, INDEX_7_EDX_0); +- CPU_FEATURE_UNSET (cpu_features, INDEX_7_EDX_1); +- CPU_FEATURE_UNSET (cpu_features, INDEX_7_EDX_5); +- CPU_FEATURE_UNSET (cpu_features, INDEX_7_EDX_6); +- CPU_FEATURE_UNSET (cpu_features, INDEX_7_EDX_7); +- CPU_FEATURE_UNSET (cpu_features, INDEX_7_EDX_9); +- CPU_FEATURE_UNSET (cpu_features, INDEX_7_EDX_11); +- CPU_FEATURE_UNSET (cpu_features, INDEX_7_EDX_12); +- CPU_FEATURE_UNSET (cpu_features, INDEX_7_EDX_13); +- CPU_FEATURE_UNSET (cpu_features, INDEX_7_EDX_17); +- CPU_FEATURE_UNSET (cpu_features, INDEX_7_EDX_19); +- CPU_FEATURE_UNSET (cpu_features, INDEX_7_EDX_21); +- CPU_FEATURE_UNSET (cpu_features, INDEX_7_EDX_23); +- +- /* EAX/EBX from COMMON_CPUID_INDEX_1 and EAX from COMMON_CPUID_INDEX_7 +- aren't used for CPU feature detection. */ +- cpu_features->features[COMMON_CPUID_INDEX_1].usable.eax = 0; +- cpu_features->features[COMMON_CPUID_INDEX_1].usable.ebx = 0; +- cpu_features->features[COMMON_CPUID_INDEX_7].usable.eax = 0; +- +- /* Starting from COMMON_CPUID_INDEX_80000001, copy the cpuid bits to +- usable bits. */ ++ /* Copy the cpuid bits to usable bits for CPU featuress whose usability ++ in user space can be detected without additonal OS support. */ ++ CPU_FEATURE_SET_USABLE (cpu_features, SSE3); ++ CPU_FEATURE_SET_USABLE (cpu_features, PCLMULQDQ); ++ CPU_FEATURE_SET_USABLE (cpu_features, SSSE3); ++ CPU_FEATURE_SET_USABLE (cpu_features, CMPXCHG16B); ++ CPU_FEATURE_SET_USABLE (cpu_features, SSE4_1); ++ CPU_FEATURE_SET_USABLE (cpu_features, SSE4_2); ++ CPU_FEATURE_SET_USABLE (cpu_features, MOVBE); ++ CPU_FEATURE_SET_USABLE (cpu_features, POPCNT); ++ CPU_FEATURE_SET_USABLE (cpu_features, AES); ++ CPU_FEATURE_SET_USABLE (cpu_features, OSXSAVE); ++ CPU_FEATURE_SET_USABLE (cpu_features, TSC); ++ CPU_FEATURE_SET_USABLE (cpu_features, CX8); ++ CPU_FEATURE_SET_USABLE (cpu_features, CMOV); ++ CPU_FEATURE_SET_USABLE (cpu_features, CLFSH); ++ CPU_FEATURE_SET_USABLE (cpu_features, MMX); ++ CPU_FEATURE_SET_USABLE (cpu_features, FXSR); ++ CPU_FEATURE_SET_USABLE (cpu_features, SSE); ++ CPU_FEATURE_SET_USABLE (cpu_features, SSE2); ++ CPU_FEATURE_SET_USABLE (cpu_features, HTT); ++ CPU_FEATURE_SET_USABLE (cpu_features, BMI1); ++ CPU_FEATURE_SET_USABLE (cpu_features, HLE); ++ CPU_FEATURE_SET_USABLE (cpu_features, BMI2); ++ CPU_FEATURE_SET_USABLE (cpu_features, ERMS); ++ CPU_FEATURE_SET_USABLE (cpu_features, RTM); ++ CPU_FEATURE_SET_USABLE (cpu_features, RDSEED); ++ CPU_FEATURE_SET_USABLE (cpu_features, ADX); ++ CPU_FEATURE_SET_USABLE (cpu_features, CLFLUSHOPT); ++ CPU_FEATURE_SET_USABLE (cpu_features, CLWB); ++ CPU_FEATURE_SET_USABLE (cpu_features, SHA); ++ CPU_FEATURE_SET_USABLE (cpu_features, PREFETCHWT1); ++ CPU_FEATURE_SET_USABLE (cpu_features, OSPKE); ++ CPU_FEATURE_SET_USABLE (cpu_features, WAITPKG); ++ CPU_FEATURE_SET_USABLE (cpu_features, GFNI); ++ CPU_FEATURE_SET_USABLE (cpu_features, RDPID); ++ CPU_FEATURE_SET_USABLE (cpu_features, CLDEMOTE); ++ CPU_FEATURE_SET_USABLE (cpu_features, MOVDIRI); ++ CPU_FEATURE_SET_USABLE (cpu_features, MOVDIR64B); ++ CPU_FEATURE_SET_USABLE (cpu_features, FSRM); ++ CPU_FEATURE_SET_USABLE (cpu_features, SERIALIZE); ++ CPU_FEATURE_SET_USABLE (cpu_features, TSXLDTRK); + CPU_FEATURE_SET_USABLE (cpu_features, LAHF64_SAHF64); +- CPU_FEATURE_SET_USABLE (cpu_features, SVM); + CPU_FEATURE_SET_USABLE (cpu_features, LZCNT); + CPU_FEATURE_SET_USABLE (cpu_features, SSE4A); + CPU_FEATURE_SET_USABLE (cpu_features, PREFETCHW); +- CPU_FEATURE_SET_USABLE (cpu_features, XOP); +- CPU_FEATURE_SET_USABLE (cpu_features, LWP); +- CPU_FEATURE_SET_USABLE (cpu_features, FMA4); + CPU_FEATURE_SET_USABLE (cpu_features, TBM); +- CPU_FEATURE_SET_USABLE (cpu_features, SYSCALL_SYSRET); +- CPU_FEATURE_SET_USABLE (cpu_features, NX); +- CPU_FEATURE_SET_USABLE (cpu_features, PAGE1GB); + CPU_FEATURE_SET_USABLE (cpu_features, RDTSCP); +- CPU_FEATURE_SET_USABLE (cpu_features, LM); +- CPU_FEATURE_SET_USABLE (cpu_features, XSAVEOPT); +- CPU_FEATURE_SET_USABLE (cpu_features, XSAVEC); +- CPU_FEATURE_SET_USABLE (cpu_features, XGETBV_ECX_1); +- CPU_FEATURE_SET_USABLE (cpu_features, XSAVES); +- CPU_FEATURE_SET_USABLE (cpu_features, XFD); +- CPU_FEATURE_SET_USABLE (cpu_features, INVARIANT_TSC); + CPU_FEATURE_SET_USABLE (cpu_features, WBNOINVD); +- CPU_FEATURE_SET_USABLE (cpu_features, AVX512_BF16); +- +- /* MPX has been deprecated. */ +- CPU_FEATURE_UNSET (cpu_features, MPX); +- +- /* Clear the usable bits which require OS support. */ +- CPU_FEATURE_UNSET (cpu_features, FMA); +- CPU_FEATURE_UNSET (cpu_features, AVX); +- CPU_FEATURE_UNSET (cpu_features, F16C); +- CPU_FEATURE_UNSET (cpu_features, AVX2); +- CPU_FEATURE_UNSET (cpu_features, AVX512F); +- CPU_FEATURE_UNSET (cpu_features, AVX512DQ); +- CPU_FEATURE_UNSET (cpu_features, AVX512_IFMA); +- CPU_FEATURE_UNSET (cpu_features, AVX512PF); +- CPU_FEATURE_UNSET (cpu_features, AVX512ER); +- CPU_FEATURE_UNSET (cpu_features, AVX512CD); +- CPU_FEATURE_UNSET (cpu_features, AVX512BW); +- CPU_FEATURE_UNSET (cpu_features, AVX512VL); +- CPU_FEATURE_UNSET (cpu_features, AVX512_VBMI); +- CPU_FEATURE_UNSET (cpu_features, PKU); +- CPU_FEATURE_UNSET (cpu_features, AVX512_VBMI2); +- CPU_FEATURE_UNSET (cpu_features, VAES); +- CPU_FEATURE_UNSET (cpu_features, VPCLMULQDQ); +- CPU_FEATURE_UNSET (cpu_features, AVX512_VNNI); +- CPU_FEATURE_UNSET (cpu_features, AVX512_BITALG); +- CPU_FEATURE_UNSET (cpu_features, AVX512_VPOPCNTDQ); +- CPU_FEATURE_UNSET (cpu_features, AVX512_4VNNIW); +- CPU_FEATURE_UNSET (cpu_features, AVX512_4FMAPS); +- CPU_FEATURE_UNSET (cpu_features, AVX512_VP2INTERSECT); +- CPU_FEATURE_UNSET (cpu_features, AMX_BF16); +- CPU_FEATURE_UNSET (cpu_features, AMX_TILE); +- CPU_FEATURE_UNSET (cpu_features, AMX_INT8); +- CPU_FEATURE_UNSET (cpu_features, XOP); +- CPU_FEATURE_UNSET (cpu_features, FMA4); +- CPU_FEATURE_UNSET (cpu_features, XSAVEC); +- CPU_FEATURE_UNSET (cpu_features, XFD); +- CPU_FEATURE_UNSET (cpu_features, AVX512_BF16); + + /* Can we call xgetbv? */ + if (CPU_FEATURES_CPU_P (cpu_features, OSXSAVE)) +@@ -243,8 +191,11 @@ update_usable (struct cpu_features *cpu_features) + CPU_FEATURE_SET_USABLE (cpu_features, AMX_INT8); + } + +- +- /* XFD is usable only when OSXSAVE is enabled. */ ++ /* These features are usable only when OSXSAVE is enabled. */ ++ CPU_FEATURE_SET (cpu_features, XSAVE); ++ CPU_FEATURE_SET_USABLE (cpu_features, XSAVEOPT); ++ CPU_FEATURE_SET_USABLE (cpu_features, XSAVEC); ++ CPU_FEATURE_SET_USABLE (cpu_features, XGETBV_ECX_1); + CPU_FEATURE_SET_USABLE (cpu_features, XFD); + + /* For _dl_runtime_resolve, set xsave_state_size to xsave area diff --git a/SOURCES/glibc-rh1817513-83.patch b/SOURCES/glibc-rh1817513-83.patch new file mode 100644 index 0000000..f3b8f3a --- /dev/null +++ b/SOURCES/glibc-rh1817513-83.patch @@ -0,0 +1,1664 @@ +commit 9620398097de3981c1adf5233e2b3478d36bc1b3 +Author: H.J. Lu +Date: Mon Jun 29 18:30:54 2020 -0700 + + x86: Install [BZ #26124] + + Install so that programmers can do + + #if __has_include() + #include + #endif + ... + + if (CPU_FEATURE_USABLE (SSE2)) + ... + if (CPU_FEATURE_USABLE (AVX2)) + ... + + exports only: + + enum + { + COMMON_CPUID_INDEX_1 = 0, + COMMON_CPUID_INDEX_7, + COMMON_CPUID_INDEX_80000001, + COMMON_CPUID_INDEX_D_ECX_1, + COMMON_CPUID_INDEX_80000007, + COMMON_CPUID_INDEX_80000008, + COMMON_CPUID_INDEX_7_ECX_1, + /* Keep the following line at the end. */ + COMMON_CPUID_INDEX_MAX + }; + + struct cpuid_features + { + struct cpuid_registers cpuid; + struct cpuid_registers usable; + }; + + struct cpu_features + { + struct cpu_features_basic basic; + struct cpuid_features features[COMMON_CPUID_INDEX_MAX]; + }; + + /* Get a pointer to the CPU features structure. */ + extern const struct cpu_features *__x86_get_cpu_features + (unsigned int max) __attribute__ ((const)); + + Since all feature checks are done through macros, programs compiled with + a newer are compatible with the older glibc binaries + as long as the layout of struct cpu_features is identical. The features + array can be expanded with backward binary compatibility for both .o and + .so files. When COMMON_CPUID_INDEX_MAX is increased to support new + processor features, __x86_get_cpu_features in the older glibc binaries + returns NULL and HAS_CPU_FEATURE/CPU_FEATURE_USABLE return false on the + new processor feature. No new symbol version is neeeded. + + Both CPU_FEATURE_USABLE and HAS_CPU_FEATURE are provided. HAS_CPU_FEATURE + can be used to identify processor features. + + Note: Although GCC has __builtin_cpu_supports, it only supports a subset + of and it is equivalent to CPU_FEATURE_USABLE. It + doesn't support HAS_CPU_FEATURE. + +Conflicts: + sysdeps/x86/sys/platform/x86.h + sysdeps/x86/tst-get-cpu-features.c + sysdeps/x86_64/multiarch/test-multiarch.c + (Copyright year, URL differences.) + +Downstream changes: Do not install , +and use a GLIBC_PRIVATE symbol for __x86_get_cpu_features. + +diff --git a/manual/platform.texi b/manual/platform.texi +index 504addc956086820..2c145acdc3564cbb 100644 +--- a/manual/platform.texi ++++ b/manual/platform.texi +@@ -7,6 +7,7 @@ + @menu + * PowerPC:: Facilities Specific to the PowerPC Architecture + * RISC-V:: Facilities Specific to the RISC-V Architecture ++* X86:: Facilities Specific to the X86 Architecture + @end menu + + @node PowerPC +@@ -134,3 +135,519 @@ all threads in the current process. Setting the + ordering on only the current thread is necessary. All other flag bits are + reserved. + @end deftypefun ++ ++@node X86 ++@appendixsec X86-specific Facilities ++ ++Facilities specific to X86 that are not specific to a particular ++operating system are declared in @file{sys/platform/x86.h}. ++ ++@deftypefun {const struct cpu_features *} __x86_get_cpu_features (unsigned int @var{max}) ++@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}} ++Return a pointer to x86 CPU feature structure used by query macros for x86 ++CPU features. If @var{max} exceeds @code{COMMON_CPUID_INDEX_MAX} which ++is the limit of the CPUID leaves supported by @Theglibc{}, the function ++returns @code{NULL}, indicating that the queried processor feature is ++unsupported by @Theglibc{} run-time. ++@end deftypefun ++ ++@deftypefn Macro int HAS_CPU_FEATURE (@var{name}) ++This macro returns a nonzero value (true) if the processor has the feature ++@var{name}. ++@end deftypefn ++ ++@deftypefn Macro int CPU_FEATURE_USABLE (@var{name}) ++This macro returns a nonzero value (true) if the processor has the feature ++@var{name} and the feature is supported by the operating system. ++@end deftypefn ++ ++The supported processor features are: ++ ++@itemize @bullet ++ ++@item ++@code{ACPI} -- Thermal Monitor and Software Controlled Clock Facilities. ++ ++@item ++@code{ADX} -- ADX instruction extensions. ++ ++@item ++@code{APIC} -- APIC On-Chip. ++ ++@item ++@code{AES} -- The AES instruction extensions. ++ ++@item ++@code{AMX_BF16} -- Tile computational operations on bfloat16 numbers. ++ ++@item ++@code{AMX_INT8} -- Tile computational operations on 8-bit numbers. ++ ++@item ++@code{AMX_TILE} -- Tile architecture. ++ ++@item ++@code{ARCH_CAPABILITIES} -- IA32_ARCH_CAPABILITIES MSR. ++ ++@item ++@code{AVX} -- The AVX instruction extensions. ++ ++@item ++@code{AVX2} -- The AVX2 instruction extensions. ++ ++@item ++@code{AVX512_4FMAPS} -- The AVX512_4FMAPS instruction extensions. ++ ++@item ++@code{AVX512_4VNNIW} -- The AVX512_4VNNIW instruction extensions. ++ ++@item ++@code{AVX512_BF16} -- The AVX512_BF16 instruction extensions. ++ ++@item ++@code{AVX512_BITALG} -- The AVX512_BITALG instruction extensions. ++ ++@item ++@code{AVX512_IFMA} -- The AVX512_IFMA instruction extensions. ++ ++@item ++@code{AVX512_VBMI} -- The AVX512_VBMI instruction extensions. ++ ++@item ++@code{AVX512_VBMI2} -- The AVX512_VBMI2 instruction extensions. ++ ++@item ++@code{AVX512_VNNI} -- The AVX512_VNNI instruction extensions. ++ ++@item ++@code{AVX512_VP2INTERSECT} -- The AVX512_VP2INTERSECT instruction ++extensions. ++ ++@item ++@code{AVX512_VPOPCNTDQ} -- The AVX512_VPOPCNTDQ instruction extensions. ++ ++@item ++@code{AVX512BW} -- The AVX512BW instruction extensions. ++ ++@item ++@code{AVX512CD} -- The AVX512CD instruction extensions. ++ ++@item ++@code{AVX512ER} -- The AVX512ER instruction extensions. ++ ++@item ++@code{AVX512DQ} -- The AVX512DQ instruction extensions. ++ ++@item ++@code{AVX512F} -- The AVX512F instruction extensions. ++ ++@item ++@code{AVX512PF} -- The AVX512PF instruction extensions. ++ ++@item ++@code{AVX512VL} -- The AVX512VL instruction extensions. ++ ++@item ++@code{BMI1} -- BMI1 instructions. ++ ++@item ++@code{BMI2} -- BMI2 instructions. ++ ++@item ++@code{CLDEMOTE} -- CLDEMOTE instruction. ++ ++@item ++@code{CLFLUSHOPT} -- CLFLUSHOPT instruction. ++ ++@item ++@code{CLFSH} -- CLFLUSH instruction. ++ ++@item ++@code{CLWB} -- CLWB instruction. ++ ++@item ++@code{CMOV} -- Conditional Move instructions. ++ ++@item ++@code{CMPXCHG16B} -- CMPXCHG16B instruction. ++ ++@item ++@code{CNXT_ID} -- L1 Context ID. ++ ++@item ++@code{CORE_CAPABILITIES} -- IA32_CORE_CAPABILITIES MSR. ++ ++@item ++@code{CX8} -- CMPXCHG8B instruction. ++ ++@item ++@code{DCA} -- Data prefetch from a memory mapped device. ++ ++@item ++@code{DE} -- Debugging Extensions. ++ ++@item ++@code{DEPR_FPU_CS_DS} -- Deprecates FPU CS and FPU DS values. ++ ++@item ++@code{DS} -- Debug Store. ++ ++@item ++@code{DS_CPL} -- CPL Qualified Debug Store. ++ ++@item ++@code{DTES64} -- 64-bit DS Area. ++ ++@item ++@code{EIST} -- Enhanced Intel SpeedStep technology. ++ ++@item ++@code{ENQCMD} -- Enqueue Stores instructions. ++ ++@item ++@code{ERMS} -- Enhanced REP MOVSB/STOSB. ++ ++@item ++@code{F16C} -- 16-bit floating-point conversion instructions. ++ ++@item ++@code{FMA} -- FMA extensions using YMM state. ++ ++@item ++@code{FMA4} -- FMA4 instruction extensions. ++ ++@item ++@code{FPU} -- X87 Floating Point Unit On-Chip. ++ ++@item ++@code{FSGSBASE} -- RDFSBASE/RDGSBASE/WRFSBASE/WRGSBASE instructions. ++ ++@item ++@code{FSRM} -- Fast Short REP MOV. ++ ++@item ++@code{FXSR} -- FXSAVE and FXRSTOR instructions. ++ ++@item ++@code{GFNI} -- GFNI instruction extensions. ++ ++@item ++@code{HLE} -- HLE instruction extensions. ++ ++@item ++@code{HTT} -- Max APIC IDs reserved field is Valid. ++ ++@item ++@code{HYBRID} -- Hybrid processor. ++ ++@item ++@code{IBRS_IBPB} -- Indirect branch restricted speculation (IBRS) and ++the indirect branch predictor barrier (IBPB). ++ ++@item ++@code{IBT} -- Intel Indirect Branch Tracking instruction extensions. ++ ++@item ++@code{INVARIANT_TSC} -- Invariant TSC. ++ ++@item ++@code{INVPCID} -- INVPCID instruction. ++ ++@item ++@code{L1D_FLUSH} -- IA32_FLUSH_CMD MSR. ++ ++@item ++@code{LAHF64_SAHF64} -- LAHF/SAHF available in 64-bit mode. ++ ++@item ++@code{LM} -- Long mode. ++ ++@item ++@code{LWP} -- Lightweight profiling. ++ ++@item ++@code{LZCNT} -- LZCNT instruction. ++ ++@item ++@code{MCA} -- Machine Check Architecture. ++ ++@item ++@code{MCE} -- Machine Check Exception. ++ ++@item ++@code{MD_CLEAR} -- MD_CLEAR. ++ ++@item ++@code{MMX} -- Intel MMX Technology. ++ ++@item ++@code{MONITOR} -- MONITOR/MWAIT instructions. ++ ++@item ++@code{MOVBE} -- MOVBE instruction. ++ ++@item ++@code{MOVDIRI} -- MOVDIRI instruction. ++ ++@item ++@code{MOVDIR64B} -- MOVDIR64B instruction. ++ ++@item ++@code{MPX} -- Intel Memory Protection Extensions. ++ ++@item ++@code{MSR} -- Model Specific Registers RDMSR and WRMSR instructions. ++ ++@item ++@code{MTRR} -- Memory Type Range Registers. ++ ++@item ++@code{NX} -- No-execute page protection. ++ ++@item ++@code{OSPKE} -- OS has set CR4.PKE to enable protection keys. ++ ++@item ++@code{OSXSAVE} -- The OS has set CR4.OSXSAVE[bit 18] to enable ++XSETBV/XGETBV instructions to access XCR0 and to support processor ++extended state management using XSAVE/XRSTOR. ++ ++@item ++@code{PAE} -- Physical Address Extension. ++ ++@item ++@code{PAGE1GB} -- 1-GByte page. ++ ++@item ++@code{PAT} -- Page Attribute Table. ++ ++@item ++@code{PBE} -- Pending Break Enable. ++ ++@item ++@code{PCID} -- Process-context identifiers. ++ ++@item ++@code{PCLMULQDQ} -- PCLMULQDQ instruction. ++ ++@item ++@code{PCONFIG} -- PCONFIG instruction. ++ ++@item ++@code{PDCM} -- Perfmon and Debug Capability. ++ ++@item ++@code{PGE} -- Page Global Bit. ++ ++@item ++@code{PKS} -- Protection keys for supervisor-mode pages. ++ ++@item ++@code{PKU} -- Protection keys for user-mode pages. ++ ++@item ++@code{POPCNT} -- POPCNT instruction. ++ ++@item ++@code{PREFETCHW} -- PREFETCHW instruction. ++ ++@item ++@code{PREFETCHWT1} -- PREFETCHWT1 instruction. ++ ++@item ++@code{PSE} -- Page Size Extension. ++ ++@item ++@code{PSE_36} -- 36-Bit Page Size Extension. ++ ++@item ++@code{PSN} -- Processor Serial Number. ++ ++@item ++@code{RDPID} -- RDPID instruction. ++ ++@item ++@code{RDRAND} -- RDRAND instruction. ++ ++@item ++@code{RDSEED} -- RDSEED instruction. ++ ++@item ++@code{RDT_A} -- Intel Resource Director Technology (Intel RDT) Allocation ++capability. ++ ++@item ++@code{RDT_M} -- Intel Resource Director Technology (Intel RDT) Monitoring ++capability. ++ ++@item ++@code{RDTSCP} -- RDTSCP instruction. ++ ++@item ++@code{RTM} -- RTM instruction extensions. ++ ++@item ++@code{SDBG} -- IA32_DEBUG_INTERFACE MSR for silicon debug. ++ ++@item ++@code{SEP} -- SYSENTER and SYSEXIT instructions. ++ ++@item ++@code{SERIALIZE} -- SERIALIZE instruction. ++ ++@item ++@code{SGX} -- Intel Software Guard Extensions. ++ ++@item ++@code{SGX_LC} -- SGX Launch Configuration. ++ ++@item ++@code{SHA} -- SHA instruction extensions. ++ ++@item ++@code{SHSTK} -- Intel Shadow Stack instruction extensions. ++ ++@item ++@code{SMAP} -- Supervisor-Mode Access Prevention. ++ ++@item ++@code{SMEP} -- Supervisor-Mode Execution Prevention. ++ ++@item ++@code{SMX} -- Safer Mode Extensions. ++ ++@item ++@code{SS} -- Self Snoop. ++ ++@item ++@code{SSBD} -- Speculative Store Bypass Disable (SSBD). ++ ++@item ++@code{SSE} -- Streaming SIMD Extensions. ++ ++@item ++@code{SSE2} -- Streaming SIMD Extensions 2. ++ ++@item ++@code{SSE3} -- Streaming SIMD Extensions 3. ++ ++@item ++@code{SSE4_1} -- Streaming SIMD Extensions 4.1. ++ ++@item ++@code{SSE4_2} -- Streaming SIMD Extensions 4.2. ++ ++@item ++@code{SSE4A} -- SSE4A instruction extensions. ++ ++@item ++@code{SSSE3} -- Supplemental Streaming SIMD Extensions 3. ++ ++@item ++@code{STIBP} -- Single thread indirect branch predictors (STIBP). ++ ++@item ++@code{SVM} -- Secure Virtual Machine. ++ ++@item ++@code{SYSCALL_SYSRET} -- SYSCALL/SYSRET instructions. ++ ++@item ++@code{TBM} -- Trailing bit manipulation instructions. ++ ++@item ++@code{TM} -- Thermal Monitor. ++ ++@item ++@code{TM2} -- Thermal Monitor 2. ++ ++@item ++@code{TRACE} -- Intel Processor Trace. ++ ++@item ++@code{TSC} -- Time Stamp Counter. RDTSC instruction. ++ ++@item ++@code{TSC_ADJUST} -- IA32_TSC_ADJUST MSR. ++ ++@item ++@code{TSC_DEADLINE} -- Local APIC timer supports one-shot operation ++using a TSC deadline value. ++ ++@item ++@code{TSXLDTRK} -- TSXLDTRK instructions. ++ ++@item ++@code{UMIP} -- User-mode instruction prevention. ++ ++@item ++@code{VAES} -- VAES instruction extensions. ++ ++@item ++@code{VME} -- Virtual 8086 Mode Enhancements. ++ ++@item ++@code{VMX} -- Virtual Machine Extensions. ++ ++@item ++@code{VPCLMULQDQ} -- VPCLMULQDQ instruction. ++ ++@item ++@code{WAITPKG} -- WAITPKG instruction extensions. ++ ++@item ++@code{WBNOINVD} -- WBINVD/WBNOINVD instructions. ++ ++@item ++@code{X2APIC} -- x2APIC. ++ ++@item ++@code{XFD} -- Extended Feature Disable (XFD). ++ ++@item ++@code{XGETBV_ECX_1} -- XGETBV with ECX = 1. ++ ++@item ++@code{XOP} -- XOP instruction extensions. ++ ++@item ++@code{XSAVE} -- The XSAVE/XRSTOR processor extended states feature, the ++XSETBV/XGETBV instructions, and XCR0. ++ ++@item ++@code{XSAVEC} -- XSAVEC instruction. ++ ++@item ++@code{XSAVEOPT} -- XSAVEOPT instruction. ++ ++@item ++@code{XSAVES} -- XSAVES/XRSTORS instructions. ++ ++@item ++@code{XTPRUPDCTRL} -- xTPR Update Control. ++ ++@end itemize ++ ++You could query if a processor supports @code{AVX} with: ++ ++@smallexample ++#include ++ ++int ++support_avx (void) ++@{ ++ return HAS_CPU_FEATURE (AVX); ++@} ++@end smallexample ++ ++and if @code{AVX} is usable with: ++ ++@smallexample ++#include ++ ++int ++usable_avx (void) ++@{ ++ return CPU_FEATURE_USABLE (AVX); ++@} ++@end smallexample +diff --git a/sysdeps/i386/i686/multiarch/Makefile b/sysdeps/i386/i686/multiarch/Makefile +index bf75a9947fe013a3..c4897922d710d37e 100644 +--- a/sysdeps/i386/i686/multiarch/Makefile ++++ b/sysdeps/i386/i686/multiarch/Makefile +@@ -1,7 +1,3 @@ +-ifeq ($(subdir),csu) +-tests += test-multiarch +-endif +- + ifeq ($(subdir),string) + gen-as-const-headers += locale-defines.sym + sysdep_routines += bzero-sse2 memset-sse2 memcpy-ssse3 mempcpy-ssse3 \ +diff --git a/sysdeps/i386/i686/multiarch/test-multiarch.c b/sysdeps/i386/i686/multiarch/test-multiarch.c +deleted file mode 100644 +index 593cfec2735fb5b0..0000000000000000 +--- a/sysdeps/i386/i686/multiarch/test-multiarch.c ++++ /dev/null +@@ -1 +0,0 @@ +-#include +diff --git a/sysdeps/x86/Makefile b/sysdeps/x86/Makefile +index 962bbcb07eba1259..59e928e9d08d3229 100644 +--- a/sysdeps/x86/Makefile ++++ b/sysdeps/x86/Makefile +@@ -5,7 +5,8 @@ endif + ifeq ($(subdir),elf) + sysdep-dl-routines += dl-get-cpu-features + +-tests += tst-get-cpu-features tst-get-cpu-features-static ++tests += tst-get-cpu-features tst-get-cpu-features-static \ ++ tst-cpu-features-cpuinfo tst-cpu-features-supports + tests-static += tst-get-cpu-features-static + endif + +diff --git a/sysdeps/x86/Versions b/sysdeps/x86/Versions +index e02923708e160881..df70e602192053c0 100644 +--- a/sysdeps/x86/Versions ++++ b/sysdeps/x86/Versions +@@ -1,5 +1,5 @@ + ld { + GLIBC_PRIVATE { +- __get_cpu_features; ++ __x86_get_cpu_features; + } + } +diff --git a/sysdeps/x86/dl-get-cpu-features.c b/sysdeps/x86/dl-get-cpu-features.c +index 49593f19c64ad0bb..2aba0d167129b336 100644 +--- a/sysdeps/x86/dl-get-cpu-features.c ++++ b/sysdeps/x86/dl-get-cpu-features.c +@@ -18,10 +18,12 @@ + + #include + +-#undef __get_cpu_features ++#undef __x86_get_cpu_features + + const struct cpu_features * +-__get_cpu_features (void) ++__x86_get_cpu_features (unsigned int max) + { ++ if (max > COMMON_CPUID_INDEX_MAX) ++ return NULL; + return &GLRO(dl_x86_cpu_features); + } +diff --git a/sysdeps/x86/include/cpu-features.h b/sysdeps/x86/include/cpu-features.h +new file mode 100644 +index 0000000000000000..dcf29b6fe8578078 +--- /dev/null ++++ b/sysdeps/x86/include/cpu-features.h +@@ -0,0 +1,183 @@ ++/* Data structure for x86 CPU features. ++ 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 ++ . */ ++ ++#ifndef _PRIVATE_CPU_FEATURES_H ++#define _PRIVATE_CPU_FEATURES_H 1 ++ ++#ifdef _CPU_FEATURES_H ++# error this should be impossible ++#endif ++ ++#ifndef _ISOMAC ++/* Get most of the contents from the public header, but we define a ++ different `struct cpu_features' type for private use. */ ++# define cpu_features cpu_features_public ++# define __x86_get_cpu_features __x86_get_cpu_features_public ++#endif ++ ++#include ++ ++#ifndef _ISOMAC ++ ++# undef cpu_features ++# undef __x86_get_cpu_features ++# define __get_cpu_features() __x86_get_cpu_features (0) ++ ++enum ++{ ++ /* The integer bit array index for the first set of preferred feature ++ bits. */ ++ PREFERRED_FEATURE_INDEX_1 = 0, ++ /* The current maximum size of the feature integer bit array. */ ++ PREFERRED_FEATURE_INDEX_MAX ++}; ++ ++/* Only used directly in cpu-features.c. */ ++# define CPU_FEATURE_SET(ptr, name) \ ++ ptr->features[index_cpu_##name].usable.reg_##name |= bit_cpu_##name; ++# define CPU_FEATURE_UNSET(ptr, name) \ ++ ptr->features[index_cpu_##name].usable.reg_##name &= ~bit_cpu_##name; ++# define CPU_FEATURE_SET_USABLE(ptr, name) \ ++ ptr->features[index_cpu_##name].usable.reg_##name \ ++ |= ptr->features[index_cpu_##name].cpuid.reg_##name & bit_cpu_##name; ++# define CPU_FEATURE_PREFERRED_P(ptr, name) \ ++ ((ptr->preferred[index_arch_##name] & bit_arch_##name) != 0) ++# define CPU_FEATURE_CPU_P(ptr, name) \ ++ CPU_FEATURE_CHECK_P (ptr, name, cpuid) ++ ++/* HAS_CPU_FEATURE evaluates to true if CPU supports the feature. */ ++# undef HAS_CPU_FEATURE ++# define HAS_CPU_FEATURE(name) \ ++ CPU_FEATURE_CPU_P (__x86_get_cpu_features (0), name) ++/* CPU_FEATURE_USABLE evaluates to true if the feature is usable. */ ++# undef CPU_FEATURE_USABLE ++# define CPU_FEATURE_USABLE(name) \ ++ CPU_FEATURE_USABLE_P (__x86_get_cpu_features (0), name) ++/* CPU_FEATURE_PREFER evaluates to true if we prefer the feature at ++ runtime. */ ++# define CPU_FEATURE_PREFERRED(name) \ ++ CPU_FEATURE_PREFERRED_P(__get_cpu_features (), name) ++ ++# define CPU_FEATURES_CPU_P(ptr, name) \ ++ CPU_FEATURE_CPU_P (ptr, name) ++# define CPU_FEATURES_ARCH_P(ptr, name) \ ++ CPU_FEATURE_PREFERRED_P (ptr, name) ++# define HAS_ARCH_FEATURE(name) \ ++ CPU_FEATURE_PREFERRED (name) ++ ++/* PREFERRED_FEATURE_INDEX_1. */ ++# define bit_arch_I586 (1u << 0) ++# define bit_arch_I686 (1u << 1) ++# define bit_arch_Fast_Rep_String (1u << 2) ++# define bit_arch_Fast_Copy_Backward (1u << 3) ++# define bit_arch_Fast_Unaligned_Load (1u << 4) ++# define bit_arch_Fast_Unaligned_Copy (1u << 5) ++# define bit_arch_Slow_BSF (1u << 6) ++# define bit_arch_Slow_SSE4_2 (1u << 7) ++# define bit_arch_AVX_Fast_Unaligned_Load (1u << 8) ++# define bit_arch_Prefer_MAP_32BIT_EXEC (1u << 9) ++# define bit_arch_Prefer_PMINUB_for_stringop (1u << 10) ++# define bit_arch_Prefer_No_VZEROUPPER (1u << 11) ++# define bit_arch_Prefer_ERMS (1u << 12) ++# define bit_arch_Prefer_FSRM (1u << 13) ++# define bit_arch_Prefer_No_AVX512 (1u << 14) ++# define bit_arch_MathVec_Prefer_No_AVX512 (1u << 15) ++ ++# define index_arch_Fast_Rep_String PREFERRED_FEATURE_INDEX_1 ++# define index_arch_Fast_Copy_Backward PREFERRED_FEATURE_INDEX_1 ++# define index_arch_Slow_BSF PREFERRED_FEATURE_INDEX_1 ++# define index_arch_Fast_Unaligned_Load PREFERRED_FEATURE_INDEX_1 ++# define index_arch_Prefer_PMINUB_for_stringop PREFERRED_FEATURE_INDEX_1 ++# define index_arch_Fast_Unaligned_Copy PREFERRED_FEATURE_INDEX_1 ++# define index_arch_I586 PREFERRED_FEATURE_INDEX_1 ++# define index_arch_I686 PREFERRED_FEATURE_INDEX_1 ++# define index_arch_Slow_SSE4_2 PREFERRED_FEATURE_INDEX_1 ++# define index_arch_AVX_Fast_Unaligned_Load PREFERRED_FEATURE_INDEX_1 ++# define index_arch_Prefer_MAP_32BIT_EXEC PREFERRED_FEATURE_INDEX_1 ++# define index_arch_Prefer_No_VZEROUPPER PREFERRED_FEATURE_INDEX_1 ++# define index_arch_Prefer_ERMS PREFERRED_FEATURE_INDEX_1 ++# define index_arch_Prefer_No_AVX512 PREFERRED_FEATURE_INDEX_1 ++# define index_arch_MathVec_Prefer_No_AVX512 PREFERRED_FEATURE_INDEX_1 ++# define index_arch_Prefer_FSRM PREFERRED_FEATURE_INDEX_1 ++ ++/* XCR0 Feature flags. */ ++# define bit_XMM_state (1u << 1) ++# define bit_YMM_state (1u << 2) ++# define bit_Opmask_state (1u << 5) ++# define bit_ZMM0_15_state (1u << 6) ++# define bit_ZMM16_31_state (1u << 7) ++# define bit_XTILECFG_state (1u << 17) ++# define bit_XTILEDATA_state (1u << 18) ++ ++struct cpu_features ++{ ++ struct cpu_features_basic basic; ++ struct cpuid_features features[COMMON_CPUID_INDEX_MAX]; ++ unsigned int preferred[PREFERRED_FEATURE_INDEX_MAX]; ++ /* The state size for XSAVEC or XSAVE. The type must be unsigned long ++ int so that we use ++ ++ sub xsave_state_size_offset(%rip) %RSP_LP ++ ++ in _dl_runtime_resolve. */ ++ unsigned long int xsave_state_size; ++ /* The full state size for XSAVE when XSAVEC is disabled by ++ ++ GLIBC_TUNABLES=glibc.cpu.hwcaps=-XSAVEC ++ */ ++ unsigned int xsave_state_full_size; ++ /* Data cache size for use in memory and string routines, typically ++ L1 size. */ ++ unsigned long int data_cache_size; ++ /* Shared cache size for use in memory and string routines, typically ++ L2 or L3 size. */ ++ unsigned long int shared_cache_size; ++ /* Threshold to use non temporal store. */ ++ unsigned long int non_temporal_threshold; ++ /* Threshold to use "rep movsb". */ ++ unsigned long int rep_movsb_threshold; ++ /* Threshold to use "rep stosb". */ ++ unsigned long int rep_stosb_threshold; ++}; ++ ++# if defined (_LIBC) && !IS_IN (nonlib) ++/* Unused for x86. */ ++# define INIT_ARCH() ++# define __x86_get_cpu_features(max) (&GLRO(dl_x86_cpu_features)) ++# endif ++ ++# ifdef __x86_64__ ++# define HAS_CPUID 1 ++# elif (defined __i586__ || defined __pentium__ \ ++ || defined __geode__ || defined __k6__) ++# define HAS_CPUID 1 ++# define HAS_I586 1 ++# define HAS_I686 HAS_ARCH_FEATURE (I686) ++# elif defined __i486__ ++# define HAS_CPUID 0 ++# define HAS_I586 HAS_ARCH_FEATURE (I586) ++# define HAS_I686 HAS_ARCH_FEATURE (I686) ++# else ++# define HAS_CPUID 1 ++# define HAS_I586 1 ++# define HAS_I686 1 ++# endif ++ ++#endif /* !_ISOMAC */ ++ ++#endif /* include/cpu-features.h */ +diff --git a/sysdeps/x86/cpu-features.h b/sysdeps/x86/sys/platform/x86.h +similarity index 81% +rename from sysdeps/x86/cpu-features.h +rename to sysdeps/x86/sys/platform/x86.h +index 3b401d441b8d370a..ebc5f6fc16cb8104 100644 +--- a/sysdeps/x86/cpu-features.h ++++ b/sysdeps/x86/sys/platform/x86.h +@@ -1,5 +1,6 @@ +-/* This file is part of the GNU C Library. +- Copyright (C) 2008-2018 Free Software Foundation, Inc. ++/* Data structure for x86 CPU features. ++ This file is part of the GNU C Library. ++ Copyright (C) 2008-2020 Free Software Foundation, Inc. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public +@@ -15,17 +16,8 @@ + License along with the GNU C Library; if not, see + . */ + +-#ifndef cpu_features_h +-#define cpu_features_h +- +-enum +-{ +- /* The integer bit array index for the first set of preferred feature +- bits. */ +- PREFERRED_FEATURE_INDEX_1 = 0, +- /* The current maximum size of the feature integer bit array. */ +- PREFERRED_FEATURE_INDEX_MAX +-}; ++#ifndef _SYS_PLATFORM_X86_H ++#define _SYS_PLATFORM_X86_H + + enum + { +@@ -76,73 +68,32 @@ struct cpu_features + { + struct cpu_features_basic basic; + struct cpuid_features features[COMMON_CPUID_INDEX_MAX]; +- unsigned int preferred[PREFERRED_FEATURE_INDEX_MAX]; +- /* The state size for XSAVEC or XSAVE. The type must be unsigned long +- int so that we use +- +- sub xsave_state_size_offset(%rip) %RSP_LP +- +- in _dl_runtime_resolve. */ +- unsigned long int xsave_state_size; +- /* The full state size for XSAVE when XSAVEC is disabled by +- +- GLIBC_TUNABLES=glibc.cpu.hwcaps=-XSAVEC +- */ +- unsigned int xsave_state_full_size; +- /* Data cache size for use in memory and string routines, typically +- L1 size. */ +- unsigned long int data_cache_size; +- /* Shared cache size for use in memory and string routines, typically +- L2 or L3 size. */ +- unsigned long int shared_cache_size; +- /* Threshold to use non temporal store. */ +- unsigned long int non_temporal_threshold; +- /* Threshold to use "rep movsb". */ +- unsigned long int rep_movsb_threshold; +- /* Threshold to use "rep stosb". */ +- unsigned long int rep_stosb_threshold; + }; + +-/* Used from outside of glibc to get access to the CPU features +- structure. */ +-extern const struct cpu_features *__get_cpu_features (void) ++/* Get a pointer to the CPU features structure. */ ++extern const struct cpu_features *__x86_get_cpu_features (unsigned int) + __attribute__ ((const)); + +-/* Only used directly in cpu-features.c. */ + #define CPU_FEATURE_CHECK_P(ptr, name, check) \ + ((ptr->features[index_cpu_##name].check.reg_##name \ + & bit_cpu_##name) != 0) +-#define CPU_FEATURE_SET(ptr, name) \ +- ptr->features[index_cpu_##name].usable.reg_##name |= bit_cpu_##name; +-#define CPU_FEATURE_UNSET(ptr, name) \ +- ptr->features[index_cpu_##name].usable.reg_##name &= ~bit_cpu_##name; +-#define CPU_FEATURE_SET_USABLE(ptr, name) \ +- ptr->features[index_cpu_##name].usable.reg_##name \ +- |= ptr->features[index_cpu_##name].cpuid.reg_##name & bit_cpu_##name; +-#define CPU_FEATURE_PREFERRED_P(ptr, name) \ +- ((ptr->preferred[index_arch_##name] & bit_arch_##name) != 0) + #define CPU_FEATURE_CPU_P(ptr, name) \ + CPU_FEATURE_CHECK_P (ptr, name, cpuid) + #define CPU_FEATURE_USABLE_P(ptr, name) \ + CPU_FEATURE_CHECK_P (ptr, name, usable) + + /* HAS_CPU_FEATURE evaluates to true if CPU supports the feature. */ +-#define HAS_CPU_FEATURE(name) \ +- CPU_FEATURE_CPU_P (__get_cpu_features (), name) ++#define HAS_CPU_FEATURE(name) \ ++ (__extension__ \ ++ ({ const struct cpu_features *__ptr = \ ++ __x86_get_cpu_features (COMMON_CPUID_INDEX_MAX); \ ++ __ptr && CPU_FEATURE_CPU_P (__ptr, name); })) + /* CPU_FEATURE_USABLE evaluates to true if the feature is usable. */ +-#define CPU_FEATURE_USABLE(name) \ +- CPU_FEATURE_USABLE_P (__get_cpu_features (), name) +-/* CPU_FEATURE_PREFER evaluates to true if we prefer the feature at +- runtime. */ +-#define CPU_FEATURE_PREFERRED(name) \ +- CPU_FEATURE_PREFERRED_P(__get_cpu_features (), name) +- +-#define CPU_FEATURES_CPU_P(ptr, name) \ +- CPU_FEATURE_CPU_P (ptr, name) +-#define CPU_FEATURES_ARCH_P(ptr, name) \ +- CPU_FEATURE_PREFERRED_P (ptr, name) +-#define HAS_ARCH_FEATURE(name) \ +- CPU_FEATURE_PREFERRED (name) ++#define CPU_FEATURE_USABLE(name) \ ++ (__extension__ \ ++ ({ const struct cpu_features *__ptr = \ ++ __x86_get_cpu_features (COMMON_CPUID_INDEX_MAX); \ ++ __ptr && CPU_FEATURE_USABLE_P (__ptr, name); })) + + /* CPU features. */ + +@@ -787,71 +738,4 @@ extern const struct cpu_features *__get_cpu_features (void) + /* EAX. */ + #define reg_AVX512_BF16 eax + +-/* FEATURE_INDEX_2. */ +-#define bit_arch_I586 (1u << 0) +-#define bit_arch_I686 (1u << 1) +-#define bit_arch_Fast_Rep_String (1u << 2) +-#define bit_arch_Fast_Copy_Backward (1u << 3) +-#define bit_arch_Fast_Unaligned_Load (1u << 4) +-#define bit_arch_Fast_Unaligned_Copy (1u << 5) +-#define bit_arch_Slow_BSF (1u << 6) +-#define bit_arch_Slow_SSE4_2 (1u << 7) +-#define bit_arch_AVX_Fast_Unaligned_Load (1u << 8) +-#define bit_arch_Prefer_MAP_32BIT_EXEC (1u << 9) +-#define bit_arch_Prefer_PMINUB_for_stringop (1u << 10) +-#define bit_arch_Prefer_No_VZEROUPPER (1u << 11) +-#define bit_arch_Prefer_ERMS (1u << 12) +-#define bit_arch_Prefer_FSRM (1u << 13) +-#define bit_arch_Prefer_No_AVX512 (1u << 14) +-#define bit_arch_MathVec_Prefer_No_AVX512 (1u << 15) +- +-#define index_arch_Fast_Rep_String PREFERRED_FEATURE_INDEX_1 +-#define index_arch_Fast_Copy_Backward PREFERRED_FEATURE_INDEX_1 +-#define index_arch_Slow_BSF PREFERRED_FEATURE_INDEX_1 +-#define index_arch_Fast_Unaligned_Load PREFERRED_FEATURE_INDEX_1 +-#define index_arch_Prefer_PMINUB_for_stringop PREFERRED_FEATURE_INDEX_1 +-#define index_arch_Fast_Unaligned_Copy PREFERRED_FEATURE_INDEX_1 +-#define index_arch_I586 PREFERRED_FEATURE_INDEX_1 +-#define index_arch_I686 PREFERRED_FEATURE_INDEX_1 +-#define index_arch_Slow_SSE4_2 PREFERRED_FEATURE_INDEX_1 +-#define index_arch_AVX_Fast_Unaligned_Load PREFERRED_FEATURE_INDEX_1 +-#define index_arch_Prefer_MAP_32BIT_EXEC PREFERRED_FEATURE_INDEX_1 +-#define index_arch_Prefer_No_VZEROUPPER PREFERRED_FEATURE_INDEX_1 +-#define index_arch_Prefer_ERMS PREFERRED_FEATURE_INDEX_1 +-#define index_arch_Prefer_No_AVX512 PREFERRED_FEATURE_INDEX_1 +-#define index_arch_MathVec_Prefer_No_AVX512 PREFERRED_FEATURE_INDEX_1 +-#define index_arch_Prefer_FSRM PREFERRED_FEATURE_INDEX_1 +- +-/* XCR0 Feature flags. */ +-#define bit_XMM_state (1u << 1) +-#define bit_YMM_state (1u << 2) +-#define bit_Opmask_state (1u << 5) +-#define bit_ZMM0_15_state (1u << 6) +-#define bit_ZMM16_31_state (1u << 7) +-#define bit_XTILECFG_state (1u << 17) +-#define bit_XTILEDATA_state (1u << 18) +- +-# if defined (_LIBC) && !IS_IN (nonlib) +-/* Unused for x86. */ +-# define INIT_ARCH() +-# define __get_cpu_features() (&GLRO(dl_x86_cpu_features)) +-# endif +- +-#ifdef __x86_64__ +-# define HAS_CPUID 1 +-#elif (defined __i586__ || defined __pentium__ \ +- || defined __geode__ || defined __k6__) +-# define HAS_CPUID 1 +-# define HAS_I586 1 +-# define HAS_I686 HAS_ARCH_FEATURE (I686) +-#elif defined __i486__ +-# define HAS_CPUID 0 +-# define HAS_I586 HAS_ARCH_FEATURE (I586) +-# define HAS_I686 HAS_ARCH_FEATURE (I686) +-#else +-# define HAS_CPUID 1 +-# define HAS_I586 1 +-# define HAS_I686 1 +-#endif +- +-#endif /* cpu_features_h */ ++#endif /* _SYS_PLATFORM_X86_H */ +diff --git a/sysdeps/x86/tst-cpu-features-cpuinfo.c b/sysdeps/x86/tst-cpu-features-cpuinfo.c +new file mode 100644 +index 0000000000000000..96277284d15a0690 +--- /dev/null ++++ b/sysdeps/x86/tst-cpu-features-cpuinfo.c +@@ -0,0 +1,250 @@ ++/* Test CPU feature data against /proc/cpuinfo. ++ This file is part of the GNU C Library. ++ Copyright (C) 2012-2020 Free Software Foundation, Inc. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for 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 char *cpu_flags; ++ ++/* Search for flags in /proc/cpuinfo and store line ++ in cpu_flags. */ ++void ++get_cpuinfo (void) ++{ ++ FILE *f; ++ char *line = NULL; ++ size_t len = 0; ++ ssize_t read; ++ ++ f = fopen ("/proc/cpuinfo", "r"); ++ if (f == NULL) ++ { ++ printf ("cannot open /proc/cpuinfo\n"); ++ exit (1); ++ } ++ ++ while ((read = getline (&line, &len, f)) != -1) ++ { ++ if (strncmp (line, "flags", 5) == 0) ++ { ++ cpu_flags = strdup (line); ++ break; ++ } ++ } ++ fclose (f); ++ free (line); ++} ++ ++int ++check_proc (const char *proc_name, int flag, int usable, const char *name) ++{ ++ int found = 0; ++ ++ printf ("Checking %s:\n", name); ++ if (!usable) ++ { ++ printf (" %s: insufficient usable info, skipped\n", name); ++ return 0; ++ } ++ printf (" %s: %d\n", name, flag); ++ if (strstr (cpu_flags, proc_name) != NULL) ++ found = 1; ++ printf (" cpuinfo (%s): %d\n", proc_name, found); ++ ++ if (found != flag) ++ printf (" *** failure ***\n"); ++ ++ return (found != flag); ++} ++ ++#define CHECK_PROC(str, name) \ ++ check_proc (#str, HAS_CPU_FEATURE (name), CPU_FEATURE_USABLE (name), \ ++ "HAS_CPU_FEATURE (" #name ")"); ++ ++static int ++do_test (int argc, char **argv) ++{ ++ int fails = 0; ++ ++ get_cpuinfo (); ++ fails += CHECK_PROC (acpi, ACPI); ++ fails += CHECK_PROC (adx, ADX); ++ fails += CHECK_PROC (apic, APIC); ++ fails += CHECK_PROC (aes, AES); ++ fails += CHECK_PROC (amx_bf16, AMX_BF16); ++ fails += CHECK_PROC (amx_int8, AMX_INT8); ++ fails += CHECK_PROC (amx_tile, AMX_TILE); ++ fails += CHECK_PROC (arch_capabilities, ARCH_CAPABILITIES); ++ fails += CHECK_PROC (avx, AVX); ++ fails += CHECK_PROC (avx2, AVX2); ++ fails += CHECK_PROC (avx512_4fmaps, AVX512_4FMAPS); ++ fails += CHECK_PROC (avx512_4vnniw, AVX512_4VNNIW); ++ fails += CHECK_PROC (avx512_bf16, AVX512_BF16); ++ fails += CHECK_PROC (avx512_bitalg, AVX512_BITALG); ++ fails += CHECK_PROC (avx512ifma, AVX512_IFMA); ++ fails += CHECK_PROC (avx512_vbmi, AVX512_VBMI); ++ fails += CHECK_PROC (avx512_vbmi2, AVX512_VBMI2); ++ fails += CHECK_PROC (avx512_vnni, AVX512_VNNI); ++ fails += CHECK_PROC (avx512_vp2intersect, AVX512_VP2INTERSECT); ++ fails += CHECK_PROC (avx512_vpopcntdq, AVX512_VPOPCNTDQ); ++ fails += CHECK_PROC (avx512bw, AVX512BW); ++ fails += CHECK_PROC (avx512cd, AVX512CD); ++ fails += CHECK_PROC (avx512er, AVX512ER); ++ fails += CHECK_PROC (avx512dq, AVX512DQ); ++ fails += CHECK_PROC (avx512f, AVX512F); ++ fails += CHECK_PROC (avx512pf, AVX512PF); ++ fails += CHECK_PROC (avx512vl, AVX512VL); ++ fails += CHECK_PROC (bmi1, BMI1); ++ fails += CHECK_PROC (bmi2, BMI2); ++ fails += CHECK_PROC (cldemote, CLDEMOTE); ++ fails += CHECK_PROC (clflushopt, CLFLUSHOPT); ++ fails += CHECK_PROC (clflush, CLFSH); ++ fails += CHECK_PROC (clwb, CLWB); ++ fails += CHECK_PROC (cmov, CMOV); ++ fails += CHECK_PROC (cx16, CMPXCHG16B); ++ fails += CHECK_PROC (cnxt_id, CNXT_ID); ++ fails += CHECK_PROC (core_capabilities, CORE_CAPABILITIES); ++ fails += CHECK_PROC (cx8, CX8); ++ fails += CHECK_PROC (dca, DCA); ++ fails += CHECK_PROC (de, DE); ++ fails += CHECK_PROC (zero_fcs_fds, DEPR_FPU_CS_DS); ++ fails += CHECK_PROC (ds, DS); ++ fails += CHECK_PROC (ds_cpl, DS_CPL); ++ fails += CHECK_PROC (dtes64, DTES64); ++ fails += CHECK_PROC (est, EIST); ++ fails += CHECK_PROC (enqcmd, ENQCMD); ++ fails += CHECK_PROC (erms, ERMS); ++ fails += CHECK_PROC (f16c, F16C); ++ fails += CHECK_PROC (fma, FMA); ++ fails += CHECK_PROC (fma4, FMA4); ++ fails += CHECK_PROC (fpu, FPU); ++ fails += CHECK_PROC (fsgsbase, FSGSBASE); ++ fails += CHECK_PROC (fsrm, FSRM); ++ fails += CHECK_PROC (fxsr, FXSR); ++ fails += CHECK_PROC (gfni, GFNI); ++ fails += CHECK_PROC (hle, HLE); ++ fails += CHECK_PROC (ht, HTT); ++ fails += CHECK_PROC (hybrid, HYBRID); ++ fails += CHECK_PROC (ibrs, IBRS_IBPB); ++ fails += CHECK_PROC (ibt, IBT); ++ fails += CHECK_PROC (invariant_tsc, INVARIANT_TSC); ++ fails += CHECK_PROC (invpcid, INVPCID); ++ fails += CHECK_PROC (flush_l1d, L1D_FLUSH); ++ fails += CHECK_PROC (lahf_lm, LAHF64_SAHF64); ++ fails += CHECK_PROC (lm, LM); ++ fails += CHECK_PROC (lwp, LWP); ++ fails += CHECK_PROC (abm, LZCNT); ++ fails += CHECK_PROC (mca, MCA); ++ fails += CHECK_PROC (mce, MCE); ++ fails += CHECK_PROC (md_clear, MD_CLEAR); ++ fails += CHECK_PROC (mmx, MMX); ++ fails += CHECK_PROC (monitor, MONITOR); ++ fails += CHECK_PROC (movbe, MOVBE); ++ fails += CHECK_PROC (movdiri, MOVDIRI); ++ fails += CHECK_PROC (movdir64b, MOVDIR64B); ++ fails += CHECK_PROC (mpx, MPX); ++ fails += CHECK_PROC (msr, MSR); ++ fails += CHECK_PROC (mtrr, MTRR); ++ fails += CHECK_PROC (nx, NX); ++ fails += CHECK_PROC (ospke, OSPKE); ++#if 0 ++ /* NB: /proc/cpuinfo doesn't report this feature. */ ++ fails += CHECK_PROC (osxsave, OSXSAVE); ++#endif ++ fails += CHECK_PROC (pae, PAE); ++ fails += CHECK_PROC (pdpe1gb, PAGE1GB); ++ fails += CHECK_PROC (pat, PAT); ++ fails += CHECK_PROC (pbe, PBE); ++ fails += CHECK_PROC (pcid, PCID); ++ fails += CHECK_PROC (pclmulqdq, PCLMULQDQ); ++ fails += CHECK_PROC (pconfig, PCONFIG); ++ fails += CHECK_PROC (pdcm, PDCM); ++ fails += CHECK_PROC (pge, PGE); ++ fails += CHECK_PROC (pks, PKS); ++ fails += CHECK_PROC (pku, PKU); ++ fails += CHECK_PROC (popcnt, POPCNT); ++ fails += CHECK_PROC (3dnowprefetch, PREFETCHW); ++ fails += CHECK_PROC (prefetchwt1, PREFETCHWT1); ++ fails += CHECK_PROC (pse, PSE); ++ fails += CHECK_PROC (pse36, PSE_36); ++ fails += CHECK_PROC (psn, PSN); ++ fails += CHECK_PROC (rdpid, RDPID); ++ fails += CHECK_PROC (rdrand, RDRAND); ++ fails += CHECK_PROC (rdseed, RDSEED); ++ fails += CHECK_PROC (rdt_a, RDT_A); ++ fails += CHECK_PROC (cqm, RDT_M); ++ fails += CHECK_PROC (rdtscp, RDTSCP); ++ fails += CHECK_PROC (rtm, RTM); ++ fails += CHECK_PROC (sdbg, SDBG); ++ fails += CHECK_PROC (sep, SEP); ++ fails += CHECK_PROC (serialize, SERIALIZE); ++ fails += CHECK_PROC (sgx, SGX); ++ fails += CHECK_PROC (sgx_lc, SGX_LC); ++ fails += CHECK_PROC (sha_ni, SHA); ++ fails += CHECK_PROC (shstk, SHSTK); ++ fails += CHECK_PROC (smap, SMAP); ++ fails += CHECK_PROC (smep, SMEP); ++ fails += CHECK_PROC (smx, SMX); ++ fails += CHECK_PROC (ss, SS); ++ fails += CHECK_PROC (ssbd, SSBD); ++ fails += CHECK_PROC (sse, SSE); ++ fails += CHECK_PROC (sse2, SSE2); ++ fails += CHECK_PROC (sse3, SSE3); ++ fails += CHECK_PROC (sse4_1, SSE4_1); ++ fails += CHECK_PROC (sse4_2, SSE4_2); ++ fails += CHECK_PROC (sse4a, SSE4A); ++ fails += CHECK_PROC (ssse3, SSSE3); ++ fails += CHECK_PROC (stibp, STIBP); ++ fails += CHECK_PROC (svm, SVM); ++#ifdef __x86_64__ ++ /* NB: SYSCALL_SYSRET is 64-bit only. */ ++ fails += CHECK_PROC (syscall, SYSCALL_SYSRET); ++#endif ++ fails += CHECK_PROC (tbm, TBM); ++ fails += CHECK_PROC (tm, TM); ++ fails += CHECK_PROC (tm2, TM2); ++ fails += CHECK_PROC (intel_pt, TRACE); ++ fails += CHECK_PROC (tsc, TSC); ++ fails += CHECK_PROC (tsc_adjust, TSC_ADJUST); ++ fails += CHECK_PROC (tsc_deadline, TSC_DEADLINE); ++ fails += CHECK_PROC (tsxldtrk, TSXLDTRK); ++ fails += CHECK_PROC (umip, UMIP); ++ fails += CHECK_PROC (vaes, VAES); ++ fails += CHECK_PROC (vme, VME); ++ fails += CHECK_PROC (vmx, VMX); ++ fails += CHECK_PROC (vpclmulqdq, VPCLMULQDQ); ++ fails += CHECK_PROC (waitpkg, WAITPKG); ++ fails += CHECK_PROC (wbnoinvd, WBNOINVD); ++ fails += CHECK_PROC (x2apic, X2APIC); ++ fails += CHECK_PROC (xfd, XFD); ++ fails += CHECK_PROC (xgetbv1, XGETBV_ECX_1); ++ fails += CHECK_PROC (xop, XOP); ++ fails += CHECK_PROC (xsave, XSAVE); ++ fails += CHECK_PROC (xsavec, XSAVEC); ++ fails += CHECK_PROC (xsaveopt, XSAVEOPT); ++ fails += CHECK_PROC (xsaves, XSAVES); ++ fails += CHECK_PROC (xtpr, XTPRUPDCTRL); ++ ++ printf ("%d differences between /proc/cpuinfo and glibc code.\n", fails); ++ ++ return (fails != 0); ++} ++ ++#include "../../../test-skeleton.c" +diff --git a/sysdeps/x86/tst-cpu-features-supports.c b/sysdeps/x86/tst-cpu-features-supports.c +new file mode 100644 +index 0000000000000000..bf881b531f4bc2ed +--- /dev/null ++++ b/sysdeps/x86/tst-cpu-features-supports.c +@@ -0,0 +1,192 @@ ++/* Test CPU feature data against __builtin_cpu_supports. ++ This file is part of the GNU C Library. ++ Copyright (C) 2020 Free Software Foundation, Inc. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for 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 ++check_supports (int supports, int usable, const char *supports_name, ++ const char *name) ++{ ++ printf ("Checking %s:\n", name); ++ printf (" %s: %d\n", name, usable); ++ printf (" __builtin_cpu_supports (%s): %d\n", ++ supports_name, supports); ++ ++ if ((supports != 0) != (usable != 0)) ++ { ++ printf (" *** failure ***\n"); ++ return 1; ++ } ++ ++ return 0; ++} ++ ++#define CHECK_SUPPORTS(str, name) \ ++ check_supports (__builtin_cpu_supports (#str), \ ++ CPU_FEATURE_USABLE (name), \ ++ #str, "HAS_CPU_FEATURE (" #name ")"); ++ ++static int ++do_test (int argc, char **argv) ++{ ++ int fails = 0; ++ ++#if __GNUC_PREREQ (11, 0) ++ fails += CHECK_SUPPORTS (adx, ADX); ++#endif ++#if __GNUC_PREREQ (6, 0) ++ fails += CHECK_SUPPORTS (aes, AES); ++#endif ++#if __GNUC_PREREQ (11, 1) ++ fails += CHECK_SUPPORTS (amx_bf16, AMX_BF16); ++ fails += CHECK_SUPPORTS (amx_int8, AMX_INT8); ++ fails += CHECK_SUPPORTS (amx_tile, AMX_TILE); ++#endif ++ fails += CHECK_SUPPORTS (avx, AVX); ++ fails += CHECK_SUPPORTS (avx2, AVX2); ++#if __GNUC_PREREQ (7, 0) ++ fails += CHECK_SUPPORTS (avx5124fmaps, AVX512_4FMAPS); ++ fails += CHECK_SUPPORTS (avx5124vnniw, AVX512_4VNNIW); ++#endif ++#if __GNUC_PREREQ (10, 0) ++ fails += CHECK_SUPPORTS (avx512bf16, AVX512_BF16); ++#endif ++#if __GNUC_PREREQ (8, 0) ++ fails += CHECK_SUPPORTS (avx512bitalg, AVX512_BITALG); ++#endif ++#if __GNUC_PREREQ (6, 0) ++ fails += CHECK_SUPPORTS (avx512ifma, AVX512_IFMA); ++ fails += CHECK_SUPPORTS (avx512vbmi, AVX512_VBMI); ++#endif ++#if __GNUC_PREREQ (8, 0) ++ fails += CHECK_SUPPORTS (avx512vbmi2, AVX512_VBMI2); ++ fails += CHECK_SUPPORTS (avx512vnni, AVX512_VNNI); ++#endif ++#if __GNUC_PREREQ (10, 0) ++ fails += CHECK_SUPPORTS (avx512vp2intersect, AVX512_VP2INTERSECT); ++#endif ++#if __GNUC_PREREQ (7, 0) ++ fails += CHECK_SUPPORTS (avx512vpopcntdq, AVX512_VPOPCNTDQ); ++#endif ++#if __GNUC_PREREQ (6, 0) ++ fails += CHECK_SUPPORTS (avx512bw, AVX512BW); ++ fails += CHECK_SUPPORTS (avx512cd, AVX512CD); ++ fails += CHECK_SUPPORTS (avx512er, AVX512ER); ++ fails += CHECK_SUPPORTS (avx512dq, AVX512DQ); ++#endif ++#if __GNUC_PREREQ (5, 0) ++ fails += CHECK_SUPPORTS (avx512f, AVX512F); ++#endif ++#if __GNUC_PREREQ (6, 0) ++ fails += CHECK_SUPPORTS (avx512pf, AVX512PF); ++ fails += CHECK_SUPPORTS (avx512vl, AVX512VL); ++#endif ++#if __GNUC_PREREQ (5, 0) ++ fails += CHECK_SUPPORTS (bmi, BMI1); ++ fails += CHECK_SUPPORTS (bmi2, BMI2); ++#endif ++#if __GNUC_PREREQ (11, 0) ++ fails += CHECK_SUPPORTS (cldemote, CLDEMOTE); ++ fails += CHECK_SUPPORTS (clflushopt, CLFLUSHOPT); ++ fails += CHECK_SUPPORTS (clwb, CLWB); ++#endif ++ fails += CHECK_SUPPORTS (cmov, CMOV); ++#if __GNUC_PREREQ (11, 0) ++ fails += CHECK_SUPPORTS (cmpxchg16b, CMPXCHG16B); ++ fails += CHECK_SUPPORTS (cmpxchg8b, CX8); ++ fails += CHECK_SUPPORTS (enqcmd, ENQCMD); ++ fails += CHECK_SUPPORTS (f16c, F16C); ++#endif ++#if __GNUC_PREREQ (4, 9) ++ fails += CHECK_SUPPORTS (fma, FMA); ++ fails += CHECK_SUPPORTS (fma4, FMA4); ++#endif ++#if __GNUC_PREREQ (11, 0) ++ fails += CHECK_SUPPORTS (fsgsbase, FSGSBASE); ++ fails += CHECK_SUPPORTS (fxsave, FXSR); ++#endif ++#if __GNUC_PREREQ (8, 0) ++ fails += CHECK_SUPPORTS (gfni, GFNI); ++#endif ++#if __GNUC_PREREQ (11, 0) ++ fails += CHECK_SUPPORTS (hle, HLE); ++ fails += CHECK_SUPPORTS (ibt, IBT); ++ fails += CHECK_SUPPORTS (lahf_lm, LAHF64_SAHF64); ++ fails += CHECK_SUPPORTS (lm, LM); ++ fails += CHECK_SUPPORTS (lwp, LWP); ++ fails += CHECK_SUPPORTS (lzcnt, LZCNT); ++#endif ++ fails += CHECK_SUPPORTS (mmx, MMX); ++#if __GNUC_PREREQ (11, 0) ++ fails += CHECK_SUPPORTS (movbe, MOVBE); ++ fails += CHECK_SUPPORTS (movdiri, MOVDIRI); ++ fails += CHECK_SUPPORTS (movdir64b, MOVDIR64B); ++ fails += CHECK_SUPPORTS (osxsave, OSXSAVE); ++ fails += CHECK_SUPPORTS (pconfig, PCONFIG); ++ fails += CHECK_SUPPORTS (pku, PKU); ++#endif ++ fails += CHECK_SUPPORTS (popcnt, POPCNT); ++#if __GNUC_PREREQ (11, 0) ++ fails += CHECK_SUPPORTS (prefetchwt1, PREFETCHWT1); ++ fails += CHECK_SUPPORTS (rdpid, RDPID); ++ fails += CHECK_SUPPORTS (rdrnd, RDRAND); ++ fails += CHECK_SUPPORTS (rdseed, RDSEED); ++ fails += CHECK_SUPPORTS (rtm, RTM); ++ fails += CHECK_SUPPORTS (serialize, SERIALIZE); ++ fails += CHECK_SUPPORTS (sha, SHA); ++ fails += CHECK_SUPPORTS (shstk, SHSTK); ++#endif ++ fails += CHECK_SUPPORTS (sse, SSE); ++ fails += CHECK_SUPPORTS (sse2, SSE2); ++ fails += CHECK_SUPPORTS (sse3, SSE3); ++ fails += CHECK_SUPPORTS (sse4.1, SSE4_1); ++ fails += CHECK_SUPPORTS (sse4.2, SSE4_2); ++#if __GNUC_PREREQ (4, 9) ++ fails += CHECK_SUPPORTS (sse4a, SSE4A); ++#endif ++ fails += CHECK_SUPPORTS (ssse3, SSSE3); ++#if __GNUC_PREREQ (11, 0) ++ fails += CHECK_SUPPORTS (tbm, TBM); ++ fails += CHECK_SUPPORTS (tsxldtrk, TSXLDTRK); ++ fails += CHECK_SUPPORTS (vaes, VAES); ++#endif ++#if __GNUC_PREREQ (8, 0) ++ fails += CHECK_SUPPORTS (vpclmulqdq, VPCLMULQDQ); ++#endif ++#if __GNUC_PREREQ (11, 0) ++ fails += CHECK_SUPPORTS (waitpkg, WAITPKG); ++ fails += CHECK_SUPPORTS (wbnoinvd, WBNOINVD); ++#endif ++#if __GNUC_PREREQ (4, 9) ++ fails += CHECK_SUPPORTS (xop, XOP); ++#endif ++#if __GNUC_PREREQ (11, 0) ++ fails += CHECK_SUPPORTS (xsave, XSAVE); ++ fails += CHECK_SUPPORTS (xsavec, XSAVEC); ++ fails += CHECK_SUPPORTS (xsaveopt, XSAVEOPT); ++ fails += CHECK_SUPPORTS (xsaves, XSAVES); ++#endif ++ ++ printf ("%d differences between __builtin_cpu_supports and glibc code.\n", ++ fails); ++ ++ return (fails != 0); ++} ++ ++#include "../../../test-skeleton.c" +diff --git a/sysdeps/x86/tst-get-cpu-features.c b/sysdeps/x86/tst-get-cpu-features.c +index 582b125a2dad3f21..95e0d33f6c7eeace 100644 +--- a/sysdeps/x86/tst-get-cpu-features.c ++++ b/sysdeps/x86/tst-get-cpu-features.c +@@ -1,5 +1,5 @@ +-/* Test case for x86 __get_cpu_features interface +- Copyright (C) 2015-2018 Free Software Foundation, Inc. ++/* Test case for __x86_get_cpu_features interface ++ Copyright (C) 2015-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 +@@ -18,7 +18,7 @@ + + #include + #include +-#include ++#include + #include + + #define CHECK_CPU_FEATURE(name) \ +@@ -44,7 +44,7 @@ static const char * const cpu_kinds[] = + static int + do_test (void) + { +- const struct cpu_features *cpu_features = __get_cpu_features (); ++ const struct cpu_features *cpu_features = __x86_get_cpu_features (0); + + switch (cpu_features->basic.kind) + { +diff --git a/sysdeps/x86_64/fpu/math-tests-arch.h b/sysdeps/x86_64/fpu/math-tests-arch.h +index 61955d70863321fd..c908eac6b4fff16d 100644 +--- a/sysdeps/x86_64/fpu/math-tests-arch.h ++++ b/sysdeps/x86_64/fpu/math-tests-arch.h +@@ -16,7 +16,7 @@ + License along with the GNU C Library; if not, see + . */ + +-#include ++#include + + #if defined REQUIRE_AVX + +diff --git a/sysdeps/x86_64/multiarch/Makefile b/sysdeps/x86_64/multiarch/Makefile +index 395e432c092ca17c..9477538af46787a5 100644 +--- a/sysdeps/x86_64/multiarch/Makefile ++++ b/sysdeps/x86_64/multiarch/Makefile +@@ -1,7 +1,3 @@ +-ifeq ($(subdir),csu) +-tests += test-multiarch +-endif +- + ifeq ($(subdir),string) + + sysdep_routines += strncat-c stpncpy-c strncpy-c \ +diff --git a/sysdeps/x86_64/multiarch/test-multiarch.c b/sysdeps/x86_64/multiarch/test-multiarch.c +deleted file mode 100644 +index cc2ea56a6753402d..0000000000000000 +--- a/sysdeps/x86_64/multiarch/test-multiarch.c ++++ /dev/null +@@ -1,96 +0,0 @@ +-/* Test CPU feature data. +- This file is part of the GNU C Library. +- Copyright (C) 2012-2018 Free Software Foundation, Inc. +- +- The GNU C Library is free software; you can redistribute it and/or +- modify it under the terms of the GNU Lesser General Public +- License as published by the Free Software Foundation; either +- version 2.1 of the License, or (at your option) any later version. +- +- The GNU C Library is distributed in the hope that it will be useful, +- but WITHOUT ANY WARRANTY; without even the implied warranty of +- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +- Lesser General Public License for 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 char *cpu_flags; +- +-/* Search for flags in /proc/cpuinfo and store line +- in cpu_flags. */ +-void +-get_cpuinfo (void) +-{ +- FILE *f; +- char *line = NULL; +- size_t len = 0; +- ssize_t read; +- +- f = fopen ("/proc/cpuinfo", "r"); +- if (f == NULL) +- { +- printf ("cannot open /proc/cpuinfo\n"); +- exit (1); +- } +- +- while ((read = getline (&line, &len, f)) != -1) +- { +- if (strncmp (line, "flags", 5) == 0) +- { +- cpu_flags = strdup (line); +- break; +- } +- } +- fclose (f); +- free (line); +-} +- +-int +-check_proc (const char *proc_name, int flag, const char *name) +-{ +- int found = 0; +- +- printf ("Checking %s:\n", name); +- printf (" init-arch %d\n", flag); +- if (strstr (cpu_flags, proc_name) != NULL) +- found = 1; +- printf (" cpuinfo (%s) %d\n", proc_name, found); +- +- if (found != flag) +- printf (" *** failure ***\n"); +- +- return (found != flag); +-} +- +-static int +-do_test (int argc, char **argv) +-{ +- int fails; +- +- get_cpuinfo (); +- fails = check_proc ("avx", CPU_FEATURE_USABLE (AVX), +- "CPU_FEATURE_USABLE (AVX)"); +- fails += check_proc ("fma4", CPU_FEATURE_USABLE (FMA4), +- "CPU_FEATURE_USABLE (FMA4)"); +- fails += check_proc ("sse4_2", CPU_FEATURE_USABLE (SSE4_2), +- "CPU_FEATURE_USABLE (SSE4_2)"); +- fails += check_proc ("sse4_1", CPU_FEATURE_USABLE (SSE4_1) +- , "CPU_FEATURE_USABLE (SSE4_1)"); +- fails += check_proc ("ssse3", CPU_FEATURE_USABLE (SSSE3), +- "CPU_FEATURE_USABLE (SSSE3)"); +- fails += check_proc ("popcnt", CPU_FEATURE_USABLE (POPCNT), +- "CPU_FEATURE_USABLE (POPCNT)"); +- +- printf ("%d differences between /proc/cpuinfo and glibc code.\n", fails); +- +- return (fails != 0); +-} +- +-#include "../../../test-skeleton.c" diff --git a/SOURCES/glibc-rh1817513-84.patch b/SOURCES/glibc-rh1817513-84.patch new file mode 100644 index 0000000..e7124ef --- /dev/null +++ b/SOURCES/glibc-rh1817513-84.patch @@ -0,0 +1,207 @@ +commit f2c679d4b2c73a95f437c705f960a4af1fa23498 +Author: H.J. Lu +Date: Tue Sep 15 05:49:27 2020 -0700 + + : Add Intel Key Locker support + + Add Intel Key Locker: + + https://software.intel.com/content/www/us/en/develop/download/intel-key-locker-specification.html + + support to . Intel Key Locker has + + 1. KL: AES Key Locker instructions. + 2. WIDE_KL: AES wide Key Locker instructions. + 3. AESKLE: AES Key Locker instructions are enabled by OS. + + Applications should use + + if (CPU_FEATURE_USABLE (KL)) + + and + + if (CPU_FEATURE_USABLE (WIDE_KL)) + + to check if AES Key Locker instructions and AES wide Key Locker + instructions are usable. + +diff --git a/manual/platform.texi b/manual/platform.texi +index 2c145acdc3564cbb..95b0ed0642c9f8a9 100644 +--- a/manual/platform.texi ++++ b/manual/platform.texi +@@ -177,6 +177,9 @@ The supported processor features are: + @item + @code{AES} -- The AES instruction extensions. + ++@item ++@code{AESKLE} -- AES Key Locker instructions are enabled by OS. ++ + @item + @code{AMX_BF16} -- Tile computational operations on bfloat16 numbers. + +@@ -353,6 +356,9 @@ the indirect branch predictor barrier (IBPB). + @item + @code{INVPCID} -- INVPCID instruction. + ++@item ++@code{KL} -- AES Key Locker instructions. ++ + @item + @code{L1D_FLUSH} -- IA32_FLUSH_CMD MSR. + +@@ -598,6 +604,9 @@ using a TSC deadline value. + @item + @code{WBNOINVD} -- WBINVD/WBNOINVD instructions. + ++@item ++@code{WIDE_KL} -- AES wide Key Locker instructions. ++ + @item + @code{X2APIC} -- x2APIC. + +diff --git a/sysdeps/x86/cpu-features.c b/sysdeps/x86/cpu-features.c +index 6954728c47d0126b..77a596a15404b575 100644 +--- a/sysdeps/x86/cpu-features.c ++++ b/sysdeps/x86/cpu-features.c +@@ -269,6 +269,14 @@ update_usable (struct cpu_features *cpu_features) + /* Determine if PKU is usable. */ + if (CPU_FEATURES_CPU_P (cpu_features, OSPKE)) + CPU_FEATURE_SET (cpu_features, PKU); ++ ++ /* Determine if Key Locker instructions are usable. */ ++ if (CPU_FEATURES_CPU_P (cpu_features, AESKLE)) ++ { ++ CPU_FEATURE_SET (cpu_features, AESKLE); ++ CPU_FEATURE_SET_USABLE (cpu_features, KL); ++ CPU_FEATURE_SET_USABLE (cpu_features, WIDE_KL); ++ } + } + + static void +@@ -341,6 +349,12 @@ get_common_indices (struct cpu_features *cpu_features, + cpu_features->features[COMMON_CPUID_INDEX_D_ECX_1].cpuid.ecx, + cpu_features->features[COMMON_CPUID_INDEX_D_ECX_1].cpuid.edx); + ++ if (cpu_features->basic.max_cpuid >= 0x19) ++ __cpuid_count (0x19, 0, ++ cpu_features->features[COMMON_CPUID_INDEX_19].cpuid.eax, ++ cpu_features->features[COMMON_CPUID_INDEX_19].cpuid.ebx, ++ cpu_features->features[COMMON_CPUID_INDEX_19].cpuid.ecx, ++ cpu_features->features[COMMON_CPUID_INDEX_19].cpuid.edx); + } + + _Static_assert (((index_arch_Fast_Unaligned_Load +diff --git a/sysdeps/x86/sys/platform/x86.h b/sysdeps/x86/sys/platform/x86.h +index ebc5f6fc16cb8104..bcc81ab5f8ac8265 100644 +--- a/sysdeps/x86/sys/platform/x86.h ++++ b/sysdeps/x86/sys/platform/x86.h +@@ -28,6 +28,7 @@ enum + COMMON_CPUID_INDEX_80000007, + COMMON_CPUID_INDEX_80000008, + COMMON_CPUID_INDEX_7_ECX_1, ++ COMMON_CPUID_INDEX_19, + /* Keep the following line at the end. */ + COMMON_CPUID_INDEX_MAX + }; +@@ -224,7 +225,7 @@ extern const struct cpu_features *__x86_get_cpu_features (unsigned int) + /* Note: Bits 17-21: The value of MAWAU used by the BNDLDX and BNDSTX + instructions in 64-bit mode. */ + #define bit_cpu_RDPID (1u << 22) +-#define bit_cpu_INDEX_7_ECX_23 (1u << 23) ++#define bit_cpu_KL (1u << 23) + #define bit_cpu_INDEX_7_ECX_24 (1u << 24) + #define bit_cpu_CLDEMOTE (1u << 25) + #define bit_cpu_INDEX_7_ECX_26 (1u << 26) +@@ -312,6 +313,12 @@ extern const struct cpu_features *__x86_get_cpu_features (unsigned int) + /* EAX. */ + #define bit_cpu_AVX512_BF16 (1u << 5) + ++/* COMMON_CPUID_INDEX_19. */ ++ ++/* EBX. */ ++#define bit_cpu_AESKLE (1u << 0) ++#define bit_cpu_WIDE_KL (1u << 2) ++ + /* COMMON_CPUID_INDEX_1. */ + + /* ECX. */ +@@ -437,7 +444,7 @@ extern const struct cpu_features *__x86_get_cpu_features (unsigned int) + #define index_cpu_INDEX_7_ECX_15 COMMON_CPUID_INDEX_7 + #define index_cpu_INDEX_7_ECX_16 COMMON_CPUID_INDEX_7 + #define index_cpu_RDPID COMMON_CPUID_INDEX_7 +-#define index_cpu_INDEX_7_ECX_23 COMMON_CPUID_INDEX_7 ++#define index_cpu_KL COMMON_CPUID_INDEX_7 + #define index_cpu_INDEX_7_ECX_24 COMMON_CPUID_INDEX_7 + #define index_cpu_CLDEMOTE COMMON_CPUID_INDEX_7 + #define index_cpu_INDEX_7_ECX_26 COMMON_CPUID_INDEX_7 +@@ -525,6 +532,12 @@ extern const struct cpu_features *__x86_get_cpu_features (unsigned int) + /* EAX. */ + #define index_cpu_AVX512_BF16 COMMON_CPUID_INDEX_7_ECX_1 + ++/* COMMON_CPUID_INDEX_19. */ ++ ++/* EBX. */ ++#define index_cpu_AESKLE COMMON_CPUID_INDEX_19 ++#define index_cpu_WIDE_KL COMMON_CPUID_INDEX_19 ++ + /* COMMON_CPUID_INDEX_1. */ + + /* ECX. */ +@@ -650,7 +663,7 @@ extern const struct cpu_features *__x86_get_cpu_features (unsigned int) + #define reg_INDEX_7_ECX_15 ecx + #define reg_INDEX_7_ECX_16 ecx + #define reg_RDPID ecx +-#define reg_INDEX_7_ECX_23 ecx ++#define reg_KL ecx + #define reg_INDEX_7_ECX_24 ecx + #define reg_CLDEMOTE ecx + #define reg_INDEX_7_ECX_26 ecx +@@ -738,4 +751,10 @@ extern const struct cpu_features *__x86_get_cpu_features (unsigned int) + /* EAX. */ + #define reg_AVX512_BF16 eax + ++/* COMMON_CPUID_INDEX_19. */ ++ ++/* EBX. */ ++#define reg_AESKLE ebx ++#define reg_WIDE_KL ebx ++ + #endif /* _SYS_PLATFORM_X86_H */ +diff --git a/sysdeps/x86/tst-get-cpu-features.c b/sysdeps/x86/tst-get-cpu-features.c +index 95e0d33f6c7eeace..c01d701b52090983 100644 +--- a/sysdeps/x86/tst-get-cpu-features.c ++++ b/sysdeps/x86/tst-get-cpu-features.c +@@ -170,6 +170,7 @@ do_test (void) + CHECK_CPU_FEATURE (AVX512_BITALG); + CHECK_CPU_FEATURE (AVX512_VPOPCNTDQ); + CHECK_CPU_FEATURE (RDPID); ++ CHECK_CPU_FEATURE (KL); + CHECK_CPU_FEATURE (CLDEMOTE); + CHECK_CPU_FEATURE (MOVDIRI); + CHECK_CPU_FEATURE (MOVDIR64B); +@@ -217,6 +218,8 @@ do_test (void) + CHECK_CPU_FEATURE (INVARIANT_TSC); + CHECK_CPU_FEATURE (WBNOINVD); + CHECK_CPU_FEATURE (AVX512_BF16); ++ CHECK_CPU_FEATURE (AESKLE); ++ CHECK_CPU_FEATURE (WIDE_KL); + + printf ("Usable CPU features:\n"); + CHECK_CPU_FEATURE_USABLE (SSE3); +@@ -323,6 +326,7 @@ do_test (void) + CHECK_CPU_FEATURE_USABLE (AVX512_BITALG); + CHECK_CPU_FEATURE_USABLE (AVX512_VPOPCNTDQ); + CHECK_CPU_FEATURE_USABLE (RDPID); ++ CHECK_CPU_FEATURE_USABLE (KL); + CHECK_CPU_FEATURE_USABLE (CLDEMOTE); + CHECK_CPU_FEATURE_USABLE (MOVDIRI); + CHECK_CPU_FEATURE_USABLE (MOVDIR64B); +@@ -370,6 +374,8 @@ do_test (void) + CHECK_CPU_FEATURE_USABLE (INVARIANT_TSC); + CHECK_CPU_FEATURE_USABLE (WBNOINVD); + CHECK_CPU_FEATURE_USABLE (AVX512_BF16); ++ CHECK_CPU_FEATURE_USABLE (AESKLE); ++ CHECK_CPU_FEATURE_USABLE (WIDE_KL); + + return 0; + } diff --git a/SOURCES/glibc-rh1817513-85.patch b/SOURCES/glibc-rh1817513-85.patch new file mode 100644 index 0000000..10a18fa --- /dev/null +++ b/SOURCES/glibc-rh1817513-85.patch @@ -0,0 +1,73 @@ +commit 94cd37ebb293321115a36a422b091fdb72d2fb08 +Author: H.J. Lu +Date: Wed Sep 16 05:27:32 2020 -0700 + + x86: Use HAS_CPU_FEATURE with IBT and SHSTK [BZ #26625] + + commit 04bba1e5d84b6fd8d3a3b006bc240cd5d241ee30 + Author: H.J. Lu + Date: Wed Aug 5 13:51:56 2020 -0700 + + x86: Set CPU usable feature bits conservatively [BZ #26552] + + Set CPU usable feature bits only for CPU features which are usable in + user space and whose usability can be detected from user space, excluding + features like FSGSBASE whose enable bit can only be checked in the kernel. + + no longer turns on the usable bits of IBT and SHSTK since we don't know + if IBT and SHSTK are usable until much later. Use HAS_CPU_FEATURE to + check if the processor supports IBT and SHSTK. + +diff --git a/sysdeps/x86/cpu-features.c b/sysdeps/x86/cpu-features.c +index 77a596a15404b575..7f2ff00f2b4b45f2 100644 +--- a/sysdeps/x86/cpu-features.c ++++ b/sysdeps/x86/cpu-features.c +@@ -722,9 +722,9 @@ no_cpuid: + GLIBC_TUNABLES=glibc.cpu.hwcaps=-IBT,-SHSTK + */ + unsigned int cet_feature = 0; +- if (!CPU_FEATURE_USABLE (IBT)) ++ if (!HAS_CPU_FEATURE (IBT)) + cet_feature |= GNU_PROPERTY_X86_FEATURE_1_IBT; +- if (!CPU_FEATURE_USABLE (SHSTK)) ++ if (!HAS_CPU_FEATURE (SHSTK)) + cet_feature |= GNU_PROPERTY_X86_FEATURE_1_SHSTK; + + if (cet_feature) +diff --git a/sysdeps/x86/dl-cet.c b/sysdeps/x86/dl-cet.c +index 11ff0618fae7230f..d481bddc27e5d7cc 100644 +--- a/sysdeps/x86/dl-cet.c ++++ b/sysdeps/x86/dl-cet.c +@@ -74,10 +74,10 @@ dl_cet_check (struct link_map *m, const char *program) + + GLIBC_TUNABLES=glibc.cpu.hwcaps=-IBT,-SHSTK + */ +- enable_ibt &= (CPU_FEATURE_USABLE (IBT) ++ enable_ibt &= (HAS_CPU_FEATURE (IBT) + && (enable_ibt_type == cet_always_on + || (m->l_cet & lc_ibt) != 0)); +- enable_shstk &= (CPU_FEATURE_USABLE (SHSTK) ++ enable_shstk &= (HAS_CPU_FEATURE (SHSTK) + && (enable_shstk_type == cet_always_on + || (m->l_cet & lc_shstk) != 0)); + } +diff --git a/sysdeps/x86/tst-get-cpu-features.c b/sysdeps/x86/tst-get-cpu-features.c +index c01d701b52090983..3ec94e0c9a191f36 100644 +--- a/sysdeps/x86/tst-get-cpu-features.c ++++ b/sysdeps/x86/tst-get-cpu-features.c +@@ -318,7 +318,6 @@ do_test (void) + CHECK_CPU_FEATURE_USABLE (OSPKE); + CHECK_CPU_FEATURE_USABLE (WAITPKG); + CHECK_CPU_FEATURE_USABLE (AVX512_VBMI2); +- CHECK_CPU_FEATURE_USABLE (SHSTK); + CHECK_CPU_FEATURE_USABLE (GFNI); + CHECK_CPU_FEATURE_USABLE (VAES); + CHECK_CPU_FEATURE_USABLE (VPCLMULQDQ); +@@ -342,7 +341,6 @@ do_test (void) + CHECK_CPU_FEATURE_USABLE (HYBRID); + CHECK_CPU_FEATURE_USABLE (TSXLDTRK); + CHECK_CPU_FEATURE_USABLE (PCONFIG); +- CHECK_CPU_FEATURE_USABLE (IBT); + CHECK_CPU_FEATURE_USABLE (AMX_BF16); + CHECK_CPU_FEATURE_USABLE (AMX_TILE); + CHECK_CPU_FEATURE_USABLE (AMX_INT8); diff --git a/SOURCES/glibc-rh1817513-86.patch b/SOURCES/glibc-rh1817513-86.patch new file mode 100644 index 0000000..05a09e7 --- /dev/null +++ b/SOURCES/glibc-rh1817513-86.patch @@ -0,0 +1,173 @@ +commit c6702789344043fa998923c8f32ed0bdb2edfa9c +Author: Vincent Mihalkovic +Date: Tue Sep 29 12:34:39 2020 +0200 + + ld.so: add an --argv0 option [BZ #16124] + +Conflicts: + elf/Makefile + (Missing test backports.) + +diff --git a/elf/Makefile b/elf/Makefile +index 82b5b4a07495c805..837a070c267527e1 100644 +--- a/elf/Makefile ++++ b/elf/Makefile +@@ -198,7 +198,8 @@ tests += restest1 preloadtest loadfail multiload origtest resolvfail \ + 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 ++ tst-tls-ie tst-tls-ie-dlmopen \ ++ argv0test + # reldep9 + tests-internal += loadtest unload unload2 circleload1 \ + neededtest neededtest2 neededtest3 neededtest4 \ +@@ -395,7 +396,7 @@ 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)tst-rtld-preload.out $(objpfx)argv0test.out + endif + tests-special += $(objpfx)check-textrel.out $(objpfx)check-execstack.out \ + $(objpfx)check-wx-segment.out \ +@@ -1716,3 +1717,10 @@ $(objpfx)tst-tls-ie-dlmopen.out: \ + $(objpfx)tst-tls-ie-mod6.so + + $(objpfx)tst-tls-surplus: $(libdl) ++ ++$(objpfx)argv0test.out: tst-rtld-argv0.sh $(objpfx)ld.so \ ++ $(objpfx)argv0test ++ $(SHELL) $< $(objpfx)ld.so $(objpfx)argv0test \ ++ '$(test-wrapper-env)' '$(run_program_env)' \ ++ '$(rpath-link)' 'test-argv0' > $@; \ ++ $(evaluate-test) +diff --git a/elf/argv0test.c b/elf/argv0test.c +new file mode 100644 +index 0000000000000000..c22ba5ea70ed7dbf +--- /dev/null ++++ b/elf/argv0test.c +@@ -0,0 +1,31 @@ ++/* Test for --argv0 option ld.so. ++ ++ 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 ++ ++static int ++do_test (int argc, char **argv) ++{ ++ TEST_COMPARE_STRING (argv[0], "test-argv0"); ++ return 0; ++} ++ ++#define TEST_FUNCTION_ARGV do_test ++#include +diff --git a/elf/rtld.c b/elf/rtld.c +index 67441ac6f252350e..4107a215abd554f4 100644 +--- a/elf/rtld.c ++++ b/elf/rtld.c +@@ -1196,6 +1196,8 @@ dl_main (const ElfW(Phdr) *phdr, + installing it. */ + rtld_is_main = true; + ++ char *argv0 = NULL; ++ + /* Note the place where the dynamic linker actually came from. */ + GL(dl_rtld_map).l_name = rtld_progname; + +@@ -1253,6 +1255,14 @@ dl_main (const ElfW(Phdr) *phdr, + else if (! strcmp (_dl_argv[1], "--preload") && _dl_argc > 2) + { + preloadarg = _dl_argv[2]; ++ _dl_skip_args += 2; ++ _dl_argc -= 2; ++ _dl_argv += 2; ++ } ++ else if (! strcmp (_dl_argv[1], "--argv0") && _dl_argc > 2) ++ { ++ argv0 = _dl_argv[2]; ++ + _dl_skip_args += 2; + _dl_argc -= 2; + _dl_argv += 2; +@@ -1286,7 +1296,8 @@ of this helper program; chances are you did not intend to run this program.\n\ + --inhibit-rpath LIST ignore RUNPATH and RPATH information in object names\n\ + in LIST\n\ + --audit LIST use objects named in LIST as auditors\n\ +- --preload LIST preload objects named in LIST\n"); ++ --preload LIST preload objects named in LIST\n\ ++ --argv0 STRING set argv[0] to STRING before running\n"); + + ++_dl_skip_args; + --_dl_argc; +@@ -1378,6 +1389,10 @@ of this helper program; chances are you did not intend to run this program.\n\ + break; + } + #endif ++ ++ /* Set the argv[0] string now that we've processed the executable. */ ++ if (argv0 != NULL) ++ _dl_argv[0] = argv0; + } + else + { +diff --git a/elf/tst-rtld-argv0.sh b/elf/tst-rtld-argv0.sh +new file mode 100755 +index 0000000000000000..14d97fb375fc652b +--- /dev/null ++++ b/elf/tst-rtld-argv0.sh +@@ -0,0 +1,37 @@ ++#!/bin/sh ++# Test for --argv0 option ld.so. ++# 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 ++# . ++ ++set -e ++ ++rtld=$1 ++test_program=$2 ++test_wrapper_env=$3 ++run_program_env=$4 ++library_path=$5 ++argv0=$6 ++ ++echo "# [${test_wrapper_env}] [${run_program_env}] [$rtld] [--library-path]" \ ++ "[$library_path] [--argv0] [$argv0] [$test_program]" ++${test_wrapper_env} \ ++${run_program_env} \ ++$rtld --library-path "$library_path" \ ++ --argv0 "$argv0" $test_program 2>&1 && rc=0 || rc=$? ++echo "# exit status $rc" ++ ++exit $rc diff --git a/SOURCES/glibc-rh1817513-87.patch b/SOURCES/glibc-rh1817513-87.patch new file mode 100644 index 0000000..b3c202c --- /dev/null +++ b/SOURCES/glibc-rh1817513-87.patch @@ -0,0 +1,97 @@ +commit 56f8d442942ee51824b4683be83f776a811a3f2a +Author: Florian Weimer +Date: Wed Oct 7 16:40:23 2020 +0200 + + elf: Do not search HWCAP subdirectories in statically linked binaries + + This functionality does not seem to be useful since static dlopen + is mostly used for iconv/character set conversion and NSS support. + gconv modules are loaded with full paths anyway, so that the + HWCAP subdirectory logic does not apply. + + Reviewed-by: Adhemerval Zanella + +diff --git a/elf/Makefile b/elf/Makefile +index 837a070c267527e1..ef655630d50b07aa 100644 +--- a/elf/Makefile ++++ b/elf/Makefile +@@ -29,7 +29,7 @@ routines = $(all-dl-routines) dl-support dl-iteratephdr \ + + # The core dynamic linking functions are in libc for the static and + # profiled libraries. +-dl-routines = $(addprefix dl-,load lookup object reloc deps hwcaps \ ++dl-routines = $(addprefix dl-,load lookup object reloc deps \ + runtime init fini debug misc \ + version profile tls origin scope \ + execstack open close trampoline \ +@@ -59,7 +59,7 @@ elide-routines.os = $(all-dl-routines) dl-support enbl-secure dl-origin \ + # 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-error-minimal dl-conflict dl-hwcaps + all-rtld-routines = $(rtld-routines) $(sysdep-rtld-routines) + + CFLAGS-dl-runtime.c += -fexceptions -fasynchronous-unwind-tables +diff --git a/elf/dl-load.c b/elf/dl-load.c +index 64da5323d0e368c1..2b4dd9a0f3e27b70 100644 +--- a/elf/dl-load.c ++++ b/elf/dl-load.c +@@ -101,9 +101,13 @@ int __stack_prot attribute_hidden attribute_relro + static struct r_search_path_struct env_path_list attribute_relro; + + /* List of the hardware capabilities we might end up using. */ ++#ifdef SHARED + static const struct r_strlenpair *capstr attribute_relro; + static size_t ncapstr attribute_relro; + static size_t max_capstrlen attribute_relro; ++#else ++enum { ncapstr = 1, max_capstrlen = 0 }; ++#endif + + + /* Get the generated information about the trusted directories. Use +@@ -691,9 +695,11 @@ _dl_init_paths (const char *llp) + /* Fill in the information about the application's RPATH and the + directories addressed by the LD_LIBRARY_PATH environment variable. */ + ++#ifdef SHARED + /* Get the capabilities. */ + capstr = _dl_important_hwcaps (GLRO(dl_platform), GLRO(dl_platformlen), + &ncapstr, &max_capstrlen); ++#endif + + /* First set up the rest of the default search directory entries. */ + aelem = rtld_search_dirs.dirs = (struct r_search_path_elem **) +@@ -1459,11 +1465,15 @@ print_search_path (struct r_search_path_elem **list, + for (cnt = 0; cnt < ncapstr; ++cnt) + if ((*list)->status[cnt] != nonexisting) + { ++#ifdef SHARED + char *cp = __mempcpy (endp, capstr[cnt].str, capstr[cnt].len); + if (cp == buf || (cp == buf + 1 && buf[0] == '/')) + cp[0] = '\0'; + else + cp[-1] = '\0'; ++#else ++ *endp = '\0'; ++#endif + + _dl_debug_printf_c (first ? "%s" : ":%s", buf); + first = 0; +@@ -1836,11 +1846,15 @@ open_path (const char *name, size_t namelen, int mode, + if (this_dir->status[cnt] == nonexisting) + continue; + ++#ifdef SHARED + buflen = + ((char *) __mempcpy (__mempcpy (edp, capstr[cnt].str, + capstr[cnt].len), + name, namelen) + - buf); ++#else ++ buflen = (char *) __mempcpy (edp, name, namelen) - buf; ++#endif + + /* Print name we try if this is wanted. */ + if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_LIBS)) diff --git a/SOURCES/glibc-rh1817513-88.patch b/SOURCES/glibc-rh1817513-88.patch new file mode 100644 index 0000000..6100353 --- /dev/null +++ b/SOURCES/glibc-rh1817513-88.patch @@ -0,0 +1,144 @@ +commit b31d4355ae817aa3caf9414f842cc07465bca028 +Author: Florian Weimer +Date: Wed Oct 7 16:39:50 2020 +0200 + + elf: Implement _dl_write + + The generic version is parallel to _dl_writev. It cannot use + _dl_writev directly because the errno value needs to be obtained + under a lock. + + Reviewed-by: Adhemerval Zanella + +Backport adjusted for different INTERNAL_SYSCALL_CALL definition +downstream. + +diff --git a/elf/Makefile b/elf/Makefile +index ef655630d50b07aa..e2078f6bc325b7e0 100644 +--- a/elf/Makefile ++++ b/elf/Makefile +@@ -34,7 +34,7 @@ dl-routines = $(addprefix dl-,load lookup object reloc deps \ + version profile tls origin scope \ + execstack open close trampoline \ + exception sort-maps lookup-direct \ +- call-libc-early-init) ++ call-libc-early-init write) + ifeq (yes,$(use-ldconfig)) + dl-routines += dl-cache + endif +diff --git a/elf/dl-write.c b/elf/dl-write.c +new file mode 100644 +index 0000000000000000..7350aff0035d4fbc +--- /dev/null ++++ b/elf/dl-write.c +@@ -0,0 +1,56 @@ ++/* Implementation of the _dl_write function. 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, see ++ . */ ++ ++#include ++#include ++#include ++#include ++ ++ssize_t ++_dl_write (int fd, const void *buffer, size_t length) ++{ ++ struct iovec iov = { .iov_base = (void *) buffer, .iov_len = length }; ++ ssize_t ret; ++ ++#if RTLD_PRIVATE_ERRNO ++ /* We have to take this lock just to be sure we don't clobber the private ++ errno when it's being used by another thread that cares about it. ++ Yet we must be sure not to try calling the lock functions before ++ the thread library is fully initialized. */ ++ if (__glibc_unlikely (_dl_starting_up)) ++ { ++ ret = __writev (fd, &iov, 1); ++ if (ret < 0) ++ ret = -errno; ++ } ++ else ++ { ++ __rtld_lock_lock_recursive (GL(dl_load_lock)); ++ __writev (fd, &iov, 1); ++ if (ret < 0) ++ ret = -errno; ++ __rtld_lock_unlock_recursive (GL(dl_load_lock)); ++ } ++#else ++ ret = __writev (fd, &iov, 1); ++ if (ret < 0) ++ ret = -errno; ++#endif ++ ++ return ret; ++} +diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h +index 37f1915b0c75a020..4aa28b0229e0b339 100644 +--- a/sysdeps/generic/ldsodefs.h ++++ b/sysdeps/generic/ldsodefs.h +@@ -754,6 +754,12 @@ _dl_dprintf (int fd, const char *fmt, ...) + } + #endif + ++/* Write LENGTH bytes at BUFFER to FD, like write. Returns the number ++ of bytes written on success, or a negative error constant on ++ failure. */ ++ssize_t _dl_write (int fd, const void *buffer, size_t length) ++ attribute_hidden; ++ + /* Write a message on the specified descriptor standard output. The + parameters are interpreted as for a `printf' call. */ + #define _dl_printf(fmt, args...) \ +diff --git a/sysdeps/unix/sysv/linux/dl-write.c b/sysdeps/unix/sysv/linux/dl-write.c +new file mode 100644 +index 0000000000000000..2c670a8059077076 +--- /dev/null ++++ b/sysdeps/unix/sysv/linux/dl-write.c +@@ -0,0 +1,31 @@ ++/* Implementation of the _dl_write function. Linux 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, see ++ . */ ++ ++#include ++#include ++#include ++ ++ssize_t ++_dl_write (int fd, const void *buffer, size_t length) ++{ ++ INTERNAL_SYSCALL_DECL (err); ++ long int r = INTERNAL_SYSCALL_CALL (write, err, fd, buffer, length); ++ if (INTERNAL_SYSCALL_ERROR_P (r, err)) ++ r = - INTERNAL_SYSCALL_ERRNO (r, err); ++ return r; ++} diff --git a/SOURCES/glibc-rh1817513-89.patch b/SOURCES/glibc-rh1817513-89.patch new file mode 100644 index 0000000..64a511e --- /dev/null +++ b/SOURCES/glibc-rh1817513-89.patch @@ -0,0 +1,46 @@ +commit 72d36ffd7db55ae599f4c77feb0eae25a0f3714e +Author: Florian Weimer +Date: Thu Oct 8 10:57:09 2020 +0200 + + elf: Implement __rtld_malloc_is_complete + + In some cases, it is difficult to determine the kind of malloc + based on the execution context, so a function to determine that + is helpful. + + Reviewed-by: Adhemerval Zanella + +diff --git a/elf/dl-minimal.c b/elf/dl-minimal.c +index 4335f1bd24289b01..cf7df8a8d5eabe9d 100644 +--- a/elf/dl-minimal.c ++++ b/elf/dl-minimal.c +@@ -59,6 +59,14 @@ __rtld_malloc_init_stubs (void) + __rtld_realloc = &rtld_realloc; + } + ++bool ++__rtld_malloc_is_complete (void) ++{ ++ /* The caller assumes that there is an active malloc. */ ++ assert (__rtld_malloc != NULL); ++ return __rtld_malloc != &rtld_malloc; ++} ++ + /* Lookup NAME at VERSION in the scope of MATCH. */ + static void * + lookup_malloc_symbol (struct link_map *main_map, const char *name, +diff --git a/include/rtld-malloc.h b/include/rtld-malloc.h +index b026a3270cd24819..9266ec532f3f3376 100644 +--- a/include/rtld-malloc.h ++++ b/include/rtld-malloc.h +@@ -66,6 +66,10 @@ realloc (void *ptr, size_t size) + implementation. */ + void __rtld_malloc_init_stubs (void) attribute_hidden; + ++/* Return false if the active malloc is the ld.so minimal malloc, true ++ if it is the full implementation from libc.so. */ ++_Bool __rtld_malloc_is_complete (void) attribute_hidden; ++ + /* Called shortly before the final self-relocation (when RELRO + variables are still writable) to activate the real malloc + implementation. MAIN_MAP is the link map of the executable. */ diff --git a/SOURCES/glibc-rh1817513-9.patch b/SOURCES/glibc-rh1817513-9.patch new file mode 100644 index 0000000..06b352b --- /dev/null +++ b/SOURCES/glibc-rh1817513-9.patch @@ -0,0 +1,247 @@ +commit 72771e53753647111d31c5c4bf43d8901e6baf7e +Author: H.J. Lu +Date: Wed Oct 17 15:16:38 2018 -0700 + + x86: Use _rdtsc intrinsic for HP_TIMING_NOW + + Since _rdtsc intrinsic is supported in GCC 4.9, we can use it for + HP_TIMING_NOW. This patch + + 1. Create x86 hp-timing.h to replace i686 and x86_64 hp-timing.h. + 2. Move MINIMUM_ISA from init-arch.h to isa.h so that x86 hp-timing.h + can check minimum x86 ISA to decide if _rdtsc can be used. + + NB: Checking if __i686__ isn't sufficient since __i686__ may not be + defined when building for i686 class processors. + + * sysdeps/i386/init-arch.h: Removed. + * sysdeps/i386/i586/init-arch.h: Likewise. + * sysdeps/i386/i686/init-arch.h: Likewise. + * sysdeps/i386/i686/hp-timing.h: Likewise. + * sysdeps/x86_64/hp-timing.h: Likewise. + * sysdeps/i386/isa.h: New file. + * sysdeps/i386/i586/isa.h: Likewise. + * sysdeps/i386/i686/isa.h: Likewise. + * sysdeps/x86_64/isa.h: Likewise. + * sysdeps/x86/hp-timing.h: New file. + * sysdeps/x86/init-arch.h: Include . + +diff --git a/sysdeps/i386/i586/init-arch.h b/sysdeps/i386/i586/isa.h +similarity index 85% +rename from sysdeps/i386/i586/init-arch.h +rename to sysdeps/i386/i586/isa.h +index 72fb46c61e4c5f34..79481ce68033e58c 100644 +--- a/sysdeps/i386/i586/init-arch.h ++++ b/sysdeps/i386/i586/isa.h +@@ -1,4 +1,5 @@ +-/* Copyright (C) 2015-2018 Free Software Foundation, Inc. ++/* x86 ISA info. i586 version. ++ 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 +@@ -15,5 +16,9 @@ + License along with the GNU C Library; if not, see + . */ + ++#ifndef _ISA_H ++#define _ISA_H ++ + #define MINIMUM_ISA 586 +-#include ++ ++#endif +diff --git a/sysdeps/i386/i686/init-arch.h b/sysdeps/i386/i686/isa.h +similarity index 85% +rename from sysdeps/i386/i686/init-arch.h +rename to sysdeps/i386/i686/isa.h +index ab99392b586b1e2d..584e26bd4f928021 100644 +--- a/sysdeps/i386/i686/init-arch.h ++++ b/sysdeps/i386/i686/isa.h +@@ -1,4 +1,5 @@ +-/* Copyright (C) 2015-2018 Free Software Foundation, Inc. ++/* x86 ISA info. i686 version. ++ 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 +@@ -15,5 +16,9 @@ + License along with the GNU C Library; if not, see + . */ + ++#ifndef _ISA_H ++#define _ISA_H ++ + #define MINIMUM_ISA 686 +-#include ++ ++#endif +diff --git a/sysdeps/i386/init-arch.h b/sysdeps/i386/isa.h +similarity index 85% +rename from sysdeps/i386/init-arch.h +rename to sysdeps/i386/isa.h +index 043089ceb99db33f..e0a1e9c84fd37efb 100644 +--- a/sysdeps/i386/init-arch.h ++++ b/sysdeps/i386/isa.h +@@ -1,4 +1,5 @@ +-/* Copyright (C) 2015-2018 Free Software Foundation, Inc. ++/* x86 ISA info. i486 version. ++ 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 +@@ -15,5 +16,9 @@ + License along with the GNU C Library; if not, see + . */ + ++#ifndef _ISA_H ++#define _ISA_H ++ + #define MINIMUM_ISA 486 +-#include ++ ++#endif +diff --git a/sysdeps/i386/i686/hp-timing.h b/sysdeps/x86/hp-timing.h +similarity index 69% +rename from sysdeps/i386/i686/hp-timing.h +rename to sysdeps/x86/hp-timing.h +index 59af526fdba0b6f5..1c20e9d8289cc15b 100644 +--- a/sysdeps/i386/i686/hp-timing.h ++++ b/sysdeps/x86/hp-timing.h +@@ -1,7 +1,6 @@ +-/* High precision, low overhead timing functions. i686 version. +- Copyright (C) 1998-2018 Free Software Foundation, Inc. ++/* High precision, low overhead timing functions. x86 version. ++ Copyright (C) 2018 Free Software Foundation, Inc. + This file is part of the GNU C Library. +- Contributed by Ulrich Drepper , 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 +@@ -20,12 +19,17 @@ + #ifndef _HP_TIMING_H + #define _HP_TIMING_H 1 + ++#include ++ ++#if MINIMUM_ISA == 686 || MINIMUM_ISA == 8664 ++# include ++ + /* We always assume having the timestamp register. */ +-#define HP_TIMING_AVAIL (1) +-#define HP_SMALL_TIMING_AVAIL (1) ++# define HP_TIMING_AVAIL (1) ++# define HP_SMALL_TIMING_AVAIL (1) + + /* We indeed have inlined functions. */ +-#define HP_TIMING_INLINE (1) ++# define HP_TIMING_INLINE (1) + + /* We use 64bit values for the times. */ + typedef unsigned long long int hp_timing_t; +@@ -35,8 +39,14 @@ typedef unsigned long long int hp_timing_t; + running in this moment. This could be changed by using a barrier like + 'cpuid' right before the `rdtsc' instruciton. But we are not interested + in accurate clock cycles here so we don't do this. */ +-#define HP_TIMING_NOW(Var) __asm__ __volatile__ ("rdtsc" : "=A" (Var)) ++# define HP_TIMING_NOW(Var) ((Var) = _rdtsc ()) + +-#include ++# include ++#else ++/* NB: Undefine _HP_TIMING_H so that will ++ be included. */ ++# undef _HP_TIMING_H ++# include ++#endif + +-#endif /* hp-timing.h */ ++#endif /* hp-timing.h */ +diff --git a/sysdeps/x86/init-arch.h b/sysdeps/x86/init-arch.h +index a81ca8a4eb292e72..bc860fcd69a605b3 100644 +--- a/sysdeps/x86/init-arch.h ++++ b/sysdeps/x86/init-arch.h +@@ -21,6 +21,7 @@ + # include + #endif + #include ++#include + + #ifndef __x86_64__ + /* Due to the reordering and the other nifty extensions in i686, it is +diff --git a/sysdeps/x86_64/hp-timing.h b/sysdeps/x86_64/hp-timing.h +deleted file mode 100644 +index ec543bef03b6c2d1..0000000000000000 +--- a/sysdeps/x86_64/hp-timing.h ++++ /dev/null +@@ -1,40 +0,0 @@ +-/* 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; +- +-/* The "=A" constraint used in 32-bit mode does not work in 64-bit mode. */ +-#define HP_TIMING_NOW(Var) \ +- ({ unsigned int _hi, _lo; \ +- asm volatile ("rdtsc" : "=a" (_lo), "=d" (_hi)); \ +- (Var) = ((unsigned long long int) _hi << 32) | _lo; }) +- +-#include +- +-#endif /* hp-timing.h */ +diff --git a/sysdeps/x86_64/isa.h b/sysdeps/x86_64/isa.h +new file mode 100644 +index 0000000000000000..452bce75eb03a474 +--- /dev/null ++++ b/sysdeps/x86_64/isa.h +@@ -0,0 +1,24 @@ ++/* x86 ISA info. x86-64 version. ++ 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 _ISA_H ++#define _ISA_H ++ ++#define MINIMUM_ISA 8664 ++ ++#endif diff --git a/SOURCES/glibc-rh1817513-90.patch b/SOURCES/glibc-rh1817513-90.patch new file mode 100644 index 0000000..344808e --- /dev/null +++ b/SOURCES/glibc-rh1817513-90.patch @@ -0,0 +1,568 @@ +commit 2bf9e641fd50ec34b04b70829679abf64fc0ed78 +Author: Florian Weimer +Date: Thu Oct 8 10:57:09 2020 +0200 + + elf: Extract command-line/environment variables state from rtld.c + + Introduce struct dl_main_state and move it to . Rename + enum mode to enum rtld_mode and add the rtld_mode_ prefix to the enum + constants. + + This avoids the need for putting state that is only needed during + startup into the ld.so data segment. + +Conflicts: + elf/rtld.c + (Caused by glibc-fedora-__libc_multiple_libcs.patch.) + +diff --git a/elf/dl-main.h b/elf/dl-main.h +new file mode 100644 +index 0000000000000000..bcc9bcf2e8fee6e7 +--- /dev/null ++++ b/elf/dl-main.h +@@ -0,0 +1,98 @@ ++/* Information collection during ld.so startup. ++ Copyright (C) 1995-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 ++ . */ ++ ++#ifndef _DL_MAIN ++#define _DL_MAIN ++ ++#include ++ ++/* Length limits for names and paths, to protect the dynamic linker, ++ particularly when __libc_enable_secure is active. */ ++#ifdef NAME_MAX ++# define SECURE_NAME_LIMIT NAME_MAX ++#else ++# define SECURE_NAME_LIMIT 255 ++#endif ++#ifdef PATH_MAX ++# define SECURE_PATH_LIMIT PATH_MAX ++#else ++# define SECURE_PATH_LIMIT 1024 ++#endif ++ ++/* Strings containing colon-separated lists of audit modules. */ ++struct audit_list ++{ ++ /* Array of strings containing colon-separated path lists. Each ++ audit module needs its own namespace, so pre-allocate the largest ++ possible list. */ ++ const char *audit_strings[DL_NNS]; ++ ++ /* Number of entries added to audit_strings. */ ++ size_t length; ++ ++ /* Index into the audit_strings array (for the iteration phase). */ ++ size_t current_index; ++ ++ /* Tail of audit_strings[current_index] which still needs ++ processing. */ ++ const char *current_tail; ++ ++ /* Scratch buffer for returning a name which is part of the strings ++ in audit_strings. */ ++ char fname[SECURE_NAME_LIMIT]; ++}; ++ ++/* This is a list of all the modes the dynamic loader can be in. */ ++enum rtld_mode ++ { ++ rtld_mode_normal, rtld_mode_list, rtld_mode_verify, rtld_mode_trace, ++ }; ++ ++/* Aggregated state information extracted from environment variables ++ and the ld.so command line. */ ++struct dl_main_state ++{ ++ struct audit_list audit_list; ++ ++ /* The library search path. */ ++ const char *library_path; ++ ++ /* The list preloaded objects from LD_PRELOAD. */ ++ const char *preloadlist; ++ ++ /* The preload list passed as a command argument. */ ++ const char *preloadarg; ++ ++ enum rtld_mode mode; ++ ++ /* True if any of the debugging options is enabled. */ ++ bool any_debug; ++ ++ /* True if information about versions has to be printed. */ ++ bool version_info; ++}; ++ ++/* Helper function to invoke _dl_init_paths with the right arguments ++ from *STATE. */ ++static inline void ++call_init_paths (const struct dl_main_state *state) ++{ ++ _dl_init_paths (state->library_path); ++} ++ ++#endif /* _DL_MAIN */ +diff --git a/elf/rtld.c b/elf/rtld.c +index 4107a215abd554f4..fbfa441bf3b050ff 100644 +--- a/elf/rtld.c ++++ b/elf/rtld.c +@@ -45,6 +45,7 @@ + #include + #include + #include ++#include + + #include + +@@ -109,42 +110,6 @@ static void print_missing_version (int errcode, const char *objname, + /* Print the various times we collected. */ + static void print_statistics (const hp_timing_t *total_timep); + +-/* Length limits for names and paths, to protect the dynamic linker, +- particularly when __libc_enable_secure is active. */ +-#ifdef NAME_MAX +-# define SECURE_NAME_LIMIT NAME_MAX +-#else +-# define SECURE_NAME_LIMIT 255 +-#endif +-#ifdef PATH_MAX +-# define SECURE_PATH_LIMIT PATH_MAX +-#else +-# define SECURE_PATH_LIMIT 1024 +-#endif +- +-/* Strings containing colon-separated lists of audit modules. */ +-struct audit_list +-{ +- /* Array of strings containing colon-separated path lists. Each +- audit module needs its own namespace, so pre-allocate the largest +- possible list. */ +- const char *audit_strings[DL_NNS]; +- +- /* Number of entries added to audit_strings. */ +- size_t length; +- +- /* Index into the audit_strings array (for the iteration phase). */ +- size_t current_index; +- +- /* Tail of audit_strings[current_index] which still needs +- processing. */ +- const char *current_tail; +- +- /* Scratch buffer for returning a name which is part of the strings +- in audit_strings. */ +- char fname[SECURE_NAME_LIMIT]; +-}; +- + /* Creates an empty audit list. */ + static void audit_list_init (struct audit_list *); + +@@ -165,13 +130,13 @@ static void audit_list_add_dynamic_tag (struct audit_list *, + audit_list_add_dynamic_tags calls. */ + static const char *audit_list_next (struct audit_list *); + +-/* This is a list of all the modes the dynamic loader can be in. */ +-enum mode { normal, list, verify, trace }; ++/* Initialize *STATE with the defaults. */ ++static void dl_main_state_init (struct dl_main_state *state); + + /* Process all environments variables the dynamic linker must recognize. + Since all of them start with `LD_' we are a bit smarter while finding + all the entries. */ +-static void process_envvars (enum mode *modep, struct audit_list *); ++static void process_envvars (struct dl_main_state *state); + + #ifdef DL_ARGV_NOT_RELRO + int _dl_argc attribute_hidden; +@@ -314,6 +279,18 @@ audit_list_count (struct audit_list *list) + return naudit; + } + ++static void ++dl_main_state_init (struct dl_main_state *state) ++{ ++ audit_list_init (&state->audit_list); ++ state->library_path = NULL; ++ state->preloadlist = NULL; ++ state->preloadarg = NULL; ++ state->mode = rtld_mode_normal; ++ state->any_debug = false; ++ state->version_info = false; ++} ++ + /* Set nonzero during loading and initialization of executable and + libraries, cleared before the executable's entry point runs. This + must not be initialized to nonzero, because the unused dynamic +@@ -896,15 +873,6 @@ security_init (void) + + #include "setup-vdso.h" + +-/* The library search path. */ +-static const char *library_path attribute_relro; +-/* The list preloaded objects. */ +-static const char *preloadlist attribute_relro; +-/* Nonzero if information about versions has to be printed. */ +-static int version_info attribute_relro; +-/* The preload list passed as a command argument. */ +-static const char *preloadarg attribute_relro; +- + /* The LD_PRELOAD environment variable gives list of libraries + separated by white space or colons that are loaded before the + executable's dependencies and prepended to the global scope list. +@@ -1146,7 +1114,6 @@ dl_main (const ElfW(Phdr) *phdr, + ElfW(auxv_t) *auxv) + { + const ElfW(Phdr) *ph; +- enum mode mode; + struct link_map *main_map; + size_t file_size; + char *file; +@@ -1156,8 +1123,8 @@ dl_main (const ElfW(Phdr) *phdr, + bool rtld_is_main = false; + void *tcbp = NULL; + +- struct audit_list audit_list; +- audit_list_init (&audit_list); ++ struct dl_main_state state; ++ dl_main_state_init (&state); + + GL(dl_init_static_tls) = &_dl_nothread_init_static_tls; + +@@ -1172,7 +1139,7 @@ dl_main (const ElfW(Phdr) *phdr, + GL(dl_make_stack_executable_hook) = &_dl_make_stack_executable; + + /* Process the environment variable which control the behaviour. */ +- process_envvars (&mode, &audit_list); ++ process_envvars (&state); + + /* Set up a flag which tells we are just starting. */ + _dl_starting_up = 1; +@@ -1204,7 +1171,7 @@ dl_main (const ElfW(Phdr) *phdr, + while (_dl_argc > 1) + if (! strcmp (_dl_argv[1], "--list")) + { +- mode = list; ++ state.mode = rtld_mode_list; + GLRO(dl_lazy) = -1; /* This means do no dependency analysis. */ + + ++_dl_skip_args; +@@ -1213,7 +1180,7 @@ dl_main (const ElfW(Phdr) *phdr, + } + else if (! strcmp (_dl_argv[1], "--verify")) + { +- mode = verify; ++ state.mode = rtld_mode_verify; + + ++_dl_skip_args; + --_dl_argc; +@@ -1229,7 +1196,7 @@ dl_main (const ElfW(Phdr) *phdr, + else if (! strcmp (_dl_argv[1], "--library-path") + && _dl_argc > 2) + { +- library_path = _dl_argv[2]; ++ state.library_path = _dl_argv[2]; + + _dl_skip_args += 2; + _dl_argc -= 2; +@@ -1246,7 +1213,7 @@ dl_main (const ElfW(Phdr) *phdr, + } + else if (! strcmp (_dl_argv[1], "--audit") && _dl_argc > 2) + { +- audit_list_add_string (&audit_list, _dl_argv[2]); ++ audit_list_add_string (&state.audit_list, _dl_argv[2]); + + _dl_skip_args += 2; + _dl_argc -= 2; +@@ -1254,7 +1221,7 @@ dl_main (const ElfW(Phdr) *phdr, + } + else if (! strcmp (_dl_argv[1], "--preload") && _dl_argc > 2) + { +- preloadarg = _dl_argv[2]; ++ state.preloadarg = _dl_argv[2]; + _dl_skip_args += 2; + _dl_argc -= 2; + _dl_argv += 2; +@@ -1322,7 +1289,7 @@ of this helper program; chances are you did not intend to run this program.\n\ + break; + } + +- if (__builtin_expect (mode, normal) == verify) ++ if (__glibc_unlikely (state.mode == rtld_mode_verify)) + { + const char *objname; + const char *err_str = NULL; +@@ -1351,7 +1318,7 @@ of this helper program; chances are you did not intend to run this program.\n\ + /* Now the map for the main executable is available. */ + main_map = GL(dl_ns)[LM_ID_BASE]._ns_loaded; + +- if (__builtin_expect (mode, normal) == normal ++ if (__glibc_likely (state.mode == rtld_mode_normal) + && GL(dl_rtld_map).l_info[DT_SONAME] != NULL + && main_map->l_info[DT_SONAME] != NULL + && strcmp ((const char *) D_PTR (&GL(dl_rtld_map), l_info[DT_STRTAB]) +@@ -1592,7 +1559,7 @@ ERROR: '%s': cannot process note segment.\n", _dl_argv[0]); + _dl_setup_hash (main_map); + } + +- if (__builtin_expect (mode, normal) == verify) ++ if (__glibc_unlikely (state.mode == rtld_mode_verify)) + { + /* We were called just to verify that this is a dynamic + executable using us as the program interpreter. Exit with an +@@ -1619,7 +1586,7 @@ ERROR: '%s': cannot process note segment.\n", _dl_argv[0]); + + /* Initialize the data structures for the search paths for shared + objects. */ +- _dl_init_paths (library_path); ++ call_init_paths (&state); + + /* Initialize _r_debug. */ + struct r_debug *r = _dl_debug_initialize (GL(dl_rtld_map).l_addr, +@@ -1684,14 +1651,14 @@ ERROR: '%s': cannot process note segment.\n", _dl_argv[0]); + /* Assign a module ID. Do this before loading any audit modules. */ + GL(dl_rtld_map).l_tls_modid = _dl_next_tls_modid (); + +- audit_list_add_dynamic_tag (&audit_list, main_map, DT_AUDIT); +- audit_list_add_dynamic_tag (&audit_list, main_map, DT_DEPAUDIT); ++ audit_list_add_dynamic_tag (&state.audit_list, main_map, DT_AUDIT); ++ audit_list_add_dynamic_tag (&state.audit_list, main_map, DT_DEPAUDIT); + + /* If we have auditing DSOs to load, do it now. */ + bool need_security_init = true; +- if (audit_list.length > 0) ++ if (state.audit_list.length > 0) + { +- size_t naudit = audit_list_count (&audit_list); ++ size_t naudit = audit_list_count (&state.audit_list); + + /* Since we start using the auditing DSOs right away we need to + initialize the data structures now. */ +@@ -1704,7 +1671,7 @@ ERROR: '%s': cannot process note segment.\n", _dl_argv[0]); + security_init (); + need_security_init = false; + +- load_audit_modules (main_map, &audit_list); ++ load_audit_modules (main_map, &state.audit_list); + + /* The count based on audit strings may overestimate the number + of audit modules that got loaded, but not underestimate. */ +@@ -1759,19 +1726,21 @@ ERROR: '%s': cannot process note segment.\n", _dl_argv[0]); + struct link_map **preloads = NULL; + unsigned int npreloads = 0; + +- if (__glibc_unlikely (preloadlist != NULL)) ++ if (__glibc_unlikely (state.preloadlist != NULL)) + { + RTLD_TIMING_VAR (start); + rtld_timer_start (&start); +- npreloads += handle_preload_list (preloadlist, main_map, "LD_PRELOAD"); ++ npreloads += handle_preload_list (state.preloadlist, main_map, ++ "LD_PRELOAD"); + rtld_timer_accum (&load_time, start); + } + +- if (__glibc_unlikely (preloadarg != NULL)) ++ if (__glibc_unlikely (state.preloadarg != NULL)) + { + RTLD_TIMING_VAR (start); + rtld_timer_start (&start); +- npreloads += handle_preload_list (preloadarg, main_map, "--preload"); ++ npreloads += handle_preload_list (state.preloadarg, main_map, ++ "--preload"); + rtld_timer_accum (&load_time, start); + } + +@@ -1878,7 +1847,8 @@ ERROR: '%s': cannot process note segment.\n", _dl_argv[0]); + { + RTLD_TIMING_VAR (start); + rtld_timer_start (&start); +- _dl_map_object_deps (main_map, preloads, npreloads, mode == trace, 0); ++ _dl_map_object_deps (main_map, preloads, npreloads, ++ state.mode == rtld_mode_trace, 0); + rtld_timer_accum (&load_time, start); + } + +@@ -1905,7 +1875,7 @@ ERROR: '%s': cannot process note segment.\n", _dl_argv[0]); + rtld_multiple_ref = true; + + GL(dl_rtld_map).l_prev = main_map->l_searchlist.r_list[i - 1]; +- if (__builtin_expect (mode, normal) == normal) ++ if (__glibc_likely (state.mode == rtld_mode_normal)) + { + GL(dl_rtld_map).l_next = (i + 1 < main_map->l_searchlist.r_nlist + ? main_map->l_searchlist.r_list[i + 1] +@@ -1938,8 +1908,8 @@ ERROR: '%s': cannot process note segment.\n", _dl_argv[0]); + versions we need. */ + { + struct version_check_args args; +- args.doexit = mode == normal; +- args.dotrace = mode == trace; ++ args.doexit = state.mode == rtld_mode_normal; ++ args.dotrace = state.mode == rtld_mode_trace; + _dl_receive_error (print_missing_version, version_check_doit, &args); + } + +@@ -1959,7 +1929,7 @@ ERROR: '%s': cannot process note segment.\n", _dl_argv[0]); + earlier. */ + security_init (); + +- if (__builtin_expect (mode, normal) != normal) ++ if (__glibc_unlikely (state.mode != rtld_mode_normal)) + { + /* We were run just to list the shared libraries. It is + important that we do this before real relocation, because the +@@ -2061,7 +2031,7 @@ ERROR: '%s': cannot process note segment.\n", _dl_argv[0]); + (size_t) l->l_map_start); + } + +- if (__builtin_expect (mode, trace) != trace) ++ if (__glibc_unlikely (state.mode != rtld_mode_trace)) + for (i = 1; i < (unsigned int) _dl_argc; ++i) + { + const ElfW(Sym) *ref = NULL; +@@ -2115,7 +2085,7 @@ ERROR: '%s': cannot process note segment.\n", _dl_argv[0]); + } + } + #define VERNEEDTAG (DT_NUM + DT_THISPROCNUM + DT_VERSIONTAGIDX (DT_VERNEED)) +- if (version_info) ++ if (state.version_info) + { + /* Print more information. This means here, print information + about the versions needed. */ +@@ -2477,13 +2447,10 @@ print_missing_version (int errcode __attribute__ ((unused)), + objname, errstring); + } + +-/* Nonzero if any of the debugging options is enabled. */ +-static int any_debug attribute_relro; +- + /* Process the string given as the parameter which explains which debugging + options are enabled. */ + static void +-process_dl_debug (const char *dl_debug) ++process_dl_debug (struct dl_main_state *state, const char *dl_debug) + { + /* When adding new entries make sure that the maximal length of a name + is correctly handled in the LD_DEBUG_HELP code below. */ +@@ -2540,7 +2507,7 @@ process_dl_debug (const char *dl_debug) + && memcmp (dl_debug, debopts[cnt].name, len) == 0) + { + GLRO(dl_debug_mask) |= debopts[cnt].mask; +- any_debug = 1; ++ state->any_debug = true; + break; + } + +@@ -2594,11 +2561,10 @@ extern char **_environ attribute_hidden; + + + static void +-process_envvars (enum mode *modep, struct audit_list *audit_list) ++process_envvars (struct dl_main_state *state) + { + char **runp = _environ; + char *envline; +- enum mode mode = normal; + char *debug_output = NULL; + + /* This is the default place for profiling data file. */ +@@ -2630,25 +2596,25 @@ process_envvars (enum mode *modep, struct audit_list *audit_list) + /* Debugging of the dynamic linker? */ + if (memcmp (envline, "DEBUG", 5) == 0) + { +- process_dl_debug (&envline[6]); ++ process_dl_debug (state, &envline[6]); + break; + } + if (memcmp (envline, "AUDIT", 5) == 0) +- audit_list_add_string (audit_list, &envline[6]); ++ audit_list_add_string (&state->audit_list, &envline[6]); + break; + + case 7: + /* Print information about versions. */ + if (memcmp (envline, "VERBOSE", 7) == 0) + { +- version_info = envline[8] != '\0'; ++ state->version_info = envline[8] != '\0'; + break; + } + + /* List of objects to be preloaded. */ + if (memcmp (envline, "PRELOAD", 7) == 0) + { +- preloadlist = &envline[8]; ++ state->preloadlist = &envline[8]; + break; + } + +@@ -2697,7 +2663,7 @@ process_envvars (enum mode *modep, struct audit_list *audit_list) + if (!__libc_enable_secure + && memcmp (envline, "LIBRARY_PATH", 12) == 0) + { +- library_path = &envline[13]; ++ state->library_path = &envline[13]; + break; + } + +@@ -2739,7 +2705,7 @@ process_envvars (enum mode *modep, struct audit_list *audit_list) + /* The mode of the dynamic linker can be set. */ + if (memcmp (envline, "TRACE_PRELINKING", 16) == 0) + { +- mode = trace; ++ state->mode = rtld_mode_trace; + GLRO(dl_verbose) = 1; + GLRO(dl_debug_mask) |= DL_DEBUG_PRELINK; + GLRO(dl_trace_prelink) = &envline[17]; +@@ -2749,7 +2715,7 @@ process_envvars (enum mode *modep, struct audit_list *audit_list) + case 20: + /* The mode of the dynamic linker can be set. */ + if (memcmp (envline, "TRACE_LOADED_OBJECTS", 20) == 0) +- mode = trace; ++ state->mode = rtld_mode_trace; + break; + + /* We might have some extra environment variable to handle. This +@@ -2762,9 +2728,6 @@ process_envvars (enum mode *modep, struct audit_list *audit_list) + } + } + +- /* The caller wants this information. */ +- *modep = mode; +- + /* Extra security for SUID binaries. Remove all dangerous environment + variables. */ + if (__builtin_expect (__libc_enable_secure, 0)) +@@ -2793,13 +2756,13 @@ process_envvars (enum mode *modep, struct audit_list *audit_list) + GLRO(dl_debug_mask) = 0; + } + +- if (mode != normal) ++ if (state->mode != rtld_mode_normal) + _exit (5); + } + /* If we have to run the dynamic linker in debugging mode and the + LD_DEBUG_OUTPUT environment variable is given, we write the debug + messages to this file. */ +- else if (any_debug && debug_output != NULL) ++ else if (state->any_debug && debug_output != NULL) + { + const int flags = O_WRONLY | O_APPEND | O_CREAT | O_NOFOLLOW; + size_t name_len = strlen (debug_output); diff --git a/SOURCES/glibc-rh1817513-91.patch b/SOURCES/glibc-rh1817513-91.patch new file mode 100644 index 0000000..00dbfed --- /dev/null +++ b/SOURCES/glibc-rh1817513-91.patch @@ -0,0 +1,161 @@ +commit 9590a71adcf134c77f2d0f5711b0d6ab1b4193e6 +Author: Florian Weimer +Date: Thu Oct 8 10:57:10 2020 +0200 + + elf: Move ld.so error/help output to _dl_usage + + Also add a comment to elf/Makefile, explaining why we cannot use + config.status for autoconf template processing. + + Reviewed-by: Adhemerval Zanella + +diff --git a/elf/Makefile b/elf/Makefile +index e2078f6bc325b7e0..e5666e5bf7817c3c 100644 +--- a/elf/Makefile ++++ b/elf/Makefile +@@ -59,7 +59,7 @@ elide-routines.os = $(all-dl-routines) dl-support enbl-secure dl-origin \ + # 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-error-minimal dl-conflict dl-hwcaps dl-usage + all-rtld-routines = $(rtld-routines) $(sysdep-rtld-routines) + + CFLAGS-dl-runtime.c += -fexceptions -fasynchronous-unwind-tables +@@ -598,6 +598,12 @@ ldso_install: $(inst_rtlddir)/$(rtld-installed-name) + endif + + ++# Workarounds for ${exec_prefix} expansion in configure variables. ++# config.status cannot be used directly for processing ldd.bash.in or ++# expanding variables such as sysconfdir because the expansion ++# contains the literal string ${exec_prefix}, which is not valid in C ++# headers or installed shell scripts. ++ + ldd-rewrite = -e 's%@RTLD@%$(rtlddir)/$(rtld-installed-name)%g' \ + -e 's%@VERSION@%$(version)%g' \ + -e 's|@PKGVERSION@|$(PKGVERSION)|g' \ +@@ -635,6 +641,7 @@ libof-ldconfig = ldconfig + CFLAGS-dl-cache.c += $(SYSCONF-FLAGS) + CFLAGS-cache.c += $(SYSCONF-FLAGS) + CFLAGS-rtld.c += $(SYSCONF-FLAGS) ++CFLAGS-dl-usage.c += $(SYSCONF-FLAGS) + + cpp-srcs-left := $(all-rtld-routines:=.os) + lib := rtld +diff --git a/elf/dl-main.h b/elf/dl-main.h +index bcc9bcf2e8fee6e7..b01f433f9c8d9e1a 100644 +--- a/elf/dl-main.h ++++ b/elf/dl-main.h +@@ -19,7 +19,9 @@ + #ifndef _DL_MAIN + #define _DL_MAIN + ++#include + #include ++#include + + /* Length limits for names and paths, to protect the dynamic linker, + particularly when __libc_enable_secure is active. */ +@@ -95,4 +97,7 @@ call_init_paths (const struct dl_main_state *state) + _dl_init_paths (state->library_path); + } + ++/* Print ld.so usage information and exit. */ ++_Noreturn void _dl_usage (void) attribute_hidden; ++ + #endif /* _DL_MAIN */ +diff --git a/elf/dl-usage.c b/elf/dl-usage.c +new file mode 100644 +index 0000000000000000..f3d89d22b71d7d12 +--- /dev/null ++++ b/elf/dl-usage.c +@@ -0,0 +1,51 @@ ++/* Print usage information and help for ld.so. ++ Copyright (C) 1995-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 ++ ++void ++_dl_usage (void) ++{ ++ _dl_fatal_printf ("\ ++Usage: ld.so [OPTION]... EXECUTABLE-FILE [ARGS-FOR-PROGRAM...]\n\ ++You have invoked `ld.so', the helper program for shared library executables.\n\ ++This program usually lives in the file `/lib/ld.so', and special directives\n\ ++in executable files using ELF shared libraries tell the system's program\n\ ++loader to load the helper program from this file. This helper program loads\n\ ++the shared libraries needed by the program executable, prepares the program\n\ ++to run, and runs it. You may invoke this helper program directly from the\n\ ++command line to load and run an ELF executable file; this is like executing\n\ ++that file itself, but always uses this helper program from the file you\n\ ++specified, instead of the helper program file specified in the executable\n\ ++file you run. This is mostly of use for maintainers to test new versions\n\ ++of this helper program; chances are you did not intend to run this program.\n\ ++\n\ ++ --list list all dependencies and how they are resolved\n\ ++ --verify verify that given object really is a dynamically linked\n\ ++ object we can handle\n\ ++ --inhibit-cache Do not use " LD_SO_CACHE "\n\ ++ --library-path PATH use given PATH instead of content of the environment\n\ ++ variable LD_LIBRARY_PATH\n\ ++ --inhibit-rpath LIST ignore RUNPATH and RPATH information in object names\n\ ++ in LIST\n\ ++ --audit LIST use objects named in LIST as auditors\n\ ++ --preload LIST preload objects named in LIST\n\ ++ --argv0 STRING set argv[0] to STRING before running\n"); ++} +diff --git a/elf/rtld.c b/elf/rtld.c +index fbfa441bf3b050ff..a12a56b550bbc837 100644 +--- a/elf/rtld.c ++++ b/elf/rtld.c +@@ -1240,31 +1240,7 @@ dl_main (const ElfW(Phdr) *phdr, + /* If we have no further argument the program was called incorrectly. + Grant the user some education. */ + if (_dl_argc < 2) +- _dl_fatal_printf ("\ +-Usage: ld.so [OPTION]... EXECUTABLE-FILE [ARGS-FOR-PROGRAM...]\n\ +-You have invoked `ld.so', the helper program for shared library executables.\n\ +-This program usually lives in the file `/lib/ld.so', and special directives\n\ +-in executable files using ELF shared libraries tell the system's program\n\ +-loader to load the helper program from this file. This helper program loads\n\ +-the shared libraries needed by the program executable, prepares the program\n\ +-to run, and runs it. You may invoke this helper program directly from the\n\ +-command line to load and run an ELF executable file; this is like executing\n\ +-that file itself, but always uses this helper program from the file you\n\ +-specified, instead of the helper program file specified in the executable\n\ +-file you run. This is mostly of use for maintainers to test new versions\n\ +-of this helper program; chances are you did not intend to run this program.\n\ +-\n\ +- --list list all dependencies and how they are resolved\n\ +- --verify verify that given object really is a dynamically linked\n\ +- object we can handle\n\ +- --inhibit-cache Do not use " LD_SO_CACHE "\n\ +- --library-path PATH use given PATH instead of content of the environment\n\ +- variable LD_LIBRARY_PATH\n\ +- --inhibit-rpath LIST ignore RUNPATH and RPATH information in object names\n\ +- in LIST\n\ +- --audit LIST use objects named in LIST as auditors\n\ +- --preload LIST preload objects named in LIST\n\ +- --argv0 STRING set argv[0] to STRING before running\n"); ++ _dl_usage (); + + ++_dl_skip_args; + --_dl_argc; diff --git a/SOURCES/glibc-rh1817513-92.patch b/SOURCES/glibc-rh1817513-92.patch new file mode 100644 index 0000000..45c4c95 --- /dev/null +++ b/SOURCES/glibc-rh1817513-92.patch @@ -0,0 +1,113 @@ +commit 27316f4a23efdc90bdfe4569a6c4b7e27941606e +Author: Florian Weimer +Date: Thu Oct 8 10:57:10 2020 +0200 + + elf: Record whether paths come from LD_LIBRARY_PATH or --library-path + + This allows more precise LD_DEBUG diagnostics. + + Reviewed-by: Adhemerval Zanella + +diff --git a/elf/dl-load.c b/elf/dl-load.c +index 2b4dd9a0f3e27b70..1403a2e9c04e9a16 100644 +--- a/elf/dl-load.c ++++ b/elf/dl-load.c +@@ -682,7 +682,7 @@ cache_rpath (struct link_map *l, + + + void +-_dl_init_paths (const char *llp) ++_dl_init_paths (const char *llp, const char *source) + { + size_t idx; + const char *strp; +@@ -820,7 +820,7 @@ _dl_init_paths (const char *llp) + } + + (void) fillin_rpath (llp_tmp, env_path_list.dirs, ":;", +- "LD_LIBRARY_PATH", NULL, l); ++ source, NULL, l); + + if (env_path_list.dirs[0] == NULL) + { +diff --git a/elf/dl-main.h b/elf/dl-main.h +index b01f433f9c8d9e1a..79c9c40056504f80 100644 +--- a/elf/dl-main.h ++++ b/elf/dl-main.h +@@ -74,6 +74,9 @@ struct dl_main_state + /* The library search path. */ + const char *library_path; + ++ /* Where library_path comes from. LD_LIBRARY_PATH or --library-path. */ ++ const char *library_path_source; ++ + /* The list preloaded objects from LD_PRELOAD. */ + const char *preloadlist; + +@@ -94,7 +97,7 @@ struct dl_main_state + static inline void + call_init_paths (const struct dl_main_state *state) + { +- _dl_init_paths (state->library_path); ++ _dl_init_paths (state->library_path, state->library_path_source); + } + + /* Print ld.so usage information and exit. */ +diff --git a/elf/dl-support.c b/elf/dl-support.c +index ef5455b91c17ca30..fb9672367f8d6abd 100644 +--- a/elf/dl-support.c ++++ b/elf/dl-support.c +@@ -315,7 +315,7 @@ _dl_non_dynamic_init (void) + + /* Initialize the data structures for the search paths for shared + objects. */ +- _dl_init_paths (getenv ("LD_LIBRARY_PATH")); ++ _dl_init_paths (getenv ("LD_LIBRARY_PATH"), "LD_LIBRARY_PATH"); + + /* Remember the last search directory added at startup. */ + _dl_init_all_dirs = GL(dl_all_dirs); +diff --git a/elf/rtld.c b/elf/rtld.c +index a12a56b550bbc837..8e91cee41b62b894 100644 +--- a/elf/rtld.c ++++ b/elf/rtld.c +@@ -284,6 +284,7 @@ dl_main_state_init (struct dl_main_state *state) + { + audit_list_init (&state->audit_list); + state->library_path = NULL; ++ state->library_path_source = NULL; + state->preloadlist = NULL; + state->preloadarg = NULL; + state->mode = rtld_mode_normal; +@@ -1197,6 +1198,7 @@ dl_main (const ElfW(Phdr) *phdr, + && _dl_argc > 2) + { + state.library_path = _dl_argv[2]; ++ state.library_path_source = "--library-path"; + + _dl_skip_args += 2; + _dl_argc -= 2; +@@ -2640,6 +2642,7 @@ process_envvars (struct dl_main_state *state) + && memcmp (envline, "LIBRARY_PATH", 12) == 0) + { + state->library_path = &envline[13]; ++ state->library_path_source = "LD_LIBRARY_PATH"; + break; + } + +diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h +index 4aa28b0229e0b339..aa006afafaf46dee 100644 +--- a/sysdeps/generic/ldsodefs.h ++++ b/sysdeps/generic/ldsodefs.h +@@ -1044,8 +1044,10 @@ rtld_hidden_proto (_dl_debug_state) + extern struct r_debug *_dl_debug_initialize (ElfW(Addr) ldbase, Lmid_t ns) + attribute_hidden; + +-/* Initialize the basic data structure for the search paths. */ +-extern void _dl_init_paths (const char *library_path) attribute_hidden; ++/* Initialize the basic data structure for the search paths. SOURCE ++ is either "LD_LIBRARY_PATH" or "--library-path". */ ++extern void _dl_init_paths (const char *library_path, const char *source) ++ attribute_hidden; + + /* Gather the information needed to install the profiling tables and start + the timers. */ diff --git a/SOURCES/glibc-rh1817513-93.patch b/SOURCES/glibc-rh1817513-93.patch new file mode 100644 index 0000000..e755b67 --- /dev/null +++ b/SOURCES/glibc-rh1817513-93.patch @@ -0,0 +1,202 @@ +commit e0f1a58f3d1f4f55591b524e9dcff23cc98a509e +Author: Florian Weimer +Date: Thu Oct 8 10:57:10 2020 +0200 + + elf: Implement ld.so --help + + --help processing is deferred to the point where the executable has + been loaded, so that it is possible to eventually include information + from the main executable in the help output. + + As suggested in the GNU command-line interface guidelines, the help + message is printed to standard output, and the exit status is + successful. + + Handle usage errors closer to the GNU command-line interface + guidelines. + + Reviewed-by: Adhemerval Zanella + +diff --git a/elf/dl-main.h b/elf/dl-main.h +index 79c9c40056504f80..ac7249a580214860 100644 +--- a/elf/dl-main.h ++++ b/elf/dl-main.h +@@ -63,6 +63,7 @@ struct audit_list + enum rtld_mode + { + rtld_mode_normal, rtld_mode_list, rtld_mode_verify, rtld_mode_trace, ++ rtld_mode_help, + }; + + /* Aggregated state information extracted from environment variables +@@ -101,6 +102,11 @@ call_init_paths (const struct dl_main_state *state) + } + + /* Print ld.so usage information and exit. */ +-_Noreturn void _dl_usage (void) attribute_hidden; ++_Noreturn void _dl_usage (const char *argv0, const char *wrong_option) ++ attribute_hidden; ++ ++/* Print ld.so --help output and exit. */ ++_Noreturn void _dl_help (const char *argv0, struct dl_main_state *state) ++ attribute_hidden; + + #endif /* _DL_MAIN */ +diff --git a/elf/dl-usage.c b/elf/dl-usage.c +index f3d89d22b71d7d12..c1820dca2fa117ee 100644 +--- a/elf/dl-usage.c ++++ b/elf/dl-usage.c +@@ -19,12 +19,24 @@ + #include + #include + #include ++#include + + void +-_dl_usage (void) ++_dl_usage (const char *argv0, const char *wrong_option) + { +- _dl_fatal_printf ("\ +-Usage: ld.so [OPTION]... EXECUTABLE-FILE [ARGS-FOR-PROGRAM...]\n\ ++ if (wrong_option != NULL) ++ _dl_error_printf ("%s: unrecognized option '%s'\n", argv0, wrong_option); ++ else ++ _dl_error_printf ("%s: missing program name\n", argv0); ++ _dl_error_printf ("Try '%s --help' for more information.\n", argv0); ++ _exit (EXIT_FAILURE); ++} ++ ++void ++_dl_help (const char *argv0, struct dl_main_state *state) ++{ ++ _dl_printf ("\ ++Usage: %s [OPTION]... EXECUTABLE-FILE [ARGS-FOR-PROGRAM...]\n\ + You have invoked `ld.so', the helper program for shared library executables.\n\ + This program usually lives in the file `/lib/ld.so', and special directives\n\ + in executable files using ELF shared libraries tell the system's program\n\ +@@ -47,5 +59,9 @@ of this helper program; chances are you did not intend to run this program.\n\ + in LIST\n\ + --audit LIST use objects named in LIST as auditors\n\ + --preload LIST preload objects named in LIST\n\ +- --argv0 STRING set argv[0] to STRING before running\n"); ++ --argv0 STRING set argv[0] to STRING before running\n\ ++ --help display this help and exit\n\ ++", ++ argv0); ++ _exit (EXIT_SUCCESS); + } +diff --git a/elf/rtld.c b/elf/rtld.c +index 8e91cee41b62b894..b92641cb1c2d99a6 100644 +--- a/elf/rtld.c ++++ b/elf/rtld.c +@@ -1145,6 +1145,7 @@ dl_main (const ElfW(Phdr) *phdr, + /* Set up a flag which tells we are just starting. */ + _dl_starting_up = 1; + ++ const char *ld_so_name = _dl_argv[0]; + if (*user_entry == (ElfW(Addr)) ENTRY_POINT) + { + /* Ho ho. We are not the program interpreter! We are the program +@@ -1172,8 +1173,12 @@ dl_main (const ElfW(Phdr) *phdr, + while (_dl_argc > 1) + if (! strcmp (_dl_argv[1], "--list")) + { +- state.mode = rtld_mode_list; +- GLRO(dl_lazy) = -1; /* This means do no dependency analysis. */ ++ if (state.mode != rtld_mode_help) ++ { ++ state.mode = rtld_mode_list; ++ /* This means do no dependency analysis. */ ++ GLRO(dl_lazy) = -1; ++ } + + ++_dl_skip_args; + --_dl_argc; +@@ -1181,7 +1186,8 @@ dl_main (const ElfW(Phdr) *phdr, + } + else if (! strcmp (_dl_argv[1], "--verify")) + { +- state.mode = rtld_mode_verify; ++ if (state.mode != rtld_mode_help) ++ state.mode = rtld_mode_verify; + + ++_dl_skip_args; + --_dl_argc; +@@ -1236,13 +1242,34 @@ dl_main (const ElfW(Phdr) *phdr, + _dl_argc -= 2; + _dl_argv += 2; + } ++ else if (strcmp (_dl_argv[1], "--help") == 0) ++ { ++ state.mode = rtld_mode_help; ++ --_dl_argc; ++ ++_dl_argv; ++ } ++ else if (_dl_argv[1][0] == '-' && _dl_argv[1][1] == '-') ++ { ++ if (_dl_argv[1][1] == '\0') ++ /* End of option list. */ ++ break; ++ else ++ /* Unrecognized option. */ ++ _dl_usage (ld_so_name, _dl_argv[1]); ++ } + else + break; + + /* If we have no further argument the program was called incorrectly. + Grant the user some education. */ + if (_dl_argc < 2) +- _dl_usage (); ++ { ++ if (state.mode == rtld_mode_help) ++ /* --help without an executable is not an error. */ ++ _dl_help (ld_so_name, &state); ++ else ++ _dl_usage (ld_so_name, NULL); ++ } + + ++_dl_skip_args; + --_dl_argc; +@@ -1267,7 +1294,8 @@ dl_main (const ElfW(Phdr) *phdr, + break; + } + +- if (__glibc_unlikely (state.mode == rtld_mode_verify)) ++ if (__glibc_unlikely (state.mode == rtld_mode_verify ++ || state.mode == rtld_mode_help)) + { + const char *objname; + const char *err_str = NULL; +@@ -1280,9 +1308,16 @@ dl_main (const ElfW(Phdr) *phdr, + (void) _dl_catch_error (&objname, &err_str, &malloced, map_doit, + &args); + if (__glibc_unlikely (err_str != NULL)) +- /* We don't free the returned string, the programs stops +- anyway. */ +- _exit (EXIT_FAILURE); ++ { ++ /* We don't free the returned string, the programs stops ++ anyway. */ ++ if (state.mode == rtld_mode_help) ++ /* Mask the failure to load the main object. The help ++ message contains less information in this case. */ ++ _dl_help (ld_so_name, &state); ++ else ++ _exit (EXIT_FAILURE); ++ } + } + else + { +@@ -1632,6 +1667,11 @@ ERROR: '%s': cannot process note segment.\n", _dl_argv[0]); + audit_list_add_dynamic_tag (&state.audit_list, main_map, DT_AUDIT); + audit_list_add_dynamic_tag (&state.audit_list, main_map, DT_DEPAUDIT); + ++ /* At this point, all data has been obtained that is included in the ++ --help output. */ ++ if (__glibc_unlikely (state.mode == rtld_mode_help)) ++ _dl_help (ld_so_name, &state); ++ + /* If we have auditing DSOs to load, do it now. */ + bool need_security_init = true; + if (state.audit_list.length > 0) diff --git a/SOURCES/glibc-rh1817513-94.patch b/SOURCES/glibc-rh1817513-94.patch new file mode 100644 index 0000000..8d1b874 --- /dev/null +++ b/SOURCES/glibc-rh1817513-94.patch @@ -0,0 +1,79 @@ +commit 542923d949e8b2480e48bd85fea13cf5d00d30b7 +Author: Florian Weimer +Date: Thu Oct 8 15:33:00 2020 +0200 + + elf: Implement ld.so --version + + This prints out version information for the dynamic loader and + exits immediately, without further command line processing + (which seems to match what some GNU tools do). + + Reviewed-by: Adhemerval Zanella + +diff --git a/elf/dl-main.h b/elf/dl-main.h +index ac7249a580214860..b51256d3b48230b0 100644 +--- a/elf/dl-main.h ++++ b/elf/dl-main.h +@@ -105,6 +105,9 @@ call_init_paths (const struct dl_main_state *state) + _Noreturn void _dl_usage (const char *argv0, const char *wrong_option) + attribute_hidden; + ++/* Print ld.so version information and exit. */ ++_Noreturn void _dl_version (void) attribute_hidden; ++ + /* Print ld.so --help output and exit. */ + _Noreturn void _dl_help (const char *argv0, struct dl_main_state *state) + attribute_hidden; +diff --git a/elf/dl-usage.c b/elf/dl-usage.c +index c1820dca2fa117ee..f3c5ac76d37f9c03 100644 +--- a/elf/dl-usage.c ++++ b/elf/dl-usage.c +@@ -20,6 +20,7 @@ + #include + #include + #include ++#include "version.h" + + void + _dl_usage (const char *argv0, const char *wrong_option) +@@ -32,6 +33,19 @@ _dl_usage (const char *argv0, const char *wrong_option) + _exit (EXIT_FAILURE); + } + ++void ++_dl_version (void) ++{ ++ _dl_printf ("\ ++ld.so " PKGVERSION RELEASE " release version " VERSION ".\n\ ++Copyright (C) 2020 Free Software Foundation, Inc.\n\ ++This is free software; see the source for copying conditions.\n\ ++There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A\n\ ++PARTICULAR PURPOSE.\n\ ++"); ++ _exit (EXIT_SUCCESS); ++} ++ + void + _dl_help (const char *argv0, struct dl_main_state *state) + { +@@ -61,6 +75,7 @@ of this helper program; chances are you did not intend to run this program.\n\ + --preload LIST preload objects named in LIST\n\ + --argv0 STRING set argv[0] to STRING before running\n\ + --help display this help and exit\n\ ++ --version output version information and exit\n\ + ", + argv0); + _exit (EXIT_SUCCESS); +diff --git a/elf/rtld.c b/elf/rtld.c +index b92641cb1c2d99a6..da1eef108508b95f 100644 +--- a/elf/rtld.c ++++ b/elf/rtld.c +@@ -1248,6 +1248,8 @@ dl_main (const ElfW(Phdr) *phdr, + --_dl_argc; + ++_dl_argv; + } ++ else if (strcmp (_dl_argv[1], "--version") == 0) ++ _dl_version (); + else if (_dl_argv[1][0] == '-' && _dl_argv[1][1] == '-') + { + if (_dl_argv[1][1] == '\0') diff --git a/SOURCES/glibc-rh1817513-95.patch b/SOURCES/glibc-rh1817513-95.patch new file mode 100644 index 0000000..12e1075 --- /dev/null +++ b/SOURCES/glibc-rh1817513-95.patch @@ -0,0 +1,43 @@ +commit ca52c56abf50b89a95dc2a4a5504c0d7d3862961 +Author: Florian Weimer +Date: Thu Oct 8 15:33:00 2020 +0200 + + elf: Use the term "program interpreter" in the ld.so help message + + This is the term that the ELF standard itself uses. + + Reviewed-by: Adhemerval Zanella + +diff --git a/elf/dl-usage.c b/elf/dl-usage.c +index f3c5ac76d37f9c03..8c24c13770500df9 100644 +--- a/elf/dl-usage.c ++++ b/elf/dl-usage.c +@@ -51,17 +51,17 @@ _dl_help (const char *argv0, struct dl_main_state *state) + { + _dl_printf ("\ + Usage: %s [OPTION]... EXECUTABLE-FILE [ARGS-FOR-PROGRAM...]\n\ +-You have invoked `ld.so', the helper program for shared library executables.\n\ +-This program usually lives in the file `/lib/ld.so', and special directives\n\ +-in executable files using ELF shared libraries tell the system's program\n\ +-loader to load the helper program from this file. This helper program loads\n\ +-the shared libraries needed by the program executable, prepares the program\n\ +-to run, and runs it. You may invoke this helper program directly from the\n\ +-command line to load and run an ELF executable file; this is like executing\n\ +-that file itself, but always uses this helper program from the file you\n\ +-specified, instead of the helper program file specified in the executable\n\ +-file you run. This is mostly of use for maintainers to test new versions\n\ +-of this helper program; chances are you did not intend to run this program.\n\ ++You have invoked 'ld.so', the program interpreter for dynamically-linked\n\ ++ELF programs. Usually, the program interpreter is invoked automatically\n\ ++when a dynamically-linked executable is started.\n\ ++\n\ ++You may invoke the program interpreter program directly from the command\n\ ++line to load and run an ELF executable file; this is like executing that\n\ ++file itself, but always uses the program interpreter you invoked,\n\ ++instead of the program interpreter specified in the executable file you\n\ ++run. Invoking the program interpreter directly provides access to\n\ ++additional diagnostics, and changing the dynamic linker behavior without\n\ ++setting environment variables (which would be inherited by subprocesses).\n\ + \n\ + --list list all dependencies and how they are resolved\n\ + --verify verify that given object really is a dynamically linked\n\ diff --git a/SOURCES/glibc-rh1817513-96.patch b/SOURCES/glibc-rh1817513-96.patch new file mode 100644 index 0000000..94a0c03 --- /dev/null +++ b/SOURCES/glibc-rh1817513-96.patch @@ -0,0 +1,39 @@ +commit db03874df9843ab98c4faeb658f04d17e6db83a6 +Author: Florian Weimer +Date: Thu Oct 8 15:33:00 2020 +0200 + + elf: Print the full name of the dynamic loader in the ld.so help message + + This requires defining a macro for the full path, matching the + -Wl,--dynamic-link= arguments used for linking glibc programs, + and ldd script. + + Reviewed-by: Adhemerval Zanella + +diff --git a/elf/Makefile b/elf/Makefile +index e5666e5bf7817c3c..bc96b8fd65e376cc 100644 +--- a/elf/Makefile ++++ b/elf/Makefile +@@ -641,7 +641,8 @@ libof-ldconfig = ldconfig + CFLAGS-dl-cache.c += $(SYSCONF-FLAGS) + CFLAGS-cache.c += $(SYSCONF-FLAGS) + CFLAGS-rtld.c += $(SYSCONF-FLAGS) +-CFLAGS-dl-usage.c += $(SYSCONF-FLAGS) ++CFLAGS-dl-usage.c += $(SYSCONF-FLAGS) \ ++ -D'RTLD="$(rtlddir)/$(rtld-installed-name)"' + + cpp-srcs-left := $(all-rtld-routines:=.os) + lib := rtld +diff --git a/elf/dl-usage.c b/elf/dl-usage.c +index 8c24c13770500df9..1003a435bfc2b39e 100644 +--- a/elf/dl-usage.c ++++ b/elf/dl-usage.c +@@ -76,6 +76,8 @@ setting environment variables (which would be inherited by subprocesses).\n\ + --argv0 STRING set argv[0] to STRING before running\n\ + --help display this help and exit\n\ + --version output version information and exit\n\ ++\n\ ++This program interpreter self-identifies as: " RTLD "\n\ + ", + argv0); + _exit (EXIT_SUCCESS); diff --git a/SOURCES/glibc-rh1817513-97.patch b/SOURCES/glibc-rh1817513-97.patch new file mode 100644 index 0000000..754d50a --- /dev/null +++ b/SOURCES/glibc-rh1817513-97.patch @@ -0,0 +1,174 @@ +commit 50b1b7a3905cbcdfbcc7eab335aa81478d711d1a +Author: Florian Weimer +Date: Thu Oct 8 15:33:00 2020 +0200 + + elf: Make __rtld_env_path_list and __rtld_search_dirs global variables + + They have been renamed from env_path_list and rtld_search_dirs to + avoid linknamespace issues. + + This change will allow future use these variables in diagnostics. + + Reviewed-by: Adhemerval Zanella + +diff --git a/elf/dl-load.c b/elf/dl-load.c +index 1403a2e9c04e9a16..2eb4f35b2467f7d8 100644 +--- a/elf/dl-load.c ++++ b/elf/dl-load.c +@@ -98,7 +98,7 @@ int __stack_prot attribute_hidden attribute_relro + + + /* This is the decomposed LD_LIBRARY_PATH search path. */ +-static struct r_search_path_struct env_path_list attribute_relro; ++struct r_search_path_struct __rtld_env_path_list attribute_relro; + + /* List of the hardware capabilities we might end up using. */ + #ifdef SHARED +@@ -442,7 +442,7 @@ add_name_to_object (struct link_map *l, const char *name) + } + + /* Standard search directories. */ +-static struct r_search_path_struct rtld_search_dirs attribute_relro; ++struct r_search_path_struct __rtld_search_dirs attribute_relro; + + static size_t max_dirnamelen; + +@@ -702,9 +702,9 @@ _dl_init_paths (const char *llp, const char *source) + #endif + + /* First set up the rest of the default search directory entries. */ +- aelem = rtld_search_dirs.dirs = (struct r_search_path_elem **) ++ aelem = __rtld_search_dirs.dirs = (struct r_search_path_elem **) + malloc ((nsystem_dirs_len + 1) * sizeof (struct r_search_path_elem *)); +- if (rtld_search_dirs.dirs == NULL) ++ if (__rtld_search_dirs.dirs == NULL) + { + errstring = N_("cannot create search path array"); + signal_error: +@@ -715,16 +715,17 @@ _dl_init_paths (const char *llp, const char *source) + + ncapstr * sizeof (enum r_dir_status)) + / sizeof (struct r_search_path_elem)); + +- rtld_search_dirs.dirs[0] = malloc (nsystem_dirs_len * round_size +- * sizeof (*rtld_search_dirs.dirs[0])); +- if (rtld_search_dirs.dirs[0] == NULL) ++ __rtld_search_dirs.dirs[0] ++ = malloc (nsystem_dirs_len * round_size ++ * sizeof (*__rtld_search_dirs.dirs[0])); ++ if (__rtld_search_dirs.dirs[0] == NULL) + { + errstring = N_("cannot create cache for search path"); + goto signal_error; + } + +- rtld_search_dirs.malloced = 0; +- pelem = GL(dl_all_dirs) = rtld_search_dirs.dirs[0]; ++ __rtld_search_dirs.malloced = 0; ++ pelem = GL(dl_all_dirs) = __rtld_search_dirs.dirs[0]; + strp = system_dirs; + idx = 0; + +@@ -811,27 +812,27 @@ _dl_init_paths (const char *llp, const char *source) + if (*cp == ':' || *cp == ';') + ++nllp; + +- env_path_list.dirs = (struct r_search_path_elem **) ++ __rtld_env_path_list.dirs = (struct r_search_path_elem **) + malloc ((nllp + 1) * sizeof (struct r_search_path_elem *)); +- if (env_path_list.dirs == NULL) ++ if (__rtld_env_path_list.dirs == NULL) + { + errstring = N_("cannot create cache for search path"); + goto signal_error; + } + +- (void) fillin_rpath (llp_tmp, env_path_list.dirs, ":;", ++ (void) fillin_rpath (llp_tmp, __rtld_env_path_list.dirs, ":;", + source, NULL, l); + +- if (env_path_list.dirs[0] == NULL) ++ if (__rtld_env_path_list.dirs[0] == NULL) + { +- free (env_path_list.dirs); +- env_path_list.dirs = (void *) -1; ++ free (__rtld_env_path_list.dirs); ++ __rtld_env_path_list.dirs = (void *) -1; + } + +- env_path_list.malloced = 0; ++ __rtld_env_path_list.malloced = 0; + } + else +- env_path_list.dirs = (void *) -1; ++ __rtld_env_path_list.dirs = (void *) -1; + } + + +@@ -1946,9 +1947,9 @@ open_path (const char *name, size_t namelen, int mode, + if (sps->malloced) + free (sps->dirs); + +- /* rtld_search_dirs and env_path_list are attribute_relro, therefore +- avoid writing into it. */ +- if (sps != &rtld_search_dirs && sps != &env_path_list) ++ /* __rtld_search_dirs and __rtld_env_path_list are ++ attribute_relro, therefore avoid writing to them. */ ++ if (sps != &__rtld_search_dirs && sps != &__rtld_env_path_list) + sps->dirs = (void *) -1; + } + +@@ -2096,8 +2097,8 @@ _dl_map_object (struct link_map *loader, const char *name, + } + + /* Try the LD_LIBRARY_PATH environment variable. */ +- if (fd == -1 && env_path_list.dirs != (void *) -1) +- fd = open_path (name, namelen, mode, &env_path_list, ++ if (fd == -1 && __rtld_env_path_list.dirs != (void *) -1) ++ fd = open_path (name, namelen, mode, &__rtld_env_path_list, + &realname, &fb, + loader ?: GL(dl_ns)[LM_ID_BASE]._ns_loaded, + LA_SER_LIBPATH, &found_other_class); +@@ -2186,8 +2187,8 @@ _dl_map_object (struct link_map *loader, const char *name, + if (fd == -1 + && ((l = loader ?: GL(dl_ns)[nsid]._ns_loaded) == NULL + || __glibc_likely (!(l->l_flags_1 & DF_1_NODEFLIB))) +- && rtld_search_dirs.dirs != (void *) -1) +- fd = open_path (name, namelen, mode, &rtld_search_dirs, ++ && __rtld_search_dirs.dirs != (void *) -1) ++ fd = open_path (name, namelen, mode, &__rtld_search_dirs, + &realname, &fb, l, LA_SER_DEFAULT, &found_other_class); + + /* Add another newline when we are tracing the library loading. */ +@@ -2355,7 +2356,7 @@ _dl_rtld_di_serinfo (struct link_map *loader, Dl_serinfo *si, bool counting) + } + + /* Try the LD_LIBRARY_PATH environment variable. */ +- add_path (&p, &env_path_list, XXX_ENV); ++ add_path (&p, &__rtld_env_path_list, XXX_ENV); + + /* Look at the RUNPATH information for this binary. */ + if (cache_rpath (loader, &loader->l_runpath_dirs, DT_RUNPATH, "RUNPATH")) +@@ -2367,7 +2368,7 @@ _dl_rtld_di_serinfo (struct link_map *loader, Dl_serinfo *si, bool counting) + + /* Finally, try the default path. */ + if (!(loader->l_flags_1 & DF_1_NODEFLIB)) +- add_path (&p, &rtld_search_dirs, XXX_default); ++ add_path (&p, &__rtld_search_dirs, XXX_default); + + if (counting) + /* Count the struct size before the string area, which we didn't +diff --git a/include/link.h b/include/link.h +index e90fa79a0b332087..cdd011f59445e490 100644 +--- a/include/link.h ++++ b/include/link.h +@@ -79,6 +79,10 @@ struct r_search_path_struct + int malloced; + }; + ++/* Search path information computed by _dl_init_paths. */ ++extern struct r_search_path_struct __rtld_search_dirs attribute_hidden; ++extern struct r_search_path_struct __rtld_env_path_list attribute_hidden; ++ + /* Structure describing a loaded shared object. The `l_next' and `l_prev' + members form a chain of all the shared objects loaded at startup. + diff --git a/SOURCES/glibc-rh1817513-98.patch b/SOURCES/glibc-rh1817513-98.patch new file mode 100644 index 0000000..d861cbc --- /dev/null +++ b/SOURCES/glibc-rh1817513-98.patch @@ -0,0 +1,81 @@ +commit 10b39a5124aea509dfeef2f39a0835adb0fb2296 +Author: Florian Weimer +Date: Fri Oct 9 10:13:14 2020 +0200 + + elf: Add library search path information to ld.so --help + + Reviewed-by: Adhemerval Zanella + +diff --git a/elf/dl-usage.c b/elf/dl-usage.c +index 1003a435bfc2b39e..8d39bc9d5442bc59 100644 +--- a/elf/dl-usage.c ++++ b/elf/dl-usage.c +@@ -46,6 +46,61 @@ PARTICULAR PURPOSE.\n\ + _exit (EXIT_SUCCESS); + } + ++/* Print part of the library search path (from a single source). */ ++static void ++print_search_path_for_help_1 (struct r_search_path_elem **list) ++{ ++ if (list == NULL || list == (void *) -1) ++ /* Path is missing or marked as inactive. */ ++ return; ++ ++ for (; *list != NULL; ++list) ++ { ++ _dl_write (STDOUT_FILENO, " ", 2); ++ const char *name = (*list)->dirname; ++ size_t namelen = (*list)->dirnamelen; ++ if (namelen == 0) ++ { ++ /* The empty string denotes the current directory. */ ++ name = "."; ++ namelen = 1; ++ } ++ else if (namelen > 1) ++ /* Remove the trailing slash. */ ++ --namelen; ++ _dl_write (STDOUT_FILENO, name, namelen); ++ _dl_printf (" (%s)\n", (*list)->what); ++ } ++} ++ ++/* Prints the library search path. See _dl_init_paths in dl-load.c ++ how this information is populated. */ ++static void ++print_search_path_for_help (struct dl_main_state *state) ++{ ++ if (__rtld_search_dirs.dirs == NULL) ++ /* The run-time search paths have not yet been initialized. */ ++ _dl_init_paths (state->library_path, state->library_path_source); ++ ++ _dl_printf ("\nShared library search path:\n"); ++ ++ /* The print order should reflect the processing in ++ _dl_map_object. */ ++ ++ struct link_map *map = GL(dl_ns)[LM_ID_BASE]._ns_loaded; ++ if (map != NULL) ++ print_search_path_for_help_1 (map->l_rpath_dirs.dirs); ++ ++ print_search_path_for_help_1 (__rtld_env_path_list.dirs); ++ ++ if (map != NULL) ++ print_search_path_for_help_1 (map->l_runpath_dirs.dirs); ++ ++ _dl_printf (" (libraries located via %s)\n", LD_SO_CACHE); ++ ++ print_search_path_for_help_1 (__rtld_search_dirs.dirs); ++} ++ + void + _dl_help (const char *argv0, struct dl_main_state *state) + { +@@ -80,5 +135,6 @@ setting environment variables (which would be inherited by subprocesses).\n\ + This program interpreter self-identifies as: " RTLD "\n\ + ", + argv0); ++ print_search_path_for_help (state); + _exit (EXIT_SUCCESS); + } diff --git a/SOURCES/glibc-rh1817513-99.patch b/SOURCES/glibc-rh1817513-99.patch new file mode 100644 index 0000000..b55d80e --- /dev/null +++ b/SOURCES/glibc-rh1817513-99.patch @@ -0,0 +1,94 @@ +commit 647103ea3a2aae2e6791b3bebe9e33eedc168102 +Author: Florian Weimer +Date: Fri Oct 9 10:13:14 2020 +0200 + + elf: Enhance ld.so --help to print HWCAP subdirectories + + Reviewed-by: Adhemerval Zanella + +diff --git a/elf/dl-usage.c b/elf/dl-usage.c +index 8d39bc9d5442bc59..c07f43835bd771cf 100644 +--- a/elf/dl-usage.c ++++ b/elf/dl-usage.c +@@ -22,6 +22,8 @@ + #include + #include "version.h" + ++#include ++ + void + _dl_usage (const char *argv0, const char *wrong_option) + { +@@ -101,6 +103,65 @@ print_search_path_for_help (struct dl_main_state *state) + print_search_path_for_help_1 (__rtld_search_dirs.dirs); + } + ++/* Helper function for printing flags associated with a HWCAP name. */ ++static void ++print_hwcap_1 (bool *first, bool active, const char *label) ++{ ++ if (active) ++ { ++ if (*first) ++ { ++ _dl_printf (" ("); ++ *first = false; ++ } ++ else ++ _dl_printf (", "); ++ _dl_printf ("%s", label); ++ } ++} ++ ++/* Called after a series of print_hwcap_1 calls to emit the line ++ terminator. */ ++static void ++print_hwcap_1_finish (bool *first) ++{ ++ if (*first) ++ _dl_printf ("\n"); ++ else ++ _dl_printf (")\n"); ++} ++ ++/* Write a list of hwcap subdirectories to standard output. See ++ _dl_important_hwcaps in dl-hwcaps.c. */ ++static void ++print_legacy_hwcap_directories (void) ++{ ++ _dl_printf ("\n\ ++Legacy HWCAP subdirectories under library search path directories:\n"); ++ ++ const char *platform = GLRO (dl_platform); ++ if (platform != NULL) ++ _dl_printf (" %s (AT_PLATFORM; supported, searched)\n", platform); ++ ++ _dl_printf (" tls (supported, searched)\n"); ++ ++ uint64_t hwcap_mask = GET_HWCAP_MASK(); ++ uint64_t searched = GLRO (dl_hwcap) & hwcap_mask; ++ for (int n = 63; n >= 0; --n) ++ { ++ uint64_t bit = 1ULL << n; ++ if (HWCAP_IMPORTANT & bit) ++ { ++ _dl_printf (" %s", _dl_hwcap_string (n)); ++ bool first = true; ++ print_hwcap_1 (&first, GLRO (dl_hwcap) & bit, "supported"); ++ print_hwcap_1 (&first, !(hwcap_mask & bit), "masked"); ++ print_hwcap_1 (&first, searched & bit, "searched"); ++ print_hwcap_1_finish (&first); ++ } ++ } ++} ++ + void + _dl_help (const char *argv0, struct dl_main_state *state) + { +@@ -136,5 +197,6 @@ This program interpreter self-identifies as: " RTLD "\n\ + ", + argv0); + print_search_path_for_help (state); ++ print_legacy_hwcap_directories (); + _exit (EXIT_SUCCESS); + } diff --git a/SOURCES/glibc-rh1821531-1.patch b/SOURCES/glibc-rh1821531-1.patch new file mode 100644 index 0000000..c09ace9 --- /dev/null +++ b/SOURCES/glibc-rh1821531-1.patch @@ -0,0 +1,136 @@ +commit 284f42bc778e487dfd5dff5c01959f93b9e0c4f5 +Author: Wilco Dijkstra +Date: Fri Aug 3 17:24:12 2018 +0100 + + Simplify and speedup strstr/strcasestr first match + + Looking at the benchtests, both strstr and strcasestr spend a lot of time + in a slow initialization loop handling one character per iteration. + This can be simplified and use the much faster strlen/strnlen/strchr/memcmp. + Read ahead a few cachelines to reduce the number of strnlen calls, which + improves performance by ~3-4%. This patch improves the time taken for the + full strstr benchtest by >40%. + + * string/strcasestr.c (STRCASESTR): Simplify and speedup first match. + * string/strstr.c (AVAILABLE): Likewise. + +diff --git a/string/strcasestr.c b/string/strcasestr.c +index 421764bd1b0ff22e..8aa76037dcc052f3 100644 +--- a/string/strcasestr.c ++++ b/string/strcasestr.c +@@ -59,31 +59,22 @@ + case-insensitive comparison. This function gives unspecified + results in multibyte locales. */ + char * +-STRCASESTR (const char *haystack_start, const char *needle_start) ++STRCASESTR (const char *haystack, const char *needle) + { +- const char *haystack = haystack_start; +- const char *needle = needle_start; + size_t needle_len; /* Length of NEEDLE. */ + size_t haystack_len; /* Known minimum length of HAYSTACK. */ +- bool ok = true; /* True if NEEDLE is prefix of HAYSTACK. */ +- +- /* Determine length of NEEDLE, and in the process, make sure +- HAYSTACK is at least as long (no point processing all of a long +- NEEDLE if HAYSTACK is too short). */ +- while (*haystack && *needle) +- { +- ok &= (TOLOWER ((unsigned char) *haystack) +- == TOLOWER ((unsigned char) *needle)); +- haystack++; +- needle++; +- } +- if (*needle) ++ ++ /* Handle empty NEEDLE special case. */ ++ if (needle[0] == '\0') ++ return (char *) haystack; ++ ++ /* Ensure HAYSTACK length is at least as long as NEEDLE length. ++ Since a match may occur early on in a huge HAYSTACK, use strnlen ++ and read ahead a few cachelines for improved performance. */ ++ needle_len = strlen (needle); ++ haystack_len = __strnlen (haystack, needle_len + 256); ++ if (haystack_len < needle_len) + return NULL; +- if (ok) +- return (char *) haystack_start; +- needle_len = needle - needle_start; +- haystack = haystack_start + 1; +- haystack_len = needle_len - 1; + + /* Perform the search. Abstract memory is considered to be an array + of 'unsigned char' values, not an array of 'char' values. See +@@ -91,10 +82,10 @@ STRCASESTR (const char *haystack_start, const char *needle_start) + if (needle_len < LONG_NEEDLE_THRESHOLD) + return two_way_short_needle ((const unsigned char *) haystack, + haystack_len, +- (const unsigned char *) needle_start, ++ (const unsigned char *) needle, + needle_len); + return two_way_long_needle ((const unsigned char *) haystack, haystack_len, +- (const unsigned char *) needle_start, ++ (const unsigned char *) needle, + needle_len); + } + +diff --git a/string/strstr.c b/string/strstr.c +index 79ebcc75329d0b17..f74d7189ed1319f6 100644 +--- a/string/strstr.c ++++ b/string/strstr.c +@@ -51,33 +51,32 @@ + if NEEDLE is empty, otherwise NULL if NEEDLE is not found in + HAYSTACK. */ + char * +-STRSTR (const char *haystack_start, const char *needle_start) ++STRSTR (const char *haystack, const char *needle) + { +- const char *haystack = haystack_start; +- const char *needle = needle_start; + size_t needle_len; /* Length of NEEDLE. */ + size_t haystack_len; /* Known minimum length of HAYSTACK. */ +- bool ok = true; /* True if NEEDLE is prefix of HAYSTACK. */ +- +- /* Determine length of NEEDLE, and in the process, make sure +- HAYSTACK is at least as long (no point processing all of a long +- NEEDLE if HAYSTACK is too short). */ +- while (*haystack && *needle) +- ok &= *haystack++ == *needle++; +- if (*needle) ++ ++ /* Handle empty NEEDLE special case. */ ++ if (needle[0] == '\0') ++ return (char *) haystack; ++ ++ /* Skip until we find the first matching char from NEEDLE. */ ++ haystack = strchr (haystack, needle[0]); ++ if (haystack == NULL || needle[1] == '\0') ++ return (char *) haystack; ++ ++ /* Ensure HAYSTACK length is at least as long as NEEDLE length. ++ Since a match may occur early on in a huge HAYSTACK, use strnlen ++ and read ahead a few cachelines for improved performance. */ ++ needle_len = strlen (needle); ++ haystack_len = __strnlen (haystack, needle_len + 256); ++ if (haystack_len < needle_len) + return NULL; +- if (ok) +- return (char *) haystack_start; +- +- /* Reduce the size of haystack using strchr, since it has a smaller +- linear coefficient than the Two-Way algorithm. */ +- needle_len = needle - needle_start; +- haystack = strchr (haystack_start + 1, *needle_start); +- if (!haystack || __builtin_expect (needle_len == 1, 0)) ++ ++ /* Check whether we have a match. This improves performance since we avoid ++ the initialization overhead of the two-way algorithm. */ ++ if (memcmp (haystack, needle, needle_len) == 0) + return (char *) haystack; +- needle -= needle_len; +- haystack_len = (haystack > haystack_start + needle_len ? 1 +- : needle_len + haystack_start - haystack); + + /* Perform the search. Abstract memory is considered to be an array + of 'unsigned char' values, not an array of 'char' values. See diff --git a/SOURCES/glibc-rh1821531-2.patch b/SOURCES/glibc-rh1821531-2.patch new file mode 100644 index 0000000..f97e4a5 --- /dev/null +++ b/SOURCES/glibc-rh1821531-2.patch @@ -0,0 +1,260 @@ +commit 5e0a7ecb6629461b28adc1a5aabcc0ede122f201 +Author: Wilco Dijkstra +Date: Wed Jun 12 11:38:52 2019 +0100 + + Improve performance of strstr + + This patch significantly improves performance of strstr using a novel + modified Horspool algorithm. Needles up to size 256 use a bad-character + table indexed by hashed pairs of characters to quickly skip past mismatches. + Long needles use a self-adapting filtering step to avoid comparing the whole + needle repeatedly. + + By limiting the needle length to 256, the shift table only requires 8 bits + per entry, lowering preprocessing overhead and minimizing cache effects. + This limit also implies worst-case performance is linear. + + Small needles up to size 3 use a dedicated linear search. Very long needles + use the Two-Way algorithm. + + The performance gain using the improved bench-strstr on Cortex-A72 is 5.8 + times basic_strstr and 3.7 times twoway_strstr. + + Tested against GLIBC testsuite, randomized tests and the GNULIB strstr test + (https://git.savannah.gnu.org/cgit/gnulib.git/tree/tests/test-strstr.c). + + Reviewed-by: Szabolcs Nagy + + * string/str-two-way.h (two_way_short_needle): Add inline to avoid + warning. + (two_way_long_needle): Block inlining. + * string/strstr.c (strstr2): Add new function. + (strstr3): Likewise. + (STRSTR): Completely rewrite strstr to improve performance. + +diff --git a/string/str-two-way.h b/string/str-two-way.h +index 523d946c59412e1f..358959bef0fd6f74 100644 +--- a/string/str-two-way.h ++++ b/string/str-two-way.h +@@ -221,7 +221,7 @@ critical_factorization (const unsigned char *needle, size_t needle_len, + most 2 * HAYSTACK_LEN - NEEDLE_LEN comparisons occur in searching. + If AVAILABLE modifies HAYSTACK_LEN (as in strstr), then at most 3 * + HAYSTACK_LEN - NEEDLE_LEN comparisons occur in searching. */ +-static RETURN_TYPE ++static inline RETURN_TYPE + two_way_short_needle (const unsigned char *haystack, size_t haystack_len, + const unsigned char *needle, size_t needle_len) + { +@@ -382,8 +382,11 @@ two_way_short_needle (const unsigned char *haystack, size_t haystack_len, + and sublinear performance O(HAYSTACK_LEN / NEEDLE_LEN) is possible. + If AVAILABLE modifies HAYSTACK_LEN (as in strstr), then at most 3 * + HAYSTACK_LEN - NEEDLE_LEN comparisons occur in searching, and +- sublinear performance is not possible. */ +-static RETURN_TYPE ++ sublinear performance is not possible. ++ ++ Since this function is large and complex, block inlining to avoid ++ slowing down the common case of small needles. */ ++__attribute__((noinline)) static RETURN_TYPE + two_way_long_needle (const unsigned char *haystack, size_t haystack_len, + const unsigned char *needle, size_t needle_len) + { +diff --git a/string/strstr.c b/string/strstr.c +index f74d7189ed1319f6..7ffb18ab4285b060 100644 +--- a/string/strstr.c ++++ b/string/strstr.c +@@ -16,29 +16,17 @@ + License along with the GNU C Library; if not, see + . */ + +-/* This particular implementation was written by Eric Blake, 2008. */ +- + #ifndef _LIBC + # include + #endif + +-/* Specification of strstr. */ + #include + +-#include +- +-#ifndef _LIBC +-# define __builtin_expect(expr, val) (expr) +-#endif +- + #define RETURN_TYPE char * + #define AVAILABLE(h, h_l, j, n_l) \ + (((j) + (n_l) <= (h_l)) \ + || ((h_l) += __strnlen ((void*)((h) + (h_l)), (n_l) + 512), \ + (j) + (n_l) <= (h_l))) +-#define CHECK_EOL (1) +-#define RET0_IF_0(a) if (!a) goto ret0 +-#define FASTSEARCH(S,C,N) (void*) strchr ((void*)(S), (C)) + #include "str-two-way.h" + + #undef strstr +@@ -47,47 +35,128 @@ + #define STRSTR strstr + #endif + +-/* Return the first occurrence of NEEDLE in HAYSTACK. Return HAYSTACK +- if NEEDLE is empty, otherwise NULL if NEEDLE is not found in +- HAYSTACK. */ +-char * +-STRSTR (const char *haystack, const char *needle) ++static inline char * ++strstr2 (const unsigned char *hs, const unsigned char *ne) + { +- size_t needle_len; /* Length of NEEDLE. */ +- size_t haystack_len; /* Known minimum length of HAYSTACK. */ +- +- /* Handle empty NEEDLE special case. */ +- if (needle[0] == '\0') +- return (char *) haystack; ++ uint32_t h1 = (ne[0] << 16) | ne[1]; ++ uint32_t h2 = 0; ++ for (int c = hs[0]; h1 != h2 && c != 0; c = *++hs) ++ h2 = (h2 << 16) | c; ++ return h1 == h2 ? (char *)hs - 2 : NULL; ++} + +- /* Skip until we find the first matching char from NEEDLE. */ +- haystack = strchr (haystack, needle[0]); +- if (haystack == NULL || needle[1] == '\0') +- return (char *) haystack; ++static inline char * ++strstr3 (const unsigned char *hs, const unsigned char *ne) ++{ ++ uint32_t h1 = ((uint32_t)ne[0] << 24) | (ne[1] << 16) | (ne[2] << 8); ++ uint32_t h2 = 0; ++ for (int c = hs[0]; h1 != h2 && c != 0; c = *++hs) ++ h2 = (h2 | c) << 8; ++ return h1 == h2 ? (char *)hs - 3 : NULL; ++} + +- /* Ensure HAYSTACK length is at least as long as NEEDLE length. +- Since a match may occur early on in a huge HAYSTACK, use strnlen ++/* Hash character pairs so a small shift table can be used. All bits of ++ p[0] are included, but not all bits from p[-1]. So if two equal hashes ++ match on p[-1], p[0] matches too. Hash collisions are harmless and result ++ in smaller shifts. */ ++#define hash2(p) (((size_t)(p)[0] - ((size_t)(p)[-1] << 3)) % sizeof (shift)) ++ ++/* Fast strstr algorithm with guaranteed linear-time performance. ++ Small needles up to size 3 use a dedicated linear search. Longer needles ++ up to size 256 use a novel modified Horspool algorithm. It hashes pairs ++ of characters to quickly skip past mismatches. The main search loop only ++ exits if the last 2 characters match, avoiding unnecessary calls to memcmp ++ and allowing for a larger skip if there is no match. A self-adapting ++ filtering check is used to quickly detect mismatches in long needles. ++ By limiting the needle length to 256, the shift table can be reduced to 8 ++ bits per entry, lowering preprocessing overhead and minimizing cache effects. ++ The limit also implies worst-case performance is linear. ++ Needles larger than 256 characters use the linear-time Two-Way algorithm. */ ++char * ++STRSTR (const char *haystack, const char *needle) ++{ ++ const unsigned char *hs = (const unsigned char *) haystack; ++ const unsigned char *ne = (const unsigned char *) needle; ++ ++ /* Handle short needle special cases first. */ ++ if (ne[0] == '\0') ++ return (char *)hs; ++ hs = (const unsigned char *)strchr ((const char*)hs, ne[0]); ++ if (hs == NULL || ne[1] == '\0') ++ return (char*)hs; ++ if (ne[2] == '\0') ++ return strstr2 (hs, ne); ++ if (ne[3] == '\0') ++ return strstr3 (hs, ne); ++ ++ /* Ensure haystack length is at least as long as needle length. ++ Since a match may occur early on in a huge haystack, use strnlen + and read ahead a few cachelines for improved performance. */ +- needle_len = strlen (needle); +- haystack_len = __strnlen (haystack, needle_len + 256); +- if (haystack_len < needle_len) ++ size_t ne_len = strlen ((const char*)ne); ++ size_t hs_len = __strnlen ((const char*)hs, ne_len | 512); ++ if (hs_len < ne_len) + return NULL; + +- /* Check whether we have a match. This improves performance since we avoid +- the initialization overhead of the two-way algorithm. */ +- if (memcmp (haystack, needle, needle_len) == 0) +- return (char *) haystack; +- +- /* Perform the search. Abstract memory is considered to be an array +- of 'unsigned char' values, not an array of 'char' values. See +- ISO C 99 section 6.2.6.1. */ +- if (needle_len < LONG_NEEDLE_THRESHOLD) +- return two_way_short_needle ((const unsigned char *) haystack, +- haystack_len, +- (const unsigned char *) needle, needle_len); +- return two_way_long_needle ((const unsigned char *) haystack, haystack_len, +- (const unsigned char *) needle, needle_len); ++ /* Check whether we have a match. This improves performance since we ++ avoid initialization overheads. */ ++ if (memcmp (hs, ne, ne_len) == 0) ++ return (char *) hs; ++ ++ /* Use Two-Way algorithm for very long needles. */ ++ if (__glibc_unlikely (ne_len > 256)) ++ return two_way_long_needle (hs, hs_len, ne, ne_len); ++ ++ const unsigned char *end = hs + hs_len - ne_len; ++ uint8_t shift[256]; ++ size_t tmp, shift1; ++ size_t m1 = ne_len - 1; ++ size_t offset = 0; ++ ++ /* Initialize bad character shift hash table. */ ++ memset (shift, 0, sizeof (shift)); ++ for (int i = 1; i < m1; i++) ++ shift[hash2 (ne + i)] = i; ++ /* Shift1 is the amount we can skip after matching the hash of the ++ needle end but not the full needle. */ ++ shift1 = m1 - shift[hash2 (ne + m1)]; ++ shift[hash2 (ne + m1)] = m1; ++ ++ while (1) ++ { ++ if (__glibc_unlikely (hs > end)) ++ { ++ end += __strnlen ((const char*)end + m1 + 1, 2048); ++ if (hs > end) ++ return NULL; ++ } ++ ++ /* Skip past character pairs not in the needle. */ ++ do ++ { ++ hs += m1; ++ tmp = shift[hash2 (hs)]; ++ } ++ while (tmp == 0 && hs <= end); ++ ++ /* If the match is not at the end of the needle, shift to the end ++ and continue until we match the hash of the needle end. */ ++ hs -= tmp; ++ if (tmp < m1) ++ continue; ++ ++ /* Hash of the last 2 characters matches. If the needle is long, ++ try to quickly filter out mismatches. */ ++ if (m1 < 15 || memcmp (hs + offset, ne + offset, 8) == 0) ++ { ++ if (memcmp (hs, ne, m1) == 0) ++ return (void *) hs; ++ ++ /* Adjust filter offset when it doesn't find the mismatch. */ ++ offset = (offset >= 8 ? offset : m1) - 8; ++ } ++ ++ /* Skip based on matching the hash of the needle end. */ ++ hs += shift1; ++ } + } + libc_hidden_builtin_def (strstr) +- +-#undef LONG_NEEDLE_THRESHOLD diff --git a/SOURCES/glibc-rh1836867.patch b/SOURCES/glibc-rh1836867.patch new file mode 100644 index 0000000..d546a44 --- /dev/null +++ b/SOURCES/glibc-rh1836867.patch @@ -0,0 +1,194 @@ +commit 790b8dda4455865cb8c3a47801f4304c1a43baf6 +Author: Florian Weimer +Date: Tue May 19 14:09:38 2020 +0200 + + nss_compat: internal_end*ent may clobber errno, hiding ERANGE [BZ #25976] + + During cleanup, before returning from get*_r functions, the end*ent + calls must not change errno. Otherwise, an ERANGE error from the + underlying implementation can be hidden, causing unexpected lookup + failures. This commit introduces an internal_end*ent_noerror + function which saves and restore errno, and marks the original + internal_end*ent function as warn_unused_result, so that it is used + only in contexts were errors from it can be handled explicitly. + + Reviewed-by: DJ Delorie + +diff --git a/nss/nss_compat/compat-grp.c b/nss/nss_compat/compat-grp.c +index 012929eae7048702..fca9f4860f72e3d2 100644 +--- a/nss/nss_compat/compat-grp.c ++++ b/nss/nss_compat/compat-grp.c +@@ -142,7 +142,7 @@ _nss_compat_setgrent (int stayopen) + } + + +-static enum nss_status ++static enum nss_status __attribute_warn_unused_result__ + internal_endgrent (ent_t *ent) + { + if (ent->stream != NULL) +@@ -163,6 +163,15 @@ internal_endgrent (ent_t *ent) + return NSS_STATUS_SUCCESS; + } + ++/* Like internal_endgrent, but preserve errno in all cases. */ ++static void ++internal_endgrent_noerror (ent_t *ent) ++{ ++ int saved_errno = errno; ++ enum nss_status unused __attribute__ ((unused)) = internal_endgrent (ent); ++ __set_errno (saved_errno); ++} ++ + enum nss_status + _nss_compat_endgrent (void) + { +@@ -483,7 +492,7 @@ _nss_compat_getgrnam_r (const char *name, struct group *grp, + if (result == NSS_STATUS_SUCCESS) + result = internal_getgrnam_r (name, grp, &ent, buffer, buflen, errnop); + +- internal_endgrent (&ent); ++ internal_endgrent_noerror (&ent); + + return result; + } +@@ -612,7 +621,7 @@ _nss_compat_getgrgid_r (gid_t gid, struct group *grp, + if (result == NSS_STATUS_SUCCESS) + result = internal_getgrgid_r (gid, grp, &ent, buffer, buflen, errnop); + +- internal_endgrent (&ent); ++ internal_endgrent_noerror (&ent); + + return result; + } +diff --git a/nss/nss_compat/compat-initgroups.c b/nss/nss_compat/compat-initgroups.c +index 5beaa6b88b7e1764..d7a89ea8e7718ab0 100644 +--- a/nss/nss_compat/compat-initgroups.c ++++ b/nss/nss_compat/compat-initgroups.c +@@ -133,7 +133,7 @@ internal_setgrent (ent_t *ent) + } + + +-static enum nss_status ++static enum nss_status __attribute_warn_unused_result__ + internal_endgrent (ent_t *ent) + { + if (ent->stream != NULL) +@@ -157,6 +157,15 @@ internal_endgrent (ent_t *ent) + return NSS_STATUS_SUCCESS; + } + ++/* Like internal_endgrent, but preserve errno in all cases. */ ++static void ++internal_endgrent_noerror (ent_t *ent) ++{ ++ int saved_errno = errno; ++ enum nss_status unused __attribute__ ((unused)) = internal_endgrent (ent); ++ __set_errno (saved_errno); ++} ++ + /* Add new group record. */ + static void + add_group (long int *start, long int *size, gid_t **groupsp, long int limit, +@@ -501,7 +510,7 @@ _nss_compat_initgroups_dyn (const char *user, gid_t group, long int *start, + done: + scratch_buffer_free (&tmpbuf); + +- internal_endgrent (&intern); ++ internal_endgrent_noerror (&intern); + + return status; + } +diff --git a/nss/nss_compat/compat-pwd.c b/nss/nss_compat/compat-pwd.c +index a903452cdf96de74..8832fb7518d8bbff 100644 +--- a/nss/nss_compat/compat-pwd.c ++++ b/nss/nss_compat/compat-pwd.c +@@ -259,7 +259,7 @@ _nss_compat_setpwent (int stayopen) + } + + +-static enum nss_status ++static enum nss_status __attribute_warn_unused_result__ + internal_endpwent (ent_t *ent) + { + if (ent->stream != NULL) +@@ -287,6 +287,15 @@ internal_endpwent (ent_t *ent) + return NSS_STATUS_SUCCESS; + } + ++/* Like internal_endpwent, but preserve errno in all cases. */ ++static void ++internal_endpwent_noerror (ent_t *ent) ++{ ++ int saved_errno = errno; ++ enum nss_status unused __attribute__ ((unused)) = internal_endpwent (ent); ++ __set_errno (saved_errno); ++} ++ + enum nss_status + _nss_compat_endpwent (void) + { +@@ -822,7 +831,7 @@ _nss_compat_getpwnam_r (const char *name, struct passwd *pwd, + if (result == NSS_STATUS_SUCCESS) + result = internal_getpwnam_r (name, pwd, &ent, buffer, buflen, errnop); + +- internal_endpwent (&ent); ++ internal_endpwent_noerror (&ent); + + return result; + } +@@ -1061,7 +1070,7 @@ _nss_compat_getpwuid_r (uid_t uid, struct passwd *pwd, + if (result == NSS_STATUS_SUCCESS) + result = internal_getpwuid_r (uid, pwd, &ent, buffer, buflen, errnop); + +- internal_endpwent (&ent); ++ internal_endpwent_noerror (&ent); + + return result; + } +diff --git a/nss/nss_compat/compat-spwd.c b/nss/nss_compat/compat-spwd.c +index eb96ca09172d5743..684a06007ab84ac9 100644 +--- a/nss/nss_compat/compat-spwd.c ++++ b/nss/nss_compat/compat-spwd.c +@@ -215,7 +215,7 @@ _nss_compat_setspent (int stayopen) + } + + +-static enum nss_status ++static enum nss_status __attribute_warn_unused_result__ + internal_endspent (ent_t *ent) + { + if (ent->stream != NULL) +@@ -244,6 +244,15 @@ internal_endspent (ent_t *ent) + return NSS_STATUS_SUCCESS; + } + ++/* Like internal_endspent, but preserve errno in all cases. */ ++static void ++internal_endspent_noerror (ent_t *ent) ++{ ++ int saved_errno = errno; ++ enum nss_status unused __attribute__ ((unused)) = internal_endspent (ent); ++ __set_errno (saved_errno); ++} ++ + enum nss_status + _nss_compat_endspent (void) + { +@@ -261,7 +270,6 @@ _nss_compat_endspent (void) + return result; + } + +- + static enum nss_status + getspent_next_nss_netgr (const char *name, struct spwd *result, ent_t *ent, + char *group, char *buffer, size_t buflen, +@@ -786,7 +794,7 @@ _nss_compat_getspnam_r (const char *name, struct spwd *pwd, + if (result == NSS_STATUS_SUCCESS) + result = internal_getspnam_r (name, pwd, &ent, buffer, buflen, errnop); + +- internal_endspent (&ent); ++ internal_endspent_noerror (&ent); + + return result; + } diff --git a/SOURCES/glibc-rh1845098-1.patch b/SOURCES/glibc-rh1845098-1.patch new file mode 100644 index 0000000..463697d --- /dev/null +++ b/SOURCES/glibc-rh1845098-1.patch @@ -0,0 +1,36 @@ +commit ae725e3f9cb4e1eb825ebe1d55241c98c2ea32f1 +Author: Tulio Magno Quites Machado Filho +Date: Mon Jun 15 11:15:57 2020 -0300 + + powerpc: Add new hwcap values + + Linux commit ID ee988c11acf6f9464b7b44e9a091bf6afb3b3a49 reserved 2 new + bits in AT_HWCAP2: + - PPC_FEATURE2_ARCH_3_1 indicates the availability of the POWER ISA + 3.1; + - PPC_FEATURE2_MMA indicates the availability of the Matrix-Multiply + Assist facility. + +diff --git a/sysdeps/powerpc/bits/hwcap.h b/sysdeps/powerpc/bits/hwcap.h +index b35f5eddc1d309bb..f2853a11df16f63c 100644 +--- a/sysdeps/powerpc/bits/hwcap.h ++++ b/sysdeps/powerpc/bits/hwcap.h +@@ -74,3 +74,5 @@ + #define PPC_FEATURE2_SCV 0x00100000 /* scv syscall. */ + #define PPC_FEATURE2_HTM_NO_SUSPEND 0x00080000 /* TM without suspended + state. */ ++#define PPC_FEATURE2_ARCH_3_1 0x00040000 /* ISA 3.1. */ ++#define PPC_FEATURE2_MMA 0x00020000 /* Matrix-Multiply Assist. */ +diff --git a/sysdeps/powerpc/dl-procinfo.c b/sysdeps/powerpc/dl-procinfo.c +index 35cac2e249916507..4555d4548554e788 100644 +--- a/sysdeps/powerpc/dl-procinfo.c ++++ b/sysdeps/powerpc/dl-procinfo.c +@@ -77,7 +77,7 @@ PROCINFO_CLASS const char _dl_powerpc_cap_flags[64][15] + "", "", "", "", + "", "", "", "", + "", "", "", "", +- "", "", "", "htm-no-suspend", ++ "", "mma", "arch_3_1", "htm-no-suspend", + "scv", "darn", "ieee128", "arch_3_00", + "htm-nosc", "vcrypto", "tar", "isel", + "ebb", "dscr", "htm", "arch_2_07", diff --git a/SOURCES/glibc-rh1845098-2.patch b/SOURCES/glibc-rh1845098-2.patch new file mode 100644 index 0000000..d947c3b --- /dev/null +++ b/SOURCES/glibc-rh1845098-2.patch @@ -0,0 +1,52 @@ +This patch is based on the following commit, with the new Implies +files for POWER10, and the preconfigure changes removed. + +commit d2ba3677da7a785556fcd708404d8e049b1c063b +Author: Tulio Magno Quites Machado Filho +Date: Wed Jun 24 18:04:41 2020 -0300 + + powerpc: Add support for POWER10 + + 1. Add the directories to hold POWER10 files. + + 2. Add support to select POWER10 libraries based on AT_PLATFORM. + + 3. Let submachine=power10 be set automatically. + + +diff --git a/sysdeps/powerpc/dl-procinfo.h b/sysdeps/powerpc/dl-procinfo.h +index 3803379ab2303658..3558d6a83ca2a988 100644 +--- a/sysdeps/powerpc/dl-procinfo.h ++++ b/sysdeps/powerpc/dl-procinfo.h +@@ -37,7 +37,7 @@ + #define HWCAP_IMPORTANT (PPC_FEATURE_HAS_ALTIVEC \ + + PPC_FEATURE_HAS_DFP) + +-#define _DL_PLATFORMS_COUNT 15 ++#define _DL_PLATFORMS_COUNT 16 + + #define _DL_FIRST_PLATFORM 32 + /* Mask to filter out platforms. */ +@@ -60,6 +60,7 @@ + #define PPC_PLATFORM_PPC476 12 + #define PPC_PLATFORM_POWER8 13 + #define PPC_PLATFORM_POWER9 14 ++#define PPC_PLATFORM_POWER10 15 + + static inline const char * + __attribute__ ((unused)) +@@ -91,6 +92,14 @@ _dl_string_platform (const char *str) + str += 5; + switch (*str) + { ++ case '1': ++ if (str[1] == '0') ++ { ++ ret = _DL_FIRST_PLATFORM + PPC_PLATFORM_POWER10; ++ } ++ else ++ return -1; ++ break; + case '4': + ret = _DL_FIRST_PLATFORM + PPC_PLATFORM_POWER4; + break; diff --git a/SOURCES/glibc-rh1845098-3.patch b/SOURCES/glibc-rh1845098-3.patch new file mode 100644 index 0000000..feefa6f --- /dev/null +++ b/SOURCES/glibc-rh1845098-3.patch @@ -0,0 +1,26 @@ +commit f6add169c89bbdd139a2eb845686127ead5799cd +Author: Tulio Magno Quites Machado Filho +Date: Tue Jul 21 18:01:39 2020 -0300 + + powerpc: Fix POWER10 selection + + Add a line that was missing from a previous commit. + Without increasing str, the null-byte is not validated, and + _dl_string_platform returns -1. + + Fixes: d2ba3677da7a ("powerpc: Add support for POWER10") + + Reviewed-by: Carlos O'Donell + +diff --git a/sysdeps/powerpc/dl-procinfo.h b/sysdeps/powerpc/dl-procinfo.h +index 3558d6a83ca2a988..3593e9661b06dcff 100644 +--- a/sysdeps/powerpc/dl-procinfo.h ++++ b/sysdeps/powerpc/dl-procinfo.h +@@ -96,6 +96,7 @@ _dl_string_platform (const char *str) + if (str[1] == '0') + { + ret = _DL_FIRST_PLATFORM + PPC_PLATFORM_POWER10; ++ str++; + } + else + return -1; diff --git a/SOURCES/glibc-rh1855790-1.patch b/SOURCES/glibc-rh1855790-1.patch new file mode 100644 index 0000000..91eaf37 --- /dev/null +++ b/SOURCES/glibc-rh1855790-1.patch @@ -0,0 +1,120 @@ +commit 15eab1e3e89129ab3ed03f5bdc3415b26e9caeb9 +Author: H.J. Lu +Date: Sat Feb 1 05:44:55 2020 -0800 + + i386: Don't unnecessarily save and restore EAX, ECX and EDX [BZ# 25262] + + On i386, since EAX, ECX and EDX are caller-saved, there are no need + to save and restore EAX, ECX and EDX in getcontext, setcontext and + swapcontext. They just need to clear EAX on success. The extra + scratch registers are needed to enable CET. + + Tested on i386. + + Reviewed-by: Adhemerval Zanella +--- + +diff --git a/sysdeps/unix/sysv/linux/i386/getcontext.S b/sysdeps/unix/sysv/linux/i386/getcontext.S +index 26ca08a..6637596 100644 +--- a/sysdeps/unix/sysv/linux/i386/getcontext.S ++++ b/sysdeps/unix/sysv/linux/i386/getcontext.S +@@ -26,13 +26,7 @@ ENTRY(__getcontext) + /* Load address of the context data structure. */ + movl 4(%esp), %eax + +- /* Return value of getcontext. EAX is the only register whose +- value is not preserved. */ +- movl $0, oEAX(%eax) +- +- /* Save the 32-bit register values and the return address. */ +- movl %ecx, oECX(%eax) +- movl %edx, oEDX(%eax) ++ /* Save the preserved register values and the return address. */ + movl %edi, oEDI(%eax) + movl %esi, oESI(%eax) + movl %ebp, oEBP(%eax) +diff --git a/sysdeps/unix/sysv/linux/i386/setcontext.S b/sysdeps/unix/sysv/linux/i386/setcontext.S +index a604fca..7565d7d 100644 +--- a/sysdeps/unix/sysv/linux/i386/setcontext.S ++++ b/sysdeps/unix/sysv/linux/i386/setcontext.S +@@ -65,22 +65,19 @@ ENTRY(__setcontext) + cfi_offset (esi, oESI) + cfi_offset (ebp, oEBP) + cfi_offset (ebx, oEBX) +- cfi_offset (edx, oEDX) +- cfi_offset (ecx, oECX) + movl oESP(%eax), %esp + + /* Push the return address on the new stack so we can return there. */ + pushl %ecx + +- /* Load the values of all the 32-bit registers (except ESP). +- Since we are loading from EAX, it must be last. */ ++ /* Load the values of all the preserved registers (except ESP). */ + movl oEDI(%eax), %edi + movl oESI(%eax), %esi + movl oEBP(%eax), %ebp + movl oEBX(%eax), %ebx +- movl oEDX(%eax), %edx +- movl oECX(%eax), %ecx +- movl oEAX(%eax), %eax ++ ++ /* All done, return 0 for success. */ ++ xorl %eax, %eax + + /* End FDE here, we fall into another context. */ + cfi_endproc +diff --git a/sysdeps/unix/sysv/linux/i386/swapcontext.S b/sysdeps/unix/sysv/linux/i386/swapcontext.S +index 431f22c..ce27d51 100644 +--- a/sysdeps/unix/sysv/linux/i386/swapcontext.S ++++ b/sysdeps/unix/sysv/linux/i386/swapcontext.S +@@ -26,13 +26,7 @@ ENTRY(__swapcontext) + /* Load address of the context data structure we save in. */ + movl 4(%esp), %eax + +- /* Return value of swapcontext. EAX is the only register whose +- value is not preserved. */ +- movl $0, oEAX(%eax) +- +- /* Save the 32-bit register values and the return address. */ +- movl %ecx, oECX(%eax) +- movl %edx, oEDX(%eax) ++ /* Save the preserved register values and the return address. */ + movl %edi, oEDI(%eax) + movl %esi, oESI(%eax) + movl %ebp, oEBP(%eax) +@@ -91,15 +85,14 @@ ENTRY(__swapcontext) + /* Push the return address on the new stack so we can return there. */ + pushl %ecx + +- /* Load the values of all the 32-bit registers (except ESP). +- Since we are loading from EAX, it must be last. */ ++ /* Load the values of all the preserved registers (except ESP). */ + movl oEDI(%eax), %edi + movl oESI(%eax), %esi + movl oEBP(%eax), %ebp + movl oEBX(%eax), %ebx +- movl oEDX(%eax), %edx +- movl oECX(%eax), %ecx +- movl oEAX(%eax), %eax ++ ++ /* All done, return 0 for success. */ ++ xorl %eax, %eax + + /* The following 'ret' will pop the address of the code and jump + to it. */ +diff --git a/sysdeps/unix/sysv/linux/i386/ucontext_i.sym b/sysdeps/unix/sysv/linux/i386/ucontext_i.sym +index b11a550..1dfe03d 100644 +--- a/sysdeps/unix/sysv/linux/i386/ucontext_i.sym ++++ b/sysdeps/unix/sysv/linux/i386/ucontext_i.sym +@@ -21,9 +21,6 @@ oESI mreg (ESI) + oEBP mreg (EBP) + oESP mreg (ESP) + oEBX mreg (EBX) +-oEDX mreg (EDX) +-oECX mreg (ECX) +-oEAX mreg (EAX) + oEIP mreg (EIP) + oFPREGS mcontext (fpregs) + oSIGMASK ucontext (uc_sigmask) + diff --git a/SOURCES/glibc-rh1855790-10.patch b/SOURCES/glibc-rh1855790-10.patch new file mode 100644 index 0000000..fb4a056 --- /dev/null +++ b/SOURCES/glibc-rh1855790-10.patch @@ -0,0 +1,380 @@ +commit 9e38f455a6c602be86b7b5a8d6523cbdcd7ec051 +Author: H.J. Lu +Date: Mon Apr 27 15:44:07 2020 -0700 + + x86: Add --enable-cet=permissive + + When CET is enabled, it is an error to dlopen a non CET enabled shared + library in CET enabled application. It may be desirable to make CET + permissive, that is disable CET when dlopening a non CET enabled shared + library. With the new --enable-cet=permissive configure option, CET is + disabled when dlopening a non CET enabled shared library. + + Add DEFAULT_DL_X86_CET_CONTROL to config.h.in: + + /* The default value of x86 CET control. */ + #define DEFAULT_DL_X86_CET_CONTROL cet_elf_property + + which enables CET features based on ELF property note. + + --enable-cet=permissive it to + + /* The default value of x86 CET control. */ + #define DEFAULT_DL_X86_CET_CONTROL cet_permissive + + which enables CET features permissively. + + Update tst-cet-legacy-5a, tst-cet-legacy-5b, tst-cet-legacy-6a and + tst-cet-legacy-6b to check --enable-cet and --enable-cet=permissive. +--- + +diff --git a/INSTALL b/INSTALL +index d56e102..0655650 100644 +--- a/INSTALL ++++ b/INSTALL +@@ -116,20 +116,24 @@ if 'CFLAGS' is specified it must enable optimization. For example: + executables (PIE) by default. + + '--enable-cet' ++'--enable-cet=permissive' + Enable Intel Control-flow Enforcement Technology (CET) support. +- When the GNU C Library is built with '--enable-cet', the resulting +- library is protected with indirect branch tracking (IBT) and shadow +- stack (SHSTK). When CET is enabled, the GNU C Library is +- compatible with all existing executables and shared libraries. +- This feature is currently supported on i386, x86_64 and x32 with +- GCC 8 and binutils 2.29 or later. Note that when CET is enabled, +- the GNU C Library requires CPUs capable of multi-byte NOPs, like +- x86-64 processors as well as Intel Pentium Pro or newer. ++ When the GNU C Library is built with '--enable-cet' or ++ '--enable-cet=permissive', the resulting library is protected with ++ indirect branch tracking (IBT) and shadow stack (SHSTK). When CET ++ is enabled, the GNU C Library is compatible with all existing ++ executables and shared libraries. This feature is currently ++ supported on i386, x86_64 and x32 with GCC 8 and binutils 2.29 or ++ later. Note that when CET is enabled, the GNU C Library requires ++ CPUs capable of multi-byte NOPs, like x86-64 processors as well as ++ Intel Pentium Pro or newer. With '--enable-cet', it is an error to ++ dlopen a non CET enabled shared library in CET enabled application. ++ With '--enable-cet=permissive', CET is disabled when dlopening a ++ non CET enabled shared library in CET enabled application. + + NOTE: '--enable-cet' has been tested for i686, x86_64 and x32 on +- non-CET processors. '--enable-cet' has been tested for x86_64 and +- x32 on CET SDVs, but Intel CET support hasn't been validated for +- i686. ++ non-CET processors. '--enable-cet' has been tested for i686, ++ x86_64 and x32 on CET processors. + + '--disable-profile' + Don't build libraries with profiling information. You may want to +diff --git a/config.h.in b/config.h.in +index f63f6c8..8520b0f 100644 +--- a/config.h.in ++++ b/config.h.in +@@ -259,4 +259,7 @@ + in i386 6 argument syscall issue). */ + #define CAN_USE_REGISTER_ASM_EBP 0 + ++/* The default value of x86 CET control. */ ++#define DEFAULT_DL_X86_CET_CONTROL cet_elf_property ++ + #endif +diff --git a/manual/install.texi b/manual/install.texi +index 351d67c..7e9f2be 100644 +--- a/manual/install.texi ++++ b/manual/install.texi +@@ -147,20 +147,24 @@ PIE. This option also implies that glibc programs and tests are created + as dynamic position independent executables (PIE) by default. + + @item --enable-cet ++@itemx --enable-cet=permissive + Enable Intel Control-flow Enforcement Technology (CET) support. When +-@theglibc{} is built with @option{--enable-cet}, the resulting library ++@theglibc{} is built with @option{--enable-cet} or ++@option{--enable-cet=permissive}, the resulting library + is protected with indirect branch tracking (IBT) and shadow stack + (SHSTK)@. When CET is enabled, @theglibc{} is compatible with all + existing executables and shared libraries. This feature is currently + supported on i386, x86_64 and x32 with GCC 8 and binutils 2.29 or later. + Note that when CET is enabled, @theglibc{} requires CPUs capable of + multi-byte NOPs, like x86-64 processors as well as Intel Pentium Pro or +-newer. ++newer. With @option{--enable-cet}, it is an error to dlopen a non CET ++enabled shared library in CET enabled application. With ++@option{--enable-cet=permissive}, CET is disabled when dlopening a ++non CET enabled shared library in CET enabled application. + + NOTE: @option{--enable-cet} has been tested for i686, x86_64 and x32 + on non-CET processors. @option{--enable-cet} has been tested for +-x86_64 and x32 on CET SDVs, but Intel CET support hasn't been validated +-for i686. ++i686, x86_64 and x32 on CET processors. + + @item --disable-profile + Don't build libraries with profiling information. You may want to use +diff --git a/sysdeps/unix/sysv/linux/x86/Makefile b/sysdeps/unix/sysv/linux/x86/Makefile +index 7dc4e61..8ac2fd4 100644 +--- a/sysdeps/unix/sysv/linux/x86/Makefile ++++ b/sysdeps/unix/sysv/linux/x86/Makefile +@@ -24,7 +24,7 @@ ifeq ($(subdir),setjmp) + tests += tst-saved_mask-1 + endif + +-ifeq ($(enable-cet),yes) ++ifneq ($(enable-cet),no) + ifeq ($(subdir),elf) + tests += tst-cet-property-1 tst-cet-property-2 + +diff --git a/sysdeps/x86/Makefile b/sysdeps/x86/Makefile +index d9bdf0b..d5f821e 100644 +--- a/sysdeps/x86/Makefile ++++ b/sysdeps/x86/Makefile +@@ -14,7 +14,7 @@ gen-as-const-headers += jmp_buf-ssp.sym + sysdep_routines += __longjmp_cancel + endif + +-ifeq ($(enable-cet),yes) ++ifneq ($(enable-cet),no) + ifeq ($(subdir),elf) + sysdep-dl-routines += dl-cet + +@@ -41,13 +41,21 @@ CFLAGS-tst-cet-legacy-4.c += -fcf-protection=branch + CFLAGS-tst-cet-legacy-4a.c += -fcf-protection + CFLAGS-tst-cet-legacy-4b.c += -fcf-protection + CFLAGS-tst-cet-legacy-mod-4.c += -fcf-protection=none +-CFLAGS-tst-cet-legacy-5a.c += -fcf-protection +-CFLAGS-tst-cet-legacy-5b.c += -fcf-protection ++CFLAGS-tst-cet-legacy-5a.c += -fcf-protection -mshstk ++ifeq ($(enable-cet),permissive) ++CPPFLAGS-tst-cet-legacy-5a.c += -DCET_IS_PERMISSIVE=1 ++endif ++CFLAGS-tst-cet-legacy-5b.c += -fcf-protection -mshstk ++CPPFLAGS-tst-cet-legacy-5b.c += -DCET_DISABLED_BY_ENV=1 + CFLAGS-tst-cet-legacy-mod-5a.c += -fcf-protection=branch + CFLAGS-tst-cet-legacy-mod-5b.c += -fcf-protection + CFLAGS-tst-cet-legacy-mod-5c.c += -fcf-protection +-CFLAGS-tst-cet-legacy-6a.c += -fcf-protection +-CFLAGS-tst-cet-legacy-6b.c += -fcf-protection ++CFLAGS-tst-cet-legacy-6a.c += -fcf-protection -mshstk ++ifeq ($(enable-cet),permissive) ++CPPFLAGS-tst-cet-legacy-6a.c += -DCET_IS_PERMISSIVE=1 ++endif ++CFLAGS-tst-cet-legacy-6b.c += -fcf-protection -mshstk ++CPPFLAGS-tst-cet-legacy-6b.c += -DCET_DISABLED_BY_ENV=1 + CFLAGS-tst-cet-legacy-mod-6a.c += -fcf-protection=branch + CFLAGS-tst-cet-legacy-mod-6b.c += -fcf-protection + CFLAGS-tst-cet-legacy-mod-6c.c += -fcf-protection +diff --git a/sysdeps/x86/configure b/sysdeps/x86/configure +index b1ff281..81cc4e8 100644 +--- a/sysdeps/x86/configure ++++ b/sysdeps/x86/configure +@@ -1,7 +1,7 @@ + # This file is generated from configure.ac by Autoconf. DO NOT EDIT! + # Local configure fragment for sysdeps/x86. + +-if test x"$enable_cet" = xyes; then ++if test $enable_cet != no; then + # Check if CET can be enabled. + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether CET can be enabled" >&5 + $as_echo_n "checking whether CET can be enabled... " >&6; } +@@ -27,17 +27,11 @@ EOF + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $libc_cv_x86_cet_available" >&5 + $as_echo "$libc_cv_x86_cet_available" >&6; } +- if test $libc_cv_x86_cet_available = yes; then +- enable_cet=yes +- else +- if test x"$enable_cet" = xdefault; then +- enable_cet=no +- else +- as_fn_error $? "$CC doesn't support CET" "$LINENO" 5 +- fi ++ if test $libc_cv_x86_cet_available != yes; then ++ as_fn_error $? "$CC doesn't support CET" "$LINENO" 5 + fi + fi +-if test $enable_cet = yes; then ++if test $enable_cet != no; then + # Check if assembler supports CET. + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $AS supports CET" >&5 + $as_echo_n "checking whether $AS supports CET... " >&6; } +@@ -65,5 +59,12 @@ $as_echo "$libc_cv_x86_cet_as" >&6; } + as_fn_error $? "$AS doesn't support CET" "$LINENO" 5 + fi + fi ++if test $enable_cet = yes; then ++ $as_echo "#define DEFAULT_DL_X86_CET_CONTROL cet_elf_property" >>confdefs.h ++ ++elif test $enable_cet = permissive; then ++ $as_echo "#define DEFAULT_DL_X86_CET_CONTROL cet_permissive" >>confdefs.h ++ ++fi + config_vars="$config_vars + enable-cet = $enable_cet" +diff --git a/sysdeps/x86/configure.ac b/sysdeps/x86/configure.ac +index a909b07..8f3e119 100644 +--- a/sysdeps/x86/configure.ac ++++ b/sysdeps/x86/configure.ac +@@ -1,7 +1,7 @@ + GLIBC_PROVIDES dnl See aclocal.m4 in the top level source directory. + # Local configure fragment for sysdeps/x86. + +-if test x"$enable_cet" = xyes; then ++if test $enable_cet != no; then + # Check if CET can be enabled. + AC_CACHE_CHECK(whether CET can be enabled, + libc_cv_x86_cet_available, [dnl +@@ -16,17 +16,11 @@ EOF + libc_cv_x86_cet_available=no + fi + rm -rf conftest*]) +- if test $libc_cv_x86_cet_available = yes; then +- enable_cet=yes +- else +- if test x"$enable_cet" = xdefault; then +- enable_cet=no +- else +- AC_MSG_ERROR([$CC doesn't support CET]) +- fi ++ if test $libc_cv_x86_cet_available != yes; then ++ AC_MSG_ERROR([$CC doesn't support CET]) + fi + fi +-if test $enable_cet = yes; then ++if test $enable_cet != no; then + # Check if assembler supports CET. + AC_CACHE_CHECK(whether $AS supports CET, + libc_cv_x86_cet_as, [dnl +@@ -43,4 +37,9 @@ EOF + AC_MSG_ERROR([$AS doesn't support CET]) + fi + fi ++if test $enable_cet = yes; then ++ AC_DEFINE(DEFAULT_DL_X86_CET_CONTROL, cet_elf_property) ++elif test $enable_cet = permissive; then ++ AC_DEFINE(DEFAULT_DL_X86_CET_CONTROL, cet_permissive) ++fi + LIBC_CONFIG_VAR([enable-cet], [$enable_cet]) +diff --git a/sysdeps/x86/dl-procruntime.c b/sysdeps/x86/dl-procruntime.c +index 26b2b39..72b16fa 100644 +--- a/sysdeps/x86/dl-procruntime.c ++++ b/sysdeps/x86/dl-procruntime.c +@@ -65,8 +65,8 @@ PROCINFO_CLASS struct dl_x86_feature_control _dl_x86_feature_control + # endif + # ifndef PROCINFO_DECL + = { +- .ibt = cet_elf_property, +- .shstk = cet_elf_property ++ .ibt = DEFAULT_DL_X86_CET_CONTROL, ++ .shstk = DEFAULT_DL_X86_CET_CONTROL, + } + # endif + # if !defined SHARED || defined PROCINFO_DECL +diff --git a/sysdeps/x86/tst-cet-legacy-5.c b/sysdeps/x86/tst-cet-legacy-5.c +index 0a34d37..c578979 100644 +--- a/sysdeps/x86/tst-cet-legacy-5.c ++++ b/sysdeps/x86/tst-cet-legacy-5.c +@@ -22,6 +22,14 @@ + #include + #include + #include ++#include ++#include ++ ++#if defined CET_IS_PERMISSIVE || defined CET_DISABLED_BY_ENV ++# define CET_MAYBE_DISABLED 1 ++#else ++# define CET_MAYBE_DISABLED 0 ++#endif + + static void + do_test_1 (const char *modname, bool fail) +@@ -32,24 +40,25 @@ do_test_1 (const char *modname, bool fail) + h = dlopen (modname, RTLD_LAZY); + if (h == NULL) + { ++ const char *err = dlerror (); + if (fail) + { +- const char *err = dlerror (); + if (strstr (err, "rebuild shared object with SHSTK support enabled") + == NULL) +- { +- printf ("incorrect dlopen '%s' error: %s\n", modname, +- err); +- exit (1); +- } ++ FAIL_EXIT1 ("incorrect dlopen '%s' error: %s\n", modname, err); + + return; + } + +- printf ("cannot open '%s': %s\n", modname, dlerror ()); +- exit (1); ++ FAIL_EXIT1 ("cannot open '%s': %s\n", modname, err); + } + ++ /* NB: dlopen should never fail on non-CET platforms. If SHSTK is ++ disabled, assuming IBT is also disabled. */ ++ bool cet_enabled = _get_ssp () != 0 && !CET_MAYBE_DISABLED; ++ if (fail && cet_enabled) ++ FAIL_EXIT1 ("dlopen should have failed\n"); ++ + fp = dlsym (h, "test"); + if (fp == NULL) + { +diff --git a/sysdeps/x86/tst-cet-legacy-6.c b/sysdeps/x86/tst-cet-legacy-6.c +index bd45218..78e72ba 100644 +--- a/sysdeps/x86/tst-cet-legacy-6.c ++++ b/sysdeps/x86/tst-cet-legacy-6.c +@@ -22,6 +22,14 @@ + #include + #include + #include ++#include ++#include ++ ++#if defined CET_IS_PERMISSIVE || defined CET_DISABLED_BY_ENV ++# define CET_MAYBE_DISABLED 1 ++#else ++# define CET_MAYBE_DISABLED 0 ++#endif + + static void + do_test_1 (const char *modname, bool fail) +@@ -32,24 +40,25 @@ do_test_1 (const char *modname, bool fail) + h = dlopen (modname, RTLD_LAZY); + if (h == NULL) + { ++ const char *err = dlerror (); + if (fail) + { +- const char *err = dlerror (); + if (strstr (err, "rebuild shared object with SHSTK support enabled") + == NULL) +- { +- printf ("incorrect dlopen '%s' error: %s\n", modname, +- err); +- exit (1); +- } ++ FAIL_EXIT1 ("incorrect dlopen '%s' error: %s\n", modname, err); + + return; + } + +- printf ("cannot open '%s': %s\n", modname, dlerror ()); +- exit (1); ++ FAIL_EXIT1 ("cannot open '%s': %s\n", modname, err); + } + ++ /* NB: dlopen should never fail on non-CET platforms. If SHSTK is ++ disabled, assuming IBT is also disabled. */ ++ bool cet_enabled = _get_ssp () != 0 && !CET_MAYBE_DISABLED; ++ if (fail && cet_enabled) ++ FAIL_EXIT1 ("dlopen should have failed\n"); ++ + fp = dlsym (h, "test"); + if (fp == NULL) + { + diff --git a/SOURCES/glibc-rh1855790-11.patch b/SOURCES/glibc-rh1855790-11.patch new file mode 100644 index 0000000..8f6d3c4 --- /dev/null +++ b/SOURCES/glibc-rh1855790-11.patch @@ -0,0 +1,293 @@ +commit c02695d776406faaf63418e4e80c4a7023af0b4f +Author: H.J. Lu +Date: Wed Sep 16 16:00:14 2020 -0700 + + x86/CET: Update vfork to prevent child return + + Child of vfork should either call _exit or one of the exec family of + functions. But normally there is nothing to prevent child of vfork from + return of the vfork-calling function. Simpilfy x86 vfork when shadow + stack is in use to introduce mismatched shadow stack in child of vfork + to trigger SIGSEGV when the child returns from the function in which + vfork was called. +--- + +diff --git a/sysdeps/unix/sysv/linux/i386/vfork.S b/sysdeps/unix/sysv/linux/i386/vfork.S +index ceb41db0bd..91277a639f 100644 +--- a/sysdeps/unix/sysv/linux/i386/vfork.S ++++ b/sysdeps/unix/sysv/linux/i386/vfork.S +@@ -21,39 +21,6 @@ + #include + #include + +-#if SHSTK_ENABLED +-/* The shadow stack prevents us from pushing the saved return PC onto +- the stack and returning normally. Instead we pop the shadow stack +- and return directly. This is the safest way to return and ensures +- any stack manipulations done by the vfork'd child doesn't cause the +- parent to terminate when CET is enabled. */ +-# undef SYSCALL_ERROR_HANDLER +-# ifdef PIC +-# define SYSCALL_ERROR_HANDLER \ +-0: \ +- calll .L1; \ +-.L1: \ +- popl %edx; \ +-.L2: \ +- addl $_GLOBAL_OFFSET_TABLE_ + (.L2 - .L1), %edx; \ +- movl __libc_errno@gotntpoff(%edx), %edx; \ +- negl %eax; \ +- movl %eax, %gs:(%edx); \ +- orl $-1, %eax; \ +- jmp 1b; +-# else +-# define SYSCALL_ERROR_HANDLER \ +-0: \ +- movl __libc_errno@indntpoff, %edx; \ +- negl %eax; \ +- movl %eax, %gs:(%edx); \ +- orl $-1, %eax; \ +- jmp 1b; +-# endif +-# undef SYSCALL_ERROR_LABEL +-# define SYSCALL_ERROR_LABEL 0f +-#endif +- + /* 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, +@@ -70,20 +37,17 @@ ENTRY (__vfork) + movl $SYS_ify (vfork), %eax + int $0x80 + +-#if !SHSTK_ENABLED + /* Jump to the return PC. Don't jump directly since this + disturbs the branch target cache. Instead push the return + address back on the stack. */ + pushl %ecx + cfi_adjust_cfa_offset (4) +-#endif + + cmpl $-4095, %eax + /* Branch forward if it failed. */ + jae SYSCALL_ERROR_LABEL + + #if SHSTK_ENABLED +-1: + /* Check if shadow stack is in use. */ + xorl %edx, %edx + rdsspd %edx +@@ -91,18 +55,19 @@ ENTRY (__vfork) + /* Normal return if shadow stack isn't in use. */ + je L(no_shstk) + +- /* Pop return address from shadow stack and jump back to caller +- directly. */ +- movl $1, %edx +- incsspd %edx ++ testl %eax, %eax ++ /* In parent, normal return. */ ++ jnz L(no_shstk) ++ ++ /* NB: In child, jump back to caller via indirect branch without ++ popping shadow stack which is shared with parent. Keep shadow ++ stack mismatched so that child returns in the vfork-calling ++ function will trigger SIGSEGV. */ ++ popl %ecx ++ cfi_adjust_cfa_offset (-4) + jmp *%ecx + + L(no_shstk): +- /* Jump to the return PC. Don't jump directly since this +- disturbs the branch target cache. Instead push the return +- address back on the stack. */ +- pushl %ecx +- cfi_adjust_cfa_offset (4) + #endif + + ret +diff --git a/sysdeps/unix/sysv/linux/x86/Makefile b/sysdeps/unix/sysv/linux/x86/Makefile +index 50fd018fa3..6bfd6bec49 100644 +--- a/sysdeps/unix/sysv/linux/x86/Makefile ++++ b/sysdeps/unix/sysv/linux/x86/Makefile +@@ -40,6 +40,11 @@ $(objpfx)tst-cet-property-2.out: $(objpfx)tst-cet-property-2 \ + $(evaluate-test) + endif + ++ifeq ($(subdir),posix) ++tests += tst-cet-vfork-1 ++CFLAGS-tst-cet-vfork-1.c += -mshstk ++endif ++ + ifeq ($(subdir),stdlib) + tests += tst-cet-setcontext-1 + CFLAGS-tst-cet-setcontext-1.c += -mshstk +diff --git a/sysdeps/unix/sysv/linux/x86/tst-cet-vfork-1.c b/sysdeps/unix/sysv/linux/x86/tst-cet-vfork-1.c +new file mode 100644 +index 0000000000..5b9fc8c170 +--- /dev/null ++++ b/sysdeps/unix/sysv/linux/x86/tst-cet-vfork-1.c +@@ -0,0 +1,88 @@ ++/* Verify that child of the vfork-calling function can't return when ++ shadow stack is in use. ++ 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 ++#include ++ ++__attribute__ ((noclone, noinline)) ++static void ++do_test_1 (void) ++{ ++ pid_t p1; ++ int fd[2]; ++ ++ if (pipe (fd) == -1) ++ { ++ puts ("pipe failed"); ++ _exit (EXIT_FAILURE); ++ } ++ ++ if ((p1 = vfork ()) == 0) ++ { ++ pid_t p = getpid (); ++ TEMP_FAILURE_RETRY (write (fd[1], &p, sizeof (p))); ++ /* Child return should trigger SIGSEGV. */ ++ return; ++ } ++ else if (p1 == -1) ++ { ++ puts ("vfork failed"); ++ _exit (EXIT_FAILURE); ++ } ++ ++ pid_t p2 = 0; ++ if (TEMP_FAILURE_RETRY (read (fd[0], &p2, sizeof (pid_t))) ++ != sizeof (pid_t)) ++ puts ("pipd read failed"); ++ else ++ { ++ int r; ++ if (TEMP_FAILURE_RETRY (waitpid (p1, &r, 0)) != p1) ++ puts ("waitpid failed"); ++ else if (r != 0) ++ puts ("pip write in child failed"); ++ } ++ ++ /* Parent exits immediately so that parent returns without triggering ++ SIGSEGV when shadow stack isn't in use. */ ++ _exit (EXIT_FAILURE); ++} ++ ++static int ++do_test (void) ++{ ++ /* NB: This test should trigger SIGSEGV with shadow stack enabled. */ ++ if (_get_ssp () == 0) ++ return EXIT_UNSUPPORTED; ++ do_test_1 (); ++ /* Child exits immediately so that child returns without triggering ++ SIGSEGV when shadow stack isn't in use. */ ++ _exit (EXIT_FAILURE); ++} ++ ++#define EXPECTED_SIGNAL (_get_ssp () == 0 ? 0 : SIGSEGV) ++#include +diff --git a/sysdeps/unix/sysv/linux/x86_64/vfork.S b/sysdeps/unix/sysv/linux/x86_64/vfork.S +index 776d2fc610..613ff7e846 100644 +--- a/sysdeps/unix/sysv/linux/x86_64/vfork.S ++++ b/sysdeps/unix/sysv/linux/x86_64/vfork.S +@@ -20,22 +20,6 @@ + #include + #include + +-#if SHSTK_ENABLED +-/* The shadow stack prevents us from pushing the saved return PC onto +- the stack and returning normally. Instead we pop the shadow stack +- and return directly. This is the safest way to return and ensures +- any stack manipulations done by the vfork'd child doesn't cause the +- parent to terminate when CET is enabled. */ +-# undef SYSCALL_ERROR_HANDLER +-# define SYSCALL_ERROR_HANDLER \ +-0: \ +- SYSCALL_SET_ERRNO; \ +- or $-1, %RAX_LP; \ +- jmp 1b; +-# undef SYSCALL_ERROR_LABEL +-# define SYSCALL_ERROR_LABEL 0f +-#endif +- + /* 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, +@@ -53,17 +37,14 @@ ENTRY (__vfork) + movl $SYS_ify (vfork), %eax + syscall + +-#if !SHSTK_ENABLED + /* Push back the return PC. */ + pushq %rdi + cfi_adjust_cfa_offset(8) +-#endif + + cmpl $-4095, %eax + jae SYSCALL_ERROR_LABEL /* Branch forward if it failed. */ + + #if SHSTK_ENABLED +-1: + /* Check if shadow stack is in use. */ + xorl %esi, %esi + rdsspq %rsi +@@ -71,16 +52,19 @@ ENTRY (__vfork) + /* Normal return if shadow stack isn't in use. */ + je L(no_shstk) + +- /* Pop return address from shadow stack and jump back to caller +- directly. */ +- movl $1, %esi +- incsspq %rsi ++ testl %eax, %eax ++ /* In parent, normal return. */ ++ jnz L(no_shstk) ++ ++ /* NB: In child, jump back to caller via indirect branch without ++ popping shadow stack which is shared with parent. Keep shadow ++ stack mismatched so that child returns in the vfork-calling ++ function will trigger SIGSEGV. */ ++ popq %rdi ++ cfi_adjust_cfa_offset(-8) + jmp *%rdi + + L(no_shstk): +- /* Push back the return PC. */ +- pushq %rdi +- cfi_adjust_cfa_offset(8) + #endif + + /* Normal return. */ +-- +2.26.2 + diff --git a/SOURCES/glibc-rh1855790-2.patch b/SOURCES/glibc-rh1855790-2.patch new file mode 100644 index 0000000..4d0aed9 --- /dev/null +++ b/SOURCES/glibc-rh1855790-2.patch @@ -0,0 +1,24 @@ +commit 4031d7484ab3f6327184b5973d91f46978ebe8cf +Author: H.J. Lu +Date: Sat Feb 1 05:44:55 2020 -0800 + + i386/sub_n.S: Add a missing _CET_ENDBR to indirect jump target + + Add a missing _CET_ENDBR to indirect jump targe in sysdeps/i386/sub_n.S. + + Reviewed-by: Adhemerval Zanella +--- + +diff --git a/sysdeps/i386/sub_n.S b/sysdeps/i386/sub_n.S +index ada0cf5..949958a 100644 +--- a/sysdeps/i386/sub_n.S ++++ b/sysdeps/i386/sub_n.S +@@ -91,6 +91,7 @@ L(oop): movl (%esi),%eax + movl 8(%esi),%eax + sbbl 8(%edx),%eax + movl %eax,8(%edi) ++ _CET_ENDBR + movl 12(%esi),%eax + sbbl 12(%edx),%eax + movl %eax,12(%edi) + diff --git a/SOURCES/glibc-rh1855790-3.patch b/SOURCES/glibc-rh1855790-3.patch new file mode 100644 index 0000000..490d67c --- /dev/null +++ b/SOURCES/glibc-rh1855790-3.patch @@ -0,0 +1,33 @@ +commit 825b58f3fb04781e559858510fe83a8c4bf28425 +Author: H.J. Lu +Date: Sat Feb 1 05:44:55 2020 -0800 + + i386-mcount.S: Add _CET_ENDBR to _mcount and __fentry__ + + Since _mcount and __fentry__ don't use ENTRY, we need to add _CET_ENDBR + by hand. + + Reviewed-by: Adhemerval Zanella +--- + +diff --git a/sysdeps/i386/i386-mcount.S b/sysdeps/i386/i386-mcount.S +index 3db2fcd..8c8eeb8 100644 +--- a/sysdeps/i386/i386-mcount.S ++++ b/sysdeps/i386/i386-mcount.S +@@ -30,6 +30,7 @@ + .type C_SYMBOL_NAME(_mcount), @function + .align ALIGNARG(4) + C_LABEL(_mcount) ++ _CET_ENDBR + /* Save the caller-clobbered registers. */ + pushl %eax + pushl %ecx +@@ -58,6 +59,7 @@ weak_alias (_mcount, mcount) + .type C_SYMBOL_NAME(__fentry__), @function + .align ALIGNARG(4) + C_LABEL(__fentry__) ++ _CET_ENDBR + /* Save the caller-clobbered registers. */ + pushl %eax + pushl %ecx + diff --git a/SOURCES/glibc-rh1855790-4.patch b/SOURCES/glibc-rh1855790-4.patch new file mode 100644 index 0000000..cfaea33 --- /dev/null +++ b/SOURCES/glibc-rh1855790-4.patch @@ -0,0 +1,92 @@ +commit 0455f251f494d30db4b52f11b5b0b7f285f775ef +Author: H.J. Lu +Date: Sat Feb 1 05:44:55 2020 -0800 + + i386: Use ENTRY/END in assembly codes + + Use ENTRY and END in assembly codes so that ENDBR32 will be added at + function entries when CET is enabled. + + Reviewed-by: Adhemerval Zanella +--- + +diff --git a/sysdeps/i386/nptl/pthread_spin_lock.S b/sysdeps/i386/nptl/pthread_spin_lock.S +index 1980fec..8aa081b 100644 +--- a/sysdeps/i386/nptl/pthread_spin_lock.S ++++ b/sysdeps/i386/nptl/pthread_spin_lock.S +@@ -15,12 +15,10 @@ + License along with the GNU C Library; if not, see + . */ + ++#include + #include + +- .globl pthread_spin_lock +- .type pthread_spin_lock,@function +- .align 16 +-pthread_spin_lock: ++ENTRY (pthread_spin_lock) + mov 4(%esp), %eax + 1: LOCK + decl 0(%eax) +@@ -34,4 +32,4 @@ pthread_spin_lock: + cmpl $0, 0(%eax) + jg 1b + jmp 2b +- .size pthread_spin_lock,.-pthread_spin_lock ++END (pthread_spin_lock) +diff --git a/sysdeps/i386/nptl/pthread_spin_unlock.S b/sysdeps/i386/nptl/pthread_spin_unlock.S +index 2e71086..2995001 100644 +--- a/sysdeps/i386/nptl/pthread_spin_unlock.S ++++ b/sysdeps/i386/nptl/pthread_spin_unlock.S +@@ -16,15 +16,14 @@ + License along with the GNU C Library; if not, see + . */ + +- .globl pthread_spin_unlock +- .type pthread_spin_unlock,@function +- .align 16 +-pthread_spin_unlock: ++#include ++ ++ENTRY (pthread_spin_unlock) + movl 4(%esp), %eax + movl $1, (%eax) + xorl %eax, %eax + ret +- .size pthread_spin_unlock,.-pthread_spin_unlock ++END (pthread_spin_unlock) + + /* The implementation of pthread_spin_init is identical. */ + .globl pthread_spin_init +diff --git a/sysdeps/i386/pthread_spin_trylock.S b/sysdeps/i386/pthread_spin_trylock.S +index 686dd8c..42cbdb7 100644 +--- a/sysdeps/i386/pthread_spin_trylock.S ++++ b/sysdeps/i386/pthread_spin_trylock.S +@@ -16,6 +16,7 @@ + License along with the GNU C Library; if not, see + . */ + ++#include + #include + + +@@ -25,10 +26,7 @@ + # define LOCK lock + #endif + +- .globl pthread_spin_trylock +- .type pthread_spin_trylock,@function +- .align 16 +-pthread_spin_trylock: ++ENTRY (pthread_spin_trylock) + movl 4(%esp), %edx + movl $1, %eax + xorl %ecx, %ecx +@@ -43,4 +41,4 @@ pthread_spin_trylock: + 0: + #endif + ret +- .size pthread_spin_trylock,.-pthread_spin_trylock ++END (pthread_spin_trylock) + diff --git a/SOURCES/glibc-rh1855790-5.patch b/SOURCES/glibc-rh1855790-5.patch new file mode 100644 index 0000000..908ff46 --- /dev/null +++ b/SOURCES/glibc-rh1855790-5.patch @@ -0,0 +1,63 @@ +commit bbfc0f0f8e30680437d1c5b90563018bcd403881 +Author: H.J. Lu +Date: Sat Feb 1 05:44:56 2020 -0800 + + i386: Remove _exit.S + + The generic implementation is suffice since __NR_exit_group is always + support and i386 does define ABORT_INSTRUCTION. + + Reviewed-by: Adhemerval Zanella +--- + +diff --git a/sysdeps/unix/sysv/linux/i386/_exit.S b/sysdeps/unix/sysv/linux/i386/_exit.S +deleted file mode 100644 +index a10eede..0000000 +--- a/sysdeps/unix/sysv/linux/i386/_exit.S ++++ /dev/null +@@ -1,44 +0,0 @@ +-/* 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 +- . */ +- +-#include +- +- .text +- .type _exit,@function +- .global _exit +-_exit: +- movl 4(%esp), %ebx +- +- /* Try the new syscall first. */ +-#ifdef __NR_exit_group +- movl $__NR_exit_group, %eax +- ENTER_KERNEL +-#endif +- +- /* Not available. Now the old one. */ +- movl $__NR_exit, %eax +- /* Don't bother using ENTER_KERNEL here. If the exit_group +- syscall is not available AT_SYSINFO isn't either. */ +- int $0x80 +- +- /* This must not fail. Be sure we don't return. */ +- hlt +- .size _exit,.-_exit +- +-libc_hidden_def (_exit) +-rtld_hidden_def (_exit) +-weak_alias (_exit, _Exit) + diff --git a/SOURCES/glibc-rh1855790-6.patch b/SOURCES/glibc-rh1855790-6.patch new file mode 100644 index 0000000..0ecf744 --- /dev/null +++ b/SOURCES/glibc-rh1855790-6.patch @@ -0,0 +1,572 @@ +commit 5d844e1b72513cf59b5e7c14295644efdcc66e44 +Author: H.J. Lu +Date: Fri Feb 14 14:45:34 2020 -0800 + + i386: Enable CET support in ucontext functions + + 1. getcontext and swapcontext are updated to save the caller's shadow + stack pointer and return address. + 2. setcontext and swapcontext are updated to restore shadow stack and + jump to new context directly. + 3. makecontext is updated to allocate a new shadow stack and set the + caller's return address to the helper code, L(exitcode). + 4. Since we no longer save and restore EAX, ECX and EDX in getcontext, + setcontext and swapcontext, we can use them as scratch register slots + to enable CET in ucontext functions. + + Since makecontext allocates a new shadow stack when making a new + context and kernel allocates a new shadow stack for clone/fork/vfork + syscalls, we track the current shadow stack base. In setcontext and + swapcontext, if the target shadow stack base is the same as the current + shadow stack base, we unwind the shadow stack. Otherwise it is a stack + switch and we look for a restore token. + + We enable shadow stack at run-time only if program and all used shared + objects, including dlopened ones, are shadow stack enabled, which means + that they must be compiled with GCC 8 or above and glibc 2.28 or above. + We need to save and restore shadow stack only if shadow stack is enabled. + When caller of getcontext, setcontext, swapcontext and makecontext is + compiled with smaller ucontext_t, shadow stack won't be enabled at + run-time. We check if shadow stack is enabled before accessing the + extended field in ucontext_t. + + Tested on i386 CET/non-CET machines. + + Reviewed-by: Carlos O'Donell +--- + +diff --git a/sysdeps/unix/sysv/linux/i386/getcontext.S b/sysdeps/unix/sysv/linux/i386/getcontext.S +index 6637596..4ed9d03 100644 +--- a/sysdeps/unix/sysv/linux/i386/getcontext.S ++++ b/sysdeps/unix/sysv/linux/i386/getcontext.S +@@ -18,6 +18,7 @@ + . */ + + #include ++#include + + #include "ucontext_i.h" + +@@ -42,6 +43,61 @@ ENTRY(__getcontext) + movw %fs, %dx + movl %edx, oFS(%eax) + ++#if SHSTK_ENABLED ++ /* Check if shadow stack is enabled. */ ++ testl $X86_FEATURE_1_SHSTK, %gs:FEATURE_1_OFFSET ++ jz L(no_shstk) ++ ++ /* Save EAX in EDX. */ ++ movl %eax, %edx ++ ++ xorl %eax, %eax ++ cmpl %gs:SSP_BASE_OFFSET, %eax ++ jnz L(shadow_stack_bound_recorded) ++ ++ /* Save EBX in the first scratch register slot. */ ++ movl %ebx, oSCRATCH1(%edx) ++ ++ /* Get the base address and size of the default shadow stack ++ which must be the current shadow stack since nothing has ++ been recorded yet. */ ++ sub $24, %esp ++ mov %esp, %ecx ++ movl $ARCH_CET_STATUS, %ebx ++ movl $__NR_arch_prctl, %eax ++ ENTER_KERNEL ++ testl %eax, %eax ++ jz L(continue_no_err) ++ ++ /* This should never happen. */ ++ hlt ++ ++L(continue_no_err): ++ /* Restore EBX from the first scratch register slot. */ ++ movl oSCRATCH1(%edx), %ebx ++ ++ /* Record the base of the current shadow stack. */ ++ movl 8(%esp), %eax ++ movl %eax, %gs:SSP_BASE_OFFSET ++ add $24, %esp ++ ++L(shadow_stack_bound_recorded): ++ /* Load address of the context data structure. */ ++ movl 4(%esp), %eax ++ ++ /* Get the current shadow stack pointer. */ ++ rdsspd %edx ++ /* NB: Save the caller's shadow stack so that we can jump back ++ to the caller directly. */ ++ addl $4, %edx ++ movl %edx, oSSP(%eax) ++ ++ /* Save the current shadow stack base in ucontext. */ ++ movl %gs:SSP_BASE_OFFSET, %edx ++ movl %edx, (oSSP + 4)(%eax) ++ ++L(no_shstk): ++#endif + /* We have separate floating-point register content memory on the + stack. We use the __fpregs_mem block in the context. Set the + links up correctly. */ +diff --git a/sysdeps/unix/sysv/linux/i386/makecontext.S b/sysdeps/unix/sysv/linux/i386/makecontext.S +index e3ca3dc..2d82ddc 100644 +--- a/sysdeps/unix/sysv/linux/i386/makecontext.S ++++ b/sysdeps/unix/sysv/linux/i386/makecontext.S +@@ -18,6 +18,7 @@ + . */ + + #include ++#include + + #include "ucontext_i.h" + +@@ -68,6 +69,127 @@ ENTRY(__makecontext) + jnz 1b + 2: + ++#if SHSTK_ENABLED ++ /* Check if Shadow Stack is enabled. */ ++ testl $X86_FEATURE_1_SHSTK, %gs:FEATURE_1_OFFSET ++ jz L(skip_ssp) ++ ++ /* Reload the pointer to ucontext. */ ++ movl 4(%esp), %eax ++ ++ /* Shadow stack is enabled. We need to allocate a new shadow ++ stack. */ ++ subl oSS_SP(%eax), %edx ++ shrl $STACK_SIZE_TO_SHADOW_STACK_SIZE_SHIFT, %edx ++ ++ /* Align shadow stack size to 8 bytes. */ ++ addl $7, %edx ++ andl $-8, %edx ++ ++ /* Store shadow stack size in __ssp[2]. */ ++ movl %edx, (oSSP + 8)(%eax) ++ ++ /* Save ESI in the second scratch register slot. */ ++ movl %esi, oSCRATCH2(%eax) ++ /* Save EDI in the third scratch register slot. */ ++ movl %edi, oSCRATCH3(%eax) ++ ++ /* Save the pointer to ucontext. */ ++ movl %eax, %edi ++ ++ /* Get the original shadow stack pointer. */ ++ rdsspd %esi ++ ++ /* Align the saved original shadow stack pointer to the next ++ 8 byte aligned boundary. */ ++ andl $-8, %esi ++ ++ /* Load the top of the new stack into EDX. */ ++ movl oESP(%eax), %edx ++ ++ /* We need to terminate the FDE here because the unwinder looks ++ at ra-1 for unwind information. */ ++ cfi_endproc ++ ++ /* Swap the original stack pointer with the top of the new ++ stack. */ ++ xchgl %esp, %edx ++ ++ /* Add 4 bytes since CALL will push the 4-byte return address ++ onto stack. */ ++ addl $4, %esp ++ ++ /* Allocate the new shadow stack. Save EBX in the first scratch ++ register slot. */ ++ movl %ebx, oSCRATCH1(%eax) ++ ++ /* CET syscall takes 64-bit sizes. */ ++ subl $16, %esp ++ movl (oSSP + 8)(%eax), %ecx ++ movl %ecx, (%esp) ++ movl $0, 4(%esp) ++ movl %ecx, 8(%esp) ++ movl $0, 12(%esp) ++ movl %esp, %ecx ++ ++ movl $ARCH_CET_ALLOC_SHSTK, %ebx ++ movl $__NR_arch_prctl, %eax ++ ENTER_KERNEL ++ testl %eax, %eax ++ jne L(hlt) /* This should never happen. */ ++ ++ /* Copy the base address of the new shadow stack to __ssp[1]. */ ++ movl (%esp), %eax ++ movl %eax, (oSSP + 4)(%edi) ++ ++ addl $16, %esp ++ ++ /* Restore EBX from the first scratch register slot. */ ++ movl oSCRATCH1(%edi), %ebx ++ ++ /* Get the size of the new shadow stack. */ ++ movl (oSSP + 8)(%edi), %ecx ++ ++ /* Use the restore stoken to restore the new shadow stack. */ ++ rstorssp -8(%eax, %ecx) ++ ++ /* Save the restore token at the next 8 byte aligned boundary ++ on the original shadow stack. */ ++ saveprevssp ++ ++ /* Push the address of "jmp exitcode" onto the new stack as ++ well as the new shadow stack. */ ++ call 1f ++ jmp L(exitcode) ++1: ++ ++ /* Get the new shadow stack pointer. */ ++ rdsspd %eax ++ ++ /* Use the restore stoken to restore the original shadow stack. */ ++ rstorssp -8(%esi) ++ ++ /* Save the restore token on the new shadow stack. */ ++ saveprevssp ++ ++ /* Store the new shadow stack pointer in __ssp[0]. */ ++ movl %eax, oSSP(%edi) ++ ++ /* Restore the original stack. */ ++ mov %edx, %esp ++ ++ cfi_startproc ++ ++ /* Restore ESI from the second scratch register slot. */ ++ movl oSCRATCH2(%edi), %esi ++ /* Restore EDI from the third scratch register slot. */ ++ movl oSCRATCH3(%edi), %edi ++ ++ ret ++ ++L(skip_ssp): ++#endif ++ + /* If the function we call returns we must continue with the + context which is given in the uc_link element. To do this + set the return address for the function the user provides +@@ -123,6 +245,7 @@ L(call_exit): + call HIDDEN_JUMPTARGET(exit) + /* The 'exit' call should never return. In case it does cause + the process to terminate. */ ++L(hlt): + hlt + cfi_startproc + END(__makecontext) +diff --git a/sysdeps/unix/sysv/linux/i386/setcontext.S b/sysdeps/unix/sysv/linux/i386/setcontext.S +index 7565d7d..7b58918 100644 +--- a/sysdeps/unix/sysv/linux/i386/setcontext.S ++++ b/sysdeps/unix/sysv/linux/i386/setcontext.S +@@ -18,6 +18,7 @@ + . */ + + #include ++#include + + #include "ucontext_i.h" + +@@ -56,9 +57,6 @@ ENTRY(__setcontext) + movl oFS(%eax), %ecx + movw %cx, %fs + +- /* Fetch the address to return to. */ +- movl oEIP(%eax), %ecx +- + /* Load the new stack pointer. */ + cfi_def_cfa (eax, 0) + cfi_offset (edi, oEDI) +@@ -67,6 +65,103 @@ ENTRY(__setcontext) + cfi_offset (ebx, oEBX) + movl oESP(%eax), %esp + ++#if SHSTK_ENABLED ++ /* Check if Shadow Stack is enabled. */ ++ testl $X86_FEATURE_1_SHSTK, %gs:FEATURE_1_OFFSET ++ jz L(no_shstk) ++ ++ /* If the base of the target shadow stack is the same as the ++ base of the current shadow stack, we unwind the shadow ++ stack. Otherwise it is a stack switch and we look for a ++ restore token. */ ++ movl oSSP(%eax), %esi ++ movl %esi, %edi ++ ++ /* Get the base of the target shadow stack. */ ++ movl (oSSP + 4)(%eax), %ecx ++ cmpl %gs:SSP_BASE_OFFSET, %ecx ++ je L(unwind_shadow_stack) ++ ++ /* Align the saved original shadow stack pointer to the next ++ 8 byte aligned boundary. */ ++ andl $-8, %esi ++ ++L(find_restore_token_loop): ++ /* Look for a restore token. */ ++ movl -8(%esi), %ebx ++ andl $-8, %ebx ++ cmpl %esi, %ebx ++ je L(restore_shadow_stack) ++ ++ /* Try the next slot. */ ++ subl $8, %esi ++ jmp L(find_restore_token_loop) ++ ++L(restore_shadow_stack): ++ /* Pop return address from the shadow stack since setcontext ++ will not return. */ ++ movl $1, %ebx ++ incsspd %ebx ++ ++ /* Use the restore stoken to restore the target shadow stack. */ ++ rstorssp -8(%esi) ++ ++ /* Save the restore token on the old shadow stack. NB: This ++ restore token may be checked by setcontext or swapcontext ++ later. */ ++ saveprevssp ++ ++ /* Record the new shadow stack base that was switched to. */ ++ movl (oSSP + 4)(%eax), %ebx ++ movl %ebx, %gs:SSP_BASE_OFFSET ++ ++L(unwind_shadow_stack): ++ rdsspd %ebx ++ subl %edi, %ebx ++ je L(skip_unwind_shadow_stack) ++ negl %ebx ++ shrl $2, %ebx ++ movl $255, %esi ++L(loop): ++ cmpl %esi, %ebx ++ cmovb %ebx, %esi ++ incsspd %esi ++ subl %esi, %ebx ++ ja L(loop) ++ ++L(skip_unwind_shadow_stack): ++ ++ /* Load the values of all the preserved registers (except ESP). */ ++ movl oEDI(%eax), %edi ++ movl oESI(%eax), %esi ++ movl oEBP(%eax), %ebp ++ movl oEBX(%eax), %ebx ++ ++ /* Get the return address set with getcontext. */ ++ movl oEIP(%eax), %ecx ++ ++ /* Check if return address is valid for the case when setcontext ++ is invoked from L(exitcode) with linked context. */ ++ rdsspd %eax ++ cmpl (%eax), %ecx ++ /* Clear EAX to indicate success. NB: Don't use xorl to keep ++ EFLAGS for jne. */ ++ movl $0, %eax ++ jne L(jmp) ++ /* Return to the new context if return address valid. */ ++ pushl %ecx ++ ret ++ ++L(jmp): ++ /* Jump to the new context directly. */ ++ jmp *%ecx ++ ++L(no_shstk): ++#endif ++ ++ /* Fetch the address to return to. */ ++ movl oEIP(%eax), %ecx ++ + /* Push the return address on the new stack so we can return there. */ + pushl %ecx + +diff --git a/sysdeps/unix/sysv/linux/i386/swapcontext.S b/sysdeps/unix/sysv/linux/i386/swapcontext.S +index ce27d51..d1b648c 100644 +--- a/sysdeps/unix/sysv/linux/i386/swapcontext.S ++++ b/sysdeps/unix/sysv/linux/i386/swapcontext.S +@@ -18,6 +18,7 @@ + . */ + + #include ++#include + + #include "ucontext_i.h" + +@@ -76,6 +77,144 @@ ENTRY(__swapcontext) + movl oFS(%eax), %edx + movw %dx, %fs + ++#if SHSTK_ENABLED ++ /* Check if Shadow Stack is enabled. */ ++ testl $X86_FEATURE_1_SHSTK, %gs:FEATURE_1_OFFSET ++ jz L(no_shstk) ++ ++ xorl %eax, %eax ++ cmpl %gs:SSP_BASE_OFFSET, %eax ++ jnz L(shadow_stack_bound_recorded) ++ ++ /* Get the base address and size of the default shadow stack ++ which must be the current shadow stack since nothing has ++ been recorded yet. */ ++ sub $24, %esp ++ mov %esp, %ecx ++ movl $ARCH_CET_STATUS, %ebx ++ movl $__NR_arch_prctl, %eax ++ ENTER_KERNEL ++ testl %eax, %eax ++ jz L(continue_no_err) ++ ++ /* This should never happen. */ ++ hlt ++ ++L(continue_no_err): ++ /* Record the base of the current shadow stack. */ ++ movl 8(%esp), %eax ++ movl %eax, %gs:SSP_BASE_OFFSET ++ add $24, %esp ++ ++L(shadow_stack_bound_recorded): ++ /* Load address of the context data structure we save in. */ ++ movl 4(%esp), %eax ++ ++ /* Load address of the context data structure we swap in */ ++ movl 8(%esp), %edx ++ ++ /* If we unwind the stack, we can't undo stack unwinding. Just ++ save the target shadow stack pointer as the current shadow ++ stack pointer. */ ++ movl oSSP(%edx), %ecx ++ movl %ecx, oSSP(%eax) ++ ++ /* Save the current shadow stack base in ucontext. */ ++ movl %gs:SSP_BASE_OFFSET, %ecx ++ movl %ecx, (oSSP + 4)(%eax) ++ ++ /* If the base of the target shadow stack is the same as the ++ base of the current shadow stack, we unwind the shadow ++ stack. Otherwise it is a stack switch and we look for a ++ restore token. */ ++ movl oSSP(%edx), %esi ++ movl %esi, %edi ++ ++ /* Get the base of the target shadow stack. */ ++ movl (oSSP + 4)(%edx), %ecx ++ cmpl %gs:SSP_BASE_OFFSET, %ecx ++ je L(unwind_shadow_stack) ++ ++ /* Align the saved original shadow stack pointer to the next ++ 8 byte aligned boundary. */ ++ andl $-8, %esi ++ ++L(find_restore_token_loop): ++ /* Look for a restore token. */ ++ movl -8(%esi), %ebx ++ andl $-8, %ebx ++ cmpl %esi, %ebx ++ je L(restore_shadow_stack) ++ ++ /* Try the next slot. */ ++ subl $8, %esi ++ jmp L(find_restore_token_loop) ++ ++L(restore_shadow_stack): ++ /* The target shadow stack will be restored. Save the current ++ shadow stack pointer. */ ++ rdsspd %ecx ++ movl %ecx, oSSP(%eax) ++ ++ /* Use the restore stoken to restore the target shadow stack. */ ++ rstorssp -8(%esi) ++ ++ /* Save the restore token on the old shadow stack. NB: This ++ restore token may be checked by setcontext or swapcontext ++ later. */ ++ saveprevssp ++ ++ /* Record the new shadow stack base that was switched to. */ ++ movl (oSSP + 4)(%edx), %ebx ++ movl %ebx, %gs:SSP_BASE_OFFSET ++ ++L(unwind_shadow_stack): ++ rdsspd %ebx ++ subl %edi, %ebx ++ je L(skip_unwind_shadow_stack) ++ negl %ebx ++ shrl $2, %ebx ++ movl $255, %esi ++L(loop): ++ cmpl %esi, %ebx ++ cmovb %ebx, %esi ++ incsspd %esi ++ subl %esi, %ebx ++ ja L(loop) ++ ++L(skip_unwind_shadow_stack): ++ ++ /* Load the new stack pointer. */ ++ movl oESP(%edx), %esp ++ ++ /* Load the values of all the preserved registers (except ESP). */ ++ movl oEDI(%edx), %edi ++ movl oESI(%edx), %esi ++ movl oEBP(%edx), %ebp ++ movl oEBX(%edx), %ebx ++ ++ /* Get the return address set with getcontext. */ ++ movl oEIP(%edx), %ecx ++ ++ /* Check if return address is valid for the case when setcontext ++ is invoked from L(exitcode) with linked context. */ ++ rdsspd %eax ++ cmpl (%eax), %ecx ++ /* Clear EAX to indicate success. NB: Don't use xorl to keep ++ EFLAGS for jne. */ ++ movl $0, %eax ++ jne L(jmp) ++ /* Return to the new context if return address valid. */ ++ pushl %ecx ++ ret ++ ++L(jmp): ++ /* Jump to the new context directly. */ ++ jmp *%ecx ++ ++L(no_shstk): ++#endif ++ + /* Fetch the address to return to. */ + movl oEIP(%eax), %ecx + +diff --git a/sysdeps/unix/sysv/linux/i386/sysdep.h b/sysdeps/unix/sysv/linux/i386/sysdep.h +index 3255cc7..9344ac7 100644 +--- a/sysdeps/unix/sysv/linux/i386/sysdep.h ++++ b/sysdeps/unix/sysv/linux/i386/sysdep.h +@@ -656,4 +656,9 @@ struct libc_do_syscall_args + # endif + #endif + ++/* Each shadow stack slot takes 4 bytes. Assuming that each stack ++ frame takes 128 bytes, this is used to compute shadow stack size ++ from stack size. */ ++#define STACK_SIZE_TO_SHADOW_STACK_SIZE_SHIFT 5 ++ + #endif /* linux/i386/sysdep.h */ +diff --git a/sysdeps/unix/sysv/linux/i386/ucontext_i.sym b/sysdeps/unix/sysv/linux/i386/ucontext_i.sym +index 1dfe03d..1d8608e 100644 +--- a/sysdeps/unix/sysv/linux/i386/ucontext_i.sym ++++ b/sysdeps/unix/sysv/linux/i386/ucontext_i.sym +@@ -22,6 +22,10 @@ oEBP mreg (EBP) + oESP mreg (ESP) + oEBX mreg (EBX) + oEIP mreg (EIP) ++oSCRATCH1 mreg (EAX) ++oSCRATCH2 mreg (ECX) ++oSCRATCH3 mreg (EDX) + oFPREGS mcontext (fpregs) + oSIGMASK ucontext (uc_sigmask) + oFPREGSMEM ucontext (__fpregs_mem) ++oSSP ucontext (__ssp) + diff --git a/SOURCES/glibc-rh1855790-7.patch b/SOURCES/glibc-rh1855790-7.patch new file mode 100644 index 0000000..990df57 --- /dev/null +++ b/SOURCES/glibc-rh1855790-7.patch @@ -0,0 +1,574 @@ +commit 1fabdb99084df004f7f4cdc7068d1be209a258be +Author: H.J. Lu +Date: Wed Mar 18 04:35:54 2020 -0700 + + x86: Remove ARCH_CET_LEGACY_BITMAP [BZ #25397] + + Since legacy bitmap doesn't cover jitted code generated by legacy JIT + engine, it isn't very useful. This patch removes ARCH_CET_LEGACY_BITMAP + and treats indirect branch tracking similar to shadow stack by removing + legacy bitmap support. + + Tested on CET Linux/x86-64 and non-CET Linux/x86-64. + + Reviewed-by: Carlos O'Donell +--- + +diff --git a/sysdeps/unix/sysv/linux/x86/dl-cet.h b/sysdeps/unix/sysv/linux/x86/dl-cet.h +index 3fbcfeb..47c52e6 100644 +--- a/sysdeps/unix/sysv/linux/x86/dl-cet.h ++++ b/sysdeps/unix/sysv/linux/x86/dl-cet.h +@@ -19,27 +19,6 @@ + #include + + static inline int __attribute__ ((always_inline)) +-dl_cet_allocate_legacy_bitmap (unsigned long *legacy_bitmap) +-{ +- /* Allocate legacy bitmap. */ +- INTERNAL_SYSCALL_DECL (err); +-#ifdef __LP64__ +- return (int) INTERNAL_SYSCALL (arch_prctl, err, 2, +- ARCH_CET_LEGACY_BITMAP, legacy_bitmap); +-#else +- unsigned long long legacy_bitmap_u64[2]; +- int res = INTERNAL_SYSCALL (arch_prctl, err, 2, +- ARCH_CET_LEGACY_BITMAP, legacy_bitmap_u64); +- if (res == 0) +- { +- legacy_bitmap[0] = legacy_bitmap_u64[0]; +- legacy_bitmap[1] = legacy_bitmap_u64[1]; +- } +- return res; +-#endif +-} +- +-static inline int __attribute__ ((always_inline)) + dl_cet_disable_cet (unsigned int cet_feature) + { + INTERNAL_SYSCALL_DECL (err); +diff --git a/sysdeps/unix/sysv/linux/x86/include/asm/prctl.h b/sysdeps/unix/sysv/linux/x86/include/asm/prctl.h +index f67f329..45ad0b0 100644 +--- a/sysdeps/unix/sysv/linux/x86/include/asm/prctl.h ++++ b/sysdeps/unix/sysv/linux/x86/include/asm/prctl.h +@@ -24,9 +24,4 @@ + OUT: allocated shadow stack address: *addr. + */ + # define ARCH_CET_ALLOC_SHSTK 0x3004 +-/* Return legacy region bitmap info in unsigned long long *addr: +- address: addr[0]. +- size: addr[1]. +- */ +-# define ARCH_CET_LEGACY_BITMAP 0x3005 + #endif /* ARCH_CET_STATUS */ +diff --git a/sysdeps/x86/Makefile b/sysdeps/x86/Makefile +index 43ad4a7..d9bdf0b 100644 +--- a/sysdeps/x86/Makefile ++++ b/sysdeps/x86/Makefile +@@ -20,7 +20,8 @@ sysdep-dl-routines += dl-cet + + tests += tst-cet-legacy-1 tst-cet-legacy-2 tst-cet-legacy-2a \ + tst-cet-legacy-3 tst-cet-legacy-4 \ +- tst-cet-legacy-5a tst-cet-legacy-6a ++ tst-cet-legacy-5a tst-cet-legacy-6a tst-cet-legacy-7 \ ++ tst-cet-legacy-8 + ifneq (no,$(have-tunables)) + tests += tst-cet-legacy-4a tst-cet-legacy-4b tst-cet-legacy-4c \ + tst-cet-legacy-5b tst-cet-legacy-6b +@@ -42,14 +43,16 @@ CFLAGS-tst-cet-legacy-4b.c += -fcf-protection + CFLAGS-tst-cet-legacy-mod-4.c += -fcf-protection=none + CFLAGS-tst-cet-legacy-5a.c += -fcf-protection + CFLAGS-tst-cet-legacy-5b.c += -fcf-protection +-CFLAGS-tst-cet-legacy-mod-5a.c += -fcf-protection=none ++CFLAGS-tst-cet-legacy-mod-5a.c += -fcf-protection=branch + CFLAGS-tst-cet-legacy-mod-5b.c += -fcf-protection + CFLAGS-tst-cet-legacy-mod-5c.c += -fcf-protection + CFLAGS-tst-cet-legacy-6a.c += -fcf-protection + CFLAGS-tst-cet-legacy-6b.c += -fcf-protection +-CFLAGS-tst-cet-legacy-mod-6a.c += -fcf-protection=none ++CFLAGS-tst-cet-legacy-mod-6a.c += -fcf-protection=branch + CFLAGS-tst-cet-legacy-mod-6b.c += -fcf-protection + CFLAGS-tst-cet-legacy-mod-6c.c += -fcf-protection ++CFLAGS-tst-cet-legacy-7.c += -fcf-protection=none ++CFLAGS-tst-cet-legacy-8.c += -mshstk + + $(objpfx)tst-cet-legacy-1: $(objpfx)tst-cet-legacy-mod-1.so \ + $(objpfx)tst-cet-legacy-mod-2.so +diff --git a/sysdeps/x86/dl-cet.c b/sysdeps/x86/dl-cet.c +index b82ba14..627d937 100644 +--- a/sysdeps/x86/dl-cet.c ++++ b/sysdeps/x86/dl-cet.c +@@ -33,63 +33,6 @@ + # error GNU_PROPERTY_X86_FEATURE_1_SHSTK != X86_FEATURE_1_SHSTK + #endif + +-static int +-dl_cet_mark_legacy_region (struct link_map *l) +-{ +- /* Mark PT_LOAD segments with PF_X in legacy code page bitmap. */ +- size_t i, phnum = l->l_phnum; +- const ElfW(Phdr) *phdr = l->l_phdr; +-#ifdef __x86_64__ +- typedef unsigned long long word_t; +-#else +- typedef unsigned long word_t; +-#endif +- unsigned int bits_to_set; +- word_t mask_to_set; +-#define BITS_PER_WORD (sizeof (word_t) * 8) +-#define BITMAP_FIRST_WORD_MASK(start) \ +- (~((word_t) 0) << ((start) & (BITS_PER_WORD - 1))) +-#define BITMAP_LAST_WORD_MASK(nbits) \ +- (~((word_t) 0) >> (-(nbits) & (BITS_PER_WORD - 1))) +- +- word_t *bitmap = (word_t *) GL(dl_x86_legacy_bitmap)[0]; +- word_t bitmap_size = GL(dl_x86_legacy_bitmap)[1]; +- word_t *p; +- size_t page_size = GLRO(dl_pagesize); +- +- for (i = 0; i < phnum; i++) +- if (phdr[i].p_type == PT_LOAD && (phdr[i].p_flags & PF_X)) +- { +- /* One bit in legacy bitmap represents a page. */ +- ElfW(Addr) start = (phdr[i].p_vaddr + l->l_addr) / page_size; +- ElfW(Addr) len = (phdr[i].p_memsz + page_size - 1) / page_size; +- ElfW(Addr) end = start + len; +- +- if ((end / 8) > bitmap_size) +- return -EINVAL; +- +- p = bitmap + (start / BITS_PER_WORD); +- bits_to_set = BITS_PER_WORD - (start % BITS_PER_WORD); +- mask_to_set = BITMAP_FIRST_WORD_MASK (start); +- +- while (len >= bits_to_set) +- { +- *p |= mask_to_set; +- len -= bits_to_set; +- bits_to_set = BITS_PER_WORD; +- mask_to_set = ~((word_t) 0); +- p++; +- } +- if (len) +- { +- mask_to_set &= BITMAP_LAST_WORD_MASK (end); +- *p |= mask_to_set; +- } +- } +- +- return 0; +-} +- + /* Check if object M is compatible with CET. */ + + static void +@@ -117,6 +60,8 @@ dl_cet_check (struct link_map *m, const char *program) + if (ibt_enabled || shstk_enabled) + { + struct link_map *l = NULL; ++ unsigned int ibt_legacy = 0, shstk_legacy = 0; ++ bool found_ibt_legacy = false, found_shstk_legacy = false; + + /* Check if IBT and SHSTK are enabled in object. */ + bool enable_ibt = (ibt_enabled +@@ -142,10 +87,7 @@ dl_cet_check (struct link_map *m, const char *program) + support IBT nor SHSTK. */ + if (enable_ibt || enable_shstk) + { +- int res; + unsigned int i; +- unsigned int first_legacy, last_legacy; +- bool need_legacy_bitmap = false; + + i = m->l_searchlist.r_nlist; + while (i-- > 0) +@@ -167,91 +109,25 @@ dl_cet_check (struct link_map *m, const char *program) + continue; + #endif + +- if (enable_ibt +- && enable_ibt_type != CET_ALWAYS_ON +- && !(l->l_cet & lc_ibt)) ++ /* IBT is enabled only if it is enabled in executable as ++ well as all shared objects. */ ++ enable_ibt &= (enable_ibt_type == CET_ALWAYS_ON ++ || (l->l_cet & lc_ibt) != 0); ++ if (!found_ibt_legacy && enable_ibt != ibt_enabled) + { +- /* Remember the first and last legacy objects. */ +- if (!need_legacy_bitmap) +- last_legacy = i; +- first_legacy = i; +- need_legacy_bitmap = true; ++ found_ibt_legacy = true; ++ ibt_legacy = i; + } + + /* SHSTK is enabled only if it is enabled in executable as + well as all shared objects. */ + enable_shstk &= (enable_shstk_type == CET_ALWAYS_ON + || (l->l_cet & lc_shstk) != 0); +- } +- +- if (need_legacy_bitmap) +- { +- if (GL(dl_x86_legacy_bitmap)[0]) +- { +- /* Change legacy bitmap to writable. */ +- if (__mprotect ((void *) GL(dl_x86_legacy_bitmap)[0], +- GL(dl_x86_legacy_bitmap)[1], +- PROT_READ | PROT_WRITE) < 0) +- { +-mprotect_failure: +- if (program) +- _dl_fatal_printf ("%s: mprotect legacy bitmap failed\n", +- l->l_name); +- else +- _dl_signal_error (EINVAL, l->l_name, "dlopen", +- N_("mprotect legacy bitmap failed")); +- } +- } +- else ++ if (enable_shstk != shstk_enabled) + { +- /* Allocate legacy bitmap. */ +- int res = dl_cet_allocate_legacy_bitmap +- (GL(dl_x86_legacy_bitmap)); +- if (res != 0) +- { +- if (program) +- _dl_fatal_printf ("%s: legacy bitmap isn't available\n", +- l->l_name); +- else +- _dl_signal_error (EINVAL, l->l_name, "dlopen", +- N_("legacy bitmap isn't available")); +- } ++ found_shstk_legacy = true; ++ shstk_legacy = i; + } +- +- /* Put legacy shared objects in legacy bitmap. */ +- for (i = first_legacy; i <= last_legacy; i++) +- { +- l = m->l_initfini[i]; +- +- if (l->l_init_called || (l->l_cet & lc_ibt)) +- continue; +- +-#ifdef SHARED +- if (l == &GL(dl_rtld_map) +- || l->l_real == &GL(dl_rtld_map) +- || (program && l == m)) +- continue; +-#endif +- +- /* If IBT is enabled in executable and IBT isn't enabled +- in this shard object, mark PT_LOAD segments with PF_X +- in legacy code page bitmap. */ +- res = dl_cet_mark_legacy_region (l); +- if (res != 0) +- { +- if (program) +- _dl_fatal_printf ("%s: failed to mark legacy code region\n", +- l->l_name); +- else +- _dl_signal_error (-res, l->l_name, "dlopen", +- N_("failed to mark legacy code region")); +- } +- } +- +- /* Change legacy bitmap to read-only. */ +- if (__mprotect ((void *) GL(dl_x86_legacy_bitmap)[0], +- GL(dl_x86_legacy_bitmap)[1], PROT_READ) < 0) +- goto mprotect_failure; + } + } + +@@ -259,23 +135,40 @@ mprotect_failure: + + if (enable_ibt != ibt_enabled || enable_shstk != shstk_enabled) + { +- if (!program +- && enable_shstk_type != CET_PERMISSIVE) ++ if (!program) + { +- /* When SHSTK is enabled, we can't dlopening a shared +- object without SHSTK. */ +- if (enable_shstk != shstk_enabled) +- _dl_signal_error (EINVAL, l->l_name, "dlopen", +- N_("shadow stack isn't enabled")); +- return; ++ if (enable_ibt_type != CET_PERMISSIVE) ++ { ++ /* When IBT is enabled, we cannot dlopen a shared ++ object without IBT. */ ++ if (found_ibt_legacy) ++ _dl_signal_error (0, ++ m->l_initfini[ibt_legacy]->l_name, ++ "dlopen", ++ N_("rebuild shared object with IBT support enabled")); ++ } ++ ++ if (enable_shstk_type != CET_PERMISSIVE) ++ { ++ /* When SHSTK is enabled, we cannot dlopen a shared ++ object without SHSTK. */ ++ if (found_shstk_legacy) ++ _dl_signal_error (0, ++ m->l_initfini[shstk_legacy]->l_name, ++ "dlopen", ++ N_("rebuild shared object with SHSTK support enabled")); ++ } ++ ++ if (enable_ibt_type != CET_PERMISSIVE ++ && enable_shstk_type != CET_PERMISSIVE) ++ return; + } + + /* Disable IBT and/or SHSTK if they are enabled by kernel, but + disabled in executable or shared objects. */ + unsigned int cet_feature = 0; + +- /* Disable IBT only during program startup. */ +- if (program && !enable_ibt) ++ if (!enable_ibt) + cet_feature |= GNU_PROPERTY_X86_FEATURE_1_IBT; + if (!enable_shstk) + cet_feature |= GNU_PROPERTY_X86_FEATURE_1_SHSTK; +@@ -286,8 +179,14 @@ mprotect_failure: + if (program) + _dl_fatal_printf ("%s: can't disable CET\n", program); + else +- _dl_signal_error (-res, l->l_name, "dlopen", +- N_("can't disable CET")); ++ { ++ if (found_ibt_legacy) ++ l = m->l_initfini[ibt_legacy]; ++ else ++ l = m->l_initfini[shstk_legacy]; ++ _dl_signal_error (-res, l->l_name, "dlopen", ++ N_("can't disable CET")); ++ } + } + + /* Clear the disabled bits in dl_x86_feature_1. */ +@@ -297,17 +196,21 @@ mprotect_failure: + } + + #ifdef SHARED +- if (program +- && (!shstk_enabled +- || enable_shstk_type != CET_PERMISSIVE) +- && (ibt_enabled || shstk_enabled)) ++ if (program && (ibt_enabled || shstk_enabled)) + { +- /* Lock CET if IBT or SHSTK is enabled in executable. Don't +- lock CET if SHSTK is enabled permissively. */ +- int res = dl_cet_lock_cet (); +- if (res != 0) +- _dl_fatal_printf ("%s: can't lock CET\n", program); ++ if ((!ibt_enabled ++ || enable_ibt_type != CET_PERMISSIVE) ++ && (!shstk_enabled ++ || enable_shstk_type != CET_PERMISSIVE)) ++ { ++ /* Lock CET if IBT or SHSTK is enabled in executable unless ++ IBT or SHSTK is enabled permissively. */ ++ int res = dl_cet_lock_cet (); ++ if (res != 0) ++ _dl_fatal_printf ("%s: can't lock CET\n", program); ++ } + ++ /* Set feature_1 if IBT or SHSTK is enabled in executable. */ + cet_feature_changed = true; + } + #endif +diff --git a/sysdeps/x86/dl-procruntime.c b/sysdeps/x86/dl-procruntime.c +index eddbde6..920bfe8 100644 +--- a/sysdeps/x86/dl-procruntime.c ++++ b/sysdeps/x86/dl-procruntime.c +@@ -54,15 +54,4 @@ PROCINFO_CLASS unsigned int _dl_x86_feature_1[2] + # else + , + # endif +- +-# if !defined PROCINFO_DECL && defined SHARED +- ._dl_x86_legacy_bitmap +-# else +-PROCINFO_CLASS unsigned long _dl_x86_legacy_bitmap[2] +-# endif +-# if !defined SHARED || defined PROCINFO_DECL +-; +-# else +-, +-# endif + #endif +diff --git a/sysdeps/x86/tst-cet-legacy-4.c b/sysdeps/x86/tst-cet-legacy-4.c +index 3ead63d..f0ba326 100644 +--- a/sysdeps/x86/tst-cet-legacy-4.c ++++ b/sysdeps/x86/tst-cet-legacy-4.c +@@ -20,6 +20,9 @@ + #include + #include + #include ++#include ++ ++#include + + static int + do_test (void) +@@ -31,22 +34,18 @@ do_test (void) + h = dlopen (modname, RTLD_LAZY); + if (h == NULL) + { +- printf ("cannot open '%s': %s\n", modname, dlerror ()); +- exit (1); ++ const char *err = dlerror (); ++ if (!strstr (err, "rebuild shared object with IBT support enabled")) ++ FAIL_EXIT1 ("incorrect dlopen '%s' error: %s\n", modname, err); ++ return 0; + } + + fp = dlsym (h, "test"); + if (fp == NULL) +- { +- printf ("cannot get symbol 'test': %s\n", dlerror ()); +- exit (1); +- } ++ FAIL_EXIT1 ("cannot get symbol 'test': %s\n", dlerror ()); + + if (fp () != 0) +- { +- puts ("test () != 0"); +- exit (1); +- } ++ FAIL_EXIT1 ("test () != 0"); + + dlclose (h); + +diff --git a/sysdeps/x86/tst-cet-legacy-5.c b/sysdeps/x86/tst-cet-legacy-5.c +index fbf640f..e1ca09d 100644 +--- a/sysdeps/x86/tst-cet-legacy-5.c ++++ b/sysdeps/x86/tst-cet-legacy-5.c +@@ -35,7 +35,8 @@ do_test_1 (const char *modname, bool fail) + if (fail) + { + const char *err = dlerror (); +- if (strstr (err, "shadow stack isn't enabled") == NULL) ++ if (strstr (err, "rebuild shared object with SHSTK support enabled") ++ == NULL) + { + printf ("incorrect dlopen '%s' error: %s\n", modname, + dlerror ()); +diff --git a/sysdeps/x86/tst-cet-legacy-6.c b/sysdeps/x86/tst-cet-legacy-6.c +index 9151225..184a35b 100644 +--- a/sysdeps/x86/tst-cet-legacy-6.c ++++ b/sysdeps/x86/tst-cet-legacy-6.c +@@ -35,7 +35,8 @@ do_test_1 (const char *modname, bool fail) + if (fail) + { + const char *err = dlerror (); +- if (strstr (err, "shadow stack isn't enabled") == NULL) ++ if (strstr (err, "rebuild shared object with SHSTK support enabled") ++ == NULL) + { + printf ("incorrect dlopen '%s' error: %s\n", modname, + dlerror ()); +diff --git a/sysdeps/x86/tst-cet-legacy-7.c b/sysdeps/x86/tst-cet-legacy-7.c +new file mode 100644 +index 0000000..58bcb29 +--- /dev/null ++++ b/sysdeps/x86/tst-cet-legacy-7.c +@@ -0,0 +1,38 @@ ++/* Check compatibility of legacy executable with a JIT engine. ++ 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 ++ ++/* Check that mmapped legacy code works with -fcf-protection=none. */ ++ ++static int ++do_test (void) ++{ ++ void (*funcp) (void); ++ funcp = xmmap (NULL, 0x1000, PROT_EXEC | PROT_READ | PROT_WRITE, ++ MAP_ANONYMOUS | MAP_PRIVATE, -1); ++ printf ("mmap = %p\n", funcp); ++ /* Write RET instruction. */ ++ *(char *) funcp = 0xc3; ++ funcp (); ++ return 0; ++} ++ ++#include +diff --git a/sysdeps/x86/tst-cet-legacy-8.c b/sysdeps/x86/tst-cet-legacy-8.c +new file mode 100644 +index 0000000..11e8115 +--- /dev/null ++++ b/sysdeps/x86/tst-cet-legacy-8.c +@@ -0,0 +1,48 @@ ++/* Check incompatibility with legacy JIT engine. ++ 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 ++ ++/* Check that mmapped legacy code trigges segfault with -fcf-protection. */ ++ ++static int ++do_test (void) ++{ ++ /* NB: This test should trigger SIGSEGV on CET platforms. If SHSTK ++ is disabled, assuming IBT is also disabled. */ ++ if (_get_ssp () == 0) ++ return EXIT_UNSUPPORTED; ++ ++ void (*funcp) (void); ++ funcp = xmmap (NULL, 0x1000, PROT_EXEC | PROT_READ | PROT_WRITE, ++ MAP_ANONYMOUS | MAP_PRIVATE, -1); ++ printf ("mmap = %p\n", funcp); ++ /* Write RET instruction. */ ++ *(char *) funcp = 0xc3; ++ funcp (); ++ return EXIT_FAILURE; ++} ++ ++#define EXPECTED_SIGNAL (_get_ssp () == 0 ? 0 : SIGSEGV) ++#include + diff --git a/SOURCES/glibc-rh1855790-8.patch b/SOURCES/glibc-rh1855790-8.patch new file mode 100644 index 0000000..47c212d --- /dev/null +++ b/SOURCES/glibc-rh1855790-8.patch @@ -0,0 +1,420 @@ +commit 674ea88294bfb8d89878a0ebbbcec38a85e118a5 +Author: H.J. Lu +Date: Tue Apr 28 10:05:25 2020 -0700 + + x86: Move CET control to _dl_x86_feature_control [BZ #25887] + + 1. Include to get architecture specific initializer in + rtld_global. + 2. Change _dl_x86_feature_1[2] to _dl_x86_feature_1. + 3. Add _dl_x86_feature_control after _dl_x86_feature_1, which is a + struct of 2 bitfields for IBT and SHSTK control + + This fixes [BZ #25887]. +--- + +diff --git a/elf/rtld.c b/elf/rtld.c +index e107bd1..7f030f7 100644 +--- a/elf/rtld.c ++++ b/elf/rtld.c +@@ -230,6 +230,8 @@ rtld_hidden_def (_dl_starting_up) + (except those which cannot be added for some reason). */ + struct rtld_global _rtld_global = + { ++ /* Get architecture specific initializer. */ ++#include + /* Generally the default presumption without further information is an + * executable stack but this is not true for all platforms. */ + ._dl_stack_flags = DEFAULT_STACK_PERMS, +diff --git a/sysdeps/i386/dl-machine.h b/sysdeps/i386/dl-machine.h +index f6cfb90..8c959e3 100644 +--- a/sysdeps/i386/dl-machine.h ++++ b/sysdeps/i386/dl-machine.h +@@ -71,7 +71,7 @@ elf_machine_runtime_setup (struct link_map *l, int lazy, int profile) + extern void _dl_runtime_profile_shstk (Elf32_Word) attribute_hidden; + /* Check if SHSTK is enabled by kernel. */ + bool shstk_enabled +- = (GL(dl_x86_feature_1)[0] & GNU_PROPERTY_X86_FEATURE_1_SHSTK) != 0; ++ = (GL(dl_x86_feature_1) & GNU_PROPERTY_X86_FEATURE_1_SHSTK) != 0; + + if (l->l_info[DT_JMPREL] && lazy) + { +diff --git a/sysdeps/unix/sysv/linux/x86/cpu-features.c b/sysdeps/unix/sysv/linux/x86/cpu-features.c +index 8566a26..9f40624 100644 +--- a/sysdeps/unix/sysv/linux/x86/cpu-features.c ++++ b/sysdeps/unix/sysv/linux/x86/cpu-features.c +@@ -36,7 +36,7 @@ static inline void + x86_setup_tls (void) + { + __libc_setup_tls (); +- THREAD_SETMEM (THREAD_SELF, header.feature_1, GL(dl_x86_feature_1)[0]); ++ THREAD_SETMEM (THREAD_SELF, header.feature_1, GL(dl_x86_feature_1)); + } + + # define ARCH_SETUP_TLS() x86_setup_tls () +diff --git a/sysdeps/x86/cet-control.h b/sysdeps/x86/cet-control.h +new file mode 100644 +index 0000000..7b29f95 +--- /dev/null ++++ b/sysdeps/x86/cet-control.h +@@ -0,0 +1,41 @@ ++/* x86 CET tuning. ++ This file is part of the GNU C Library. ++ Copyright (C) 2018 Free Software Foundation, Inc. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for 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 _CET_CONTROL_H ++#define _CET_CONTROL_H ++ ++/* For each CET feature, IBT and SHSTK, valid control values. */ ++enum dl_x86_cet_control ++{ ++ /* Enable CET features based on ELF property note. */ ++ cet_elf_property = 0, ++ /* Always enable CET features. */ ++ cet_always_on, ++ /* Always disable CET features. */ ++ cet_always_off, ++ /* Enable CET features permissively. */ ++ cet_permissive ++}; ++ ++struct dl_x86_feature_control ++{ ++ enum dl_x86_cet_control ibt : 2; ++ enum dl_x86_cet_control shstk : 2; ++}; ++ ++#endif /* cet-control.h */ +diff --git a/sysdeps/x86/cet-tunables.h b/sysdeps/x86/cet-tunables.h +deleted file mode 100644 +index ca02305..0000000 +--- a/sysdeps/x86/cet-tunables.h ++++ /dev/null +@@ -1,29 +0,0 @@ +-/* x86 CET tuning. +- This file is part of the GNU C Library. +- Copyright (C) 2018 Free Software Foundation, Inc. +- +- The GNU C Library is free software; you can redistribute it and/or +- modify it under the terms of the GNU Lesser General Public +- License as published by the Free Software Foundation; either +- version 2.1 of the License, or (at your option) any later version. +- +- The GNU C Library is distributed in the hope that it will be useful, +- but WITHOUT ANY WARRANTY; without even the implied warranty of +- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +- Lesser General Public License for more details. +- +- You should have received a copy of the GNU Lesser General Public +- License along with the GNU C Library; if not, see +- . */ +- +-/* Valid control values: +- 0: Enable CET features based on ELF property note. +- 1: Always disable CET features. +- 2: Always enable CET features. +- 3: Enable CET features permissively. +- */ +-#define CET_ELF_PROPERTY 0 +-#define CET_ALWAYS_OFF 1 +-#define CET_ALWAYS_ON 2 +-#define CET_PERMISSIVE 3 +-#define CET_MAX CET_PERMISSIVE +diff --git a/sysdeps/x86/cpu-features.c b/sysdeps/x86/cpu-features.c +index 4695ac8..ac74f40 100644 +--- a/sysdeps/x86/cpu-features.c ++++ b/sysdeps/x86/cpu-features.c +@@ -39,7 +39,6 @@ extern void TUNABLE_CALLBACK (set_x86_shstk) (tunable_val_t *) + + #if CET_ENABLED + # include +-# include + #endif + + static void +@@ -490,7 +489,7 @@ no_cpuid: + + if (cet_status) + { +- GL(dl_x86_feature_1)[0] = cet_status; ++ GL(dl_x86_feature_1) = cet_status; + + # ifndef SHARED + /* Check if IBT and SHSTK are enabled by kernel. */ +@@ -514,14 +513,13 @@ no_cpuid: + + /* Clear the disabled bits in dl_x86_feature_1. */ + if (res == 0) +- GL(dl_x86_feature_1)[0] &= ~cet_feature; ++ GL(dl_x86_feature_1) &= ~cet_feature; + } + + /* Lock CET if IBT or SHSTK is enabled in executable. Don't +- lock CET if SHSTK is enabled permissively. */ +- if (((GL(dl_x86_feature_1)[1] >> CET_MAX) +- & ((1 << CET_MAX) - 1)) +- != CET_PERMISSIVE) ++ lock CET if IBT or SHSTK is enabled permissively. */ ++ if (GL(dl_x86_feature_control).ibt != cet_permissive ++ && GL(dl_x86_feature_control).shstk != cet_permissive) + dl_cet_lock_cet (); + } + # endif +diff --git a/sysdeps/x86/cpu-tunables.c b/sysdeps/x86/cpu-tunables.c +index 69155a8..fad6726 100644 +--- a/sysdeps/x86/cpu-tunables.c ++++ b/sysdeps/x86/cpu-tunables.c +@@ -336,28 +336,18 @@ TUNABLE_CALLBACK (set_hwcaps) (tunable_val_t *valp) + } + + # if CET_ENABLED +-# include + + attribute_hidden + void + TUNABLE_CALLBACK (set_x86_ibt) (tunable_val_t *valp) + { + if (DEFAULT_MEMCMP (valp->strval, "on", sizeof ("on")) == 0) +- { +- GL(dl_x86_feature_1)[1] &= ~((1 << CET_MAX) - 1); +- GL(dl_x86_feature_1)[1] |= CET_ALWAYS_ON; +- } ++ GL(dl_x86_feature_control).ibt = cet_always_on; + else if (DEFAULT_MEMCMP (valp->strval, "off", sizeof ("off")) == 0) +- { +- GL(dl_x86_feature_1)[1] &= ~((1 << CET_MAX) - 1); +- GL(dl_x86_feature_1)[1] |= CET_ALWAYS_OFF; +- } ++ GL(dl_x86_feature_control).ibt = cet_always_off; + else if (DEFAULT_MEMCMP (valp->strval, "permissive", + sizeof ("permissive")) == 0) +- { +- GL(dl_x86_feature_1)[1] &= ~((1 << CET_MAX) - 1); +- GL(dl_x86_feature_1)[1] |= CET_PERMISSIVE; +- } ++ GL(dl_x86_feature_control).ibt = cet_permissive; + } + + attribute_hidden +@@ -365,21 +355,12 @@ void + TUNABLE_CALLBACK (set_x86_shstk) (tunable_val_t *valp) + { + if (DEFAULT_MEMCMP (valp->strval, "on", sizeof ("on")) == 0) +- { +- GL(dl_x86_feature_1)[1] &= ~(((1 << CET_MAX) - 1) << CET_MAX); +- GL(dl_x86_feature_1)[1] |= (CET_ALWAYS_ON << CET_MAX); +- } ++ GL(dl_x86_feature_control).shstk = cet_always_on; + else if (DEFAULT_MEMCMP (valp->strval, "off", sizeof ("off")) == 0) +- { +- GL(dl_x86_feature_1)[1] &= ~(((1 << CET_MAX) - 1) << CET_MAX); +- GL(dl_x86_feature_1)[1] |= (CET_ALWAYS_OFF << CET_MAX); +- } ++ GL(dl_x86_feature_control).shstk = cet_always_off; + else if (DEFAULT_MEMCMP (valp->strval, "permissive", + sizeof ("permissive")) == 0) +- { +- GL(dl_x86_feature_1)[1] &= ~(((1 << CET_MAX) - 1) << CET_MAX); +- GL(dl_x86_feature_1)[1] |= (CET_PERMISSIVE << CET_MAX); +- } ++ GL(dl_x86_feature_control).shstk = cet_permissive; + } + # endif + #endif +diff --git a/sysdeps/x86/dl-cet.c b/sysdeps/x86/dl-cet.c +index 627d937..ebc0d57 100644 +--- a/sysdeps/x86/dl-cet.c ++++ b/sysdeps/x86/dl-cet.c +@@ -20,7 +20,6 @@ + #include + #include + #include +-#include + + /* GNU_PROPERTY_X86_FEATURE_1_IBT and GNU_PROPERTY_X86_FEATURE_1_SHSTK + are defined in , which are only available for C sources. +@@ -39,23 +38,23 @@ static void + dl_cet_check (struct link_map *m, const char *program) + { + /* Check how IBT should be enabled. */ +- unsigned int enable_ibt_type +- = GL(dl_x86_feature_1)[1] & ((1 << CET_MAX) - 1); ++ enum dl_x86_cet_control enable_ibt_type ++ = GL(dl_x86_feature_control).ibt; + /* Check how SHSTK should be enabled. */ +- unsigned int enable_shstk_type +- = ((GL(dl_x86_feature_1)[1] >> CET_MAX) & ((1 << CET_MAX) - 1)); ++ enum dl_x86_cet_control enable_shstk_type ++ = GL(dl_x86_feature_control).shstk; + + /* No legacy object check if both IBT and SHSTK are always on. */ +- if (enable_ibt_type == CET_ALWAYS_ON +- && enable_shstk_type == CET_ALWAYS_ON) ++ if (enable_ibt_type == cet_always_on ++ && enable_shstk_type == cet_always_on) + return; + + /* Check if IBT is enabled by kernel. */ + bool ibt_enabled +- = (GL(dl_x86_feature_1)[0] & GNU_PROPERTY_X86_FEATURE_1_IBT) != 0; ++ = (GL(dl_x86_feature_1) & GNU_PROPERTY_X86_FEATURE_1_IBT) != 0; + /* Check if SHSTK is enabled by kernel. */ + bool shstk_enabled +- = (GL(dl_x86_feature_1)[0] & GNU_PROPERTY_X86_FEATURE_1_SHSTK) != 0; ++ = (GL(dl_x86_feature_1) & GNU_PROPERTY_X86_FEATURE_1_SHSTK) != 0; + + if (ibt_enabled || shstk_enabled) + { +@@ -65,9 +64,9 @@ dl_cet_check (struct link_map *m, const char *program) + + /* Check if IBT and SHSTK are enabled in object. */ + bool enable_ibt = (ibt_enabled +- && enable_ibt_type != CET_ALWAYS_OFF); ++ && enable_ibt_type != cet_always_off); + bool enable_shstk = (shstk_enabled +- && enable_shstk_type != CET_ALWAYS_OFF); ++ && enable_shstk_type != cet_always_off); + if (program) + { + /* Enable IBT and SHSTK only if they are enabled in executable. +@@ -76,10 +75,10 @@ dl_cet_check (struct link_map *m, const char *program) + GLIBC_TUNABLES=glibc.tune.hwcaps=-IBT,-SHSTK + */ + enable_ibt &= (HAS_CPU_FEATURE (IBT) +- && (enable_ibt_type == CET_ALWAYS_ON ++ && (enable_ibt_type == cet_always_on + || (m->l_cet & lc_ibt) != 0)); + enable_shstk &= (HAS_CPU_FEATURE (SHSTK) +- && (enable_shstk_type == CET_ALWAYS_ON ++ && (enable_shstk_type == cet_always_on + || (m->l_cet & lc_shstk) != 0)); + } + +@@ -111,7 +110,7 @@ dl_cet_check (struct link_map *m, const char *program) + + /* IBT is enabled only if it is enabled in executable as + well as all shared objects. */ +- enable_ibt &= (enable_ibt_type == CET_ALWAYS_ON ++ enable_ibt &= (enable_ibt_type == cet_always_on + || (l->l_cet & lc_ibt) != 0); + if (!found_ibt_legacy && enable_ibt != ibt_enabled) + { +@@ -121,7 +120,7 @@ dl_cet_check (struct link_map *m, const char *program) + + /* SHSTK is enabled only if it is enabled in executable as + well as all shared objects. */ +- enable_shstk &= (enable_shstk_type == CET_ALWAYS_ON ++ enable_shstk &= (enable_shstk_type == cet_always_on + || (l->l_cet & lc_shstk) != 0); + if (enable_shstk != shstk_enabled) + { +@@ -137,7 +136,7 @@ dl_cet_check (struct link_map *m, const char *program) + { + if (!program) + { +- if (enable_ibt_type != CET_PERMISSIVE) ++ if (enable_ibt_type != cet_permissive) + { + /* When IBT is enabled, we cannot dlopen a shared + object without IBT. */ +@@ -148,7 +147,7 @@ dl_cet_check (struct link_map *m, const char *program) + N_("rebuild shared object with IBT support enabled")); + } + +- if (enable_shstk_type != CET_PERMISSIVE) ++ if (enable_shstk_type != cet_permissive) + { + /* When SHSTK is enabled, we cannot dlopen a shared + object without SHSTK. */ +@@ -159,8 +158,8 @@ dl_cet_check (struct link_map *m, const char *program) + N_("rebuild shared object with SHSTK support enabled")); + } + +- if (enable_ibt_type != CET_PERMISSIVE +- && enable_shstk_type != CET_PERMISSIVE) ++ if (enable_ibt_type != cet_permissive ++ && enable_shstk_type != cet_permissive) + return; + } + +@@ -190,7 +189,7 @@ dl_cet_check (struct link_map *m, const char *program) + } + + /* Clear the disabled bits in dl_x86_feature_1. */ +- GL(dl_x86_feature_1)[0] &= ~cet_feature; ++ GL(dl_x86_feature_1) &= ~cet_feature; + + cet_feature_changed = true; + } +@@ -199,9 +198,9 @@ dl_cet_check (struct link_map *m, const char *program) + if (program && (ibt_enabled || shstk_enabled)) + { + if ((!ibt_enabled +- || enable_ibt_type != CET_PERMISSIVE) ++ || enable_ibt_type != cet_permissive) + && (!shstk_enabled +- || enable_shstk_type != CET_PERMISSIVE)) ++ || enable_shstk_type != cet_permissive)) + { + /* Lock CET if IBT or SHSTK is enabled in executable unless + IBT or SHSTK is enabled permissively. */ +diff --git a/sysdeps/x86/dl-procruntime.c b/sysdeps/x86/dl-procruntime.c +index 920bfe8..26b2b39 100644 +--- a/sysdeps/x86/dl-procruntime.c ++++ b/sysdeps/x86/dl-procruntime.c +@@ -47,7 +47,27 @@ + # if !defined PROCINFO_DECL && defined SHARED + ._dl_x86_feature_1 + # else +-PROCINFO_CLASS unsigned int _dl_x86_feature_1[2] ++PROCINFO_CLASS unsigned int _dl_x86_feature_1 ++# endif ++# ifndef PROCINFO_DECL ++= 0 ++# endif ++# if !defined SHARED || defined PROCINFO_DECL ++; ++# else ++, ++# endif ++ ++# if !defined PROCINFO_DECL && defined SHARED ++ ._dl_x86_feature_control ++# else ++PROCINFO_CLASS struct dl_x86_feature_control _dl_x86_feature_control ++# endif ++# ifndef PROCINFO_DECL ++= { ++ .ibt = cet_elf_property, ++ .shstk = cet_elf_property ++ } + # endif + # if !defined SHARED || defined PROCINFO_DECL + ; +diff --git a/sysdeps/x86/ldsodefs.h b/sysdeps/x86/ldsodefs.h +index 0616215..54f6864 100644 +--- a/sysdeps/x86/ldsodefs.h ++++ b/sysdeps/x86/ldsodefs.h +@@ -61,6 +61,7 @@ struct La_x32_retval; + struct La_x86_64_retval *, \ + const char *) + ++#include + #include_next + + #endif + diff --git a/SOURCES/glibc-rh1855790-9.patch b/SOURCES/glibc-rh1855790-9.patch new file mode 100644 index 0000000..a4e0e49 --- /dev/null +++ b/SOURCES/glibc-rh1855790-9.patch @@ -0,0 +1,42 @@ +commit 635d6fae03257129b4672591b700a495cb6cb6c7 +Author: H.J. Lu +Date: Sat Feb 1 05:43:34 2020 -0800 + + x86: Don't make 2 calls to dlerror () in a row + + We shouldn't make 2 calls to dlerror () in a row since the first call + will clear the error. We should just use the return value from the + first call. + + Tested on Linux/x86-64. + + Reviewed-by: Florian Weimer +--- + +diff --git a/sysdeps/x86/tst-cet-legacy-5.c b/sysdeps/x86/tst-cet-legacy-5.c +index e1ca09d..0a34d37 100644 +--- a/sysdeps/x86/tst-cet-legacy-5.c ++++ b/sysdeps/x86/tst-cet-legacy-5.c +@@ -39,7 +39,7 @@ do_test_1 (const char *modname, bool fail) + == NULL) + { + printf ("incorrect dlopen '%s' error: %s\n", modname, +- dlerror ()); ++ err); + exit (1); + } + +diff --git a/sysdeps/x86/tst-cet-legacy-6.c b/sysdeps/x86/tst-cet-legacy-6.c +index 184a35b..bd45218 100644 +--- a/sysdeps/x86/tst-cet-legacy-6.c ++++ b/sysdeps/x86/tst-cet-legacy-6.c +@@ -39,7 +39,7 @@ do_test_1 (const char *modname, bool fail) + == NULL) + { + printf ("incorrect dlopen '%s' error: %s\n", modname, +- dlerror ()); ++ err); + exit (1); + } + + diff --git a/SOURCES/glibc-rh1856398.patch b/SOURCES/glibc-rh1856398.patch new file mode 100644 index 0000000..8eebe0b --- /dev/null +++ b/SOURCES/glibc-rh1856398.patch @@ -0,0 +1,25 @@ +commit 16536e98e36e08bc1ce1edbd8dd50c7c3bb7a936 +Author: Florian Weimer +Date: Tue May 12 11:30:30 2020 +0200 + + aarch64: Accept PLT calls to __getauxval within libc.so + + When using outline atomics (-moutline-atomics, the default for ARMv8-A + starting with GCC 10), libgcc contains an ELF constructor which calls + __getauxval. This code is built outside of glibc, so none of its + internal PLT avoidance schemes can be applied to it. This change + suppresses the elf/check-localplt failure. + +diff -rup a/sysdeps/unix/sysv/linux/aarch64/localplt.data b/sysdeps/unix/sysv/linux/aarch64/localplt.data +--- a/sysdeps/unix/sysv/linux/aarch64/localplt.data 2018-08-01 01:10:47.000000000 -0400 ++++ b/sysdeps/unix/sysv/linux/aarch64/localplt.data 2020-10-27 15:55:53.457002541 -0400 +@@ -7,6 +7,9 @@ libc.so: malloc + libc.so: memalign + libc.so: realloc + libm.so: matherr ++# If outline atomics are used, libgcc (built outside of glibc) may ++# call __getauxval using the PLT. ++libc.so: __getauxval ? + # The dynamic loader needs __tls_get_addr for TLS. + ld.so: __tls_get_addr + # The main malloc is interposed into the dynamic linker, for diff --git a/SOURCES/glibc-rh1868106-1.patch b/SOURCES/glibc-rh1868106-1.patch new file mode 100644 index 0000000..1469c9b --- /dev/null +++ b/SOURCES/glibc-rh1868106-1.patch @@ -0,0 +1,62 @@ +Partial backport of: + +commit 333221862ecbebde60dd16e7ca17d26444e62f50 +Author: Florian Weimer +Date: Mon Apr 8 11:19:38 2019 +0200 + + resolv: Remove RES_INSECURE1, RES_INSECURE2 + + Always perform the associated security checks. + +The constants and their debug output handling are preserve in this +backport. + +diff --git a/resolv/res_send.c b/resolv/res_send.c +index 705ecb7189d215c2..c9b02cca130bc20d 100644 +--- a/resolv/res_send.c ++++ b/resolv/res_send.c +@@ -1324,31 +1324,25 @@ send_dg(res_state statp, + */ + goto wait; + } +- if (!(statp->options & RES_INSECURE1) && +- !res_ourserver_p(statp, &from)) { +- /* +- * response from wrong server? ignore it. +- * XXX - potential security hazard could +- * be detected here. +- */ +- goto wait; +- } +- if (!(statp->options & RES_INSECURE2) +- && (recvresp1 || !res_queriesmatch(buf, buf + buflen, ++ ++ /* Paranoia check. Due to the connected UDP socket, ++ the kernel has already filtered invalid addresses ++ for us. */ ++ if (!res_ourserver_p(statp, &from)) ++ goto wait; ++ ++ /* Check for the correct header layout and a matching ++ question. */ ++ if ((recvresp1 || !res_queriesmatch(buf, buf + buflen, + *thisansp, + *thisansp + + *thisanssizp)) + && (recvresp2 || !res_queriesmatch(buf2, buf2 + buflen2, + *thisansp, + *thisansp +- + *thisanssizp))) { +- /* +- * response contains wrong query? ignore it. +- * XXX - potential security hazard could +- * be detected here. +- */ +- goto wait; +- } ++ + *thisanssizp))) ++ goto wait; ++ + if (anhp->rcode == SERVFAIL || + anhp->rcode == NOTIMP || + anhp->rcode == REFUSED) { diff --git a/SOURCES/glibc-rh1868106-2.patch b/SOURCES/glibc-rh1868106-2.patch new file mode 100644 index 0000000..a1e5bc9 --- /dev/null +++ b/SOURCES/glibc-rh1868106-2.patch @@ -0,0 +1,51 @@ +Backport the support/ changes from this commit, to avoid future +conflicts: + +commit 446997ff1433d33452b81dfa9e626b8dccf101a4 +Author: Florian Weimer +Date: Wed Oct 30 17:26:58 2019 +0100 + + resolv: Implement trust-ad option for /etc/resolv.conf [BZ #20358] + + This introduces a concept of trusted name servers, for which the + AD bit is passed through to applications. For untrusted name + servers (the default), the AD bit in responses are cleared, to + provide a safe default. + + This approach is very similar to the one suggested by Pavel Šimerda + in . + + The DNS test framework in support/ is enhanced with support for + setting the AD bit in responses. + + Tested on x86_64-linux-gnu. + + Change-Id: Ibfe0f7c73ea221c35979842c5c3b6ed486495ccc + +diff --git a/support/resolv_test.c b/support/resolv_test.c +index 3f2a09f36f445878..28af227cb5ed901c 100644 +--- a/support/resolv_test.c ++++ b/support/resolv_test.c +@@ -182,6 +182,8 @@ resolv_response_init (struct resolv_response_builder *b, + if (flags.tc) + b->buffer[2] |= 0x02; + b->buffer[3] = 0x80 | flags.rcode; /* Always set RA. */ ++ if (flags.ad) ++ b->buffer[3] |= 0x20; + + /* Fill in the initial section count values. */ + b->buffer[4] = flags.qdcount >> 8; +diff --git a/support/resolv_test.h b/support/resolv_test.h +index 4c2e6c1b417f5fcd..be736aead40cd0cc 100644 +--- a/support/resolv_test.h ++++ b/support/resolv_test.h +@@ -134,6 +134,9 @@ struct resolv_response_flags + /* If true, the TC (truncation) flag will be set. */ + bool tc; + ++ /* If true, the AD (authenticated data) flag will be set. */ ++ bool ad; ++ + /* Initial section count values. Can be used to artificially + increase the counts, for malformed packet testing.*/ + unsigned short qdcount; diff --git a/SOURCES/glibc-rh1868106-3.patch b/SOURCES/glibc-rh1868106-3.patch new file mode 100644 index 0000000..dc3c8ea --- /dev/null +++ b/SOURCES/glibc-rh1868106-3.patch @@ -0,0 +1,293 @@ +commit 873e239a4c3d8ec235c27439c1bdc5bbf8aa1818 +Author: Florian Weimer +Date: Wed Oct 14 10:54:39 2020 +0200 + + support: Provide a way to reorder responses within the DNS test server + +diff --git a/support/Makefile b/support/Makefile +index 3c940aa6a7bdfc99..37d5dcc92a5c6dee 100644 +--- a/support/Makefile ++++ b/support/Makefile +@@ -35,6 +35,8 @@ libsupport-routines = \ + ignore_stderr \ + next_to_fault \ + oom_error \ ++ resolv_response_context_duplicate \ ++ resolv_response_context_free \ + resolv_test \ + set_fortify_handler \ + support-xfstat \ +diff --git a/support/resolv_response_context_duplicate.c b/support/resolv_response_context_duplicate.c +new file mode 100644 +index 0000000000000000..f9c5c3462ad053ec +--- /dev/null ++++ b/support/resolv_response_context_duplicate.c +@@ -0,0 +1,37 @@ ++/* Duplicate a response context used in DNS resolver tests. ++ 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 ++ ++struct resolv_response_context * ++resolv_response_context_duplicate (const struct resolv_response_context *ctx) ++{ ++ struct resolv_response_context *result = xmalloc (sizeof (*result)); ++ memcpy (result, ctx, sizeof (*result)); ++ if (result->client_address != NULL) ++ { ++ result->client_address = xmalloc (result->client_address_length); ++ memcpy (result->client_address, ctx->client_address, ++ result->client_address_length); ++ } ++ result->query_buffer = xmalloc (result->query_length); ++ memcpy (result->query_buffer, ctx->query_buffer, result->query_length); ++ return result; ++} +diff --git a/support/resolv_response_context_free.c b/support/resolv_response_context_free.c +new file mode 100644 +index 0000000000000000..b88c05ffd4acfdd4 +--- /dev/null ++++ b/support/resolv_response_context_free.c +@@ -0,0 +1,28 @@ ++/* Free a response context used in DNS resolver tests. ++ 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 ++ ++void ++resolv_response_context_free (struct resolv_response_context *ctx) ++{ ++ free (ctx->query_buffer); ++ free (ctx->client_address); ++ free (ctx); ++} +diff --git a/support/resolv_test.c b/support/resolv_test.c +index 28af227cb5ed901c..8cca4e6cf723de28 100644 +--- a/support/resolv_test.c ++++ b/support/resolv_test.c +@@ -434,9 +434,9 @@ resolv_response_buffer (const struct resolv_response_builder *b) + return result; + } + +-static struct resolv_response_builder * +-response_builder_allocate +- (const unsigned char *query_buffer, size_t query_length) ++struct resolv_response_builder * ++resolv_response_builder_allocate (const unsigned char *query_buffer, ++ size_t query_length) + { + struct resolv_response_builder *b = xmalloc (sizeof (*b)); + memset (b, 0, offsetof (struct resolv_response_builder, buffer)); +@@ -445,8 +445,8 @@ response_builder_allocate + return b; + } + +-static void +-response_builder_free (struct resolv_response_builder *b) ++void ++resolv_response_builder_free (struct resolv_response_builder *b) + { + tdestroy (b->compression_offsets, free); + free (b); +@@ -661,13 +661,17 @@ server_thread_udp_process_one (struct resolv_test *obj, int server_index) + + struct resolv_response_context ctx = + { ++ .test = obj, ++ .client_address = &peer, ++ .client_address_length = peerlen, + .query_buffer = query, + .query_length = length, + .server_index = server_index, + .tcp = false, + .edns = qinfo.edns, + }; +- struct resolv_response_builder *b = response_builder_allocate (query, length); ++ struct resolv_response_builder *b ++ = resolv_response_builder_allocate (query, length); + obj->config.response_callback + (&ctx, b, qinfo.qname, qinfo.qclass, qinfo.qtype); + +@@ -684,7 +688,7 @@ server_thread_udp_process_one (struct resolv_test *obj, int server_index) + if (b->offset >= 12) + printf ("info: UDP server %d: sending response:" + " %zu bytes, RCODE %d (for %s/%u/%u)\n", +- server_index, b->offset, b->buffer[3] & 0x0f, ++ ctx.server_index, b->offset, b->buffer[3] & 0x0f, + qinfo.qname, qinfo.qclass, qinfo.qtype); + else + printf ("info: UDP server %d: sending response: %zu bytes" +@@ -694,23 +698,31 @@ server_thread_udp_process_one (struct resolv_test *obj, int server_index) + if (b->truncate_bytes > 0) + printf ("info: truncated by %u bytes\n", b->truncate_bytes); + } +- size_t to_send = b->offset; +- if (to_send < b->truncate_bytes) +- to_send = 0; +- else +- to_send -= b->truncate_bytes; +- +- /* Ignore most errors here because the other end may have closed +- the socket. */ +- if (sendto (obj->servers[server_index].socket_udp, +- b->buffer, to_send, 0, +- (struct sockaddr *) &peer, peerlen) < 0) +- TEST_VERIFY_EXIT (errno != EBADF); ++ resolv_response_send_udp (&ctx, b); + } +- response_builder_free (b); ++ resolv_response_builder_free (b); + return true; + } + ++void ++resolv_response_send_udp (const struct resolv_response_context *ctx, ++ struct resolv_response_builder *b) ++{ ++ TEST_VERIFY_EXIT (!ctx->tcp); ++ size_t to_send = b->offset; ++ if (to_send < b->truncate_bytes) ++ to_send = 0; ++ else ++ to_send -= b->truncate_bytes; ++ ++ /* Ignore most errors here because the other end may have closed ++ the socket. */ ++ if (sendto (ctx->test->servers[ctx->server_index].socket_udp, ++ b->buffer, to_send, 0, ++ ctx->client_address, ctx->client_address_length) < 0) ++ TEST_VERIFY_EXIT (errno != EBADF); ++} ++ + /* UDP thread_callback function. Variant for one thread per + server. */ + static void +@@ -897,14 +909,15 @@ server_thread_tcp_client (void *arg) + + struct resolv_response_context ctx = + { ++ .test = closure->obj, + .query_buffer = query_buffer, + .query_length = query_length, + .server_index = closure->server_index, + .tcp = true, + .edns = qinfo.edns, + }; +- struct resolv_response_builder *b = response_builder_allocate +- (query_buffer, query_length); ++ struct resolv_response_builder *b ++ = resolv_response_builder_allocate (query_buffer, query_length); + closure->obj->config.response_callback + (&ctx, b, qinfo.qname, qinfo.qclass, qinfo.qtype); + +@@ -936,7 +949,7 @@ server_thread_tcp_client (void *arg) + writev_fully (closure->client_socket, buffers, 2); + } + bool close_flag = b->close; +- response_builder_free (b); ++ resolv_response_builder_free (b); + free (query_buffer); + if (close_flag) + break; +diff --git a/support/resolv_test.h b/support/resolv_test.h +index be736aead40cd0cc..ff5571dace92c936 100644 +--- a/support/resolv_test.h ++++ b/support/resolv_test.h +@@ -35,25 +35,36 @@ struct resolv_edns_info + uint16_t payload_size; + }; + ++/* This opaque struct collects information about the resolver testing ++ currently in progress. */ ++struct resolv_test; ++ + /* This struct provides context information when the response callback + specified in struct resolv_redirect_config is invoked. */ + struct resolv_response_context + { +- const unsigned char *query_buffer; ++ struct resolv_test *test; ++ void *client_address; ++ size_t client_address_length; ++ unsigned char *query_buffer; + size_t query_length; + int server_index; + bool tcp; + struct resolv_edns_info edns; + }; + ++/* Produces a deep copy of the context. */ ++struct resolv_response_context * ++ resolv_response_context_duplicate (const struct resolv_response_context *); ++ ++/* Frees the copy. For the context passed to the response function, ++ this happens implicitly. */ ++void resolv_response_context_free (struct resolv_response_context *); ++ + /* This opaque struct is used to construct responses from within the + response callback function. */ + struct resolv_response_builder; + +-/* This opaque struct collects information about the resolver testing +- currently in progress. */ +-struct resolv_test; +- + enum + { + /* Maximum number of test servers supported by the framework. */ +@@ -188,6 +199,22 @@ void resolv_response_close (struct resolv_response_builder *); + /* The size of the response packet built so far. */ + size_t resolv_response_length (const struct resolv_response_builder *); + ++/* Allocates a response builder tied to a specific query packet, ++ starting at QUERY_BUFFER, containing QUERY_LENGTH bytes. */ ++struct resolv_response_builder * ++ resolv_response_builder_allocate (const unsigned char *query_buffer, ++ size_t query_length); ++ ++/* Deallocates a response buffer. */ ++void resolv_response_builder_free (struct resolv_response_builder *); ++ ++/* Sends a UDP response using a specific context. This can be used to ++ reorder or duplicate responses, along with ++ resolv_response_context_duplicate and ++ response_builder_allocate. */ ++void resolv_response_send_udp (const struct resolv_response_context *, ++ struct resolv_response_builder *); ++ + __END_DECLS + + #endif /* SUPPORT_RESOLV_TEST_H */ diff --git a/SOURCES/glibc-rh1868106-4.patch b/SOURCES/glibc-rh1868106-4.patch new file mode 100644 index 0000000..7559a15 --- /dev/null +++ b/SOURCES/glibc-rh1868106-4.patch @@ -0,0 +1,36 @@ +commit 08443b19965f48862b02c2fd7b33a39d66daf2ff +Author: Florian Weimer +Date: Wed Oct 14 10:54:39 2020 +0200 + + support: Provide a way to clear the RA bit in DNS server responses + +diff --git a/support/resolv_test.c b/support/resolv_test.c +index 8cca4e6cf723de28..9323f1d55b0be8f1 100644 +--- a/support/resolv_test.c ++++ b/support/resolv_test.c +@@ -181,7 +181,9 @@ resolv_response_init (struct resolv_response_builder *b, + b->buffer[2] |= b->query_buffer[2] & 0x01; /* Copy the RD bit. */ + if (flags.tc) + b->buffer[2] |= 0x02; +- b->buffer[3] = 0x80 | flags.rcode; /* Always set RA. */ ++ b->buffer[3] = flags.rcode; ++ if (!flags.clear_ra) ++ b->buffer[3] |= 0x80; + if (flags.ad) + b->buffer[3] |= 0x20; + +diff --git a/support/resolv_test.h b/support/resolv_test.h +index ff5571dace92c936..825abb9ff2897a43 100644 +--- a/support/resolv_test.h ++++ b/support/resolv_test.h +@@ -148,6 +148,10 @@ struct resolv_response_flags + /* If true, the AD (authenticated data) flag will be set. */ + bool ad; + ++ /* If true, do not set the RA (recursion available) flag in the ++ response. */ ++ bool clear_ra; ++ + /* Initial section count values. Can be used to artificially + increase the counts, for malformed packet testing.*/ + unsigned short qdcount; diff --git a/SOURCES/glibc-rh1868106-5.patch b/SOURCES/glibc-rh1868106-5.patch new file mode 100644 index 0000000..d5848b6 --- /dev/null +++ b/SOURCES/glibc-rh1868106-5.patch @@ -0,0 +1,442 @@ +commit f1f00c072138af90ae6da180f260111f09afe7a3 +Author: Florian Weimer +Date: Wed Oct 14 10:54:39 2020 +0200 + + resolv: Handle transaction ID collisions in parallel queries (bug 26600) + + If the transaction IDs are equal, the old check attributed both + responses to the first query, not recognizing the second response. + This fixes bug 26600. + +diff --git a/resolv/Makefile b/resolv/Makefile +index 72a0f196506ac489..cee5225f8933f245 100644 +--- a/resolv/Makefile ++++ b/resolv/Makefile +@@ -62,6 +62,11 @@ tests += \ + tst-resolv-search \ + tst-resolv-trailing \ + ++# This test calls __res_context_send directly, which is not exported ++# from libresolv. ++tests-internal += tst-resolv-txnid-collision ++tests-static += tst-resolv-txnid-collision ++ + # These tests need libdl. + ifeq (yes,$(build-shared)) + tests += \ +@@ -202,6 +207,8 @@ $(objpfx)tst-resolv-search: $(objpfx)libresolv.so $(shared-thread-library) + $(objpfx)tst-resolv-trailing: $(objpfx)libresolv.so $(shared-thread-library) + $(objpfx)tst-resolv-threads: \ + $(libdl) $(objpfx)libresolv.so $(shared-thread-library) ++$(objpfx)tst-resolv-txnid-collision: $(objpfx)libresolv.a \ ++ $(static-thread-library) + $(objpfx)tst-resolv-canonname: \ + $(libdl) $(objpfx)libresolv.so $(shared-thread-library) + +diff --git a/resolv/res_send.c b/resolv/res_send.c +index c9b02cca130bc20d..ac19627634281c2f 100644 +--- a/resolv/res_send.c ++++ b/resolv/res_send.c +@@ -1315,15 +1315,6 @@ send_dg(res_state statp, + *terrno = EMSGSIZE; + return close_and_return_error (statp, resplen2); + } +- if ((recvresp1 || hp->id != anhp->id) +- && (recvresp2 || hp2->id != anhp->id)) { +- /* +- * response from old query, ignore it. +- * XXX - potential security hazard could +- * be detected here. +- */ +- goto wait; +- } + + /* Paranoia check. Due to the connected UDP socket, + the kernel has already filtered invalid addresses +@@ -1333,15 +1324,24 @@ send_dg(res_state statp, + + /* Check for the correct header layout and a matching + question. */ +- if ((recvresp1 || !res_queriesmatch(buf, buf + buflen, +- *thisansp, +- *thisansp +- + *thisanssizp)) +- && (recvresp2 || !res_queriesmatch(buf2, buf2 + buflen2, +- *thisansp, +- *thisansp +- + *thisanssizp))) +- goto wait; ++ int matching_query = 0; /* Default to no matching query. */ ++ if (!recvresp1 ++ && anhp->id == hp->id ++ && res_queriesmatch (buf, buf + buflen, ++ *thisansp, *thisansp + *thisanssizp)) ++ matching_query = 1; ++ if (!recvresp2 ++ && anhp->id == hp2->id ++ && res_queriesmatch (buf2, buf2 + buflen2, ++ *thisansp, *thisansp + *thisanssizp)) ++ matching_query = 2; ++ if (matching_query == 0) ++ /* Spurious UDP packet. Drop it and continue ++ waiting. */ ++ { ++ need_recompute = 1; ++ goto wait; ++ } + + if (anhp->rcode == SERVFAIL || + anhp->rcode == NOTIMP || +@@ -1356,7 +1356,7 @@ send_dg(res_state statp, + /* No data from the first reply. */ + resplen = 0; + /* We are waiting for a possible second reply. */ +- if (hp->id == anhp->id) ++ if (matching_query == 1) + recvresp1 = 1; + else + recvresp2 = 1; +@@ -1387,7 +1387,7 @@ send_dg(res_state statp, + return (1); + } + /* Mark which reply we received. */ +- if (recvresp1 == 0 && hp->id == anhp->id) ++ if (matching_query == 1) + recvresp1 = 1; + else + recvresp2 = 1; +diff --git a/resolv/tst-resolv-txnid-collision.c b/resolv/tst-resolv-txnid-collision.c +new file mode 100644 +index 0000000000000000..611d37362f3e5e89 +--- /dev/null ++++ b/resolv/tst-resolv-txnid-collision.c +@@ -0,0 +1,329 @@ ++/* Test parallel queries with transaction ID collisions. ++ 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 ++#include ++#include ++#include ++ ++/* Result of parsing a DNS question name. ++ ++ A question name has the form reorder-N-M-rcode-C.example.net, where ++ N and M are either 0 and 1, corresponding to the reorder member, ++ and C is a number that will be stored in the rcode field. ++ ++ Also see parse_qname below. */ ++struct parsed_qname ++{ ++ /* The DNS response code requested from the first server. The ++ second server always responds with RCODE zero. */ ++ int rcode; ++ ++ /* Indicates whether to perform reordering in the responses from the ++ respective server. */ ++ bool reorder[2]; ++}; ++ ++/* Fills *PARSED based on QNAME. */ ++static void ++parse_qname (struct parsed_qname *parsed, const char *qname) ++{ ++ int reorder0; ++ int reorder1; ++ int rcode; ++ char *suffix; ++ if (sscanf (qname, "reorder-%d-%d.rcode-%d.%ms", ++ &reorder0, &reorder1, &rcode, &suffix) == 4) ++ { ++ if (reorder0 != 0) ++ TEST_COMPARE (reorder0, 1); ++ if (reorder1 != 0) ++ TEST_COMPARE (reorder1, 1); ++ TEST_VERIFY (rcode >= 0 && rcode <= 15); ++ TEST_COMPARE_STRING (suffix, "example.net"); ++ free (suffix); ++ ++ parsed->rcode = rcode; ++ parsed->reorder[0] = reorder0; ++ parsed->reorder[1] = reorder1; ++ } ++ else ++ FAIL_EXIT1 ("unexpected query: %s", qname); ++} ++ ++/* Used to construct a response. The first server responds with an ++ error, the second server succeeds. */ ++static void ++build_response (const struct resolv_response_context *ctx, ++ struct resolv_response_builder *b, ++ const char *qname, uint16_t qclass, uint16_t qtype) ++{ ++ struct parsed_qname parsed; ++ parse_qname (&parsed, qname); ++ ++ switch (ctx->server_index) ++ { ++ case 0: ++ { ++ struct resolv_response_flags flags = { 0 }; ++ if (parsed.rcode == 0) ++ /* Simulate a delegation in case a NODATA (RCODE zero) ++ response is requested. */ ++ flags.clear_ra = true; ++ else ++ flags.rcode = parsed.rcode; ++ ++ resolv_response_init (b, flags); ++ resolv_response_add_question (b, qname, qclass, qtype); ++ } ++ break; ++ ++ case 1: ++ { ++ struct resolv_response_flags flags = { 0, }; ++ resolv_response_init (b, flags); ++ resolv_response_add_question (b, qname, qclass, qtype); ++ ++ resolv_response_section (b, ns_s_an); ++ resolv_response_open_record (b, qname, qclass, qtype, 0); ++ if (qtype == T_A) ++ { ++ char ipv4[4] = { 192, 0, 2, 1 }; ++ resolv_response_add_data (b, &ipv4, sizeof (ipv4)); ++ } ++ else ++ { ++ char ipv6[16] ++ = { 0x20, 0x01, 0xd, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }; ++ resolv_response_add_data (b, &ipv6, sizeof (ipv6)); ++ } ++ resolv_response_close_record (b); ++ } ++ break; ++ } ++} ++ ++/* Used to reorder responses. */ ++struct resolv_response_context *previous_query; ++ ++/* Used to keep track of the queries received. */ ++static int previous_server_index = -1; ++static uint16_t previous_qtype; ++ ++/* For each server, buffer the first query and then send both answers ++ to the second query, reordered if requested. */ ++static void ++response (const struct resolv_response_context *ctx, ++ struct resolv_response_builder *b, ++ const char *qname, uint16_t qclass, uint16_t qtype) ++{ ++ TEST_VERIFY (qtype == T_A || qtype == T_AAAA); ++ if (ctx->server_index != 0) ++ TEST_COMPARE (ctx->server_index, 1); ++ ++ struct parsed_qname parsed; ++ parse_qname (&parsed, qname); ++ ++ if (previous_query == NULL) ++ { ++ /* No buffered query. Record this query and do not send a ++ response. */ ++ TEST_COMPARE (previous_qtype, 0); ++ previous_query = resolv_response_context_duplicate (ctx); ++ previous_qtype = qtype; ++ resolv_response_drop (b); ++ previous_server_index = ctx->server_index; ++ ++ if (test_verbose) ++ printf ("info: buffering first query for: %s\n", qname); ++ } ++ else ++ { ++ TEST_VERIFY (previous_query != 0); ++ TEST_COMPARE (ctx->server_index, previous_server_index); ++ TEST_VERIFY (previous_qtype != qtype); /* Not a duplicate. */ ++ ++ /* If reordering, send a response for this query explicitly, and ++ then skip the implicit send. */ ++ if (parsed.reorder[ctx->server_index]) ++ { ++ if (test_verbose) ++ printf ("info: sending reordered second response for: %s\n", ++ qname); ++ build_response (ctx, b, qname, qclass, qtype); ++ resolv_response_send_udp (ctx, b); ++ resolv_response_drop (b); ++ } ++ ++ /* Build a response for the previous query and send it, thus ++ reordering the two responses. */ ++ { ++ if (test_verbose) ++ printf ("info: sending first response for: %s\n", qname); ++ struct resolv_response_builder *btmp ++ = resolv_response_builder_allocate (previous_query->query_buffer, ++ previous_query->query_length); ++ build_response (ctx, btmp, qname, qclass, previous_qtype); ++ resolv_response_send_udp (ctx, btmp); ++ resolv_response_builder_free (btmp); ++ } ++ ++ /* If not reordering, send the reply as usual. */ ++ if (!parsed.reorder[ctx->server_index]) ++ { ++ if (test_verbose) ++ printf ("info: sending non-reordered second response for: %s\n", ++ qname); ++ build_response (ctx, b, qname, qclass, qtype); ++ } ++ ++ /* Unbuffer the response and prepare for the next query. */ ++ resolv_response_context_free (previous_query); ++ previous_query = NULL; ++ previous_qtype = 0; ++ previous_server_index = -1; ++ } ++} ++ ++/* Runs a query for QNAME and checks for the expected reply. See ++ struct parsed_qname for the expected format for QNAME. */ ++static void ++test_qname (const char *qname, int rcode) ++{ ++ struct resolv_context *ctx = __resolv_context_get (); ++ TEST_VERIFY_EXIT (ctx != NULL); ++ ++ unsigned char q1[512]; ++ int q1len = res_mkquery (QUERY, qname, C_IN, T_A, NULL, 0, NULL, ++ q1, sizeof (q1)); ++ TEST_VERIFY_EXIT (q1len > 12); ++ ++ unsigned char q2[512]; ++ int q2len = res_mkquery (QUERY, qname, C_IN, T_AAAA, NULL, 0, NULL, ++ q2, sizeof (q2)); ++ TEST_VERIFY_EXIT (q2len > 12); ++ ++ /* Produce a transaction ID collision. */ ++ memcpy (q2, q1, 2); ++ ++ unsigned char ans1[512]; ++ unsigned char *ans1p = ans1; ++ unsigned char *ans2p = NULL; ++ int nans2p = 0; ++ int resplen2 = 0; ++ int ans2p_malloced = 0; ++ ++ /* Perform a parallel A/AAAA query. */ ++ int resplen1 = __res_context_send (ctx, q1, q1len, q2, q2len, ++ ans1, sizeof (ans1), &ans1p, ++ &ans2p, &nans2p, ++ &resplen2, &ans2p_malloced); ++ ++ TEST_VERIFY (resplen1 > 12); ++ TEST_VERIFY (resplen2 > 12); ++ if (resplen1 <= 12 || resplen2 <= 12) ++ return; ++ ++ if (rcode == 1 || rcode == 3) ++ { ++ /* Format Error and Name Error responses does not trigger ++ switching to the next server. */ ++ TEST_COMPARE (ans1p[3] & 0x0f, rcode); ++ TEST_COMPARE (ans2p[3] & 0x0f, rcode); ++ return; ++ } ++ ++ /* The response should be successful. */ ++ TEST_COMPARE (ans1p[3] & 0x0f, 0); ++ TEST_COMPARE (ans2p[3] & 0x0f, 0); ++ ++ /* Due to bug 19691, the answer may not be in the slot matching the ++ query. Assume that the AAAA response is the longer one. */ ++ unsigned char *a_answer; ++ int a_answer_length; ++ unsigned char *aaaa_answer; ++ int aaaa_answer_length; ++ if (resplen2 > resplen1) ++ { ++ a_answer = ans1p; ++ a_answer_length = resplen1; ++ aaaa_answer = ans2p; ++ aaaa_answer_length = resplen2; ++ } ++ else ++ { ++ a_answer = ans2p; ++ a_answer_length = resplen2; ++ aaaa_answer = ans1p; ++ aaaa_answer_length = resplen1; ++ } ++ ++ { ++ char *expected = xasprintf ("name: %s\n" ++ "address: 192.0.2.1\n", ++ qname); ++ check_dns_packet (qname, a_answer, a_answer_length, expected); ++ free (expected); ++ } ++ { ++ char *expected = xasprintf ("name: %s\n" ++ "address: 2001:db8::1\n", ++ qname); ++ check_dns_packet (qname, aaaa_answer, aaaa_answer_length, expected); ++ free (expected); ++ } ++ ++ if (ans2p_malloced) ++ free (ans2p); ++ ++ __resolv_context_put (ctx); ++} ++ ++static int ++do_test (void) ++{ ++ struct resolv_test *aux = resolv_test_start ++ ((struct resolv_redirect_config) ++ { ++ .response_callback = response, ++ }); ++ ++ for (int rcode = 0; rcode <= 5; ++rcode) ++ for (int do_reorder_0 = 0; do_reorder_0 < 2; ++do_reorder_0) ++ for (int do_reorder_1 = 0; do_reorder_1 < 2; ++do_reorder_1) ++ { ++ char *qname = xasprintf ("reorder-%d-%d.rcode-%d.example.net", ++ do_reorder_0, do_reorder_1, rcode); ++ test_qname (qname, rcode); ++ free (qname); ++ } ++ ++ resolv_test_end (aux); ++ ++ return 0; ++} ++ ++#include diff --git a/SOURCES/glibc-rh1868106-6.patch b/SOURCES/glibc-rh1868106-6.patch new file mode 100644 index 0000000..c85bafe --- /dev/null +++ b/SOURCES/glibc-rh1868106-6.patch @@ -0,0 +1,31 @@ +commit b8b53b338f6da91e86d115a39da860cefac736ad +Author: Florian Weimer +Date: Thu Oct 15 12:33:13 2020 +0200 + + resolv: Serialize processing in resolv/tst-resolv-txnid-collision + + When switching name servers, response processing by two server + threads clobbers the global test state. (There is still some + risk that this test is negatively impact by packet drops and + packet reordering, but this applies to many of the resolver tests + and is difficult to avoid.) + + Fixes commit f1f00c072138af90ae6da180f260111f09afe7a3 ("resolv: + Handle transaction ID collisions in parallel queries (bug 26600)"). + +diff --git a/resolv/tst-resolv-txnid-collision.c b/resolv/tst-resolv-txnid-collision.c +index 611d37362f3e5e89..189b76f1268f4e4d 100644 +--- a/resolv/tst-resolv-txnid-collision.c ++++ b/resolv/tst-resolv-txnid-collision.c +@@ -309,6 +309,11 @@ do_test (void) + ((struct resolv_redirect_config) + { + .response_callback = response, ++ ++ /* The response callback use global state (the previous_* ++ variables), and query processing must therefore be ++ serialized. */ ++ .single_thread_udp = true, + }); + + for (int rcode = 0; rcode <= 5; ++rcode) diff --git a/SOURCES/glibc-rh1871383-1.patch b/SOURCES/glibc-rh1871383-1.patch new file mode 100644 index 0000000..67c88fd --- /dev/null +++ b/SOURCES/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/SOURCES/glibc-rh1871383-2.patch b/SOURCES/glibc-rh1871383-2.patch new file mode 100644 index 0000000..0313dbb --- /dev/null +++ b/SOURCES/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/SOURCES/glibc-rh1871383-3.patch b/SOURCES/glibc-rh1871383-3.patch new file mode 100644 index 0000000..e5a18e8 --- /dev/null +++ b/SOURCES/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/SOURCES/glibc-rh1871383-4.patch b/SOURCES/glibc-rh1871383-4.patch new file mode 100644 index 0000000..cac8349 --- /dev/null +++ b/SOURCES/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/SOURCES/glibc-rh1871383-5.patch b/SOURCES/glibc-rh1871383-5.patch new file mode 100644 index 0000000..bc51a1e --- /dev/null +++ b/SOURCES/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/SOURCES/glibc-rh1871383-6.patch b/SOURCES/glibc-rh1871383-6.patch new file mode 100644 index 0000000..b21971a --- /dev/null +++ b/SOURCES/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/SOURCES/glibc-rh1871383-7.patch b/SOURCES/glibc-rh1871383-7.patch new file mode 100644 index 0000000..61d11c4 --- /dev/null +++ b/SOURCES/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/SOURCES/glibc-rh1871386-1.patch b/SOURCES/glibc-rh1871386-1.patch new file mode 100644 index 0000000..5cd3074 --- /dev/null +++ b/SOURCES/glibc-rh1871386-1.patch @@ -0,0 +1,20 @@ +commit 0798b8ecc8da8667362496c1217d18635106c609 +Author: Vineet Gupta +Date: Wed Apr 8 19:56:12 2020 -0700 + + ARC: Update syscall-names.list for ARC specific syscalls + +diff --git a/sysdeps/unix/sysv/linux/syscall-names.list b/sysdeps/unix/sysv/linux/syscall-names.list +index 314a653938..21a62a06f4 100644 +--- a/sysdeps/unix/sysv/linux/syscall-names.list ++++ b/sysdeps/unix/sysv/linux/syscall-names.list +@@ -41,6 +41,9 @@ adjtimex + afs_syscall + alarm + alloc_hugepages ++arc_gettls ++arc_settls ++arc_usr_cmpxchg + arch_prctl + arm_fadvise64_64 + arm_sync_file_range diff --git a/SOURCES/glibc-rh1871386-2.patch b/SOURCES/glibc-rh1871386-2.patch new file mode 100644 index 0000000..d89c08d --- /dev/null +++ b/SOURCES/glibc-rh1871386-2.patch @@ -0,0 +1,26 @@ +commit b67339d0bbc07911859ca8c488e1923441cd3c33 +Author: Joseph Myers +Date: Mon Jun 15 22:58:22 2020 +0000 + + Update syscall-names.list for Linux 5.7. + + Linux 5.7 has no new syscalls. Update the version number in + syscall-names.list to reflect that it is still current for 5.7. + + Tested with build-many-glibcs.py. + +diff --git a/sysdeps/unix/sysv/linux/syscall-names.list b/sysdeps/unix/sysv/linux/syscall-names.list +index 21a62a06f4..15dec5b98f 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.6. +-kernel 5.6 ++# The list of system calls is current as of Linux 5.7. ++kernel 5.7 + + FAST_atomic_update + FAST_cmpxchg diff --git a/SOURCES/glibc-rh1871386-3.patch b/SOURCES/glibc-rh1871386-3.patch new file mode 100644 index 0000000..09bd048 --- /dev/null +++ b/SOURCES/glibc-rh1871386-3.patch @@ -0,0 +1,37 @@ +commit 1cfb4715288845ebc55ad664421b48b32de9599c +Author: Joseph Myers +Date: Fri Aug 7 14:38:43 2020 +0000 + + Update syscall lists for Linux 5.8. + + Linux 5.8 has one new syscall, faccessat2. 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 for RHEL 8.5.0. + +diff --git a/sysdeps/unix/sysv/linux/syscall-names.list b/sysdeps/unix/sysv/linux/syscall-names.list +index 15dec5b98f..a462318ecf 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.7. +-kernel 5.7 ++# The list of system calls is current as of Linux 5.8. ++kernel 5.8 + + FAST_atomic_update + FAST_cmpxchg +@@ -105,6 +105,7 @@ execveat + exit + exit_group + faccessat ++faccessat2 + fadvise64 + fadvise64_64 + fallocate diff --git a/SOURCES/glibc-rh1871386-4.patch b/SOURCES/glibc-rh1871386-4.patch new file mode 100644 index 0000000..72bb49d --- /dev/null +++ b/SOURCES/glibc-rh1871386-4.patch @@ -0,0 +1,37 @@ +commit dac8713629c8736a60aebec2f01657e46baa4c73 +Author: Joseph Myers +Date: Fri Oct 23 16:31:11 2020 +0000 + + Update syscall lists for Linux 5.9. + + Linux 5.9 has one new syscall, close_range. 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 for RHEL 8.5.0. + +diff --git a/sysdeps/unix/sysv/linux/syscall-names.list b/sysdeps/unix/sysv/linux/syscall-names.list +index a462318ecf..2d42aaf803 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.8. +-kernel 5.8 ++# The list of system calls is current as of Linux 5.9. ++kernel 5.9 + + FAST_atomic_update + FAST_cmpxchg +@@ -79,6 +79,7 @@ clone + clone2 + clone3 + close ++close_range + cmpxchg_badaddr + connect + copy_file_range diff --git a/SOURCES/glibc-rh1871386-5.patch b/SOURCES/glibc-rh1871386-5.patch new file mode 100644 index 0000000..a2e2b7d --- /dev/null +++ b/SOURCES/glibc-rh1871386-5.patch @@ -0,0 +1,37 @@ +commit bcf47eb0fba4c6278aadd6a377d6b7b3f673e17c +Author: Joseph Myers +Date: Wed Dec 16 02:08:52 2020 +0000 + + Update syscall lists for Linux 5.10. + + Linux 5.10 has one new syscall, process_madvise. 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 for RHEL 8.5.0. + +diff --git a/sysdeps/unix/sysv/linux/syscall-names.list b/sysdeps/unix/sysv/linux/syscall-names.list +index 2d42aaf803..4bd42be2b9 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.9. +-kernel 5.9 ++# The list of system calls is current as of Linux 5.10. ++kernel 5.10 + + FAST_atomic_update + FAST_cmpxchg +@@ -433,6 +433,7 @@ pread64 + preadv + preadv2 + prlimit64 ++process_madvise + process_vm_readv + process_vm_writev + prof diff --git a/SOURCES/glibc-rh1871386-6.patch b/SOURCES/glibc-rh1871386-6.patch new file mode 100644 index 0000000..36a47e8 --- /dev/null +++ b/SOURCES/glibc-rh1871386-6.patch @@ -0,0 +1,42 @@ +commit 2b778ceb4010c28d70de9b8eab20e8d88eed586b +Author: Paul Eggert +Date: Sat Jan 2 11:32:25 2021 -0800 + + Update copyright dates with scripts/update-copyrights + + I used these shell commands: + + ../glibc/scripts/update-copyrights $PWD/../gnulib/build-aux/update-copyright + (cd ../glibc && git commit -am"[this commit message]") + + and then ignored the output, which consisted lines saying "FOO: warning: + copyright statement not found" for each of 6694 files FOO. + I then removed trailing white space from benchtests/bench-pthread-locks.c + and iconvdata/tst-iconv-big5-hkscs-to-2ucs4.c, to work around this + diagnostic from Savannah: + remote: *** pre-commit check failed ... + remote: *** error: lines with trailing whitespace found + remote: error: hook declined to update refs/heads/master + +Modified to only update copyright for syscall-names.list for RHEL 8.5.0. Also +update licenses link to use https. + +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 2021-03-16 14:12:27.828571456 -0400 ++++ b/sysdeps/unix/sysv/linux/syscall-names.list 2021-03-16 14:13:23.950145631 -0400 +@@ -1,5 +1,5 @@ + # List of all known Linux system calls. +-# Copyright (C) 2017-2018 Free Software Foundation, Inc. ++# Copyright (C) 2017-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 +@@ -14,7 +14,7 @@ + # + # 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 the list of system call names. It has to remain in + # alphabetical order. Lines which start with # are treated as comments. diff --git a/SOURCES/glibc-rh1871386-7.patch b/SOURCES/glibc-rh1871386-7.patch new file mode 100644 index 0000000..79774e7 --- /dev/null +++ b/SOURCES/glibc-rh1871386-7.patch @@ -0,0 +1,37 @@ +commit 83908b3a1ea51e3aa7ff422275940e56dbba989f +Author: Joseph Myers +Date: Fri Feb 19 21:16:27 2021 +0000 + + Update syscall lists for Linux 5.11. + + Linux 5.11 has one new syscall, epoll_pwait2. 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 for RHEL 8.5.0. + +diff --git a/sysdeps/unix/sysv/linux/syscall-names.list b/sysdeps/unix/sysv/linux/syscall-names.list +index 4df7eeab96..f6cb34089d 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.10. +-kernel 5.10 ++# The list of system calls is current as of Linux 5.11. ++kernel 5.11 + + FAST_atomic_update + FAST_cmpxchg +@@ -95,6 +95,7 @@ epoll_create1 + epoll_ctl + epoll_ctl_old + epoll_pwait ++epoll_pwait2 + epoll_wait + epoll_wait_old + eventfd diff --git a/SOURCES/glibc-rh1871387-1.patch b/SOURCES/glibc-rh1871387-1.patch new file mode 100644 index 0000000..f37c484 --- /dev/null +++ b/SOURCES/glibc-rh1871387-1.patch @@ -0,0 +1,254 @@ +commit 7793ad7a2c00434398aa8bb3f5932e2fdf43536a +Author: Rajalakshmi Srinivasaraghavan +Date: Thu Aug 16 12:12:02 2018 +0530 + + powerpc: Rearrange little endian specific files + + This patch moves little endian specific POWER9 optimization files to + sysdeps/powerpc/powerpc64/le and creates POWER9 ifunc functions + only for little endian. + +diff --git a/sysdeps/powerpc/powerpc64/power9/strcmp.S b/sysdeps/powerpc/powerpc64/le/power9/strcmp.S +similarity index 93% +rename from sysdeps/powerpc/powerpc64/power9/strcmp.S +rename to sysdeps/powerpc/powerpc64/le/power9/strcmp.S +index 98243a9d51e1577f..bf057f598ef2aa55 100644 +--- a/sysdeps/powerpc/powerpc64/power9/strcmp.S ++++ b/sysdeps/powerpc/powerpc64/le/power9/strcmp.S +@@ -15,7 +15,6 @@ + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ +-#ifdef __LITTLE_ENDIAN__ + #include + + #ifndef STRCMP +@@ -30,16 +29,16 @@ + as in POWER8 patch and uses vectorised loops after that. */ + + /* TODO: Change this to actual instructions when minimum binutils is upgraded +- to 2.27. Macros are defined below for these newer instructions in order ++ to 2.27. Macros are defined below for these newer instructions in order + to maintain compatibility. */ +-# define VCTZLSBB(r,v) .long (0x10010602 | ((r)<<(32-11)) | ((v)<<(32-21))) ++#define VCTZLSBB(r,v) .long (0x10010602 | ((r)<<(32-11)) | ((v)<<(32-21))) + +-# define VEXTUBRX(t,a,b) .long (0x1000070d \ ++#define VEXTUBRX(t,a,b) .long (0x1000070d \ + | ((t)<<(32-11)) \ + | ((a)<<(32-16)) \ + | ((b)<<(32-21)) ) + +-# define VCMPNEZB(t,a,b) .long (0x10000507 \ ++#define VCMPNEZB(t,a,b) .long (0x10000507 \ + | ((t)<<(32-11)) \ + | ((a)<<(32-16)) \ + | ((b)<<(32-21)) ) +@@ -48,7 +47,7 @@ + reg1: Vector to hold next 16 bytes. + reg2: Address to read from. + reg3: Permute control vector. */ +-# define GET16BYTES(reg1, reg2, reg3) \ ++#define GET16BYTES(reg1, reg2, reg3) \ + lvx reg1, 0, reg2; \ + vperm v8, v2, reg1, reg3; \ + vcmpequb. v8, v0, v8; \ +@@ -263,6 +262,3 @@ L(pagecross_nullfound): + b L(pagecross_retdiff) + END (STRCMP) + libc_hidden_builtin_def (strcmp) +-#else +-#include +-#endif +diff --git a/sysdeps/powerpc/powerpc64/power9/strncmp.S b/sysdeps/powerpc/powerpc64/le/power9/strncmp.S +similarity index 95% +rename from sysdeps/powerpc/powerpc64/power9/strncmp.S +rename to sysdeps/powerpc/powerpc64/le/power9/strncmp.S +index 40be98ff45c9f485..93a79343c6be1099 100644 +--- a/sysdeps/powerpc/powerpc64/power9/strncmp.S ++++ b/sysdeps/powerpc/powerpc64/le/power9/strncmp.S +@@ -15,7 +15,6 @@ + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ +-#ifdef __LITTLE_ENDIAN__ + #include + + /* Implements the function +@@ -31,16 +30,16 @@ + #endif + + /* TODO: Change this to actual instructions when minimum binutils is upgraded +- to 2.27. Macros are defined below for these newer instructions in order ++ to 2.27. Macros are defined below for these newer instructions in order + to maintain compatibility. */ +-# define VCTZLSBB(r,v) .long (0x10010602 | ((r)<<(32-11)) | ((v)<<(32-21))) ++#define VCTZLSBB(r,v) .long (0x10010602 | ((r)<<(32-11)) | ((v)<<(32-21))) + +-# define VEXTUBRX(t,a,b) .long (0x1000070d \ ++#define VEXTUBRX(t,a,b) .long (0x1000070d \ + | ((t)<<(32-11)) \ + | ((a)<<(32-16)) \ + | ((b)<<(32-21)) ) + +-# define VCMPNEZB(t,a,b) .long (0x10000507 \ ++#define VCMPNEZB(t,a,b) .long (0x10000507 \ + | ((t)<<(32-11)) \ + | ((a)<<(32-16)) \ + | ((b)<<(32-21)) ) +@@ -49,7 +48,7 @@ + reg1: Vector to hold next 16 bytes. + reg2: Address to read from. + reg3: Permute control vector. */ +-# define GET16BYTES(reg1, reg2, reg3) \ ++#define GET16BYTES(reg1, reg2, reg3) \ + lvx reg1, 0, reg2; \ + vperm v8, v2, reg1, reg3; \ + vcmpequb. v8, v0, v8; \ +@@ -374,6 +373,3 @@ L(byte_ne_3): + b L(byte_ne_1) + END(STRNCMP) + libc_hidden_builtin_def(strncmp) +-#else +-#include +-#endif +diff --git a/sysdeps/powerpc/powerpc64/multiarch/Makefile b/sysdeps/powerpc/powerpc64/multiarch/Makefile +index 4df6b45c4c1c495a..963ea84dbfa98c74 100644 +--- a/sysdeps/powerpc/powerpc64/multiarch/Makefile ++++ b/sysdeps/powerpc/powerpc64/multiarch/Makefile +@@ -12,7 +12,7 @@ sysdep_routines += memcpy-power8-cached memcpy-power7 memcpy-a2 memcpy-power6 \ + strnlen-power8 strnlen-power7 strnlen-ppc64 \ + strcasecmp-power7 strcasecmp_l-power7 \ + strncase-power7 strncase_l-power7 \ +- strncmp-power9 strncmp-power8 strncmp-power7 \ ++ strncmp-power8 strncmp-power7 \ + strncmp-power4 strncmp-ppc64 \ + strchr-power8 strchr-power7 strchr-ppc64 \ + strchrnul-power8 strchrnul-power7 strchrnul-ppc64 \ +@@ -22,7 +22,7 @@ sysdep_routines += memcpy-power8-cached memcpy-power7 memcpy-a2 memcpy-power6 \ + strncat-power8 strncat-power7 strncat-ppc64 \ + strncpy-power7 strncpy-ppc64 \ + stpncpy-power8 stpncpy-power7 stpncpy-ppc64 \ +- strcmp-power9 strcmp-power8 strcmp-power7 strcmp-ppc64 \ ++ strcmp-power8 strcmp-power7 strcmp-ppc64 \ + strcat-power8 strcat-power7 strcat-ppc64 \ + memmove-power7 memmove-ppc64 wordcopy-ppc64 bcopy-ppc64 \ + strncpy-power8 strstr-power7 strstr-ppc64 \ +@@ -31,6 +31,9 @@ sysdep_routines += memcpy-power8-cached memcpy-power7 memcpy-a2 memcpy-power6 \ + strcasecmp-ppc64 strcasecmp-power8 strncase-ppc64 \ + strncase-power8 + ++ifneq (,$(filter %le,$(config-machine))) ++sysdep_routines += strcmp-power9 strncmp-power9 ++endif + CFLAGS-strncase-power7.c += -mcpu=power7 -funroll-loops + CFLAGS-strncase_l-power7.c += -mcpu=power7 -funroll-loops + endif +diff --git a/sysdeps/powerpc/powerpc64/multiarch/ifunc-impl-list.c b/sysdeps/powerpc/powerpc64/multiarch/ifunc-impl-list.c +index 38a21e478e2527f5..1d374f2ae48165bd 100644 +--- a/sysdeps/powerpc/powerpc64/multiarch/ifunc-impl-list.c ++++ b/sysdeps/powerpc/powerpc64/multiarch/ifunc-impl-list.c +@@ -112,8 +112,10 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + + /* Support sysdeps/powerpc/powerpc64/multiarch/strncmp.c. */ + IFUNC_IMPL (i, name, strncmp, ++#ifdef __LITTLE_ENDIAN__ + IFUNC_IMPL_ADD (array, i, strncmp, hwcap2 & PPC_FEATURE2_ARCH_3_00, + __strncmp_power9) ++#endif + IFUNC_IMPL_ADD (array, i, strncmp, hwcap2 & PPC_FEATURE2_ARCH_2_07, + __strncmp_power8) + IFUNC_IMPL_ADD (array, i, strncmp, hwcap & PPC_FEATURE_HAS_VSX, +@@ -337,9 +339,11 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + + /* Support sysdeps/powerpc/powerpc64/multiarch/strcmp.c. */ + IFUNC_IMPL (i, name, strcmp, ++#ifdef __LITTLE_ENDIAN__ + IFUNC_IMPL_ADD (array, i, strcmp, + hwcap2 & PPC_FEATURE2_ARCH_3_00, + __strcmp_power9) ++#endif + IFUNC_IMPL_ADD (array, i, strcmp, + hwcap2 & PPC_FEATURE2_ARCH_2_07, + __strcmp_power8) +diff --git a/sysdeps/powerpc/powerpc64/multiarch/strcmp-power9.S b/sysdeps/powerpc/powerpc64/multiarch/strcmp-power9.S +index 8b569d38be783316..545e6cee91e61311 100644 +--- a/sysdeps/powerpc/powerpc64/multiarch/strcmp-power9.S ++++ b/sysdeps/powerpc/powerpc64/multiarch/strcmp-power9.S +@@ -16,11 +16,11 @@ + License along with the GNU C Library; if not, see + . */ + +-#if IS_IN (libc) ++#if defined __LITTLE_ENDIAN__ && IS_IN (libc) + #define STRCMP __strcmp_power9 + + #undef libc_hidden_builtin_def + #define libc_hidden_builtin_def(name) + +-#include ++#include + #endif +diff --git a/sysdeps/powerpc/powerpc64/multiarch/strcmp.c b/sysdeps/powerpc/powerpc64/multiarch/strcmp.c +index b669053166771cae..2422c8d72cfdec83 100644 +--- a/sysdeps/powerpc/powerpc64/multiarch/strcmp.c ++++ b/sysdeps/powerpc/powerpc64/multiarch/strcmp.c +@@ -27,13 +27,17 @@ + extern __typeof (strcmp) __strcmp_ppc attribute_hidden; + extern __typeof (strcmp) __strcmp_power7 attribute_hidden; + extern __typeof (strcmp) __strcmp_power8 attribute_hidden; ++# ifdef __LITTLE_ENDIAN__ + extern __typeof (strcmp) __strcmp_power9 attribute_hidden; ++# endif + + # undef strcmp + + libc_ifunc_redirected (__redirect_strcmp, strcmp, ++# ifdef __LITTLE_ENDIAN__ + (hwcap2 & PPC_FEATURE2_ARCH_3_00) + ? __strcmp_power9 : ++# endif + (hwcap2 & PPC_FEATURE2_ARCH_2_07) + ? __strcmp_power8 + : (hwcap & PPC_FEATURE_HAS_VSX) +diff --git a/sysdeps/powerpc/powerpc64/multiarch/strncmp-power9.S b/sysdeps/powerpc/powerpc64/multiarch/strncmp-power9.S +index 3356f7252771a043..c6f0128379c497b4 100644 +--- a/sysdeps/powerpc/powerpc64/multiarch/strncmp-power9.S ++++ b/sysdeps/powerpc/powerpc64/multiarch/strncmp-power9.S +@@ -15,11 +15,11 @@ + License along with the GNU C Library; if not, see + . */ + +-#if IS_IN (libc) ++#if defined __LITTLE_ENDIAN__ && IS_IN (libc) + #define STRNCMP __strncmp_power9 + + #undef libc_hidden_builtin_def + #define libc_hidden_builtin_def(name) + +-#include ++#include + #endif +diff --git a/sysdeps/powerpc/powerpc64/multiarch/strncmp.c b/sysdeps/powerpc/powerpc64/multiarch/strncmp.c +index c4a40d1ec7245a3b..9c887ee18186f070 100644 +--- a/sysdeps/powerpc/powerpc64/multiarch/strncmp.c ++++ b/sysdeps/powerpc/powerpc64/multiarch/strncmp.c +@@ -29,14 +29,18 @@ extern __typeof (strncmp) __strncmp_ppc attribute_hidden; + extern __typeof (strncmp) __strncmp_power4 attribute_hidden; + extern __typeof (strncmp) __strncmp_power7 attribute_hidden; + extern __typeof (strncmp) __strncmp_power8 attribute_hidden; ++# ifdef __LITTLE_ENDIAN__ + extern __typeof (strncmp) __strncmp_power9 attribute_hidden; ++# endif + # undef strncmp + + /* Avoid DWARF definition DIE on ifunc symbol so that GDB can handle + ifunc symbol properly. */ + libc_ifunc_redirected (__redirect_strncmp, strncmp, ++# ifdef __LITTLE_ENDIAN_ + (hwcap2 & PPC_FEATURE2_ARCH_3_00) + ? __strncmp_power9 : ++# endif + (hwcap2 & PPC_FEATURE2_ARCH_2_07) + ? __strncmp_power8 + : (hwcap & PPC_FEATURE_HAS_VSX) diff --git a/SOURCES/glibc-rh1871387-2.patch b/SOURCES/glibc-rh1871387-2.patch new file mode 100644 index 0000000..7f0cc39 --- /dev/null +++ b/SOURCES/glibc-rh1871387-2.patch @@ -0,0 +1,245 @@ +commit 39037048502d52ab6422c18f2d178d6228d2c7b9 +Author: Anton Blanchard via Libc-alpha +Date: Thu May 14 09:00:26 2020 +1000 + + powerpc: Optimized strcpy for POWER9 + + This version uses VSX store vector with length instructions and is + significantly faster on small strings and relatively unaligned large + strings, compared to the POWER8 version. A few examples: + + __strcpy_power9 __strcpy_power8 + Length 16, alignments in bytes 0/ 0: 2.52454 4.62695 + Length 412, alignments in bytes 4/ 0: 11.6 22.9185 + +diff --git a/sysdeps/powerpc/powerpc64/le/power9/strcpy.S b/sysdeps/powerpc/powerpc64/le/power9/strcpy.S +new file mode 100644 +index 0000000000000000..5749228054667b2d +--- /dev/null ++++ b/sysdeps/powerpc/powerpc64/le/power9/strcpy.S +@@ -0,0 +1,144 @@ ++/* Optimized strcpy implementation for PowerPC64/POWER9. ++ 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 ++ ++#ifndef STRCPY ++# define STRCPY strcpy ++#endif ++ ++/* Implements the function ++ ++ char * [r3] strcpy (char *dest [r3], const char *src [r4]) ++ ++ The implementation can load bytes past a null terminator, but only ++ up to the next 16B boundary, so it never crosses a page. */ ++ ++.machine power9 ++ENTRY_TOCLESS (STRCPY, 4) ++ CALL_MCOUNT 2 ++ ++ /* NULL string optimisation */ ++ lbz r0,0(r4) ++ stb r0,0(r3) ++ cmpwi r0,0 ++ beqlr ++ ++ addi r4,r4,1 ++ addi r11,r3,1 ++ ++ vspltisb v18,0 /* Zeroes in v18 */ ++ ++ neg r5,r4 ++ rldicl r9,r5,0,60 /* How many bytes to get source 16B aligned? */ ++ ++ /* Get source 16B aligned */ ++ lvx v0,0,r4 ++ lvsr v1,0,r4 ++ vperm v0,v18,v0,v1 ++ ++ vcmpequb v6,v0,v18 /* 0xff if byte is NULL, 0x00 otherwise */ ++ vctzlsbb r8,v6 /* Number of trailing zeroes */ ++ addi r8,r8,1 /* Add null terminator */ ++ ++ /* r8 = bytes including null ++ r9 = bytes to get source 16B aligned ++ if r8 > r9 ++ no null, copy r9 bytes ++ else ++ there is a null, copy r8 bytes and return. */ ++ cmpd r8,r9 ++ bgt L(no_null) ++ ++ sldi r10,r8,56 /* stxvl wants size in top 8 bits */ ++ stxvl 32+v0,r11,r10 /* Partial store */ ++ ++ blr ++ ++L(no_null): ++ sldi r10,r9,56 /* stxvl wants size in top 8 bits */ ++ stxvl 32+v0,r11,r10 /* Partial store */ ++ ++ add r4,r4,r9 ++ add r11,r11,r9 ++ ++L(loop): ++ lxv 32+v0,0(r4) ++ vcmpequb. v6,v0,v18 /* Any zero bytes? */ ++ bne cr6,L(tail1) ++ ++ lxv 32+v1,16(r4) ++ vcmpequb. v6,v1,v18 /* Any zero bytes? */ ++ bne cr6,L(tail2) ++ ++ lxv 32+v2,32(r4) ++ vcmpequb. v6,v2,v18 /* Any zero bytes? */ ++ bne cr6,L(tail3) ++ ++ lxv 32+v3,48(r4) ++ vcmpequb. v6,v3,v18 /* Any zero bytes? */ ++ bne cr6,L(tail4) ++ ++ stxv 32+v0,0(r11) ++ stxv 32+v1,16(r11) ++ stxv 32+v2,32(r11) ++ stxv 32+v3,48(r11) ++ ++ addi r4,r4,64 ++ addi r11,r11,64 ++ ++ b L(loop) ++ ++L(tail1): ++ vctzlsbb r8,v6 ++ addi r8,r8,1 ++ sldi r9,r8,56 /* stxvl wants size in top 8 bits */ ++ stxvl 32+v0,r11,r9 ++ blr ++ ++L(tail2): ++ stxv 32+v0,0(r11) ++ vctzlsbb r8,v6 /* Number of trailing zeroes */ ++ addi r8,r8,1 /* Add null terminator */ ++ sldi r10,r8,56 /* stxvl wants size in top 8 bits */ ++ addi r11,r11,16 ++ stxvl 32+v1,r11,r10 /* Partial store */ ++ blr ++ ++L(tail3): ++ stxv 32+v0,0(r11) ++ stxv 32+v1,16(r11) ++ vctzlsbb r8,v6 /* Number of trailing zeroes */ ++ addi r8,r8,1 /* Add null terminator */ ++ sldi r10,r8,56 /* stxvl wants size in top 8 bits */ ++ addi r11,r11,32 ++ stxvl 32+v2,r11,r10 /* Partial store */ ++ blr ++ ++L(tail4): ++ stxv 32+v0,0(r11) ++ stxv 32+v1,16(r11) ++ stxv 32+v2,32(r11) ++ vctzlsbb r8,v6 /* Number of trailing zeroes */ ++ addi r8,r8,1 /* Add null terminator */ ++ sldi r10,r8,56 /* stxvl wants size in top 8 bits */ ++ addi r11,r11,48 ++ stxvl 32+v3,r11,r10 /* Partial store */ ++ blr ++END (STRCPY) ++libc_hidden_builtin_def (strcpy) +diff --git a/sysdeps/powerpc/powerpc64/multiarch/Makefile b/sysdeps/powerpc/powerpc64/multiarch/Makefile +index 963ea84dbfa98c74..17057bcbd694a710 100644 +--- a/sysdeps/powerpc/powerpc64/multiarch/Makefile ++++ b/sysdeps/powerpc/powerpc64/multiarch/Makefile +@@ -32,7 +32,7 @@ sysdep_routines += memcpy-power8-cached memcpy-power7 memcpy-a2 memcpy-power6 \ + strncase-power8 + + ifneq (,$(filter %le,$(config-machine))) +-sysdep_routines += strcmp-power9 strncmp-power9 ++sysdep_routines += strcmp-power9 strncmp-power9 strcpy-power9 + endif + CFLAGS-strncase-power7.c += -mcpu=power7 -funroll-loops + CFLAGS-strncase_l-power7.c += -mcpu=power7 -funroll-loops +diff --git a/sysdeps/powerpc/powerpc64/multiarch/ifunc-impl-list.c b/sysdeps/powerpc/powerpc64/multiarch/ifunc-impl-list.c +index 1d374f2ae48165bd..2857fa8f36599afd 100644 +--- a/sysdeps/powerpc/powerpc64/multiarch/ifunc-impl-list.c ++++ b/sysdeps/powerpc/powerpc64/multiarch/ifunc-impl-list.c +@@ -85,6 +85,10 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + + /* Support sysdeps/powerpc/powerpc64/multiarch/strcpy.c. */ + IFUNC_IMPL (i, name, strcpy, ++#ifdef __LITTLE_ENDIAN__ ++ IFUNC_IMPL_ADD (array, i, strcpy, hwcap2 & PPC_FEATURE2_ARCH_3_00, ++ __strcpy_power9) ++#endif + IFUNC_IMPL_ADD (array, i, strcpy, hwcap2 & PPC_FEATURE2_ARCH_2_07, + __strcpy_power8) + IFUNC_IMPL_ADD (array, i, strcpy, hwcap & PPC_FEATURE_HAS_VSX, +diff --git a/sysdeps/powerpc/powerpc64/multiarch/strcpy-power9.S b/sysdeps/powerpc/powerpc64/multiarch/strcpy-power9.S +new file mode 100644 +index 0000000000000000..d22aa0a8d690cad7 +--- /dev/null ++++ b/sysdeps/powerpc/powerpc64/multiarch/strcpy-power9.S +@@ -0,0 +1,26 @@ ++/* Optimized strcpy implementation for POWER9/PPC64. ++ Copyright (C) 2016-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 ++ . */ ++ ++#if defined __LITTLE_ENDIAN__ && IS_IN (libc) ++#define STRCPY __strcpy_power9 ++ ++#undef libc_hidden_builtin_def ++#define libc_hidden_builtin_def(name) ++ ++#include ++#endif +diff --git a/sysdeps/powerpc/powerpc64/multiarch/strcpy.c b/sysdeps/powerpc/powerpc64/multiarch/strcpy.c +index b18a92a62a526d9c..88826392be4bdf48 100644 +--- a/sysdeps/powerpc/powerpc64/multiarch/strcpy.c ++++ b/sysdeps/powerpc/powerpc64/multiarch/strcpy.c +@@ -25,9 +25,16 @@ + extern __typeof (strcpy) __strcpy_ppc attribute_hidden; + extern __typeof (strcpy) __strcpy_power7 attribute_hidden; + extern __typeof (strcpy) __strcpy_power8 attribute_hidden; ++# ifdef __LITTLE_ENDIAN__ ++extern __typeof (strcpy) __strcpy_power9 attribute_hidden; ++# endif + #undef strcpy + + libc_ifunc_redirected (__redirect_strcpy, strcpy, ++# ifdef __LITTLE_ENDIAN__ ++ (hwcap2 & PPC_FEATURE2_ARCH_3_00) ++ ? __strcpy_power9 : ++# endif + (hwcap2 & PPC_FEATURE2_ARCH_2_07) + ? __strcpy_power8 + : (hwcap & PPC_FEATURE_HAS_VSX) diff --git a/SOURCES/glibc-rh1871387-3.patch b/SOURCES/glibc-rh1871387-3.patch new file mode 100644 index 0000000..5ccacc9 --- /dev/null +++ b/SOURCES/glibc-rh1871387-3.patch @@ -0,0 +1,270 @@ +commit aa70d0563256b8ea053203177f756bca33b5cf37 +Author: Anton Blanchard via Libc-alpha +Date: Thu May 14 09:08:35 2020 +1000 + + powerpc: Optimized stpcpy for POWER9 + + Add stpcpy support to the POWER9 strcpy. This is up to 40% faster on + small strings and up to 90% faster on long relatively unaligned strings, + compared to the POWER8 version. A few examples: + + __stpcpy_power9 __stpcpy_power8 + Length 20, alignments in bytes 4/ 4: 2.58246 4.8788 + Length 1024, alignments in bytes 1/ 6: 24.8186 47.8528 + +diff --git a/sysdeps/powerpc/powerpc64/le/power9/stpcpy.S b/sysdeps/powerpc/powerpc64/le/power9/stpcpy.S +new file mode 100644 +index 0000000000000000..44425cb1e80ea198 +--- /dev/null ++++ b/sysdeps/powerpc/powerpc64/le/power9/stpcpy.S +@@ -0,0 +1,24 @@ ++/* Optimized stpcpy implementation for PowerPC64/POWER9. ++ Copyright (C) 2015-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 ++ . */ ++ ++#define USE_AS_STPCPY ++#include ++ ++weak_alias (__stpcpy, stpcpy) ++libc_hidden_def (__stpcpy) ++libc_hidden_builtin_def (stpcpy) +diff --git a/sysdeps/powerpc/powerpc64/le/power9/strcpy.S b/sysdeps/powerpc/powerpc64/le/power9/strcpy.S +index 5749228054667b2d..ce8f50329177fd06 100644 +--- a/sysdeps/powerpc/powerpc64/le/power9/strcpy.S ++++ b/sysdeps/powerpc/powerpc64/le/power9/strcpy.S +@@ -18,19 +18,35 @@ + + #include + +-#ifndef STRCPY +-# define STRCPY strcpy +-#endif ++#ifdef USE_AS_STPCPY ++# ifndef STPCPY ++# define FUNC_NAME __stpcpy ++# else ++# define FUNC_NAME STPCPY ++# endif ++#else ++# ifndef STRCPY ++# define FUNC_NAME strcpy ++# else ++# define FUNC_NAME STRCPY ++# endif ++#endif /* !USE_AS_STPCPY */ + + /* Implements the function + + char * [r3] strcpy (char *dest [r3], const char *src [r4]) + ++ or ++ ++ char * [r3] stpcpy (char *dest [r3], const char *src [r4]) ++ ++ if USE_AS_STPCPY is defined. ++ + The implementation can load bytes past a null terminator, but only + up to the next 16B boundary, so it never crosses a page. */ + + .machine power9 +-ENTRY_TOCLESS (STRCPY, 4) ++ENTRY_TOCLESS (FUNC_NAME, 4) + CALL_MCOUNT 2 + + /* NULL string optimisation */ +@@ -53,8 +69,8 @@ ENTRY_TOCLESS (STRCPY, 4) + vperm v0,v18,v0,v1 + + vcmpequb v6,v0,v18 /* 0xff if byte is NULL, 0x00 otherwise */ +- vctzlsbb r8,v6 /* Number of trailing zeroes */ +- addi r8,r8,1 /* Add null terminator */ ++ vctzlsbb r7,v6 /* Number of trailing zeroes */ ++ addi r8,r7,1 /* Add null terminator */ + + /* r8 = bytes including null + r9 = bytes to get source 16B aligned +@@ -68,6 +84,11 @@ ENTRY_TOCLESS (STRCPY, 4) + sldi r10,r8,56 /* stxvl wants size in top 8 bits */ + stxvl 32+v0,r11,r10 /* Partial store */ + ++#ifdef USE_AS_STPCPY ++ /* stpcpy returns the dest address plus the size not counting the ++ final '\0'. */ ++ add r3,r11,r7 ++#endif + blr + + L(no_null): +@@ -106,28 +127,43 @@ L(loop): + + L(tail1): + vctzlsbb r8,v6 +- addi r8,r8,1 +- sldi r9,r8,56 /* stxvl wants size in top 8 bits */ ++ addi r9,r8,1 ++ sldi r9,r9,56 /* stxvl wants size in top 8 bits */ + stxvl 32+v0,r11,r9 ++#ifdef USE_AS_STPCPY ++ /* stpcpy returns the dest address plus the size not counting the ++ final '\0'. */ ++ add r3,r11,r8 ++#endif + blr + + L(tail2): + stxv 32+v0,0(r11) + vctzlsbb r8,v6 /* Number of trailing zeroes */ +- addi r8,r8,1 /* Add null terminator */ +- sldi r10,r8,56 /* stxvl wants size in top 8 bits */ ++ addi r9,r8,1 /* Add null terminator */ ++ sldi r10,r9,56 /* stxvl wants size in top 8 bits */ + addi r11,r11,16 + stxvl 32+v1,r11,r10 /* Partial store */ ++#ifdef USE_AS_STPCPY ++ /* stpcpy returns the dest address plus the size not counting the ++ final '\0'. */ ++ add r3,r11,r8 ++#endif + blr + + L(tail3): + stxv 32+v0,0(r11) + stxv 32+v1,16(r11) + vctzlsbb r8,v6 /* Number of trailing zeroes */ +- addi r8,r8,1 /* Add null terminator */ +- sldi r10,r8,56 /* stxvl wants size in top 8 bits */ ++ addi r9,r8,1 /* Add null terminator */ ++ sldi r10,r9,56 /* stxvl wants size in top 8 bits */ + addi r11,r11,32 + stxvl 32+v2,r11,r10 /* Partial store */ ++#ifdef USE_AS_STPCPY ++ /* stpcpy returns the dest address plus the size not counting the ++ final '\0'. */ ++ add r3,r11,r8 ++#endif + blr + + L(tail4): +@@ -135,10 +171,17 @@ L(tail4): + stxv 32+v1,16(r11) + stxv 32+v2,32(r11) + vctzlsbb r8,v6 /* Number of trailing zeroes */ +- addi r8,r8,1 /* Add null terminator */ +- sldi r10,r8,56 /* stxvl wants size in top 8 bits */ ++ addi r9,r8,1 /* Add null terminator */ ++ sldi r10,r9,56 /* stxvl wants size in top 8 bits */ + addi r11,r11,48 + stxvl 32+v3,r11,r10 /* Partial store */ ++#ifdef USE_AS_STPCPY ++ /* stpcpy returns the dest address plus the size not counting the ++ final '\0'. */ ++ add r3,r11,r8 ++#endif + blr +-END (STRCPY) ++END (FUNC_NAME) ++#ifndef USE_AS_STPCPY + libc_hidden_builtin_def (strcpy) ++#endif +diff --git a/sysdeps/powerpc/powerpc64/multiarch/Makefile b/sysdeps/powerpc/powerpc64/multiarch/Makefile +index 17057bcbd694a710..cada6b19bf3c8fab 100644 +--- a/sysdeps/powerpc/powerpc64/multiarch/Makefile ++++ b/sysdeps/powerpc/powerpc64/multiarch/Makefile +@@ -32,7 +32,7 @@ sysdep_routines += memcpy-power8-cached memcpy-power7 memcpy-a2 memcpy-power6 \ + strncase-power8 + + ifneq (,$(filter %le,$(config-machine))) +-sysdep_routines += strcmp-power9 strncmp-power9 strcpy-power9 ++sysdep_routines += strcmp-power9 strncmp-power9 strcpy-power9 stpcpy-power9 + endif + CFLAGS-strncase-power7.c += -mcpu=power7 -funroll-loops + CFLAGS-strncase_l-power7.c += -mcpu=power7 -funroll-loops +diff --git a/sysdeps/powerpc/powerpc64/multiarch/ifunc-impl-list.c b/sysdeps/powerpc/powerpc64/multiarch/ifunc-impl-list.c +index 2857fa8f36599afd..b0abc6b61dc15f19 100644 +--- a/sysdeps/powerpc/powerpc64/multiarch/ifunc-impl-list.c ++++ b/sysdeps/powerpc/powerpc64/multiarch/ifunc-impl-list.c +@@ -98,6 +98,10 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + + /* Support sysdeps/powerpc/powerpc64/multiarch/stpcpy.c. */ + IFUNC_IMPL (i, name, stpcpy, ++#ifdef __LITTLE_ENDIAN__ ++ IFUNC_IMPL_ADD (array, i, strncmp, hwcap2 & PPC_FEATURE2_ARCH_3_00, ++ __stpcpy_power9) ++#endif + IFUNC_IMPL_ADD (array, i, stpcpy, hwcap2 & PPC_FEATURE2_ARCH_2_07, + __stpcpy_power8) + IFUNC_IMPL_ADD (array, i, stpcpy, hwcap & PPC_FEATURE_HAS_VSX, +diff --git a/sysdeps/powerpc/powerpc64/multiarch/stpcpy-power9.S b/sysdeps/powerpc/powerpc64/multiarch/stpcpy-power9.S +new file mode 100644 +index 0000000000000000..a728d49fd2575e00 +--- /dev/null ++++ b/sysdeps/powerpc/powerpc64/multiarch/stpcpy-power9.S +@@ -0,0 +1,24 @@ ++/* Optimized stpcpy implementation for POWER9/PPC64. ++ Copyright (C) 2015-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 ++ . */ ++ ++#define STPCPY __stpcpy_power9 ++ ++#undef libc_hidden_builtin_def ++#define libc_hidden_builtin_def(name) ++ ++#include +diff --git a/sysdeps/powerpc/powerpc64/multiarch/stpcpy.c b/sysdeps/powerpc/powerpc64/multiarch/stpcpy.c +index 34c889644133d757..8ce58572e0f27c7f 100644 +--- a/sysdeps/powerpc/powerpc64/multiarch/stpcpy.c ++++ b/sysdeps/powerpc/powerpc64/multiarch/stpcpy.c +@@ -26,13 +26,20 @@ + extern __typeof (__stpcpy) __stpcpy_ppc attribute_hidden; + extern __typeof (__stpcpy) __stpcpy_power7 attribute_hidden; + extern __typeof (__stpcpy) __stpcpy_power8 attribute_hidden; ++# ifdef __LITTLE_ENDIAN__ ++extern __typeof (__stpcpy) __stpcpy_power9 attribute_hidden; ++# endif + + libc_ifunc_hidden (__stpcpy, __stpcpy, +- (hwcap2 & PPC_FEATURE2_ARCH_2_07) +- ? __stpcpy_power8 +- : (hwcap & PPC_FEATURE_HAS_VSX) +- ? __stpcpy_power7 +- : __stpcpy_ppc); ++# ifdef __LITTLE_ENDIAN__ ++ (hwcap2 & PPC_FEATURE2_ARCH_3_00) ++ ? __stpcpy_power9 : ++# endif ++ (hwcap2 & PPC_FEATURE2_ARCH_2_07) ++ ? __stpcpy_power8 ++ : (hwcap & PPC_FEATURE_HAS_VSX) ++ ? __stpcpy_power7 ++ : __stpcpy_ppc); + + weak_alias (__stpcpy, stpcpy) + libc_hidden_def (__stpcpy) diff --git a/SOURCES/glibc-rh1871387-4.patch b/SOURCES/glibc-rh1871387-4.patch new file mode 100644 index 0000000..1161362 --- /dev/null +++ b/SOURCES/glibc-rh1871387-4.patch @@ -0,0 +1,213 @@ +commit 765de945efc5d5602999b2999fe8abdf04881370 +Author: Anton Blanchard +Date: Thu May 14 21:49:16 2020 +1000 + + powerpc: Optimized rawmemchr for POWER9 + + This version uses vector instructions and is up to 60% faster on medium + matches and up to 90% faster on long matches, compared to the POWER7 + version. A few examples: + + __rawmemchr_power9 __rawmemchr_power7 + Length 32, alignment 0: 2.27566 3.77765 + Length 64, alignment 2: 2.46231 3.51064 + Length 1024, alignment 0: 17.3059 32.6678 + +diff --git a/sysdeps/powerpc/powerpc64/le/power9/rawmemchr.S b/sysdeps/powerpc/powerpc64/le/power9/rawmemchr.S +new file mode 100644 +index 0000000000000000..9d0276c9315af5c8 +--- /dev/null ++++ b/sysdeps/powerpc/powerpc64/le/power9/rawmemchr.S +@@ -0,0 +1,107 @@ ++/* Optimized rawmemchr implementation for PowerPC64/POWER9. ++ 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 ++ ++#ifndef RAWMEMCHR ++# define RAWMEMCHR __rawmemchr ++#endif ++ ++/* Implements the function ++ ++ int [r3] rawmemchr (void *s [r3], int c [r4]) ++ ++ The implementation can load bytes past a matching byte, but only ++ up to the next 16B boundary, so it never crosses a page. */ ++ ++.machine power9 ++ENTRY_TOCLESS (RAWMEMCHR, 4) ++ CALL_MCOUNT 2 ++ ++ xori r5,r4,0xff ++ ++ mtvsrd v18+32,r4 /* matching char in v18 */ ++ mtvsrd v19+32,r5 /* non matching char in v19 */ ++ ++ vspltb v18,v18,7 /* replicate */ ++ vspltb v19,v19,7 /* replicate */ ++ ++ neg r5,r3 ++ rldicl r9,r5,0,60 /* How many bytes to get source 16B aligned? */ ++ ++ /* Align data and fill bytes not loaded with non matching char */ ++ lvx v0,0,r3 ++ lvsr v1,0,r3 ++ vperm v0,v19,v0,v1 ++ ++ vcmpequb. v6,v0,v18 /* 0xff if byte matches, 0x00 otherwise */ ++ beq cr6,L(aligned) ++ ++ vctzlsbb r0,v6 ++ add r3,r3,r0 ++ blr ++ ++L(aligned): ++ add r3,r3,r9 ++ ++L(loop): ++ lxv v0+32,0(r3) ++ vcmpequb. v6,v0,v18 /* 0xff if byte matches, 0x00 otherwise */ ++ bne cr6,L(tail1) ++ ++ lxv v0+32,16(r3) ++ vcmpequb. v6,v0,v18 /* 0xff if byte matches, 0x00 otherwise */ ++ bne cr6,L(tail2) ++ ++ lxv v0+32,32(r3) ++ vcmpequb. v6,v0,v18 /* 0xff if byte matches, 0x00 otherwise */ ++ bne cr6,L(tail3) ++ ++ lxv v0+32,48(r3) ++ vcmpequb. v6,v0,v18 /* 0xff if byte matches, 0x00 otherwise */ ++ bne cr6,L(tail4) ++ ++ addi r3,r3,64 ++ b L(loop) ++ ++L(tail1): ++ vctzlsbb r0,v6 ++ add r3,r3,r0 ++ blr ++ ++L(tail2): ++ vctzlsbb r0,v6 ++ add r3,r3,r0 ++ addi r3,r3,16 ++ blr ++ ++L(tail3): ++ vctzlsbb r0,v6 ++ add r3,r3,r0 ++ addi r3,r3,32 ++ blr ++ ++L(tail4): ++ vctzlsbb r0,v6 ++ add r3,r3,r0 ++ addi r3,r3,48 ++ blr ++ ++END (RAWMEMCHR) ++weak_alias (__rawmemchr,rawmemchr) ++libc_hidden_builtin_def (__rawmemchr) +diff --git a/sysdeps/powerpc/powerpc64/multiarch/Makefile b/sysdeps/powerpc/powerpc64/multiarch/Makefile +index cada6b19bf3c8fab..1a8ef5fb73c3b0db 100644 +--- a/sysdeps/powerpc/powerpc64/multiarch/Makefile ++++ b/sysdeps/powerpc/powerpc64/multiarch/Makefile +@@ -32,7 +32,8 @@ sysdep_routines += memcpy-power8-cached memcpy-power7 memcpy-a2 memcpy-power6 \ + strncase-power8 + + ifneq (,$(filter %le,$(config-machine))) +-sysdep_routines += strcmp-power9 strncmp-power9 strcpy-power9 stpcpy-power9 ++sysdep_routines += strcmp-power9 strncmp-power9 strcpy-power9 stpcpy-power9 \ ++ rawmemchr-power9 + endif + CFLAGS-strncase-power7.c += -mcpu=power7 -funroll-loops + CFLAGS-strncase_l-power7.c += -mcpu=power7 -funroll-loops +diff --git a/sysdeps/powerpc/powerpc64/multiarch/ifunc-impl-list.c b/sysdeps/powerpc/powerpc64/multiarch/ifunc-impl-list.c +index b0abc6b61dc15f19..297935863e44c0e1 100644 +--- a/sysdeps/powerpc/powerpc64/multiarch/ifunc-impl-list.c ++++ b/sysdeps/powerpc/powerpc64/multiarch/ifunc-impl-list.c +@@ -216,6 +216,11 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + + /* Support sysdeps/powerpc/powerpc64/multiarch/rawmemchr.c. */ + IFUNC_IMPL (i, name, rawmemchr, ++#ifdef __LITTLE_ENDIAN__ ++ IFUNC_IMPL_ADD (array, i, rawmemchr, ++ hwcap2 & PPC_FEATURE2_ARCH_3_00, ++ __rawmemchr_power9) ++#endif + IFUNC_IMPL_ADD (array, i, rawmemchr, + hwcap & PPC_FEATURE_HAS_VSX, + __rawmemchr_power7) +diff --git a/sysdeps/powerpc/powerpc64/multiarch/rawmemchr-power9.S b/sysdeps/powerpc/powerpc64/multiarch/rawmemchr-power9.S +new file mode 100644 +index 0000000000000000..bac0a9090e7a07f8 +--- /dev/null ++++ b/sysdeps/powerpc/powerpc64/multiarch/rawmemchr-power9.S +@@ -0,0 +1,21 @@ ++/* Optimized rawmemchr implementation for PowerPC64/POWER9. ++ 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 ++ . */ ++ ++#define RAWMEMCHR __rawmemchr_power9 ++ ++#include +diff --git a/sysdeps/powerpc/powerpc64/multiarch/rawmemchr.c b/sysdeps/powerpc/powerpc64/multiarch/rawmemchr.c +index 02bac49b53d52411..2a7ae5a1ed02e556 100644 +--- a/sysdeps/powerpc/powerpc64/multiarch/rawmemchr.c ++++ b/sysdeps/powerpc/powerpc64/multiarch/rawmemchr.c +@@ -24,13 +24,21 @@ + + extern __typeof (__rawmemchr) __rawmemchr_ppc attribute_hidden; + extern __typeof (__rawmemchr) __rawmemchr_power7 attribute_hidden; ++# ifdef __LITTLE_ENDIAN__ ++extern __typeof (__rawmemchr) __rawmemchr_power9 attribute_hidden; ++# endif ++ + # undef __rawmemchr + + /* Avoid DWARF definition DIE on ifunc symbol so that GDB can handle + ifunc symbol properly. */ + libc_ifunc_redirected (__redirect___rawmemchr, __rawmemchr, +- (hwcap & PPC_FEATURE_HAS_VSX) +- ? __rawmemchr_power7 ++# ifdef __LITTLE_ENDIAN__ ++ (hwcap2 & PPC_FEATURE2_ARCH_3_00) ++ ? __rawmemchr_power9 : ++# endif ++ (hwcap & PPC_FEATURE_HAS_VSX) ++ ? __rawmemchr_power7 + : __rawmemchr_ppc); + + weak_alias (__rawmemchr, rawmemchr) diff --git a/SOURCES/glibc-rh1871387-5.patch b/SOURCES/glibc-rh1871387-5.patch new file mode 100644 index 0000000..8190aed --- /dev/null +++ b/SOURCES/glibc-rh1871387-5.patch @@ -0,0 +1,300 @@ +commit a23bd00f9d810c28d9e83ce1d7cf53968375937d +Author: Paul E. Murphy +Date: Mon May 18 11:16:06 2020 -0500 + + powerpc64le: add optimized strlen for P9 + + This started as a trivial change to Anton's rawmemchr. I got + carried away. This is a hybrid between P8's asympotically + faster 64B checks with extremely efficient small string checks + e.g <64B (and sometimes a little bit more depending on alignment). + + The second trick is to align to 64B by running a 48B checking loop + 16B at a time until we naturally align to 64B (i.e checking 48/96/144 + bytes/iteration based on the alignment after the first 5 comparisons). + This allieviates the need to check page boundaries. + + Finally, explicly use the P7 strlen with the runtime loader when building + P9. We need to be cautious about vector/vsx extensions here on P9 only + builds. + +diff --git a/sysdeps/powerpc/powerpc64/le/power9/rtld-strlen.S b/sysdeps/powerpc/powerpc64/le/power9/rtld-strlen.S +new file mode 100644 +index 0000000000000000..e9d83323acacfbca +--- /dev/null ++++ b/sysdeps/powerpc/powerpc64/le/power9/rtld-strlen.S +@@ -0,0 +1 @@ ++#include +diff --git a/sysdeps/powerpc/powerpc64/le/power9/strlen.S b/sysdeps/powerpc/powerpc64/le/power9/strlen.S +new file mode 100644 +index 0000000000000000..66a9b79647eebbd8 +--- /dev/null ++++ b/sysdeps/powerpc/powerpc64/le/power9/strlen.S +@@ -0,0 +1,213 @@ ++/* Optimized strlen implementation for PowerPC64/POWER9. ++ 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 ++ ++#ifndef STRLEN ++# define STRLEN __strlen ++# define DEFINE_STRLEN_HIDDEN_DEF 1 ++#endif ++ ++/* Implements the function ++ ++ int [r3] strlen (const void *s [r3]) ++ ++ The implementation can load bytes past a matching byte, but only ++ up to the next 64B boundary, so it never crosses a page. */ ++ ++.machine power9 ++ENTRY_TOCLESS (STRLEN, 4) ++ CALL_MCOUNT 2 ++ ++ vspltisb v18,0 ++ vspltisb v19,-1 ++ ++ neg r5,r3 ++ rldicl r9,r5,0,60 /* How many bytes to get source 16B aligned? */ ++ ++ /* Align data and fill bytes not loaded with non matching char. */ ++ lvx v0,0,r3 ++ lvsr v1,0,r3 ++ vperm v0,v19,v0,v1 ++ ++ vcmpequb. v6,v0,v18 ++ beq cr6,L(aligned) ++ ++ vctzlsbb r3,v6 ++ blr ++ ++ /* Test 64B 16B at a time. The 64B vector loop is optimized for ++ longer strings. Likewise, we check a multiple of 64B to avoid ++ breaking the alignment calculation below. */ ++L(aligned): ++ add r4,r3,r9 ++ rldicl. r5,r4,60,62 /* Determine the number of 48B loops needed for ++ alignment to 64B. And test for zero. */ ++ ++ lxv v0+32,0(r4) ++ vcmpequb. v6,v0,v18 ++ bne cr6,L(tail1) ++ ++ lxv v0+32,16(r4) ++ vcmpequb. v6,v0,v18 ++ bne cr6,L(tail2) ++ ++ lxv v0+32,32(r4) ++ vcmpequb. v6,v0,v18 ++ bne cr6,L(tail3) ++ ++ lxv v0+32,48(r4) ++ vcmpequb. v6,v0,v18 ++ bne cr6,L(tail4) ++ addi r4,r4,64 ++ ++ /* Speculatively generate a fake 16B aligned address to generate the ++ vector byte constant 0,1,..,15 using lvsl during reduction. */ ++ li r0,0 ++ ++ /* Skip the alignment if already 64B aligned. */ ++ beq L(loop_64b) ++ mtctr r5 ++ ++ /* Test 48B per iteration until 64B aligned. */ ++ .p2align 5 ++L(loop): ++ lxv v0+32,0(r4) ++ vcmpequb. v6,v0,v18 ++ bne cr6,L(tail1) ++ ++ lxv v0+32,16(r4) ++ vcmpequb. v6,v0,v18 ++ bne cr6,L(tail2) ++ ++ lxv v0+32,32(r4) ++ vcmpequb. v6,v0,v18 ++ bne cr6,L(tail3) ++ ++ addi r4,r4,48 ++ bdnz L(loop) ++ ++ .p2align 5 ++L(loop_64b): ++ lxv v1+32,0(r4) /* Load 4 quadwords. */ ++ lxv v2+32,16(r4) ++ lxv v3+32,32(r4) ++ lxv v4+32,48(r4) ++ vminub v5,v1,v2 /* Compare and merge into one VR for speed. */ ++ vminub v6,v3,v4 ++ vminub v7,v5,v6 ++ vcmpequb. v7,v7,v18 /* Check for NULLs. */ ++ addi r4,r4,64 /* Adjust address for the next iteration. */ ++ bne cr6,L(vmx_zero) ++ ++ lxv v1+32,0(r4) /* Load 4 quadwords. */ ++ lxv v2+32,16(r4) ++ lxv v3+32,32(r4) ++ lxv v4+32,48(r4) ++ vminub v5,v1,v2 /* Compare and merge into one VR for speed. */ ++ vminub v6,v3,v4 ++ vminub v7,v5,v6 ++ vcmpequb. v7,v7,v18 /* Check for NULLs. */ ++ addi r4,r4,64 /* Adjust address for the next iteration. */ ++ bne cr6,L(vmx_zero) ++ ++ lxv v1+32,0(r4) /* Load 4 quadwords. */ ++ lxv v2+32,16(r4) ++ lxv v3+32,32(r4) ++ lxv v4+32,48(r4) ++ vminub v5,v1,v2 /* Compare and merge into one VR for speed. */ ++ vminub v6,v3,v4 ++ vminub v7,v5,v6 ++ vcmpequb. v7,v7,v18 /* Check for NULLs. */ ++ addi r4,r4,64 /* Adjust address for the next iteration. */ ++ beq cr6,L(loop_64b) ++ ++L(vmx_zero): ++ /* OK, we found a null byte. Let's look for it in the current 64-byte ++ block and mark it in its corresponding VR. */ ++ vcmpequb v1,v1,v18 ++ vcmpequb v2,v2,v18 ++ vcmpequb v3,v3,v18 ++ vcmpequb v4,v4,v18 ++ ++ /* We will now 'compress' the result into a single doubleword, so it ++ can be moved to a GPR for the final calculation. First, we ++ generate an appropriate mask for vbpermq, so we can permute bits into ++ the first halfword. */ ++ vspltisb v10,3 ++ lvsl v11,0,r0 ++ vslb v10,v11,v10 ++ ++ /* Permute the first bit of each byte into bits 48-63. */ ++ vbpermq v1,v1,v10 ++ vbpermq v2,v2,v10 ++ vbpermq v3,v3,v10 ++ vbpermq v4,v4,v10 ++ ++ /* Shift each component into its correct position for merging. */ ++ vsldoi v2,v2,v2,2 ++ vsldoi v3,v3,v3,4 ++ vsldoi v4,v4,v4,6 ++ ++ /* Merge the results and move to a GPR. */ ++ vor v1,v2,v1 ++ vor v2,v3,v4 ++ vor v4,v1,v2 ++ mfvrd r10,v4 ++ ++ /* Adjust address to the begninning of the current 64-byte block. */ ++ addi r4,r4,-64 ++ ++ cnttzd r0,r10 /* Count trailing zeros before the match. */ ++ subf r5,r3,r4 ++ add r3,r5,r0 /* Compute final length. */ ++ blr ++ ++L(tail1): ++ vctzlsbb r0,v6 ++ add r4,r4,r0 ++ subf r3,r3,r4 ++ blr ++ ++L(tail2): ++ vctzlsbb r0,v6 ++ add r4,r4,r0 ++ addi r4,r4,16 ++ subf r3,r3,r4 ++ blr ++ ++L(tail3): ++ vctzlsbb r0,v6 ++ add r4,r4,r0 ++ addi r4,r4,32 ++ subf r3,r3,r4 ++ blr ++ ++L(tail4): ++ vctzlsbb r0,v6 ++ add r4,r4,r0 ++ addi r4,r4,48 ++ subf r3,r3,r4 ++ blr ++ ++END (STRLEN) ++ ++#ifdef DEFINE_STRLEN_HIDDEN_DEF ++weak_alias (__strlen, strlen) ++libc_hidden_builtin_def (strlen) ++#endif +diff --git a/sysdeps/powerpc/powerpc64/multiarch/Makefile b/sysdeps/powerpc/powerpc64/multiarch/Makefile +index 1a8ef5fb73c3b0db..6d5661d08257b7a0 100644 +--- a/sysdeps/powerpc/powerpc64/multiarch/Makefile ++++ b/sysdeps/powerpc/powerpc64/multiarch/Makefile +@@ -33,7 +33,7 @@ sysdep_routines += memcpy-power8-cached memcpy-power7 memcpy-a2 memcpy-power6 \ + + ifneq (,$(filter %le,$(config-machine))) + sysdep_routines += strcmp-power9 strncmp-power9 strcpy-power9 stpcpy-power9 \ +- rawmemchr-power9 ++ rawmemchr-power9 strlen-power9 + endif + CFLAGS-strncase-power7.c += -mcpu=power7 -funroll-loops + CFLAGS-strncase_l-power7.c += -mcpu=power7 -funroll-loops +diff --git a/sysdeps/powerpc/powerpc64/multiarch/ifunc-impl-list.c b/sysdeps/powerpc/powerpc64/multiarch/ifunc-impl-list.c +index 297935863e44c0e1..daa30d3907395680 100644 +--- a/sysdeps/powerpc/powerpc64/multiarch/ifunc-impl-list.c ++++ b/sysdeps/powerpc/powerpc64/multiarch/ifunc-impl-list.c +@@ -111,6 +111,10 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + + /* Support sysdeps/powerpc/powerpc64/multiarch/strlen.c. */ + IFUNC_IMPL (i, name, strlen, ++#ifdef __LITTLE_ENDIAN__ ++ IFUNC_IMPL_ADD (array, i, strcpy, hwcap2 & PPC_FEATURE2_ARCH_3_00, ++ __strlen_power9) ++#endif + IFUNC_IMPL_ADD (array, i, strlen, hwcap2 & PPC_FEATURE2_ARCH_2_07, + __strlen_power8) + IFUNC_IMPL_ADD (array, i, strlen, hwcap & PPC_FEATURE_HAS_VSX, +diff --git a/sysdeps/powerpc/powerpc64/multiarch/strlen-power9.S b/sysdeps/powerpc/powerpc64/multiarch/strlen-power9.S +new file mode 100644 +index 0000000000000000..68c8d54b5f5876a2 +--- /dev/null ++++ b/sysdeps/powerpc/powerpc64/multiarch/strlen-power9.S +@@ -0,0 +1,2 @@ ++#define STRLEN __strlen_power9 ++#include +diff --git a/sysdeps/powerpc/powerpc64/multiarch/strlen.c b/sysdeps/powerpc/powerpc64/multiarch/strlen.c +index 74810dab9929d505..b7f0fbb13fb97783 100644 +--- a/sysdeps/powerpc/powerpc64/multiarch/strlen.c ++++ b/sysdeps/powerpc/powerpc64/multiarch/strlen.c +@@ -30,8 +30,13 @@ extern __typeof (__redirect_strlen) __libc_strlen; + extern __typeof (__redirect_strlen) __strlen_ppc attribute_hidden; + extern __typeof (__redirect_strlen) __strlen_power7 attribute_hidden; + extern __typeof (__redirect_strlen) __strlen_power8 attribute_hidden; ++extern __typeof (__redirect_strlen) __strlen_power9 attribute_hidden; + + libc_ifunc (__libc_strlen, ++# ifdef __LITTLE_ENDIAN__ ++ (hwcap2 & PPC_FEATURE2_ARCH_3_00) ++ ? __strlen_power9 : ++# endif + (hwcap2 & PPC_FEATURE2_ARCH_2_07) + ? __strlen_power8 : + (hwcap & PPC_FEATURE_HAS_VSX) diff --git a/SOURCES/glibc-rh1871387-6.patch b/SOURCES/glibc-rh1871387-6.patch new file mode 100644 index 0000000..e05901b --- /dev/null +++ b/SOURCES/glibc-rh1871387-6.patch @@ -0,0 +1,31 @@ +commit 07f3ecdba69c5190180112c25757040c69041bb9 +Author: Raphael Moreira Zinsly +Date: Thu Sep 17 11:16:36 2020 -0300 + + powerpc: fix ifunc implementation list for POWER9 strlen and stpcpy + + __strlen_power9 and __stpcpy_power9 were added to their ifunc lists + using the wrong function names. + +diff --git a/sysdeps/powerpc/powerpc64/multiarch/ifunc-impl-list.c b/sysdeps/powerpc/powerpc64/multiarch/ifunc-impl-list.c +index daa30d3907395680..e622ab4d47548146 100644 +--- a/sysdeps/powerpc/powerpc64/multiarch/ifunc-impl-list.c ++++ b/sysdeps/powerpc/powerpc64/multiarch/ifunc-impl-list.c +@@ -99,7 +99,7 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + /* Support sysdeps/powerpc/powerpc64/multiarch/stpcpy.c. */ + IFUNC_IMPL (i, name, stpcpy, + #ifdef __LITTLE_ENDIAN__ +- IFUNC_IMPL_ADD (array, i, strncmp, hwcap2 & PPC_FEATURE2_ARCH_3_00, ++ IFUNC_IMPL_ADD (array, i, stpcpy, hwcap2 & PPC_FEATURE2_ARCH_3_00, + __stpcpy_power9) + #endif + IFUNC_IMPL_ADD (array, i, stpcpy, hwcap2 & PPC_FEATURE2_ARCH_2_07, +@@ -112,7 +112,7 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + /* Support sysdeps/powerpc/powerpc64/multiarch/strlen.c. */ + IFUNC_IMPL (i, name, strlen, + #ifdef __LITTLE_ENDIAN__ +- IFUNC_IMPL_ADD (array, i, strcpy, hwcap2 & PPC_FEATURE2_ARCH_3_00, ++ IFUNC_IMPL_ADD (array, i, strlen, hwcap2 & PPC_FEATURE2_ARCH_3_00, + __strlen_power9) + #endif + IFUNC_IMPL_ADD (array, i, strlen, hwcap2 & PPC_FEATURE2_ARCH_2_07, diff --git a/SOURCES/glibc-rh1871394-1.patch b/SOURCES/glibc-rh1871394-1.patch new file mode 100644 index 0000000..bc36d64 --- /dev/null +++ b/SOURCES/glibc-rh1871394-1.patch @@ -0,0 +1,47 @@ +commit 75870237ff3bb363447b03f4b0af100227570910 +Author: Sunil K Pandey +Date: Fri Jun 12 08:57:16 2020 -0700 + + Fix avx2 strncmp offset compare condition check [BZ #25933] + + strcmp-avx2.S: In avx2 strncmp function, strings are compared in + chunks of 4 vector size(i.e. 32x4=128 byte for avx2). After first 4 + vector size comparison, code must check whether it already passed + the given offset. This patch implement avx2 offset check condition + for strncmp function, if both string compare same for first 4 vector + size. + +diff --git a/sysdeps/x86_64/multiarch/strcmp-avx2.S b/sysdeps/x86_64/multiarch/strcmp-avx2.S +index 5f88a68262..d42b04b54f 100644 +--- a/sysdeps/x86_64/multiarch/strcmp-avx2.S ++++ b/sysdeps/x86_64/multiarch/strcmp-avx2.S +@@ -591,7 +591,14 @@ L(loop_cross_page_2_vec): + movl $(PAGE_SIZE / (VEC_SIZE * 4) - 1), %esi + + testq %rdi, %rdi ++# ifdef USE_AS_STRNCMP ++ /* At this point, if %rdi value is 0, it already tested ++ VEC_SIZE*4+%r10 byte starting from %rax. This label ++ checks whether strncmp maximum offset reached or not. */ ++ je L(string_nbyte_offset_check) ++# else + je L(back_to_loop) ++# endif + tzcntq %rdi, %rcx + addq %r10, %rcx + /* Adjust for number of bytes skipped. */ +@@ -627,6 +634,14 @@ L(loop_cross_page_2_vec): + VZEROUPPER + ret + ++# ifdef USE_AS_STRNCMP ++L(string_nbyte_offset_check): ++ leaq (VEC_SIZE * 4)(%r10), %r10 ++ cmpq %r10, %r11 ++ jbe L(zero) ++ jmp L(back_to_loop) ++# endif ++ + .p2align 4 + L(cross_page_loop): + /* Check one byte/dword at a time. */ diff --git a/SOURCES/glibc-rh1871394-2.patch b/SOURCES/glibc-rh1871394-2.patch new file mode 100644 index 0000000..11ae1e3 --- /dev/null +++ b/SOURCES/glibc-rh1871394-2.patch @@ -0,0 +1,69 @@ +commit f7e3f92b7c45663be808279a43b5221c16001229 +Author: H.J. Lu +Date: Thu May 7 07:29:46 2020 -0700 + + strncmp: Add a testcase for page boundary [BZ #25933] + + Add a strncmp testcase to cover cases where one of strings ends on the + page boundary with the maximum string length less than the number bytes + of each AVX2 loop iteration and different offsets from page boundary. + + The updated string/test-strncmp fails on Intel Core i7-8559U without + + ommit 1c6432316bc434a72108d7b0c7cfbfdde64c3124 + Author: Sunil K Pandey + Date: Fri Jun 12 08:57:16 2020 -0700 + + Fix avx2 strncmp offset compare condition check [BZ #25933] + +diff --git a/string/test-strncmp.c b/string/test-strncmp.c +index d961ac4493..962679b384 100644 +--- a/string/test-strncmp.c ++++ b/string/test-strncmp.c +@@ -403,6 +403,38 @@ check2 (void) + free (s2); + } + ++static void ++check3 (void) ++{ ++ /* To trigger bug 25933, we need a size that is equal to the vector ++ length times 4. In the case of AVX2 for Intel, we need 32 * 4. We ++ make this test generic and run it for all architectures as additional ++ boundary testing for such related algorithms. */ ++ size_t size = 32 * 4; ++ CHAR *s1 = (CHAR *) (buf1 + (BUF1PAGES - 1) * page_size); ++ CHAR *s2 = (CHAR *) (buf2 + (BUF1PAGES - 1) * page_size); ++ int exp_result; ++ ++ memset (s1, 'a', page_size); ++ memset (s2, 'a', page_size); ++ s1[(page_size / CHARBYTES) - 1] = (CHAR) 0; ++ ++ /* Iterate over a size that is just below where we expect the bug to ++ trigger up to the size we expect will trigger the bug e.g. [99-128]. ++ Likewise iterate the start of two strings between 30 and 31 bytes ++ away from the boundary to simulate alignment changes. */ ++ for (size_t s = 99; s <= size; s++) ++ for (size_t s1a = 30; s1a < 32; s1a++) ++ for (size_t s2a = 30; s2a < 32; s2a++) ++ { ++ CHAR *s1p = s1 + (page_size / CHARBYTES - s) - s1a; ++ CHAR *s2p = s2 + (page_size / CHARBYTES - s) - s2a; ++ exp_result = SIMPLE_STRNCMP (s1p, s2p, s); ++ FOR_EACH_IMPL (impl, 0) ++ check_result (impl, s1p, s2p, s, exp_result); ++ } ++} ++ + int + test_main (void) + { +@@ -412,6 +444,7 @@ test_main (void) + + check1 (); + check2 (); ++ check3 (); + + printf ("%23s", ""); + FOR_EACH_IMPL (impl, 0) diff --git a/SOURCES/glibc-rh1871394-3.patch b/SOURCES/glibc-rh1871394-3.patch new file mode 100644 index 0000000..fd47aff --- /dev/null +++ b/SOURCES/glibc-rh1871394-3.patch @@ -0,0 +1,60 @@ +commit 659c0411880328ed341ca26b43d069ec5269a8b5 +Author: H.J. Lu +Date: Thu Jun 11 09:03:56 2020 -0700 + + strcmp: Add a testcase for page boundary + + Add a strcmp testcase to cover cases where both strings end on the page + boundary. + +diff --git a/string/test-strcmp.c b/string/test-strcmp.c +index 8d4784de80..6a840fc04b 100644 +--- a/string/test-strcmp.c ++++ b/string/test-strcmp.c +@@ -359,6 +359,38 @@ check (void) + } + } + ++static void ++check2 (void) ++{ ++ /* To trigger bug 25933, we need a size that is equal to the vector ++ length times 4. In the case of AVX2 for Intel, we need 32 * 4. We ++ make this test generic and run it for all architectures as additional ++ boundary testing for such related algorithms. */ ++ size_t size = 32 * 4; ++ CHAR *s1 = (CHAR *) (buf1 + (BUF1PAGES - 1) * page_size); ++ CHAR *s2 = (CHAR *) (buf2 + (BUF1PAGES - 1) * page_size); ++ int exp_result; ++ ++ memset (s1, 'a', page_size); ++ memset (s2, 'a', page_size); ++ s1[(page_size / CHARBYTES) - 1] = (CHAR) 0; ++ s2[(page_size / CHARBYTES) - 1] = (CHAR) 0; ++ ++ /* Iterate over a size that is just below where we expect the bug to ++ trigger up to the size we expect will trigger the bug e.g. [99-128]. ++ Likewise iterate the start of two strings between 30 and 31 bytes ++ away from the boundary to simulate alignment changes. */ ++ for (size_t s = 99; s <= size; s++) ++ for (size_t s1a = 30; s1a < 32; s1a++) ++ for (size_t s2a = 30; s2a < 32; s2a++) ++ { ++ CHAR *s1p = s1 + (page_size / CHARBYTES - s) - s1a; ++ CHAR *s2p = s2 + (page_size / CHARBYTES - s) - s2a; ++ exp_result = SIMPLE_STRCMP (s1p, s2p); ++ FOR_EACH_IMPL (impl, 0) ++ check_result (impl, s1p, s2p, exp_result); ++ } ++} + + int + test_main (void) +@@ -367,6 +399,7 @@ test_main (void) + + test_init (); + check(); ++ check2 (); + + printf ("%23s", ""); + FOR_EACH_IMPL (impl, 0) diff --git a/SOURCES/glibc-rh1871395-1.patch b/SOURCES/glibc-rh1871395-1.patch new file mode 100644 index 0000000..8f87702 --- /dev/null +++ b/SOURCES/glibc-rh1871395-1.patch @@ -0,0 +1,55 @@ +commit 0792c8ae1aebf538de45ff9a0e2e401a60525de2 +Author: Stefan Liebler +Date: Fri Jun 26 09:45:11 2020 +0200 + + S390: Optimize __memcpy_z196. + + This patch introduces an extra loop without pfd instructions + as it turned out that the pfd instructions are usefull + for copies >=64KB but are counterproductive for smaller copies. + +diff --git a/sysdeps/s390/memcpy-z900.S b/sysdeps/s390/memcpy-z900.S +index f2e9aaeb2d..dc2f491ec3 100644 +--- a/sysdeps/s390/memcpy-z900.S ++++ b/sysdeps/s390/memcpy-z900.S +@@ -184,25 +184,34 @@ ENTRY(MEMCPY_Z196) + je .L_Z196_4 + .L_Z196_start2: + aghi %r4,-1 +- srlg %r5,%r4,8 +- ltgr %r5,%r5 ++ risbg %r5,%r4,8,128+63,56 # r0 = r5 / 256 + jne .L_Z196_5 + .L_Z196_3: + exrl %r4,.L_Z196_14 + .L_Z196_4: + br %r14 + .L_Z196_5: +- cgfi %r5,262144 # Switch to mvcle for copies >64MB +- jh __memcpy_mvcle ++ cgfi %r5,255 # Switch to loop with pfd for copies >=64kB ++ jh .L_Z196_6 + .L_Z196_2: +- pfd 1,768(%r3) +- pfd 2,768(%r1) + mvc 0(256,%r1),0(%r3) + aghi %r5,-1 + la %r1,256(%r1) + la %r3,256(%r3) + jne .L_Z196_2 + j .L_Z196_3 ++.L_Z196_6: ++ cgfi %r5,262144 # Switch to mvcle for copies >64MB ++ jh __memcpy_mvcle ++.L_Z196_7: ++ pfd 1,1024(%r3) ++ pfd 2,1024(%r1) ++ mvc 0(256,%r1),0(%r3) ++ aghi %r5,-1 ++ la %r1,256(%r1) ++ la %r3,256(%r3) ++ jne .L_Z196_7 ++ j .L_Z196_3 + .L_Z196_14: + mvc 0(1,%r1),0(%r3) + END(MEMCPY_Z196) diff --git a/SOURCES/glibc-rh1871395-2.patch b/SOURCES/glibc-rh1871395-2.patch new file mode 100644 index 0000000..d215b5f --- /dev/null +++ b/SOURCES/glibc-rh1871395-2.patch @@ -0,0 +1,54 @@ +commit 1d21fb1061cbeb50414a8f371abb36548d90f150 +Author: Stefan Liebler +Date: Fri Jun 26 09:45:11 2020 +0200 + + S390: Optimize __memset_z196. + + It turned out that an 256b-mvc instruction which depends on the + result of a previous 256b-mvc instruction is counterproductive. + Therefore this patch adjusts the 256b-loop by storing the + first byte with stc and setting the remaining 255b with mvc. + Now the 255b-mvc instruction depends on the stc instruction. + +diff --git a/sysdeps/s390/memset-z900.S b/sysdeps/s390/memset-z900.S +index ca3eac0522..1e0c334156 100644 +--- a/sysdeps/s390/memset-z900.S ++++ b/sysdeps/s390/memset-z900.S +@@ -157,28 +157,27 @@ ENTRY(MEMSET_Z196) + # if !defined __s390x__ + llgfr %r4,%r4 + # endif /* !defined __s390x__ */ +- ltgr %r4,%r4 +- je .L_Z196_4 ++ clgfi %r4,1 ++ jl .L_Z196_4 # n == 0 + stc %r3,0(%r2) ++ je .L_Z196_4 # n == 1 ++ aghi %r4,-2 + lgr %r1,%r2 +- cghi %r4,1 +- je .L_Z196_4 +- aghi %r4,-2 +- srlg %r5,%r4,8 +- ltgr %r5,%r5 +- jne .L_Z196_1 ++ risbg %r5,%r4,8,128+63,56 # r5 = n / 256 ++ jne .L_Z196_1 # Jump away if r5 != 0 + .L_Z196_3: + exrl %r4,.L_Z196_17 + .L_Z196_4: + br %r14 + .L_Z196_1: + cgfi %r5,1048576 +- jh __memset_mvcle # Switch to mvcle for >256MB ++ jh __memset_mvcle # Switch to mvcle for >256MB + .L_Z196_2: + pfd 2,1024(%r1) +- mvc 1(256,%r1),0(%r1) ++ mvc 1(255,%r1),0(%r1) + aghi %r5,-1 + la %r1,256(%r1) ++ stc %r3,0(%r1) + jne .L_Z196_2 + j .L_Z196_3 + .L_Z196_17: diff --git a/SOURCES/glibc-rh1871397-1.patch b/SOURCES/glibc-rh1871397-1.patch new file mode 100644 index 0000000..bf1e46a --- /dev/null +++ b/SOURCES/glibc-rh1871397-1.patch @@ -0,0 +1,233 @@ +From 299210c1fa67e2dfb564475986fce11cd33db9ad Mon Sep 17 00:00:00 2001 +From: Florian Weimer +Date: Thu, 16 Jul 2020 16:12:46 +0200 +Subject: [PATCH 01/11] nss_files: Consolidate file opening in + __nss_files_fopen + +Tested-by: Carlos O'Donell +Reviewed-by: Carlos O'Donell +--- + include/nss_files.h | 28 ++++++++++++++++++++++++ + nss/Makefile | 2 +- + nss/Versions | 1 + + nss/nss_files/files-XXX.c | 3 ++- + nss/nss_files/files-alias.c | 5 +++-- + nss/nss_files/files-initgroups.c | 6 ++--- + nss/nss_files/files-netgrp.c | 5 ++--- + nss/nss_files_fopen.c | 47 ++++++++++++++++++++++++++++++++++++++++ + 8 files changed, 86 insertions(+), 11 deletions(-) + create mode 100644 include/nss_files.h + create mode 100644 nss/nss_files_fopen.c + +diff -rupN a/include/nss_files.h b/include/nss_files.h +--- a/include/nss_files.h 1969-12-31 19:00:00.000000000 -0500 ++++ b/include/nss_files.h 2020-09-11 21:28:42.027034988 -0400 +@@ -0,0 +1,28 @@ ++/* Internal routines for nss_files. ++ 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 ++ . */ ++ ++#ifndef _NSS_FILES_H ++#define _NSS_FILES_H ++ ++#include ++ ++/* Open PATH for reading, as a data source for nss_files. */ ++FILE *__nss_files_fopen (const char *path); ++libc_hidden_proto (__nss_files_fopen) ++ ++#endif /* _NSS_FILES_H */ +diff -rupN a/nss/Makefile b/nss/Makefile +--- a/nss/Makefile 2020-09-11 21:24:05.569544894 -0400 ++++ b/nss/Makefile 2020-09-11 21:28:42.035035292 -0400 +@@ -28,7 +28,7 @@ headers := nss.h + routines = nsswitch getnssent getnssent_r digits_dots \ + valid_field valid_list_field rewrite_field \ + $(addsuffix -lookup,$(databases)) \ +- compat-lookup nss_hash ++ compat-lookup nss_hash nss_files_fopen + + # These are the databases that go through nss dispatch. + # Caution: if you add a database here, you must add its real name +diff -rupN a/nss/Versions b/nss/Versions +--- a/nss/Versions 2020-09-11 21:24:04.852517683 -0400 ++++ b/nss/Versions 2020-09-11 21:28:42.041035519 -0400 +@@ -21,6 +21,7 @@ libc { + __nss_passwd_lookup2; __nss_group_lookup2; __nss_hosts_lookup2; + __nss_services_lookup2; __nss_next2; __nss_lookup; + __nss_hash; __nss_database_lookup2; ++ __nss_files_fopen; + } + } + +diff -rupN a/nss/nss_files/files-XXX.c b/nss/nss_files/files-XXX.c +--- a/nss/nss_files/files-XXX.c 2018-08-01 01:10:47.000000000 -0400 ++++ b/nss/nss_files/files-XXX.c 2020-09-11 21:28:42.049035823 -0400 +@@ -22,6 +22,7 @@ + #include + #include + #include "nsswitch.h" ++#include + + #include + +@@ -74,7 +75,7 @@ internal_setent (FILE **stream) + + if (*stream == NULL) + { +- *stream = fopen (DATAFILE, "rce"); ++ *stream = __nss_files_fopen (DATAFILE); + + if (*stream == NULL) + status = errno == EAGAIN ? NSS_STATUS_TRYAGAIN : NSS_STATUS_UNAVAIL; +diff -rupN a/nss/nss_files/files-alias.c b/nss/nss_files/files-alias.c +--- a/nss/nss_files/files-alias.c 2020-09-11 21:24:02.004409596 -0400 ++++ b/nss/nss_files/files-alias.c 2020-09-11 21:28:42.055036051 -0400 +@@ -29,6 +29,7 @@ + #include + + #include "nsswitch.h" ++#include + + /* Locks the static variables in this file. */ + __libc_lock_define_initialized (static, lock) +@@ -47,7 +48,7 @@ internal_setent (FILE **stream) + + if (*stream == NULL) + { +- *stream = fopen ("/etc/aliases", "rce"); ++ *stream = __nss_files_fopen ("/etc/aliases"); + + if (*stream == NULL) + status = errno == EAGAIN ? NSS_STATUS_TRYAGAIN : NSS_STATUS_UNAVAIL; +@@ -213,7 +214,7 @@ get_next_alias (FILE *stream, const char + + first_unused = cp; + +- listfile = fopen (&cp[9], "rce"); ++ listfile = __nss_files_fopen (&cp[9]); + /* If the file does not exist we simply ignore + the statement. */ + if (listfile != NULL +diff -rupN a/nss/nss_files/files-initgroups.c b/nss/nss_files/files-initgroups.c +--- a/nss/nss_files/files-initgroups.c 2018-08-01 01:10:47.000000000 -0400 ++++ b/nss/nss_files/files-initgroups.c 2020-09-11 22:08:25.130740010 -0400 +@@ -25,22 +25,20 @@ + #include + #include + #include ++#include + + enum nss_status + _nss_files_initgroups_dyn (const char *user, gid_t group, long int *start, + long int *size, gid_t **groupsp, long int limit, + int *errnop) + { +- FILE *stream = fopen ("/etc/group", "rce"); ++ FILE *stream = __nss_files_fopen ("/etc/group"); + if (stream == NULL) + { + *errnop = errno; + return *errnop == ENOMEM ? NSS_STATUS_TRYAGAIN : NSS_STATUS_UNAVAIL; + } + +- /* No other thread using this stream. */ +- __fsetlocking (stream, FSETLOCKING_BYCALLER); +- + char *line = NULL; + size_t linelen = 0; + enum nss_status status = NSS_STATUS_SUCCESS; +diff -rupN a/nss/nss_files/files-netgrp.c b/nss/nss_files/files-netgrp.c +--- a/nss/nss_files/files-netgrp.c 2018-08-01 01:10:47.000000000 -0400 ++++ b/nss/nss_files/files-netgrp.c 2020-09-11 21:28:42.068036544 -0400 +@@ -26,6 +26,7 @@ + #include + #include "nsswitch.h" + #include "netgroup.h" ++#include + + #define DATAFILE "/etc/netgroup" + +@@ -62,7 +63,7 @@ _nss_files_setnetgrent (const char *grou + return NSS_STATUS_UNAVAIL; + + /* Find the netgroups file and open it. */ +- fp = fopen (DATAFILE, "rce"); ++ fp = __nss_files_fopen (DATAFILE); + if (fp == NULL) + status = errno == EAGAIN ? NSS_STATUS_TRYAGAIN : NSS_STATUS_UNAVAIL; + else +@@ -76,8 +77,6 @@ _nss_files_setnetgrent (const char *grou + status = NSS_STATUS_NOTFOUND; + result->cursor = result->data; + +- __fsetlocking (fp, FSETLOCKING_BYCALLER); +- + while (!feof_unlocked (fp)) + { + ssize_t curlen = getline (&line, &line_len, fp); +diff -rupN a/nss/nss_files_fopen.c b/nss/nss_files_fopen.c +--- a/nss/nss_files_fopen.c 1969-12-31 19:00:00.000000000 -0500 ++++ b/nss/nss_files_fopen.c 2020-09-11 21:28:42.074036771 -0400 +@@ -0,0 +1,47 @@ ++/* Open an nss_files database file. ++ 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 ++ ++FILE * ++__nss_files_fopen (const char *path) ++{ ++ FILE *fp = fopen (path, "rce"); ++ if (fp == NULL) ++ return NULL; ++ ++ /* The stream is not shared across threads. */ ++ __fsetlocking (fp, FSETLOCKING_BYCALLER); ++ ++ /* This tells libio that the file is seekable, and that fp->_offset ++ is correct, ensuring that __ftello64 is efficient (bug 26257). */ ++ if (__fseeko64 (fp, 0, SEEK_SET) < 0) ++ { ++ /* nss_files requires seekable files, to deal with repeated ++ reads of the same line after reporting ERANGE. */ ++ fclose (fp); ++ __set_errno (ESPIPE); ++ return NULL; ++ } ++ ++ return fp; ++} ++libc_hidden_def (__nss_files_fopen) diff --git a/SOURCES/glibc-rh1871397-10.patch b/SOURCES/glibc-rh1871397-10.patch new file mode 100644 index 0000000..106a868 --- /dev/null +++ b/SOURCES/glibc-rh1871397-10.patch @@ -0,0 +1,82 @@ +From 00bc6830e3fe3f10495917afe0835ddd19133c6a Mon Sep 17 00:00:00 2001 +From: Florian Weimer +Date: Thu, 16 Jul 2020 17:34:43 +0200 +Subject: [PATCH 10/11] shadow: Implement fgetspent_r using __nss_fgetent_r + +Tested-by: Carlos O'Donell +Reviewed-by: Carlos O'Donell +--- + gshadow/tst-fgetsgent_r.c | 1 + + shadow/fgetspent_r.c | 43 ++++++------------------------------------- + 2 files changed, 7 insertions(+), 37 deletions(-) + +diff -rup a/gshadow/tst-fgetsgent_r.c b/gshadow/tst-fgetsgent_r.c +--- a/gshadow/tst-fgetsgent_r.c 2020-09-14 18:00:57.174146151 -0400 ++++ b/gshadow/tst-fgetsgent_r.c 2020-09-14 19:12:57.867548005 -0400 +@@ -168,6 +168,7 @@ run_test (const char *path, size_t buffe + free (result_storage); + } + ++ xfclose (fp); + return resized; + } + +diff -rup a/shadow/fgetspent_r.c b/shadow/fgetspent_r.c +--- a/shadow/fgetspent_r.c 2018-08-01 01:10:47.000000000 -0400 ++++ b/shadow/fgetspent_r.c 2020-09-14 19:17:15.623285970 -0400 +@@ -20,9 +20,6 @@ + #include + #include + +-#define flockfile(s) _IO_flockfile (s) +-#define funlockfile(s) _IO_funlockfile (s) +- + /* Define a line parsing function using the common code + used in the nss_files module. */ + +@@ -39,39 +36,11 @@ int + __fgetspent_r (FILE *stream, struct spwd *resbuf, char *buffer, size_t buflen, + struct spwd **result) + { +- char *p; +- +- flockfile (stream); +- do +- { +- buffer[buflen - 1] = '\xff'; +- p = fgets_unlocked (buffer, buflen, stream); +- if (p == NULL && feof_unlocked (stream)) +- { +- funlockfile (stream); +- *result = NULL; +- __set_errno (ENOENT); +- return errno; +- } +- if (p == NULL || buffer[buflen - 1] != '\xff') +- { +- funlockfile (stream); +- *result = NULL; +- __set_errno (ERANGE); +- return errno; +- } +- +- /* Skip leading blanks. */ +- while (isspace (*p)) +- ++p; +- } while (*p == '\0' || *p == '#' || /* Ignore empty and comment lines. */ +- /* Parse the line. If it is invalid, loop to +- get the next line of the file to parse. */ +- ! parse_line (buffer, (void *) resbuf, NULL, 0, &errno)); +- +- funlockfile (stream); +- +- *result = resbuf; +- return 0; ++ int ret = __nss_fgetent_r (stream, resbuf, buffer, buflen, parse_line); ++ if (ret == 0) ++ *result = resbuf; ++ else ++ *result = NULL; ++ return ret; + } + weak_alias (__fgetspent_r, fgetspent_r) diff --git a/SOURCES/glibc-rh1871397-11.patch b/SOURCES/glibc-rh1871397-11.patch new file mode 100644 index 0000000..e045949 --- /dev/null +++ b/SOURCES/glibc-rh1871397-11.patch @@ -0,0 +1,492 @@ +From ec2f1fddf29053957d061dfe310f106388472a4f Mon Sep 17 00:00:00 2001 +From: Florian Weimer +Date: Wed, 15 Jul 2020 12:37:01 +0200 +Subject: [PATCH 11/11] libio: Remove __libc_readline_unlocked + +__nss_readline supersedes it. This reverts part of commit +3f5e3f5d066dcffb80af48ae2cf35a01a85a8f10 ("libio: Implement +internal function __libc_readline_unlocked"). The internal +aliases __fseeko64 and __ftello64 are preserved because +they are needed by __nss_readline as well. + +Tested-by: Carlos O'Donell +Reviewed-by: Carlos O'Donell +--- + include/stdio.h | 13 --- + libio/Makefile | 4 +- + libio/Versions | 1 - + libio/readline.c | 170 ------------------------------------ + libio/tst-readline.c | 237 --------------------------------------------------- + 5 files changed, 2 insertions(+), 423 deletions(-) + delete mode 100644 libio/readline.c + delete mode 100644 libio/tst-readline.c + +diff -rupN a/include/stdio.h b/include/stdio.h +--- a/include/stdio.h 2020-09-14 17:48:49.359699532 -0400 ++++ b/include/stdio.h 2020-09-14 19:20:51.204429471 -0400 +@@ -135,19 +135,6 @@ extern int __fxprintf (FILE *__fp, const + extern int __fxprintf_nocancel (FILE *__fp, const char *__fmt, ...) + __attribute__ ((__format__ (__printf__, 2, 3))) attribute_hidden; + +-/* Read the next line from FP into BUFFER, of LENGTH bytes. LINE will +- include the line terminator and a NUL terminator. On success, +- return the length of the line, including the line terminator, but +- excluding the NUL termintor. On EOF, return zero and write a NUL +- terminator. On error, return -1 and set errno. If the total byte +- count (line and both terminators) exceeds LENGTH, return -1 and set +- errno to ERANGE (but do not mark the stream as failed). +- +- The behavior is undefined if FP is not seekable, or if the stream +- is already in an error state. */ +-ssize_t __libc_readline_unlocked (FILE *fp, char *buffer, size_t length); +-libc_hidden_proto (__libc_readline_unlocked); +- + extern const char *const _sys_errlist_internal[] attribute_hidden; + extern int _sys_nerr_internal attribute_hidden; + +diff -rupN a/libio/Makefile b/libio/Makefile +--- a/libio/Makefile 2020-09-14 17:48:45.722562485 -0400 ++++ b/libio/Makefile 2020-09-14 19:20:51.211429735 -0400 +@@ -49,7 +49,7 @@ routines := \ + __fbufsize __freading __fwriting __freadable __fwritable __flbf \ + __fpurge __fpending __fsetlocking \ + \ +- libc_fatal fmemopen oldfmemopen vtables readline ++ libc_fatal fmemopen oldfmemopen vtables + + tests = tst_swprintf tst_wprintf tst_swscanf tst_wscanf tst_getwc tst_putwc \ + tst_wprintf2 tst-widetext test-fmemopen tst-ext tst-ext2 \ +@@ -67,7 +67,7 @@ tests = tst_swprintf tst_wprintf tst_sws + tst-ftell-append tst-fputws tst-bz22415 tst-fgetc-after-eof \ + tst-wfile-sync + +-tests-internal = tst-vtables tst-vtables-interposed tst-readline ++tests-internal = tst-vtables tst-vtables-interposed + + ifeq (yes,$(build-shared)) + # Add test-fopenloc only if shared library is enabled since it depends on +diff -rupN a/libio/Versions b/libio/Versions +--- a/libio/Versions 2018-08-01 01:10:47.000000000 -0400 ++++ b/libio/Versions 2020-09-14 19:20:51.217429962 -0400 +@@ -161,6 +161,5 @@ libc { + + __fseeko64; + __ftello64; +- __libc_readline_unlocked; + } + } +diff -rupN a/libio/readline.c b/libio/readline.c +--- a/libio/readline.c 2018-08-01 01:10:47.000000000 -0400 ++++ b/libio/readline.c 1969-12-31 19:00:00.000000000 -0500 +@@ -1,170 +0,0 @@ +-/* fgets with ERANGE error reporting and size_t buffer length. +- 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 +-#include +- +-#include "libioP.h" +- +-/* Return -1 and set errno to EINVAL if it is ERANGE. */ +-static ssize_t +-fail_no_erange (void) +-{ +- if (errno == ERANGE) +- __set_errno (EINVAL); +- return -1; +-} +- +-/* Slow path for reading the line. Called with no data in the stream +- read buffer. Write data to [BUFFER, BUFFER_END). */ +-static ssize_t +-readline_slow (FILE *fp, char *buffer, char *buffer_end) +-{ +- char *start = buffer; +- +- while (buffer < buffer_end) +- { +- if (__underflow (fp) == EOF) +- { +- if (_IO_ferror_unlocked (fp)) +- /* If the EOF was caused by a read error, report it. */ +- return fail_no_erange (); +- *buffer = '\0'; +- /* Do not include the null terminator. */ +- return buffer - start; +- } +- +- /* __underflow has filled the buffer. */ +- char *readptr = fp->_IO_read_ptr; +- ssize_t readlen = fp->_IO_read_end - readptr; +- /* Make sure that __underflow really has acquired some data. */ +- assert (readlen > 0); +- char *pnl = memchr (readptr, '\n', readlen); +- if (pnl != NULL) +- { +- /* We found the terminator. */ +- size_t line_length = pnl - readptr; +- if (line_length + 2 > buffer_end - buffer) +- /* Not enough room in the caller-supplied buffer. */ +- break; +- memcpy (buffer, readptr, line_length + 1); +- buffer[line_length + 1] = '\0'; +- fp->_IO_read_ptr = pnl + 1; +- /* Do not include the null terminator. */ +- return buffer - start + line_length + 1; +- } +- +- if (readlen >= buffer_end - buffer) +- /* Not enough room in the caller-supplied buffer. */ +- break; +- +- /* Save and consume the stream buffer. */ +- memcpy (buffer, readptr, readlen); +- fp->_IO_read_ptr = fp->_IO_read_end; +- buffer += readlen; +- } +- +- /* The line does not fit into the buffer. */ +- __set_errno (ERANGE); +- return -1; +-} +- +-ssize_t +-__libc_readline_unlocked (FILE *fp, char *buffer, size_t buffer_length) +-{ +- char *buffer_end = buffer + buffer_length; +- +- /* Orient the stream. */ +- if (__builtin_expect (fp->_mode, -1) == 0) +- _IO_fwide (fp, -1); +- +- /* Fast path: The line terminator is found in the buffer. */ +- char *readptr = fp->_IO_read_ptr; +- ssize_t readlen = fp->_IO_read_end - readptr; +- off64_t start_offset; /* File offset before reading anything. */ +- if (readlen > 0) +- { +- char *pnl = memchr (readptr, '\n', readlen); +- if (pnl != NULL) +- { +- size_t line_length = pnl - readptr; +- /* Account for line and null terminators. */ +- if (line_length + 2 > buffer_length) +- { +- __set_errno (ERANGE); +- return -1; +- } +- memcpy (buffer, readptr, line_length + 1); +- buffer[line_length + 1] = '\0'; +- /* Consume the entire line. */ +- fp->_IO_read_ptr = pnl + 1; +- return line_length + 1; +- } +- +- /* If the buffer does not have enough space for what is pending +- in the stream (plus a NUL terminator), the buffer is too +- small. */ +- if (readlen + 1 > buffer_length) +- { +- __set_errno (ERANGE); +- return -1; +- } +- +- /* End of line not found. We need all the buffered data. Fall +- through to the slow path. */ +- memcpy (buffer, readptr, readlen); +- buffer += readlen; +- /* The original length is invalid after this point. Use +- buffer_end instead. */ +-#pragma GCC poison buffer_length +- /* Read the old offset before updating the read pointer. */ +- start_offset = __ftello64 (fp); +- fp->_IO_read_ptr = fp->_IO_read_end; +- } +- else +- { +- readlen = 0; +- start_offset = __ftello64 (fp); +- } +- +- /* Slow path: Read more data from the underlying file. We need to +- restore the file pointer if the buffer is too small. First, +- check if the __ftello64 call above failed. */ +- if (start_offset < 0) +- return fail_no_erange (); +- +- ssize_t result = readline_slow (fp, buffer, buffer_end); +- if (result < 0) +- { +- if (errno == ERANGE) +- { +- /* Restore the file pointer so that the caller may read the +- same line again. */ +- if (__fseeko64 (fp, start_offset, SEEK_SET) < 0) +- return fail_no_erange (); +- __set_errno (ERANGE); +- } +- /* Do not restore the file position on other errors; it is +- likely that the __fseeko64 call would fail, too. */ +- return -1; +- } +- return readlen + result; +-} +-libc_hidden_def (__libc_readline_unlocked) +diff -rupN a/libio/tst-readline.c b/libio/tst-readline.c +--- a/libio/tst-readline.c 2020-09-14 17:48:41.969421067 -0400 ++++ b/libio/tst-readline.c 1969-12-31 19:00:00.000000000 -0500 +@@ -1,237 +0,0 @@ +-/* Test the __libc_readline_unlocked function. +- 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 +- . */ +- +-/* Exercise __libc_readline_unlocked with various combinations of line +- lengths, stdio buffer sizes, and line read buffer sizes. */ +- +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +- +-enum +- { +- maximum_line_length = 7, +- number_of_lines = 3, +- }; +- +-/* -1: Do not set buffer size. 0: unbuffered. Otherwise, use this as +- the size of the buffer. */ +-static int buffer_size; +- +-/* These size of the buffer used for reading. Must be at least 2. */ +-static int read_size; +- +-/* If a read files with ERANGE, increase the buffer size by this +- amount. Must be positive. */ +-static int read_size_increment; +- +-/* If non-zero, do not reset the read size after an ERANGE error. */ +-static int read_size_preserve; +- +-/* If non-zero, no '\n' at the end of the file. */ +-static int no_newline_at_eof; +- +-/* Length of the line, or -1 if the line is not present. */ +-static int line_lengths[number_of_lines]; +- +-/* The name of the test file. */ +-static char *test_file_path; +- +-/* The contents of the test file. */ +-static char expected_contents[(maximum_line_length + 2) * number_of_lines + 1]; +-static size_t expected_length; +- +-/* Returns a random byte which is not zero or the line terminator. */ +-static char +-random_char (void) +-{ +- static unsigned int rand_state = 1; +- while (true) +- { +- char result = rand_r (&rand_state) >> 16; +- if (result != 0 && result != '\n') +- return result; +- } +-} +- +-/* Create the test file. */ +-static void +-prepare (int argc, char **argv) +-{ +- int fd = create_temp_file ("tst-readline-", &test_file_path); +- TEST_VERIFY_EXIT (fd >= 0); +- xclose (fd); +-} +- +-/* Prepare the test file. Return false if the test parameters are +- incongruent and the test should be skipped. */ +-static bool +-write_test_file (void) +-{ +- expected_length = 0; +- char *p = expected_contents; +- for (int lineno = 0; lineno < number_of_lines; ++lineno) +- for (int i = 0; i < line_lengths[lineno]; ++i) +- *p++ = random_char (); +- expected_length = p - &expected_contents[0]; +- if (no_newline_at_eof) +- { +- if (expected_length == 0) +- return false; +- --expected_length; +- --p; +- } +- if (test_verbose > 0) +- { +- printf ("info: writing test file of %zu bytes:\n", expected_length); +- for (int i = 0; i < number_of_lines; ++i) +- printf (" line %d: %d\n", i, line_lengths[i]); +- if (no_newline_at_eof) +- puts (" (no newline at EOF)"); +- } +- TEST_VERIFY_EXIT (expected_length < sizeof (expected_contents)); +- *p++ = '\0'; +- support_write_file_string (test_file_path, expected_contents); +- return true; +-} +- +-/* Run a single test (a combination of a test file and read +- parameters). */ +-static void +-run_test (void) +-{ +- TEST_VERIFY_EXIT (read_size_increment > 0); +- if (test_verbose > 0) +- { +- printf ("info: running test: buffer_size=%d read_size=%d\n" +- " read_size_increment=%d read_size_preserve=%d\n", +- buffer_size, read_size, read_size_increment, read_size_preserve); +- } +- +- struct xmemstream result; +- xopen_memstream (&result); +- +- FILE *fp = xfopen (test_file_path, "rce"); +- char *fp_buffer = NULL; +- if (buffer_size == 0) +- TEST_VERIFY_EXIT (setvbuf (fp, NULL, _IONBF, 0) == 0); +- if (buffer_size > 0) +- { +- fp_buffer = xmalloc (buffer_size); +- TEST_VERIFY_EXIT (setvbuf (fp, fp_buffer, _IOFBF, buffer_size) == 0); +- } +- +- char *line_buffer = xmalloc (read_size); +- size_t line_buffer_size = read_size; +- +- while (true) +- { +- ssize_t ret = __libc_readline_unlocked +- (fp, line_buffer, line_buffer_size); +- if (ret < 0) +- { +- TEST_VERIFY (ret == -1); +- if (errno != ERANGE) +- FAIL_EXIT1 ("__libc_readline_unlocked: %m"); +- line_buffer_size += read_size_increment; +- free (line_buffer); +- line_buffer = xmalloc (line_buffer_size); +- /* Try reading this line again. */ +- } +- else if (ret == 0) +- break; +- else +- { +- /* A line has been read. Save it. */ +- TEST_VERIFY (ret == strlen (line_buffer)); +- const char *pnl = strchr (line_buffer, '\n'); +- /* If there is a \n, it must be at the end. */ +- TEST_VERIFY (pnl == NULL || pnl == line_buffer + ret - 1); +- fputs (line_buffer, result.out); +- +- /* Restore the original read size if required. */ +- if (line_buffer_size > read_size && !read_size_preserve) +- { +- line_buffer_size = read_size; +- free (line_buffer); +- line_buffer = xmalloc (line_buffer_size); +- } +- } +- } +- +- xfclose (fp); +- free (fp_buffer); +- free (line_buffer); +- +- xfclose_memstream (&result); +- TEST_VERIFY (result.length == expected_length); +- TEST_VERIFY (strcmp (result.buffer, expected_contents) == 0); +- if (test_verbose > 0) +- { +- printf ("info: expected (%zu): [[%s]]\n", +- expected_length, expected_contents); +- printf ("info: actual (%zu): [[%s]]\n", result.length, result.buffer); +- } +- free (result.buffer); +-} +- +-/* Test one test file with multiple read parameters. */ +-static void +-test_one_file (void) +-{ +- for (buffer_size = -1; buffer_size <= maximum_line_length + 1; ++buffer_size) +- for (read_size = 2; read_size <= maximum_line_length + 2; ++read_size) +- for (read_size_increment = 1; read_size_increment <= 4; +- ++read_size_increment) +- for (read_size_preserve = 0; read_size_preserve < 2; +- ++read_size_preserve) +- run_test (); +-} +- +- +-static int +-do_test (void) +-{ +- /* Set up the test file contents. */ +- for (line_lengths[0] = -1; line_lengths[0] <= maximum_line_length; +- ++line_lengths[0]) +- for (line_lengths[1] = -1; line_lengths[1] <= maximum_line_length; +- ++line_lengths[1]) +- for (line_lengths[2] = -1; line_lengths[2] <= maximum_line_length; +- ++line_lengths[2]) +- for (no_newline_at_eof = 0; no_newline_at_eof < 2; ++no_newline_at_eof) +- { +- if (!write_test_file ()) +- continue; +- test_one_file (); +- } +- free (test_file_path); +- return 0; +-} +- +-#define TIMEOUT 100 +-#define PREPARE prepare +-#include diff --git a/SOURCES/glibc-rh1871397-2.patch b/SOURCES/glibc-rh1871397-2.patch new file mode 100644 index 0000000..1b95b01 --- /dev/null +++ b/SOURCES/glibc-rh1871397-2.patch @@ -0,0 +1,123 @@ +From 23ed36735af09c258e542266aaed92cdd8571c6c Mon Sep 17 00:00:00 2001 +From: Florian Weimer +Date: Thu, 16 Jul 2020 16:21:28 +0200 +Subject: [PATCH 02/11] nss_compat: Do not use mmap to read database files (bug + 26258) + +This avoids crashes in case the files are truncated for some reason. +For typically file sizes, it is also going to be slightly faster. +Using __nss_files_fopen instead mirrors what nss_files does. + +Tested-by: Carlos O'Donell +Reviewed-by: Carlos O'Donell +--- + nss/nss_compat/compat-grp.c | 6 ++---- + nss/nss_compat/compat-initgroups.c | 6 ++---- + nss/nss_compat/compat-pwd.c | 6 ++---- + nss/nss_compat/compat-spwd.c | 6 ++---- + 4 files changed, 8 insertions(+), 16 deletions(-) + +diff -rup a/nss/nss_compat/compat-grp.c b/nss/nss_compat/compat-grp.c +--- a/nss/nss_compat/compat-grp.c 2020-09-14 15:49:18.248178627 -0400 ++++ b/nss/nss_compat/compat-grp.c 2020-09-14 17:18:22.514977541 -0400 +@@ -26,6 +26,7 @@ + #include + #include + #include ++#include + + static service_user *ni; + static enum nss_status (*nss_setgrent) (int stayopen); +@@ -106,13 +107,10 @@ internal_setgrent (ent_t *ent, int stayo + + if (ent->stream == NULL) + { +- ent->stream = fopen ("/etc/group", "rme"); ++ ent->stream = __nss_files_fopen ("/etc/group"); + + if (ent->stream == NULL) + status = errno == EAGAIN ? NSS_STATUS_TRYAGAIN : NSS_STATUS_UNAVAIL; +- else +- /* We take care of locking ourself. */ +- __fsetlocking (ent->stream, FSETLOCKING_BYCALLER); + } + else + rewind (ent->stream); +diff -rup a/nss/nss_compat/compat-initgroups.c b/nss/nss_compat/compat-initgroups.c +--- a/nss/nss_compat/compat-initgroups.c 2020-09-14 15:49:18.255178892 -0400 ++++ b/nss/nss_compat/compat-initgroups.c 2020-09-14 17:18:22.519977728 -0400 +@@ -29,6 +29,7 @@ + #include + #include + #include ++#include + + static service_user *ni; + /* Type of the lookup function. */ +@@ -121,13 +122,10 @@ internal_setgrent (ent_t *ent) + else + ent->blacklist.current = 0; + +- ent->stream = fopen ("/etc/group", "rme"); ++ ent->stream = __nss_files_fopen ("/etc/group"); + + if (ent->stream == NULL) + status = errno == EAGAIN ? NSS_STATUS_TRYAGAIN : NSS_STATUS_UNAVAIL; +- else +- /* We take care of locking ourself. */ +- __fsetlocking (ent->stream, FSETLOCKING_BYCALLER); + + return status; + } +diff -rup a/nss/nss_compat/compat-pwd.c b/nss/nss_compat/compat-pwd.c +--- a/nss/nss_compat/compat-pwd.c 2020-09-14 15:49:18.260179081 -0400 ++++ b/nss/nss_compat/compat-pwd.c 2020-09-14 17:18:22.523977879 -0400 +@@ -27,6 +27,7 @@ + #include + #include + #include ++#include + + #include "netgroup.h" + #include "nisdomain.h" +@@ -221,13 +222,10 @@ internal_setpwent (ent_t *ent, int stayo + + if (ent->stream == NULL) + { +- ent->stream = fopen ("/etc/passwd", "rme"); ++ ent->stream = __nss_files_fopen ("/etc/passwd"); + + if (ent->stream == NULL) + status = errno == EAGAIN ? NSS_STATUS_TRYAGAIN : NSS_STATUS_UNAVAIL; +- else +- /* We take care of locking ourself. */ +- __fsetlocking (ent->stream, FSETLOCKING_BYCALLER); + } + else + rewind (ent->stream); +diff -rup a/nss/nss_compat/compat-spwd.c b/nss/nss_compat/compat-spwd.c +--- a/nss/nss_compat/compat-spwd.c 2020-09-14 15:49:18.264179232 -0400 ++++ b/nss/nss_compat/compat-spwd.c 2020-09-14 17:18:22.527978029 -0400 +@@ -27,6 +27,7 @@ + #include + #include + #include ++#include + + #include "netgroup.h" + #include "nisdomain.h" +@@ -177,13 +178,10 @@ internal_setspent (ent_t *ent, int stayo + + if (ent->stream == NULL) + { +- ent->stream = fopen ("/etc/shadow", "rme"); ++ ent->stream = __nss_files_fopen ("/etc/shadow"); + + if (ent->stream == NULL) + status = errno == EAGAIN ? NSS_STATUS_TRYAGAIN : NSS_STATUS_UNAVAIL; +- else +- /* We take care of locking ourself. */ +- __fsetlocking (ent->stream, FSETLOCKING_BYCALLER); + } + else + rewind (ent->stream); diff --git a/SOURCES/glibc-rh1871397-3.patch b/SOURCES/glibc-rh1871397-3.patch new file mode 100644 index 0000000..474ab8b --- /dev/null +++ b/SOURCES/glibc-rh1871397-3.patch @@ -0,0 +1,227 @@ +From e9b2340998ab22402a8e968ba674c380a625b9dc Mon Sep 17 00:00:00 2001 +From: Florian Weimer +Date: Thu, 16 Jul 2020 16:40:44 +0200 +Subject: [PATCH 03/11] nss_files: Consolidate line parse declarations in + + +These functions should eventually have the same type, so it makes +sense to declare them together. + +Tested-by: Carlos O'Donell +Reviewed-by: Carlos O'Donell +--- + include/grp.h | 6 ------ + include/gshadow.h | 6 ------ + include/netdb.h | 13 ------------ + include/netinet/ether.h | 6 ------ + include/nss_files.h | 51 +++++++++++++++++++++++++++++++++++++++++++++ + include/pwd.h | 6 ------ + include/rpc/netdb.h | 6 ------ + include/shadow.h | 6 ------ + nss/nss_files/files-parse.c | 1 + + 9 files changed, 52 insertions(+), 49 deletions(-) + +diff --git a/include/grp.h b/include/grp.h +index 58f7b4d..2cd2475 100644 +--- a/include/grp.h ++++ b/include/grp.h +@@ -30,12 +30,6 @@ extern int __old_getgrnam_r (const char *__name, struct group *__resultbuf, + char *__buffer, size_t __buflen, + struct group **__result); + +-struct parser_data; +-extern int _nss_files_parse_grent (char *line, struct group *result, +- struct parser_data *data, +- size_t datalen, int *errnop); +-libc_hidden_proto (_nss_files_parse_grent) +- + #define DECLARE_NSS_PROTOTYPES(service) \ + extern enum nss_status _nss_ ## service ## _setgrent (int); \ + extern enum nss_status _nss_ ## service ## _endgrent (void); \ +diff --git a/include/gshadow.h b/include/gshadow.h +index aa6a5a6..1cefcfc 100644 +--- a/include/gshadow.h ++++ b/include/gshadow.h +@@ -10,11 +10,5 @@ extern int __sgetsgent_r (const char *string, struct sgrp *resbuf, + char *buffer, size_t buflen, struct sgrp **result) + attribute_hidden; + +-struct parser_data; +-extern int _nss_files_parse_sgent (char *line, struct sgrp *result, +- struct parser_data *data, +- size_t datalen, int *errnop); +-libc_hidden_proto (_nss_files_parse_sgent) +- + # endif /* !_ISOMAC */ + #endif +diff --git a/include/netdb.h b/include/netdb.h +index 6b43135..49d63c1 100644 +--- a/include/netdb.h ++++ b/include/netdb.h +@@ -202,23 +202,10 @@ libc_hidden_proto (ruserpass) + + #include + +-struct parser_data; +-extern int _nss_files_parse_protoent (char *line, struct protoent *result, +- struct parser_data *data, +- size_t datalen, int *errnop); +-extern int _nss_files_parse_servent (char *line, struct servent *result, +- struct parser_data *data, +- size_t datalen, int *errnop); +-extern int _nss_files_parse_netent (char *line, struct netent *result, +- struct parser_data *data, +- size_t datalen, int *errnop); + extern enum nss_status _nss_netgroup_parseline (char **cursor, + struct __netgrent *result, + char *buffer, size_t buflen, + int *errnop); +-libnss_files_hidden_proto (_nss_files_parse_protoent) +-libnss_files_hidden_proto (_nss_files_parse_servent) +-libnss_files_hidden_proto (_nss_files_parse_netent) + libnss_files_hidden_proto (_nss_netgroup_parseline) + + #define DECLARE_NSS_PROTOTYPES(service) \ +diff --git a/include/netinet/ether.h b/include/netinet/ether.h +index 8fd05f8..1763a7e 100644 +--- a/include/netinet/ether.h ++++ b/include/netinet/ether.h +@@ -15,12 +15,6 @@ struct etherent + struct ether_addr e_addr; + }; + +-struct parser_data; +-extern int _nss_files_parse_etherent (char *line, struct etherent *result, +- struct parser_data *data, +- size_t datalen, int *errnop); +-libnss_files_hidden_proto (_nss_files_parse_etherent) +- + #define DECLARE_NSS_PROTOTYPES(service) \ + extern enum nss_status _nss_ ## service ## _setetherent (int __stayopen); \ + extern enum nss_status _nss_ ## service ## _endetherent (void); \ +diff --git a/include/nss_files.h b/include/nss_files.h +index 17144b7..54b354a 100644 +--- a/include/nss_files.h ++++ b/include/nss_files.h +@@ -25,4 +25,55 @@ + FILE *__nss_files_fopen (const char *path); + libc_hidden_proto (__nss_files_fopen) + ++struct parser_data; ++struct etherent; ++struct group; ++struct netent; ++struct passwd; ++struct protoent; ++struct rpcent; ++struct servent; ++struct sgrp; ++struct spwd; ++ ++/* Instances of the parse_line function from ++ nss/nss_files/files-parse.c. */ ++extern int _nss_files_parse_etherent (char *line, struct etherent *result, ++ struct parser_data *data, ++ size_t datalen, int *errnop); ++extern int _nss_files_parse_grent (char *line, struct group *result, ++ struct parser_data *data, ++ size_t datalen, int *errnop); ++extern int _nss_files_parse_netent (char *line, struct netent *result, ++ struct parser_data *data, ++ size_t datalen, int *errnop); ++extern int _nss_files_parse_protoent (char *line, struct protoent *result, ++ struct parser_data *data, ++ size_t datalen, int *errnop); ++extern int _nss_files_parse_pwent (char *line, struct passwd *result, ++ struct parser_data *data, ++ size_t datalen, int *errnop); ++extern int _nss_files_parse_rpcent (char *line, struct rpcent *result, ++ struct parser_data *data, ++ size_t datalen, int *errnop); ++extern int _nss_files_parse_servent (char *line, struct servent *result, ++ struct parser_data *data, ++ size_t datalen, int *errnop); ++extern int _nss_files_parse_sgent (char *line, struct sgrp *result, ++ struct parser_data *data, ++ size_t datalen, int *errnop); ++extern int _nss_files_parse_spent (char *line, struct spwd *result, ++ struct parser_data *data, ++ size_t datalen, int *errnop); ++ ++libnss_files_hidden_proto (_nss_files_parse_etherent) ++libc_hidden_proto (_nss_files_parse_grent) ++libnss_files_hidden_proto (_nss_files_parse_netent) ++libnss_files_hidden_proto (_nss_files_parse_protoent) ++libc_hidden_proto (_nss_files_parse_pwent) ++libnss_files_hidden_proto (_nss_files_parse_rpcent) ++libnss_files_hidden_proto (_nss_files_parse_servent) ++libc_hidden_proto (_nss_files_parse_sgent) ++libc_hidden_proto (_nss_files_parse_spent) ++ + #endif /* _NSS_FILES_H */ +diff --git a/include/pwd.h b/include/pwd.h +index fd23fe9..f8975d4 100644 +--- a/include/pwd.h ++++ b/include/pwd.h +@@ -26,12 +26,6 @@ extern int __fgetpwent_r (FILE * __stream, struct passwd *__resultbuf, + + #include + +-struct parser_data; +-extern int _nss_files_parse_pwent (char *line, struct passwd *result, +- struct parser_data *data, +- size_t datalen, int *errnop); +-libc_hidden_proto (_nss_files_parse_pwent) +- + #define DECLARE_NSS_PROTOTYPES(service) \ + extern enum nss_status _nss_ ## service ## _setpwent (int); \ + extern enum nss_status _nss_ ## service ## _endpwent (void); \ +diff --git a/include/rpc/netdb.h b/include/rpc/netdb.h +index 5ddd776..c1a936e 100644 +--- a/include/rpc/netdb.h ++++ b/include/rpc/netdb.h +@@ -24,12 +24,6 @@ extern int __getrpcent_r (struct rpcent *__result_buf, char *__buffer, + extern int __old_getrpcent_r (struct rpcent *__result_buf, char *__buffer, + size_t __buflen, struct rpcent **__result); + +-struct parser_data; +-extern int _nss_files_parse_rpcent (char *line, struct rpcent *result, +- struct parser_data *data, +- size_t datalen, int *errnop); +-libnss_files_hidden_proto (_nss_files_parse_rpcent) +- + #define DECLARE_NSS_PROTOTYPES(service) \ + extern enum nss_status _nss_ ## service ## _setrpcent (int); \ + extern enum nss_status _nss_ ## service ## _endrpcent (void); \ +diff --git a/include/shadow.h b/include/shadow.h +index 5168d8d..fb16819 100644 +--- a/include/shadow.h ++++ b/include/shadow.h +@@ -25,12 +25,6 @@ extern int __fgetspent_r (FILE *__stream, struct spwd *__result_buf, + extern int __lckpwdf (void); + extern int __ulckpwdf (void); + +-struct parser_data; +-extern int _nss_files_parse_spent (char *line, struct spwd *result, +- struct parser_data *data, +- size_t datalen, int *errnop); +-libc_hidden_proto (_nss_files_parse_spent) +- + #define DECLARE_NSS_PROTOTYPES(service) \ + extern enum nss_status _nss_ ## service ## _setspent (int); \ + extern enum nss_status _nss_ ## service ## _endspent (void); \ +diff --git a/nss/nss_files/files-parse.c b/nss/nss_files/files-parse.c +index a563d81..3820287 100644 +--- a/nss/nss_files/files-parse.c ++++ b/nss/nss_files/files-parse.c +@@ -21,6 +21,7 @@ + #include + #include + #include ++#include + + /* These symbols are defined by the including source file: + +-- +1.8.3.1 + diff --git a/SOURCES/glibc-rh1871397-4.patch b/SOURCES/glibc-rh1871397-4.patch new file mode 100644 index 0000000..aed1bd8 --- /dev/null +++ b/SOURCES/glibc-rh1871397-4.patch @@ -0,0 +1,111 @@ +From 9980bf0b307368959cb29f3ca3f7446ad92347f1 Mon Sep 17 00:00:00 2001 +From: Florian Weimer +Date: Thu, 16 Jul 2020 16:55:45 +0200 +Subject: [PATCH 04/11] nss_files: Use generic result pointer in parse_line + +As a result, all parse_line functions have the same prototype, except +for that producing struct hostent. This change is ABI-compatible, so +it does not alter the internal GLIBC_PRIVATE ABI (otherwise we should +probably have renamed the exported functions). + +A future change will use this to implement a generict fget*ent_r +function. + +Tested-by: Carlos O'Donell +Reviewed-by: Carlos O'Donell +--- + include/nss_files.h | 48 ++++++++++++--------------------------------- + nss/nss_files/files-parse.c | 5 +++-- + 2 files changed, 15 insertions(+), 38 deletions(-) + +diff --git a/include/nss_files.h b/include/nss_files.h +index 54b354a..d0f2681 100644 +--- a/include/nss_files.h ++++ b/include/nss_files.h +@@ -26,45 +26,21 @@ FILE *__nss_files_fopen (const char *path); + libc_hidden_proto (__nss_files_fopen) + + struct parser_data; +-struct etherent; +-struct group; +-struct netent; +-struct passwd; +-struct protoent; +-struct rpcent; +-struct servent; +-struct sgrp; +-struct spwd; + + /* Instances of the parse_line function from + nss/nss_files/files-parse.c. */ +-extern int _nss_files_parse_etherent (char *line, struct etherent *result, +- struct parser_data *data, +- size_t datalen, int *errnop); +-extern int _nss_files_parse_grent (char *line, struct group *result, +- struct parser_data *data, +- size_t datalen, int *errnop); +-extern int _nss_files_parse_netent (char *line, struct netent *result, +- struct parser_data *data, +- size_t datalen, int *errnop); +-extern int _nss_files_parse_protoent (char *line, struct protoent *result, +- struct parser_data *data, +- size_t datalen, int *errnop); +-extern int _nss_files_parse_pwent (char *line, struct passwd *result, +- struct parser_data *data, +- size_t datalen, int *errnop); +-extern int _nss_files_parse_rpcent (char *line, struct rpcent *result, +- struct parser_data *data, +- size_t datalen, int *errnop); +-extern int _nss_files_parse_servent (char *line, struct servent *result, +- struct parser_data *data, +- size_t datalen, int *errnop); +-extern int _nss_files_parse_sgent (char *line, struct sgrp *result, +- struct parser_data *data, +- size_t datalen, int *errnop); +-extern int _nss_files_parse_spent (char *line, struct spwd *result, +- struct parser_data *data, +- size_t datalen, int *errnop); ++typedef int nss_files_parse_line (char *line, void *result, ++ struct parser_data *data, ++ size_t datalen, int *errnop); ++extern nss_files_parse_line _nss_files_parse_etherent; ++extern nss_files_parse_line _nss_files_parse_grent; ++extern nss_files_parse_line _nss_files_parse_netent; ++extern nss_files_parse_line _nss_files_parse_protoent; ++extern nss_files_parse_line _nss_files_parse_pwent; ++extern nss_files_parse_line _nss_files_parse_rpcent; ++extern nss_files_parse_line _nss_files_parse_servent; ++extern nss_files_parse_line _nss_files_parse_sgent; ++extern nss_files_parse_line _nss_files_parse_spent; + + libnss_files_hidden_proto (_nss_files_parse_etherent) + libc_hidden_proto (_nss_files_parse_grent) +diff --git a/nss/nss_files/files-parse.c b/nss/nss_files/files-parse.c +index 3820287..c6cd43b 100644 +--- a/nss/nss_files/files-parse.c ++++ b/nss/nss_files/files-parse.c +@@ -87,7 +87,7 @@ struct parser_data + #ifdef EXTERN_PARSER + + /* The parser is defined in a different module. */ +-extern int parse_line (char *line, struct STRUCTURE *result, ++extern int parse_line (char *line, void *result, + struct parser_data *data, size_t datalen, int *errnop + EXTRA_ARGS_DECL); + +@@ -99,10 +99,11 @@ extern int parse_line (char *line, struct STRUCTURE *result, + + # define LINE_PARSER(EOLSET, BODY) \ + parser_stclass int \ +-parse_line (char *line, struct STRUCTURE *result, \ ++parse_line (char *line, void *generic_result, \ + struct parser_data *data, size_t datalen, int *errnop \ + EXTRA_ARGS_DECL) \ + { \ ++ struct STRUCTURE *result = generic_result; \ + ENTDATA_DECL (data) \ + BUFFER_PREPARE \ + char *p = strpbrk (line, EOLSET "\n"); \ +-- +1.8.3.1 + diff --git a/SOURCES/glibc-rh1871397-5.patch b/SOURCES/glibc-rh1871397-5.patch new file mode 100644 index 0000000..857cd83 --- /dev/null +++ b/SOURCES/glibc-rh1871397-5.patch @@ -0,0 +1,28 @@ +From d4b4586315974d2471486d41891aa9463a5838ad Mon Sep 17 00:00:00 2001 +From: Florian Weimer +Date: Thu, 16 Jul 2020 17:00:46 +0200 +Subject: [PATCH 05/11] libio: Add fseterr_unlocked for internal use + +Tested-by: Carlos O'Donell +Reviewed-by: Carlos O'Donell +--- + include/stdio.h | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff -rup a/include/stdio.h b/include/stdio.h +--- a/include/stdio.h 2020-09-14 17:39:06.191727167 -0400 ++++ b/include/stdio.h 2020-09-14 17:43:44.780222972 -0400 +@@ -9,6 +9,13 @@ + + /* Now define the internal interfaces. */ + ++/* Set the error indicator on FP. */ ++static inline void ++fseterr_unlocked (FILE *fp) ++{ ++ fp->_flags |= _IO_ERR_SEEN; ++} ++ + extern int __fcloseall (void) attribute_hidden; + extern int __snprintf (char *__restrict __s, size_t __maxlen, + const char *__restrict __format, ...) diff --git a/SOURCES/glibc-rh1871397-6.patch b/SOURCES/glibc-rh1871397-6.patch new file mode 100644 index 0000000..997f84a --- /dev/null +++ b/SOURCES/glibc-rh1871397-6.patch @@ -0,0 +1,406 @@ +commit bdee910e88006ae33dc83ac3d2c0708adb6627d0 +Author: Florian Weimer +Date: Wed Jul 15 13:41:31 2020 +0200 + + nss: Add __nss_fgetent_r + + And helper functions __nss_readline, __nss_readline_seek, + __nss_parse_line_result. + + This consolidates common code for handling overlong lines and + parse files. Use the new functionality in internal_getent + in nss/nss_files/files-XXX.c. + + Tested-by: Carlos O'Donell + Reviewed-by: Carlos O'Donell + +diff -rupN a/include/nss_files.h b/include/nss_files.h +--- a/include/nss_files.h 2020-09-14 17:48:49.353699306 -0400 ++++ b/include/nss_files.h 2020-09-14 17:55:21.856488740 -0400 +@@ -25,6 +25,28 @@ + FILE *__nss_files_fopen (const char *path); + libc_hidden_proto (__nss_files_fopen) + ++/* Read a line from FP, storing it BUF. Strip leading blanks and skip ++ comments. Sets errno and returns error code on failure. Special ++ failure: ERANGE means the buffer is too small. The function writes ++ the original offset to *POFFSET (which can be negative in the case ++ of non-seekable input). */ ++int __nss_readline (FILE *fp, char *buf, size_t len, off64_t *poffset); ++libc_hidden_proto (__nss_readline) ++ ++/* Seek FP to OFFSET. Sets errno and returns error code on failure. ++ On success, sets errno to ERANGE and returns ERANGE (to indicate ++ re-reading of the same input line to the caller). If OFFSET is ++ negative, fail with ESPIPE without seeking. Intended to be used ++ after parsing data read by __nss_readline failed with ERANGE. */ ++int __nss_readline_seek (FILE *fp, off64_t offset) attribute_hidden; ++ ++/* Handles the result of a parse_line call (as defined by ++ nss/nss_files/files-parse.c). Adjusts the file offset of FP as ++ necessary. Returns 0 on success, and updates errno on failure (and ++ returns that error code). */ ++int __nss_parse_line_result (FILE *fp, off64_t offset, int parse_line_result); ++libc_hidden_proto (__nss_parse_line_result) ++ + struct parser_data; + + /* Instances of the parse_line function from +@@ -52,4 +74,11 @@ libnss_files_hidden_proto (_nss_files_pa + libc_hidden_proto (_nss_files_parse_sgent) + libc_hidden_proto (_nss_files_parse_spent) + ++/* Generic implementation of fget*ent_r. Reads lines from FP until ++ EOF or a successful parse into *RESULT using PARSER. Returns 0 on ++ success, ENOENT on EOF, ERANGE on too-small buffer. */ ++int __nss_fgetent_r (FILE *fp, void *result, ++ char *buffer, size_t buffer_length, ++ nss_files_parse_line parser) attribute_hidden; ++ + #endif /* _NSS_FILES_H */ +diff -rupN a/nss/Makefile b/nss/Makefile +--- a/nss/Makefile 2020-09-14 17:48:49.293697045 -0400 ++++ b/nss/Makefile 2020-09-14 17:55:21.860488891 -0400 +@@ -28,7 +28,9 @@ headers := nss.h + routines = nsswitch getnssent getnssent_r digits_dots \ + valid_field valid_list_field rewrite_field \ + $(addsuffix -lookup,$(databases)) \ +- compat-lookup nss_hash nss_files_fopen ++ compat-lookup nss_hash nss_files_fopen \ ++ nss_readline nss_parse_line_result \ ++ nss_fgetent_r + + # These are the databases that go through nss dispatch. + # Caution: if you add a database here, you must add its real name +diff -rupN a/nss/Versions b/nss/Versions +--- a/nss/Versions 2020-09-14 17:48:49.294697083 -0400 ++++ b/nss/Versions 2020-09-14 17:55:21.867489155 -0400 +@@ -21,7 +21,7 @@ libc { + __nss_passwd_lookup2; __nss_group_lookup2; __nss_hosts_lookup2; + __nss_services_lookup2; __nss_next2; __nss_lookup; + __nss_hash; __nss_database_lookup2; +- __nss_files_fopen; ++ __nss_files_fopen; __nss_readline; __nss_parse_line_result; + } + } + +diff -rupN a/nss/nss_fgetent_r.c b/nss/nss_fgetent_r.c +--- a/nss/nss_fgetent_r.c 1969-12-31 19:00:00.000000000 -0500 ++++ b/nss/nss_fgetent_r.c 2020-09-14 17:55:21.870489268 -0400 +@@ -0,0 +1,55 @@ ++/* Generic implementation of fget*ent_r. ++ 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 ++ ++int ++__nss_fgetent_r (FILE *fp, void *result, char *buffer, size_t buffer_length, ++ nss_files_parse_line parser) ++{ ++ int ret; ++ ++ _IO_flockfile (fp); ++ ++ while (true) ++ { ++ off64_t original_offset; ++ ret = __nss_readline (fp, buffer, buffer_length, &original_offset); ++ if (ret == 0) ++ { ++ /* Parse the line into *RESULT. */ ++ ret = parser (buffer, result, ++ (struct parser_data *) buffer, buffer_length, &errno); ++ ++ /* Translate the result code from the parser into an errno ++ value. Also seeks back to the start of the line if ++ necessary. */ ++ ret = __nss_parse_line_result (fp, original_offset, ret); ++ ++ if (ret == EINVAL) ++ /* Skip over malformed lines. */ ++ continue; ++ } ++ break; ++ } ++ ++ _IO_funlockfile (fp); ++ ++ return ret; ++} +diff -rupN a/nss/nss_files/files-XXX.c b/nss/nss_files/files-XXX.c +--- a/nss/nss_files/files-XXX.c 2020-09-14 17:48:49.296697158 -0400 ++++ b/nss/nss_files/files-XXX.c 2020-09-14 17:55:21.878489569 -0400 +@@ -135,10 +135,9 @@ internal_getent (FILE *stream, struct ST + char *buffer, size_t buflen, int *errnop H_ERRNO_PROTO + EXTRA_ARGS_DECL) + { +- char *p; + struct parser_data *data = (void *) buffer; + size_t linebuflen = buffer + buflen - data->linebuffer; +- int parse_result; ++ int saved_errno = errno; /* Do not clobber errno on success. */ + + if (buflen < sizeof *data + 2) + { +@@ -149,66 +148,42 @@ internal_getent (FILE *stream, struct ST + + while (true) + { +- ssize_t r = __libc_readline_unlocked +- (stream, data->linebuffer, linebuflen); +- if (r < 0) +- { +- *errnop = errno; +- H_ERRNO_SET (NETDB_INTERNAL); +- if (*errnop == ERANGE) +- /* Request larger buffer. */ +- return NSS_STATUS_TRYAGAIN; +- else +- /* Other read failure. */ +- return NSS_STATUS_UNAVAIL; +- } +- else if (r == 0) ++ off64_t original_offset; ++ int ret = __nss_readline (stream, data->linebuffer, linebuflen, ++ &original_offset); ++ if (ret == ENOENT) + { + /* End of file. */ + H_ERRNO_SET (HOST_NOT_FOUND); ++ __set_errno (saved_errno); + return NSS_STATUS_NOTFOUND; + } +- +- /* Everything OK. Now skip leading blanks. */ +- p = data->linebuffer; +- while (isspace (*p)) +- ++p; +- +- /* Ignore empty and comment lines. */ +- if (*p == '\0' || *p == '#') +- continue; +- +- /* Parse the line. */ +- *errnop = EINVAL; +- parse_result = parse_line (p, result, data, buflen, errnop EXTRA_ARGS); +- +- if (parse_result == -1) ++ else if (ret == 0) + { +- if (*errnop == ERANGE) ++ ret = __nss_parse_line_result (stream, original_offset, ++ parse_line (data->linebuffer, ++ result, data, buflen, ++ errnop EXTRA_ARGS)); ++ if (ret == 0) + { +- /* Return to the original file position at the beginning +- of the line, so that the next call can read it again +- if necessary. */ +- if (__fseeko64 (stream, -r, SEEK_CUR) != 0) +- { +- if (errno == ERANGE) +- *errnop = EINVAL; +- else +- *errnop = errno; +- H_ERRNO_SET (NETDB_INTERNAL); +- return NSS_STATUS_UNAVAIL; +- } ++ /* Line has been parsed successfully. */ ++ __set_errno (saved_errno); ++ return NSS_STATUS_SUCCESS; + } +- H_ERRNO_SET (NETDB_INTERNAL); +- return NSS_STATUS_TRYAGAIN; ++ else if (ret == EINVAL) ++ /* If it is invalid, loop to get the next line of the file ++ to parse. */ ++ continue; + } + +- /* Return the data if parsed successfully. */ +- if (parse_result != 0) +- return NSS_STATUS_SUCCESS; +- +- /* If it is invalid, loop to get the next line of the file to +- parse. */ ++ *errnop = ret; ++ H_ERRNO_SET (NETDB_INTERNAL); ++ if (ret == ERANGE) ++ /* Request larger buffer. */ ++ return NSS_STATUS_TRYAGAIN; ++ else ++ /* Other read failure. */ ++ return NSS_STATUS_UNAVAIL; + } + } + +diff -rupN a/nss/nss_parse_line_result.c b/nss/nss_parse_line_result.c +--- a/nss/nss_parse_line_result.c 1969-12-31 19:00:00.000000000 -0500 ++++ b/nss/nss_parse_line_result.c 2020-09-14 17:55:21.880489645 -0400 +@@ -0,0 +1,46 @@ ++/* Implementation of __nss_parse_line_result. ++ 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 ++ ++int ++__nss_parse_line_result (FILE *fp, off64_t offset, int parse_line_result) ++{ ++ assert (parse_line_result >= -1 && parse_line_result <= 1); ++ ++ switch (__builtin_expect (parse_line_result, 1)) ++ { ++ case 1: ++ /* Sucess. */ ++ return 0; ++ case 0: ++ /* Parse error. */ ++ __set_errno (EINVAL); ++ return EINVAL; ++ case -1: ++ /* Out of buffer space. */ ++ return __nss_readline_seek (fp, offset); ++ ++ default: ++ __builtin_unreachable (); ++ } ++} ++libc_hidden_def (__nss_parse_line_result) +diff -rupN a/nss/nss_readline.c b/nss/nss_readline.c +--- a/nss/nss_readline.c 1969-12-31 19:00:00.000000000 -0500 ++++ b/nss/nss_readline.c 2020-09-14 17:55:21.883489758 -0400 +@@ -0,0 +1,99 @@ ++/* Read a line from an nss_files database file. ++ 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 ++ ++int ++__nss_readline (FILE *fp, char *buf, size_t len, off64_t *poffset) ++{ ++ /* We need space for at least one character, the line terminator, ++ and the NUL byte. */ ++ if (len < 3) ++ { ++ *poffset = -1; ++ __set_errno (ERANGE); ++ return ERANGE; ++ } ++ ++ while (true) ++ { ++ /* Keep original offset for retries. */ ++ *poffset = __ftello64 (fp); ++ ++ buf[len - 1] = '\xff'; /* Marker to recognize truncation. */ ++ if (fgets_unlocked (buf, len, fp) == NULL) ++ { ++ if (feof_unlocked (fp)) ++ { ++ __set_errno (ENOENT); ++ return ENOENT; ++ } ++ else ++ { ++ /* Any other error. Do not return ERANGE in this case ++ because the caller would retry. */ ++ if (errno == ERANGE) ++ __set_errno (EINVAL); ++ return errno; ++ } ++ } ++ else if (buf[len - 1] != '\xff') ++ /* The buffer is too small. Arrange for re-reading the same ++ line on the next call. */ ++ return __nss_readline_seek (fp, *poffset); ++ ++ /* fgets_unlocked succeeded. */ ++ ++ /* Remove leading whitespace. */ ++ char *p = buf; ++ while (isspace (*p)) ++ ++p; ++ if (*p == '\0' || *p == '#') ++ /* Skip empty lines and comments. */ ++ continue; ++ if (p != buf) ++ memmove (buf, p, strlen (p)); ++ ++ /* Return line to the caller. */ ++ return 0; ++ } ++} ++libc_hidden_def (__nss_readline) ++ ++int ++__nss_readline_seek (FILE *fp, off64_t offset) ++{ ++ if (offset < 0 /* __ftello64 failed. */ ++ || __fseeko64 (fp, offset, SEEK_SET) < 0) ++ { ++ /* Without seeking support, it is not possible to ++ re-read the same line, so this is a hard failure. */ ++ fseterr_unlocked (fp); ++ __set_errno (ESPIPE); ++ return ESPIPE; ++ } ++ else ++ { ++ __set_errno (ERANGE); ++ return ERANGE; ++ } ++} diff --git a/SOURCES/glibc-rh1871397-7.patch b/SOURCES/glibc-rh1871397-7.patch new file mode 100644 index 0000000..3465d9d --- /dev/null +++ b/SOURCES/glibc-rh1871397-7.patch @@ -0,0 +1,85 @@ +From 4f62a21d0ed19ff29bba704167179b862140d011 Mon Sep 17 00:00:00 2001 +From: Florian Weimer +Date: Thu, 16 Jul 2020 17:28:28 +0200 +Subject: [PATCH 07/11] grp: Implement fgetgrent_r using __nss_fgetent_r + +Tested-by: Carlos O'Donell +Reviewed-by: Carlos O'Donell +--- + grp/fgetgrent_r.c | 54 ++++++------------------------------------------------ + 1 file changed, 6 insertions(+), 48 deletions(-) + +diff --git a/grp/fgetgrent_r.c b/grp/fgetgrent_r.c +index 03daf4f..b598584 100644 +--- a/grp/fgetgrent_r.c ++++ b/grp/fgetgrent_r.c +@@ -20,10 +20,6 @@ + #include + #include + +-#include +-#define flockfile(s) _IO_flockfile (s) +-#define funlockfile(s) _IO_funlockfile (s) +- + /* Define a line parsing function using the common code + used in the nss_files module. */ + +@@ -59,49 +55,11 @@ int + __fgetgrent_r (FILE *stream, struct group *resbuf, char *buffer, size_t buflen, + struct group **result) + { +- char *p; +- int parse_result; +- +- flockfile (stream); +- do +- { +- buffer[buflen - 1] = '\xff'; +- p = fgets_unlocked (buffer, buflen, stream); +- if (__builtin_expect (p == NULL, 0) && feof_unlocked (stream)) +- { +- funlockfile (stream); +- *result = NULL; +- __set_errno (ENOENT); +- return errno; +- } +- if (__builtin_expect (p == NULL, 0) || buffer[buflen - 1] != '\xff') +- { +- funlockfile (stream); +- *result = NULL; +- __set_errno (ERANGE); +- return errno; +- } +- +- /* Skip leading blanks. */ +- while (isspace (*p)) +- ++p; +- } while (*p == '\0' || *p == '#' /* Ignore empty and comment lines. */ +- /* Parse the line. If it is invalid, loop to +- get the next line of the file to parse. */ +- || ! (parse_result = parse_line (p, resbuf, +- (void *) buffer, buflen, +- &errno))); +- +- funlockfile (stream); +- +- if (__builtin_expect (parse_result, 0) == -1) +- { +- /* The parser ran out of space. */ +- *result = NULL; +- return errno; +- } +- +- *result = resbuf; +- return 0; ++ int ret = __nss_fgetent_r (stream, resbuf, buffer, buflen, parse_line); ++ if (ret == 0) ++ *result = resbuf; ++ else ++ *result = NULL; ++ return ret; + } + weak_alias (__fgetgrent_r, fgetgrent_r) +-- +1.8.3.1 + diff --git a/SOURCES/glibc-rh1871397-8.patch b/SOURCES/glibc-rh1871397-8.patch new file mode 100644 index 0000000..58bd476 --- /dev/null +++ b/SOURCES/glibc-rh1871397-8.patch @@ -0,0 +1,272 @@ +From 2add4235ef674988948155f9a8f60a8c7b09bcff Mon Sep 17 00:00:00 2001 +From: Florian Weimer +Date: Thu, 16 Jul 2020 17:31:20 +0200 +Subject: [PATCH 08/11] gshadow: Implement fgetsgent_r using __nss_fgetent_r + (bug 20338) + +Tested-by: Carlos O'Donell +Reviewed-by: Carlos O'Donell +--- + gshadow/Makefile | 2 +- + gshadow/fgetsgent_r.c | 41 ++-------- + gshadow/tst-fgetsgent_r.c | 191 ++++++++++++++++++++++++++++++++++++++++++++++ + 3 files changed, 198 insertions(+), 36 deletions(-) + create mode 100644 gshadow/tst-fgetsgent_r.c + +diff -rupN a/gshadow/Makefile b/gshadow/Makefile +--- a/gshadow/Makefile 2018-08-01 01:10:47.000000000 -0400 ++++ b/gshadow/Makefile 2020-09-14 18:00:57.167145887 -0400 +@@ -26,7 +26,7 @@ headers = gshadow.h + routines = getsgent getsgnam sgetsgent fgetsgent putsgent \ + getsgent_r getsgnam_r sgetsgent_r fgetsgent_r + +-tests = tst-gshadow tst-putsgent ++tests = tst-gshadow tst-putsgent tst-fgetsgent_r + + CFLAGS-getsgent_r.c += -fexceptions + CFLAGS-getsgent.c += -fexceptions +diff -rupN a/gshadow/fgetsgent_r.c b/gshadow/fgetsgent_r.c +--- a/gshadow/fgetsgent_r.c 2018-08-01 01:10:47.000000000 -0400 ++++ b/gshadow/fgetsgent_r.c 2020-09-14 18:45:59.189353065 -0400 +@@ -36,40 +36,11 @@ int + __fgetsgent_r (FILE *stream, struct sgrp *resbuf, char *buffer, size_t buflen, + struct sgrp **result) + { +- char *p; +- +- _IO_flockfile (stream); +- do +- { +- buffer[buflen - 1] = '\xff'; +- p = fgets_unlocked (buffer, buflen, stream); +- if (p == NULL && feof_unlocked (stream)) +- { +- _IO_funlockfile (stream); +- *result = NULL; +- __set_errno (ENOENT); +- return errno; +- } +- if (p == NULL || buffer[buflen - 1] != '\xff') +- { +- _IO_funlockfile (stream); +- *result = NULL; +- __set_errno (ERANGE); +- return errno; +- } +- +- /* Skip leading blanks. */ +- while (isspace (*p)) +- ++p; +- } while (*p == '\0' || *p == '#' || /* Ignore empty and comment lines. */ +- /* Parse the line. If it is invalid, loop to +- get the next line of the file to parse. */ +- ! parse_line (buffer, (void *) resbuf, (void *) buffer, buflen, +- &errno)); +- +- _IO_funlockfile (stream); +- +- *result = resbuf; +- return 0; ++ int ret = __nss_fgetent_r (stream, resbuf, buffer, buflen, parse_line); ++ if (ret == 0) ++ *result = resbuf; ++ else ++ *result = NULL; ++ return ret; + } + weak_alias (__fgetsgent_r, fgetsgent_r) +diff -rupN a/gshadow/tst-fgetsgent_r.c b/gshadow/tst-fgetsgent_r.c +--- a/gshadow/tst-fgetsgent_r.c 1969-12-31 19:00:00.000000000 -0500 ++++ b/gshadow/tst-fgetsgent_r.c 2020-09-14 18:00:57.174146151 -0400 +@@ -0,0 +1,191 @@ ++/* Test for fgetsgent_r and buffer sizes. ++ 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 ++#include ++ ++/* Turn a parsed struct back into a line string. The returned string ++ should be freed. */ ++static char * ++format_ent (const struct sgrp *e) ++{ ++ struct xmemstream stream; ++ xopen_memstream (&stream); ++ TEST_COMPARE (putsgent (e, stream.out), 0); ++ xfclose_memstream (&stream); ++ return stream.buffer; ++} ++ ++/* An entry in the input file along with the expected output. */ ++struct input ++{ ++ const char *line; /* Line in the file. */ ++ const char *expected; /* Expected output. NULL if skipped. */ ++}; ++ ++const struct input inputs[] = ++ { ++ /* Regular entries. */ ++ { "g1:x1::\n", "g1:x1::\n" }, ++ { "g2:x2:a1:\n", "g2:x2:a1:\n" }, ++ { "g3:x3:a2:u1\n", "g3:x3:a2:u1\n" }, ++ { "g4:x4:a3,a4:u2,u3,u4\n", "g4:x4:a3,a4:u2,u3,u4\n" }, ++ ++ /* Comments and empty lines. */ ++ { "\n", NULL }, ++ { " \n", NULL }, ++ { "\t\n", NULL }, ++ { "#g:x::\n", NULL }, ++ { " #g:x::\n", NULL }, ++ { "\t#g:x::\n", NULL }, ++ { " \t#g:x::\n", NULL }, ++ ++ /* Marker for synchronization. */ ++ { "g5:x5::\n", "g5:x5::\n" }, ++ ++ /* Leading whitespace. */ ++ { " g6:x6::\n", "g6:x6::\n" }, ++ { "\tg7:x7::\n", "g7:x7::\n" }, ++ ++ /* This is expected to trigger buffer exhaustion during parsing ++ (bug 20338). */ ++ { ++ "g8:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx:u5,u6,u7,u8,u9:\n", ++ "g8:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx:u5,u6,u7,u8,u9:\n", ++ }, ++ { ++ "g9:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx::a5,a6,a7,a8,a9,a10\n", ++ "g9:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx::a5,a6,a7,a8,a9,a10\n", ++ }, ++ }; ++ ++/* Writes the test data to a temporary file and returns its name. The ++ returned pointer should be freed. */ ++static char * ++create_test_file (void) ++{ ++ char *path; ++ int fd = create_temp_file ("tst-fgetsgent_r-", &path); ++ FILE *fp = fdopen (fd, "w"); ++ TEST_VERIFY_EXIT (fp != NULL); ++ ++ for (size_t i = 0; i < array_length (inputs); ++i) ++ fputs (inputs[i].line, fp); ++ ++ xfclose (fp); ++ return path; ++} ++ ++/* Read the test file with the indicated start buffer size. Return ++ true if the buffer size had to be increased during reading. */ ++static bool ++run_test (const char *path, size_t buffer_size) ++{ ++ bool resized = false; ++ FILE *fp = xfopen (path, "r"); ++ ++ /* This avoids repeated lseek system calls (bug 26257). */ ++ TEST_COMPARE (fseeko64 (fp, 0, SEEK_SET), 0); ++ ++ size_t i = 0; ++ while (true) ++ { ++ /* Skip over unused expected entries. */ ++ while (i < array_length (inputs) && inputs[i].expected == NULL) ++ ++i; ++ ++ /* Store the data on the heap, to help valgrind to detect ++ invalid accesses. */ ++ struct sgrp *result_storage = xmalloc (sizeof (*result_storage)); ++ char *buffer = xmalloc (buffer_size); ++ struct sgrp **result_pointer_storage ++ = xmalloc (sizeof (*result_pointer_storage)); ++ ++ int ret = fgetsgent_r (fp, result_storage, buffer, buffer_size, ++ result_pointer_storage); ++ if (ret == 0) ++ { ++ TEST_VERIFY (*result_pointer_storage != NULL); ++ TEST_VERIFY (i < array_length (inputs)); ++ if (*result_pointer_storage != NULL ++ && i < array_length (inputs)) ++ { ++ char * actual = format_ent (*result_pointer_storage); ++ TEST_COMPARE_STRING (inputs[i].expected, actual); ++ free (actual); ++ ++i; ++ } ++ else ++ break; ++ } ++ else ++ { ++ TEST_VERIFY (*result_pointer_storage == NULL); ++ TEST_COMPARE (ret, errno); ++ ++ if (ret == ENOENT) ++ { ++ TEST_COMPARE (i, array_length (inputs)); ++ free (result_pointer_storage); ++ free (buffer); ++ free (result_storage); ++ break; ++ } ++ else if (ret == ERANGE) ++ { ++ resized = true; ++ ++buffer_size; ++ } ++ else ++ FAIL_EXIT1 ("read failure: %m"); ++ } ++ ++ free (result_pointer_storage); ++ free (buffer); ++ free (result_storage); ++ } ++ ++ return resized; ++} ++ ++static int ++do_test (void) ++{ ++ char *path = create_test_file (); ++ ++ for (size_t buffer_size = 3; ; ++buffer_size) ++ { ++ bool resized = run_test (path, buffer_size); ++ if (!resized) ++ break; ++ } ++ ++ free (path); ++ ++ return 0; ++} ++ ++#include diff --git a/SOURCES/glibc-rh1871397-9.patch b/SOURCES/glibc-rh1871397-9.patch new file mode 100644 index 0000000..4e0396e --- /dev/null +++ b/SOURCES/glibc-rh1871397-9.patch @@ -0,0 +1,70 @@ +From ee1c062be09da006e82ab34c1c9b5c82dd2af92c Mon Sep 17 00:00:00 2001 +From: Florian Weimer +Date: Thu, 16 Jul 2020 17:34:19 +0200 +Subject: [PATCH 09/11] pwd: Implement fgetpwent_r using __nss_fgetent_r + +Tested-by: Carlos O'Donell +Reviewed-by: Carlos O'Donell +--- + pwd/fgetpwent_r.c | 43 ++++++------------------------------------- + 1 file changed, 6 insertions(+), 37 deletions(-) + +diff -rup a/pwd/fgetpwent_r.c b/pwd/fgetpwent_r.c +--- a/pwd/fgetpwent_r.c 2018-08-01 01:10:47.000000000 -0400 ++++ b/pwd/fgetpwent_r.c 2020-09-14 19:03:41.277514743 -0400 +@@ -20,9 +20,6 @@ + #include + #include + +-#define flockfile(s) _IO_flockfile (s) +-#define funlockfile(s) _IO_funlockfile (s) +- + /* Define a line parsing function using the common code + used in the nss_files module. */ + +@@ -72,39 +69,11 @@ int + __fgetpwent_r (FILE *stream, struct passwd *resbuf, char *buffer, + size_t buflen, struct passwd **result) + { +- char *p; +- +- flockfile (stream); +- do +- { +- buffer[buflen - 1] = '\xff'; +- p = fgets_unlocked (buffer, buflen, stream); +- if (p == NULL && feof_unlocked (stream)) +- { +- funlockfile (stream); +- *result = NULL; +- __set_errno (ENOENT); +- return errno; +- } +- if (p == NULL || buffer[buflen - 1] != '\xff') +- { +- funlockfile (stream); +- *result = NULL; +- __set_errno (ERANGE); +- return errno; +- } +- +- /* Skip leading blanks. */ +- while (isspace (*p)) +- ++p; +- } while (*p == '\0' || *p == '#' || /* Ignore empty and comment lines. */ +- /* Parse the line. If it is invalid, loop to +- get the next line of the file to parse. */ +- ! parse_line (p, resbuf, (void *) buffer, buflen, &errno)); +- +- funlockfile (stream); +- +- *result = resbuf; +- return 0; ++ int ret = __nss_fgetent_r (stream, resbuf, buffer, buflen, parse_line); ++ if (ret == 0) ++ *result = resbuf; ++ else ++ *result = NULL; ++ return ret; + } + weak_alias (__fgetpwent_r, fgetpwent_r) diff --git a/SOURCES/glibc-rh1880670-2.patch b/SOURCES/glibc-rh1880670-2.patch new file mode 100644 index 0000000..c976be6 --- /dev/null +++ b/SOURCES/glibc-rh1880670-2.patch @@ -0,0 +1,64 @@ +commit 8813b2682e4094e43b0cf1634e99619f1b8b2c62 +Author: Sajan Karumanchi +Date: Wed Oct 28 13:05:33 2020 +0530 + + x86: Optimizing memcpy for AMD Zen architecture. + + Modifying the shareable cache '__x86_shared_cache_size', which is a + factor in computing the non-temporal threshold parameter + '__x86_shared_non_temporal_threshold' to optimize memcpy for AMD Zen + architectures. + In the existing implementation, the shareable cache is computed as 'L3 + per thread, L2 per core'. Recomputing this shareable cache as 'L3 per + CCX(Core-Complex)' has brought in performance gains. + As per the large bench variant results, this patch also addresses the + regression problem on AMD Zen architectures. + + Backport of commit 59803e81f96b479c17f583b31eac44b57591a1bf upstream, + with the fix from cb3a749a22a55645dc6a52659eea765300623f98 ("x86: + Restore processing of cache size tunables in init_cacheinfo") applied. + + Reviewed-by: Premachandra Mallappa + Co-Authored-by: Florian Weimer + +Backport is off the release/2.32/master branch upstream, to minimize +conflicts. Adjusted for missing "basic" member in struct cpu_features. + +diff --git a/sysdeps/x86/cacheinfo.c b/sysdeps/x86/cacheinfo.c +index 42b468d0c4885bad..57c36d030a76c8b2 100644 +--- a/sysdeps/x86/cacheinfo.c ++++ b/sysdeps/x86/cacheinfo.c +@@ -722,7 +722,7 @@ intel_bug_no_cache_info: + threads = 1 << ((ecx >> 12) & 0x0f); + } + +- if (threads == 0) ++ if (threads == 0 || cpu_features->family >= 0x17) + { + /* If APIC ID width is not available, use logical + processor count. */ +@@ -737,8 +737,22 @@ intel_bug_no_cache_info: + if (threads > 0) + shared /= threads; + +- /* Account for exclusive L2 and L3 caches. */ +- shared += core; ++ /* Get shared cache per ccx for Zen architectures. */ ++ if (cpu_features->family >= 0x17) ++ { ++ unsigned int eax; ++ ++ /* Get number of threads share the L3 cache in CCX. */ ++ __cpuid_count (0x8000001D, 0x3, eax, ebx, ecx, edx); ++ ++ unsigned int threads_per_ccx = ((eax >> 14) & 0xfff) + 1; ++ shared *= threads_per_ccx; ++ } ++ else ++ { ++ /* Account for exclusive L2 and L3 caches. */ ++ shared += core; ++ } + } + + #ifndef DISABLE_PREFETCHW diff --git a/SOURCES/glibc-rh1880670.patch b/SOURCES/glibc-rh1880670.patch new file mode 100644 index 0000000..d76a028 --- /dev/null +++ b/SOURCES/glibc-rh1880670.patch @@ -0,0 +1,97 @@ +commit d3c57027470b78dba79c6d931e4e409b1fecfc80 +Author: Patrick McGehearty +Date: Mon Sep 28 20:11:28 2020 +0000 + + Reversing calculation of __x86_shared_non_temporal_threshold + + The __x86_shared_non_temporal_threshold determines when memcpy on x86 + uses non_temporal stores to avoid pushing other data out of the last + level cache. + + This patch proposes to revert the calculation change made by H.J. Lu's + patch of June 2, 2017. + + H.J. Lu's patch selected a threshold suitable for a single thread + getting maximum performance. It was tuned using the single threaded + large memcpy micro benchmark on an 8 core processor. The last change + changes the threshold from using 3/4 of one thread's share of the + cache to using 3/4 of the entire cache of a multi-threaded system + before switching to non-temporal stores. Multi-threaded systems with + more than a few threads are server-class and typically have many + active threads. If one thread consumes 3/4 of the available cache for + all threads, it will cause other active threads to have data removed + from the cache. Two examples show the range of the effect. John + McCalpin's widely parallel Stream benchmark, which runs in parallel + and fetches data sequentially, saw a 20% slowdown with this patch on + an internal system test of 128 threads. This regression was discovered + when comparing OL8 performance to OL7. An example that compares + normal stores to non-temporal stores may be found at + https://vgatherps.github.io/2018-09-02-nontemporal/. A simple test + shows performance loss of 400 to 500% due to a failure to use + nontemporal stores. These performance losses are most likely to occur + when the system load is heaviest and good performance is critical. + + The tunable x86_non_temporal_threshold can be used to override the + default for the knowledgable user who really wants maximum cache + allocation to a single thread in a multi-threaded system. + The manual entry for the tunable has been expanded to provide + more information about its purpose. + + modified: sysdeps/x86/cacheinfo.c + modified: manual/tunables.texi + +Conflicts: + manual/tunables.texi + (Downstream uses the glibc.tune namespace, upstream uses + glibc.cpu.) + sysdeps/x86/cacheinfo.c + (Downstream does not have rep_movsb_threshold, + x86_rep_stosb_threshold tunables.) + +diff --git a/manual/tunables.texi b/manual/tunables.texi +index 3dc6f9a44592c030..3e1e519dff153b09 100644 +--- a/manual/tunables.texi ++++ b/manual/tunables.texi +@@ -364,7 +364,11 @@ set shared cache size in bytes for use in memory and string routines. + + @deftp Tunable glibc.tune.x86_non_temporal_threshold + The @code{glibc.tune.x86_non_temporal_threshold} tunable allows the user +-to set threshold in bytes for non temporal store. ++to set threshold in bytes for non temporal store. Non temporal stores ++give a hint to the hardware to move data directly to memory without ++displacing other data from the cache. This tunable is used by some ++platforms to determine when to use non temporal stores in operations ++like memmove and memcpy. + + This tunable is specific to i386 and x86-64. + @end deftp +diff --git a/sysdeps/x86/cacheinfo.c b/sysdeps/x86/cacheinfo.c +index b9444ddd52051e05..42b468d0c4885bad 100644 +--- a/sysdeps/x86/cacheinfo.c ++++ b/sysdeps/x86/cacheinfo.c +@@ -778,14 +778,20 @@ intel_bug_no_cache_info: + __x86_shared_cache_size = shared; + } + +- /* The large memcpy micro benchmark in glibc shows that 6 times of +- shared cache size is the approximate value above which non-temporal +- store becomes faster on a 8-core processor. This is the 3/4 of the +- total shared cache size. */ ++ /* The default setting for the non_temporal threshold is 3/4 of one ++ thread's share of the chip's cache. For most Intel and AMD processors ++ with an initial release date between 2017 and 2020, a thread's typical ++ share of the cache is from 500 KBytes to 2 MBytes. Using the 3/4 ++ threshold leaves 125 KBytes to 500 KBytes of the thread's data ++ in cache after a maximum temporal copy, which will maintain ++ in cache a reasonable portion of the thread's stack and other ++ active data. If the threshold is set higher than one thread's ++ share of the cache, it has a substantial risk of negatively ++ impacting the performance of other threads running on the chip. */ + __x86_shared_non_temporal_threshold + = (cpu_features->non_temporal_threshold != 0 + ? cpu_features->non_temporal_threshold +- : __x86_shared_cache_size * threads * 3 / 4); ++ : __x86_shared_cache_size * 3 / 4); + } + + #endif diff --git a/SOURCES/glibc-rh1882466-1.patch b/SOURCES/glibc-rh1882466-1.patch new file mode 100644 index 0000000..7a22ce0 --- /dev/null +++ b/SOURCES/glibc-rh1882466-1.patch @@ -0,0 +1,51 @@ +commit cb81264fd9973cd95bbc71495185b98979d28918 +Author: Florian Weimer +Date: Fri Dec 11 17:24:08 2020 +0100 + + support: Add support_slibdir_prefix variable + + Reviewed-by: Carlos O'Donell + +diff --git a/support/Makefile b/support/Makefile +index 35b21b19a248ba7f..dcf3c4baa2a31070 100644 +--- a/support/Makefile ++++ b/support/Makefile +@@ -184,6 +184,7 @@ CFLAGS-support_paths.c = \ + -DLIBDIR_PATH=\"$(libdir)\" \ + -DBINDIR_PATH=\"$(bindir)\" \ + -DSBINDIR_PATH=\"$(sbindir)\" \ ++ -DSLIBDIR_PATH=\"$(slibdir)\" \ + -DROOTSBINDIR_PATH=\"$(rootsbindir)\" \ + -DCOMPLOCALEDIR_PATH=\"$(complocaledir)\" + +diff --git a/support/support.h b/support/support.h +index 6f7f804847f67600..f50f8cc1496d657d 100644 +--- a/support/support.h ++++ b/support/support.h +@@ -110,6 +110,8 @@ extern const char support_libdir_prefix[]; + extern const char support_bindir_prefix[]; + /* Corresponds to the install's sbin/ directory. */ + extern const char support_sbindir_prefix[]; ++/* Corresponds to the install's system /lib or /lib64 directory. */ ++extern const char support_slibdir_prefix[]; + /* Corresponds to the install's sbin/ directory (without prefix). */ + extern const char support_install_rootsbindir[]; + /* Corresponds to the install's compiled locale directory. */ +diff --git a/support/support_paths.c b/support/support_paths.c +index 6b15fae0f0173b1e..be61c8acee3ec1a5 100644 +--- a/support/support_paths.c ++++ b/support/support_paths.c +@@ -72,6 +72,13 @@ const char support_sbindir_prefix[] = SBINDIR_PATH; + # error please -DSBINDIR_PATH=something in the Makefile + #endif + ++#ifdef SLIBDIR_PATH ++/* Corresponds to the system /lib or /lib64 directory. */ ++const char support_slibdir_prefix[] = SLIBDIR_PATH; ++#else ++# error please -DSLIBDIR_PATH=something in the Makefile ++#endif ++ + #ifdef ROOTSBINDIR_PATH + /* Corresponds to the install's sbin/ directory. */ + const char support_install_rootsbindir[] = ROOTSBINDIR_PATH; diff --git a/SOURCES/glibc-rh1882466-2.patch b/SOURCES/glibc-rh1882466-2.patch new file mode 100644 index 0000000..1ee6651 --- /dev/null +++ b/SOURCES/glibc-rh1882466-2.patch @@ -0,0 +1,98 @@ +commit 9ffa50b26b0cb5d3043adf6d3d0b1ea735acc147 +Author: Florian Weimer +Date: Fri Dec 11 17:30:03 2020 +0100 + + elf: Include libc.so.6 as main program in dependency sort (bug 20972) + + _dl_map_object_deps always sorts the initially loaded object first + during dependency sorting. This means it is relocated last in + dl_open_worker. This results in crashes in IFUNC resolvers without + lazy bindings if libraries are preloaded that refer to IFUNCs in + libc.so.6: the resolvers are called when libc.so.6 has not been + relocated yet, so references to _rtld_global_ro etc. crash. + + The fix is to check against the libc.so.6 link map recorded by the + __libc_early_init framework, and let it participate in the dependency + sort. + + This fixes bug 20972. + + Reviewed-by: Carlos O'Donell + +Conflicts: + elf/Makefile + (Usual test backport differences.) + +diff --git a/elf/Makefile b/elf/Makefile +index 67029930dd2cb461..fc9c685b9d23bb6c 100644 +--- a/elf/Makefile ++++ b/elf/Makefile +@@ -215,7 +215,7 @@ tests-internal += loadtest unload unload2 circleload1 \ + 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 +-tests-container += tst-pldd ++tests-container += tst-pldd tst-preload-pthread-libc + ifeq ($(build-hardcoded-path-in-tests),yes) + tests += tst-dlopen-aout + tst-dlopen-aout-no-pie = yes +diff --git a/elf/dl-deps.c b/elf/dl-deps.c +index 50f053a1586efdc3..007069f670eced95 100644 +--- a/elf/dl-deps.c ++++ b/elf/dl-deps.c +@@ -610,7 +610,12 @@ Filters not supported with LD_TRACE_PRELINKING")); + memcpy (l_initfini, map->l_searchlist.r_list, + nlist * sizeof (struct link_map *)); + +- _dl_sort_maps (&l_initfini[1], nlist - 1, NULL, false); ++ /* 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); + + /* Terminate the list of dependencies. */ + l_initfini[nlist] = NULL; +diff --git a/elf/tst-preload-pthread-libc.c b/elf/tst-preload-pthread-libc.c +new file mode 100644 +index 0000000000000000..48cb512a93f3da19 +--- /dev/null ++++ b/elf/tst-preload-pthread-libc.c +@@ -0,0 +1,36 @@ ++/* Test relocation ordering if the main executable is libc.so.6 (bug 20972). ++ 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 ++ ++int ++main (void) ++{ ++ char *libc = xasprintf ("%s/%s", support_slibdir_prefix, LIBC_SO); ++ char *argv[] = { libc, NULL }; ++ char *envp[] = { (char *) "LD_PRELOAD=" LIBPTHREAD_SO, ++ /* Relocation ordering matters most without lazy binding. */ ++ (char *) "LD_BIND_NOW=1", ++ NULL }; ++ execve (libc, argv, envp); ++ printf ("execve of %s failed: %m\n", libc); ++ return 1; ++} diff --git a/SOURCES/glibc-rh1882466-3.patch b/SOURCES/glibc-rh1882466-3.patch new file mode 100644 index 0000000..d254df7 --- /dev/null +++ b/SOURCES/glibc-rh1882466-3.patch @@ -0,0 +1,45 @@ +commit 4d0985543f479a6f421d4d8a9e0d1dc71c9c2c53 +Author: Florian Weimer +Date: Tue Dec 15 20:56:04 2020 +0100 + + elf: Record libc.so link map when it is the main program (bug 20972) + + Otherwise, it will not participate in the dependency sorting. + + Fixes commit 9ffa50b26b0cb5d3043adf6d3d0b1ea735acc147 + ("elf: Include libc.so.6 as main program in dependency sort + (bug 20972)"). + +Conflicts: + elf/rtld.c + (Missing backported header include.) + +diff --git a/elf/rtld.c b/elf/rtld.c +index fde5a6a4a485207e..992f825ba00762a7 100644 +--- a/elf/rtld.c ++++ b/elf/rtld.c +@@ -46,6 +46,7 @@ + #include + #include + #include ++#include + + #include + +@@ -1588,6 +1589,16 @@ ERROR: '%s': cannot process note segment.\n", _dl_argv[0]); + { + /* Extract the contents of the dynamic section for easy access. */ + elf_get_dynamic_info (main_map, NULL); ++ ++ /* If the main map is libc.so, update the base namespace to ++ refer to this map. If libc.so is loaded later, this happens ++ in _dl_map_object_from_fd. */ ++ if (main_map->l_info[DT_SONAME] != NULL ++ && (strcmp (((const char *) D_PTR (main_map, l_info[DT_STRTAB]) ++ + main_map->l_info[DT_SONAME]->d_un.d_val), LIBC_SO) ++ == 0)) ++ GL(dl_ns)[LM_ID_BASE].libc_map = main_map; ++ + /* Set up our cache of pointers into the hash table. */ + _dl_setup_hash (main_map); + } diff --git a/SOURCES/glibc-rh1888660.patch b/SOURCES/glibc-rh1888660.patch new file mode 100644 index 0000000..ec80b81 --- /dev/null +++ b/SOURCES/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/SOURCES/glibc-rh1893662-1.patch b/SOURCES/glibc-rh1893662-1.patch new file mode 100644 index 0000000..f225f64 --- /dev/null +++ b/SOURCES/glibc-rh1893662-1.patch @@ -0,0 +1,47 @@ +commit 558251bd8785760ad40fcbfeaaee5d27fa5b0fe4 +Author: Szabolcs Nagy +Date: Thu Oct 22 17:55:01 2020 +0100 + + aarch64: Fix DT_AARCH64_VARIANT_PCS handling [BZ #26798] + + The variant PCS support was ineffective because in the common case + linkmap->l_mach.plt == 0 but then the symbol table flags were ignored + and normal lazy binding was used instead of resolving the relocs early. + (This was a misunderstanding about how GOT[1] is setup by the linker.) + + In practice this mainly affects SVE calls when the vector length is + more than 128 bits, then the top bits of the argument registers get + clobbered during lazy binding. + + Fixes bug 26798. + +diff --git a/sysdeps/aarch64/dl-machine.h b/sysdeps/aarch64/dl-machine.h +index b39eae4acf4086ee..3fd3c8a265d012b1 100644 +--- a/sysdeps/aarch64/dl-machine.h ++++ b/sysdeps/aarch64/dl-machine.h +@@ -391,13 +391,6 @@ elf_machine_lazy_rel (struct link_map *map, + /* Check for unexpected PLT reloc type. */ + if (__builtin_expect (r_type == AARCH64_R(JUMP_SLOT), 1)) + { +- if (map->l_mach.plt == 0) +- { +- /* Prelinking. */ +- *reloc_addr += l_addr; +- return; +- } +- + if (__glibc_unlikely (map->l_info[DT_AARCH64 (VARIANT_PCS)] != NULL)) + { + /* Check the symbol table for variant PCS symbols. */ +@@ -421,7 +414,10 @@ elf_machine_lazy_rel (struct link_map *map, + } + } + +- *reloc_addr = map->l_mach.plt; ++ if (map->l_mach.plt == 0) ++ *reloc_addr += l_addr; ++ else ++ *reloc_addr = map->l_mach.plt; + } + else if (__builtin_expect (r_type == AARCH64_R(TLSDESC), 1)) + { diff --git a/SOURCES/glibc-rh1893662-2.patch b/SOURCES/glibc-rh1893662-2.patch new file mode 100644 index 0000000..e421ade --- /dev/null +++ b/SOURCES/glibc-rh1893662-2.patch @@ -0,0 +1,349 @@ +commit e156dabc766d6f6f99ce9402999eae380a3ec1f2 +Author: Szabolcs Nagy +Date: Mon Oct 26 15:48:01 2020 +0000 + + aarch64: Add variant PCS lazy binding test [BZ #26798] + + This test fails without bug 26798 fixed because some integer registers + likely get clobbered by lazy binding and variant PCS only allows x16 + and x17 to be clobbered at call time. + + The test requires binutils 2.32.1 or newer for handling variant PCS + symbols. SVE registers are not covered by this test, to avoid the + complexity of handling multiple compile- and runtime feature support + cases. + +(Trivial textual conflicts due to lack of PAC and BTI support) + +# Conflicts: +# sysdeps/aarch64/Makefile +# sysdeps/aarch64/configure +# sysdeps/aarch64/configure.ac + +diff --git a/sysdeps/aarch64/Makefile b/sysdeps/aarch64/Makefile +index 94baaf52dda4b801..3ec78fefc6dd5797 100644 +--- a/sysdeps/aarch64/Makefile ++++ b/sysdeps/aarch64/Makefile +@@ -3,6 +3,13 @@ long-double-fcts = yes + ifeq ($(subdir),elf) + sysdep-dl-routines += tlsdesc dl-tlsdesc + gen-as-const-headers += dl-link.sym ++ ++ifeq (yes,$(aarch64-variant-pcs)) ++tests += tst-vpcs ++modules-names += tst-vpcs-mod ++LDFLAGS-tst-vpcs-mod.so = -Wl,-z,lazy ++$(objpfx)tst-vpcs: $(objpfx)tst-vpcs-mod.so ++endif + endif + + ifeq ($(subdir),csu) +diff --git a/sysdeps/aarch64/configure b/sysdeps/aarch64/configure +index 5bd355a6917df365..f78a79338aba1e34 100644 +--- a/sysdeps/aarch64/configure ++++ b/sysdeps/aarch64/configure +@@ -172,3 +172,43 @@ else + config_vars="$config_vars + default-abi = lp64" + fi ++ ++# Check if binutils supports variant PCS symbols. ++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for variant PCS support" >&5 ++$as_echo_n "checking for variant PCS support... " >&6; } ++if ${libc_cv_aarch64_variant_pcs+:} false; then : ++ $as_echo_n "(cached) " >&6 ++else ++ cat > conftest.S <&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 -dW conftest.so | grep -q AARCH64_VARIANT_PCS' ++ { { 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; }; } ++ then ++ libc_cv_aarch64_variant_pcs=yes ++ fi ++ rm -rf conftest.* ++fi ++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libc_cv_aarch64_variant_pcs" >&5 ++$as_echo "$libc_cv_aarch64_variant_pcs" >&6; } ++config_vars="$config_vars ++aarch64-variant-pcs = $libc_cv_aarch64_variant_pcs" +diff --git a/sysdeps/aarch64/configure.ac b/sysdeps/aarch64/configure.ac +index 7851dd4dac345b2a..7f13bfb93b60bfd7 100644 +--- a/sysdeps/aarch64/configure.ac ++++ b/sysdeps/aarch64/configure.ac +@@ -20,3 +20,25 @@ if test $libc_cv_aarch64_be = yes; then + else + LIBC_CONFIG_VAR([default-abi], [lp64]) + fi ++ ++# Check if binutils supports variant PCS symbols. ++AC_CACHE_CHECK([for variant PCS support], [libc_cv_aarch64_variant_pcs], [dnl ++ cat > conftest.S <. */ ++ ++ .variant_pcs vpcs_call ++ .global vpcs_call ++ .type vpcs_call, %function ++vpcs_call: ++ .cfi_startproc ++ hint 34 /* bti c. */ ++ ++ /* Save register state to *x0. */ ++ stp x0, x1, [x0] ++ stp x2, x3, [x0, 16] ++ stp x4, x5, [x0, 32] ++ stp x6, x7, [x0, 48] ++ stp x8, x9, [x0, 64] ++ stp x10, x11, [x0, 80] ++ stp x12, x13, [x0, 96] ++ stp x14, x15, [x0, 112] ++ stp x16, x17, [x0, 128] ++ stp x18, x19, [x0, 144] ++ stp x20, x21, [x0, 160] ++ stp x22, x23, [x0, 176] ++ stp x24, x25, [x0, 192] ++ stp x26, x27, [x0, 208] ++ stp x28, x29, [x0, 224] ++ mov x1, sp ++ stp x30, x1, [x0, 240] ++ stp q0, q1, [x0, 256] ++ stp q2, q3, [x0, 288] ++ stp q4, q5, [x0, 320] ++ stp q6, q7, [x0, 352] ++ stp q8, q9, [x0, 384] ++ stp q10, q11, [x0, 416] ++ stp q12, q13, [x0, 448] ++ stp q14, q15, [x0, 480] ++ stp q16, q17, [x0, 512] ++ stp q18, q19, [x0, 544] ++ stp q20, q21, [x0, 576] ++ stp q22, q23, [x0, 608] ++ stp q24, q25, [x0, 640] ++ stp q26, q27, [x0, 672] ++ stp q28, q29, [x0, 704] ++ stp q30, q31, [x0, 736] ++ ret ++ .cfi_endproc ++ .size vpcs_call, .-vpcs_call ++ ++ .global vpcs_call_regs ++ .type vpcs_call_regs, %function ++vpcs_call_regs: ++ .cfi_startproc ++ hint 34 /* bti c. */ ++ ++ stp x29, x30, [sp, -160]! ++ mov x29, sp ++ ++ /* Save callee-saved registers. */ ++ stp x19, x20, [sp, 16] ++ stp x21, x22, [sp, 32] ++ stp x23, x24, [sp, 48] ++ stp x25, x26, [sp, 64] ++ stp x27, x28, [sp, 80] ++ stp d8, d9, [sp, 96] ++ stp d10, d11, [sp, 112] ++ stp d12, d13, [sp, 128] ++ stp d14, d15, [sp, 144] ++ ++ /* Initialize most registers from *x1, and save x0, x1, x29, x30, ++ and sp (== x29), so *x1 contains the register state. */ ++ stp x0, x1, [x1] ++ str x29, [x1, 232] ++ ldp x2, x3, [x1, 16] ++ ldp x4, x5, [x1, 32] ++ ldp x6, x7, [x1, 48] ++ ldp x8, x9, [x1, 64] ++ ldp x10, x11, [x1, 80] ++ ldp x12, x13, [x1, 96] ++ ldp x14, x15, [x1, 112] ++ ldp x16, x17, [x1, 128] ++ ldp x18, x19, [x1, 144] ++ ldp x20, x21, [x1, 160] ++ ldp x22, x23, [x1, 176] ++ ldp x24, x25, [x1, 192] ++ ldp x26, x27, [x1, 208] ++ ldr x28, [x1, 224] ++ /* Skip x29, x30, sp. */ ++ ldp q0, q1, [x1, 256] ++ ldp q2, q3, [x1, 288] ++ ldp q4, q5, [x1, 320] ++ ldp q6, q7, [x1, 352] ++ ldp q8, q9, [x1, 384] ++ ldp q10, q11, [x1, 416] ++ ldp q12, q13, [x1, 448] ++ ldp q14, q15, [x1, 480] ++ ldp q16, q17, [x1, 512] ++ ldp q18, q19, [x1, 544] ++ ldp q20, q21, [x1, 576] ++ ldp q22, q23, [x1, 608] ++ ldp q24, q25, [x1, 640] ++ ldp q26, q27, [x1, 672] ++ ldp q28, q29, [x1, 704] ++ ldp q30, q31, [x1, 736] ++ ++ /* Emulate a BL using B, but save x30 before the branch. */ ++ adr x30, .L_return_addr ++ stp x30, x29, [x1, 240] ++ b vpcs_call ++.L_return_addr: ++ ++ /* Restore callee-saved registers. */ ++ ldp x19, x20, [sp, 16] ++ ldp x21, x22, [sp, 32] ++ ldp x23, x24, [sp, 48] ++ ldp x25, x26, [sp, 64] ++ ldp x27, x28, [sp, 80] ++ ldp d8, d9, [sp, 96] ++ ldp d10, d11, [sp, 112] ++ ldp d12, d13, [sp, 128] ++ ldp d14, d15, [sp, 144] ++ ++ ldp x29, x30, [sp], 160 ++ ret ++ .cfi_endproc ++ .size vpcs_call_regs, .-vpcs_call_regs +diff --git a/sysdeps/aarch64/tst-vpcs.c b/sysdeps/aarch64/tst-vpcs.c +new file mode 100644 +index 0000000000000000..92a701eb7cdea8ac +--- /dev/null ++++ b/sysdeps/aarch64/tst-vpcs.c +@@ -0,0 +1,78 @@ ++/* Test that variant PCS calls don't clobber registers with lazy binding. ++ 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 ++ ++struct regs ++{ ++ uint64_t x[32]; ++ union { ++ long double q[32]; ++ uint64_t u[64]; ++ } v; ++}; ++ ++/* Gives the registers in the caller and callee around a variant PCS call. ++ Most registers are initialized from BEFORE in the caller so they can ++ have values that likely show clobbers. Register state extensions such ++ as SVE is not covered here, only the base registers. */ ++void vpcs_call_regs (struct regs *after, struct regs *before); ++ ++static int ++do_test (void) ++{ ++ struct regs before, after; ++ int err = 0; ++ ++ unsigned char *p = (unsigned char *)&before; ++ for (int i = 0; i < sizeof before; i++) ++ p[i] = i & 0xff; ++ ++ vpcs_call_regs (&after, &before); ++ ++ for (int i = 0; i < 32; i++) ++ if (before.x[i] != after.x[i]) ++ { ++ if (i == 16 || i == 17) ++ /* Variant PCS allows clobbering x16 and x17. */ ++ continue; ++ err++; ++ printf ("x%d: before: 0x%016llx after: 0x%016llx\n", ++ i, ++ (unsigned long long)before.x[i], ++ (unsigned long long)after.x[i]); ++ } ++ for (int i = 0; i < 64; i++) ++ if (before.v.u[i] != after.v.u[i]) ++ { ++ err++; ++ printf ("v%d: before: 0x%016llx %016llx after: 0x%016llx %016llx\n", ++ i/2, ++ (unsigned long long)before.v.u[2*(i/2)+1], ++ (unsigned long long)before.v.u[2*(i/2)], ++ (unsigned long long)after.v.u[2*(i/2)+1], ++ (unsigned long long)after.v.u[2*(i/2)]); ++ } ++ if (err) ++ FAIL_EXIT1 ("The variant PCS call clobbered %d registers.\n", err); ++ return 0; ++} ++ ++#include diff --git a/SOURCES/glibc-rh1912544.patch b/SOURCES/glibc-rh1912544.patch new file mode 100644 index 0000000..c64e731 --- /dev/null +++ b/SOURCES/glibc-rh1912544.patch @@ -0,0 +1,126 @@ +commit ee7a3144c9922808181009b7b3e50e852fb4999b +Author: Andreas Schwab +Date: Mon Dec 21 08:56:43 2020 +0530 + + Fix buffer overrun in EUC-KR conversion module (bz #24973) + + The byte 0xfe as input to the EUC-KR conversion denotes a user-defined + area and is not allowed. The from_euc_kr function used to skip two bytes + when told to skip over the unknown designation, potentially running over + the buffer end. + +# Conflicts: +# iconvdata/Makefile + +diff --git a/iconvdata/Makefile b/iconvdata/Makefile +index 06e161d9b8f67118..a47a4c07cd2e3d1b 100644 +--- a/iconvdata/Makefile ++++ b/iconvdata/Makefile +@@ -73,7 +73,7 @@ modules.so := $(addsuffix .so, $(modules)) + ifeq (yes,$(build-shared)) + tests = bug-iconv1 bug-iconv2 tst-loading tst-e2big tst-iconv4 bug-iconv4 \ + tst-iconv6 bug-iconv5 bug-iconv6 tst-iconv7 bug-iconv8 bug-iconv9 \ +- bug-iconv10 bug-iconv11 bug-iconv12 ++ bug-iconv10 bug-iconv11 bug-iconv12 bug-iconv13 + ifeq ($(have-thread-library),yes) + tests += bug-iconv3 + endif +diff --git a/iconvdata/bug-iconv13.c b/iconvdata/bug-iconv13.c +new file mode 100644 +index 0000000000000000..87aaff398e0f6167 +--- /dev/null ++++ b/iconvdata/bug-iconv13.c +@@ -0,0 +1,53 @@ ++/* bug 24973: Test EUC-KR module ++ 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 ++ ++static int ++do_test (void) ++{ ++ iconv_t cd = iconv_open ("UTF-8//IGNORE", "EUC-KR"); ++ TEST_VERIFY_EXIT (cd != (iconv_t) -1); ++ ++ /* 0xfe (->0x7e : row 94) and 0xc9 (->0x49 : row 41) are user-defined ++ areas, which are not allowed and should be skipped over due to ++ //IGNORE. The trailing 0xfe also is an incomplete sequence, which ++ should be checked first. */ ++ char input[4] = { '\xc9', '\xa1', '\0', '\xfe' }; ++ char *inptr = input; ++ size_t insize = sizeof (input); ++ char output[4]; ++ char *outptr = output; ++ size_t outsize = sizeof (output); ++ ++ /* This used to crash due to buffer overrun. */ ++ TEST_VERIFY (iconv (cd, &inptr, &insize, &outptr, &outsize) == (size_t) -1); ++ TEST_VERIFY (errno == EINVAL); ++ /* The conversion should produce one character, the converted null ++ character. */ ++ TEST_VERIFY (sizeof (output) - outsize == 1); ++ ++ TEST_VERIFY_EXIT (iconv_close (cd) != -1); ++ ++ return 0; ++} ++ ++#include +diff --git a/iconvdata/euc-kr.c b/iconvdata/euc-kr.c +index 73e02817a07e873d..dc7eaa6596f5d4d4 100644 +--- a/iconvdata/euc-kr.c ++++ b/iconvdata/euc-kr.c +@@ -80,11 +80,7 @@ euckr_from_ucs4 (uint32_t ch, unsigned char *cp) + \ + if (ch <= 0x9f) \ + ++inptr; \ +- /* 0xfe(->0x7e : row 94) and 0xc9(->0x59 : row 41) are \ +- user-defined areas. */ \ +- else if (__builtin_expect (ch == 0xa0, 0) \ +- || __builtin_expect (ch > 0xfe, 0) \ +- || __builtin_expect (ch == 0xc9, 0)) \ ++ else if (__glibc_unlikely (ch == 0xa0)) \ + { \ + /* This is illegal. */ \ + STANDARD_FROM_LOOP_ERR_HANDLER (1); \ +diff --git a/iconvdata/ksc5601.h b/iconvdata/ksc5601.h +index 5588d3a14b667b42..fa2d30677c41f46a 100644 +--- a/iconvdata/ksc5601.h ++++ b/iconvdata/ksc5601.h +@@ -50,15 +50,15 @@ ksc5601_to_ucs4 (const unsigned char **s, size_t avail, unsigned char offset) + unsigned char ch2; + int idx; + ++ if (avail < 2) ++ return 0; ++ + /* row 94(0x7e) and row 41(0x49) are user-defined area in KS C 5601 */ + + if (ch < offset || (ch - offset) <= 0x20 || (ch - offset) >= 0x7e + || (ch - offset) == 0x49) + return __UNKNOWN_10646_CHAR; + +- if (avail < 2) +- return 0; +- + ch2 = (*s)[1]; + if (ch2 < offset || (ch2 - offset) <= 0x20 || (ch2 - offset) >= 0x7f) + return __UNKNOWN_10646_CHAR; diff --git a/SOURCES/glibc-rh1912670-1.patch b/SOURCES/glibc-rh1912670-1.patch new file mode 100644 index 0000000..92bd13d --- /dev/null +++ b/SOURCES/glibc-rh1912670-1.patch @@ -0,0 +1,266 @@ +Conflicts in sysdeps/unix/sysv/linux/semctl.c were due to 64-bit time_t +and RHEL8 has a simpler implementation. + +Conflicts in sysdeps/unix/sysv/linux/Makefile were due to the usual test +case conflicts. + +commit 574500a108be1d2a6a0dc97a075c9e0a98371aba +Author: Dmitry V. Levin +Date: Tue Sep 29 14:10:20 2020 -0300 + + sysvipc: Fix SEM_STAT_ANY kernel argument pass [BZ #26637] + + Handle SEM_STAT_ANY the same way as SEM_STAT so that the buffer argument + of SEM_STAT_ANY is properly passed to the kernel and back. + + The regression testcase checks for Linux specifix SysV ipc message + control extension. For IPC_INFO/SEM_INFO it tries to match the values + against the tunable /proc values and for SEM_STAT/SEM_STAT_ANY it + check if the create message queue is within the global list returned + by the kernel. + + Checked on x86_64-linux-gnu and on i686-linux-gnu (Linux v5.4 and on + Linux v4.15). + + Co-authored-by: Adhemerval Zanella + +# Conflicts: +# sysdeps/unix/sysv/linux/Makefile +# sysdeps/unix/sysv/linux/semctl.c + +diff --git a/sysdeps/unix/sysv/linux/Makefile b/sysdeps/unix/sysv/linux/Makefile +index fb4ccd63ddec7eca..c6907796152eb09d 100644 +--- a/sysdeps/unix/sysv/linux/Makefile ++++ b/sysdeps/unix/sysv/linux/Makefile +@@ -45,7 +45,8 @@ sysdep_headers += sys/mount.h sys/acct.h sys/sysctl.h \ + tests += tst-clone tst-clone2 tst-clone3 tst-fanotify tst-personality \ + tst-quota tst-sync_file_range tst-sysconf-iov_max tst-ttyname \ + test-errno-linux tst-memfd_create tst-mlock2 tst-pkey \ +- tst-rlimit-infinity tst-ofdlocks ++ tst-rlimit-infinity tst-ofdlocks \ ++ tst-sysvsem-linux + tests-internal += tst-ofdlocks-compat + + +diff --git a/sysdeps/unix/sysv/linux/semctl.c b/sysdeps/unix/sysv/linux/semctl.c +index e2925447eba2ee94..bdf31ca7747fe5a4 100644 +--- a/sysdeps/unix/sysv/linux/semctl.c ++++ b/sysdeps/unix/sysv/linux/semctl.c +@@ -51,6 +51,7 @@ __new_semctl (int semid, int semnum, int cmd, ...) + case IPC_STAT: /* arg.buf */ + case IPC_SET: + case SEM_STAT: ++ case SEM_STAT_ANY: + case IPC_INFO: /* arg.__buf */ + case SEM_INFO: + va_start (ap, cmd); +@@ -90,6 +91,7 @@ __old_semctl (int semid, int semnum, int cmd, ...) + case IPC_STAT: /* arg.buf */ + case IPC_SET: + case SEM_STAT: ++ case SEM_STAT_ANY: + case IPC_INFO: /* arg.__buf */ + case SEM_INFO: + va_start (ap, cmd); +diff --git a/sysdeps/unix/sysv/linux/tst-sysvsem-linux.c b/sysdeps/unix/sysv/linux/tst-sysvsem-linux.c +new file mode 100644 +index 0000000000000000..45f19e2d37ed194a +--- /dev/null ++++ b/sysdeps/unix/sysv/linux/tst-sysvsem-linux.c +@@ -0,0 +1,184 @@ ++/* Basic tests for Linux SYSV semaphore extensions. ++ 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 ++ ++/* These are for the temporary file we generate. */ ++static char *name; ++static int semid; ++ ++static void ++remove_sem (void) ++{ ++ /* Enforce message queue removal in case of early test failure. ++ Ignore error since the sem may already have being removed. */ ++ semctl (semid, 0, IPC_RMID, 0); ++} ++ ++static void ++do_prepare (int argc, char *argv[]) ++{ ++ TEST_VERIFY_EXIT (create_temp_file ("tst-sysvsem.", &name) != -1); ++} ++ ++#define PREPARE do_prepare ++ ++#define SEM_MODE 0644 ++ ++union semun ++{ ++ int val; ++ struct semid_ds *buf; ++ unsigned short *array; ++ struct seminfo *__buf; ++}; ++ ++struct test_seminfo ++{ ++ int semmsl; ++ int semmns; ++ int semopm; ++ int semmni; ++}; ++ ++/* It tries to obtain some system-wide SysV semaphore information from /proc ++ to check against IPC_INFO/SEM_INFO. The /proc only returns the tunables ++ value of SEMMSL, SEMMNS, SEMOPM, and SEMMNI. ++ ++ The kernel also returns constant value for SEMVMX, SEMMNU, SEMMAP, SEMUME, ++ and also SEMUSZ and SEMAEM (for IPC_INFO). The issue to check them is they ++ might change over kernel releases. */ ++ ++static void ++read_sem_stat (struct test_seminfo *tseminfo) ++{ ++ FILE *f = fopen ("/proc/sys/kernel/sem", "r"); ++ if (f == NULL) ++ FAIL_UNSUPPORTED ("/proc is not mounted or /proc/sys/kernel/sem is not " ++ "available"); ++ ++ int r = fscanf (f, "%d %d %d %d", ++ &tseminfo->semmsl, &tseminfo->semmns, &tseminfo->semopm, ++ &tseminfo->semmni); ++ TEST_VERIFY_EXIT (r == 4); ++ ++ fclose (f); ++} ++ ++ ++/* Check if the semaphore with IDX (index into the kernel's internal array) ++ matches the one with KEY. The CMD is either SEM_STAT or SEM_STAT_ANY. */ ++ ++static bool ++check_seminfo (int idx, key_t key, int cmd) ++{ ++ struct semid_ds seminfo; ++ int sid = semctl (idx, 0, cmd, (union semun) { .buf = &seminfo }); ++ /* Ignore unused array slot returned by the kernel or information from ++ unknown semaphores. */ ++ if ((sid == -1 && errno == EINVAL) || sid != semid) ++ return false; ++ ++ if (sid == -1) ++ FAIL_EXIT1 ("semctl with SEM_STAT failed (errno=%d)", errno); ++ ++ TEST_COMPARE (seminfo.sem_perm.__key, key); ++ TEST_COMPARE (seminfo.sem_perm.mode, SEM_MODE); ++ TEST_COMPARE (seminfo.sem_nsems, 1); ++ ++ return true; ++} ++ ++static int ++do_test (void) ++{ ++ atexit (remove_sem); ++ ++ key_t key = ftok (name, 'G'); ++ if (key == -1) ++ FAIL_EXIT1 ("ftok failed: %m"); ++ ++ semid = semget (key, 1, IPC_CREAT | IPC_EXCL | SEM_MODE); ++ if (semid == -1) ++ FAIL_EXIT1 ("semget failed: %m"); ++ ++ struct test_seminfo tipcinfo; ++ read_sem_stat (&tipcinfo); ++ ++ int semidx; ++ ++ { ++ struct seminfo ipcinfo; ++ semidx = semctl (semid, 0, IPC_INFO, (union semun) { .__buf = &ipcinfo }); ++ if (semidx == -1) ++ FAIL_EXIT1 ("semctl with IPC_INFO failed: %m"); ++ ++ TEST_COMPARE (ipcinfo.semmsl, tipcinfo.semmsl); ++ TEST_COMPARE (ipcinfo.semmns, tipcinfo.semmns); ++ TEST_COMPARE (ipcinfo.semopm, tipcinfo.semopm); ++ TEST_COMPARE (ipcinfo.semmni, tipcinfo.semmni); ++ } ++ ++ /* Same as before but with SEM_INFO. */ ++ { ++ struct seminfo ipcinfo; ++ semidx = semctl (semid, 0, SEM_INFO, (union semun) { .__buf = &ipcinfo }); ++ if (semidx == -1) ++ FAIL_EXIT1 ("semctl with IPC_INFO failed: %m"); ++ ++ TEST_COMPARE (ipcinfo.semmsl, tipcinfo.semmsl); ++ TEST_COMPARE (ipcinfo.semmns, tipcinfo.semmns); ++ TEST_COMPARE (ipcinfo.semopm, tipcinfo.semopm); ++ TEST_COMPARE (ipcinfo.semmni, tipcinfo.semmni); ++ } ++ ++ /* We check if the created semaphore shows in the system-wide status. */ ++ bool found = false; ++ for (int i = 0; i <= semidx; i++) ++ { ++ /* We can't tell apart if SEM_STAT_ANY is not supported (kernel older ++ than 4.17) or if the index used is invalid. So it just check if ++ value returned from a valid call matches the created semaphore. */ ++ check_seminfo (i, key, SEM_STAT_ANY); ++ ++ if (check_seminfo (i, key, SEM_STAT)) ++ { ++ found = true; ++ break; ++ } ++ } ++ ++ if (!found) ++ FAIL_EXIT1 ("semctl with SEM_STAT/SEM_STAT_ANY could not find the " ++ "created semaphore"); ++ ++ if (semctl (semid, 0, IPC_RMID, 0) == -1) ++ FAIL_EXIT1 ("semctl failed: %m"); ++ ++ return 0; ++} ++ ++#include +diff --git a/sysvipc/test-sysvsem.c b/sysvipc/test-sysvsem.c +index a8e9bff000949ff8..d197772917a7579d 100644 +--- a/sysvipc/test-sysvsem.c ++++ b/sysvipc/test-sysvsem.c +@@ -20,6 +20,7 @@ + #include + #include + #include ++#include + #include + #include + #include diff --git a/SOURCES/glibc-rh1912670-2.patch b/SOURCES/glibc-rh1912670-2.patch new file mode 100644 index 0000000..7f730f0 --- /dev/null +++ b/SOURCES/glibc-rh1912670-2.patch @@ -0,0 +1,151 @@ +Rewrite of the following commit but adjusted pre-64-bit time_t +conversion. We want to follow the same upstream behaviour and return +EINVAL for unknown commands rather than to attempt the command with an +argument of {0} which has likely never been tested upstream. + +commit a16d2abd496bd974a88207d5599265aae5ae4880 +Author: Adhemerval Zanella +Date: Tue Sep 29 14:29:48 2020 -0300 + + sysvipc: Return EINVAL for invalid semctl commands + + It avoids regressions on possible future commands that might require + additional libc support. The downside is new commands added by newer + kernels will need further glibc support. + + Checked on x86_64-linux-gnu and i686-linux-gnu (Linux v4.15 and v5.4). + +diff --git a/sysdeps/unix/sysv/linux/semctl.c b/sysdeps/unix/sysv/linux/semctl.c +index bdf31ca7747fe5a4..03c56c69a5412c82 100644 +--- a/sysdeps/unix/sysv/linux/semctl.c ++++ b/sysdeps/unix/sysv/linux/semctl.c +@@ -58,6 +58,15 @@ __new_semctl (int semid, int semnum, int cmd, ...) + arg = va_arg (ap, union semun); + va_end (ap); + break; ++ case IPC_RMID: /* arg ignored. */ ++ case GETNCNT: ++ case GETPID: ++ case GETVAL: ++ case GETZCNT: ++ break; ++ default: ++ __set_errno (EINVAL); ++ return -1; + } + + #ifdef __ASSUME_DIRECT_SYSVIPC_SYSCALLS +diff --git a/sysvipc/test-sysvipc.h b/sysvipc/test-sysvipc.h +new file mode 100644 +index 0000000000000000..d7ed496511c10afb +--- /dev/null ++++ b/sysvipc/test-sysvipc.h +@@ -0,0 +1,85 @@ ++/* Basic definition for Sysv IPC test functions. ++ 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 ++ . */ ++ ++#ifndef _TEST_SYSV_H ++#define _TEST_SYSV_H ++ ++#include ++#include ++#include ++#include ++#include ++ ++/* Return the first invalid command SysV IPC command from common shared ++ between message queue, shared memory, and semaphore. */ ++static inline int ++first_common_invalid_cmd (void) ++{ ++ const int common_cmds[] = { ++ IPC_RMID, ++ IPC_SET, ++ IPC_STAT, ++ IPC_INFO, ++ }; ++ ++ int invalid = 0; ++ for (int i = 0; i < array_length (common_cmds); i++) ++ { ++ if (invalid == common_cmds[i]) ++ { ++ invalid++; ++ i = 0; ++ } ++ } ++ ++ return invalid; ++} ++ ++/* Return the first invalid command SysV IPC command for semaphore. */ ++static inline int ++first_sem_invalid_cmd (void) ++{ ++ const int sem_cmds[] = { ++ GETPID, ++ GETVAL, ++ GETALL, ++ GETNCNT, ++ GETZCNT, ++ SETVAL, ++ SETALL, ++ SEM_STAT, ++ SEM_INFO, ++#ifdef SEM_STAT_ANY ++ SEM_STAT_ANY, ++#endif ++ }; ++ ++ int invalid = first_common_invalid_cmd (); ++ for (int i = 0; i < array_length (sem_cmds); i++) ++ { ++ if (invalid == sem_cmds[i]) ++ { ++ invalid++; ++ i = 0; ++ } ++ } ++ ++ return invalid; ++} ++ ++#endif /* _TEST_SYSV_H */ +diff --git a/sysvipc/test-sysvsem.c b/sysvipc/test-sysvsem.c +index d197772917a7579d..43a1460ec2b9308f 100644 +--- a/sysvipc/test-sysvsem.c ++++ b/sysvipc/test-sysvsem.c +@@ -25,6 +25,8 @@ + #include + #include + ++#include ++ + #include + #include + #include +@@ -80,6 +82,9 @@ do_test (void) + FAIL_EXIT1 ("semget failed (errno=%d)", errno); + } + ++ TEST_COMPARE (semctl (semid, 0, first_sem_invalid_cmd (), NULL), -1); ++ TEST_COMPARE (errno, EINVAL); ++ + /* Get semaphore kernel information and do some sanity checks. */ + struct semid_ds seminfo; + if (semctl (semid, 0, IPC_STAT, (union semun) { .buf = &seminfo }) == -1) diff --git a/SOURCES/glibc-rh1912670-3.patch b/SOURCES/glibc-rh1912670-3.patch new file mode 100644 index 0000000..046f63b --- /dev/null +++ b/SOURCES/glibc-rh1912670-3.patch @@ -0,0 +1,224 @@ +Backport only the test case: + * sysdeps/unix/sysv/linux/tst-sysvmsg-linux.c + +This improves coverage for IPC_INFO and MSG_INFO. + +We don't need the actual fix in the bug because we don't have the 64-bit +time_t handling backported. + +commit 20a00dbefca5695cccaa44846a482db8ccdd85ab +Author: Adhemerval Zanella +Date: Tue Sep 29 14:39:56 2020 -0300 + + sysvipc: Fix IPC_INFO and MSG_INFO handling [BZ #26639] + + Both commands are Linux extensions where the third argument is a + 'struct msginfo' instead of 'struct msqid_ds' and its information + does not contain any time related fields (so there is no need to + extra conversion for __IPC_TIME64. + + The regression testcase checks for Linux specifix SysV ipc message + control extension. For IPC_INFO/MSG_INFO it tries to match the values + against the tunable /proc values and for MSG_STAT/MSG_STAT_ANY it + check if the create message queue is within the global list returned + by the kernel. + + Checked on x86_64-linux-gnu and on i686-linux-gnu (Linux v5.4 and on + Linux v4.15). + +diff --git a/sysdeps/unix/sysv/linux/Makefile b/sysdeps/unix/sysv/linux/Makefile +index 7d04e3313c56c15d..688cf9fa9dea23a6 100644 +--- a/sysdeps/unix/sysv/linux/Makefile ++++ b/sysdeps/unix/sysv/linux/Makefile +@@ -46,7 +46,7 @@ tests += tst-clone tst-clone2 tst-clone3 tst-fanotify tst-personality \ + tst-quota tst-sync_file_range tst-sysconf-iov_max tst-ttyname \ + test-errno-linux tst-memfd_create tst-mlock2 tst-pkey \ + tst-rlimit-infinity tst-ofdlocks \ +- tst-sysvsem-linux ++ tst-sysvsem-linux tst-sysvmsg-linux + tests-internal += tst-ofdlocks-compat + + +diff --git a/sysdeps/unix/sysv/linux/tst-sysvmsg-linux.c b/sysdeps/unix/sysv/linux/tst-sysvmsg-linux.c +new file mode 100644 +index 0000000000000000..1857fab8c1fdf041 +--- /dev/null ++++ b/sysdeps/unix/sysv/linux/tst-sysvmsg-linux.c +@@ -0,0 +1,177 @@ ++/* Basic tests for Linux SYSV message queue extensions. ++ 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 ++#include ++ ++#include ++#include ++ ++#define MSGQ_MODE 0644 ++ ++/* These are for the temporary file we generate. */ ++static char *name; ++static int msqid; ++ ++static void ++remove_msq (void) ++{ ++ /* Enforce message queue removal in case of early test failure. ++ Ignore error since the msg may already have being removed. */ ++ msgctl (msqid, IPC_RMID, NULL); ++} ++ ++static void ++do_prepare (int argc, char *argv[]) ++{ ++ TEST_VERIFY_EXIT (create_temp_file ("tst-sysvmsg.", &name) != -1); ++} ++ ++#define PREPARE do_prepare ++ ++struct test_msginfo ++{ ++ int msgmax; ++ int msgmnb; ++ int msgmni; ++}; ++ ++/* It tries to obtain some system-wide SysV messsage queue information from ++ /proc to check against IPC_INFO/MSG_INFO. The /proc only returns the ++ tunables value of MSGMAX, MSGMNB, and MSGMNI. ++ ++ The kernel also returns constant value for MSGSSZ, MSGSEG and also MSGMAP, ++ MSGPOOL, and MSGTQL (for IPC_INFO). The issue to check them is they might ++ change over kernel releases. */ ++ ++static int ++read_proc_file (const char *file) ++{ ++ FILE *f = fopen (file, "r"); ++ if (f == NULL) ++ FAIL_UNSUPPORTED ("/proc is not mounted or %s is not available", file); ++ ++ int v; ++ int r = fscanf (f, "%d", & v); ++ TEST_VERIFY_EXIT (r == 1); ++ ++ fclose (f); ++ return v; ++} ++ ++ ++/* Check if the message queue with IDX (index into the kernel's internal ++ array) matches the one with KEY. The CMD is either MSG_STAT or ++ MSG_STAT_ANY. */ ++ ++static bool ++check_msginfo (int idx, key_t key, int cmd) ++{ ++ struct msqid_ds msginfo; ++ int mid = msgctl (idx, cmd, &msginfo); ++ /* Ignore unused array slot returned by the kernel or information from ++ unknown message queue. */ ++ if ((mid == -1 && errno == EINVAL) || mid != msqid) ++ return false; ++ ++ if (mid == -1) ++ FAIL_EXIT1 ("msgctl with %s failed: %m", ++ cmd == MSG_STAT ? "MSG_STAT" : "MSG_STAT_ANY"); ++ ++ TEST_COMPARE (msginfo.msg_perm.__key, key); ++ TEST_COMPARE (msginfo.msg_perm.mode, MSGQ_MODE); ++ TEST_COMPARE (msginfo.msg_qnum, 0); ++ ++ return true; ++} ++ ++static int ++do_test (void) ++{ ++ atexit (remove_msq); ++ ++ key_t key = ftok (name, 'G'); ++ if (key == -1) ++ FAIL_EXIT1 ("ftok failed: %m"); ++ ++ msqid = msgget (key, MSGQ_MODE | IPC_CREAT); ++ if (msqid == -1) ++ FAIL_EXIT1 ("msgget failed: %m"); ++ ++ struct test_msginfo tipcinfo; ++ tipcinfo.msgmax = read_proc_file ("/proc/sys/kernel/msgmax"); ++ tipcinfo.msgmnb = read_proc_file ("/proc/sys/kernel/msgmnb"); ++ tipcinfo.msgmni = read_proc_file ("/proc/sys/kernel/msgmni"); ++ ++ int msqidx; ++ ++ { ++ struct msginfo ipcinfo; ++ msqidx = msgctl (msqid, IPC_INFO, (struct msqid_ds *) &ipcinfo); ++ if (msqidx == -1) ++ FAIL_EXIT1 ("msgctl with IPC_INFO failed: %m"); ++ ++ TEST_COMPARE (ipcinfo.msgmax, tipcinfo.msgmax); ++ TEST_COMPARE (ipcinfo.msgmnb, tipcinfo.msgmnb); ++ TEST_COMPARE (ipcinfo.msgmni, tipcinfo.msgmni); ++ } ++ ++ /* Same as before but with MSG_INFO. */ ++ { ++ struct msginfo ipcinfo; ++ msqidx = msgctl (msqid, MSG_INFO, (struct msqid_ds *) &ipcinfo); ++ if (msqidx == -1) ++ FAIL_EXIT1 ("msgctl with IPC_INFO failed: %m"); ++ ++ TEST_COMPARE (ipcinfo.msgmax, tipcinfo.msgmax); ++ TEST_COMPARE (ipcinfo.msgmnb, tipcinfo.msgmnb); ++ TEST_COMPARE (ipcinfo.msgmni, tipcinfo.msgmni); ++ } ++ ++ /* We check if the created message queue shows in global list. */ ++ bool found = false; ++ for (int i = 0; i <= msqidx; i++) ++ { ++ /* We can't tell apart if MSG_STAT_ANY is not supported (kernel older ++ than 4.17) or if the index used is invalid. So it just check if the ++ value returned from a valid call matches the created message ++ queue. */ ++ check_msginfo (i, key, MSG_STAT_ANY); ++ ++ if (check_msginfo (i, key, MSG_STAT)) ++ { ++ found = true; ++ break; ++ } ++ } ++ ++ if (!found) ++ FAIL_EXIT1 ("msgctl with MSG_STAT/MSG_STAT_ANY could not find the " ++ "created message queue"); ++ ++ if (msgctl (msqid, IPC_RMID, NULL) == -1) ++ FAIL_EXIT1 ("msgctl failed"); ++ ++ return 0; ++} ++ ++#include diff --git a/SOURCES/glibc-rh1912670-4.patch b/SOURCES/glibc-rh1912670-4.patch new file mode 100644 index 0000000..2b0c33f --- /dev/null +++ b/SOURCES/glibc-rh1912670-4.patch @@ -0,0 +1,98 @@ +This is a rewrite of the commit for the pre-64-bit time_t version of +the msgctl handling. Similar to semctl we want the RHEL8 handling of +the unknown commands to be the same as upstream. + +commit be9b0b9a012780a403a266c90878efffb9a5f3ca +Author: Adhemerval Zanella +Date: Tue Sep 29 14:45:09 2020 -0300 + + sysvipc: Return EINVAL for invalid msgctl commands + + It avoids regressions on possible future commands that might require + additional libc support. The downside is new commands added by newer + kernels will need further glibc support. + + Checked on x86_64-linux-gnu and i686-linux-gnu (Linux v4.15 and v5.4). + +diff --git a/sysdeps/unix/sysv/linux/msgctl.c b/sysdeps/unix/sysv/linux/msgctl.c +index 7280cba31a8815a2..6a2c79d188b875b9 100644 +--- a/sysdeps/unix/sysv/linux/msgctl.c ++++ b/sysdeps/unix/sysv/linux/msgctl.c +@@ -29,6 +29,20 @@ + 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/sysvipc/test-sysvipc.h b/sysvipc/test-sysvipc.h +index ed0057b7871e505c..133fb71c6113a2b5 100644 +--- a/sysvipc/test-sysvipc.h ++++ b/sysvipc/test-sysvipc.h +@@ -134,4 +134,29 @@ first_shm_invalid_cmd (void) + return invalid; + } + ++/* Return the first invalid command SysV IPC command for message queue. */ ++static inline int ++first_msg_invalid_cmd (void) ++{ ++ const int msg_cmds[] = { ++ MSG_STAT, ++ MSG_INFO, ++#ifdef MSG_STAT_ANY ++ MSG_STAT_ANY, ++#endif ++ }; ++ ++ int invalid = first_common_invalid_cmd (); ++ for (int i = 0; i < array_length (msg_cmds); i++) ++ { ++ if (invalid == msg_cmds[i]) ++ { ++ invalid++; ++ i = 0; ++ } ++ } ++ ++ return invalid; ++} ++ + #endif /* _TEST_SYSV_H */ +diff --git a/sysvipc/test-sysvmsg.c b/sysvipc/test-sysvmsg.c +index 1e0471807cd26da1..74a907ad39ee114e 100644 +--- a/sysvipc/test-sysvmsg.c ++++ b/sysvipc/test-sysvmsg.c +@@ -24,6 +24,8 @@ + #include + #include + ++#include ++ + #include + #include + #include +@@ -86,6 +88,9 @@ do_test (void) + FAIL_EXIT1 ("msgget failed (errno=%d)", errno); + } + ++ TEST_COMPARE (msgctl (msqid, first_msg_invalid_cmd (), NULL), -1); ++ TEST_COMPARE (errno, EINVAL); ++ + /* Get message queue kernel information and do some sanity checks. */ + struct msqid_ds msginfo; + if (msgctl (msqid, IPC_STAT, &msginfo) == -1) diff --git a/SOURCES/glibc-rh1912670-5.patch b/SOURCES/glibc-rh1912670-5.patch new file mode 100644 index 0000000..2ffdbca --- /dev/null +++ b/SOURCES/glibc-rh1912670-5.patch @@ -0,0 +1,128 @@ +Rewrite of the following commit to support returning EINVAL for unknown +commands and therefore match upstream behaviour. + +commit 9ebaabeaac1a96b0d91f52902ce1dbf4f5a562dd +Author: Adhemerval Zanella +Date: Tue Sep 29 14:55:02 2020 -0300 + + sysvipc: Return EINVAL for invalid shmctl commands + + It avoids regressions on possible future commands that might require + additional libc support. The downside is new commands added by newer + kernels will need further glibc support. + + Checked on x86_64-linux-gnu and i686-linux-gnu (Linux v4.15 and v5.4). + +diff --git a/sysdeps/unix/sysv/linux/shmctl.c b/sysdeps/unix/sysv/linux/shmctl.c +index 25c5152944a6fcf3..00768bc47614f9aa 100644 +--- a/sysdeps/unix/sysv/linux/shmctl.c ++++ b/sysdeps/unix/sysv/linux/shmctl.c +@@ -33,6 +33,22 @@ + 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/sysvipc/test-sysvipc.h b/sysvipc/test-sysvipc.h +index 21ef6c656581519e..d1c8349b45b5ce49 100644 +--- a/sysvipc/test-sysvipc.h ++++ b/sysvipc/test-sysvipc.h +@@ -25,7 +25,7 @@ + #include + #include + +-/* Return the first invalid command SysV IPC command from common shared ++/* Return the first invalid SysV IPC command from common shared + between message queue, shared memory, and semaphore. */ + static inline int + first_common_invalid_cmd (void) +@@ -50,7 +50,7 @@ first_common_invalid_cmd (void) + return invalid; + } + +-/* Return the first invalid command SysV IPC command for semaphore. */ ++/* Return the first invalid SysV IPC command for semaphore. */ + static inline int + first_sem_invalid_cmd (void) + { +@@ -82,7 +82,7 @@ first_sem_invalid_cmd (void) + return invalid; + } + +-/* Return the first invalid command SysV IPC command for message queue. */ ++/* Return the first invalid SysV IPC command for message queue. */ + static inline int + first_msg_invalid_cmd (void) + { +@@ -107,4 +107,31 @@ first_msg_invalid_cmd (void) + return invalid; + } + ++/* Return the first invalid SysV IPC command for shared memory. */ ++static inline int ++first_shm_invalid_cmd (void) ++{ ++ const int shm_cmds[] = { ++ SHM_STAT, ++ SHM_INFO, ++#ifdef SHM_STAT_ANY ++ SHM_STAT_ANY, ++#endif ++ SHM_LOCK, ++ SHM_UNLOCK ++ }; ++ ++ int invalid = first_common_invalid_cmd (); ++ for (int i = 0; i < array_length (shm_cmds); i++) ++ { ++ if (invalid == shm_cmds[i]) ++ { ++ invalid++; ++ i = 0; ++ } ++ } ++ ++ return invalid; ++} ++ + #endif /* _TEST_SYSV_H */ +diff --git a/sysvipc/test-sysvshm.c b/sysvipc/test-sysvshm.c +index a7c2e0bd4065dbcd..0fdfddf8550413e4 100644 +--- a/sysvipc/test-sysvshm.c ++++ b/sysvipc/test-sysvshm.c +@@ -25,6 +25,8 @@ + #include + #include + ++#include ++ + #include + #include + #include +@@ -81,6 +83,9 @@ do_test (void) + FAIL_EXIT1 ("shmget failed (errno=%d)", errno); + } + ++ TEST_COMPARE (shmctl (shmid, first_shm_invalid_cmd (), NULL), -1); ++ TEST_COMPARE (errno, EINVAL); ++ + /* Get shared memory kernel information and do some sanity checks. */ + struct shmid_ds shminfo; + if (shmctl (shmid, IPC_STAT, &shminfo) == -1) diff --git a/SOURCES/glibc-rh1918115.patch b/SOURCES/glibc-rh1918115.patch new file mode 100644 index 0000000..1556ff4 --- /dev/null +++ b/SOURCES/glibc-rh1918115.patch @@ -0,0 +1,23 @@ +commit 23af890b3f04e80da783ba64e6b6d94822e01d54 +Author: Ondřej Hošek +Date: Wed Aug 26 04:26:50 2020 +0200 + + x86-64: Fix FMA4 detection in ifunc [BZ #26534] + + A typo in commit 107e6a3c2212ba7a3a4ec7cae8d82d73f7c95d0b causes the + FMA4 code path to be taken on systems that support FMA, even if they do + not support FMA4. Fix this to detect FMA4. + +diff --git a/sysdeps/x86_64/fpu/multiarch/ifunc-fma4.h b/sysdeps/x86_64/fpu/multiarch/ifunc-fma4.h +index 76c677198dac5cb0..6cb70ce25209ee15 100644 +--- a/sysdeps/x86_64/fpu/multiarch/ifunc-fma4.h ++++ b/sysdeps/x86_64/fpu/multiarch/ifunc-fma4.h +@@ -32,7 +32,7 @@ IFUNC_SELECTOR (void) + && CPU_FEATURE_USABLE_P (cpu_features, AVX2)) + return OPTIMIZE (fma); + +- if (CPU_FEATURE_USABLE_P (cpu_features, FMA)) ++ if (CPU_FEATURE_USABLE_P (cpu_features, FMA4)) + return OPTIMIZE (fma4); + + return OPTIMIZE (sse2); diff --git a/SOURCES/glibc-rh1918719-1.patch b/SOURCES/glibc-rh1918719-1.patch new file mode 100644 index 0000000..622ced9 --- /dev/null +++ b/SOURCES/glibc-rh1918719-1.patch @@ -0,0 +1,453 @@ +From b9d83bf3eb57e1cf8ef785f1a58e13ddf162b6f3 Mon Sep 17 00:00:00 2001 +From: Raphael M Zinsly +Date: Thu, 12 Nov 2020 13:12:24 -0300 +Subject: powerpc: Add optimized strncpy for POWER9 + +Similar to the strcpy P9 optimization, this version uses VSX to improve +performance. + +Reviewed-by: Matheus Castanho +Reviewed-by: Tulio Magno Quites Machado Filho + +diff --git a/sysdeps/powerpc/powerpc64/le/power9/strncpy.S b/sysdeps/powerpc/powerpc64/le/power9/strncpy.S +new file mode 100644 +index 0000000000..cbfc37bda3 +--- /dev/null ++++ b/sysdeps/powerpc/powerpc64/le/power9/strncpy.S +@@ -0,0 +1,344 @@ ++/* Optimized strncpy implementation for POWER9 LE. ++ 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 ++ ++# ifndef STRNCPY ++# define FUNC_NAME strncpy ++# else ++# define FUNC_NAME STRNCPY ++# endif ++ ++#ifndef MEMSET ++/* For builds without IFUNC support, local calls should be made to internal ++ GLIBC symbol (created by libc_hidden_builtin_def). */ ++# ifdef SHARED ++# define MEMSET_is_local ++# define MEMSET __GI_memset ++# else ++# define MEMSET memset ++# endif ++#endif ++ ++#define FRAMESIZE (FRAME_MIN_SIZE+8) ++ ++/* Implements the function ++ ++ char * [r3] strncpy (char *dest [r3], const char *src [r4], size_t n [r5]) ++ ++ The implementation can load bytes past a null terminator, but only ++ up to the next 16-byte aligned address, so it never crosses a page. */ ++ ++.machine power9 ++#ifdef MEMSET_is_local ++ENTRY_TOCLESS (FUNC_NAME, 4) ++#else ++ENTRY (FUNC_NAME, 4) ++#endif ++ CALL_MCOUNT 2 ++ ++ /* NULL string optimizations */ ++ cmpdi r5, 0 ++ beqlr ++ ++ lbz r0,0(r4) ++ stb r0,0(r3) ++ addi r11,r3,1 ++ addi r5,r5,-1 ++ vspltisb v18,0 /* Zeroes in v18 */ ++ cmpdi r0,0 ++ beq L(zero_padding) ++ ++ /* Empty/1-byte string optimization */ ++ cmpdi r5,0 ++ beqlr ++ ++ addi r4,r4,1 ++ neg r7,r4 ++ rldicl r9,r7,0,60 /* How many bytes to get source 16B aligned? */ ++ ++ /* Get source 16B aligned */ ++ lvx v0,0,r4 ++ lvsr v1,0,r4 ++ vperm v0,v18,v0,v1 ++ ++ vcmpequb v6,v0,v18 /* 0xff if byte is NULL, 0x00 otherwise */ ++ vctzlsbb r7,v6 /* Number of trailing zeroes */ ++ addi r8,r7,1 /* Add null terminator */ ++ ++ /* r8 = bytes including null ++ r9 = bytes to get source 16B aligned ++ if r8 > r9 ++ no null, copy r9 bytes ++ else ++ there is a null, copy r8 bytes and return. */ ++ cmpld r8,r9 ++ bgt L(no_null) ++ ++ cmpld cr6,r8,r5 /* r8 <= n? */ ++ ble cr6,L(null) ++ ++ sldi r10,r5,56 /* stxvl wants size in top 8 bits */ ++ stxvl 32+v0,r11,r10 /* Partial store */ ++ ++ blr ++ ++L(null): ++ sldi r10,r8,56 /* stxvl wants size in top 8 bits */ ++ stxvl 32+v0,r11,r10 /* Partial store */ ++ ++ add r11,r11,r8 ++ sub r5,r5,r8 ++ b L(zero_padding) ++ ++L(no_null): ++ cmpld r9,r5 /* Check if length was reached. */ ++ bge L(n_tail1) ++ ++ sldi r10,r9,56 /* stxvl wants size in top 8 bits */ ++ stxvl 32+v0,r11,r10 /* Partial store */ ++ ++ add r4,r4,r9 ++ add r11,r11,r9 ++ sub r5,r5,r9 ++ ++L(loop): ++ cmpldi cr6,r5,64 /* Check if length was reached. */ ++ ble cr6,L(final_loop) ++ ++ lxv 32+v0,0(r4) ++ vcmpequb. v6,v0,v18 /* Any zero bytes? */ ++ bne cr6,L(prep_tail1) ++ ++ lxv 32+v1,16(r4) ++ vcmpequb. v6,v1,v18 /* Any zero bytes? */ ++ bne cr6,L(prep_tail2) ++ ++ lxv 32+v2,32(r4) ++ vcmpequb. v6,v2,v18 /* Any zero bytes? */ ++ bne cr6,L(prep_tail3) ++ ++ lxv 32+v3,48(r4) ++ vcmpequb. v6,v3,v18 /* Any zero bytes? */ ++ bne cr6,L(prep_tail4) ++ ++ stxv 32+v0,0(r11) ++ stxv 32+v1,16(r11) ++ stxv 32+v2,32(r11) ++ stxv 32+v3,48(r11) ++ ++ addi r4,r4,64 ++ addi r11,r11,64 ++ addi r5,r5,-64 ++ ++ b L(loop) ++ ++L(final_loop): ++ cmpldi cr5,r5,16 ++ lxv 32+v0,0(r4) ++ vcmpequb. v6,v0,v18 /* Any zero bytes? */ ++ ble cr5,L(prep_n_tail1) ++ bne cr6,L(count_tail1) ++ addi r5,r5,-16 ++ ++ cmpldi cr5,r5,16 ++ lxv 32+v1,16(r4) ++ vcmpequb. v6,v1,v18 /* Any zero bytes? */ ++ ble cr5,L(prep_n_tail2) ++ bne cr6,L(count_tail2) ++ addi r5,r5,-16 ++ ++ cmpldi cr5,r5,16 ++ lxv 32+v2,32(r4) ++ vcmpequb. v6,v2,v18 /* Any zero bytes? */ ++ ble cr5,L(prep_n_tail3) ++ bne cr6,L(count_tail3) ++ addi r5,r5,-16 ++ ++ lxv 32+v3,48(r4) ++ vcmpequb. v6,v3,v18 /* Any zero bytes? */ ++ beq cr6,L(n_tail4) ++ ++ vctzlsbb r8,v6 /* Number of trailing zeroes */ ++ cmpld r8,r5 /* r8 < n? */ ++ blt L(tail4) ++ ++L(n_tail4): ++ stxv 32+v0,0(r11) ++ stxv 32+v1,16(r11) ++ stxv 32+v2,32(r11) ++ sldi r10,r5,56 /* stxvl wants size in top 8 bits */ ++ addi r11,r11,48 /* Offset */ ++ stxvl 32+v3,r11,r10 /* Partial store */ ++ blr ++ ++L(prep_n_tail1): ++ beq cr6,L(n_tail1) /* Any zero bytes? */ ++ vctzlsbb r8,v6 /* Number of trailing zeroes */ ++ cmpld r8,r5 /* r8 < n? */ ++ blt L(tail1) ++ ++L(n_tail1): ++ sldi r10,r5,56 /* stxvl wants size in top 8 bits */ ++ stxvl 32+v0,r11,r10 /* Partial store */ ++ blr ++ ++L(prep_n_tail2): ++ beq cr6,L(n_tail2) /* Any zero bytes? */ ++ vctzlsbb r8,v6 /* Number of trailing zeroes */ ++ cmpld r8,r5 /* r8 < n? */ ++ blt L(tail2) ++ ++L(n_tail2): ++ stxv 32+v0,0(r11) ++ sldi r10,r5,56 /* stxvl wants size in top 8 bits */ ++ addi r11,r11,16 /* offset */ ++ stxvl 32+v1,r11,r10 /* Partial store */ ++ blr ++ ++L(prep_n_tail3): ++ beq cr6,L(n_tail3) /* Any zero bytes? */ ++ vctzlsbb r8,v6 /* Number of trailing zeroes */ ++ cmpld r8,r5 /* r8 < n? */ ++ blt L(tail3) ++ ++L(n_tail3): ++ stxv 32+v0,0(r11) ++ stxv 32+v1,16(r11) ++ sldi r10,r5,56 /* stxvl wants size in top 8 bits */ ++ addi r11,r11,32 /* Offset */ ++ stxvl 32+v2,r11,r10 /* Partial store */ ++ blr ++ ++L(prep_tail1): ++L(count_tail1): ++ vctzlsbb r8,v6 /* Number of trailing zeroes */ ++L(tail1): ++ addi r9,r8,1 /* Add null terminator */ ++ sldi r10,r9,56 /* stxvl wants size in top 8 bits */ ++ stxvl 32+v0,r11,r10 /* Partial store */ ++ add r11,r11,r9 ++ sub r5,r5,r9 ++ b L(zero_padding) ++ ++L(prep_tail2): ++ addi r5,r5,-16 ++L(count_tail2): ++ vctzlsbb r8,v6 /* Number of trailing zeroes */ ++L(tail2): ++ addi r9,r8,1 /* Add null terminator */ ++ stxv 32+v0,0(r11) ++ sldi r10,r9,56 /* stxvl wants size in top 8 bits */ ++ addi r11,r11,16 /* offset */ ++ stxvl 32+v1,r11,r10 /* Partial store */ ++ add r11,r11,r9 ++ sub r5,r5,r9 ++ b L(zero_padding) ++ ++L(prep_tail3): ++ addi r5,r5,-32 ++L(count_tail3): ++ vctzlsbb r8,v6 /* Number of trailing zeroes */ ++L(tail3): ++ addi r9,r8,1 /* Add null terminator */ ++ stxv 32+v0,0(r11) ++ stxv 32+v1,16(r11) ++ sldi r10,r9,56 /* stxvl wants size in top 8 bits */ ++ addi r11,r11,32 /* offset */ ++ stxvl 32+v2,r11,r10 /* Partial store */ ++ add r11,r11,r9 ++ sub r5,r5,r9 ++ b L(zero_padding) ++ ++L(prep_tail4): ++ addi r5,r5,-48 ++ vctzlsbb r8,v6 /* Number of trailing zeroes */ ++L(tail4): ++ addi r9,r8,1 /* Add null terminator */ ++ stxv 32+v0,0(r11) ++ stxv 32+v1,16(r11) ++ stxv 32+v2,32(r11) ++ sldi r10,r9,56 /* stxvl wants size in top 8 bits */ ++ addi r11,r11,48 /* offset */ ++ stxvl 32+v3,r11,r10 /* Partial store */ ++ add r11,r11,r9 ++ sub r5,r5,r9 ++ ++/* This code pads the remainder of dest with NULL bytes. For large numbers ++ memset gives a better performance, 255 was chosen through experimentation. ++ */ ++L(zero_padding): ++ cmpldi r5,255 ++ bge L(zero_padding_memset) ++ ++L(zero_padding_loop): ++ cmpldi cr6,r5,16 /* Check if length was reached. */ ++ ble cr6,L(zero_padding_end) ++ ++ stxv v18,0(r11) ++ addi r11,r11,16 ++ addi r5,r5,-16 ++ ++ b L(zero_padding_loop) ++ ++L(zero_padding_end): ++ sldi r10,r5,56 /* stxvl wants size in top 8 bits */ ++ stxvl v18,r11,r10 /* Partial store */ ++ blr ++ ++ .align 4 ++L(zero_padding_memset): ++ std r30,-8(r1) /* Save r30 on the stack. */ ++ cfi_offset(r30, -8) ++ mr r30,r3 /* Save the return value of strncpy. */ ++ /* Prepare the call to memset. */ ++ mr r3,r11 /* Pointer to the area to be zero-filled. */ ++ li r4,0 /* Byte to be written (zero). */ ++ ++ /* We delayed the creation of the stack frame, as well as the saving of ++ the link register, because only at this point, we are sure that ++ doing so is actually needed. */ ++ ++ /* Save the link register. */ ++ mflr r0 ++ std r0,16(r1) ++ ++ /* Create the stack frame. */ ++ stdu r1,-FRAMESIZE(r1) ++ cfi_adjust_cfa_offset(FRAMESIZE) ++ cfi_offset(lr, 16) ++ ++ bl MEMSET ++#ifndef MEMSET_is_local ++ nop ++#endif ++ ++ ld r0,FRAMESIZE+16(r1) ++ ++ mr r3,r30 /* Restore the return value of strncpy, i.e.: ++ dest. */ ++ ld r30,FRAMESIZE-8(r1) /* Restore r30. */ ++ /* Restore the stack frame. */ ++ addi r1,r1,FRAMESIZE ++ cfi_adjust_cfa_offset(-FRAMESIZE) ++ /* Restore the link register. */ ++ mtlr r0 ++ cfi_restore(lr) ++ blr ++ ++END (FUNC_NAME) +diff --git a/sysdeps/powerpc/powerpc64/multiarch/Makefile b/sysdeps/powerpc/powerpc64/multiarch/Makefile +index 19acb6c64a..cd2b47b403 100644 +--- a/sysdeps/powerpc/powerpc64/multiarch/Makefile ++++ b/sysdeps/powerpc/powerpc64/multiarch/Makefile +@@ -33,7 +33,7 @@ sysdep_routines += memcpy-power8-cached memcpy-power7 memcpy-a2 memcpy-power6 \ + + ifneq (,$(filter %le,$(config-machine))) + sysdep_routines += strcmp-power9 strncmp-power9 strcpy-power9 stpcpy-power9 \ +- rawmemchr-power9 strlen-power9 ++ rawmemchr-power9 strlen-power9 strncpy-power9 + endif + CFLAGS-strncase-power7.c += -mcpu=power7 -funroll-loops + CFLAGS-strncase_l-power7.c += -mcpu=power7 -funroll-loops +diff --git a/sysdeps/powerpc/powerpc64/multiarch/ifunc-impl-list.c b/sysdeps/powerpc/powerpc64/multiarch/ifunc-impl-list.c +index dd54e7d6bb..135326c97a 100644 +--- a/sysdeps/powerpc/powerpc64/multiarch/ifunc-impl-list.c ++++ b/sysdeps/powerpc/powerpc64/multiarch/ifunc-impl-list.c +@@ -301,6 +301,12 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + + /* Support sysdeps/powerpc/powerpc64/multiarch/strncpy.c. */ + IFUNC_IMPL (i, name, strncpy, ++#ifdef __LITTLE_ENDIAN__ ++ IFUNC_IMPL_ADD (array, i, strncpy, ++ (hwcap2 & PPC_FEATURE2_ARCH_3_00) ++ && (hwcap & PPC_FEATURE_HAS_VSX), ++ __strncpy_power9) ++#endif + IFUNC_IMPL_ADD (array, i, strncpy, + hwcap2 & PPC_FEATURE2_ARCH_2_07, + __strncpy_power8) +diff --git a/sysdeps/powerpc/powerpc64/multiarch/strncpy-power9.S b/sysdeps/powerpc/powerpc64/multiarch/strncpy-power9.S +new file mode 100644 +index 0000000000..2b57c190f5 +--- /dev/null ++++ b/sysdeps/powerpc/powerpc64/multiarch/strncpy-power9.S +@@ -0,0 +1,32 @@ ++/* Optimized strncpy implementation for POWER9 LE. ++ 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 ++ . */ ++ ++#if defined __LITTLE_ENDIAN__ && IS_IN (libc) ++# define STRNCPY __strncpy_power9 ++ ++# undef libc_hidden_builtin_def ++# define libc_hidden_builtin_def(name) ++ ++/* memset is used to pad the end of the string. */ ++# define MEMSET __memset_power8 ++# ifdef SHARED ++# define MEMSET_is_local ++# endif ++ ++# include ++#endif +diff --git a/sysdeps/powerpc/powerpc64/multiarch/strncpy.c b/sysdeps/powerpc/powerpc64/multiarch/strncpy.c +index 7bacf28aca..af8b6cdd9c 100644 +--- a/sysdeps/powerpc/powerpc64/multiarch/strncpy.c ++++ b/sysdeps/powerpc/powerpc64/multiarch/strncpy.c +@@ -28,11 +28,19 @@ + extern __typeof (strncpy) __strncpy_ppc attribute_hidden; + extern __typeof (strncpy) __strncpy_power7 attribute_hidden; + extern __typeof (strncpy) __strncpy_power8 attribute_hidden; ++# ifdef __LITTLE_ENDIAN__ ++extern __typeof (strncpy) __strncpy_power9 attribute_hidden; ++# endif + # undef strncpy + + /* Avoid DWARF definition DIE on ifunc symbol so that GDB can handle + ifunc symbol properly. */ + libc_ifunc_redirected (__redirect_strncpy, strncpy, ++# ifdef __LITTLE_ENDIAN__ ++ (hwcap2 & PPC_FEATURE2_ARCH_3_00) && ++ (hwcap & PPC_FEATURE_HAS_VSX) ++ ? __strncpy_power9 : ++# endif + (hwcap2 & PPC_FEATURE2_ARCH_2_07) + ? __strncpy_power8 + : (hwcap & PPC_FEATURE_HAS_VSX) diff --git a/SOURCES/glibc-rh1918719-2.patch b/SOURCES/glibc-rh1918719-2.patch new file mode 100644 index 0000000..0a50fd5 --- /dev/null +++ b/SOURCES/glibc-rh1918719-2.patch @@ -0,0 +1,307 @@ +From 7beee7b39adeda657f45989b0635033dae25a1fd Mon Sep 17 00:00:00 2001 +From: Raphael M Zinsly +Date: Thu, 12 Nov 2020 13:12:24 -0300 +Subject: powerpc: Add optimized stpncpy for POWER9 + +Add stpncpy support into the POWER9 strncpy. + +Reviewed-by: Matheus Castanho +Reviewed-by: Tulio Magno Quites Machado Filho + +diff --git a/sysdeps/powerpc/powerpc64/le/power9/stpncpy.S b/sysdeps/powerpc/powerpc64/le/power9/stpncpy.S +new file mode 100644 +index 0000000000..81d9673d8b +--- /dev/null ++++ b/sysdeps/powerpc/powerpc64/le/power9/stpncpy.S +@@ -0,0 +1,24 @@ ++/* Optimized stpncpy implementation for POWER9 LE. ++ 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 ++ . */ ++ ++#define USE_AS_STPNCPY ++#include ++ ++weak_alias (__stpncpy, stpncpy) ++libc_hidden_def (__stpncpy) ++libc_hidden_builtin_def (stpncpy) +diff --git a/sysdeps/powerpc/powerpc64/le/power9/strncpy.S b/sysdeps/powerpc/powerpc64/le/power9/strncpy.S +index cbfc37bda3..b4ba428662 100644 +--- a/sysdeps/powerpc/powerpc64/le/power9/strncpy.S ++++ b/sysdeps/powerpc/powerpc64/le/power9/strncpy.S +@@ -18,11 +18,19 @@ + + #include + ++#ifdef USE_AS_STPNCPY ++# ifndef STPNCPY ++# define FUNC_NAME __stpncpy ++# else ++# define FUNC_NAME STPNCPY ++# endif ++#else + # ifndef STRNCPY + # define FUNC_NAME strncpy + # else + # define FUNC_NAME STRNCPY + # endif ++#endif /* !USE_AS_STPNCPY */ + + #ifndef MEMSET + /* For builds without IFUNC support, local calls should be made to internal +@@ -41,6 +49,12 @@ + + char * [r3] strncpy (char *dest [r3], const char *src [r4], size_t n [r5]) + ++ or ++ ++ char * [r3] stpncpy (char *dest [r3], const char *src [r4], size_t n [r5]) ++ ++ if USE_AS_STPNCPY is defined. ++ + The implementation can load bytes past a null terminator, but only + up to the next 16-byte aligned address, so it never crosses a page. */ + +@@ -66,7 +80,15 @@ ENTRY (FUNC_NAME, 4) + + /* Empty/1-byte string optimization */ + cmpdi r5,0 ++#ifdef USE_AS_STPNCPY ++ bgt L(cont) ++ /* Compute pointer to last byte copied into dest. */ ++ addi r3,r3,1 ++ blr ++L(cont): ++#else + beqlr ++#endif + + addi r4,r4,1 + neg r7,r4 +@@ -96,12 +118,20 @@ ENTRY (FUNC_NAME, 4) + sldi r10,r5,56 /* stxvl wants size in top 8 bits */ + stxvl 32+v0,r11,r10 /* Partial store */ + ++#ifdef USE_AS_STPNCPY ++ /* Compute pointer to last byte copied into dest. */ ++ add r3,r11,r5 ++#endif + blr + + L(null): + sldi r10,r8,56 /* stxvl wants size in top 8 bits */ + stxvl 32+v0,r11,r10 /* Partial store */ + ++#ifdef USE_AS_STPNCPY ++ /* Compute pointer to last byte copied into dest. */ ++ add r3,r11,r7 ++#endif + add r11,r11,r8 + sub r5,r5,r8 + b L(zero_padding) +@@ -185,6 +215,10 @@ L(n_tail4): + sldi r10,r5,56 /* stxvl wants size in top 8 bits */ + addi r11,r11,48 /* Offset */ + stxvl 32+v3,r11,r10 /* Partial store */ ++#ifdef USE_AS_STPNCPY ++ /* Compute pointer to last byte copied into dest. */ ++ add r3,r11,r5 ++#endif + blr + + L(prep_n_tail1): +@@ -196,6 +230,10 @@ L(prep_n_tail1): + L(n_tail1): + sldi r10,r5,56 /* stxvl wants size in top 8 bits */ + stxvl 32+v0,r11,r10 /* Partial store */ ++#ifdef USE_AS_STPNCPY ++ /* Compute pointer to last byte copied into dest. */ ++ add r3,r11,r5 ++#endif + blr + + L(prep_n_tail2): +@@ -209,6 +247,10 @@ L(n_tail2): + sldi r10,r5,56 /* stxvl wants size in top 8 bits */ + addi r11,r11,16 /* offset */ + stxvl 32+v1,r11,r10 /* Partial store */ ++#ifdef USE_AS_STPNCPY ++ /* Compute pointer to last byte copied into dest. */ ++ add r3,r11,r5 ++#endif + blr + + L(prep_n_tail3): +@@ -223,6 +265,10 @@ L(n_tail3): + sldi r10,r5,56 /* stxvl wants size in top 8 bits */ + addi r11,r11,32 /* Offset */ + stxvl 32+v2,r11,r10 /* Partial store */ ++#ifdef USE_AS_STPNCPY ++ /* Compute pointer to last byte copied into dest. */ ++ add r3,r11,r5 ++#endif + blr + + L(prep_tail1): +@@ -232,6 +278,10 @@ L(tail1): + addi r9,r8,1 /* Add null terminator */ + sldi r10,r9,56 /* stxvl wants size in top 8 bits */ + stxvl 32+v0,r11,r10 /* Partial store */ ++#ifdef USE_AS_STPNCPY ++ /* Compute pointer to last byte copied into dest. */ ++ add r3,r11,r8 ++#endif + add r11,r11,r9 + sub r5,r5,r9 + b L(zero_padding) +@@ -246,6 +296,10 @@ L(tail2): + sldi r10,r9,56 /* stxvl wants size in top 8 bits */ + addi r11,r11,16 /* offset */ + stxvl 32+v1,r11,r10 /* Partial store */ ++#ifdef USE_AS_STPNCPY ++ /* Compute pointer to last byte copied into dest. */ ++ add r3,r11,r8 ++#endif + add r11,r11,r9 + sub r5,r5,r9 + b L(zero_padding) +@@ -261,6 +315,10 @@ L(tail3): + sldi r10,r9,56 /* stxvl wants size in top 8 bits */ + addi r11,r11,32 /* offset */ + stxvl 32+v2,r11,r10 /* Partial store */ ++#ifdef USE_AS_STPNCPY ++ /* Compute pointer to last byte copied into dest. */ ++ add r3,r11,r8 ++#endif + add r11,r11,r9 + sub r5,r5,r9 + b L(zero_padding) +@@ -276,6 +334,10 @@ L(tail4): + sldi r10,r9,56 /* stxvl wants size in top 8 bits */ + addi r11,r11,48 /* offset */ + stxvl 32+v3,r11,r10 /* Partial store */ ++#ifdef USE_AS_STPNCPY ++ /* Compute pointer to last byte copied into dest. */ ++ add r3,r11,r8 ++#endif + add r11,r11,r9 + sub r5,r5,r9 + +@@ -331,7 +393,8 @@ L(zero_padding_memset): + ld r0,FRAMESIZE+16(r1) + + mr r3,r30 /* Restore the return value of strncpy, i.e.: +- dest. */ ++ dest. For stpncpy, the return value is the ++ same as return value of memset. */ + ld r30,FRAMESIZE-8(r1) /* Restore r30. */ + /* Restore the stack frame. */ + addi r1,r1,FRAMESIZE +@@ -342,3 +405,6 @@ L(zero_padding_memset): + blr + + END (FUNC_NAME) ++#ifndef USE_AS_STPNCPY ++libc_hidden_builtin_def (strncpy) ++#endif +diff --git a/sysdeps/powerpc/powerpc64/multiarch/Makefile b/sysdeps/powerpc/powerpc64/multiarch/Makefile +index cd2b47b403..f46bf50732 100644 +--- a/sysdeps/powerpc/powerpc64/multiarch/Makefile ++++ b/sysdeps/powerpc/powerpc64/multiarch/Makefile +@@ -33,7 +33,7 @@ sysdep_routines += memcpy-power8-cached memcpy-power7 memcpy-a2 memcpy-power6 \ + + ifneq (,$(filter %le,$(config-machine))) + sysdep_routines += strcmp-power9 strncmp-power9 strcpy-power9 stpcpy-power9 \ +- rawmemchr-power9 strlen-power9 strncpy-power9 ++ rawmemchr-power9 strlen-power9 strncpy-power9 stpncpy-power9 + endif + CFLAGS-strncase-power7.c += -mcpu=power7 -funroll-loops + CFLAGS-strncase_l-power7.c += -mcpu=power7 -funroll-loops +diff --git a/sysdeps/powerpc/powerpc64/multiarch/ifunc-impl-list.c b/sysdeps/powerpc/powerpc64/multiarch/ifunc-impl-list.c +index 135326c97a..8e19ebbf09 100644 +--- a/sysdeps/powerpc/powerpc64/multiarch/ifunc-impl-list.c ++++ b/sysdeps/powerpc/powerpc64/multiarch/ifunc-impl-list.c +@@ -318,6 +318,12 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + + /* Support sysdeps/powerpc/powerpc64/multiarch/stpncpy.c. */ + IFUNC_IMPL (i, name, stpncpy, ++#ifdef __LITTLE_ENDIAN__ ++ IFUNC_IMPL_ADD (array, i, stpncpy, ++ (hwcap2 & PPC_FEATURE2_ARCH_3_00) ++ && (hwcap & PPC_FEATURE_HAS_VSX), ++ __stpncpy_power9) ++#endif + IFUNC_IMPL_ADD (array, i, stpncpy, + hwcap2 & PPC_FEATURE2_ARCH_2_07, + __stpncpy_power8) +diff --git a/sysdeps/powerpc/powerpc64/multiarch/stpncpy-power9.S b/sysdeps/powerpc/powerpc64/multiarch/stpncpy-power9.S +new file mode 100644 +index 0000000000..1188bd0894 +--- /dev/null ++++ b/sysdeps/powerpc/powerpc64/multiarch/stpncpy-power9.S +@@ -0,0 +1,29 @@ ++/* Optimized stpncpy implementation for POWER9 LE. ++ 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 ++ . */ ++ ++#define STPNCPY __stpncpy_power9 ++ ++#undef libc_hidden_builtin_def ++#define libc_hidden_builtin_def(name) ++ ++#define MEMSET __memset_power8 ++#ifdef SHARED ++# define MEMSET_is_local ++#endif ++ ++#include +diff --git a/sysdeps/powerpc/powerpc64/multiarch/stpncpy.c b/sysdeps/powerpc/powerpc64/multiarch/stpncpy.c +index 17df886431..3758f29ad1 100644 +--- a/sysdeps/powerpc/powerpc64/multiarch/stpncpy.c ++++ b/sysdeps/powerpc/powerpc64/multiarch/stpncpy.c +@@ -26,10 +26,18 @@ + extern __typeof (__stpncpy) __stpncpy_ppc attribute_hidden; + extern __typeof (__stpncpy) __stpncpy_power7 attribute_hidden; + extern __typeof (__stpncpy) __stpncpy_power8 attribute_hidden; ++# ifdef __LITTLE_ENDIAN__ ++extern __typeof (__stpncpy) __stpncpy_power9 attribute_hidden; ++# endif + # undef stpncpy + # undef __stpncpy + + libc_ifunc_redirected (__redirect___stpncpy, __stpncpy, ++# ifdef __LITTLE_ENDIAN__ ++ (hwcap2 & PPC_FEATURE2_ARCH_3_00) && ++ (hwcap & PPC_FEATURE_HAS_VSX) ++ ? __stpncpy_power9 : ++# endif + (hwcap2 & PPC_FEATURE2_ARCH_2_07) + ? __stpncpy_power8 + : (hwcap & PPC_FEATURE_HAS_VSX) diff --git a/SOURCES/glibc-rh1918719-3.patch b/SOURCES/glibc-rh1918719-3.patch new file mode 100644 index 0000000..3c061fe --- /dev/null +++ b/SOURCES/glibc-rh1918719-3.patch @@ -0,0 +1,30 @@ +From 3322ecbfe29a16e74c4f584d661b0b8018bb4031 Mon Sep 17 00:00:00 2001 +From: Raphael Moreira Zinsly +Date: Mon, 14 Sep 2020 11:59:24 -0300 +Subject: [PATCH] powerpc: Protect dl_powerpc_cpu_features on INIT_ARCH() [BZ + #26615] + +dl_powerpc_cpu_features also needs to be protected by __GLRO to check +for the _rtld_global_ro realocation before accessing it. + +Reviewed-by: Tulio Magno Quites Machado Filho +--- + sysdeps/powerpc/powerpc32/power4/multiarch/init-arch.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/sysdeps/powerpc/powerpc32/power4/multiarch/init-arch.h b/sysdeps/powerpc/powerpc32/power4/multiarch/init-arch.h +index 17ddfcf528..c8fa07fadc 100644 +--- a/sysdeps/powerpc/powerpc32/power4/multiarch/init-arch.h ++++ b/sysdeps/powerpc/powerpc32/power4/multiarch/init-arch.h +@@ -38,7 +38,7 @@ + unsigned long int hwcap = __GLRO(dl_hwcap); \ + unsigned long int __attribute__((unused)) hwcap2 = __GLRO(dl_hwcap2); \ + bool __attribute__((unused)) use_cached_memopt = \ +- GLRO(dl_powerpc_cpu_features).use_cached_memopt; \ ++ __GLRO(dl_powerpc_cpu_features.use_cached_memopt); \ + if (hwcap & PPC_FEATURE_ARCH_2_06) \ + hwcap |= PPC_FEATURE_ARCH_2_05 | \ + PPC_FEATURE_POWER5_PLUS | \ +-- +2.27.0 + diff --git a/SOURCES/glibc-rh1924919.patch b/SOURCES/glibc-rh1924919.patch new file mode 100644 index 0000000..72c211a --- /dev/null +++ b/SOURCES/glibc-rh1924919.patch @@ -0,0 +1,287 @@ +commit 7d88c6142c6efc160c0ee5e4f85cde382c072888 +Author: Florian Weimer +Date: Wed Jan 27 13:36:12 2021 +0100 + + gconv: Fix assertion failure in ISO-2022-JP-3 module (bug 27256) + + The conversion loop to the internal encoding does not follow + the interface contract that __GCONV_FULL_OUTPUT is only returned + after the internal wchar_t buffer has been filled completely. This + is enforced by the first of the two asserts in iconv/skeleton.c: + + /* We must run out of output buffer space in this + rerun. */ + assert (outbuf == outerr); + assert (nstatus == __GCONV_FULL_OUTPUT); + + This commit solves this issue by queuing a second wide character + which cannot be written immediately in the state variable, like + other converters already do (e.g., BIG5-HKSCS or TSCII). + + Reported-by: Tavis Ormandy + +Conflicts: + iconvdata/Makefile + (Usual differences in backported tests.) + +diff --git a/iconvdata/Makefile b/iconvdata/Makefile +index a47a4c07cd2e3d1b..32656ad31d9b434b 100644 +--- a/iconvdata/Makefile ++++ b/iconvdata/Makefile +@@ -73,7 +73,7 @@ modules.so := $(addsuffix .so, $(modules)) + ifeq (yes,$(build-shared)) + tests = bug-iconv1 bug-iconv2 tst-loading tst-e2big tst-iconv4 bug-iconv4 \ + tst-iconv6 bug-iconv5 bug-iconv6 tst-iconv7 bug-iconv8 bug-iconv9 \ +- bug-iconv10 bug-iconv11 bug-iconv12 bug-iconv13 ++ bug-iconv10 bug-iconv11 bug-iconv12 bug-iconv13 bug-iconv14 + ifeq ($(have-thread-library),yes) + tests += bug-iconv3 + endif +@@ -316,6 +316,8 @@ $(objpfx)bug-iconv10.out: $(objpfx)gconv-modules \ + $(addprefix $(objpfx),$(modules.so)) + $(objpfx)bug-iconv12.out: $(objpfx)gconv-modules \ + $(addprefix $(objpfx),$(modules.so)) ++$(objpfx)bug-iconv14.out: $(objpfx)gconv-modules \ ++ $(addprefix $(objpfx),$(modules.so)) + + $(objpfx)iconv-test.out: run-iconv-test.sh $(objpfx)gconv-modules \ + $(addprefix $(objpfx),$(modules.so)) \ +diff --git a/iconvdata/bug-iconv14.c b/iconvdata/bug-iconv14.c +new file mode 100644 +index 0000000000000000..902f140fa949cbac +--- /dev/null ++++ b/iconvdata/bug-iconv14.c +@@ -0,0 +1,127 @@ ++/* Assertion in ISO-2022-JP-3 due to two-character sequence (bug 27256). ++ 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 ++ ++/* Use an escape sequence to return to the initial state. */ ++static void ++with_escape_sequence (void) ++{ ++ iconv_t c = iconv_open ("UTF-8", "ISO-2022-JP-3"); ++ TEST_VERIFY_EXIT (c != (iconv_t) -1); ++ ++ char in[] = "\e$(O+D\e(B"; ++ char *inbuf = in; ++ size_t inleft = strlen (in); ++ char out[3]; /* Space for one output character. */ ++ char *outbuf; ++ size_t outleft; ++ ++ outbuf = out; ++ outleft = sizeof (out); ++ TEST_COMPARE (iconv (c, &inbuf, &inleft, &outbuf, &outleft), (size_t) -1); ++ TEST_COMPARE (errno, E2BIG); ++ TEST_COMPARE (inleft, 3); ++ TEST_COMPARE (inbuf - in, strlen (in) - 3); ++ TEST_COMPARE (outleft, sizeof (out) - 2); ++ TEST_COMPARE (outbuf - out, 2); ++ TEST_COMPARE (out[0] & 0xff, 0xc3); ++ TEST_COMPARE (out[1] & 0xff, 0xa6); ++ ++ /* Return to the initial shift state, producing the pending ++ character. */ ++ outbuf = out; ++ outleft = sizeof (out); ++ TEST_COMPARE (iconv (c, &inbuf, &inleft, &outbuf, &outleft), 0); ++ TEST_COMPARE (inleft, 0); ++ TEST_COMPARE (inbuf - in, strlen (in)); ++ TEST_COMPARE (outleft, sizeof (out) - 2); ++ TEST_COMPARE (outbuf - out, 2); ++ TEST_COMPARE (out[0] & 0xff, 0xcc); ++ TEST_COMPARE (out[1] & 0xff, 0x80); ++ ++ /* Nothing should be flushed the second time. */ ++ outbuf = out; ++ outleft = sizeof (out); ++ TEST_COMPARE (iconv (c, NULL, 0, &outbuf, &outleft), 0); ++ TEST_COMPARE (outleft, sizeof (out)); ++ TEST_COMPARE (outbuf - out, 0); ++ TEST_COMPARE (out[0] & 0xff, 0xcc); ++ TEST_COMPARE (out[1] & 0xff, 0x80); ++ ++ TEST_COMPARE (iconv_close (c), 0); ++} ++ ++/* Use an explicit flush to return to the initial state. */ ++static void ++with_flush (void) ++{ ++ iconv_t c = iconv_open ("UTF-8", "ISO-2022-JP-3"); ++ TEST_VERIFY_EXIT (c != (iconv_t) -1); ++ ++ char in[] = "\e$(O+D"; ++ char *inbuf = in; ++ size_t inleft = strlen (in); ++ char out[3]; /* Space for one output character. */ ++ char *outbuf; ++ size_t outleft; ++ ++ outbuf = out; ++ outleft = sizeof (out); ++ TEST_COMPARE (iconv (c, &inbuf, &inleft, &outbuf, &outleft), (size_t) -1); ++ TEST_COMPARE (errno, E2BIG); ++ TEST_COMPARE (inleft, 0); ++ TEST_COMPARE (inbuf - in, strlen (in)); ++ TEST_COMPARE (outleft, sizeof (out) - 2); ++ TEST_COMPARE (outbuf - out, 2); ++ TEST_COMPARE (out[0] & 0xff, 0xc3); ++ TEST_COMPARE (out[1] & 0xff, 0xa6); ++ ++ /* Flush the pending character. */ ++ outbuf = out; ++ outleft = sizeof (out); ++ TEST_COMPARE (iconv (c, NULL, 0, &outbuf, &outleft), 0); ++ TEST_COMPARE (outleft, sizeof (out) - 2); ++ TEST_COMPARE (outbuf - out, 2); ++ TEST_COMPARE (out[0] & 0xff, 0xcc); ++ TEST_COMPARE (out[1] & 0xff, 0x80); ++ ++ /* Nothing should be flushed the second time. */ ++ outbuf = out; ++ outleft = sizeof (out); ++ TEST_COMPARE (iconv (c, NULL, 0, &outbuf, &outleft), 0); ++ TEST_COMPARE (outleft, sizeof (out)); ++ TEST_COMPARE (outbuf - out, 0); ++ TEST_COMPARE (out[0] & 0xff, 0xcc); ++ TEST_COMPARE (out[1] & 0xff, 0x80); ++ ++ TEST_COMPARE (iconv_close (c), 0); ++} ++ ++static int ++do_test (void) ++{ ++ with_escape_sequence (); ++ with_flush (); ++ return 0; ++} ++ ++#include +diff --git a/iconvdata/iso-2022-jp-3.c b/iconvdata/iso-2022-jp-3.c +index de259580c3f378bb..047fab8e8dfbde7e 100644 +--- a/iconvdata/iso-2022-jp-3.c ++++ b/iconvdata/iso-2022-jp-3.c +@@ -67,23 +67,34 @@ enum + CURRENT_SEL_MASK = 7 << 3 + }; + +-/* During UCS-4 to ISO-2022-JP-3 conversion, the COUNT element of the state +- also contains the last two bytes to be output, shifted by 6 bits, and a +- one-bit indicator whether they must be preceded by the shift sequence, +- in bit 22. */ ++/* During UCS-4 to ISO-2022-JP-3 conversion, the COUNT element of the ++ state also contains the last two bytes to be output, shifted by 6 ++ bits, and a one-bit indicator whether they must be preceded by the ++ shift sequence, in bit 22. During ISO-2022-JP-3 to UCS-4 ++ conversion, COUNT may also contain a non-zero pending wide ++ character, shifted by six bits. This happens for certain inputs in ++ JISX0213_1_2004_set and JISX0213_2_set if the second wide character ++ in a combining sequence cannot be written because the buffer is ++ full. */ + + /* Since this is a stateful encoding we have to provide code which resets + the output state to the initial state. This has to be done during the + flushing. */ + #define EMIT_SHIFT_TO_INIT \ +- if ((data->__statep->__count & ~7) != ASCII_set) \ ++ if (data->__statep->__count != ASCII_set) \ + { \ + if (FROM_DIRECTION) \ + { \ +- /* It's easy, we don't have to emit anything, we just reset the \ +- state for the input. */ \ +- data->__statep->__count &= 7; \ +- data->__statep->__count |= ASCII_set; \ ++ if (__glibc_likely (outbuf + 4 <= outend)) \ ++ { \ ++ /* Write out the last character. */ \ ++ *((uint32_t *) outbuf) = data->__statep->__count >> 6; \ ++ outbuf += sizeof (uint32_t); \ ++ data->__statep->__count = ASCII_set; \ ++ } \ ++ else \ ++ /* We don't have enough room in the output buffer. */ \ ++ status = __GCONV_FULL_OUTPUT; \ + } \ + else \ + { \ +@@ -151,7 +162,21 @@ enum + #define LOOPFCT FROM_LOOP + #define BODY \ + { \ +- uint32_t ch = *inptr; \ ++ uint32_t ch; \ ++ \ ++ /* Output any pending character. */ \ ++ ch = set >> 6; \ ++ if (__glibc_unlikely (ch != 0)) \ ++ { \ ++ put32 (outptr, ch); \ ++ outptr += 4; \ ++ /* Remove the pending character, but preserve state bits. */ \ ++ set &= (1 << 6) - 1; \ ++ continue; \ ++ } \ ++ \ ++ /* Otherwise read the next input byte. */ \ ++ ch = *inptr; \ + \ + /* Recognize escape sequences. */ \ + if (__glibc_unlikely (ch == ESC)) \ +@@ -297,21 +322,25 @@ enum + uint32_t u1 = __jisx0213_to_ucs_combining[ch - 1][0]; \ + uint32_t u2 = __jisx0213_to_ucs_combining[ch - 1][1]; \ + \ ++ inptr += 2; \ ++ \ ++ put32 (outptr, u1); \ ++ outptr += 4; \ ++ \ + /* See whether we have room for two characters. */ \ +- if (outptr + 8 <= outend) \ ++ if (outptr + 4 <= outend) \ + { \ +- inptr += 2; \ +- put32 (outptr, u1); \ +- outptr += 4; \ + put32 (outptr, u2); \ + outptr += 4; \ + continue; \ + } \ +- else \ +- { \ +- result = __GCONV_FULL_OUTPUT; \ +- break; \ +- } \ ++ \ ++ /* Otherwise store only the first character now, and \ ++ put the second one into the queue. */ \ ++ set |= u2 << 6; \ ++ /* Tell the caller why we terminate the loop. */ \ ++ result = __GCONV_FULL_OUTPUT; \ ++ break; \ + } \ + \ + inptr += 2; \ diff --git a/SOURCES/glibc-rh1927877.patch b/SOURCES/glibc-rh1927877.patch new file mode 100644 index 0000000..d842710 --- /dev/null +++ b/SOURCES/glibc-rh1927877.patch @@ -0,0 +1,39 @@ +commit dca565886b5e8bd7966e15f0ca42ee5cff686673 +Author: DJ Delorie +Date: Thu Feb 25 16:08:21 2021 -0500 + + nscd: Fix double free in netgroupcache [BZ #27462] + + In commit 745664bd798ec8fd50438605948eea594179fba1 a use-after-free + was fixed, but this led to an occasional double-free. This patch + tracks the "live" allocation better. + + Tested manually by a third party. + + Related: RHBZ 1927877 + + Reviewed-by: Siddhesh Poyarekar + Reviewed-by: Carlos O'Donell + +diff --git a/nscd/netgroupcache.c b/nscd/netgroupcache.c +index f521df824102bbca..5ee4413ef9384ec9 100644 +--- a/nscd/netgroupcache.c ++++ b/nscd/netgroupcache.c +@@ -248,7 +248,7 @@ addgetnetgrentX (struct database_dyn *db, int fd, request_header *req, + : NULL); + ndomain = (ndomain ? newbuf + ndomaindiff + : NULL); +- buffer = newbuf; ++ *tofreep = buffer = newbuf; + } + + nhost = memcpy (buffer + bufused, +@@ -319,7 +319,7 @@ addgetnetgrentX (struct database_dyn *db, int fd, request_header *req, + else if (status == NSS_STATUS_TRYAGAIN && e == ERANGE) + { + buflen *= 2; +- buffer = xrealloc (buffer, buflen); ++ *tofreep = buffer = xrealloc (buffer, buflen); + } + else if (status == NSS_STATUS_RETURN + || status == NSS_STATUS_NOTFOUND diff --git a/SOURCES/glibc-rh1929928-1.patch b/SOURCES/glibc-rh1929928-1.patch new file mode 100644 index 0000000..5e04ea2 --- /dev/null +++ b/SOURCES/glibc-rh1929928-1.patch @@ -0,0 +1,38 @@ +This patch is a downstream-only variant of this upstream commit: + +commit 45b1e17e9150dbd9ac2d578579063fbfa8e1b327 +Author: Szabolcs Nagy +Date: Thu Dec 17 10:03:05 2020 +0000 + + aarch64: use PTR_ARG and SIZE_ARG instead of DELOUSE + + DELOUSE was added to asm code to make them compatible with non-LP64 + ABIs, but it is an unfortunate name and the code was not compatible + with ABIs where pointer and size_t are different. Glibc currently + only supports the LP64 ABI so these macros are not really needed or + tested, but for now the name is changed to be more meaningful instead + of removing them completely. + + Some DELOUSE macros were dropped: clone, strlen and strnlen used it + unnecessarily. + + The out of tree ILP32 patches are currently not maintained and will + likely need a rework to rebase them on top of the time64 changes. + +Keeping the DELOUSE macro avoids the need to update all string +functions. Lack of BTI markers and architecture variants cause many +conflicts in a full upstream backport. + +diff --git a/sysdeps/aarch64/sysdep.h b/sysdeps/aarch64/sysdep.h +index 5b30709436d3acea..1bcf15d4f18586ba 100644 +--- a/sysdeps/aarch64/sysdep.h ++++ b/sysdeps/aarch64/sysdep.h +@@ -32,6 +32,8 @@ + # define PTR_LOG_SIZE 2 + # define DELOUSE(n) mov w##n, w##n + #endif ++#define PTR_ARG(n) DELOUSE(n) ++#define SIZE_ARG(n) DELOUSE(n) + + #define PTR_SIZE (1< +Date: Wed May 12 09:26:40 2021 +0000 + + config: Added HAVE_AARCH64_SVE_ASM for aarch64 + + This patch checks if assembler supports '-march=armv8.2-a+sve' to + generate SVE code or not, and then define HAVE_AARCH64_SVE_ASM macro. + +Conflicts: + config.h.in + (missing PAC+BTI support downstream, missing other ports) + +diff --git a/config.h.in b/config.h.in +index 8520b0fa8d4668fb..94d5ea367e10f849 100644 +--- a/config.h.in ++++ b/config.h.in +@@ -112,6 +112,11 @@ + /* AArch64 big endian ABI */ + #undef HAVE_AARCH64_BE + ++/* Assembler support ARMv8.2-A SVE. ++ This macro becomes obsolete when glibc increased the minimum ++ required version of GNU 'binutils' to 2.28 or later. */ ++#define HAVE_AARCH64_SVE_ASM 0 ++ + /* RISC-V integer ABI for ld.so. */ + #undef RISCV_ABI_XLEN + +diff --git a/sysdeps/aarch64/configure b/sysdeps/aarch64/configure +index f78a79338aba1e34..9fb713155d4ee6d8 100644 +--- a/sysdeps/aarch64/configure ++++ b/sysdeps/aarch64/configure +@@ -212,3 +212,31 @@ fi + $as_echo "$libc_cv_aarch64_variant_pcs" >&6; } + config_vars="$config_vars + aarch64-variant-pcs = $libc_cv_aarch64_variant_pcs" ++ ++# Check if asm support armv8.2-a+sve ++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for SVE support in assembler" >&5 ++$as_echo_n "checking for SVE support in assembler... " >&6; } ++if ${libc_cv_asm_sve+:} false; then : ++ $as_echo_n "(cached) " >&6 ++else ++ cat > conftest.s <<\EOF ++ ptrue p0.b ++EOF ++if { ac_try='${CC-cc} -c -march=armv8.2-a+sve 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; }; }; then ++ libc_cv_aarch64_sve_asm=yes ++else ++ libc_cv_aarch64_sve_asm=no ++fi ++rm -f conftest* ++fi ++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libc_cv_asm_sve" >&5 ++$as_echo "$libc_cv_asm_sve" >&6; } ++if test $libc_cv_aarch64_sve_asm = yes; then ++ $as_echo "#define HAVE_AARCH64_SVE_ASM 1" >>confdefs.h ++ ++fi +diff --git a/sysdeps/aarch64/configure.ac b/sysdeps/aarch64/configure.ac +index 7f13bfb93b60bfd7..0236cfcdf3c8d10d 100644 +--- a/sysdeps/aarch64/configure.ac ++++ b/sysdeps/aarch64/configure.ac +@@ -42,3 +42,18 @@ EOF + fi + rm -rf conftest.*]) + LIBC_CONFIG_VAR([aarch64-variant-pcs], [$libc_cv_aarch64_variant_pcs]) ++ ++# Check if asm support armv8.2-a+sve ++AC_CACHE_CHECK(for SVE support in assembler, libc_cv_asm_sve, [dnl ++cat > conftest.s <<\EOF ++ ptrue p0.b ++EOF ++if AC_TRY_COMMAND(${CC-cc} -c -march=armv8.2-a+sve conftest.s 1>&AS_MESSAGE_LOG_FD); then ++ libc_cv_aarch64_sve_asm=yes ++else ++ libc_cv_aarch64_sve_asm=no ++fi ++rm -f conftest*]) ++if test $libc_cv_aarch64_sve_asm = yes; then ++ AC_DEFINE(HAVE_AARCH64_SVE_ASM) ++fi diff --git a/SOURCES/glibc-rh1929928-3.patch b/SOURCES/glibc-rh1929928-3.patch new file mode 100644 index 0000000..76ff1a2 --- /dev/null +++ b/SOURCES/glibc-rh1929928-3.patch @@ -0,0 +1,140 @@ +commit 38560563587ad8eafa700c56800ff844f18fbad1 +Author: Naohiro Tamura +Date: Thu May 20 07:34:37 2021 +0000 + + aarch64: Added Vector Length Set test helper script + + This patch is a test helper script to change Vector Length for child + process. This script can be used as test-wrapper for 'make check'. + + Usage examples: + + ~/build$ make check subdirs=string \ + test-wrapper='~/glibc/sysdeps/unix/sysv/linux/aarch64/vltest.py 16' + + ~/build$ ~/glibc/sysdeps/unix/sysv/linux/aarch64/vltest.py 16 \ + make test t=string/test-memcpy + + ~/build$ ~/glibc/sysdeps/unix/sysv/linux/aarch64/vltest.py 32 \ + ./debugglibc.sh string/test-memmove + + ~/build$ ~/glibc/sysdeps/unix/sysv/linux/aarch64/vltest.py 64 \ + ./testrun.sh string/test-memset + +diff --git a/INSTALL b/INSTALL +index 065565093bd76d5b..b3a4370f592c5047 100644 +--- a/INSTALL ++++ b/INSTALL +@@ -387,6 +387,10 @@ the same syntax as 'test-wrapper-env', the only difference in its + semantics being starting with an empty set of environment variables + rather than the ambient set. + ++ For AArch64 with SVE, when testing the GNU C Library, 'test-wrapper' ++may be set to "SRCDIR/sysdeps/unix/sysv/linux/aarch64/vltest.py ++VECTOR-LENGTH" to change Vector Length. ++ + Installing the C Library + ======================== + +diff --git a/manual/install.texi b/manual/install.texi +index 7e9f2be150e6f98a..c262fd56d0cef67b 100644 +--- a/manual/install.texi ++++ b/manual/install.texi +@@ -425,6 +425,9 @@ use has the same syntax as @samp{test-wrapper-env}, the only + difference in its semantics being starting with an empty set of + environment variables rather than the ambient set. + ++For AArch64 with SVE, when testing @theglibc{}, @samp{test-wrapper} ++may be set to "@var{srcdir}/sysdeps/unix/sysv/linux/aarch64/vltest.py ++@var{vector-length}" to change Vector Length. + + @node Running make install + @appendixsec Installing the C Library +diff --git a/sysdeps/unix/sysv/linux/aarch64/vltest.py b/sysdeps/unix/sysv/linux/aarch64/vltest.py +new file mode 100755 +index 0000000000000000..bed62ad151e06868 +--- /dev/null ++++ b/sysdeps/unix/sysv/linux/aarch64/vltest.py +@@ -0,0 +1,82 @@ ++#!/usr/bin/python3 ++# Set Scalable Vector Length test helper ++# 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 ++# . ++"""Set Scalable Vector Length test helper. ++ ++Set Scalable Vector Length for child process. ++ ++examples: ++ ++~/build$ make check subdirs=string \ ++test-wrapper='~/glibc/sysdeps/unix/sysv/linux/aarch64/vltest.py 16' ++ ++~/build$ ~/glibc/sysdeps/unix/sysv/linux/aarch64/vltest.py 16 \ ++make test t=string/test-memcpy ++ ++~/build$ ~/glibc/sysdeps/unix/sysv/linux/aarch64/vltest.py 32 \ ++./debugglibc.sh string/test-memmove ++ ++~/build$ ~/glibc/sysdeps/unix/sysv/linux/aarch64/vltest.py 64 \ ++./testrun.sh string/test-memset ++""" ++import argparse ++from ctypes import cdll, CDLL ++import os ++import sys ++ ++EXIT_SUCCESS = 0 ++EXIT_FAILURE = 1 ++EXIT_UNSUPPORTED = 77 ++ ++AT_HWCAP = 16 ++HWCAP_SVE = (1 << 22) ++ ++PR_SVE_GET_VL = 51 ++PR_SVE_SET_VL = 50 ++PR_SVE_SET_VL_ONEXEC = (1 << 18) ++PR_SVE_VL_INHERIT = (1 << 17) ++PR_SVE_VL_LEN_MASK = 0xffff ++ ++def main(args): ++ libc = CDLL("libc.so.6") ++ if not libc.getauxval(AT_HWCAP) & HWCAP_SVE: ++ print("CPU doesn't support SVE") ++ sys.exit(EXIT_UNSUPPORTED) ++ ++ libc.prctl(PR_SVE_SET_VL, ++ args.vl[0] | PR_SVE_SET_VL_ONEXEC | PR_SVE_VL_INHERIT) ++ os.execvp(args.args[0], args.args) ++ print("exec system call failure") ++ sys.exit(EXIT_FAILURE) ++ ++if __name__ == '__main__': ++ parser = argparse.ArgumentParser(description= ++ "Set Scalable Vector Length test helper", ++ formatter_class=argparse.ArgumentDefaultsHelpFormatter) ++ ++ # positional argument ++ parser.add_argument("vl", nargs=1, type=int, ++ choices=range(16, 257, 16), ++ help=('vector length '\ ++ 'which is multiples of 16 from 16 to 256')) ++ # remainDer arguments ++ parser.add_argument('args', nargs=argparse.REMAINDER, ++ help=('args '\ ++ 'which is passed to child process')) ++ args = parser.parse_args() ++ main(args) diff --git a/SOURCES/glibc-rh1929928-4.patch b/SOURCES/glibc-rh1929928-4.patch new file mode 100644 index 0000000..f2ec8e3 --- /dev/null +++ b/SOURCES/glibc-rh1929928-4.patch @@ -0,0 +1,623 @@ +commit fa527f345cbbe852ec085932fbea979956c195b5 +Author: Naohiro Tamura +Date: Thu May 27 07:42:35 2021 +0000 + + aarch64: Added optimized memcpy and memmove for A64FX + + This patch optimizes the performance of memcpy/memmove for A64FX [1] + which implements ARMv8-A SVE and has L1 64KB cache per core and L2 8MB + cache per NUMA node. + + The performance optimization makes use of Scalable Vector Register + with several techniques such as loop unrolling, memory access + alignment, cache zero fill, and software pipelining. + + SVE assembler code for memcpy/memmove is implemented as Vector Length + Agnostic code so theoretically it can be run on any SOC which supports + ARMv8-A SVE standard. + + We confirmed that all testcases have been passed by running 'make + check' and 'make xcheck' not only on A64FX but also on ThunderX2. + + And also we confirmed that the SVE 512 bit vector register performance + is roughly 4 times better than Advanced SIMD 128 bit register and 8 + times better than scalar 64 bit register by running 'make bench'. + + [1] https://github.com/fujitsu/A64FX + + Reviewed-by: Wilco Dijkstra + Reviewed-by: Szabolcs Nagy + +Conflicts: + manual/tunables.texi + sysdeps/aarch64/multiarch/Makefile + sysdeps/aarch64/multiarch/ifunc-impl-list.c + sysdeps/aarch64/multiarch/init-arch.h + sysdeps/aarch64/multiarch/memcpy.c + sysdeps/aarch64/multiarch/memmove.c + sysdeps/unix/sysv/linux/aarch64/cpu-features.c + sysdeps/unix/sysv/linux/aarch64/cpu-features.h + (all conflicts due to missing optimizations for other CPUs) + +diff --git a/manual/tunables.texi b/manual/tunables.texi +index bd737b5d57080462..07887981748bc44b 100644 +--- a/manual/tunables.texi ++++ b/manual/tunables.texi +@@ -386,7 +386,7 @@ This tunable is specific to powerpc, powerpc64 and powerpc64le. + The @code{glibc.cpu.name=xxx} tunable allows the user to tell @theglibc{} to + assume that the CPU is @code{xxx} where xxx may have one of these values: + @code{generic}, @code{falkor}, @code{thunderxt88}, @code{thunderx2t99}, +-@code{thunderx2t99p1}. ++@code{thunderx2t99p1}, @code{a64fx}. + + This tunable is specific to aarch64. + @end deftp +diff --git a/sysdeps/aarch64/multiarch/Makefile b/sysdeps/aarch64/multiarch/Makefile +index 57ffdf72382c0a44..5a19ba0308e80983 100644 +--- a/sysdeps/aarch64/multiarch/Makefile ++++ b/sysdeps/aarch64/multiarch/Makefile +@@ -1,4 +1,5 @@ + ifeq ($(subdir),string) + sysdep_routines += memcpy_generic memcpy_thunderx memcpy_thunderx2 \ +- memcpy_falkor memmove_falkor memset_generic memset_falkor ++ memcpy_falkor memcpy_a64fx \ ++ memmove_falkor memset_generic memset_falkor + endif +diff --git a/sysdeps/aarch64/multiarch/ifunc-impl-list.c b/sysdeps/aarch64/multiarch/ifunc-impl-list.c +index e55be80103b948a2..f53db12acce37877 100644 +--- a/sysdeps/aarch64/multiarch/ifunc-impl-list.c ++++ b/sysdeps/aarch64/multiarch/ifunc-impl-list.c +@@ -25,7 +25,7 @@ + #include + + /* Maximum number of IFUNC implementations. */ +-#define MAX_IFUNC 4 ++#define MAX_IFUNC 7 + + size_t + __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, +@@ -42,10 +42,16 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + IFUNC_IMPL_ADD (array, i, memcpy, 1, __memcpy_thunderx) + IFUNC_IMPL_ADD (array, i, memcpy, 1, __memcpy_thunderx2) + IFUNC_IMPL_ADD (array, i, memcpy, 1, __memcpy_falkor) ++#if HAVE_AARCH64_SVE_ASM ++ IFUNC_IMPL_ADD (array, i, memcpy, sve, __memcpy_a64fx) ++#endif + IFUNC_IMPL_ADD (array, i, memcpy, 1, __memcpy_generic)) + IFUNC_IMPL (i, name, memmove, + IFUNC_IMPL_ADD (array, i, memmove, 1, __memmove_thunderx) + IFUNC_IMPL_ADD (array, i, memmove, 1, __memmove_falkor) ++#if HAVE_AARCH64_SVE_ASM ++ IFUNC_IMPL_ADD (array, i, memmove, sve, __memmove_a64fx) ++#endif + IFUNC_IMPL_ADD (array, i, memmove, 1, __memmove_generic)) + IFUNC_IMPL (i, name, memset, + /* Enable this on non-falkor processors too so that other cores +diff --git a/sysdeps/aarch64/multiarch/init-arch.h b/sysdeps/aarch64/multiarch/init-arch.h +index d1e5703cb25fdcff..65dc8f82ff23c754 100644 +--- a/sysdeps/aarch64/multiarch/init-arch.h ++++ b/sysdeps/aarch64/multiarch/init-arch.h +@@ -22,4 +22,6 @@ + uint64_t __attribute__((unused)) midr = \ + GLRO(dl_aarch64_cpu_features).midr_el1; \ + unsigned __attribute__((unused)) zva_size = \ +- GLRO(dl_aarch64_cpu_features).zva_size; ++ GLRO(dl_aarch64_cpu_features).zva_size; \ ++ bool __attribute__((unused)) sve = \ ++ GLRO(dl_aarch64_cpu_features).sve; +diff --git a/sysdeps/aarch64/multiarch/memcpy.c b/sysdeps/aarch64/multiarch/memcpy.c +index 4a04a63b0fe0c84b..e0313c42e82a7b86 100644 +--- a/sysdeps/aarch64/multiarch/memcpy.c ++++ b/sysdeps/aarch64/multiarch/memcpy.c +@@ -32,6 +32,9 @@ extern __typeof (__redirect_memcpy) __memcpy_generic attribute_hidden; + extern __typeof (__redirect_memcpy) __memcpy_thunderx attribute_hidden; + extern __typeof (__redirect_memcpy) __memcpy_thunderx2 attribute_hidden; + extern __typeof (__redirect_memcpy) __memcpy_falkor attribute_hidden; ++# if HAVE_AARCH64_SVE_ASM ++extern __typeof (__redirect_memcpy) __memcpy_a64fx attribute_hidden; ++# endif + + libc_ifunc (__libc_memcpy, + (IS_THUNDERX (midr) +@@ -40,8 +43,13 @@ libc_ifunc (__libc_memcpy, + ? __memcpy_falkor + : (IS_THUNDERX2 (midr) || IS_THUNDERX2PA (midr) + ? __memcpy_thunderx2 ++# if HAVE_AARCH64_SVE_ASM ++ : (IS_A64FX (midr) ++ ? __memcpy_a64fx ++ : __memcpy_generic))))); ++# else + : __memcpy_generic)))); +- ++# endif + # undef memcpy + strong_alias (__libc_memcpy, memcpy); + #endif +diff --git a/sysdeps/aarch64/multiarch/memcpy_a64fx.S b/sysdeps/aarch64/multiarch/memcpy_a64fx.S +new file mode 100644 +index 0000000000000000..65528405bb123737 +--- /dev/null ++++ b/sysdeps/aarch64/multiarch/memcpy_a64fx.S +@@ -0,0 +1,406 @@ ++/* Optimized memcpy for Fujitsu A64FX processor. ++ 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 ++ ++/* Assumptions: ++ * ++ * ARMv8.2-a, AArch64, unaligned accesses, sve ++ * ++ */ ++ ++#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 ++ ++#if HAVE_AARCH64_SVE_ASM ++# if IS_IN (libc) ++# define MEMCPY __memcpy_a64fx ++# define MEMMOVE __memmove_a64fx ++ ++ .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] ++ .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] ++ .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] ++ .endm ++ ++ .macro stld1b_unroll8 ++ stld1b_unroll4a ++ stld1b_unroll4b ++ .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] ++ .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 ++ ++ENTRY (MEMCPY) ++ ++ PTR_ARG (0) ++ 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) ++ ld1b_unroll8 ++ add src_ptr, src_ptr, tmp1 ++ sub rest, rest, tmp1 ++ cmp rest, tmp1 ++ b.cc 2f ++ .p2align 3 ++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 ++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] ++ 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] ++ 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) ++ ++END (MEMCPY) ++libc_hidden_builtin_def (MEMCPY) ++ ++ ++ENTRY (MEMMOVE) ++ ++ 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 ++ 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 ++ 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 ++ stld1b_unroll8 ++ sub rest, rest, tmp1 ++ cmp rest, tmp1 ++ b.ge 1b ++2: sub dest_ptr, dest_ptr, tmp1 ++ st1b_unroll8 ++ ++L(bwd_last): ++ mov dest_ptr, dest ++ mov src_ptr, src ++ b L(last) ++ ++END (MEMMOVE) ++libc_hidden_builtin_def (MEMMOVE) ++# endif /* IS_IN (libc) */ ++#endif /* HAVE_AARCH64_SVE_ASM */ +diff --git a/sysdeps/aarch64/multiarch/memmove.c b/sysdeps/aarch64/multiarch/memmove.c +index e69d8162910b938e..d96612b9cf7c3a4e 100644 +--- a/sysdeps/aarch64/multiarch/memmove.c ++++ b/sysdeps/aarch64/multiarch/memmove.c +@@ -31,14 +31,22 @@ extern __typeof (__redirect_memmove) __libc_memmove; + extern __typeof (__redirect_memmove) __memmove_generic attribute_hidden; + extern __typeof (__redirect_memmove) __memmove_thunderx attribute_hidden; + extern __typeof (__redirect_memmove) __memmove_falkor attribute_hidden; ++# if HAVE_AARCH64_SVE_ASM ++extern __typeof (__redirect_memmove) __memmove_a64fx attribute_hidden; ++# endif + + libc_ifunc (__libc_memmove, + (IS_THUNDERX (midr) + ? __memmove_thunderx + : (IS_FALKOR (midr) || IS_PHECDA (midr) + ? __memmove_falkor ++# if HAVE_AARCH64_SVE_ASM ++ : (IS_A64FX (midr) ++ ? __memmove_a64fx ++ : __memmove_generic)))); ++# else + : __memmove_generic))); +- ++# endif + # undef memmove + strong_alias (__libc_memmove, memmove); + #endif +diff --git a/sysdeps/unix/sysv/linux/aarch64/cpu-features.c b/sysdeps/unix/sysv/linux/aarch64/cpu-features.c +index b4f348509eb1c6b3..71e4355c972f1ffb 100644 +--- a/sysdeps/unix/sysv/linux/aarch64/cpu-features.c ++++ b/sysdeps/unix/sysv/linux/aarch64/cpu-features.c +@@ -36,6 +36,7 @@ static struct cpu_list cpu_list[] = { + {"thunderx2t99", 0x431F0AF0}, + {"thunderx2t99p1", 0x420F5160}, + {"phecda", 0x680F0000}, ++ {"a64fx", 0x460F0010}, + {"generic", 0x0} + }; + +@@ -80,4 +81,7 @@ init_cpu_features (struct cpu_features *cpu_features) + + if ((dczid & DCZID_DZP_MASK) == 0) + cpu_features->zva_size = 4 << (dczid & DCZID_BS_MASK); ++ ++ /* Check if SVE is supported. */ ++ cpu_features->sve = GLRO (dl_hwcap) & HWCAP_SVE; + } +diff --git a/sysdeps/unix/sysv/linux/aarch64/cpu-features.h b/sysdeps/unix/sysv/linux/aarch64/cpu-features.h +index eb35adfbe9d429d5..5691aea6de3cb7f4 100644 +--- a/sysdeps/unix/sysv/linux/aarch64/cpu-features.h ++++ b/sysdeps/unix/sysv/linux/aarch64/cpu-features.h +@@ -20,6 +20,7 @@ + #define _CPU_FEATURES_AARCH64_H + + #include ++#include + + #define MIDR_PARTNUM_SHIFT 4 + #define MIDR_PARTNUM_MASK (0xfff << MIDR_PARTNUM_SHIFT) +@@ -52,10 +53,14 @@ + #define IS_PHECDA(midr) (MIDR_IMPLEMENTOR(midr) == 'h' \ + && MIDR_PARTNUM(midr) == 0x000) + ++#define IS_A64FX(midr) (MIDR_IMPLEMENTOR(midr) == 'F' \ ++ && MIDR_PARTNUM(midr) == 0x001) ++ + struct cpu_features + { + uint64_t midr_el1; + unsigned zva_size; ++ bool sve; + }; + + #endif /* _CPU_FEATURES_AARCH64_H */ diff --git a/SOURCES/glibc-rh1929928-5.patch b/SOURCES/glibc-rh1929928-5.patch new file mode 100644 index 0000000..7b5da7d --- /dev/null +++ b/SOURCES/glibc-rh1929928-5.patch @@ -0,0 +1,371 @@ +commit 4f26956d5ba394eb3ade6c1c20b5c16864a00766 +Author: Naohiro Tamura +Date: Thu May 27 07:44:12 2021 +0000 + + aarch64: Added optimized memset for A64FX + + This patch optimizes the performance of memset for A64FX [1] which + implements ARMv8-A SVE and has L1 64KB cache per core and L2 8MB cache + per NUMA node. + + The performance optimization makes use of Scalable Vector Register + with several techniques such as loop unrolling, memory access + alignment, cache zero fill and prefetch. + + SVE assembler code for memset is implemented as Vector Length Agnostic + code so theoretically it can be run on any SOC which supports ARMv8-A + SVE standard. + + We confirmed that all testcases have been passed by running 'make + check' and 'make xcheck' not only on A64FX but also on ThunderX2. + + And also we confirmed that the SVE 512 bit vector register performance + is roughly 4 times better than Advanced SIMD 128 bit register and 8 + times better than scalar 64 bit register by running 'make bench'. + + [1] https://github.com/fujitsu/A64FX + + Reviewed-by: Wilco Dijkstra + Reviewed-by: Szabolcs Nagy + +Conflicts: + sysdeps/aarch64/multiarch/Makefile + sysdeps/aarch64/multiarch/ifunc-impl-list.c + sysdeps/aarch64/multiarch/memset.c + (all conflicts due to missing other CPU implementations downstream) + +diff --git a/sysdeps/aarch64/multiarch/Makefile b/sysdeps/aarch64/multiarch/Makefile +index 5a19ba0308e80983..5ff883a8ad8e3067 100644 +--- a/sysdeps/aarch64/multiarch/Makefile ++++ b/sysdeps/aarch64/multiarch/Makefile +@@ -1,5 +1,6 @@ + ifeq ($(subdir),string) + sysdep_routines += memcpy_generic memcpy_thunderx memcpy_thunderx2 \ + memcpy_falkor memcpy_a64fx \ +- memmove_falkor memset_generic memset_falkor ++ memmove_falkor memset_generic memset_falkor \ ++ memset_a64fx + endif +diff --git a/sysdeps/aarch64/multiarch/ifunc-impl-list.c b/sysdeps/aarch64/multiarch/ifunc-impl-list.c +index f53db12acce37877..53e3e162a1025e40 100644 +--- a/sysdeps/aarch64/multiarch/ifunc-impl-list.c ++++ b/sysdeps/aarch64/multiarch/ifunc-impl-list.c +@@ -37,7 +37,7 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + + INIT_ARCH (); + +- /* Support sysdeps/aarch64/multiarch/memcpy.c and memmove.c. */ ++ /* Support sysdeps/aarch64/multiarch/memcpy.c, memmove.c and memset.c. */ + IFUNC_IMPL (i, name, memcpy, + IFUNC_IMPL_ADD (array, i, memcpy, 1, __memcpy_thunderx) + IFUNC_IMPL_ADD (array, i, memcpy, 1, __memcpy_thunderx2) +@@ -57,6 +57,9 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + /* Enable this on non-falkor processors too so that other cores + can do a comparative analysis with __memset_generic. */ + IFUNC_IMPL_ADD (array, i, memset, (zva_size == 64), __memset_falkor) ++#if HAVE_AARCH64_SVE_ASM ++ IFUNC_IMPL_ADD (array, i, memset, sve, __memset_a64fx) ++#endif + IFUNC_IMPL_ADD (array, i, memset, 1, __memset_generic)) + + return i; +diff --git a/sysdeps/aarch64/multiarch/memset.c b/sysdeps/aarch64/multiarch/memset.c +index d74ed3a549a54b10..2c8cc72bb0b18474 100644 +--- a/sysdeps/aarch64/multiarch/memset.c ++++ b/sysdeps/aarch64/multiarch/memset.c +@@ -29,12 +29,21 @@ + extern __typeof (__redirect_memset) __libc_memset; + + extern __typeof (__redirect_memset) __memset_falkor attribute_hidden; ++# if HAVE_AARCH64_SVE_ASM ++extern __typeof (__redirect_memset) __memset_a64fx attribute_hidden; ++# endif + extern __typeof (__redirect_memset) __memset_generic attribute_hidden; + + libc_ifunc (__libc_memset, + ((IS_FALKOR (midr) || IS_PHECDA (midr)) && zva_size == 64 + ? __memset_falkor ++# if HAVE_AARCH64_SVE_ASM ++ : (IS_A64FX (midr) ++ ? __memset_a64fx ++ : __memset_generic))); ++# else + : __memset_generic)); ++# endif + + # undef memset + strong_alias (__libc_memset, memset); +diff --git a/sysdeps/aarch64/multiarch/memset_a64fx.S b/sysdeps/aarch64/multiarch/memset_a64fx.S +new file mode 100644 +index 0000000000000000..ce54e5418b08c8bc +--- /dev/null ++++ b/sysdeps/aarch64/multiarch/memset_a64fx.S +@@ -0,0 +1,268 @@ ++/* Optimized memset for Fujitsu A64FX processor. ++ 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 ++ ++/* Assumptions: ++ * ++ * ARMv8.2-a, AArch64, unaligned accesses, sve ++ * ++ */ ++ ++#define L1_SIZE (64*1024) // L1 64KB ++#define L2_SIZE (8*1024*1024) // L2 8MB - 1MB ++#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 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) ++# define MEMSET __memset_a64fx ++ ++ .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 ++ 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) ++ ++ 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 ++ ++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) ++ ++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 ++ .p2align 3 ++1: cmp rest, tmp1 ++ b.cc L(last) ++ st1b_unroll ++ add dst, dst, tmp1 ++ sub rest, rest, tmp1 ++ 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] ++ ret ++ ++L(L1_prefetch): // if rest >= L1_SIZE ++ .p2align 3 ++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(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 ++ .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 ++ ++END (MEMSET) ++libc_hidden_builtin_def (MEMSET) ++ ++#endif /* IS_IN (libc) */ ++#endif /* HAVE_AARCH64_SVE_ASM */ diff --git a/SOURCES/glibc-rh1930302-1.patch b/SOURCES/glibc-rh1930302-1.patch new file mode 100644 index 0000000..0c0d614 --- /dev/null +++ b/SOURCES/glibc-rh1930302-1.patch @@ -0,0 +1,25 @@ +commit dc91a19e6f71e1523f4ac179191a29b2131d74bb +Author: Joseph Myers +Date: Mon Jun 3 11:16:02 2019 +0000 + + Add INADDR_ALLSNOOPERS_GROUP from Linux 5.1 to netinet/in.h. + + This patch adds INADDR_ALLSNOOPERS_GROUP from Linux 5.1 to + netinet/in.h. + + Tested for x86_64. + + * inet/netinet/in.h (INADDR_ALLSNOOPERS_GROUP): New macro. + +diff --git a/inet/netinet/in.h b/inet/netinet/in.h +index 03a31b634c8bfbed..c2d12a04aab6c022 100644 +--- a/inet/netinet/in.h ++++ b/inet/netinet/in.h +@@ -204,6 +204,7 @@ enum + #define INADDR_UNSPEC_GROUP ((in_addr_t) 0xe0000000) /* 224.0.0.0 */ + #define INADDR_ALLHOSTS_GROUP ((in_addr_t) 0xe0000001) /* 224.0.0.1 */ + #define INADDR_ALLRTRS_GROUP ((in_addr_t) 0xe0000002) /* 224.0.0.2 */ ++#define INADDR_ALLSNOOPERS_GROUP ((in_addr_t) 0xe000006a) /* 224.0.0.106 */ + #define INADDR_MAX_LOCAL_GROUP ((in_addr_t) 0xe00000ff) /* 224.0.0.255 */ + + #if !__USE_KERNEL_IPV6_DEFS diff --git a/SOURCES/glibc-rh1930302-2.patch b/SOURCES/glibc-rh1930302-2.patch new file mode 100644 index 0000000..a0b75ad --- /dev/null +++ b/SOURCES/glibc-rh1930302-2.patch @@ -0,0 +1,28 @@ +commit f9ac84f92f151e07586c55e14ed628d493a5929d +Author: Joseph Myers +Date: Fri Apr 3 18:08:28 2020 +0000 + + Add IPPROTO_ETHERNET and IPPROTO_MPTCP from Linux 5.6 to netinet/in.h. + + This patch adds the IPPROTO_ETHERNET and IPPROTO_MPTCP constants from + Linux 5.6 to glibc's netinet/in.h. + + Tested for x86_64. + +diff --git a/inet/netinet/in.h b/inet/netinet/in.h +index c2d12a04aab6c022..5880e909ff3e06fb 100644 +--- a/inet/netinet/in.h ++++ b/inet/netinet/in.h +@@ -87,8 +87,12 @@ enum + #define IPPROTO_UDPLITE IPPROTO_UDPLITE + IPPROTO_MPLS = 137, /* MPLS in IP. */ + #define IPPROTO_MPLS IPPROTO_MPLS ++ IPPROTO_ETHERNET = 143, /* Ethernet-within-IPv6 Encapsulation. */ ++#define IPPROTO_ETHERNET IPPROTO_ETHERNET + IPPROTO_RAW = 255, /* Raw IP packets. */ + #define IPPROTO_RAW IPPROTO_RAW ++ IPPROTO_MPTCP = 262, /* Multipath TCP connection. */ ++#define IPPROTO_MPTCP IPPROTO_MPTCP + IPPROTO_MAX + }; + diff --git a/SOURCES/glibc-rh1932770.patch b/SOURCES/glibc-rh1932770.patch new file mode 100644 index 0000000..4960631 --- /dev/null +++ b/SOURCES/glibc-rh1932770.patch @@ -0,0 +1,177 @@ +This is a custom downstream RHEL 8 patch which rebuilds three +GLIBC_PRIVATE interfaces locally for use by libnss_files.so.2 +and libnss_compat.so.2. + +The shared objects needs the following 3 functions: +__nss_readline +__nss_parse_line_result +__nss_files_fopen (only requirement for libnss_compat.so.2) + +They are implemented in: +nss/nss_parse_line_result.c +nss/nss_readline.c +nss/nss_files_fopen.c + +We create wrappers for those functions, recompile, and link directly +into the shared objects: +nss/nss_parse_line_result_int.c +nss/nss_readline_int.c +nss/nss_files_fopen_int.c + +After building the new shared objects there are no longer any undefined +global function references to __nss_readline@GLIBC_PRIVATE, +__nss_parse_line_result@GLIBC_PRIVATE or +__nss_files_fopen@GLIBC_PRIVATE. + +Instead we see local function definitions in the shared object e.g. +Symbol table '.symtab' contains 628 entries: +... + 486: 0000000000008ce0 92 FUNC LOCAL DEFAULT 15 __nss_parse_line_result +... + 494: 0000000000008b70 72 FUNC LOCAL DEFAULT 15 __nss_readline_seek +... + 497: 0000000000008bc0 279 FUNC LOCAL DEFAULT 15 __nss_readline +... + 510: 0000000000008ce0 82 FUNC LOCAL DEFAULT 15 __nss_files_fopen + +The remaining GLIBC_PRIVATE references in the shared objects are all +pre-existing and do not impact upgrade scenarios. + +For reference the existing and present GLIBC_PRIVATE interfaces are: +__libc_alloc_buffer_alloc_array@@GLIBC_PRIVATE +__libc_alloc_buffer_copy_string@@GLIBC_PRIVATE +__libc_alloc_buffer_create_failure@@GLIBC_PRIVATE +__libc_dynarray_emplace_enlarge@@GLIBC_PRIVATE +__libc_scratch_buffer_grow@@GLIBC_PRIVATE +__resp@@GLIBC_PRIVATE +_nss_files_parse_grent@@GLIBC_PRIVATE +_nss_files_parse_pwent@@GLIBC_PRIVATE +_nss_files_parse_sgent@@GLIBC_PRIVATE +_nss_files_parse_spent@@GLIBC_PRIVATE +errno@@GLIBC_PRIVATE +__nss_database_lookup2@GLIBC_PRIVATE +__nss_lookup_function@GLIBC_PRIVATE + +Each was checked for existence in libc.so.6. + +A small reproducer was used in testing this patch, included here: +cat >> tst-rhbz1927040.c < +#include +#include +#include +#include +#include + +int +main (void) +{ + struct passwd *res; + + /* Only lookup via files. */ + printf ("INFO: Upgrade glibc, then press ENTER to see if libnss_files.so.2 loads."); + getchar (); + + /* Try to get one entry. */ + printf ("INFO: Looking up first password entry.\n"); + setpwent (); + errno = 0; + res = getpwent (); + if (res == NULL && errno != 0) + { + printf ("FAIL: Could not get entry (%s).\n", strerror(errno)); + exit (1); + } + printf ("INFO: First entry passwd.pw_name = \"%s\"\n", res->pw_name); + printf ("PASS: Call to getpwent succeeded.\n"); + endpwent (); + exit (0); +} +EOF + +Testing RHEL upgrade +from: glibc-2.28-127.el8_3.2 +to: glibc-2.28-148.el8 + +./tst-rhbz1927040 +INFO: Upgrade glibc, then press ENTER to see if libnss_files.so.2 loads. +INFO: Looking up first password entry. +INFO: Result was NULL. +PASS: Call to getpwent succeeded. + +With LD_DEBUG=all you can observe: + 22697: /lib64/libnss_files.so.2: error: symbol lookup error: undefined symbol: __nss_files_fopen, version GLIBC_PRIVATE (fatal) + +Which is the indication that the upgrade caused the transient IdM lookup failure. + +Running again succeeds: +INFO: Upgrade glibc, then press ENTER to see if libnss_files.so.2 loads. +INFO: Looking up first password entry. +INFO: First entry passwd.pw_name = "root" +PASS: Call to getpwent succeeded. + +diff --git a/nss/Makefile b/nss/Makefile +index 7359da38feb65618..d5c28a6b5ed3661c 100644 +--- a/nss/Makefile ++++ b/nss/Makefile +@@ -92,9 +92,19 @@ extra-libs-others = $(extra-libs) + subdir-dirs = $(services:%=nss_%) + vpath %.c $(subdir-dirs) ../locale/programs ../intl + +- ++# In RHEL we add nss_readline, nss_parse_line_result, and ++# nss_files_fopen to the libnss_files-routines in order to avoid the ++# case where a long running process (having never used NSS) attemps to ++# load an NSS module for the first time and that NSS module needs a ++# newer GLIBC_PRIVATE interface. In effect we must make the NSS modules ++# self-sufficient and not rely on a GLIBC_PRIVATE interface. ++# See: https://bugzilla.redhat.com/show_bug.cgi?id=1927040 ++# Note: We must recompile the objects to get the correct global symbol ++# references, which is why we have the *_int.c wrappers. + libnss_files-routines := $(addprefix files-,$(databases)) \ +- files-initgroups files-init ++ files-initgroups files-init \ ++ nss_readline_int nss_parse_line_result_int \ ++ nss_files_fopen_int + + libnss_db-dbs := $(addprefix db-,\ + $(filter-out hosts network key alias,\ +@@ -104,8 +114,10 @@ libnss_db-routines := $(libnss_db-dbs) db-open db-init hash-string + generated += $(filter-out db-alias.c db-netgrp.c, \ + $(addsuffix .c,$(libnss_db-dbs))) + ++# See note above regarding nss_files_fopen. + libnss_compat-routines := $(addprefix compat-,grp pwd spwd initgroups) \ +- nisdomain ++ nisdomain \ ++ nss_files_fopen_int + + install-others += $(inst_vardbdir)/Makefile + +diff --git a/nss/nss_files_fopen_int.c b/nss/nss_files_fopen_int.c +new file mode 100644 +index 0000000000000000..fa518084fd609b52 +--- /dev/null ++++ b/nss/nss_files_fopen_int.c +@@ -0,0 +1,3 @@ ++/* Include a local internal copy of __nss_files_fopen to make the NSS ++ module self-contained. */ ++#include +diff --git a/nss/nss_parse_line_result_int.c b/nss/nss_parse_line_result_int.c +new file mode 100644 +index 0000000000000000..bc0ee7a251743c9a +--- /dev/null ++++ b/nss/nss_parse_line_result_int.c +@@ -0,0 +1,3 @@ ++/* Include a local internal copy of __nss_parse_line_result to make the ++ NSS module self-contained. */ ++#include +diff --git a/nss/nss_readline_int.c b/nss/nss_readline_int.c +new file mode 100644 +index 0000000000000000..0e7bd259733673c9 +--- /dev/null ++++ b/nss/nss_readline_int.c +@@ -0,0 +1,3 @@ ++/* Include a local internal copy of __nss_readline and ++ __nss_readline_seek to make the NSS module self-contained. */ ++#include diff --git a/SOURCES/glibc-rh1934155-1.patch b/SOURCES/glibc-rh1934155-1.patch new file mode 100644 index 0000000..e5d5af6 --- /dev/null +++ b/SOURCES/glibc-rh1934155-1.patch @@ -0,0 +1,20 @@ +support: Pass environ to child process + +Pass environ to posix_spawn so that the child process can inherit +environment of the test. + +(cherry picked from commit e958490f8c74e660bd93c128b3bea746e268f3f6) + +diff --git a/support/support_subprocess.c b/support/support_subprocess.c +index 12c79ff6b0859877..4573350d775ac4c8 100644 +--- a/support/support_subprocess.c ++++ b/support/support_subprocess.c +@@ -84,7 +84,7 @@ support_subprogram (const char *file, char *const argv[]) + xposix_spawn_file_actions_addclose (&fa, result.stdout_pipe[1]); + xposix_spawn_file_actions_addclose (&fa, result.stderr_pipe[1]); + +- result.pid = xposix_spawn (file, &fa, NULL, argv, NULL); ++ result.pid = xposix_spawn (file, &fa, NULL, argv, environ); + + xclose (result.stdout_pipe[1]); + xclose (result.stderr_pipe[1]); diff --git a/SOURCES/glibc-rh1934155-2.patch b/SOURCES/glibc-rh1934155-2.patch new file mode 100644 index 0000000..ca842ee --- /dev/null +++ b/SOURCES/glibc-rh1934155-2.patch @@ -0,0 +1,51 @@ +support: Typo and formatting fixes + +- Add a newline to the end of error messages in transfer(). +- Fixed the name of support_subprocess_init(). + +(cherry picked from commit 95c68080a3ded882789b1629f872c3ad531efda0) + +diff --git a/support/support_capture_subprocess.c b/support/support_capture_subprocess.c +index c13b3e59ece0842e..c475e2004da3183e 100644 +--- a/support/support_capture_subprocess.c ++++ b/support/support_capture_subprocess.c +@@ -36,7 +36,7 @@ transfer (const char *what, struct pollfd *pfd, struct xmemstream *stream) + if (ret < 0) + { + support_record_failure (); +- printf ("error: reading from subprocess %s: %m", what); ++ printf ("error: reading from subprocess %s: %m\n", what); + pfd->events = 0; + pfd->revents = 0; + } +diff --git a/support/support_subprocess.c b/support/support_subprocess.c +index 4573350d775ac4c8..af01827cac81d80c 100644 +--- a/support/support_subprocess.c ++++ b/support/support_subprocess.c +@@ -27,7 +27,7 @@ + #include + + static struct support_subprocess +-support_suprocess_init (void) ++support_subprocess_init (void) + { + struct support_subprocess result; + +@@ -48,7 +48,7 @@ support_suprocess_init (void) + struct support_subprocess + support_subprocess (void (*callback) (void *), void *closure) + { +- struct support_subprocess result = support_suprocess_init (); ++ struct support_subprocess result = support_subprocess_init (); + + result.pid = xfork (); + if (result.pid == 0) +@@ -71,7 +71,7 @@ support_subprocess (void (*callback) (void *), void *closure) + struct support_subprocess + support_subprogram (const char *file, char *const argv[]) + { +- struct support_subprocess result = support_suprocess_init (); ++ struct support_subprocess result = support_subprocess_init (); + + posix_spawn_file_actions_t fa; + /* posix_spawn_file_actions_init does not fail. */ diff --git a/SOURCES/glibc-rh1934155-3.patch b/SOURCES/glibc-rh1934155-3.patch new file mode 100644 index 0000000..97ca5dd --- /dev/null +++ b/SOURCES/glibc-rh1934155-3.patch @@ -0,0 +1,447 @@ +support: Add capability to fork an sgid child + +Add a new function support_capture_subprogram_self_sgid that spawns an +sgid child of the running program with its own image and returns the +exit code of the child process. This functionality is used by at +least three tests in the testsuite at the moment, so it makes sense to +consolidate. + +There is also a new function support_subprogram_wait which should +provide simple system() like functionality that does not set up file +actions. This is useful in cases where only the return code of the +spawned subprocess is interesting. + +This patch also ports tst-secure-getenv to this new function. A +subsequent patch will port other tests. This also brings an important +change to tst-secure-getenv behaviour. Now instead of succeeding, the +test fails as UNSUPPORTED if it is unable to spawn a setgid child, +which is how it should have been in the first place. +Reviewed-by: Carlos O'Donell + +(cherry picked from commit 716a3bdc41b2b4b864dc64475015ba51e35e1273) + +diff --git a/stdlib/tst-secure-getenv.c b/stdlib/tst-secure-getenv.c +index a682b7493e41f200..156c92fea216729f 100644 +--- a/stdlib/tst-secure-getenv.c ++++ b/stdlib/tst-secure-getenv.c +@@ -30,156 +30,12 @@ + #include + #include + ++#include + #include ++#include + #include + + static char MAGIC_ARGUMENT[] = "run-actual-test"; +-#define MAGIC_STATUS 19 +- +-/* Return a GID which is not our current GID, but is present in the +- supplementary group list. */ +-static gid_t +-choose_gid (void) +-{ +- const int count = 64; +- gid_t groups[count]; +- int ret = getgroups (count, groups); +- if (ret < 0) +- { +- printf ("getgroups: %m\n"); +- exit (1); +- } +- gid_t current = getgid (); +- for (int i = 0; i < ret; ++i) +- { +- if (groups[i] != current) +- return groups[i]; +- } +- return 0; +-} +- +- +-/* Copies the executable into a restricted directory, so that we can +- safely make it SGID with the TARGET group ID. Then runs the +- executable. */ +-static int +-run_executable_sgid (gid_t target) +-{ +- char *dirname = xasprintf ("%s/secure-getenv.%jd", +- test_dir, (intmax_t) getpid ()); +- char *execname = xasprintf ("%s/bin", dirname); +- int infd = -1; +- int outfd = -1; +- int ret = -1; +- if (mkdir (dirname, 0700) < 0) +- { +- printf ("mkdir: %m\n"); +- goto err; +- } +- infd = open ("/proc/self/exe", O_RDONLY); +- if (infd < 0) +- { +- printf ("open (/proc/self/exe): %m\n"); +- goto err; +- } +- outfd = open (execname, O_WRONLY | O_CREAT | O_EXCL, 0700); +- if (outfd < 0) +- { +- printf ("open (%s): %m\n", execname); +- goto err; +- } +- char buf[4096]; +- for (;;) +- { +- ssize_t rdcount = read (infd, buf, sizeof (buf)); +- if (rdcount < 0) +- { +- printf ("read: %m\n"); +- goto err; +- } +- if (rdcount == 0) +- break; +- char *p = buf; +- char *end = buf + rdcount; +- while (p != end) +- { +- ssize_t wrcount = write (outfd, buf, end - p); +- if (wrcount == 0) +- errno = ENOSPC; +- if (wrcount <= 0) +- { +- printf ("write: %m\n"); +- goto err; +- } +- p += wrcount; +- } +- } +- if (fchown (outfd, getuid (), target) < 0) +- { +- printf ("fchown (%s): %m\n", execname); +- goto err; +- } +- if (fchmod (outfd, 02750) < 0) +- { +- printf ("fchmod (%s): %m\n", execname); +- goto err; +- } +- if (close (outfd) < 0) +- { +- printf ("close (outfd): %m\n"); +- goto err; +- } +- if (close (infd) < 0) +- { +- printf ("close (infd): %m\n"); +- goto err; +- } +- +- int kid = fork (); +- if (kid < 0) +- { +- printf ("fork: %m\n"); +- goto err; +- } +- if (kid == 0) +- { +- /* Child process. */ +- char *args[] = { execname, MAGIC_ARGUMENT, NULL }; +- execve (execname, args, environ); +- printf ("execve (%s): %m\n", execname); +- _exit (1); +- } +- int status; +- if (waitpid (kid, &status, 0) < 0) +- { +- printf ("waitpid: %m\n"); +- goto err; +- } +- if (!WIFEXITED (status) || WEXITSTATUS (status) != MAGIC_STATUS) +- { +- printf ("Unexpected exit status %d from child process\n", +- status); +- goto err; +- } +- ret = 0; +- +-err: +- if (outfd >= 0) +- close (outfd); +- if (infd >= 0) +- close (infd); +- if (execname) +- { +- unlink (execname); +- free (execname); +- } +- if (dirname) +- { +- rmdir (dirname); +- free (dirname); +- } +- return ret; +-} + + static int + do_test (void) +@@ -201,15 +57,15 @@ do_test (void) + exit (1); + } + +- gid_t target = choose_gid (); +- if (target == 0) +- { +- fprintf (stderr, +- "Could not find a suitable GID for user %jd, skipping test\n", +- (intmax_t) getuid ()); +- exit (0); +- } +- return run_executable_sgid (target); ++ int status = support_capture_subprogram_self_sgid (MAGIC_ARGUMENT); ++ ++ if (WEXITSTATUS (status) == EXIT_UNSUPPORTED) ++ return EXIT_UNSUPPORTED; ++ ++ if (!WIFEXITED (status)) ++ FAIL_EXIT1 ("Unexpected exit status %d from child process\n", status); ++ ++ return 0; + } + + static void +@@ -218,23 +74,15 @@ alternative_main (int argc, char **argv) + if (argc == 2 && strcmp (argv[1], MAGIC_ARGUMENT) == 0) + { + if (getgid () == getegid ()) +- { +- /* This can happen if the file system is mounted nosuid. */ +- fprintf (stderr, "SGID failed: GID and EGID match (%jd)\n", +- (intmax_t) getgid ()); +- exit (MAGIC_STATUS); +- } ++ /* This can happen if the file system is mounted nosuid. */ ++ FAIL_UNSUPPORTED ("SGID failed: GID and EGID match (%jd)\n", ++ (intmax_t) getgid ()); + if (getenv ("PATH") == NULL) +- { +- printf ("PATH variable not present\n"); +- exit (3); +- } ++ FAIL_EXIT (3, "PATH variable not present\n"); + if (secure_getenv ("PATH") != NULL) +- { +- printf ("PATH variable not filtered out\n"); +- exit (4); +- } +- exit (MAGIC_STATUS); ++ FAIL_EXIT (4, "PATH variable not filtered out\n"); ++ ++ exit (EXIT_SUCCESS); + } + } + +diff --git a/support/capture_subprocess.h b/support/capture_subprocess.h +index 2d2384e73df0d2d0..72fb30504684a84e 100644 +--- a/support/capture_subprocess.h ++++ b/support/capture_subprocess.h +@@ -41,6 +41,12 @@ struct support_capture_subprocess support_capture_subprocess + struct support_capture_subprocess support_capture_subprogram + (const char *file, char *const argv[]); + ++/* Copy the running program into a setgid binary and run it with CHILD_ID ++ argument. If execution is successful, return the exit status of the child ++ program, otherwise return a non-zero failure exit code. */ ++int support_capture_subprogram_self_sgid ++ (char *child_id); ++ + /* Deallocate the subprocess data captured by + support_capture_subprocess. */ + void support_capture_subprocess_free (struct support_capture_subprocess *); +diff --git a/support/subprocess.h b/support/subprocess.h +index c031878d94c70c71..a19335ee5dbfcf98 100644 +--- a/support/subprocess.h ++++ b/support/subprocess.h +@@ -38,6 +38,11 @@ struct support_subprocess support_subprocess + struct support_subprocess support_subprogram + (const char *file, char *const argv[]); + ++/* Invoke program FILE with ARGV arguments by using posix_spawn and wait for it ++ to complete. Return program exit status. */ ++int support_subprogram_wait ++ (const char *file, char *const argv[]); ++ + /* Wait for the subprocess indicated by PROC::PID. Return the status + indicate by waitpid call. */ + int support_process_wait (struct support_subprocess *proc); +diff --git a/support/support_capture_subprocess.c b/support/support_capture_subprocess.c +index c475e2004da3183e..eec5371d5602aa29 100644 +--- a/support/support_capture_subprocess.c ++++ b/support/support_capture_subprocess.c +@@ -20,11 +20,14 @@ + #include + + #include ++#include + #include + #include + #include + #include + #include ++#include ++#include + + static void + transfer (const char *what, struct pollfd *pfd, struct xmemstream *stream) +@@ -101,6 +104,129 @@ support_capture_subprogram (const char *file, char *const argv[]) + return result; + } + ++/* Copies the executable into a restricted directory, so that we can ++ safely make it SGID with the TARGET group ID. Then runs the ++ executable. */ ++static int ++copy_and_spawn_sgid (char *child_id, gid_t gid) ++{ ++ char *dirname = xasprintf ("%s/tst-tunables-setuid.%jd", ++ test_dir, (intmax_t) getpid ()); ++ char *execname = xasprintf ("%s/bin", dirname); ++ int infd = -1; ++ int outfd = -1; ++ int ret = 1, status = 1; ++ ++ TEST_VERIFY (mkdir (dirname, 0700) == 0); ++ if (support_record_failure_is_failed ()) ++ goto err; ++ ++ infd = open ("/proc/self/exe", O_RDONLY); ++ if (infd < 0) ++ FAIL_UNSUPPORTED ("unsupported: Cannot read binary from procfs\n"); ++ ++ outfd = open (execname, O_WRONLY | O_CREAT | O_EXCL, 0700); ++ TEST_VERIFY (outfd >= 0); ++ if (support_record_failure_is_failed ()) ++ goto err; ++ ++ char buf[4096]; ++ for (;;) ++ { ++ ssize_t rdcount = read (infd, buf, sizeof (buf)); ++ TEST_VERIFY (rdcount >= 0); ++ if (support_record_failure_is_failed ()) ++ goto err; ++ if (rdcount == 0) ++ break; ++ char *p = buf; ++ char *end = buf + rdcount; ++ while (p != end) ++ { ++ ssize_t wrcount = write (outfd, buf, end - p); ++ if (wrcount == 0) ++ errno = ENOSPC; ++ TEST_VERIFY (wrcount > 0); ++ if (support_record_failure_is_failed ()) ++ goto err; ++ p += wrcount; ++ } ++ } ++ TEST_VERIFY (fchown (outfd, getuid (), gid) == 0); ++ if (support_record_failure_is_failed ()) ++ goto err; ++ TEST_VERIFY (fchmod (outfd, 02750) == 0); ++ if (support_record_failure_is_failed ()) ++ goto err; ++ TEST_VERIFY (close (outfd) == 0); ++ if (support_record_failure_is_failed ()) ++ goto err; ++ TEST_VERIFY (close (infd) == 0); ++ if (support_record_failure_is_failed ()) ++ goto err; ++ ++ /* We have the binary, now spawn the subprocess. Avoid using ++ support_subprogram because we only want the program exit status, not the ++ contents. */ ++ ret = 0; ++ ++ char * const args[] = {execname, child_id, NULL}; ++ ++ status = support_subprogram_wait (args[0], args); ++ ++err: ++ if (outfd >= 0) ++ close (outfd); ++ if (infd >= 0) ++ close (infd); ++ if (execname != NULL) ++ { ++ unlink (execname); ++ free (execname); ++ } ++ if (dirname != NULL) ++ { ++ rmdir (dirname); ++ free (dirname); ++ } ++ ++ if (ret != 0) ++ FAIL_EXIT1("Failed to make sgid executable for test\n"); ++ ++ return status; ++} ++ ++int ++support_capture_subprogram_self_sgid (char *child_id) ++{ ++ gid_t target = 0; ++ const int count = 64; ++ gid_t groups[count]; ++ ++ /* Get a GID which is not our current GID, but is present in the ++ supplementary group list. */ ++ int ret = getgroups (count, groups); ++ if (ret < 0) ++ FAIL_UNSUPPORTED("Could not get group list for user %jd\n", ++ (intmax_t) getuid ()); ++ ++ gid_t current = getgid (); ++ for (int i = 0; i < ret; ++i) ++ { ++ if (groups[i] != current) ++ { ++ target = groups[i]; ++ break; ++ } ++ } ++ ++ if (target == 0) ++ FAIL_UNSUPPORTED("Could not find a suitable GID for user %jd\n", ++ (intmax_t) getuid ()); ++ ++ return copy_and_spawn_sgid (child_id, target); ++} ++ + void + support_capture_subprocess_free (struct support_capture_subprocess *p) + { +diff --git a/support/support_subprocess.c b/support/support_subprocess.c +index af01827cac81d80c..f7ee28af2531eda8 100644 +--- a/support/support_subprocess.c ++++ b/support/support_subprocess.c +@@ -92,6 +92,19 @@ support_subprogram (const char *file, char *const argv[]) + return result; + } + ++int ++support_subprogram_wait (const char *file, char *const argv[]) ++{ ++ posix_spawn_file_actions_t fa; ++ ++ posix_spawn_file_actions_init (&fa); ++ struct support_subprocess res = support_subprocess_init (); ++ ++ res.pid = xposix_spawn (file, &fa, NULL, argv, environ); ++ ++ return support_process_wait (&res); ++} ++ + int + support_process_wait (struct support_subprocess *proc) + { diff --git a/SOURCES/glibc-rh1934155-4.patch b/SOURCES/glibc-rh1934155-4.patch new file mode 100644 index 0000000..ebdebcf --- /dev/null +++ b/SOURCES/glibc-rh1934155-4.patch @@ -0,0 +1,240 @@ +tst-env-setuid: Use support_capture_subprogram_self_sgid + +Use the support_capture_subprogram_self_sgid to spawn an sgid child. +Reviewed-by: Carlos O'Donell + +(cherry picked from commit ca335281068a1ed549a75ee64f90a8310755956f) + +diff --git a/elf/tst-env-setuid.c b/elf/tst-env-setuid.c +index 183a6dd133cfa16e..eda87f9dda293e79 100644 +--- a/elf/tst-env-setuid.c ++++ b/elf/tst-env-setuid.c +@@ -29,173 +29,12 @@ + #include + #include + ++#include + #include + #include ++#include + + static char SETGID_CHILD[] = "setgid-child"; +-#define CHILD_STATUS 42 +- +-/* Return a GID which is not our current GID, but is present in the +- supplementary group list. */ +-static gid_t +-choose_gid (void) +-{ +- const int count = 64; +- gid_t groups[count]; +- int ret = getgroups (count, groups); +- if (ret < 0) +- { +- printf ("getgroups: %m\n"); +- exit (1); +- } +- gid_t current = getgid (); +- for (int i = 0; i < ret; ++i) +- { +- if (groups[i] != current) +- return groups[i]; +- } +- return 0; +-} +- +-/* Spawn and execute a program and verify that it returns the CHILD_STATUS. */ +-static pid_t +-do_execve (char **args) +-{ +- pid_t kid = vfork (); +- +- if (kid < 0) +- { +- printf ("vfork: %m\n"); +- return -1; +- } +- +- if (kid == 0) +- { +- /* Child process. */ +- execve (args[0], args, environ); +- _exit (-errno); +- } +- +- if (kid < 0) +- return 1; +- +- int status; +- +- if (waitpid (kid, &status, 0) < 0) +- { +- printf ("waitpid: %m\n"); +- return 1; +- } +- +- if (WEXITSTATUS (status) == EXIT_UNSUPPORTED) +- return EXIT_UNSUPPORTED; +- +- if (!WIFEXITED (status) || WEXITSTATUS (status) != CHILD_STATUS) +- { +- printf ("Unexpected exit status %d from child process\n", +- WEXITSTATUS (status)); +- return 1; +- } +- return 0; +-} +- +-/* Copies the executable into a restricted directory, so that we can +- safely make it SGID with the TARGET group ID. Then runs the +- executable. */ +-static int +-run_executable_sgid (gid_t target) +-{ +- char *dirname = xasprintf ("%s/tst-tunables-setuid.%jd", +- test_dir, (intmax_t) getpid ()); +- char *execname = xasprintf ("%s/bin", dirname); +- int infd = -1; +- int outfd = -1; +- int ret = 0; +- if (mkdir (dirname, 0700) < 0) +- { +- printf ("mkdir: %m\n"); +- goto err; +- } +- infd = open ("/proc/self/exe", O_RDONLY); +- if (infd < 0) +- { +- printf ("open (/proc/self/exe): %m\n"); +- goto err; +- } +- outfd = open (execname, O_WRONLY | O_CREAT | O_EXCL, 0700); +- if (outfd < 0) +- { +- printf ("open (%s): %m\n", execname); +- goto err; +- } +- char buf[4096]; +- for (;;) +- { +- ssize_t rdcount = read (infd, buf, sizeof (buf)); +- if (rdcount < 0) +- { +- printf ("read: %m\n"); +- goto err; +- } +- if (rdcount == 0) +- break; +- char *p = buf; +- char *end = buf + rdcount; +- while (p != end) +- { +- ssize_t wrcount = write (outfd, buf, end - p); +- if (wrcount == 0) +- errno = ENOSPC; +- if (wrcount <= 0) +- { +- printf ("write: %m\n"); +- goto err; +- } +- p += wrcount; +- } +- } +- if (fchown (outfd, getuid (), target) < 0) +- { +- printf ("fchown (%s): %m\n", execname); +- goto err; +- } +- if (fchmod (outfd, 02750) < 0) +- { +- printf ("fchmod (%s): %m\n", execname); +- goto err; +- } +- if (close (outfd) < 0) +- { +- printf ("close (outfd): %m\n"); +- goto err; +- } +- if (close (infd) < 0) +- { +- printf ("close (infd): %m\n"); +- goto err; +- } +- +- char *args[] = {execname, SETGID_CHILD, NULL}; +- +- ret = do_execve (args); +- +-err: +- if (outfd >= 0) +- close (outfd); +- if (infd >= 0) +- close (infd); +- if (execname) +- { +- unlink (execname); +- free (execname); +- } +- if (dirname) +- { +- rmdir (dirname); +- free (dirname); +- } +- return ret; +-} + + #ifndef test_child + static int +@@ -256,40 +95,32 @@ do_test (int argc, char **argv) + if (argc == 2 && strcmp (argv[1], SETGID_CHILD) == 0) + { + if (getgid () == getegid ()) +- { +- /* This can happen if the file system is mounted nosuid. */ +- fprintf (stderr, "SGID failed: GID and EGID match (%jd)\n", +- (intmax_t) getgid ()); +- exit (EXIT_UNSUPPORTED); +- } ++ /* This can happen if the file system is mounted nosuid. */ ++ FAIL_UNSUPPORTED ("SGID failed: GID and EGID match (%jd)\n", ++ (intmax_t) getgid ()); + + int ret = test_child (); + + if (ret != 0) + exit (1); + +- exit (CHILD_STATUS); ++ exit (EXIT_SUCCESS); + } + else + { + if (test_parent () != 0) + exit (1); + +- /* Try running a setgid program. */ +- gid_t target = choose_gid (); +- if (target == 0) +- { +- fprintf (stderr, +- "Could not find a suitable GID for user %jd, skipping test\n", +- (intmax_t) getuid ()); +- exit (0); +- } ++ int status = support_capture_subprogram_self_sgid (SETGID_CHILD); + +- return run_executable_sgid (target); +- } ++ if (WEXITSTATUS (status) == EXIT_UNSUPPORTED) ++ return EXIT_UNSUPPORTED; ++ ++ if (!WIFEXITED (status)) ++ FAIL_EXIT1 ("Unexpected exit status %d from child process\n", status); + +- /* Something went wrong and our argv was corrupted. */ +- _exit (1); ++ return 0; ++ } + } + + #define TEST_FUNCTION_ARGV do_test diff --git a/SOURCES/glibc-rh1934155-5.patch b/SOURCES/glibc-rh1934155-5.patch new file mode 100644 index 0000000..1f5dea1 --- /dev/null +++ b/SOURCES/glibc-rh1934155-5.patch @@ -0,0 +1,613 @@ +Enhance setuid-tunables test + +Instead of passing GLIBC_TUNABLES via the environment, pass the +environment variable from parent to child. This allows us to test +multiple variables to ensure better coverage. + +The test list currently only includes the case that's already being +tested. More tests will be added later. +Reviewed-by: Carlos O'Donell + +(cherry picked from commit 061fe3f8add46a89b7453e87eabb9c4695005ced) + +Also add intprops.h from 2.29 from commit 8e6fd2bdb21efe2cc1ae7571ff8fb2599db6a05a + +diff --git a/elf/Makefile b/elf/Makefile +index fc9c685b9d23bb6c..2093cefa7e73349e 100644 +--- a/elf/Makefile ++++ b/elf/Makefile +@@ -1597,8 +1597,6 @@ $(objpfx)tst-nodelete-dlclose.out: $(objpfx)tst-nodelete-dlclose-dso.so \ + + tst-env-setuid-ENV = MALLOC_CHECK_=2 MALLOC_MMAP_THRESHOLD_=4096 \ + LD_HWCAP_MASK=0x1 +-tst-env-setuid-tunables-ENV = \ +- GLIBC_TUNABLES=glibc.malloc.check=2:glibc.malloc.mmap_threshold=4096 + + $(objpfx)tst-debug1: $(libdl) + $(objpfx)tst-debug1.out: $(objpfx)tst-debug1mod1.so +diff --git a/elf/tst-env-setuid-tunables.c b/elf/tst-env-setuid-tunables.c +index d7c4f0d5742cd526..a48281b175af6920 100644 +--- a/elf/tst-env-setuid-tunables.c ++++ b/elf/tst-env-setuid-tunables.c +@@ -25,35 +25,50 @@ + #include "config.h" + #undef _LIBC + +-#define test_parent test_parent_tunables +-#define test_child test_child_tunables +- +-static int test_child_tunables (void); +-static int test_parent_tunables (void); +- +-#include "tst-env-setuid.c" ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++ ++const char *teststrings[] = ++{ ++ "glibc.malloc.check=2:glibc.malloc.mmap_threshold=4096", ++}; + +-#define CHILD_VALSTRING_VALUE "glibc.malloc.mmap_threshold=4096" +-#define PARENT_VALSTRING_VALUE \ +- "glibc.malloc.check=2:glibc.malloc.mmap_threshold=4096" ++const char *resultstrings[] = ++{ ++ "glibc.malloc.mmap_threshold=4096", ++}; + + static int +-test_child_tunables (void) ++test_child (int off) + { + const char *val = getenv ("GLIBC_TUNABLES"); + + #if HAVE_TUNABLES +- if (val != NULL && strcmp (val, CHILD_VALSTRING_VALUE) == 0) ++ if (val != NULL && strcmp (val, resultstrings[off]) == 0) + return 0; + + if (val != NULL) +- printf ("Unexpected GLIBC_TUNABLES VALUE %s\n", val); ++ printf ("[%d] Unexpected GLIBC_TUNABLES VALUE %s\n", off, val); + + return 1; + #else + if (val != NULL) + { +- printf ("GLIBC_TUNABLES not cleared\n"); ++ printf ("[%d] GLIBC_TUNABLES not cleared\n", off); + return 1; + } + return 0; +@@ -61,15 +76,48 @@ test_child_tunables (void) + } + + static int +-test_parent_tunables (void) ++do_test (int argc, char **argv) + { +- const char *val = getenv ("GLIBC_TUNABLES"); ++ /* Setgid child process. */ ++ if (argc == 2) ++ { ++ if (getgid () == getegid ()) ++ /* This can happen if the file system is mounted nosuid. */ ++ FAIL_UNSUPPORTED ("SGID failed: GID and EGID match (%jd)\n", ++ (intmax_t) getgid ()); + +- if (val != NULL && strcmp (val, PARENT_VALSTRING_VALUE) == 0) +- return 0; ++ int ret = test_child (atoi (argv[1])); + +- if (val != NULL) +- printf ("Unexpected GLIBC_TUNABLES VALUE %s\n", val); ++ if (ret != 0) ++ exit (1); + +- return 1; ++ exit (EXIT_SUCCESS); ++ } ++ else ++ { ++ int ret = 0; ++ ++ /* Spawn tests. */ ++ for (int i = 0; i < array_length (teststrings); i++) ++ { ++ char buf[INT_BUFSIZE_BOUND (int)]; ++ ++ printf ("Spawned test for %s (%d)\n", teststrings[i], i); ++ snprintf (buf, sizeof (buf), "%d\n", i); ++ if (setenv ("GLIBC_TUNABLES", teststrings[i], 1) != 0) ++ exit (1); ++ ++ int status = support_capture_subprogram_self_sgid (buf); ++ ++ /* Bail out early if unsupported. */ ++ if (WEXITSTATUS (status) == EXIT_UNSUPPORTED) ++ return EXIT_UNSUPPORTED; ++ ++ ret |= status; ++ } ++ return ret; ++ } + } ++ ++#define TEST_FUNCTION_ARGV do_test ++#include +diff --git a/include/intprops.h b/include/intprops.h +new file mode 100644 +index 0000000000000000..9702aec4c6e3c80a +--- /dev/null ++++ b/include/intprops.h +@@ -0,0 +1,455 @@ ++/* intprops.h -- properties of integer types ++ ++ Copyright (C) 2001-2018 Free Software Foundation, Inc. ++ ++ This program is free software: you can redistribute it and/or modify it ++ under the terms of the GNU Lesser General Public License as published ++ by the Free Software Foundation; either version 2.1 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public License ++ along with this program. If not, see . */ ++ ++/* Written by Paul Eggert. */ ++ ++#ifndef _GL_INTPROPS_H ++#define _GL_INTPROPS_H ++ ++#include ++ ++/* Return a value with the common real type of E and V and the value of V. ++ Do not evaluate E. */ ++#define _GL_INT_CONVERT(e, v) ((1 ? 0 : (e)) + (v)) ++ ++/* Act like _GL_INT_CONVERT (E, -V) but work around a bug in IRIX 6.5 cc; see ++ . */ ++#define _GL_INT_NEGATE_CONVERT(e, v) ((1 ? 0 : (e)) - (v)) ++ ++/* The extra casts in the following macros work around compiler bugs, ++ e.g., in Cray C 5.0.3.0. */ ++ ++/* True if the arithmetic type T is an integer type. bool counts as ++ an integer. */ ++#define TYPE_IS_INTEGER(t) ((t) 1.5 == 1) ++ ++/* True if the real type T is signed. */ ++#define TYPE_SIGNED(t) (! ((t) 0 < (t) -1)) ++ ++/* Return 1 if the real expression E, after promotion, has a ++ signed or floating type. Do not evaluate E. */ ++#define EXPR_SIGNED(e) (_GL_INT_NEGATE_CONVERT (e, 1) < 0) ++ ++ ++/* Minimum and maximum values for integer types and expressions. */ ++ ++/* The width in bits of the integer type or expression T. ++ Do not evaluate T. ++ Padding bits are not supported; this is checked at compile-time below. */ ++#define TYPE_WIDTH(t) (sizeof (t) * CHAR_BIT) ++ ++/* The maximum and minimum values for the integer type T. */ ++#define TYPE_MINIMUM(t) ((t) ~ TYPE_MAXIMUM (t)) ++#define TYPE_MAXIMUM(t) \ ++ ((t) (! TYPE_SIGNED (t) \ ++ ? (t) -1 \ ++ : ((((t) 1 << (TYPE_WIDTH (t) - 2)) - 1) * 2 + 1))) ++ ++/* The maximum and minimum values for the type of the expression E, ++ after integer promotion. E is not evaluated. */ ++#define _GL_INT_MINIMUM(e) \ ++ (EXPR_SIGNED (e) \ ++ ? ~ _GL_SIGNED_INT_MAXIMUM (e) \ ++ : _GL_INT_CONVERT (e, 0)) ++#define _GL_INT_MAXIMUM(e) \ ++ (EXPR_SIGNED (e) \ ++ ? _GL_SIGNED_INT_MAXIMUM (e) \ ++ : _GL_INT_NEGATE_CONVERT (e, 1)) ++#define _GL_SIGNED_INT_MAXIMUM(e) \ ++ (((_GL_INT_CONVERT (e, 1) << (TYPE_WIDTH ((e) + 0) - 2)) - 1) * 2 + 1) ++ ++/* Work around OpenVMS incompatibility with C99. */ ++#if !defined LLONG_MAX && defined __INT64_MAX ++# define LLONG_MAX __INT64_MAX ++# define LLONG_MIN __INT64_MIN ++#endif ++ ++/* This include file assumes that signed types are two's complement without ++ padding bits; the above macros have undefined behavior otherwise. ++ If this is a problem for you, please let us know how to fix it for your host. ++ This assumption is tested by the intprops-tests module. */ ++ ++/* Does the __typeof__ keyword work? This could be done by ++ 'configure', but for now it's easier to do it by hand. */ ++#if (2 <= __GNUC__ \ ++ || (1210 <= __IBMC__ && defined __IBM__TYPEOF__) \ ++ || (0x5110 <= __SUNPRO_C && !__STDC__)) ++# define _GL_HAVE___TYPEOF__ 1 ++#else ++# define _GL_HAVE___TYPEOF__ 0 ++#endif ++ ++/* Return 1 if the integer type or expression T might be signed. Return 0 ++ if it is definitely unsigned. This macro does not evaluate its argument, ++ and expands to an integer constant expression. */ ++#if _GL_HAVE___TYPEOF__ ++# define _GL_SIGNED_TYPE_OR_EXPR(t) TYPE_SIGNED (__typeof__ (t)) ++#else ++# define _GL_SIGNED_TYPE_OR_EXPR(t) 1 ++#endif ++ ++/* Bound on length of the string representing an unsigned integer ++ value representable in B bits. log10 (2.0) < 146/485. The ++ smallest value of B where this bound is not tight is 2621. */ ++#define INT_BITS_STRLEN_BOUND(b) (((b) * 146 + 484) / 485) ++ ++/* Bound on length of the string representing an integer type or expression T. ++ Subtract 1 for the sign bit if T is signed, and then add 1 more for ++ a minus sign if needed. ++ ++ Because _GL_SIGNED_TYPE_OR_EXPR sometimes returns 0 when its argument is ++ signed, this macro may overestimate the true bound by one byte when ++ applied to unsigned types of size 2, 4, 16, ... bytes. */ ++#define INT_STRLEN_BOUND(t) \ ++ (INT_BITS_STRLEN_BOUND (TYPE_WIDTH (t) - _GL_SIGNED_TYPE_OR_EXPR (t)) \ ++ + _GL_SIGNED_TYPE_OR_EXPR (t)) ++ ++/* Bound on buffer size needed to represent an integer type or expression T, ++ including the terminating null. */ ++#define INT_BUFSIZE_BOUND(t) (INT_STRLEN_BOUND (t) + 1) ++ ++ ++/* Range overflow checks. ++ ++ The INT__RANGE_OVERFLOW macros return 1 if the corresponding C ++ operators might not yield numerically correct answers due to ++ arithmetic overflow. They do not rely on undefined or ++ implementation-defined behavior. Their implementations are simple ++ and straightforward, but they are a bit harder to use than the ++ INT__OVERFLOW macros described below. ++ ++ Example usage: ++ ++ long int i = ...; ++ long int j = ...; ++ if (INT_MULTIPLY_RANGE_OVERFLOW (i, j, LONG_MIN, LONG_MAX)) ++ printf ("multiply would overflow"); ++ else ++ printf ("product is %ld", i * j); ++ ++ Restrictions on *_RANGE_OVERFLOW macros: ++ ++ These macros do not check for all possible numerical problems or ++ undefined or unspecified behavior: they do not check for division ++ by zero, for bad shift counts, or for shifting negative numbers. ++ ++ These macros may evaluate their arguments zero or multiple times, ++ so the arguments should not have side effects. The arithmetic ++ arguments (including the MIN and MAX arguments) must be of the same ++ integer type after the usual arithmetic conversions, and the type ++ must have minimum value MIN and maximum MAX. Unsigned types should ++ use a zero MIN of the proper type. ++ ++ These macros are tuned for constant MIN and MAX. For commutative ++ operations such as A + B, they are also tuned for constant B. */ ++ ++/* Return 1 if A + B would overflow in [MIN,MAX] arithmetic. ++ See above for restrictions. */ ++#define INT_ADD_RANGE_OVERFLOW(a, b, min, max) \ ++ ((b) < 0 \ ++ ? (a) < (min) - (b) \ ++ : (max) - (b) < (a)) ++ ++/* Return 1 if A - B would overflow in [MIN,MAX] arithmetic. ++ See above for restrictions. */ ++#define INT_SUBTRACT_RANGE_OVERFLOW(a, b, min, max) \ ++ ((b) < 0 \ ++ ? (max) + (b) < (a) \ ++ : (a) < (min) + (b)) ++ ++/* Return 1 if - A would overflow in [MIN,MAX] arithmetic. ++ See above for restrictions. */ ++#define INT_NEGATE_RANGE_OVERFLOW(a, min, max) \ ++ ((min) < 0 \ ++ ? (a) < - (max) \ ++ : 0 < (a)) ++ ++/* Return 1 if A * B would overflow in [MIN,MAX] arithmetic. ++ See above for restrictions. Avoid && and || as they tickle ++ bugs in Sun C 5.11 2010/08/13 and other compilers; see ++ . */ ++#define INT_MULTIPLY_RANGE_OVERFLOW(a, b, min, max) \ ++ ((b) < 0 \ ++ ? ((a) < 0 \ ++ ? (a) < (max) / (b) \ ++ : (b) == -1 \ ++ ? 0 \ ++ : (min) / (b) < (a)) \ ++ : (b) == 0 \ ++ ? 0 \ ++ : ((a) < 0 \ ++ ? (a) < (min) / (b) \ ++ : (max) / (b) < (a))) ++ ++/* Return 1 if A / B would overflow in [MIN,MAX] arithmetic. ++ See above for restrictions. Do not check for division by zero. */ ++#define INT_DIVIDE_RANGE_OVERFLOW(a, b, min, max) \ ++ ((min) < 0 && (b) == -1 && (a) < - (max)) ++ ++/* Return 1 if A % B would overflow in [MIN,MAX] arithmetic. ++ See above for restrictions. Do not check for division by zero. ++ Mathematically, % should never overflow, but on x86-like hosts ++ INT_MIN % -1 traps, and the C standard permits this, so treat this ++ as an overflow too. */ ++#define INT_REMAINDER_RANGE_OVERFLOW(a, b, min, max) \ ++ INT_DIVIDE_RANGE_OVERFLOW (a, b, min, max) ++ ++/* Return 1 if A << B would overflow in [MIN,MAX] arithmetic. ++ See above for restrictions. Here, MIN and MAX are for A only, and B need ++ not be of the same type as the other arguments. The C standard says that ++ behavior is undefined for shifts unless 0 <= B < wordwidth, and that when ++ A is negative then A << B has undefined behavior and A >> B has ++ implementation-defined behavior, but do not check these other ++ restrictions. */ ++#define INT_LEFT_SHIFT_RANGE_OVERFLOW(a, b, min, max) \ ++ ((a) < 0 \ ++ ? (a) < (min) >> (b) \ ++ : (max) >> (b) < (a)) ++ ++/* True if __builtin_add_overflow (A, B, P) works when P is non-null. */ ++#if 5 <= __GNUC__ && !defined __ICC ++# define _GL_HAS_BUILTIN_OVERFLOW 1 ++#else ++# define _GL_HAS_BUILTIN_OVERFLOW 0 ++#endif ++ ++/* True if __builtin_add_overflow_p (A, B, C) works. */ ++#define _GL_HAS_BUILTIN_OVERFLOW_P (7 <= __GNUC__) ++ ++/* The _GL*_OVERFLOW macros have the same restrictions as the ++ *_RANGE_OVERFLOW macros, except that they do not assume that operands ++ (e.g., A and B) have the same type as MIN and MAX. Instead, they assume ++ that the result (e.g., A + B) has that type. */ ++#if _GL_HAS_BUILTIN_OVERFLOW_P ++# define _GL_ADD_OVERFLOW(a, b, min, max) \ ++ __builtin_add_overflow_p (a, b, (__typeof__ ((a) + (b))) 0) ++# define _GL_SUBTRACT_OVERFLOW(a, b, min, max) \ ++ __builtin_sub_overflow_p (a, b, (__typeof__ ((a) - (b))) 0) ++# define _GL_MULTIPLY_OVERFLOW(a, b, min, max) \ ++ __builtin_mul_overflow_p (a, b, (__typeof__ ((a) * (b))) 0) ++#else ++# define _GL_ADD_OVERFLOW(a, b, min, max) \ ++ ((min) < 0 ? INT_ADD_RANGE_OVERFLOW (a, b, min, max) \ ++ : (a) < 0 ? (b) <= (a) + (b) \ ++ : (b) < 0 ? (a) <= (a) + (b) \ ++ : (a) + (b) < (b)) ++# define _GL_SUBTRACT_OVERFLOW(a, b, min, max) \ ++ ((min) < 0 ? INT_SUBTRACT_RANGE_OVERFLOW (a, b, min, max) \ ++ : (a) < 0 ? 1 \ ++ : (b) < 0 ? (a) - (b) <= (a) \ ++ : (a) < (b)) ++# define _GL_MULTIPLY_OVERFLOW(a, b, min, max) \ ++ (((min) == 0 && (((a) < 0 && 0 < (b)) || ((b) < 0 && 0 < (a)))) \ ++ || INT_MULTIPLY_RANGE_OVERFLOW (a, b, min, max)) ++#endif ++#define _GL_DIVIDE_OVERFLOW(a, b, min, max) \ ++ ((min) < 0 ? (b) == _GL_INT_NEGATE_CONVERT (min, 1) && (a) < - (max) \ ++ : (a) < 0 ? (b) <= (a) + (b) - 1 \ ++ : (b) < 0 && (a) + (b) <= (a)) ++#define _GL_REMAINDER_OVERFLOW(a, b, min, max) \ ++ ((min) < 0 ? (b) == _GL_INT_NEGATE_CONVERT (min, 1) && (a) < - (max) \ ++ : (a) < 0 ? (a) % (b) != ((max) - (b) + 1) % (b) \ ++ : (b) < 0 && ! _GL_UNSIGNED_NEG_MULTIPLE (a, b, max)) ++ ++/* Return a nonzero value if A is a mathematical multiple of B, where ++ A is unsigned, B is negative, and MAX is the maximum value of A's ++ type. A's type must be the same as (A % B)'s type. Normally (A % ++ -B == 0) suffices, but things get tricky if -B would overflow. */ ++#define _GL_UNSIGNED_NEG_MULTIPLE(a, b, max) \ ++ (((b) < -_GL_SIGNED_INT_MAXIMUM (b) \ ++ ? (_GL_SIGNED_INT_MAXIMUM (b) == (max) \ ++ ? (a) \ ++ : (a) % (_GL_INT_CONVERT (a, _GL_SIGNED_INT_MAXIMUM (b)) + 1)) \ ++ : (a) % - (b)) \ ++ == 0) ++ ++/* Check for integer overflow, and report low order bits of answer. ++ ++ The INT__OVERFLOW macros return 1 if the corresponding C operators ++ might not yield numerically correct answers due to arithmetic overflow. ++ The INT__WRAPV macros also store the low-order bits of the answer. ++ These macros work correctly on all known practical hosts, and do not rely ++ on undefined behavior due to signed arithmetic overflow. ++ ++ Example usage, assuming A and B are long int: ++ ++ if (INT_MULTIPLY_OVERFLOW (a, b)) ++ printf ("result would overflow\n"); ++ else ++ printf ("result is %ld (no overflow)\n", a * b); ++ ++ Example usage with WRAPV flavor: ++ ++ long int result; ++ bool overflow = INT_MULTIPLY_WRAPV (a, b, &result); ++ printf ("result is %ld (%s)\n", result, ++ overflow ? "after overflow" : "no overflow"); ++ ++ Restrictions on these macros: ++ ++ These macros do not check for all possible numerical problems or ++ undefined or unspecified behavior: they do not check for division ++ by zero, for bad shift counts, or for shifting negative numbers. ++ ++ These macros may evaluate their arguments zero or multiple times, so the ++ arguments should not have side effects. ++ ++ The WRAPV macros are not constant expressions. They support only ++ +, binary -, and *. The result type must be signed. ++ ++ These macros are tuned for their last argument being a constant. ++ ++ Return 1 if the integer expressions A * B, A - B, -A, A * B, A / B, ++ A % B, and A << B would overflow, respectively. */ ++ ++#define INT_ADD_OVERFLOW(a, b) \ ++ _GL_BINARY_OP_OVERFLOW (a, b, _GL_ADD_OVERFLOW) ++#define INT_SUBTRACT_OVERFLOW(a, b) \ ++ _GL_BINARY_OP_OVERFLOW (a, b, _GL_SUBTRACT_OVERFLOW) ++#if _GL_HAS_BUILTIN_OVERFLOW_P ++# define INT_NEGATE_OVERFLOW(a) INT_SUBTRACT_OVERFLOW (0, a) ++#else ++# define INT_NEGATE_OVERFLOW(a) \ ++ INT_NEGATE_RANGE_OVERFLOW (a, _GL_INT_MINIMUM (a), _GL_INT_MAXIMUM (a)) ++#endif ++#define INT_MULTIPLY_OVERFLOW(a, b) \ ++ _GL_BINARY_OP_OVERFLOW (a, b, _GL_MULTIPLY_OVERFLOW) ++#define INT_DIVIDE_OVERFLOW(a, b) \ ++ _GL_BINARY_OP_OVERFLOW (a, b, _GL_DIVIDE_OVERFLOW) ++#define INT_REMAINDER_OVERFLOW(a, b) \ ++ _GL_BINARY_OP_OVERFLOW (a, b, _GL_REMAINDER_OVERFLOW) ++#define INT_LEFT_SHIFT_OVERFLOW(a, b) \ ++ INT_LEFT_SHIFT_RANGE_OVERFLOW (a, b, \ ++ _GL_INT_MINIMUM (a), _GL_INT_MAXIMUM (a)) ++ ++/* Return 1 if the expression A B would overflow, ++ where OP_RESULT_OVERFLOW (A, B, MIN, MAX) does the actual test, ++ assuming MIN and MAX are the minimum and maximum for the result type. ++ Arguments should be free of side effects. */ ++#define _GL_BINARY_OP_OVERFLOW(a, b, op_result_overflow) \ ++ op_result_overflow (a, b, \ ++ _GL_INT_MINIMUM (_GL_INT_CONVERT (a, b)), \ ++ _GL_INT_MAXIMUM (_GL_INT_CONVERT (a, b))) ++ ++/* Store the low-order bits of A + B, A - B, A * B, respectively, into *R. ++ Return 1 if the result overflows. See above for restrictions. */ ++#define INT_ADD_WRAPV(a, b, r) \ ++ _GL_INT_OP_WRAPV (a, b, r, +, __builtin_add_overflow, INT_ADD_OVERFLOW) ++#define INT_SUBTRACT_WRAPV(a, b, r) \ ++ _GL_INT_OP_WRAPV (a, b, r, -, __builtin_sub_overflow, INT_SUBTRACT_OVERFLOW) ++#define INT_MULTIPLY_WRAPV(a, b, r) \ ++ _GL_INT_OP_WRAPV (a, b, r, *, __builtin_mul_overflow, INT_MULTIPLY_OVERFLOW) ++ ++/* Nonzero if this compiler has GCC bug 68193 or Clang bug 25390. See: ++ https://gcc.gnu.org/bugzilla/show_bug.cgi?id=68193 ++ https://llvm.org/bugs/show_bug.cgi?id=25390 ++ For now, assume all versions of GCC-like compilers generate bogus ++ warnings for _Generic. This matters only for older compilers that ++ lack __builtin_add_overflow. */ ++#if __GNUC__ ++# define _GL__GENERIC_BOGUS 1 ++#else ++# define _GL__GENERIC_BOGUS 0 ++#endif ++ ++/* Store the low-order bits of A B into *R, where OP specifies ++ the operation. BUILTIN is the builtin operation, and OVERFLOW the ++ overflow predicate. Return 1 if the result overflows. See above ++ for restrictions. */ ++#if _GL_HAS_BUILTIN_OVERFLOW ++# define _GL_INT_OP_WRAPV(a, b, r, op, builtin, overflow) builtin (a, b, r) ++#elif 201112 <= __STDC_VERSION__ && !_GL__GENERIC_BOGUS ++# define _GL_INT_OP_WRAPV(a, b, r, op, builtin, overflow) \ ++ (_Generic \ ++ (*(r), \ ++ signed char: \ ++ _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned int, \ ++ signed char, SCHAR_MIN, SCHAR_MAX), \ ++ short int: \ ++ _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned int, \ ++ short int, SHRT_MIN, SHRT_MAX), \ ++ int: \ ++ _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned int, \ ++ int, INT_MIN, INT_MAX), \ ++ long int: \ ++ _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned long int, \ ++ long int, LONG_MIN, LONG_MAX), \ ++ long long int: \ ++ _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned long long int, \ ++ long long int, LLONG_MIN, LLONG_MAX))) ++#else ++# define _GL_INT_OP_WRAPV(a, b, r, op, builtin, overflow) \ ++ (sizeof *(r) == sizeof (signed char) \ ++ ? _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned int, \ ++ signed char, SCHAR_MIN, SCHAR_MAX) \ ++ : sizeof *(r) == sizeof (short int) \ ++ ? _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned int, \ ++ short int, SHRT_MIN, SHRT_MAX) \ ++ : sizeof *(r) == sizeof (int) \ ++ ? _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned int, \ ++ int, INT_MIN, INT_MAX) \ ++ : _GL_INT_OP_WRAPV_LONGISH(a, b, r, op, overflow)) ++# ifdef LLONG_MAX ++# define _GL_INT_OP_WRAPV_LONGISH(a, b, r, op, overflow) \ ++ (sizeof *(r) == sizeof (long int) \ ++ ? _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned long int, \ ++ long int, LONG_MIN, LONG_MAX) \ ++ : _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned long long int, \ ++ long long int, LLONG_MIN, LLONG_MAX)) ++# else ++# define _GL_INT_OP_WRAPV_LONGISH(a, b, r, op, overflow) \ ++ _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned long int, \ ++ long int, LONG_MIN, LONG_MAX) ++# endif ++#endif ++ ++/* Store the low-order bits of A B into *R, where the operation ++ is given by OP. Use the unsigned type UT for calculation to avoid ++ overflow problems. *R's type is T, with extrema TMIN and TMAX. ++ T must be a signed integer type. Return 1 if the result overflows. */ ++#define _GL_INT_OP_CALC(a, b, r, op, overflow, ut, t, tmin, tmax) \ ++ (sizeof ((a) op (b)) < sizeof (t) \ ++ ? _GL_INT_OP_CALC1 ((t) (a), (t) (b), r, op, overflow, ut, t, tmin, tmax) \ ++ : _GL_INT_OP_CALC1 (a, b, r, op, overflow, ut, t, tmin, tmax)) ++#define _GL_INT_OP_CALC1(a, b, r, op, overflow, ut, t, tmin, tmax) \ ++ ((overflow (a, b) \ ++ || (EXPR_SIGNED ((a) op (b)) && ((a) op (b)) < (tmin)) \ ++ || (tmax) < ((a) op (b))) \ ++ ? (*(r) = _GL_INT_OP_WRAPV_VIA_UNSIGNED (a, b, op, ut, t), 1) \ ++ : (*(r) = _GL_INT_OP_WRAPV_VIA_UNSIGNED (a, b, op, ut, t), 0)) ++ ++/* Return the low-order bits of A B, where the operation is given ++ by OP. Use the unsigned type UT for calculation to avoid undefined ++ behavior on signed integer overflow, and convert the result to type T. ++ UT is at least as wide as T and is no narrower than unsigned int, ++ T is two's complement, and there is no padding or trap representations. ++ Assume that converting UT to T yields the low-order bits, as is ++ done in all known two's-complement C compilers. E.g., see: ++ https://gcc.gnu.org/onlinedocs/gcc/Integers-implementation.html ++ ++ According to the C standard, converting UT to T yields an ++ implementation-defined result or signal for values outside T's ++ range. However, code that works around this theoretical problem ++ runs afoul of a compiler bug in Oracle Studio 12.3 x86. See: ++ https://lists.gnu.org/r/bug-gnulib/2017-04/msg00049.html ++ As the compiler bug is real, don't try to work around the ++ theoretical problem. */ ++ ++#define _GL_INT_OP_WRAPV_VIA_UNSIGNED(a, b, op, ut, t) \ ++ ((t) ((ut) (a) op (ut) (b))) ++ ++#endif /* _GL_INTPROPS_H */ diff --git a/SOURCES/glibc-rh1934155-6.patch b/SOURCES/glibc-rh1934155-6.patch new file mode 100644 index 0000000..83e0ff4 --- /dev/null +++ b/SOURCES/glibc-rh1934155-6.patch @@ -0,0 +1,160 @@ +Fix SXID_ERASE behavior in setuid programs (BZ #27471) + +When parse_tunables tries to erase a tunable marked as SXID_ERASE for +setuid programs, it ends up setting the envvar string iterator +incorrectly, because of which it may parse the next tunable +incorrectly. Given that currently the implementation allows malformed +and unrecognized tunables pass through, it may even allow SXID_ERASE +tunables to go through. + +This change revamps the SXID_ERASE implementation so that: + +- Only valid tunables are written back to the tunestr string, because + of which children of SXID programs will only inherit a clean list of + identified tunables that are not SXID_ERASE. + +- Unrecognized tunables get scrubbed off from the environment and + subsequently from the child environment. + +- This has the side-effect that a tunable that is not identified by + the setxid binary, will not be passed on to a non-setxid child even + if the child could have identified that tunable. This may break + applications that expect this behaviour but expecting such tunables + to cross the SXID boundary is wrong. +Reviewed-by: Carlos O'Donell + +(cherry picked from commit 2ed18c5b534d9e92fc006202a5af0df6b72e7aca) + +diff --git a/elf/dl-tunables.c b/elf/dl-tunables.c +index 4c9d36e3980758b9..bbc3679e3564a766 100644 +--- a/elf/dl-tunables.c ++++ b/elf/dl-tunables.c +@@ -178,6 +178,7 @@ parse_tunables (char *tunestr, char *valstring) + return; + + char *p = tunestr; ++ size_t off = 0; + + while (true) + { +@@ -191,7 +192,11 @@ parse_tunables (char *tunestr, char *valstring) + /* If we reach the end of the string before getting a valid name-value + pair, bail out. */ + if (p[len] == '\0') +- return; ++ { ++ if (__libc_enable_secure) ++ tunestr[off] = '\0'; ++ return; ++ } + + /* We did not find a valid name-value pair before encountering the + colon. */ +@@ -217,35 +222,28 @@ parse_tunables (char *tunestr, char *valstring) + + if (tunable_is_name (cur->name, name)) + { +- /* If we are in a secure context (AT_SECURE) then ignore the tunable +- unless it is explicitly marked as secure. Tunable values take +- precendence over their envvar aliases. */ ++ /* If we are in a secure context (AT_SECURE) then ignore the ++ tunable unless it is explicitly marked as secure. Tunable ++ values take precedence over their envvar aliases. We write ++ the tunables that are not SXID_ERASE back to TUNESTR, thus ++ dropping all SXID_ERASE tunables and any invalid or ++ unrecognized tunables. */ + if (__libc_enable_secure) + { +- if (cur->security_level == TUNABLE_SECLEVEL_SXID_ERASE) ++ if (cur->security_level != TUNABLE_SECLEVEL_SXID_ERASE) + { +- if (p[len] == '\0') +- { +- /* Last tunable in the valstring. Null-terminate and +- return. */ +- *name = '\0'; +- return; +- } +- else +- { +- /* Remove the current tunable from the string. We do +- this by overwriting the string starting from NAME +- (which is where the current tunable begins) with +- the remainder of the string. We then have P point +- to NAME so that we continue in the correct +- position in the valstring. */ +- char *q = &p[len + 1]; +- p = name; +- while (*q != '\0') +- *name++ = *q++; +- name[0] = '\0'; +- len = 0; +- } ++ if (off > 0) ++ tunestr[off++] = ':'; ++ ++ const char *n = cur->name; ++ ++ while (*n != '\0') ++ tunestr[off++] = *n++; ++ ++ tunestr[off++] = '='; ++ ++ for (size_t j = 0; j < len; j++) ++ tunestr[off++] = value[j]; + } + + if (cur->security_level != TUNABLE_SECLEVEL_NONE) +@@ -258,9 +256,7 @@ parse_tunables (char *tunestr, char *valstring) + } + } + +- if (p[len] == '\0') +- return; +- else ++ if (p[len] != '\0') + p += len + 1; + } + } +diff --git a/elf/tst-env-setuid-tunables.c b/elf/tst-env-setuid-tunables.c +index a48281b175af6920..0b9b075c40598c6f 100644 +--- a/elf/tst-env-setuid-tunables.c ++++ b/elf/tst-env-setuid-tunables.c +@@ -45,11 +45,37 @@ + const char *teststrings[] = + { + "glibc.malloc.check=2:glibc.malloc.mmap_threshold=4096", ++ "glibc.malloc.check=2:glibc.malloc.check=2:glibc.malloc.mmap_threshold=4096", ++ "glibc.malloc.check=2:glibc.malloc.mmap_threshold=4096:glibc.malloc.check=2", ++ "glibc.malloc.perturb=0x800", ++ "glibc.malloc.perturb=0x800:glibc.malloc.mmap_threshold=4096", ++ "glibc.malloc.perturb=0x800:not_valid.malloc.check=2:glibc.malloc.mmap_threshold=4096", ++ "glibc.not_valid.check=2:glibc.malloc.mmap_threshold=4096", ++ "not_valid.malloc.check=2:glibc.malloc.mmap_threshold=4096", ++ "glibc.malloc.garbage=2:glibc.maoc.mmap_threshold=4096:glibc.malloc.check=2", ++ "glibc.malloc.check=4:glibc.malloc.garbage=2:glibc.maoc.mmap_threshold=4096", ++ ":glibc.malloc.garbage=2:glibc.malloc.check=1", ++ "glibc.malloc.check=1:glibc.malloc.check=2", ++ "not_valid.malloc.check=2", ++ "glibc.not_valid.check=2", + }; + + const char *resultstrings[] = + { + "glibc.malloc.mmap_threshold=4096", ++ "glibc.malloc.mmap_threshold=4096", ++ "glibc.malloc.mmap_threshold=4096", ++ "glibc.malloc.perturb=0x800", ++ "glibc.malloc.perturb=0x800:glibc.malloc.mmap_threshold=4096", ++ "glibc.malloc.perturb=0x800:glibc.malloc.mmap_threshold=4096", ++ "glibc.malloc.mmap_threshold=4096", ++ "glibc.malloc.mmap_threshold=4096", ++ "", ++ "", ++ "", ++ "", ++ "", ++ "", + }; + + static int diff --git a/SOURCES/glibc-rh1934162-1.patch b/SOURCES/glibc-rh1934162-1.patch new file mode 100644 index 0000000..3a50009 --- /dev/null +++ b/SOURCES/glibc-rh1934162-1.patch @@ -0,0 +1,159 @@ +From 332421312576bd7095e70589154af99b124dd2d1 Mon Sep 17 00:00:00 2001 +From: Carlos O'Donell +Date: Fri, 12 Mar 2021 16:44:47 +0100 +Subject: elf: Always set l in _dl_init_paths (bug 23462) + +After d1d5471579eb0426671bf94f2d71e61dfb204c30 ("Remove dead +DL_DST_REQ_STATIC code.") we always setup the link map l to make the +static and shared cases the same. The bug is that in elf/dl-load.c +(_dl_init_paths) we conditionally set l only in the #ifdef SHARED +case, but unconditionally use it later. The simple solution is to +remove the #ifdef SHARED conditional, because it's no longer needed, +and unconditionally setup l for both the static and shared cases. A +regression test is added to run a static binary with +LD_LIBRARY_PATH='$ORIGIN' which crashes before the fix and runs after +the fix. + +Co-Authored-By: Florian Weimer + +diff --git a/elf/Makefile b/elf/Makefile +--- a/elf/Makefile 2021-11-02 16:28:14.720143774 -0400 ++++ b/elf/Makefile 2021-11-02 18:42:38.763843571 -0400 +@@ -151,7 +151,8 @@ 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-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 +@@ -1811,3 +1812,5 @@ $(objpfx)tst-glibc-hwcaps-mask.out: \ + # Generic dependency for sysdeps implementation of + # tst-glibc-hwcaps-cache. + $(objpfx)tst-glibc-hwcaps-cache.out: $(objpfx)tst-glibc-hwcaps ++ ++tst-dst-static-ENV = LD_LIBRARY_PATH='$$ORIGIN' +diff --git a/elf/dl-load.c b/elf/dl-load.c +index 9e2089cfaa..376a2e64d6 100644 +--- a/elf/dl-load.c ++++ b/elf/dl-load.c +@@ -758,50 +758,45 @@ _dl_init_paths (const char *llp, const char *source, + max_dirnamelen = SYSTEM_DIRS_MAX_LEN; + *aelem = NULL; + +-#ifdef SHARED + /* This points to the map of the main object. */ + l = GL(dl_ns)[LM_ID_BASE]._ns_loaded; +- if (l != NULL) ++ assert (l->l_type != lt_loaded); ++ ++ if (l->l_info[DT_RUNPATH]) ++ { ++ /* Allocate room for the search path and fill in information ++ from RUNPATH. */ ++ decompose_rpath (&l->l_runpath_dirs, ++ (const void *) (D_PTR (l, l_info[DT_STRTAB]) ++ + l->l_info[DT_RUNPATH]->d_un.d_val), ++ l, "RUNPATH"); ++ /* During rtld init the memory is allocated by the stub malloc, ++ prevent any attempt to free it by the normal malloc. */ ++ l->l_runpath_dirs.malloced = 0; ++ ++ /* The RPATH is ignored. */ ++ l->l_rpath_dirs.dirs = (void *) -1; ++ } ++ else + { +- assert (l->l_type != lt_loaded); ++ l->l_runpath_dirs.dirs = (void *) -1; + +- if (l->l_info[DT_RUNPATH]) ++ if (l->l_info[DT_RPATH]) + { + /* Allocate room for the search path and fill in information +- from RUNPATH. */ +- decompose_rpath (&l->l_runpath_dirs, ++ from RPATH. */ ++ decompose_rpath (&l->l_rpath_dirs, + (const void *) (D_PTR (l, l_info[DT_STRTAB]) +- + l->l_info[DT_RUNPATH]->d_un.d_val), +- l, "RUNPATH"); +- /* During rtld init the memory is allocated by the stub malloc, +- prevent any attempt to free it by the normal malloc. */ +- l->l_runpath_dirs.malloced = 0; +- +- /* The RPATH is ignored. */ +- l->l_rpath_dirs.dirs = (void *) -1; ++ + l->l_info[DT_RPATH]->d_un.d_val), ++ l, "RPATH"); ++ /* During rtld init the memory is allocated by the stub ++ malloc, prevent any attempt to free it by the normal ++ malloc. */ ++ l->l_rpath_dirs.malloced = 0; + } + else +- { +- l->l_runpath_dirs.dirs = (void *) -1; +- +- if (l->l_info[DT_RPATH]) +- { +- /* Allocate room for the search path and fill in information +- from RPATH. */ +- decompose_rpath (&l->l_rpath_dirs, +- (const void *) (D_PTR (l, l_info[DT_STRTAB]) +- + l->l_info[DT_RPATH]->d_un.d_val), +- l, "RPATH"); +- /* During rtld init the memory is allocated by the stub +- malloc, prevent any attempt to free it by the normal +- malloc. */ +- l->l_rpath_dirs.malloced = 0; +- } +- else +- l->l_rpath_dirs.dirs = (void *) -1; +- } ++ l->l_rpath_dirs.dirs = (void *) -1; + } +-#endif /* SHARED */ + + if (llp != NULL && *llp != '\0') + { +diff --git a/elf/tst-dst-static.c b/elf/tst-dst-static.c +new file mode 100644 +index 0000000000..56eb371c96 +--- /dev/null ++++ b/elf/tst-dst-static.c +@@ -0,0 +1,32 @@ ++/* Test DST expansion for static binaries doesn't carsh. Bug 23462. ++ 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 ++ . */ ++ ++/* The purpose of this test is to exercise the code in elf/dl-loac.c ++ (_dl_init_paths) or thereabout and ensure that static binaries ++ don't crash when expanding DSTs. ++ ++ If the dynamic loader code linked into the static binary cannot ++ handle expanding the DSTs e.g. null-deref on an incomplete link ++ map, then it will crash before reaching main, so the test harness ++ is unnecessary. */ ++ ++int ++main (void) ++{ ++ return 0; ++} diff --git a/SOURCES/glibc-rh1934162-2.patch b/SOURCES/glibc-rh1934162-2.patch new file mode 100644 index 0000000..aad6dab --- /dev/null +++ b/SOURCES/glibc-rh1934162-2.patch @@ -0,0 +1,74 @@ +From 4e6db99c665d3b82a70a3e218860ef087b1555b4 Mon Sep 17 00:00:00 2001 +From: Florian Weimer +Date: Mon, 15 Mar 2021 10:33:43 +0100 +Subject: elf: ld.so --help calls _dl_init_paths without a main map [BZ #27577] + +In this case, use the link map of the dynamic loader itself as +a replacement. This is more than just a hack: if we ever support +DT_RUNPATH/DT_RPATH for the dynamic loader, reporting it for +ld.so --help (without further command line arguments) would be the +right thing to do. + +Fixes commit 332421312576bd7095e70589154af99b124dd2d1 ("elf: Always +set l in _dl_init_paths (bug 23462)"). + +diff --git a/elf/Makefile b/elf/Makefile +index 4c9e63dac9..ba4689a7fa 100644 +--- a/elf/Makefile ++++ b/elf/Makefile +@@ -231,7 +231,7 @@ 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-ldconfig-X.out $(objpfx)tst-rtld-help.out + 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 +@@ -409,7 +409,8 @@ 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-preload.out $(objpfx)argv0test.out \ ++ $(objpfx)tst-rtld-help.out + endif + tests-special += $(objpfx)check-textrel.out $(objpfx)check-execstack.out \ + $(objpfx)check-wx-segment.out \ +@@ -1814,3 +1815,16 @@ $(objpfx)list-tunables.out: tst-rtld-list-tunables.sh $(objpfx)ld.so + $(objpfx)tst-glibc-hwcaps-cache.out: $(objpfx)tst-glibc-hwcaps + + tst-dst-static-ENV = LD_LIBRARY_PATH='$$ORIGIN' ++ ++$(objpfx)tst-rtld-help.out: $(objpfx)ld.so ++ $(test-wrapper) $(rtld-prefix) --help > $@; \ ++ status=$$?; \ ++ echo "info: ld.so exit status: $$status" >> $@; \ ++ if ! grep -q 'Legacy HWCAP subdirectories under library search path directories' $@; then \ ++ echo "error: missing subdirectory pattern" >> $@; \ ++ if test $$status -eq 0; then \ ++ status=1; \ ++ fi; \ ++ fi; \ ++ (exit $$status); \ ++ $(evaluate-test) +diff --git a/elf/dl-load.c b/elf/dl-load.c +index 376a2e64d6..2f760503c5 100644 +--- a/elf/dl-load.c ++++ b/elf/dl-load.c +@@ -758,8 +758,14 @@ _dl_init_paths (const char *llp, const char *source, + max_dirnamelen = SYSTEM_DIRS_MAX_LEN; + *aelem = NULL; + +- /* This points to the map of the main object. */ ++ /* This points to the map of the main object. If there is no main ++ object (e.g., under --help, use the dynamic loader itself as a ++ stand-in. */ + l = GL(dl_ns)[LM_ID_BASE]._ns_loaded; ++#ifdef SHARED ++ if (l == NULL) ++ l = &GL (dl_rtld_map); ++#endif + assert (l->l_type != lt_loaded); + + if (l->l_info[DT_RUNPATH]) diff --git a/SOURCES/glibc-rh1936864.patch b/SOURCES/glibc-rh1936864.patch new file mode 100644 index 0000000..688a60c --- /dev/null +++ b/SOURCES/glibc-rh1936864.patch @@ -0,0 +1,28 @@ +commit 583dd860d5b833037175247230a328f0050dbfe9 +Author: Paul Eggert +Date: Mon Jan 21 11:08:13 2019 -0800 + + regex: fix read overrun [BZ #24114] + + Problem found by AddressSanitizer, reported by Hongxu Chen in: + https://debbugs.gnu.org/34140 + * posix/regexec.c (proceed_next_node): + Do not read past end of input buffer. + +diff --git a/posix/regexec.c b/posix/regexec.c +index 73644c2341336e66..06b8487c3e3eab0e 100644 +--- a/posix/regexec.c ++++ b/posix/regexec.c +@@ -1289,8 +1289,10 @@ proceed_next_node (const re_match_context_t *mctx, Idx nregs, regmatch_t *regs, + else if (naccepted) + { + char *buf = (char *) re_string_get_buffer (&mctx->input); +- if (memcmp (buf + regs[subexp_idx].rm_so, buf + *pidx, +- naccepted) != 0) ++ if (mctx->input.valid_len - *pidx < naccepted ++ || (memcmp (buf + regs[subexp_idx].rm_so, buf + *pidx, ++ naccepted) ++ != 0)) + return -1; + } + } diff --git a/SOURCES/glibc-rh1937515.patch b/SOURCES/glibc-rh1937515.patch new file mode 100644 index 0000000..1e77538 --- /dev/null +++ b/SOURCES/glibc-rh1937515.patch @@ -0,0 +1,90 @@ +Based on the following commit, adjusted for glibc-2.28 in RHEL-8: + +commit 27f74636752d0c4438cf8346cf2a76b6fcf3be16 +Author: H.J. Lu +Date: Fri Mar 19 06:15:37 2021 -0700 + + x86: Properly disable XSAVE related features [BZ #27605] + + 1. Support GLIBC_TUNABLES=glibc.cpu.hwcaps=-XSAVE. + 2. Disable all features which depend on XSAVE: + a. If OSXSAVE is disabled by glibc tunables. Or + b. If both XSAVE and XSAVEC aren't usable. + +diff --git a/sysdeps/x86/cpu-features.c b/sysdeps/x86/cpu-features.c +index 805d00a43309fc23..910425053d9e226f 100644 +--- a/sysdeps/x86/cpu-features.c ++++ b/sysdeps/x86/cpu-features.c +@@ -654,6 +654,60 @@ no_cpuid: + = TUNABLE_GET (x86_data_cache_size, long int, NULL); + cpu_features->shared_cache_size + = TUNABLE_GET (x86_shared_cache_size, long int, NULL); ++ ++ bool disable_xsave_features = false; ++ ++ if (!CPU_FEATURE_USABLE_P (cpu_features, OSXSAVE)) ++ { ++ /* These features are usable only if OSXSAVE is usable. */ ++ CPU_FEATURE_UNSET (cpu_features, XSAVE); ++ CPU_FEATURE_UNSET (cpu_features, XSAVEOPT); ++ CPU_FEATURE_UNSET (cpu_features, XSAVEC); ++ CPU_FEATURE_UNSET (cpu_features, XGETBV_ECX_1); ++ CPU_FEATURE_UNSET (cpu_features, XFD); ++ ++ disable_xsave_features = true; ++ } ++ ++ if (disable_xsave_features ++ || (!CPU_FEATURE_USABLE_P (cpu_features, XSAVE) ++ && !CPU_FEATURE_USABLE_P (cpu_features, XSAVEC))) ++ { ++ /* Clear xsave_state_size if both XSAVE and XSAVEC aren't usable. */ ++ cpu_features->xsave_state_size = 0; ++ ++ CPU_FEATURE_UNSET (cpu_features, AVX); ++ CPU_FEATURE_UNSET (cpu_features, AVX2); ++ CPU_FEATURE_UNSET (cpu_features, AVX_VNNI); ++ CPU_FEATURE_UNSET (cpu_features, FMA); ++ CPU_FEATURE_UNSET (cpu_features, VAES); ++ CPU_FEATURE_UNSET (cpu_features, VPCLMULQDQ); ++ CPU_FEATURE_UNSET (cpu_features, XOP); ++ CPU_FEATURE_UNSET (cpu_features, F16C); ++ CPU_FEATURE_UNSET (cpu_features, AVX512F); ++ CPU_FEATURE_UNSET (cpu_features, AVX512CD); ++ CPU_FEATURE_UNSET (cpu_features, AVX512ER); ++ CPU_FEATURE_UNSET (cpu_features, AVX512PF); ++ CPU_FEATURE_UNSET (cpu_features, AVX512VL); ++ CPU_FEATURE_UNSET (cpu_features, AVX512DQ); ++ CPU_FEATURE_UNSET (cpu_features, AVX512BW); ++ CPU_FEATURE_UNSET (cpu_features, AVX512_4FMAPS); ++ CPU_FEATURE_UNSET (cpu_features, AVX512_4VNNIW); ++ CPU_FEATURE_UNSET (cpu_features, AVX512_BITALG); ++ CPU_FEATURE_UNSET (cpu_features, AVX512_IFMA); ++ CPU_FEATURE_UNSET (cpu_features, AVX512_VBMI); ++ CPU_FEATURE_UNSET (cpu_features, AVX512_VBMI2); ++ CPU_FEATURE_UNSET (cpu_features, AVX512_VNNI); ++ CPU_FEATURE_UNSET (cpu_features, AVX512_VPOPCNTDQ); ++ CPU_FEATURE_UNSET (cpu_features, AVX512_VP2INTERSECT); ++ CPU_FEATURE_UNSET (cpu_features, AVX512_BF16); ++ CPU_FEATURE_UNSET (cpu_features, AVX512_FP16); ++ CPU_FEATURE_UNSET (cpu_features, AMX_BF16); ++ CPU_FEATURE_UNSET (cpu_features, AMX_TILE); ++ CPU_FEATURE_UNSET (cpu_features, AMX_INT8); ++ ++ CPU_FEATURE_UNSET (cpu_features, FMA4); ++ } + #endif + + /* Reuse dl_platform, dl_hwcap and dl_hwcap_mask for x86. */ +diff --git a/sysdeps/x86/cpu-tunables.c b/sysdeps/x86/cpu-tunables.c +index 0728023007a0f423..3173b2b959ca88f9 100644 +--- a/sysdeps/x86/cpu-tunables.c ++++ b/sysdeps/x86/cpu-tunables.c +@@ -168,6 +168,7 @@ TUNABLE_CALLBACK (set_hwcaps) (tunable_val_t *valp) + CHECK_GLIBC_IFUNC_CPU_OFF (n, cpu_features, MOVBE, 5); + CHECK_GLIBC_IFUNC_CPU_OFF (n, cpu_features, SHSTK, 5); + CHECK_GLIBC_IFUNC_CPU_OFF (n, cpu_features, SSSE3, 5); ++ CHECK_GLIBC_IFUNC_CPU_OFF (n, cpu_features, XSAVE, 5); + } + break; + case 6: diff --git a/SOURCES/glibc-rh1956357-1.patch b/SOURCES/glibc-rh1956357-1.patch new file mode 100644 index 0000000..2c4fca1 --- /dev/null +++ b/SOURCES/glibc-rh1956357-1.patch @@ -0,0 +1,100 @@ +commit 56c81132ccc6f468fa4fc29c536db060e18e9d87 +Author: Raphael Moreira Zinsly +Date: Tue Feb 23 14:14:37 2021 -0300 + + powerpc: Add optimized ilogb* for POWER9 + + The instructions xsxexpdp and xsxexpqp introduced on POWER9 extract + the exponent from a double-precision and quad-precision floating-point + respectively, thus they can be used to improve ilogb, ilogbf and ilogbf128. + +diff --git a/sysdeps/powerpc/fpu/math_private.h b/sysdeps/powerpc/fpu/math_private.h +index e642d6c8237578ea..5bbc468829062a48 100644 +--- a/sysdeps/powerpc/fpu/math_private.h ++++ b/sysdeps/powerpc/fpu/math_private.h +@@ -26,7 +26,28 @@ + + #include_next + +-#if defined _ARCH_PWR9 && __HAVE_DISTINCT_FLOAT128 ++#ifdef _ARCH_PWR9 ++ ++#if __GNUC_PREREQ (8, 0) ++# define _GL_HAS_BUILTIN_ILOGB 1 ++#elif defined __has_builtin ++# define _GL_HAS_BUILTIN_ILOGB __has_builtin (__builtin_vsx_scalar_extract_exp) ++#else ++# define _GL_HAS_BUILTIN_ILOGB 0 ++#endif ++ ++#define __builtin_test_dc_ilogbf __builtin_test_dc_ilogb ++#define __builtin_ilogbf __builtin_ilogb ++ ++#define __builtin_test_dc_ilogb(x, y) \ ++ __builtin_vsx_scalar_test_data_class_dp(x, y) ++#define __builtin_ilogb(x) __builtin_vsx_scalar_extract_exp(x) - 0x3ff ++ ++#define __builtin_test_dc_ilogbf128(x, y) \ ++ __builtin_vsx_scalar_test_data_class_qp(x, y) ++#define __builtin_ilogbf128(x) __builtin_vsx_scalar_extract_expq(x) - 0x3fff ++ ++#if __HAVE_DISTINCT_FLOAT128 + extern __always_inline _Float128 + __ieee754_sqrtf128 (_Float128 __x) + { +@@ -35,6 +56,9 @@ __ieee754_sqrtf128 (_Float128 __x) + return __z; + } + #endif ++#else /* !_ARCH_PWR9 */ ++#define _GL_HAS_BUILTIN_ILOGB 0 ++#endif + + #if defined _ARCH_PWR5X + +diff --git a/sysdeps/powerpc/powerpc64/le/fpu/w_ilogb_template.c b/sysdeps/powerpc/powerpc64/le/fpu/w_ilogb_template.c +new file mode 100644 +index 0000000000000000..b5c1c0aa9db86f3d +--- /dev/null ++++ b/sysdeps/powerpc/powerpc64/le/fpu/w_ilogb_template.c +@@ -0,0 +1,30 @@ ++#include ++#include ++#include ++#include ++#include ++ ++#if _GL_HAS_BUILTIN_ILOGB ++int ++M_DECL_FUNC (__ilogb) (FLOAT x) ++{ ++ int r; ++ /* Check for exceptional cases. */ ++ if (! M_SUF(__builtin_test_dc_ilogb) (x, 0x7f)) ++ r = M_SUF (__builtin_ilogb) (x); ++ else ++ /* Fallback to the generic ilogb if x is NaN, Inf or subnormal. */ ++ r = M_SUF (__ieee754_ilogb) (x); ++ if (__builtin_expect (r == FP_ILOGB0, 0) ++ || __builtin_expect (r == FP_ILOGBNAN, 0) ++ || __builtin_expect (r == INT_MAX, 0)) ++ { ++ __set_errno (EDOM); ++ __feraiseexcept (FE_INVALID); ++ } ++ return r; ++} ++declare_mgen_alias (__ilogb, ilogb) ++#else ++#include ++#endif +diff --git a/sysdeps/powerpc/powerpc64/le/fpu/w_ilogbl.c b/sysdeps/powerpc/powerpc64/le/fpu/w_ilogbl.c +new file mode 100644 +index 0000000000000000..205f154f0089a269 +--- /dev/null ++++ b/sysdeps/powerpc/powerpc64/le/fpu/w_ilogbl.c +@@ -0,0 +1,4 @@ ++/* Skip the optimization for long double as ibm128 does not provide an ++ optimized builtin. */ ++#include ++#include diff --git a/SOURCES/glibc-rh1956357-2.patch b/SOURCES/glibc-rh1956357-2.patch new file mode 100644 index 0000000..c1da766 --- /dev/null +++ b/SOURCES/glibc-rh1956357-2.patch @@ -0,0 +1,64 @@ +commit a7d88506c260e7a0e4268803e76fc19e38ed041f +Author: Raphael Moreira Zinsly +Date: Thu Feb 25 09:58:52 2021 -0300 + + powerpc: Add optimized llogb* for POWER9 + + The POWER9 builtins used to improve the ilogb* functions can be + used in the llogb* functions as well. + +diff --git a/sysdeps/powerpc/powerpc64/le/fpu/w_llogb_template.c b/sysdeps/powerpc/powerpc64/le/fpu/w_llogb_template.c +new file mode 100644 +index 0000000000000000..d00b71d2a34e28da +--- /dev/null ++++ b/sysdeps/powerpc/powerpc64/le/fpu/w_llogb_template.c +@@ -0,0 +1,39 @@ ++#include ++#include ++#include ++#include ++#include ++ ++#if _GL_HAS_BUILTIN_ILOGB ++long int ++M_DECL_FUNC (__llogb) (FLOAT x) ++{ ++ int r; ++ /* Check for exceptional cases. */ ++ if (! M_SUF(__builtin_test_dc_ilogb) (x, 0x7f)) ++ r = M_SUF (__builtin_ilogb) (x); ++ else ++ /* Fallback to the generic ilogb if x is NaN, Inf or subnormal. */ ++ r = M_SUF (__ieee754_ilogb) (x); ++ long int lr = r; ++ if (__glibc_unlikely (r == FP_ILOGB0) ++ || __glibc_unlikely (r == FP_ILOGBNAN) ++ || __glibc_unlikely (r == INT_MAX)) ++ { ++#if LONG_MAX != INT_MAX ++ if (r == FP_ILOGB0) ++ lr = FP_LLOGB0; ++ else if (r == FP_ILOGBNAN) ++ lr = FP_LLOGBNAN; ++ else ++ lr = LONG_MAX; ++#endif ++ __set_errno (EDOM); ++ __feraiseexcept (FE_INVALID); ++ } ++ return lr; ++} ++declare_mgen_alias (__llogb, llogb) ++#else ++#include ++#endif +diff --git a/sysdeps/powerpc/powerpc64/le/fpu/w_llogbl.c b/sysdeps/powerpc/powerpc64/le/fpu/w_llogbl.c +new file mode 100644 +index 0000000000000000..69477a37ae82c476 +--- /dev/null ++++ b/sysdeps/powerpc/powerpc64/le/fpu/w_llogbl.c +@@ -0,0 +1,4 @@ ++/* Skip the optimization for long double as ibm128 does not provide an ++ optimized builtin. */ ++#include ++#include diff --git a/SOURCES/glibc-rh1956357-3.patch b/SOURCES/glibc-rh1956357-3.patch new file mode 100644 index 0000000..6596582 --- /dev/null +++ b/SOURCES/glibc-rh1956357-3.patch @@ -0,0 +1,334 @@ +commit 10624a97e8e47004985740cbb04060a84cfada76 +Author: Matheus Castanho +Date: Tue Sep 29 15:40:08 2020 -0300 + + powerpc: Add optimized strlen for POWER10 + + Improvements compared to POWER9 version: + + 1. Take into account first 16B comparison for aligned strings + + The previous version compares the first 16B and increments r4 by the number + of bytes until the address is 16B-aligned, then starts doing aligned loads at + that address. For aligned strings, this causes the first 16B to be compared + twice, because the increment is 0. Here we calculate the next 16B-aligned + address differently, which avoids that issue. + + 2. Use simple comparisons for the first ~192 bytes + + The main loop is good for big strings, but comparing 16B each time is better + for smaller strings. So after aligning the address to 16 Bytes, we check + more 176B in 16B chunks. There may be some overlaps with the main loop for + unaligned strings, but we avoid using the more aggressive strategy too soon, + and also allow the loop to start at a 64B-aligned address. This greatly + benefits smaller strings and avoids overlapping checks if the string is + already aligned at a 64B boundary. + + 3. Reduce dependencies between load blocks caused by address calculation on loop + + Doing a precise time tracing on the code showed many loads in the loop were + stalled waiting for updates to r4 from previous code blocks. This + implementation avoids that as much as possible by using 2 registers (r4 and + r5) to hold addresses to be used by different parts of the code. + + Also, the previous code aligned the address to 16B, then to 64B by doing a + few 48B loops (if needed) until the address was aligned. The main loop could + not start until that 48B loop had finished and r4 was updated with the + current address. Here we calculate the address used by the loop very early, + so it can start sooner. + + The main loop now uses 2 pointers 128B apart to make pointer updates less + frequent, and also unrolls 1 iteration to guarantee there is enough time + between iterations to update the pointers, reducing stalled cycles. + + 4. Use new P10 instructions + + lxvp is used to load 32B with a single instruction, reducing contention in + the load queue. + + vextractbm allows simplifying the tail code for the loop, replacing + vbpermq and avoiding having to generate a permute control vector. + + Reviewed-by: Paul E Murphy + Reviewed-by: Raphael M Zinsly + Reviewed-by: Lucas A. M. Magalhaes + +diff --git a/sysdeps/powerpc/powerpc64/le/power10/strlen.S b/sysdeps/powerpc/powerpc64/le/power10/strlen.S +new file mode 100644 +index 0000000000000000..ca7e9eb3d84c9b00 +--- /dev/null ++++ b/sysdeps/powerpc/powerpc64/le/power10/strlen.S +@@ -0,0 +1,221 @@ ++/* Optimized strlen implementation for POWER10 LE. ++ 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 ++ ++#ifndef STRLEN ++# define STRLEN __strlen ++# define DEFINE_STRLEN_HIDDEN_DEF 1 ++#endif ++ ++/* TODO: Replace macros by the actual instructions when minimum binutils becomes ++ >= 2.35. This is used to keep compatibility with older versions. */ ++#define VEXTRACTBM(rt,vrb) \ ++ .long(((4)<<(32-6)) \ ++ | ((rt)<<(32-11)) \ ++ | ((8)<<(32-16)) \ ++ | ((vrb)<<(32-21)) \ ++ | 1602) ++ ++#define LXVP(xtp,dq,ra) \ ++ .long(((6)<<(32-6)) \ ++ | ((((xtp)-32)>>1)<<(32-10)) \ ++ | ((1)<<(32-11)) \ ++ | ((ra)<<(32-16)) \ ++ | dq) ++ ++#define CHECK16(vreg,offset,addr,label) \ ++ lxv vreg+32,offset(addr); \ ++ vcmpequb. vreg,vreg,v18; \ ++ bne cr6,L(label); ++ ++/* Load 4 quadwords, merge into one VR for speed and check for NULLs. r6 has # ++ of bytes already checked. */ ++#define CHECK64(offset,addr,label) \ ++ li r6,offset; \ ++ LXVP(v4+32,offset,addr); \ ++ LXVP(v6+32,offset+32,addr); \ ++ vminub v14,v4,v5; \ ++ vminub v15,v6,v7; \ ++ vminub v16,v14,v15; \ ++ vcmpequb. v0,v16,v18; \ ++ bne cr6,L(label) ++ ++#define TAIL(vreg,increment) \ ++ vctzlsbb r4,vreg; \ ++ subf r3,r3,r5; \ ++ addi r4,r4,increment; \ ++ add r3,r3,r4; \ ++ blr ++ ++/* Implements the function ++ ++ int [r3] strlen (const void *s [r3]) ++ ++ The implementation can load bytes past a matching byte, but only ++ up to the next 64B boundary, so it never crosses a page. */ ++ ++.machine power9 ++ ++ENTRY_TOCLESS (STRLEN, 4) ++ CALL_MCOUNT 1 ++ ++ vspltisb v18,0 ++ vspltisb v19,-1 ++ ++ /* Next 16B-aligned address. Prepare address for L(aligned). */ ++ addi r5,r3,16 ++ clrrdi r5,r5,4 ++ ++ /* Align data and fill bytes not loaded with non matching char. */ ++ lvx v0,0,r3 ++ lvsr v1,0,r3 ++ vperm v0,v19,v0,v1 ++ ++ vcmpequb. v6,v0,v18 ++ beq cr6,L(aligned) ++ ++ vctzlsbb r3,v6 ++ blr ++ ++ /* Test next 176B, 16B at a time. The main loop is optimized for longer ++ strings, so checking the first bytes in 16B chunks benefits a lot ++ small strings. */ ++ .p2align 5 ++L(aligned): ++ /* Prepare address for the loop. */ ++ addi r4,r3,192 ++ clrrdi r4,r4,6 ++ ++ CHECK16(v0,0,r5,tail1) ++ CHECK16(v1,16,r5,tail2) ++ CHECK16(v2,32,r5,tail3) ++ CHECK16(v3,48,r5,tail4) ++ CHECK16(v4,64,r5,tail5) ++ CHECK16(v5,80,r5,tail6) ++ CHECK16(v6,96,r5,tail7) ++ CHECK16(v7,112,r5,tail8) ++ CHECK16(v8,128,r5,tail9) ++ CHECK16(v9,144,r5,tail10) ++ CHECK16(v10,160,r5,tail11) ++ ++ addi r5,r4,128 ++ ++ /* Switch to a more aggressive approach checking 64B each time. Use 2 ++ pointers 128B apart and unroll the loop once to make the pointer ++ updates and usages separated enough to avoid stalls waiting for ++ address calculation. */ ++ .p2align 5 ++L(loop): ++ CHECK64(0,r4,pre_tail_64b) ++ CHECK64(64,r4,pre_tail_64b) ++ addi r4,r4,256 ++ ++ CHECK64(0,r5,tail_64b) ++ CHECK64(64,r5,tail_64b) ++ addi r5,r5,256 ++ ++ b L(loop) ++ ++ .p2align 5 ++L(pre_tail_64b): ++ mr r5,r4 ++L(tail_64b): ++ /* OK, we found a null byte. Let's look for it in the current 64-byte ++ block and mark it in its corresponding VR. lxvp vx,0(ry) puts the ++ low 16B bytes into vx+1, and the high into vx, so the order here is ++ v5, v4, v7, v6. */ ++ vcmpequb v1,v5,v18 ++ vcmpequb v2,v4,v18 ++ vcmpequb v3,v7,v18 ++ vcmpequb v4,v6,v18 ++ ++ /* Take into account the other 64B blocks we had already checked. */ ++ add r5,r5,r6 ++ ++ /* Extract first bit of each byte. */ ++ VEXTRACTBM(r7,v1) ++ VEXTRACTBM(r8,v2) ++ VEXTRACTBM(r9,v3) ++ VEXTRACTBM(r10,v4) ++ ++ /* Shift each value into their corresponding position. */ ++ sldi r8,r8,16 ++ sldi r9,r9,32 ++ sldi r10,r10,48 ++ ++ /* Merge the results. */ ++ or r7,r7,r8 ++ or r8,r9,r10 ++ or r10,r8,r7 ++ ++ cnttzd r0,r10 /* Count trailing zeros before the match. */ ++ subf r5,r3,r5 ++ add r3,r5,r0 /* Compute final length. */ ++ blr ++ ++ .p2align 5 ++L(tail1): ++ TAIL(v0,0) ++ ++ .p2align 5 ++L(tail2): ++ TAIL(v1,16) ++ ++ .p2align 5 ++L(tail3): ++ TAIL(v2,32) ++ ++ .p2align 5 ++L(tail4): ++ TAIL(v3,48) ++ ++ .p2align 5 ++L(tail5): ++ TAIL(v4,64) ++ ++ .p2align 5 ++L(tail6): ++ TAIL(v5,80) ++ ++ .p2align 5 ++L(tail7): ++ TAIL(v6,96) ++ ++ .p2align 5 ++L(tail8): ++ TAIL(v7,112) ++ ++ .p2align 5 ++L(tail9): ++ TAIL(v8,128) ++ ++ .p2align 5 ++L(tail10): ++ TAIL(v9,144) ++ ++ .p2align 5 ++L(tail11): ++ TAIL(v10,160) ++ ++END (STRLEN) ++ ++#ifdef DEFINE_STRLEN_HIDDEN_DEF ++weak_alias (__strlen, strlen) ++libc_hidden_builtin_def (strlen) ++#endif +diff --git a/sysdeps/powerpc/powerpc64/multiarch/Makefile b/sysdeps/powerpc/powerpc64/multiarch/Makefile +index a9e13e05e90601cd..61652b65dd223018 100644 +--- a/sysdeps/powerpc/powerpc64/multiarch/Makefile ++++ b/sysdeps/powerpc/powerpc64/multiarch/Makefile +@@ -33,7 +33,8 @@ sysdep_routines += memcpy-power8-cached memcpy-power7 memcpy-a2 memcpy-power6 \ + + ifneq (,$(filter %le,$(config-machine))) + sysdep_routines += strcmp-power9 strncmp-power9 strcpy-power9 stpcpy-power9 \ +- rawmemchr-power9 strlen-power9 strncpy-power9 stpncpy-power9 ++ rawmemchr-power9 strlen-power9 strncpy-power9 stpncpy-power9 \ ++ strlen-power10 + endif + CFLAGS-strncase-power7.c += -mcpu=power7 -funroll-loops + CFLAGS-strncase_l-power7.c += -mcpu=power7 -funroll-loops +diff --git a/sysdeps/powerpc/powerpc64/multiarch/ifunc-impl-list.c b/sysdeps/powerpc/powerpc64/multiarch/ifunc-impl-list.c +index b30bc53930fc0e36..46d5956adda72b86 100644 +--- a/sysdeps/powerpc/powerpc64/multiarch/ifunc-impl-list.c ++++ b/sysdeps/powerpc/powerpc64/multiarch/ifunc-impl-list.c +@@ -112,6 +112,8 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + /* Support sysdeps/powerpc/powerpc64/multiarch/strlen.c. */ + IFUNC_IMPL (i, name, strlen, + #ifdef __LITTLE_ENDIAN__ ++ IFUNC_IMPL_ADD (array, i, strlen, hwcap2 & PPC_FEATURE2_ARCH_3_1, ++ __strlen_power10) + IFUNC_IMPL_ADD (array, i, strlen, hwcap2 & PPC_FEATURE2_ARCH_3_00, + __strlen_power9) + #endif +diff --git a/sysdeps/powerpc/powerpc64/multiarch/strlen-power10.S b/sysdeps/powerpc/powerpc64/multiarch/strlen-power10.S +new file mode 100644 +index 0000000000000000..6a774fad58c77179 +--- /dev/null ++++ b/sysdeps/powerpc/powerpc64/multiarch/strlen-power10.S +@@ -0,0 +1,2 @@ ++#define STRLEN __strlen_power10 ++#include +diff --git a/sysdeps/powerpc/powerpc64/multiarch/strlen.c b/sysdeps/powerpc/powerpc64/multiarch/strlen.c +index b7f0fbb13fb97783..11bdb96de2d2aa66 100644 +--- a/sysdeps/powerpc/powerpc64/multiarch/strlen.c ++++ b/sysdeps/powerpc/powerpc64/multiarch/strlen.c +@@ -31,9 +31,12 @@ extern __typeof (__redirect_strlen) __strlen_ppc attribute_hidden; + extern __typeof (__redirect_strlen) __strlen_power7 attribute_hidden; + extern __typeof (__redirect_strlen) __strlen_power8 attribute_hidden; + extern __typeof (__redirect_strlen) __strlen_power9 attribute_hidden; ++extern __typeof (__redirect_strlen) __strlen_power10 attribute_hidden; + + libc_ifunc (__libc_strlen, + # ifdef __LITTLE_ENDIAN__ ++ (hwcap2 & PPC_FEATURE2_ARCH_3_1) ++ ? __strlen_power10 : + (hwcap2 & PPC_FEATURE2_ARCH_3_00) + ? __strlen_power9 : + # endif diff --git a/SOURCES/glibc-rh1956357-4.patch b/SOURCES/glibc-rh1956357-4.patch new file mode 100644 index 0000000..ad6aa06 --- /dev/null +++ b/SOURCES/glibc-rh1956357-4.patch @@ -0,0 +1,527 @@ +commit dd59655e9371af86043b97e38953f43bd9496699 +Author: Lucas A. M. Magalhaes +Date: Fri Apr 30 18:12:08 2021 -0300 + + powerpc64le: Optimized memmove for POWER10 + + This patch was initially based on the __memmove_power7 with some ideas + from strncpy implementation for Power 9. + + Improvements from __memmove_power7: + + 1. Use lxvl/stxvl for alignment code. + + The code for Power 7 uses branches when the input is not naturally + aligned to the width of a vector. The new implementation uses + lxvl/stxvl instead which reduces pressure on GPRs. It also allows + the removal of branch instructions, implicitly removing branch stalls + and mispredictions. + + 2. Use of lxv/stxv and lxvl/stxvl pair is safe to use on Cache Inhibited + memory. + + On Power 10 vector load and stores are safe to use on CI memory for + addresses unaligned to 16B. This code takes advantage of this to + do unaligned loads. + + The unaligned loads don't have a significant performance impact by + themselves. However doing so decreases register pressure on GPRs + and interdependence stalls on load/store pairs. This also improved + readability as there are now less code paths for different alignments. + Finally this reduces the overall code size. + + 3. Improved performance. + + This version runs on average about 30% better than memmove_power7 + for lengths larger than 8KB. For input lengths shorter than 8KB + the improvement is smaller, it has on average about 17% better + performance. + + This version has a degradation of about 50% for input lengths + in the 0 to 31 bytes range when dest is unaligned. + + Reviewed-by: Tulio Magno Quites Machado Filho + +diff --git a/sysdeps/powerpc/powerpc64/le/power10/memmove.S b/sysdeps/powerpc/powerpc64/le/power10/memmove.S +new file mode 100644 +index 0000000000000000..7dfd57edeb37e8e4 +--- /dev/null ++++ b/sysdeps/powerpc/powerpc64/le/power10/memmove.S +@@ -0,0 +1,320 @@ ++/* Optimized memmove implementation for POWER10. ++ 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* [r3] memmove (void *dest [r3], const void *src [r4], size_t len [r5]) ++ ++ This optimization checks if 'src' and 'dst' overlap. If they do not ++ or 'src' is ahead of 'dest' then it copies forward. ++ Otherwise, an optimized backward copy is used. */ ++ ++#ifndef MEMMOVE ++# define MEMMOVE memmove ++#endif ++ .machine power9 ++ENTRY_TOCLESS (MEMMOVE, 5) ++ CALL_MCOUNT 3 ++ ++L(_memmove): ++ .p2align 5 ++ /* Check if there is overlap, if so it will branch to backward copy. */ ++ subf r9,r4,r3 ++ cmpld cr7,r9,r5 ++ blt cr7,L(memmove_bwd) ++ ++ /* Fast path for length shorter than 16 bytes. */ ++ sldi r7,r5,56 ++ lxvl 32+v2,r4,r7 ++ stxvl 32+v2,r3,r7 ++ subic. r8,r5,16 ++ blelr ++ ++ /* For shorter lengths aligning the dest address to 16 bytes either ++ decreases performance or is irrelevant. I'm making use of this ++ comparison to skip the alignment in. */ ++ cmpldi cr6,r5,256 ++ bge cr6,L(ge_256) ++ /* Account for the first 16-byte copy. */ ++ addi r4,r4,16 ++ addi r11,r3,16 /* use r11 to keep dest address on r3. */ ++ subi r5,r5,16 ++ b L(loop_head) ++ ++ .p2align 5 ++L(ge_256): ++ /* Account for the first copy <= 16 bytes. This is necessary for ++ memmove because at this point the src address can be in front of the ++ dest address. */ ++ clrldi r9,r5,56 ++ li r8,16 ++ cmpldi r9,16 ++ iselgt r9,r8,r9 ++ add r4,r4,r9 ++ add r11,r3,r9 /* use r11 to keep dest address on r3. */ ++ sub r5,r5,r9 ++ ++ /* Align dest to 16 bytes. */ ++ neg r7,r3 ++ clrldi. r9,r7,60 ++ beq L(loop_head) ++ ++ .p2align 5 ++ sldi r6,r9,56 ++ lxvl 32+v0,r4,r6 ++ stxvl 32+v0,r11,r6 ++ sub r5,r5,r9 ++ add r4,r4,r9 ++ add r11,r11,r9 ++ ++L(loop_head): ++ cmpldi r5,63 ++ ble L(final_64) ++ ++ srdi. r7,r5,7 ++ beq L(loop_tail) ++ ++ mtctr r7 ++ ++/* Main loop that copies 128 bytes each iteration. */ ++ .p2align 5 ++L(loop): ++ addi r9,r4,64 ++ addi r10,r11,64 ++ ++ lxv 32+v0,0(r4) ++ lxv 32+v1,16(r4) ++ lxv 32+v2,32(r4) ++ lxv 32+v3,48(r4) ++ ++ stxv 32+v0,0(r11) ++ stxv 32+v1,16(r11) ++ stxv 32+v2,32(r11) ++ stxv 32+v3,48(r11) ++ ++ addi r4,r4,128 ++ addi r11,r11,128 ++ ++ lxv 32+v4,0(r9) ++ lxv 32+v5,16(r9) ++ lxv 32+v6,32(r9) ++ lxv 32+v7,48(r9) ++ ++ stxv 32+v4,0(r10) ++ stxv 32+v5,16(r10) ++ stxv 32+v6,32(r10) ++ stxv 32+v7,48(r10) ++ ++ bdnz L(loop) ++ clrldi. r5,r5,57 ++ beqlr ++ ++/* Copy 64 bytes. */ ++ .p2align 5 ++L(loop_tail): ++ cmpldi cr5,r5,63 ++ ble cr5,L(final_64) ++ ++ lxv 32+v0,0(r4) ++ lxv 32+v1,16(r4) ++ lxv 32+v2,32(r4) ++ lxv 32+v3,48(r4) ++ ++ stxv 32+v0,0(r11) ++ stxv 32+v1,16(r11) ++ stxv 32+v2,32(r11) ++ stxv 32+v3,48(r11) ++ ++ addi r4,r4,64 ++ addi r11,r11,64 ++ subi r5,r5,64 ++ ++/* Copies the last 1-63 bytes. */ ++ .p2align 5 ++L(final_64): ++ /* r8 holds the number of bytes that will be copied with lxv/stxv. */ ++ clrrdi. r8,r5,4 ++ beq L(tail1) ++ ++ cmpldi cr5,r5,32 ++ lxv 32+v0,0(r4) ++ blt cr5,L(tail2) ++ ++ cmpldi cr6,r5,48 ++ lxv 32+v1,16(r4) ++ blt cr6,L(tail3) ++ ++ .p2align 5 ++ lxv 32+v2,32(r4) ++ stxv 32+v2,32(r11) ++L(tail3): ++ stxv 32+v1,16(r11) ++L(tail2): ++ stxv 32+v0,0(r11) ++ sub r5,r5,r8 ++ add r4,r4,r8 ++ add r11,r11,r8 ++ .p2align 5 ++L(tail1): ++ sldi r6,r5,56 ++ lxvl v4,r4,r6 ++ stxvl v4,r11,r6 ++ blr ++ ++/* If dest and src overlap, we should copy backwards. */ ++L(memmove_bwd): ++ add r11,r3,r5 ++ add r4,r4,r5 ++ ++ /* Optimization for length smaller than 16 bytes. */ ++ cmpldi cr5,r5,15 ++ ble cr5,L(tail1_bwd) ++ ++ /* For shorter lengths the alignment either slows down or is irrelevant. ++ The forward copy uses a already need 256 comparison for that. Here ++ it's using 128 as it will reduce code and improve readability. */ ++ cmpldi cr7,r5,128 ++ blt cr7,L(bwd_loop_tail) ++ ++ /* Align dest address to 16 bytes. */ ++ .p2align 5 ++ clrldi. r9,r11,60 ++ beq L(bwd_loop_head) ++ sub r4,r4,r9 ++ sub r11,r11,r9 ++ lxv 32+v0,0(r4) ++ sldi r6,r9,56 ++ stxvl 32+v0,r11,r6 ++ sub r5,r5,r9 ++ ++L(bwd_loop_head): ++ srdi. r7,r5,7 ++ beq L(bwd_loop_tail) ++ ++ mtctr r7 ++ ++/* Main loop that copies 128 bytes every iteration. */ ++ .p2align 5 ++L(bwd_loop): ++ addi r9,r4,-64 ++ addi r10,r11,-64 ++ ++ lxv 32+v0,-16(r4) ++ lxv 32+v1,-32(r4) ++ lxv 32+v2,-48(r4) ++ lxv 32+v3,-64(r4) ++ ++ stxv 32+v0,-16(r11) ++ stxv 32+v1,-32(r11) ++ stxv 32+v2,-48(r11) ++ stxv 32+v3,-64(r11) ++ ++ addi r4,r4,-128 ++ addi r11,r11,-128 ++ ++ lxv 32+v0,-16(r9) ++ lxv 32+v1,-32(r9) ++ lxv 32+v2,-48(r9) ++ lxv 32+v3,-64(r9) ++ ++ stxv 32+v0,-16(r10) ++ stxv 32+v1,-32(r10) ++ stxv 32+v2,-48(r10) ++ stxv 32+v3,-64(r10) ++ ++ bdnz L(bwd_loop) ++ clrldi. r5,r5,57 ++ beqlr ++ ++/* Copy 64 bytes. */ ++ .p2align 5 ++L(bwd_loop_tail): ++ cmpldi cr5,r5,63 ++ ble cr5,L(bwd_final_64) ++ ++ addi r4,r4,-64 ++ addi r11,r11,-64 ++ ++ lxv 32+v0,0(r4) ++ lxv 32+v1,16(r4) ++ lxv 32+v2,32(r4) ++ lxv 32+v3,48(r4) ++ ++ stxv 32+v0,0(r11) ++ stxv 32+v1,16(r11) ++ stxv 32+v2,32(r11) ++ stxv 32+v3,48(r11) ++ ++ subi r5,r5,64 ++ ++/* Copies the last 1-63 bytes. */ ++ .p2align 5 ++L(bwd_final_64): ++ /* r8 holds the number of bytes that will be copied with lxv/stxv. */ ++ clrrdi. r8,r5,4 ++ beq L(tail1_bwd) ++ ++ cmpldi cr5,r5,32 ++ lxv 32+v2,-16(r4) ++ blt cr5,L(tail2_bwd) ++ ++ cmpldi cr6,r5,48 ++ lxv 32+v1,-32(r4) ++ blt cr6,L(tail3_bwd) ++ ++ .p2align 5 ++ lxv 32+v0,-48(r4) ++ stxv 32+v0,-48(r11) ++L(tail3_bwd): ++ stxv 32+v1,-32(r11) ++L(tail2_bwd): ++ stxv 32+v2,-16(r11) ++ sub r4,r4,r5 ++ sub r11,r11,r5 ++ sub r5,r5,r8 ++ sldi r6,r5,56 ++ lxvl v4,r4,r6 ++ stxvl v4,r11,r6 ++ blr ++ ++/* Copy last 16 bytes. */ ++ .p2align 5 ++L(tail1_bwd): ++ sub r4,r4,r5 ++ sub r11,r11,r5 ++ sldi r6,r5,56 ++ lxvl v4,r4,r6 ++ stxvl v4,r11,r6 ++ blr ++ ++END_GEN_TB (MEMMOVE,TB_TOCLESS) ++libc_hidden_builtin_def (memmove) ++ ++/* void bcopy(const void *src [r3], void *dest [r4], size_t n [r5]) ++ Implemented in this file to avoid linker create a stub function call ++ in the branch to '_memmove'. */ ++ENTRY_TOCLESS (__bcopy) ++ mr r6,r3 ++ mr r3,r4 ++ mr r4,r6 ++ b L(_memmove) ++END (__bcopy) ++#ifndef __bcopy ++weak_alias (__bcopy, bcopy) ++#endif +diff --git a/sysdeps/powerpc/powerpc64/multiarch/Makefile b/sysdeps/powerpc/powerpc64/multiarch/Makefile +index 61652b65dd223018..66f8c6ace9824d4a 100644 +--- a/sysdeps/powerpc/powerpc64/multiarch/Makefile ++++ b/sysdeps/powerpc/powerpc64/multiarch/Makefile +@@ -32,7 +32,8 @@ sysdep_routines += memcpy-power8-cached memcpy-power7 memcpy-a2 memcpy-power6 \ + strncase-power8 + + ifneq (,$(filter %le,$(config-machine))) +-sysdep_routines += strcmp-power9 strncmp-power9 strcpy-power9 stpcpy-power9 \ ++sysdep_routines += memmove-power10 \ ++ strcmp-power9 strncmp-power9 strcpy-power9 stpcpy-power9 \ + rawmemchr-power9 strlen-power9 strncpy-power9 stpncpy-power9 \ + strlen-power10 + endif +diff --git a/sysdeps/powerpc/powerpc64/multiarch/bcopy.c b/sysdeps/powerpc/powerpc64/multiarch/bcopy.c +index 1c4a229b1fc5654a..705fef33d4e57557 100644 +--- a/sysdeps/powerpc/powerpc64/multiarch/bcopy.c ++++ b/sysdeps/powerpc/powerpc64/multiarch/bcopy.c +@@ -22,8 +22,17 @@ + extern __typeof (bcopy) __bcopy_ppc attribute_hidden; + /* __bcopy_power7 symbol is implemented at memmove-power7.S */ + extern __typeof (bcopy) __bcopy_power7 attribute_hidden; ++#ifdef __LITTLE_ENDIAN__ ++extern __typeof (bcopy) __bcopy_power10 attribute_hidden; ++#endif + + libc_ifunc (bcopy, ++#ifdef __LITTLE_ENDIAN__ ++ hwcap2 & (PPC_FEATURE2_ARCH_3_1 | ++ PPC_FEATURE2_HAS_ISEL) ++ && (hwcap & PPC_FEATURE_HAS_VSX) ++ ? __bcopy_power10 : ++#endif + (hwcap & PPC_FEATURE_HAS_VSX) + ? __bcopy_power7 + : __bcopy_ppc); +diff --git a/sysdeps/powerpc/powerpc64/multiarch/ifunc-impl-list.c b/sysdeps/powerpc/powerpc64/multiarch/ifunc-impl-list.c +index 46d5956adda72b86..4ce04bc51574cca1 100644 +--- a/sysdeps/powerpc/powerpc64/multiarch/ifunc-impl-list.c ++++ b/sysdeps/powerpc/powerpc64/multiarch/ifunc-impl-list.c +@@ -67,6 +67,13 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + + /* Support sysdeps/powerpc/powerpc64/multiarch/memmove.c. */ + IFUNC_IMPL (i, name, memmove, ++#ifdef __LITTLE_ENDIAN__ ++ IFUNC_IMPL_ADD (array, i, memmove, ++ hwcap2 & (PPC_FEATURE2_ARCH_3_1 | ++ PPC_FEATURE2_HAS_ISEL) ++ && (hwcap & PPC_FEATURE_HAS_VSX), ++ __memmove_power10) ++#endif + IFUNC_IMPL_ADD (array, i, memmove, hwcap & PPC_FEATURE_HAS_VSX, + __memmove_power7) + IFUNC_IMPL_ADD (array, i, memmove, 1, __memmove_ppc)) +@@ -186,6 +193,13 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + + /* Support sysdeps/powerpc/powerpc64/multiarch/bcopy.c. */ + IFUNC_IMPL (i, name, bcopy, ++#ifdef __LITTLE_ENDIAN__ ++ IFUNC_IMPL_ADD (array, i, bcopy, ++ hwcap2 & (PPC_FEATURE2_ARCH_3_1 | ++ PPC_FEATURE2_HAS_ISEL) ++ && (hwcap & PPC_FEATURE_HAS_VSX), ++ __bcopy_power10) ++#endif + IFUNC_IMPL_ADD (array, i, bcopy, hwcap & PPC_FEATURE_HAS_VSX, + __bcopy_power7) + IFUNC_IMPL_ADD (array, i, bcopy, 1, __bcopy_ppc)) +diff --git a/sysdeps/powerpc/powerpc64/multiarch/memmove-power10.S b/sysdeps/powerpc/powerpc64/multiarch/memmove-power10.S +new file mode 100644 +index 0000000000000000..171b32921a0a4d47 +--- /dev/null ++++ b/sysdeps/powerpc/powerpc64/multiarch/memmove-power10.S +@@ -0,0 +1,27 @@ ++/* Optimized memmove implementation for POWER10. ++ 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 ++ . */ ++ ++#define MEMMOVE __memmove_power10 ++ ++#undef libc_hidden_builtin_def ++#define libc_hidden_builtin_def(name) ++ ++#undef __bcopy ++#define __bcopy __bcopy_power10 ++ ++#include +diff --git a/sysdeps/powerpc/powerpc64/multiarch/memmove-power7.S b/sysdeps/powerpc/powerpc64/multiarch/memmove-power7.S +index 0b251d0f5f087874..fb5261ecda64d061 100644 +--- a/sysdeps/powerpc/powerpc64/multiarch/memmove-power7.S ++++ b/sysdeps/powerpc/powerpc64/multiarch/memmove-power7.S +@@ -21,7 +21,7 @@ + #undef libc_hidden_builtin_def + #define libc_hidden_builtin_def(name) + +-#undef bcopy +-#define bcopy __bcopy_power7 ++#undef __bcopy ++#define __bcopy __bcopy_power7 + + #include +diff --git a/sysdeps/powerpc/powerpc64/multiarch/memmove.c b/sysdeps/powerpc/powerpc64/multiarch/memmove.c +index 39987155cc7d3624..2fd7b6d309e4bedd 100644 +--- a/sysdeps/powerpc/powerpc64/multiarch/memmove.c ++++ b/sysdeps/powerpc/powerpc64/multiarch/memmove.c +@@ -28,14 +28,22 @@ + # include "init-arch.h" + + extern __typeof (__redirect_memmove) __libc_memmove; +- + extern __typeof (__redirect_memmove) __memmove_ppc attribute_hidden; + extern __typeof (__redirect_memmove) __memmove_power7 attribute_hidden; ++#ifdef __LITTLE_ENDIAN__ ++extern __typeof (__redirect_memmove) __memmove_power10 attribute_hidden; ++#endif + + libc_ifunc (__libc_memmove, +- (hwcap & PPC_FEATURE_HAS_VSX) +- ? __memmove_power7 +- : __memmove_ppc); ++#ifdef __LITTLE_ENDIAN__ ++ hwcap2 & (PPC_FEATURE2_ARCH_3_1 | ++ PPC_FEATURE2_HAS_ISEL) ++ && (hwcap & PPC_FEATURE_HAS_VSX) ++ ? __memmove_power10 : ++#endif ++ (hwcap & PPC_FEATURE_HAS_VSX) ++ ? __memmove_power7 ++ : __memmove_ppc); + + #undef memmove + strong_alias (__libc_memmove, memmove); +diff --git a/sysdeps/powerpc/powerpc64/power7/memmove.S b/sysdeps/powerpc/powerpc64/power7/memmove.S +index b7f3dc28d1a8eac3..9e4cabb07ef9b732 100644 +--- a/sysdeps/powerpc/powerpc64/power7/memmove.S ++++ b/sysdeps/powerpc/powerpc64/power7/memmove.S +@@ -832,4 +832,6 @@ ENTRY_TOCLESS (__bcopy) + mr r4,r6 + b L(_memmove) + END (__bcopy) ++#ifndef __bcopy + weak_alias (__bcopy, bcopy) ++#endif diff --git a/SOURCES/glibc-rh1956357-5.patch b/SOURCES/glibc-rh1956357-5.patch new file mode 100644 index 0000000..11f1597 --- /dev/null +++ b/SOURCES/glibc-rh1956357-5.patch @@ -0,0 +1,308 @@ +commit e941e0ae80626b7661c1db8953a673cafd3b8b19 +Author: Tulio Magno Quites Machado Filho +Date: Fri Apr 30 18:12:08 2021 -0300 + + powerpc64le: Optimize memcpy for POWER10 + + This implementation is based on __memcpy_power8_cached and integrates + suggestions from Anton Blanchard. + It benefits from loads and stores with length for short lengths and for + tail code, simplifying the code. + + All unaligned memory accesses use instructions that do not generate + alignment interrupts on POWER10, making it safe to use on + caching-inhibited memory. + + The main loop has also been modified in order to increase instruction + throughput by reducing the dependency on updates from previous iterations. + + On average, this implementation provides around 30% improvement when + compared to __memcpy_power7 and 10% improvement in comparison to + __memcpy_power8_cached. + +diff --git a/sysdeps/powerpc/powerpc64/le/power10/memcpy.S b/sysdeps/powerpc/powerpc64/le/power10/memcpy.S +new file mode 100644 +index 0000000000000000..ad1414db4a3a8b9f +--- /dev/null ++++ b/sysdeps/powerpc/powerpc64/le/power10/memcpy.S +@@ -0,0 +1,198 @@ ++/* Optimized memcpy implementation for POWER10. ++ 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 ++ ++ ++#ifndef MEMCPY ++# define MEMCPY memcpy ++#endif ++ ++/* __ptr_t [r3] memcpy (__ptr_t dst [r3], __ptr_t src [r4], size_t len [r5]); ++ Returns 'dst'. */ ++ ++ .machine power9 ++ENTRY_TOCLESS (MEMCPY, 5) ++ CALL_MCOUNT 3 ++ ++ /* Copy up to 16 bytes. */ ++ sldi r6,r5,56 /* Prepare [l|st]xvl counter. */ ++ lxvl v10,r4,r6 ++ stxvl v10,r3,r6 ++ subic. r6,r5,16 /* Return if len <= 16. */ ++ blelr ++ ++ /* If len >= 256, assume nothing got copied before and copy ++ again. This might cause issues with overlapped memory, but memcpy ++ is not expected to treat overlapped memory. */ ++ cmpdi r5,256 ++ bge L(copy_ge_256) ++ /* 16 < len < 256 and the first 16 bytes have already been copied. */ ++ addi r10,r3,16 /* Keep r3 intact as return value. */ ++ addi r4,r4,16 ++ subi r5,r5,16 ++ b L(copy_lt_256) /* Avoid the main loop if len < 256. */ ++ ++ .p2align 5 ++L(copy_ge_256): ++ mr r10,r3 /* Keep r3 intact as return value. */ ++ /* Align dst to 16 bytes. */ ++ andi. r9,r10,0xf ++ beq L(dst_is_align_16) ++ lxv v10,0(r4) ++ subfic r12,r9,16 ++ subf r5,r12,r5 ++ add r4,r4,r12 ++ stxv v10,0(r3) ++ add r10,r3,r12 ++ ++L(dst_is_align_16): ++ srdi r9,r5,7 /* Divide by 128. */ ++ mtctr r9 ++ addi r6,r4,64 ++ addi r7,r10,64 ++ ++ ++ /* Main loop, copy 128 bytes per iteration. ++ Use r6=src+64 and r7=dest+64 in order to reduce the dependency on ++ r4 and r10. */ ++ .p2align 5 ++L(copy_128): ++ ++ lxv v10, 0(r4) ++ lxv v11, 16(r4) ++ lxv v12, 32(r4) ++ lxv v13, 48(r4) ++ ++ addi r4,r4,128 ++ ++ stxv v10, 0(r10) ++ stxv v11, 16(r10) ++ stxv v12, 32(r10) ++ stxv v13, 48(r10) ++ ++ addi r10,r10,128 ++ ++ lxv v10, 0(r6) ++ lxv v11, 16(r6) ++ lxv v12, 32(r6) ++ lxv v13, 48(r6) ++ ++ addi r6,r6,128 ++ ++ stxv v10, 0(r7) ++ stxv v11, 16(r7) ++ stxv v12, 32(r7) ++ stxv v13, 48(r7) ++ ++ addi r7,r7,128 ++ ++ bdnz L(copy_128) ++ ++ clrldi. r5,r5,64-7 /* Have we copied everything? */ ++ beqlr ++ ++ .p2align 5 ++L(copy_lt_256): ++ cmpdi r5,16 ++ ble L(copy_le_16) ++ srdi. r9,r5,5 /* Divide by 32. */ ++ beq L(copy_lt_32) ++ mtctr r9 ++ /* Use r6=src+32, r7=dest+32, r8=src+64, r9=dest+64 in order to reduce ++ the dependency on r4 and r10. */ ++ addi r6,r4,32 ++ addi r7,r10,32 ++ addi r8,r4,64 ++ addi r9,r10,64 ++ ++ .p2align 5 ++ /* Copy 32 bytes at a time, unaligned. ++ The loop is unrolled 3 times in order to reduce the dependency on ++ r4 and r10, copying up-to 96 bytes per iteration. */ ++L(copy_32): ++ lxv v10, 0(r4) ++ lxv v11, 16(r4) ++ stxv v10, 0(r10) ++ stxv v11, 16(r10) ++ bdz L(end_copy_32a) ++ addi r4,r4,96 ++ addi r10,r10,96 ++ ++ lxv v10, 0(r6) ++ lxv v11, 16(r6) ++ addi r6,r6,96 ++ stxv v10, 0(r7) ++ stxv v11, 16(r7) ++ bdz L(end_copy_32b) ++ addi r7,r7,96 ++ ++ lxv v12, 0(r8) ++ lxv v13, 16(r8) ++ addi r8,r8,96 ++ stxv v12, 0(r9) ++ stxv v13, 16(r9) ++ addi r9,r9,96 ++ bdnz L(copy_32) ++ ++ clrldi. r5,r5,64-5 /* Have we copied everything? */ ++ beqlr ++ cmpdi r5,16 ++ ble L(copy_le_16) ++ b L(copy_lt_32) ++ ++ .p2align 5 ++L(end_copy_32a): ++ clrldi. r5,r5,64-5 /* Have we copied everything? */ ++ beqlr ++ /* 32 bytes have been copied since the last update of r4 and r10. */ ++ addi r4,r4,32 ++ addi r10,r10,32 ++ cmpdi r5,16 ++ ble L(copy_le_16) ++ b L(copy_lt_32) ++ ++ .p2align 5 ++L(end_copy_32b): ++ clrldi. r5,r5,64-5 /* Have we copied everything? */ ++ beqlr ++ /* The last iteration of the loop copied 64 bytes. Update r4 and r10 ++ accordingly. */ ++ addi r4,r4,-32 ++ addi r10,r10,-32 ++ cmpdi r5,16 ++ ble L(copy_le_16) ++ ++ .p2align 5 ++L(copy_lt_32): ++ lxv v10, 0(r4) ++ stxv v10, 0(r10) ++ addi r4,r4,16 ++ addi r10,r10,16 ++ subi r5,r5,16 ++ ++ .p2align 5 ++L(copy_le_16): ++ sldi r6,r5,56 ++ lxvl v10,r4,r6 ++ stxvl v10,r10,r6 ++ blr ++ ++ ++END_GEN_TB (MEMCPY,TB_TOCLESS) ++libc_hidden_builtin_def (memcpy) +diff --git a/sysdeps/powerpc/powerpc64/multiarch/Makefile b/sysdeps/powerpc/powerpc64/multiarch/Makefile +index 66f8c6ace9824d4a..2e3c8f2e8a81cda4 100644 +--- a/sysdeps/powerpc/powerpc64/multiarch/Makefile ++++ b/sysdeps/powerpc/powerpc64/multiarch/Makefile +@@ -32,7 +32,7 @@ sysdep_routines += memcpy-power8-cached memcpy-power7 memcpy-a2 memcpy-power6 \ + strncase-power8 + + ifneq (,$(filter %le,$(config-machine))) +-sysdep_routines += memmove-power10 \ ++sysdep_routines += memcpy-power10 memmove-power10 \ + strcmp-power9 strncmp-power9 strcpy-power9 stpcpy-power9 \ + rawmemchr-power9 strlen-power9 strncpy-power9 stpncpy-power9 \ + strlen-power10 +diff --git a/sysdeps/powerpc/powerpc64/multiarch/ifunc-impl-list.c b/sysdeps/powerpc/powerpc64/multiarch/ifunc-impl-list.c +index 4ce04bc51574cca1..9d5a14e480c02171 100644 +--- a/sysdeps/powerpc/powerpc64/multiarch/ifunc-impl-list.c ++++ b/sysdeps/powerpc/powerpc64/multiarch/ifunc-impl-list.c +@@ -51,6 +51,12 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + #ifdef SHARED + /* Support sysdeps/powerpc/powerpc64/multiarch/memcpy.c. */ + IFUNC_IMPL (i, name, memcpy, ++#ifdef __LITTLE_ENDIAN__ ++ IFUNC_IMPL_ADD (array, i, memcpy, ++ hwcap2 & PPC_FEATURE2_ARCH_3_1 ++ && hwcap & PPC_FEATURE_HAS_VSX, ++ __memcpy_power10) ++#endif + IFUNC_IMPL_ADD (array, i, memcpy, hwcap2 & PPC_FEATURE2_ARCH_2_07, + __memcpy_power8_cached) + IFUNC_IMPL_ADD (array, i, memcpy, hwcap & PPC_FEATURE_HAS_VSX, +diff --git a/sysdeps/powerpc/powerpc64/multiarch/memcpy-power10.S b/sysdeps/powerpc/powerpc64/multiarch/memcpy-power10.S +new file mode 100644 +index 0000000000000000..70e0fc3ed610cdc3 +--- /dev/null ++++ b/sysdeps/powerpc/powerpc64/multiarch/memcpy-power10.S +@@ -0,0 +1,26 @@ ++/* Optimized memcpy implementation for POWER10. ++ 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 ++ . */ ++ ++#if defined __LITTLE_ENDIAN__ && IS_IN (libc) ++#define MEMCPY __memcpy_power10 ++ ++#undef libc_hidden_builtin_def ++#define libc_hidden_builtin_def(name) ++ ++#include ++#endif +diff --git a/sysdeps/powerpc/powerpc64/multiarch/memcpy.c b/sysdeps/powerpc/powerpc64/multiarch/memcpy.c +index 44dea594f3770673..be0e47f32dde2ccf 100644 +--- a/sysdeps/powerpc/powerpc64/multiarch/memcpy.c ++++ b/sysdeps/powerpc/powerpc64/multiarch/memcpy.c +@@ -36,8 +36,15 @@ extern __typeof (__redirect_memcpy) __memcpy_power6 attribute_hidden; + extern __typeof (__redirect_memcpy) __memcpy_a2 attribute_hidden; + extern __typeof (__redirect_memcpy) __memcpy_power7 attribute_hidden; + extern __typeof (__redirect_memcpy) __memcpy_power8_cached attribute_hidden; ++# if defined __LITTLE_ENDIAN__ ++extern __typeof (__redirect_memcpy) __memcpy_power10 attribute_hidden; ++# endif + + libc_ifunc (__libc_memcpy, ++# if defined __LITTLE_ENDIAN__ ++ (hwcap2 & PPC_FEATURE2_ARCH_3_1 && hwcap & PPC_FEATURE_HAS_VSX) ++ ? __memcpy_power10 : ++# endif + ((hwcap2 & PPC_FEATURE2_ARCH_2_07) && use_cached_memopt) + ? __memcpy_power8_cached : + (hwcap & PPC_FEATURE_HAS_VSX) diff --git a/SOURCES/glibc-rh1956357-6.patch b/SOURCES/glibc-rh1956357-6.patch new file mode 100644 index 0000000..cc92e31 --- /dev/null +++ b/SOURCES/glibc-rh1956357-6.patch @@ -0,0 +1,420 @@ +commit 23fdf8178cce3c2ec320dd5eca8b544245bcaef0 +Author: Raoni Fassina Firmino +Date: Fri Apr 30 18:12:08 2021 -0300 + + powerpc64le: Optimize memset for POWER10 + + This implementation is based on __memset_power8 and integrates a lot + of suggestions from Anton Blanchard. + + The biggest difference is that it makes extensive use of stxvl to + alignment and tail code to avoid branches and small stores. It has + three main execution paths: + + a) "Short lengths" for lengths up to 64 bytes, avoiding as many + branches as possible. + + b) "General case" for larger lengths, it has an alignment section + using stxvl to avoid branches, a 128 bytes loop and then a tail + code, again using stxvl with few branches. + + c) "Zeroing cache blocks" for lengths from 256 bytes upwards and set + value being zero. It is mostly the __memset_power8 code but the + alignment phase was simplified because, at this point, address is + already 16-bytes aligned and also changed to use vector stores. + The tail code was also simplified to reuse the general case tail. + + All unaligned stores use stxvl instructions that do not generate + alignment interrupts on POWER10, making it safe to use on + caching-inhibited memory. + + On average, this implementation provides something around 30% + improvement when compared to __memset_power8. + + Reviewed-by: Matheus Castanho + Reviewed-by: Tulio Magno Quites Machado Filho + +diff --git a/sysdeps/powerpc/powerpc64/le/power10/memset.S b/sysdeps/powerpc/powerpc64/le/power10/memset.S +new file mode 100644 +index 0000000000000000..6b8e2cfdaf25fd30 +--- /dev/null ++++ b/sysdeps/powerpc/powerpc64/le/power10/memset.S +@@ -0,0 +1,256 @@ ++/* Optimized memset implementation for POWER10 LE. ++ 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 * [r3] memset (void *s [r3], int c [r4], size_t n [r5])); ++ Returns 's'. */ ++ ++#ifndef MEMSET ++# define MEMSET memset ++#endif ++ ++ .machine power9 ++ENTRY_TOCLESS (MEMSET, 5) ++ CALL_MCOUNT 3 ++ ++L(_memset): ++ /* Assume memset of zero length is uncommon, and just let it go ++ through the small path below. */ ++ cmpldi r5,64 ++ ++ /* Replicate byte to quad word. */ ++ mtvsrd v0+32,r4 ++ vspltb v0,v0,7 ++ ++ li r7,16 ++ sldi r8,r7,56 ++ ++ bgt L(large) ++ ++ /* For short lengths we want to avoid as many branches as possible. ++ We use store VSX vector with length instructions to do this. ++ It takes advantage of the fact that if the length passed to stxvl ++ is zero nothing is done, effectively a no-op. */ ++ sldi r5,r5,56 ++ ++ addi r10,r3,16 ++ ++ sub. r11,r5,r8 ++ isellt r11,0,r11 /* Saturate the subtraction to zero. */ ++ ++ stxvl v0+32,r3,r5 ++ stxvl v0+32,r10,r11 ++ ++ addi r9,r3,32 ++ addi r10,r3,48 ++ ++ sub. r11,r11,r8 ++ isellt r11,0,r11 ++ ++ sub. r5,r11,r8 ++ isellt r5,0,r5 ++ ++ stxvl v0+32,r9,r11 ++ stxvl v0+32,r10,r5 ++ ++ blr ++ ++ .balign 16 ++L(large): ++ mr r6,r3 /* Don't modify r3 since we need to return it. */ ++ ++ /* Get dest 16B aligned. */ ++ neg r0,r3 ++ clrldi. r7,r0,(64-4) ++ beq L(aligned) ++ rldic r9,r0,56,4 /* (~X & 0xf)<<56 "clrlsldi r9,r0,64-4,56". */ ++ ++ stxvl v0+32,r6,r9 /* Store up to 15B until aligned address. */ ++ ++ add r6,r6,r7 ++ sub r5,r5,r7 ++ ++ /* Go to tail if there is less than 64B left after alignment. */ ++ cmpldi r5,64 ++ blt L(tail_64) ++ ++ .balign 16 ++L(aligned): ++ /* Go to tail if there is less than 128B left after alignment. */ ++ srdi. r0,r5,7 ++ beq L(tail_128) ++ ++ /* If c == 0 && n >= 256 use dcbz to zero out full cache blocks. */ ++ cmpldi cr5,r5,255 ++ cmpldi cr6,r4,0 ++ crand 27,26,21 ++ bt 27,L(dcbz) ++ ++ mtctr r0 ++ ++ .balign 32 ++L(loop): ++ stxv v0+32,0(r6) ++ stxv v0+32,16(r6) ++ stxv v0+32,32(r6) ++ stxv v0+32,48(r6) ++ stxv v0+32,64(r6) ++ stxv v0+32,80(r6) ++ stxv v0+32,96(r6) ++ stxv v0+32,112(r6) ++ addi r6,r6,128 ++ bdnz L(loop) ++ ++ .balign 16 ++L(tail): ++ /* 127B or less left, finish the tail or return. */ ++ andi. r5,r5,127 ++ beqlr ++ ++ cmpldi r5,64 ++ blt L(tail_64) ++ ++ .balign 16 ++L(tail_128): ++ /* Stores a minimum of 64B and up to 128B and return. */ ++ stxv v0+32,0(r6) ++ stxv v0+32,16(r6) ++ stxv v0+32,32(r6) ++ stxv v0+32,48(r6) ++ addi r6,r6,64 ++ andi. r5,r5,63 ++ beqlr ++ ++ .balign 16 ++L(tail_64): ++ /* Stores up to 64B and return. */ ++ sldi r5,r5,56 ++ ++ addi r10,r6,16 ++ ++ sub. r11,r5,r8 ++ isellt r11,0,r11 ++ ++ stxvl v0+32,r6,r5 ++ stxvl v0+32,r10,r11 ++ ++ sub. r11,r11,r8 ++ blelr ++ ++ addi r9,r6,32 ++ addi r10,r6,48 ++ ++ isellt r11,0,r11 ++ ++ sub. r5,r11,r8 ++ isellt r5,0,r5 ++ ++ stxvl v0+32,r9,r11 ++ stxvl v0+32,r10,r5 ++ ++ blr ++ ++ .balign 16 ++L(dcbz): ++ /* Special case when value is 0 and we have a long length to deal ++ with. Use dcbz to zero out a full cacheline of 128 bytes at a time. ++ Before using dcbz though, we need to get the destination 128-byte ++ aligned. */ ++ neg r0,r6 ++ clrldi. r0,r0,(64-7) ++ beq L(dcbz_aligned) ++ ++ sub r5,r5,r0 ++ mtocrf 0x2,r0 /* copying bits 57..59 to cr6. The ones for sizes 64, ++ 32 and 16 which need to be checked. */ ++ ++ /* Write 16-128 bytes until DST is aligned to 128 bytes. */ ++64: bf 25,32f ++ stxv v0+32,0(r6) ++ stxv v0+32,16(r6) ++ stxv v0+32,32(r6) ++ stxv v0+32,48(r6) ++ addi r6,r6,64 ++ ++32: bf 26,16f ++ stxv v0+32,0(r6) ++ stxv v0+32,16(r6) ++ addi r6,r6,32 ++ ++16: bf 27,L(dcbz_aligned) ++ stxv v0+32,0(r6) ++ addi r6,r6,16 ++ ++ .balign 16 ++L(dcbz_aligned): ++ /* Setup dcbz unroll offsets and count numbers. */ ++ srdi. r0,r5,9 ++ li r9,128 ++ beq L(bcdz_tail) ++ li r10,256 ++ li r11,384 ++ mtctr r0 ++ ++ .balign 16 ++L(dcbz_loop): ++ /* Sets 512 bytes to zero in each iteration, the loop unrolling shows ++ a throughput boost for large sizes (2048 bytes or higher). */ ++ dcbz 0,r6 ++ dcbz r9,r6 ++ dcbz r10,r6 ++ dcbz r11,r6 ++ addi r6,r6,512 ++ bdnz L(dcbz_loop) ++ ++ andi. r5,r5,511 ++ beqlr ++ ++ .balign 16 ++L(bcdz_tail): ++ /* We have 1-511 bytes remaining. */ ++ srdi. r0,r5,7 ++ beq L(tail) ++ ++ mtocrf 0x1,r0 ++ ++256: bf 30,128f ++ dcbz 0,r6 ++ dcbz r9,r6 ++ addi r6,r6,256 ++ ++128: bf 31,L(tail) ++ dcbz 0,r6 ++ addi r6,r6,128 ++ ++ b L(tail) ++ ++END_GEN_TB (MEMSET,TB_TOCLESS) ++libc_hidden_builtin_def (memset) ++ ++/* Copied from bzero.S to prevent the linker from inserting a stub ++ between bzero and memset. */ ++ENTRY_TOCLESS (__bzero) ++ CALL_MCOUNT 2 ++ mr r5,r4 ++ li r4,0 ++ b L(_memset) ++END (__bzero) ++#ifndef __bzero ++weak_alias (__bzero, bzero) ++#endif +diff --git a/sysdeps/powerpc/powerpc64/multiarch/Makefile b/sysdeps/powerpc/powerpc64/multiarch/Makefile +index 2e3c8f2e8a81cda4..1d517698429e1230 100644 +--- a/sysdeps/powerpc/powerpc64/multiarch/Makefile ++++ b/sysdeps/powerpc/powerpc64/multiarch/Makefile +@@ -32,7 +32,7 @@ sysdep_routines += memcpy-power8-cached memcpy-power7 memcpy-a2 memcpy-power6 \ + strncase-power8 + + ifneq (,$(filter %le,$(config-machine))) +-sysdep_routines += memcpy-power10 memmove-power10 \ ++sysdep_routines += memcpy-power10 memmove-power10 memset-power10 \ + strcmp-power9 strncmp-power9 strcpy-power9 stpcpy-power9 \ + rawmemchr-power9 strlen-power9 strncpy-power9 stpncpy-power9 \ + strlen-power10 +diff --git a/sysdeps/powerpc/powerpc64/multiarch/bzero.c b/sysdeps/powerpc/powerpc64/multiarch/bzero.c +index f8cb05bea8a3505b..4ce98e324d12a31e 100644 +--- a/sysdeps/powerpc/powerpc64/multiarch/bzero.c ++++ b/sysdeps/powerpc/powerpc64/multiarch/bzero.c +@@ -27,8 +27,16 @@ extern __typeof (bzero) __bzero_power4 attribute_hidden; + extern __typeof (bzero) __bzero_power6 attribute_hidden; + extern __typeof (bzero) __bzero_power7 attribute_hidden; + extern __typeof (bzero) __bzero_power8 attribute_hidden; ++# ifdef __LITTLE_ENDIAN__ ++extern __typeof (bzero) __bzero_power10 attribute_hidden; ++# endif + + libc_ifunc (__bzero, ++# ifdef __LITTLE_ENDIAN__ ++ (hwcap2 & (PPC_FEATURE2_ARCH_3_1 | PPC_FEATURE2_HAS_ISEL) ++ && hwcap & PPC_FEATURE_HAS_VSX) ++ ? __bzero_power10 : ++# endif + (hwcap2 & PPC_FEATURE2_ARCH_2_07) + ? __bzero_power8 : + (hwcap & PPC_FEATURE_HAS_VSX) +diff --git a/sysdeps/powerpc/powerpc64/multiarch/ifunc-impl-list.c b/sysdeps/powerpc/powerpc64/multiarch/ifunc-impl-list.c +index 9d5a14e480c02171..11532f77d4d03b2a 100644 +--- a/sysdeps/powerpc/powerpc64/multiarch/ifunc-impl-list.c ++++ b/sysdeps/powerpc/powerpc64/multiarch/ifunc-impl-list.c +@@ -86,6 +86,13 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + + /* Support sysdeps/powerpc/powerpc64/multiarch/memset.c. */ + IFUNC_IMPL (i, name, memset, ++#ifdef __LITTLE_ENDIAN__ ++ IFUNC_IMPL_ADD (array, i, memset, ++ hwcap2 & (PPC_FEATURE2_ARCH_3_1 | ++ PPC_FEATURE2_HAS_ISEL) ++ && hwcap & PPC_FEATURE_HAS_VSX, ++ __memset_power10) ++#endif + IFUNC_IMPL_ADD (array, i, memset, hwcap2 & PPC_FEATURE2_ARCH_2_07, + __memset_power8) + IFUNC_IMPL_ADD (array, i, memset, hwcap & PPC_FEATURE_HAS_VSX, +@@ -187,6 +194,13 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + + /* Support sysdeps/powerpc/powerpc64/multiarch/bzero.c. */ + IFUNC_IMPL (i, name, bzero, ++#ifdef __LITTLE_ENDIAN__ ++ IFUNC_IMPL_ADD (array, i, bzero, ++ hwcap2 & (PPC_FEATURE2_ARCH_3_1 | ++ PPC_FEATURE2_HAS_ISEL) ++ && hwcap & PPC_FEATURE_HAS_VSX, ++ __bzero_power10) ++#endif + IFUNC_IMPL_ADD (array, i, bzero, hwcap2 & PPC_FEATURE2_ARCH_2_07, + __bzero_power8) + IFUNC_IMPL_ADD (array, i, bzero, hwcap & PPC_FEATURE_HAS_VSX, +diff --git a/sysdeps/powerpc/powerpc64/multiarch/memset-power10.S b/sysdeps/powerpc/powerpc64/multiarch/memset-power10.S +new file mode 100644 +index 0000000000000000..548e99789735296c +--- /dev/null ++++ b/sysdeps/powerpc/powerpc64/multiarch/memset-power10.S +@@ -0,0 +1,27 @@ ++/* Optimized memset implementation for POWER10 LE. ++ 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 ++ . */ ++ ++#define MEMSET __memset_power10 ++ ++#undef libc_hidden_builtin_def ++#define libc_hidden_builtin_def(name) ++ ++#undef __bzero ++#define __bzero __bzero_power10 ++ ++#include +diff --git a/sysdeps/powerpc/powerpc64/multiarch/memset.c b/sysdeps/powerpc/powerpc64/multiarch/memset.c +index 1a7c46fecf78ab1f..4c97622c7d7eb8aa 100644 +--- a/sysdeps/powerpc/powerpc64/multiarch/memset.c ++++ b/sysdeps/powerpc/powerpc64/multiarch/memset.c +@@ -33,10 +33,18 @@ extern __typeof (__redirect_memset) __memset_power4 attribute_hidden; + extern __typeof (__redirect_memset) __memset_power6 attribute_hidden; + extern __typeof (__redirect_memset) __memset_power7 attribute_hidden; + extern __typeof (__redirect_memset) __memset_power8 attribute_hidden; ++# ifdef __LITTLE_ENDIAN__ ++extern __typeof (__redirect_memset) __memset_power10 attribute_hidden; ++# endif + + /* Avoid DWARF definition DIE on ifunc symbol so that GDB can handle + ifunc symbol properly. */ + libc_ifunc (__libc_memset, ++# ifdef __LITTLE_ENDIAN__ ++ (hwcap2 & (PPC_FEATURE2_ARCH_3_1 | PPC_FEATURE2_HAS_ISEL) ++ && hwcap & PPC_FEATURE_HAS_VSX) ++ ? __memset_power10 : ++# endif + (hwcap2 & PPC_FEATURE2_ARCH_2_07) + ? __memset_power8 : + (hwcap & PPC_FEATURE_HAS_VSX) diff --git a/SOURCES/glibc-rh1956357-7.patch b/SOURCES/glibc-rh1956357-7.patch new file mode 100644 index 0000000..dca81f2 --- /dev/null +++ b/SOURCES/glibc-rh1956357-7.patch @@ -0,0 +1,131 @@ +commit 17a73a6d8b4c46f3e87fc53c7c25fa7cec01d707 +Author: Raoni Fassina Firmino +Date: Mon May 3 16:59:35 2021 -0300 + + powerpc64le: Fix ifunc selection for memset, memmove, bzero and bcopy + + The hwcap2 check for the aforementioned functions should check for + both PPC_FEATURE2_ARCH_3_1 and PPC_FEATURE2_HAS_ISEL but was + mistakenly checking for any one of them, enabling isa 3.1 version of + the functions in incompatible processors, like POWER8. + + Reviewed-by: Tulio Magno Quites Machado Filho + +diff --git a/sysdeps/powerpc/powerpc64/multiarch/bcopy.c b/sysdeps/powerpc/powerpc64/multiarch/bcopy.c +index 705fef33d4e57557..3c6528e5dbccfdbd 100644 +--- a/sysdeps/powerpc/powerpc64/multiarch/bcopy.c ++++ b/sysdeps/powerpc/powerpc64/multiarch/bcopy.c +@@ -28,10 +28,10 @@ extern __typeof (bcopy) __bcopy_power10 attribute_hidden; + + libc_ifunc (bcopy, + #ifdef __LITTLE_ENDIAN__ +- hwcap2 & (PPC_FEATURE2_ARCH_3_1 | +- PPC_FEATURE2_HAS_ISEL) +- && (hwcap & PPC_FEATURE_HAS_VSX) +- ? __bcopy_power10 : ++ (hwcap2 & PPC_FEATURE2_ARCH_3_1 ++ && hwcap2 & PPC_FEATURE2_HAS_ISEL ++ && hwcap & PPC_FEATURE_HAS_VSX) ++ ? __bcopy_power10 : + #endif + (hwcap & PPC_FEATURE_HAS_VSX) + ? __bcopy_power7 +diff --git a/sysdeps/powerpc/powerpc64/multiarch/bzero.c b/sysdeps/powerpc/powerpc64/multiarch/bzero.c +index 4ce98e324d12a31e..b08b381b4a3999f1 100644 +--- a/sysdeps/powerpc/powerpc64/multiarch/bzero.c ++++ b/sysdeps/powerpc/powerpc64/multiarch/bzero.c +@@ -33,7 +33,8 @@ extern __typeof (bzero) __bzero_power10 attribute_hidden; + + libc_ifunc (__bzero, + # ifdef __LITTLE_ENDIAN__ +- (hwcap2 & (PPC_FEATURE2_ARCH_3_1 | PPC_FEATURE2_HAS_ISEL) ++ (hwcap2 & PPC_FEATURE2_ARCH_3_1 ++ && hwcap2 & PPC_FEATURE2_HAS_ISEL + && hwcap & PPC_FEATURE_HAS_VSX) + ? __bzero_power10 : + # endif +diff --git a/sysdeps/powerpc/powerpc64/multiarch/ifunc-impl-list.c b/sysdeps/powerpc/powerpc64/multiarch/ifunc-impl-list.c +index 11532f77d4d03b2a..6e36659d1903448a 100644 +--- a/sysdeps/powerpc/powerpc64/multiarch/ifunc-impl-list.c ++++ b/sysdeps/powerpc/powerpc64/multiarch/ifunc-impl-list.c +@@ -75,9 +75,9 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + IFUNC_IMPL (i, name, memmove, + #ifdef __LITTLE_ENDIAN__ + IFUNC_IMPL_ADD (array, i, memmove, +- hwcap2 & (PPC_FEATURE2_ARCH_3_1 | +- PPC_FEATURE2_HAS_ISEL) +- && (hwcap & PPC_FEATURE_HAS_VSX), ++ hwcap2 & PPC_FEATURE2_ARCH_3_1 ++ && hwcap2 & PPC_FEATURE2_HAS_ISEL ++ && hwcap & PPC_FEATURE_HAS_VSX, + __memmove_power10) + #endif + IFUNC_IMPL_ADD (array, i, memmove, hwcap & PPC_FEATURE_HAS_VSX, +@@ -88,8 +88,8 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + IFUNC_IMPL (i, name, memset, + #ifdef __LITTLE_ENDIAN__ + IFUNC_IMPL_ADD (array, i, memset, +- hwcap2 & (PPC_FEATURE2_ARCH_3_1 | +- PPC_FEATURE2_HAS_ISEL) ++ hwcap2 & PPC_FEATURE2_ARCH_3_1 ++ && hwcap2 & PPC_FEATURE2_HAS_ISEL + && hwcap & PPC_FEATURE_HAS_VSX, + __memset_power10) + #endif +@@ -196,8 +196,8 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + IFUNC_IMPL (i, name, bzero, + #ifdef __LITTLE_ENDIAN__ + IFUNC_IMPL_ADD (array, i, bzero, +- hwcap2 & (PPC_FEATURE2_ARCH_3_1 | +- PPC_FEATURE2_HAS_ISEL) ++ hwcap2 & PPC_FEATURE2_ARCH_3_1 ++ && hwcap2 & PPC_FEATURE2_HAS_ISEL + && hwcap & PPC_FEATURE_HAS_VSX, + __bzero_power10) + #endif +@@ -215,9 +215,9 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + IFUNC_IMPL (i, name, bcopy, + #ifdef __LITTLE_ENDIAN__ + IFUNC_IMPL_ADD (array, i, bcopy, +- hwcap2 & (PPC_FEATURE2_ARCH_3_1 | +- PPC_FEATURE2_HAS_ISEL) +- && (hwcap & PPC_FEATURE_HAS_VSX), ++ hwcap2 & PPC_FEATURE2_ARCH_3_1 ++ && hwcap2 & PPC_FEATURE2_HAS_ISEL ++ && hwcap & PPC_FEATURE_HAS_VSX, + __bcopy_power10) + #endif + IFUNC_IMPL_ADD (array, i, bcopy, hwcap & PPC_FEATURE_HAS_VSX, +diff --git a/sysdeps/powerpc/powerpc64/multiarch/memmove.c b/sysdeps/powerpc/powerpc64/multiarch/memmove.c +index 2fd7b6d309e4bedd..27895faad0cab40e 100644 +--- a/sysdeps/powerpc/powerpc64/multiarch/memmove.c ++++ b/sysdeps/powerpc/powerpc64/multiarch/memmove.c +@@ -36,10 +36,10 @@ extern __typeof (__redirect_memmove) __memmove_power10 attribute_hidden; + + libc_ifunc (__libc_memmove, + #ifdef __LITTLE_ENDIAN__ +- hwcap2 & (PPC_FEATURE2_ARCH_3_1 | +- PPC_FEATURE2_HAS_ISEL) +- && (hwcap & PPC_FEATURE_HAS_VSX) +- ? __memmove_power10 : ++ (hwcap2 & PPC_FEATURE2_ARCH_3_1 ++ && hwcap2 & PPC_FEATURE2_HAS_ISEL ++ && hwcap & PPC_FEATURE_HAS_VSX) ++ ? __memmove_power10 : + #endif + (hwcap & PPC_FEATURE_HAS_VSX) + ? __memmove_power7 +diff --git a/sysdeps/powerpc/powerpc64/multiarch/memset.c b/sysdeps/powerpc/powerpc64/multiarch/memset.c +index 4c97622c7d7eb8aa..685623ae870a0725 100644 +--- a/sysdeps/powerpc/powerpc64/multiarch/memset.c ++++ b/sysdeps/powerpc/powerpc64/multiarch/memset.c +@@ -41,7 +41,8 @@ extern __typeof (__redirect_memset) __memset_power10 attribute_hidden; + ifunc symbol properly. */ + libc_ifunc (__libc_memset, + # ifdef __LITTLE_ENDIAN__ +- (hwcap2 & (PPC_FEATURE2_ARCH_3_1 | PPC_FEATURE2_HAS_ISEL) ++ (hwcap2 & PPC_FEATURE2_ARCH_3_1 ++ && hwcap2 & PPC_FEATURE2_HAS_ISEL + && hwcap & PPC_FEATURE_HAS_VSX) + ? __memset_power10 : + # endif diff --git a/SOURCES/glibc-rh1956357-8.patch b/SOURCES/glibc-rh1956357-8.patch new file mode 100644 index 0000000..beee664 --- /dev/null +++ b/SOURCES/glibc-rh1956357-8.patch @@ -0,0 +1,387 @@ +commit 1a594aa986ffe28657a03baa5c53c0a0e7dc2ecd +Author: Matheus Castanho +Date: Tue May 11 17:53:07 2021 -0300 + + powerpc: Add optimized rawmemchr for POWER10 + + Reuse code for optimized strlen to implement a faster version of rawmemchr. + This takes advantage of the same benefits provided by the strlen implementation, + but needs some extra steps. __strlen_power10 code should be unchanged after this + change. + + rawmemchr returns a pointer to the char found, while strlen returns only the + length, so we have to take that into account when preparing the return value. + + To quickly check 64B, the loop on __strlen_power10 merges the whole block into + 16B by using unsigned minimum vector operations (vminub) and checks if there are + any \0 on the resulting vector. The same code is used by rawmemchr if the char c + is 0. However, this approach does not work when c != 0. We first need to + subtract each byte by c, so that the value we are looking for is converted to a + 0, then taking the minimum and checking for nulls works again. + + The new code branches after it has compared ~256 bytes and chooses which of the + two strategies above will be used in the main loop, based on the char c. This + extra branch adds some overhead (~5%) for length ~256, but is quickly amortized + by the faster loop for larger sizes. + + Compared to __rawmemchr_power9, this version is ~20% faster for length < 256. + Because of the optimized main loop, the improvement becomes ~35% for c != 0 + and ~50% for c = 0 for strings longer than 256. + + Reviewed-by: Lucas A. M. Magalhaes + Reviewed-by: Raphael M Zinsly + +diff --git a/sysdeps/powerpc/powerpc64/le/power10/rawmemchr.S b/sysdeps/powerpc/powerpc64/le/power10/rawmemchr.S +new file mode 100644 +index 0000000000000000..5351c2634f6086bf +--- /dev/null ++++ b/sysdeps/powerpc/powerpc64/le/power10/rawmemchr.S +@@ -0,0 +1,22 @@ ++/* Optimized rawmemchr implementation for POWER10 LE. ++ 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 ++ ++#define USE_AS_RAWMEMCHR 1 ++#include +diff --git a/sysdeps/powerpc/powerpc64/le/power10/strlen.S b/sysdeps/powerpc/powerpc64/le/power10/strlen.S +index ca7e9eb3d84c9b00..dda5282f1b9a07cf 100644 +--- a/sysdeps/powerpc/powerpc64/le/power10/strlen.S ++++ b/sysdeps/powerpc/powerpc64/le/power10/strlen.S +@@ -18,10 +18,50 @@ + + #include + +-#ifndef STRLEN +-# define STRLEN __strlen +-# define DEFINE_STRLEN_HIDDEN_DEF 1 +-#endif ++/* To reuse the code for rawmemchr, we have some extra steps compared to the ++ strlen implementation: ++ - Sum the initial value of r3 with the position at which the char was ++ found, to guarantee we return a pointer and not the length. ++ - In the main loop, subtract each byte by the char we are looking for, ++ so we can keep using vminub to quickly check 64B at once. */ ++#ifdef USE_AS_RAWMEMCHR ++# ifndef RAWMEMCHR ++# define FUNCNAME __rawmemchr ++# else ++# define FUNCNAME RAWMEMCHR ++# endif ++# define MCOUNT_NARGS 2 ++# define VREG_ZERO v20 ++# define OFF_START_LOOP 256 ++# define RAWMEMCHR_SUBTRACT_VECTORS \ ++ vsububm v4,v4,v18; \ ++ vsububm v5,v5,v18; \ ++ vsububm v6,v6,v18; \ ++ vsububm v7,v7,v18; ++# define TAIL(vreg,increment) \ ++ vctzlsbb r4,vreg; \ ++ addi r4,r4,increment; \ ++ add r3,r5,r4; \ ++ blr ++ ++#else /* strlen */ ++ ++# ifndef STRLEN ++# define FUNCNAME __strlen ++# define DEFINE_STRLEN_HIDDEN_DEF 1 ++# else ++# define FUNCNAME STRLEN ++# endif ++# define MCOUNT_NARGS 1 ++# define VREG_ZERO v18 ++# define OFF_START_LOOP 192 ++# define TAIL(vreg,increment) \ ++ vctzlsbb r4,vreg; \ ++ subf r3,r3,r5; \ ++ addi r4,r4,increment; \ ++ add r3,r3,r4; \ ++ blr ++#endif /* USE_AS_RAWMEMCHR */ + + /* TODO: Replace macros by the actual instructions when minimum binutils becomes + >= 2.35. This is used to keep compatibility with older versions. */ +@@ -50,33 +90,41 @@ + li r6,offset; \ + LXVP(v4+32,offset,addr); \ + LXVP(v6+32,offset+32,addr); \ ++ RAWMEMCHR_SUBTRACT_VECTORS; \ + vminub v14,v4,v5; \ + vminub v15,v6,v7; \ + vminub v16,v14,v15; \ +- vcmpequb. v0,v16,v18; \ ++ vcmpequb. v0,v16,VREG_ZERO; \ + bne cr6,L(label) + +-#define TAIL(vreg,increment) \ +- vctzlsbb r4,vreg; \ +- subf r3,r3,r5; \ +- addi r4,r4,increment; \ +- add r3,r3,r4; \ +- blr +- + /* Implements the function + + int [r3] strlen (const void *s [r3]) + ++ but when USE_AS_RAWMEMCHR is set, implements the function ++ ++ void* [r3] rawmemchr (const void *s [r3], int c [r4]) ++ + The implementation can load bytes past a matching byte, but only + up to the next 64B boundary, so it never crosses a page. */ + + .machine power9 + +-ENTRY_TOCLESS (STRLEN, 4) +- CALL_MCOUNT 1 ++ENTRY_TOCLESS (FUNCNAME, 4) ++ CALL_MCOUNT MCOUNT_NARGS + +- vspltisb v18,0 ++#ifdef USE_AS_RAWMEMCHR ++ xori r5,r4,0xff ++ ++ mtvsrd v18+32,r4 /* matching char in v18 */ ++ mtvsrd v19+32,r5 /* non matching char in v19 */ ++ ++ vspltb v18,v18,7 /* replicate */ ++ vspltb v19,v19,7 /* replicate */ ++#else + vspltisb v19,-1 ++#endif ++ vspltisb VREG_ZERO,0 + + /* Next 16B-aligned address. Prepare address for L(aligned). */ + addi r5,r3,16 +@@ -90,16 +138,25 @@ ENTRY_TOCLESS (STRLEN, 4) + vcmpequb. v6,v0,v18 + beq cr6,L(aligned) + ++#ifdef USE_AS_RAWMEMCHR ++ vctzlsbb r6,v6 ++ add r3,r3,r6 ++#else + vctzlsbb r3,v6 ++#endif + blr + +- /* Test next 176B, 16B at a time. The main loop is optimized for longer +- strings, so checking the first bytes in 16B chunks benefits a lot +- small strings. */ ++ /* Test up to OFF_START_LOOP-16 bytes in 16B chunks. The main loop is ++ optimized for longer strings, so checking the first bytes in 16B ++ chunks benefits a lot small strings. */ + .p2align 5 + L(aligned): ++#ifdef USE_AS_RAWMEMCHR ++ cmpdi cr5,r4,0 /* Check if c == 0. This will be useful to ++ choose how we will perform the main loop. */ ++#endif + /* Prepare address for the loop. */ +- addi r4,r3,192 ++ addi r4,r3,OFF_START_LOOP + clrrdi r4,r4,6 + + CHECK16(v0,0,r5,tail1) +@@ -113,15 +170,43 @@ L(aligned): + CHECK16(v8,128,r5,tail9) + CHECK16(v9,144,r5,tail10) + CHECK16(v10,160,r5,tail11) ++#ifdef USE_AS_RAWMEMCHR ++ CHECK16(v0,176,r5,tail12) ++ CHECK16(v1,192,r5,tail13) ++ CHECK16(v2,208,r5,tail14) ++ CHECK16(v3,224,r5,tail15) ++#endif + + addi r5,r4,128 + ++#ifdef USE_AS_RAWMEMCHR ++ /* If c == 0, use the same loop as strlen, without the vsububm. */ ++ beq cr5,L(loop) ++ ++ /* This is very similar to the block after L(loop), the difference is ++ that here RAWMEMCHR_SUBTRACT_VECTORS is not empty, and we subtract ++ each byte loaded by the char we are looking for, this way we can keep ++ using vminub to merge the results and checking for nulls. */ ++ .p2align 5 ++L(rawmemchr_loop): ++ CHECK64(0,r4,pre_tail_64b) ++ CHECK64(64,r4,pre_tail_64b) ++ addi r4,r4,256 ++ ++ CHECK64(0,r5,tail_64b) ++ CHECK64(64,r5,tail_64b) ++ addi r5,r5,256 ++ ++ b L(rawmemchr_loop) ++#endif + /* Switch to a more aggressive approach checking 64B each time. Use 2 + pointers 128B apart and unroll the loop once to make the pointer + updates and usages separated enough to avoid stalls waiting for + address calculation. */ + .p2align 5 + L(loop): ++#undef RAWMEMCHR_SUBTRACT_VECTORS ++#define RAWMEMCHR_SUBTRACT_VECTORS /* nothing */ + CHECK64(0,r4,pre_tail_64b) + CHECK64(64,r4,pre_tail_64b) + addi r4,r4,256 +@@ -140,10 +225,10 @@ L(tail_64b): + block and mark it in its corresponding VR. lxvp vx,0(ry) puts the + low 16B bytes into vx+1, and the high into vx, so the order here is + v5, v4, v7, v6. */ +- vcmpequb v1,v5,v18 +- vcmpequb v2,v4,v18 +- vcmpequb v3,v7,v18 +- vcmpequb v4,v6,v18 ++ vcmpequb v1,v5,VREG_ZERO ++ vcmpequb v2,v4,VREG_ZERO ++ vcmpequb v3,v7,VREG_ZERO ++ vcmpequb v4,v6,VREG_ZERO + + /* Take into account the other 64B blocks we had already checked. */ + add r5,r5,r6 +@@ -165,7 +250,9 @@ L(tail_64b): + or r10,r8,r7 + + cnttzd r0,r10 /* Count trailing zeros before the match. */ ++#ifndef USE_AS_RAWMEMCHR + subf r5,r3,r5 ++#endif + add r3,r5,r0 /* Compute final length. */ + blr + +@@ -213,9 +300,32 @@ L(tail10): + L(tail11): + TAIL(v10,160) + +-END (STRLEN) ++#ifdef USE_AS_RAWMEMCHR ++ .p2align 5 ++L(tail12): ++ TAIL(v0,176) ++ ++ .p2align 5 ++L(tail13): ++ TAIL(v1,192) ++ ++ .p2align 5 ++L(tail14): ++ TAIL(v2,208) ++ ++ .p2align 5 ++L(tail15): ++ TAIL(v3,224) ++#endif ++ ++END (FUNCNAME) + +-#ifdef DEFINE_STRLEN_HIDDEN_DEF ++#ifdef USE_AS_RAWMEMCHR ++weak_alias (__rawmemchr,rawmemchr) ++libc_hidden_builtin_def (__rawmemchr) ++#else ++# ifdef DEFINE_STRLEN_HIDDEN_DEF + weak_alias (__strlen, strlen) + libc_hidden_builtin_def (strlen) ++# endif + #endif +diff --git a/sysdeps/powerpc/powerpc64/multiarch/Makefile b/sysdeps/powerpc/powerpc64/multiarch/Makefile +index 1d517698429e1230..ac2446aca62cc4ab 100644 +--- a/sysdeps/powerpc/powerpc64/multiarch/Makefile ++++ b/sysdeps/powerpc/powerpc64/multiarch/Makefile +@@ -33,9 +33,9 @@ sysdep_routines += memcpy-power8-cached memcpy-power7 memcpy-a2 memcpy-power6 \ + + ifneq (,$(filter %le,$(config-machine))) + sysdep_routines += memcpy-power10 memmove-power10 memset-power10 \ ++ rawmemchr-power9 rawmemchr-power10 \ + strcmp-power9 strncmp-power9 strcpy-power9 stpcpy-power9 \ +- rawmemchr-power9 strlen-power9 strncpy-power9 stpncpy-power9 \ +- strlen-power10 ++ strlen-power9 strncpy-power9 stpncpy-power9 strlen-power10 + endif + CFLAGS-strncase-power7.c += -mcpu=power7 -funroll-loops + CFLAGS-strncase_l-power7.c += -mcpu=power7 -funroll-loops +diff --git a/sysdeps/powerpc/powerpc64/multiarch/ifunc-impl-list.c b/sysdeps/powerpc/powerpc64/multiarch/ifunc-impl-list.c +index 6e36659d1903448a..127af84b32a8196f 100644 +--- a/sysdeps/powerpc/powerpc64/multiarch/ifunc-impl-list.c ++++ b/sysdeps/powerpc/powerpc64/multiarch/ifunc-impl-list.c +@@ -257,6 +257,10 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + /* Support sysdeps/powerpc/powerpc64/multiarch/rawmemchr.c. */ + IFUNC_IMPL (i, name, rawmemchr, + #ifdef __LITTLE_ENDIAN__ ++ IFUNC_IMPL_ADD (array, i, rawmemchr, ++ (hwcap2 & PPC_FEATURE2_ARCH_3_1) ++ && (hwcap & PPC_FEATURE_HAS_VSX), ++ __rawmemchr_power10) + IFUNC_IMPL_ADD (array, i, rawmemchr, + hwcap2 & PPC_FEATURE2_ARCH_3_00, + __rawmemchr_power9) +diff --git a/sysdeps/powerpc/powerpc64/multiarch/rawmemchr-power10.S b/sysdeps/powerpc/powerpc64/multiarch/rawmemchr-power10.S +new file mode 100644 +index 0000000000000000..bf1ed7e1941f922d +--- /dev/null ++++ b/sysdeps/powerpc/powerpc64/multiarch/rawmemchr-power10.S +@@ -0,0 +1,21 @@ ++/* Optimized rawmemchr implementation for PowerPC64/POWER10. ++ 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 ++ . */ ++ ++#define RAWMEMCHR __rawmemchr_power10 ++ ++#include +diff --git a/sysdeps/powerpc/powerpc64/multiarch/rawmemchr.c b/sysdeps/powerpc/powerpc64/multiarch/rawmemchr.c +index 2a7ae5a1ed02e556..369d6359e8987052 100644 +--- a/sysdeps/powerpc/powerpc64/multiarch/rawmemchr.c ++++ b/sysdeps/powerpc/powerpc64/multiarch/rawmemchr.c +@@ -26,6 +26,7 @@ extern __typeof (__rawmemchr) __rawmemchr_ppc attribute_hidden; + extern __typeof (__rawmemchr) __rawmemchr_power7 attribute_hidden; + # ifdef __LITTLE_ENDIAN__ + extern __typeof (__rawmemchr) __rawmemchr_power9 attribute_hidden; ++extern __typeof (__rawmemchr) __rawmemchr_power10 attribute_hidden; + # endif + + # undef __rawmemchr +@@ -34,6 +35,9 @@ extern __typeof (__rawmemchr) __rawmemchr_power9 attribute_hidden; + ifunc symbol properly. */ + libc_ifunc_redirected (__redirect___rawmemchr, __rawmemchr, + # ifdef __LITTLE_ENDIAN__ ++ (hwcap2 & PPC_FEATURE2_ARCH_3_1) ++ && (hwcap & PPC_FEATURE_HAS_VSX) ++ ? __rawmemchr_power10 : + (hwcap2 & PPC_FEATURE2_ARCH_3_00) + ? __rawmemchr_power9 : + # endif diff --git a/SOURCES/glibc-rh1961109.patch b/SOURCES/glibc-rh1961109.patch new file mode 100644 index 0000000..e47c4d7 --- /dev/null +++ b/SOURCES/glibc-rh1961109.patch @@ -0,0 +1,165 @@ +commit f17164bd51db31f47fbbdae826c63b6d78184c45 +Author: Florian Weimer +Date: Tue May 18 07:21:33 2021 +0200 + + localedata: Use U+00AF MACRON in more EBCDIC charsets [BZ #27882] + + This updates IBM256, IBM277, IBM278, IBM280, IBM284, IBM297, IBM424 + in the same way that IBM273 was updated for bug 23290. + + IBM256 and IBM424 still have holes after this change, so HAS_HOLES + is not updated. + + Reviewed-by: Siddhesh Poyarekar + +diff --git a/iconvdata/ibm277.c b/iconvdata/ibm277.c +index f93ca2acb8718dd5..0e337dbbdc06a02f 100644 +--- a/iconvdata/ibm277.c ++++ b/iconvdata/ibm277.c +@@ -23,6 +23,6 @@ + #define TABLES + + #define CHARSET_NAME "IBM277//" +-#define HAS_HOLES 1 /* Not all 256 character are defined. */ ++#define HAS_HOLES 0 + + #include <8bit-gap.c> +diff --git a/iconvdata/ibm278.c b/iconvdata/ibm278.c +index 4263000760472913..7450fb8e5b846101 100644 +--- a/iconvdata/ibm278.c ++++ b/iconvdata/ibm278.c +@@ -23,6 +23,6 @@ + #define TABLES + + #define CHARSET_NAME "IBM278//" +-#define HAS_HOLES 1 /* Not all 256 character are defined. */ ++#define HAS_HOLES 0 + + #include <8bit-gap.c> +diff --git a/iconvdata/ibm280.c b/iconvdata/ibm280.c +index 3efddd7dec2728d9..2ea5478e4e0d7007 100644 +--- a/iconvdata/ibm280.c ++++ b/iconvdata/ibm280.c +@@ -23,6 +23,6 @@ + #define TABLES + + #define CHARSET_NAME "IBM280//" +-#define HAS_HOLES 1 /* Not all 256 character are defined. */ ++#define HAS_HOLES 0 + + #include <8bit-gap.c> +diff --git a/iconvdata/ibm284.c b/iconvdata/ibm284.c +index 57dab27d0cec4a33..8dbbc6344d18528f 100644 +--- a/iconvdata/ibm284.c ++++ b/iconvdata/ibm284.c +@@ -23,6 +23,6 @@ + #define TABLES + + #define CHARSET_NAME "IBM284//" +-#define HAS_HOLES 1 /* Not all 256 character are defined. */ ++#define HAS_HOLES 0 + + #include <8bit-gap.c> +diff --git a/iconvdata/ibm297.c b/iconvdata/ibm297.c +index f355659afd4b4502..81e63ba1f28f1548 100644 +--- a/iconvdata/ibm297.c ++++ b/iconvdata/ibm297.c +@@ -23,6 +23,6 @@ + #define TABLES + + #define CHARSET_NAME "IBM297//" +-#define HAS_HOLES 1 /* Not all 256 character are defined. */ ++#define HAS_HOLES 0 + + #include <8bit-gap.c> +diff --git a/localedata/charmaps/IBM256 b/localedata/charmaps/IBM256 +index 5cfd2db5f436cd07..bdc1abf0ade3bfc4 100644 +--- a/localedata/charmaps/IBM256 ++++ b/localedata/charmaps/IBM256 +@@ -194,7 +194,7 @@ CHARMAP + /xb9 VULGAR FRACTION THREE QUARTERS + /xba NOT SIGN + /xbb VERTICAL LINE +- /xbc OVERLINE ++ /xbc MACRON + /xbd DIAERESIS + /xbe ACUTE ACCENT + /xbf DOUBLE LOW LINE +diff --git a/localedata/charmaps/IBM277 b/localedata/charmaps/IBM277 +index 1c0b5cb9fb659364..2f6e3992109a2b33 100644 +--- a/localedata/charmaps/IBM277 ++++ b/localedata/charmaps/IBM277 +@@ -195,7 +195,7 @@ CHARMAP + /xb9 VULGAR FRACTION THREE QUARTERS + /xba NOT SIGN + /xbb VERTICAL LINE +- /xbc OVERLINE ++ /xbc MACRON + /xbd DIAERESIS + /xbe ACUTE ACCENT + /xbf MULTIPLICATION SIGN +diff --git a/localedata/charmaps/IBM278 b/localedata/charmaps/IBM278 +index 646961501c74c4df..bdfae7621028f003 100644 +--- a/localedata/charmaps/IBM278 ++++ b/localedata/charmaps/IBM278 +@@ -196,7 +196,7 @@ CHARMAP + /xb9 VULGAR FRACTION THREE QUARTERS + /xba NOT SIGN + /xbb VERTICAL LINE +- /xbc OVERLINE ++ /xbc MACRON + /xbd DIAERESIS + /xbe ACUTE ACCENT + /xbf MULTIPLICATION SIGN +diff --git a/localedata/charmaps/IBM280 b/localedata/charmaps/IBM280 +index 5de3b3e7b96796c0..4c31242806b0ac19 100644 +--- a/localedata/charmaps/IBM280 ++++ b/localedata/charmaps/IBM280 +@@ -195,7 +195,7 @@ CHARMAP + /xb9 VULGAR FRACTION THREE QUARTERS + /xba NOT SIGN + /xbb VERTICAL LINE +- /xbc OVERLINE ++ /xbc MACRON + /xbd DIAERESIS + /xbe ACUTE ACCENT + /xbf MULTIPLICATION SIGN +diff --git a/localedata/charmaps/IBM284 b/localedata/charmaps/IBM284 +index c64b2a65ab748540..46a8737a715e4e56 100644 +--- a/localedata/charmaps/IBM284 ++++ b/localedata/charmaps/IBM284 +@@ -195,7 +195,7 @@ CHARMAP + /xb9 VULGAR FRACTION THREE QUARTERS + /xba CIRCUMFLEX ACCENT + /xbb EXCLAMATION MARK +- /xbc OVERLINE ++ /xbc MACRON + /xbd TILDE + /xbe ACUTE ACCENT + /xbf MULTIPLICATION SIGN +diff --git a/localedata/charmaps/IBM297 b/localedata/charmaps/IBM297 +index 33b74eee437241aa..14361ad418cf1bc7 100644 +--- a/localedata/charmaps/IBM297 ++++ b/localedata/charmaps/IBM297 +@@ -195,7 +195,7 @@ CHARMAP + /xb9 VULGAR FRACTION THREE QUARTERS + /xba NOT SIGN + /xbb VERTICAL LINE +- /xbc OVERLINE ++ /xbc MACRON + /xbd TILDE + /xbe ACUTE ACCENT + /xbf MULTIPLICATION SIGN +diff --git a/localedata/charmaps/IBM424 b/localedata/charmaps/IBM424 +index 883e43b8ae04ee4c..deca11e1b18ec0a6 100644 +--- a/localedata/charmaps/IBM424 ++++ b/localedata/charmaps/IBM424 +@@ -175,7 +175,7 @@ CHARMAP + /xb9 VULGAR FRACTION THREE QUARTERS + /xba LEFT SQUARE BRACKET + /xbb RIGHT SQUARE BRACKET +- /xbc OVERLINE ++ /xbc MACRON + /xbd DIAERESIS + /xbe ACUTE ACCENT + /xbf MULTIPLICATION SIGN diff --git a/SOURCES/glibc-rh1966472-1.patch b/SOURCES/glibc-rh1966472-1.patch new file mode 100644 index 0000000..ecccfeb --- /dev/null +++ b/SOURCES/glibc-rh1966472-1.patch @@ -0,0 +1,159 @@ +nptl: Add __pthread_attr_copy for copying pthread_attr_t objects + +Also add the private type union pthread_attr_transparent, to reduce +the amount of casting that is required. + +Reviewed-by: Carlos O'Donell +Tested-by: Carlos O'Donell +(cherry picked from commit 331c6e8a184167dd21a9f0b3fc165aeefea6eeca) + +Difference from upstream: +Unlike upstream, __pthread_attr_copy is in libpthread.so. + +# Conflicts: +# nptl/Makefile +# nptl/Versions + +diff --git a/nptl/Makefile b/nptl/Makefile +index d6b37b6efd3b7d78..b14de3ffb330c10b 100644 +--- a/nptl/Makefile ++++ b/nptl/Makefile +@@ -54,7 +54,8 @@ libpthread-routines = nptl-init nptlfreeres vars events version pt-interp \ + pthread_getconcurrency pthread_setconcurrency \ + pthread_getschedparam pthread_setschedparam \ + pthread_setschedprio \ +- pthread_attr_init pthread_attr_destroy \ ++ pthread_attr_init pthread_attr_copy \ ++ pthread_attr_destroy \ + pthread_attr_getdetachstate pthread_attr_setdetachstate \ + pthread_attr_getguardsize pthread_attr_setguardsize \ + pthread_attr_getschedparam pthread_attr_setschedparam \ +diff --git a/nptl/Versions b/nptl/Versions +index 6007fd03e7ed117c..e38272aa187fbe78 100644 +--- a/nptl/Versions ++++ b/nptl/Versions +@@ -283,5 +283,6 @@ libpthread { + __pthread_barrier_init; __pthread_barrier_wait; + __shm_directory; + __libpthread_freeres; ++ __pthread_attr_copy; + } + } +diff --git a/nptl/pthreadP.h b/nptl/pthreadP.h +index 00be8f92793e8710..a2d48b2015cd385c 100644 +--- a/nptl/pthreadP.h ++++ b/nptl/pthreadP.h +@@ -464,6 +464,9 @@ extern int __pthread_attr_getstack (const pthread_attr_t *__restrict __attr, + size_t *__restrict __stacksize); + extern int __pthread_attr_setstack (pthread_attr_t *__attr, void *__stackaddr, + size_t __stacksize); ++extern int __pthread_attr_setaffinity_np (pthread_attr_t *attr, ++ size_t cpusetsize, ++ const cpu_set_t *cpuset); + extern int __pthread_rwlock_init (pthread_rwlock_t *__restrict __rwlock, + const pthread_rwlockattr_t *__restrict + __attr); +@@ -605,6 +608,11 @@ extern void __wait_lookup_done (void) attribute_hidden; + # define PTHREAD_STATIC_FN_REQUIRE(name) __asm (".globl " #name); + #endif + ++/* Make a deep copy of the attribute *SOURCE in *TARGET. *TARGET is ++ not assumed to have been initialized. Returns 0 on success, or a ++ positive error code otherwise. */ ++int __pthread_attr_copy (pthread_attr_t *target, const pthread_attr_t *source); ++ + /* Returns 0 if POL is a valid scheduling policy. */ + static inline int + check_sched_policy_attr (int pol) +diff --git a/nptl/pthread_attr_copy.c b/nptl/pthread_attr_copy.c +new file mode 100644 +index 0000000000000000..67f272acf297100c +--- /dev/null ++++ b/nptl/pthread_attr_copy.c +@@ -0,0 +1,56 @@ ++/* Deep copy of a pthread_attr_t object. ++ 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 ++ ++int ++__pthread_attr_copy (pthread_attr_t *target, const pthread_attr_t *source) ++{ ++ /* Avoid overwriting *TARGET until all allocations have ++ succeeded. */ ++ union pthread_attr_transparent temp; ++ temp.external = *source; ++ ++ /* Force new allocation. This function has full ownership of temp. */ ++ temp.internal.cpuset = NULL; ++ temp.internal.cpusetsize = 0; ++ ++ int ret = 0; ++ ++ struct pthread_attr *isource = (struct pthread_attr *) source; ++ ++ /* Propagate affinity mask information. */ ++ if (isource->cpusetsize > 0) ++ ret = __pthread_attr_setaffinity_np (&temp.external, ++ isource->cpusetsize, ++ isource->cpuset); ++ ++ if (ret != 0) ++ { ++ /* Deallocate because we have ownership. */ ++ __pthread_attr_destroy (&temp.external); ++ return ret; ++ } ++ ++ /* Transfer ownership. *target is not assumed to have been ++ initialized. */ ++ *target = temp.external; ++ return 0; ++} +diff --git a/nptl/pthread_attr_setaffinity.c b/nptl/pthread_attr_setaffinity.c +index 545b72c91e290216..914ebf6f9cbfd5ff 100644 +--- a/nptl/pthread_attr_setaffinity.c ++++ b/nptl/pthread_attr_setaffinity.c +@@ -55,6 +55,7 @@ __pthread_attr_setaffinity_new (pthread_attr_t *attr, size_t cpusetsize, + + return 0; + } ++strong_alias (__pthread_attr_setaffinity_new, __pthread_attr_setaffinity_np) + versioned_symbol (libpthread, __pthread_attr_setaffinity_new, + pthread_attr_setaffinity_np, GLIBC_2_3_4); + +diff --git a/sysdeps/nptl/internaltypes.h b/sysdeps/nptl/internaltypes.h +index b78ad99a888b4e3b..d3dce1278de989e2 100644 +--- a/sysdeps/nptl/internaltypes.h ++++ b/sysdeps/nptl/internaltypes.h +@@ -49,6 +49,13 @@ struct pthread_attr + #define ATTR_FLAG_SCHED_SET 0x0020 + #define ATTR_FLAG_POLICY_SET 0x0040 + ++/* Used to allocate a pthread_attr_t object which is also accessed ++ internally. */ ++union pthread_attr_transparent ++{ ++ pthread_attr_t external; ++ struct pthread_attr internal; ++}; + + /* Mutex attribute data structure. */ + struct pthread_mutexattr diff --git a/SOURCES/glibc-rh1966472-2.patch b/SOURCES/glibc-rh1966472-2.patch new file mode 100644 index 0000000..014f62a --- /dev/null +++ b/SOURCES/glibc-rh1966472-2.patch @@ -0,0 +1,50 @@ +Use __pthread_attr_copy in mq_notify (bug 27896) + +Make a deep copy of the pthread attribute object to remove a potential +use-after-free issue. + +(cherry picked from commit 42d359350510506b87101cf77202fefcbfc790cb) + +# Conflicts: +# NEWS + +diff --git a/sysdeps/unix/sysv/linux/mq_notify.c b/sysdeps/unix/sysv/linux/mq_notify.c +index 3563e82cd4f4b552..c4091169306ffde8 100644 +--- a/sysdeps/unix/sysv/linux/mq_notify.c ++++ b/sysdeps/unix/sysv/linux/mq_notify.c +@@ -135,8 +135,11 @@ helper_thread (void *arg) + (void) __pthread_barrier_wait (¬ify_barrier); + } + else if (data.raw[NOTIFY_COOKIE_LEN - 1] == NOTIFY_REMOVED) +- /* The only state we keep is the copy of the thread attributes. */ +- free (data.attr); ++ { ++ /* The only state we keep is the copy of the thread attributes. */ ++ pthread_attr_destroy (data.attr); ++ free (data.attr); ++ } + } + return NULL; + } +@@ -257,8 +260,7 @@ mq_notify (mqd_t mqdes, const struct sigevent *notification) + if (data.attr == NULL) + return -1; + +- memcpy (data.attr, notification->sigev_notify_attributes, +- sizeof (pthread_attr_t)); ++ __pthread_attr_copy (data.attr, notification->sigev_notify_attributes); + } + + /* Construct the new request. */ +@@ -272,7 +274,10 @@ mq_notify (mqd_t mqdes, const struct sigevent *notification) + + /* If it failed, free the allocated memory. */ + if (__glibc_unlikely (retval != 0)) +- free (data.attr); ++ { ++ pthread_attr_destroy (data.attr); ++ free (data.attr); ++ } + + return retval; + } diff --git a/SOURCES/glibc-rh1966472-3.patch b/SOURCES/glibc-rh1966472-3.patch new file mode 100644 index 0000000..23d704f --- /dev/null +++ b/SOURCES/glibc-rh1966472-3.patch @@ -0,0 +1,44 @@ +Fix use of __pthread_attr_copy in mq_notify (bug 27896) + +__pthread_attr_copy can fail and does not initialize the attribute +structure in that case. + +If __pthread_attr_copy is never called and there is no allocated +attribute, pthread_attr_destroy should not be called, otherwise +there is a null pointer dereference in rt/tst-mqueue6. + +Fixes commit 42d359350510506b87101cf77202fefcbfc790cb +("Use __pthread_attr_copy in mq_notify (bug 27896)"). + +Reviewed-by: Siddhesh Poyarekar +(cherry picked from commit 217b6dc298156bdb0d6aea9ea93e7e394a5ff091) + +diff --git a/sysdeps/unix/sysv/linux/mq_notify.c b/sysdeps/unix/sysv/linux/mq_notify.c +index c4091169306ffde8..45449571d14c379f 100644 +--- a/sysdeps/unix/sysv/linux/mq_notify.c ++++ b/sysdeps/unix/sysv/linux/mq_notify.c +@@ -260,7 +260,14 @@ mq_notify (mqd_t mqdes, const struct sigevent *notification) + if (data.attr == NULL) + return -1; + +- __pthread_attr_copy (data.attr, notification->sigev_notify_attributes); ++ int ret = __pthread_attr_copy (data.attr, ++ notification->sigev_notify_attributes); ++ if (ret != 0) ++ { ++ free (data.attr); ++ __set_errno (ret); ++ return -1; ++ } + } + + /* Construct the new request. */ +@@ -273,7 +280,7 @@ mq_notify (mqd_t mqdes, const struct sigevent *notification) + int retval = INLINE_SYSCALL (mq_notify, 2, mqdes, &se); + + /* If it failed, free the allocated memory. */ +- if (__glibc_unlikely (retval != 0)) ++ if (retval != 0 && data.attr != NULL) + { + pthread_attr_destroy (data.attr); + free (data.attr); diff --git a/SOURCES/glibc-rh1966472-4.patch b/SOURCES/glibc-rh1966472-4.patch new file mode 100644 index 0000000..47a01ff --- /dev/null +++ b/SOURCES/glibc-rh1966472-4.patch @@ -0,0 +1,34 @@ +commit b805aebd42364fe696e417808a700fdb9800c9e8 +Author: Nikita Popov +Date: Mon Aug 9 20:17:34 2021 +0530 + + librt: fix NULL pointer dereference (bug 28213) + + Helper thread frees copied attribute on NOTIFY_REMOVED message + received from the OS kernel. Unfortunately, it fails to check whether + copied attribute actually exists (data.attr != NULL). This worked + earlier because free() checks passed pointer before actually + attempting to release corresponding memory. But + __pthread_attr_destroy assumes pointer is not NULL. + + So passing NULL pointer to __pthread_attr_destroy will result in + segmentation fault. This scenario is possible if + notification->sigev_notify_attributes == NULL (which means default + thread attributes should be used). + + Signed-off-by: Nikita Popov + Reviewed-by: Siddhesh Poyarekar + +diff --git a/sysdeps/unix/sysv/linux/mq_notify.c b/sysdeps/unix/sysv/linux/mq_notify.c +index 45449571d14c379f..581959d621135fb0 100644 +--- a/sysdeps/unix/sysv/linux/mq_notify.c ++++ b/sysdeps/unix/sysv/linux/mq_notify.c +@@ -134,7 +134,7 @@ helper_thread (void *arg) + to wait until it is done with it. */ + (void) __pthread_barrier_wait (¬ify_barrier); + } +- else if (data.raw[NOTIFY_COOKIE_LEN - 1] == NOTIFY_REMOVED) ++ else if (data.raw[NOTIFY_COOKIE_LEN - 1] == NOTIFY_REMOVED && data.attr != NULL) + { + /* The only state we keep is the copy of the thread attributes. */ + pthread_attr_destroy (data.attr); diff --git a/SOURCES/glibc-rh1971664-1.patch b/SOURCES/glibc-rh1971664-1.patch new file mode 100644 index 0000000..5a858d2 --- /dev/null +++ b/SOURCES/glibc-rh1971664-1.patch @@ -0,0 +1,102 @@ +commit 0c78b0bb78d87a7de18726a033d88904f158f0fe +Author: Siddhesh Poyarekar +Date: Mon Jun 7 14:22:17 2021 +0530 + + iconvconfig: Make file handling more general purpose + + Split out configuration file handling code from handle_dir into its + own function so that it can be reused for multiple configuration + files. + + Reviewed-by: DJ Delorie + +diff --git a/iconv/iconvconfig.c b/iconv/iconvconfig.c +index b6fef1553cbbdd3d..2b3c587bc77cfdcd 100644 +--- a/iconv/iconvconfig.c ++++ b/iconv/iconvconfig.c +@@ -644,37 +644,17 @@ add_module (char *rp, const char *directory) + cost, need_ext); + } + +- +-/* Read the config file and add the data for this directory to that. */ +-static int +-handle_dir (const char *dir) ++/* Read a gconv-modules configuration file. */ ++static bool ++handle_file (const char *dir, const char *infile) + { +- char *cp; + FILE *fp; + char *line = NULL; + size_t linelen = 0; +- size_t dirlen = strlen (dir); +- +- if (dir[dirlen - 1] != '/') +- { +- char *newp = (char *) xmalloc (dirlen + 2); +- dir = memcpy (newp, dir, dirlen); +- newp[dirlen++] = '/'; +- newp[dirlen] = '\0'; +- } +- +- char infile[prefix_len + dirlen + sizeof "gconv-modules"]; +- cp = infile; +- if (dir[0] == '/') +- cp = mempcpy (cp, prefix, prefix_len); +- strcpy (mempcpy (cp, dir, dirlen), "gconv-modules"); + + fp = fopen (infile, "r"); + if (fp == NULL) +- { +- error (0, errno, "cannot open `%s'", infile); +- return 1; +- } ++ return false; + + /* No threads present. */ + __fsetlocking (fp, FSETLOCKING_BYCALLER); +@@ -723,7 +703,42 @@ handle_dir (const char *dir) + + fclose (fp); + +- return 0; ++ return true; ++} ++ ++/* Read config files and add the data for this directory to cache. */ ++static int ++handle_dir (const char *dir) ++{ ++ char *cp; ++ size_t dirlen = strlen (dir); ++ bool found = false; ++ ++ if (dir[dirlen - 1] != '/') ++ { ++ char *newp = (char *) xmalloc (dirlen + 2); ++ dir = memcpy (newp, dir, dirlen); ++ newp[dirlen++] = '/'; ++ newp[dirlen] = '\0'; ++ } ++ ++ char infile[prefix_len + dirlen + sizeof "gconv-modules"]; ++ cp = infile; ++ if (dir[0] == '/') ++ cp = mempcpy (cp, prefix, prefix_len); ++ strcpy (mempcpy (cp, dir, dirlen), "gconv-modules"); ++ ++ found |= handle_file (dir, infile); ++ ++ if (!found) ++ { ++ error (0, errno, "failed to open gconv configuration file in `%s'", ++ dir); ++ error (0, 0, ++ "ensure that the directory contains a valid gconv-modules file."); ++ } ++ ++ return found ? 0 : 1; + } + + diff --git a/SOURCES/glibc-rh1971664-10.patch b/SOURCES/glibc-rh1971664-10.patch new file mode 100644 index 0000000..a265910 --- /dev/null +++ b/SOURCES/glibc-rh1971664-10.patch @@ -0,0 +1,188 @@ +commit eeac390eecf7de24a110dc84e77e1190f42c5305 +Author: Siddhesh Poyarekar +Date: Thu Jun 10 14:31:57 2021 +0530 + + iconvconfig: Use common gconv module parsing function + + Drop local copy of gconv file parsing and use the one in + gconv_parseconfdir.h instead. Now there is a single implementation of + configuration file parsing. + + Reviewed-by: DJ Delorie + +diff --git a/iconv/iconvconfig.c b/iconv/iconvconfig.c +index 2f9d5f45ad3a8159..01ecf6f67d55dbbf 100644 +--- a/iconv/iconvconfig.c ++++ b/iconv/iconvconfig.c +@@ -18,7 +18,6 @@ + + #include + #include +-#include + #include + #include + #include +@@ -34,10 +33,10 @@ + #include + #include + #include +-#include + #include + + #include "iconvconfig.h" ++#include + + /* Get libc version number. */ + #include "../version.h" +@@ -568,7 +567,9 @@ new_module (const char *fromname, size_t fromlen, const char *toname, + + /* Add new module. */ + static void +-add_module (char *rp, const char *directory) ++add_module (char *rp, const char *directory, ++ size_t dirlen __attribute__ ((__unused__)), ++ int modcount __attribute__ ((__unused__))) + { + /* We expect now + 1. `from' name +@@ -646,131 +647,28 @@ add_module (char *rp, const char *directory) + cost, need_ext); + } + +-/* Read a gconv-modules configuration file. */ +-static bool +-handle_file (const char *dir, const char *infile) +-{ +- FILE *fp; +- char *line = NULL; +- size_t linelen = 0; +- +- fp = fopen (infile, "r"); +- if (fp == NULL) +- return false; +- +- /* No threads present. */ +- __fsetlocking (fp, FSETLOCKING_BYCALLER); +- +- while (!feof_unlocked (fp)) +- { +- char *rp, *endp, *word; +- ssize_t n = __getdelim (&line, &linelen, '\n', fp); +- +- if (n < 0) +- /* An error occurred. */ +- break; +- +- rp = line; +- /* Terminate the line (excluding comments or newline) with a NUL +- byte to simplify the following code. */ +- endp = strchr (rp, '#'); +- if (endp != NULL) +- *endp = '\0'; +- else +- if (rp[n - 1] == '\n') +- rp[n - 1] = '\0'; +- +- while (isspace (*rp)) +- ++rp; +- +- /* If this is an empty line go on with the next one. */ +- if (rp == endp) +- continue; +- +- word = rp; +- while (*rp != '\0' && !isspace (*rp)) +- ++rp; +- +- if (rp - word == sizeof ("alias") - 1 +- && memcmp (word, "alias", sizeof ("alias") - 1) == 0) +- add_alias (rp); +- else if (rp - word == sizeof ("module") - 1 +- && memcmp (word, "module", sizeof ("module") - 1) == 0) +- add_module (rp, dir); +- /* else */ +- /* Otherwise ignore the line. */ +- } +- +- free (line); +- +- fclose (fp); +- +- return true; +-} +- + /* Read config files and add the data for this directory to cache. */ + static int + handle_dir (const char *dir) + { +- char *cp; + size_t dirlen = strlen (dir); + bool found = false; + ++ /* Add the prefix before sending it off to the parser. */ ++ char *fulldir = xmalloc (prefix_len + dirlen + 2); ++ char *cp = mempcpy (mempcpy (fulldir, prefix, prefix_len), dir, dirlen); ++ + if (dir[dirlen - 1] != '/') + { +- char *newp = (char *) xmalloc (dirlen + 2); +- dir = memcpy (newp, dir, dirlen); +- newp[dirlen++] = '/'; +- newp[dirlen] = '\0'; ++ *cp++ = '/'; ++ *cp = '\0'; ++ dirlen++; + } + +- /* First, look for a gconv-modules file. */ +- char *buf = malloc (prefix_len + dirlen + sizeof "gconv-modules.d"); +- if (buf == NULL) +- goto out; +- +- cp = buf; +- if (dir[0] == '/') +- cp = mempcpy (cp, prefix, prefix_len); +- cp = mempcpy (cp, dir, dirlen); +- cp = stpcpy (cp, "gconv-modules"); +- +- found |= handle_file (dir, buf); +- +- /* Next, see if there is a gconv-modules.d directory containing configuration +- files and if it is non-empty. */ +- cp[0] = '.'; +- cp[1] = 'd'; +- cp[2] = '\0'; +- +- DIR *confdir = opendir (buf); +- if (confdir != NULL) +- { +- struct dirent *ent; +- while ((ent = readdir (confdir)) != NULL) +- { +- if (ent->d_type != DT_REG) +- continue; +- +- size_t len = strlen (ent->d_name); +- const char *suffix = ".conf"; +- +- if (len > strlen (suffix) +- && strcmp (ent->d_name + len - strlen (suffix), suffix) == 0) +- { +- char *conf; +- if (asprintf (&conf, "%s/%s", buf, ent->d_name) < 0) +- continue; +- found |= handle_file (dir, conf); +- free (conf); +- } +- } +- closedir (confdir); +- } ++ found = gconv_parseconfdir (fulldir, dirlen + prefix_len); + +- free (buf); ++ free (fulldir); + +-out: + if (!found) + { + error (0, errno, "failed to open gconv configuration files in `%s'", diff --git a/SOURCES/glibc-rh1971664-11.patch b/SOURCES/glibc-rh1971664-11.patch new file mode 100644 index 0000000..cc5074d --- /dev/null +++ b/SOURCES/glibc-rh1971664-11.patch @@ -0,0 +1,53 @@ +Changes specific to RHEL-8: + +- lstat64 is a macro, so undefine it first + +commit f3629a4be82a393ff56646c388da2fda0101f557 +Author: Siddhesh Poyarekar +Date: Thu Jun 10 14:56:37 2021 +0530 + + Handle DT_UNKNOWN in gconv-modules.d + + On filesystems that do not support dt_type, a regular file shows up as + DT_UNKNOWN. Fall back to using lstat64 to read file properties in + such cases. + + Reviewed-by: DJ Delorie + +diff --git a/iconv/gconv_parseconfdir.h b/iconv/gconv_parseconfdir.h +index 3d4d58d4be10a250..ba9b3fd36d9e30f9 100644 +--- a/iconv/gconv_parseconfdir.h ++++ b/iconv/gconv_parseconfdir.h +@@ -32,6 +32,8 @@ + # define readdir __readdir + # define closedir __closedir + # define mempcpy __mempcpy ++# undef lstat64 ++# define lstat64 __lstat64 + #endif + + /* Name of the file containing the module information in the directories +@@ -138,7 +140,7 @@ gconv_parseconfdir (const char *dir, size_t dir_len) + struct dirent *ent; + while ((ent = readdir (confdir)) != NULL) + { +- if (ent->d_type != DT_REG) ++ if (ent->d_type != DT_REG && ent->d_type != DT_UNKNOWN) + continue; + + size_t len = strlen (ent->d_name); +@@ -148,8 +150,14 @@ gconv_parseconfdir (const char *dir, size_t dir_len) + && strcmp (ent->d_name + len - strlen (suffix), suffix) == 0) + { + char *conf; ++ struct stat64 st; + if (asprintf (&conf, "%s/%s", buf, ent->d_name) < 0) + continue; ++ if (ent->d_type == DT_UNKNOWN ++ && (lstat64 (conf, &st) == -1 ++ || !S_ISREG (st.st_mode))) ++ continue; ++ + found |= read_conf_file (conf, dir, dir_len); + free (conf); + } diff --git a/SOURCES/glibc-rh1971664-12.patch b/SOURCES/glibc-rh1971664-12.patch new file mode 100644 index 0000000..0d375f1 --- /dev/null +++ b/SOURCES/glibc-rh1971664-12.patch @@ -0,0 +1,98 @@ +commit 9429049c178b3af3d6afeb3717ff1f2214dc9572 +Author: Siddhesh Poyarekar +Date: Mon Jun 28 09:15:55 2021 +0530 + + iconvconfig: Fix multiple issues + + It was noticed on big-endian systems that msgfmt would fail with the + following error: + + msgfmt: gconv_builtin.c:70: __gconv_get_builtin_trans: Assertion `cnt < sizeof (map) / sizeof (map[0])' failed. + Aborted (core dumped) + + This is only seen on installed systems because it was due to a + corrupted gconv-modules.cache. iconvconfig had the following issues + (it was specifically freeing fulldir that caused this issue, but other + cleanups are also needed) that this patch fixes. + + - Add prefix only if dir starts with '/' + - Use asprintf instead of mempcpy so that the directory string is NULL + terminated + - Make a copy of the directory reference in new_module so that fulldir + can be freed within the same scope in handle_dir. + + Reviewed-by: Florian Weimer + +diff --git a/iconv/Makefile b/iconv/Makefile +index d09b8ac842731780..6df9862e748ae588 100644 +--- a/iconv/Makefile ++++ b/iconv/Makefile +@@ -33,7 +33,7 @@ vpath %.c ../locale/programs ../intl + iconv_prog-modules = iconv_charmap charmap charmap-dir linereader \ + dummy-repertoire simple-hash xstrdup xmalloc \ + record-status +-iconvconfig-modules = strtab xmalloc hash-string ++iconvconfig-modules = strtab xmalloc xasprintf xstrdup hash-string + extra-objs = $(iconv_prog-modules:=.o) $(iconvconfig-modules:=.o) + CFLAGS-iconv_prog.c += -I../locale/programs + CFLAGS-iconv_charmap.c += -I../locale/programs +diff --git a/iconv/iconvconfig.c b/iconv/iconvconfig.c +index 01ecf6f67d55dbbf..777da870d2f8e99a 100644 +--- a/iconv/iconvconfig.c ++++ b/iconv/iconvconfig.c +@@ -250,6 +250,7 @@ static const char gconv_module_ext[] = MODULE_EXT; + + + #include ++#include + + + /* C string table handling. */ +@@ -519,11 +520,12 @@ module_compare (const void *p1, const void *p2) + /* Create new module record. */ + static void + new_module (const char *fromname, size_t fromlen, const char *toname, +- size_t tolen, const char *directory, ++ size_t tolen, const char *dir_in, + const char *filename, size_t filelen, int cost, size_t need_ext) + { + struct module *new_module; +- size_t dirlen = strlen (directory) + 1; ++ size_t dirlen = strlen (dir_in) + 1; ++ const char *directory = xstrdup (dir_in); + char *tmp; + void **inserted; + +@@ -654,20 +656,10 @@ handle_dir (const char *dir) + size_t dirlen = strlen (dir); + bool found = false; + +- /* Add the prefix before sending it off to the parser. */ +- char *fulldir = xmalloc (prefix_len + dirlen + 2); +- char *cp = mempcpy (mempcpy (fulldir, prefix, prefix_len), dir, dirlen); ++ char *fulldir = xasprintf ("%s%s%s", dir[0] == '/' ? prefix : "", ++ dir, dir[dirlen - 1] != '/' ? "/" : ""); + +- if (dir[dirlen - 1] != '/') +- { +- *cp++ = '/'; +- *cp = '\0'; +- dirlen++; +- } +- +- found = gconv_parseconfdir (fulldir, dirlen + prefix_len); +- +- free (fulldir); ++ found = gconv_parseconfdir (fulldir, strlen (fulldir)); + + if (!found) + { +@@ -679,6 +671,8 @@ handle_dir (const char *dir) + "configuration files with names ending in .conf."); + } + ++ free (fulldir); ++ + return found ? 0 : 1; + } + diff --git a/SOURCES/glibc-rh1971664-13.patch b/SOURCES/glibc-rh1971664-13.patch new file mode 100644 index 0000000..23e523a --- /dev/null +++ b/SOURCES/glibc-rh1971664-13.patch @@ -0,0 +1,34 @@ +commit 7f784fabcb186ffaa082ed0aeed52a56b7d96cee +Author: Siddhesh Poyarekar +Date: Fri Jul 2 16:53:25 2021 +0530 + + iconvconfig: Use the public feof_unlocked + + Build of iconvconfig failed with CFLAGS=-Os since __feof_unlocked is + not a public symbol. Replace with feof_unlocked (defined to + __feof_unlocked when IS_IN (libc)) to fix this. + + Reported-by: Szabolcs Nagy + Reviewed-by: Szabolcs Nagy + +diff --git a/iconv/gconv_parseconfdir.h b/iconv/gconv_parseconfdir.h +index ba9b3fd36d9e30f9..234b85a586f1d79a 100644 +--- a/iconv/gconv_parseconfdir.h ++++ b/iconv/gconv_parseconfdir.h +@@ -34,6 +34,7 @@ + # define mempcpy __mempcpy + # undef lstat64 + # define lstat64 __lstat64 ++# define feof_unlocked __feof_unlocked + #endif + + /* Name of the file containing the module information in the directories +@@ -65,7 +66,7 @@ read_conf_file (const char *filename, const char *directory, size_t dir_len) + + /* Process the known entries of the file. Comments start with `#' and + end with the end of the line. Empty lines are ignored. */ +- while (!__feof_unlocked (fp)) ++ while (!feof_unlocked (fp)) + { + char *rp, *endp, *word; + ssize_t n = __getdelim (&line, &line_len, '\n', fp); diff --git a/SOURCES/glibc-rh1971664-14.patch b/SOURCES/glibc-rh1971664-14.patch new file mode 100644 index 0000000..09e3493 --- /dev/null +++ b/SOURCES/glibc-rh1971664-14.patch @@ -0,0 +1,32 @@ +commit 5f9b78fe35d08739b6da1e5b356786d41116c108 +Author: Siddhesh Poyarekar +Date: Tue Aug 3 21:10:20 2021 +0530 + + gconv_parseconfdir: Fix memory leak + + The allocated `conf` would leak if we have to skip over the file due + to the underlying filesystem not supporting dt_type. + + Reviewed-by: Arjun Shankar + +diff --git a/iconv/gconv_parseconfdir.h b/iconv/gconv_parseconfdir.h +index 915b60845ca11c03..e4c3c16d1f96ce0c 100644 +--- a/iconv/gconv_parseconfdir.h ++++ b/iconv/gconv_parseconfdir.h +@@ -153,12 +153,11 @@ gconv_parseconfdir (const char *dir, size_t dir_len) + struct stat64 st; + if (asprintf (&conf, "%s/%s", buf, ent->d_name) < 0) + continue; +- if (ent->d_type == DT_UNKNOWN +- && (lstat64 (conf, &st) == -1 +- || !S_ISREG (st.st_mode))) +- continue; + +- found |= read_conf_file (conf, dir, dir_len); ++ if (ent->d_type != DT_UNKNOWN ++ || (lstat64 (conf, &st) != -1 && S_ISREG (st.st_mode))) ++ found |= read_conf_file (conf, dir, dir_len); ++ + free (conf); + } + } diff --git a/SOURCES/glibc-rh1971664-15.patch b/SOURCES/glibc-rh1971664-15.patch new file mode 100644 index 0000000..8029cf6 --- /dev/null +++ b/SOURCES/glibc-rh1971664-15.patch @@ -0,0 +1,116 @@ +commit 43cea6d5652b6b9e61ac6ecc69419c909b504f47 +Author: Siddhesh Poyarekar +Date: Mon Sep 13 20:48:35 2021 +0530 + + iconvconfig: Fix behaviour with --prefix [BZ #28199] + + The consolidation of configuration parsing broke behaviour with + --prefix, where the prefix bled into the modules cache. Accept a + prefix which, when non-NULL, is prepended to the path when looking for + configuration files but only the original directory is added to the + modules cache. + + This has no effect on the codegen of gconv_conf since it passes NULL. + + Reported-by: Patrick McCarty + Reported-by: Michael Hudson-Doyle + Reviewed-by: Andreas Schwab + +diff --git a/iconv/gconv_conf.c b/iconv/gconv_conf.c +index ce64faa928dc1c52..3f5a692f1510157c 100644 +--- a/iconv/gconv_conf.c ++++ b/iconv/gconv_conf.c +@@ -476,7 +476,7 @@ __gconv_read_conf (void) + __gconv_get_path (); + + for (cnt = 0; __gconv_path_elem[cnt].name != NULL; ++cnt) +- gconv_parseconfdir (__gconv_path_elem[cnt].name, ++ gconv_parseconfdir (NULL, __gconv_path_elem[cnt].name, + __gconv_path_elem[cnt].len); + #endif + +diff --git a/iconv/gconv_parseconfdir.h b/iconv/gconv_parseconfdir.h +index e4c3c16d1f96ce0c..433aa18bab5083b0 100644 +--- a/iconv/gconv_parseconfdir.h ++++ b/iconv/gconv_parseconfdir.h +@@ -39,7 +39,6 @@ + /* Name of the file containing the module information in the directories + along the path. */ + static const char gconv_conf_filename[] = "gconv-modules"; +-static const char gconv_conf_dirname[] = "gconv-modules.d"; + + static void add_alias (char *); + static void add_module (char *, const char *, size_t, int); +@@ -110,19 +109,28 @@ read_conf_file (const char *filename, const char *directory, size_t dir_len) + return true; + } + ++/* Prefix DIR (with length DIR_LEN) with PREFIX if the latter is non-NULL and ++ parse configuration in it. */ ++ + static __always_inline bool +-gconv_parseconfdir (const char *dir, size_t dir_len) ++gconv_parseconfdir (const char *prefix, const char *dir, size_t dir_len) + { +- /* No slash needs to be inserted between dir and gconv_conf_filename; +- dir already ends in a slash. */ +- char *buf = malloc (dir_len + sizeof (gconv_conf_dirname)); ++ /* No slash needs to be inserted between dir and gconv_conf_filename; dir ++ already ends in a slash. The additional 2 is to accommodate the ".d" ++ when looking for configuration files in gconv-modules.d. */ ++ size_t buflen = dir_len + sizeof (gconv_conf_filename) + 2; ++ char *buf = malloc (buflen + (prefix != NULL ? strlen (prefix) : 0)); ++ char *cp = buf; + bool found = false; + + if (buf == NULL) + return false; + +- char *cp = mempcpy (mempcpy (buf, dir, dir_len), gconv_conf_filename, +- sizeof (gconv_conf_filename)); ++ if (prefix != NULL) ++ cp = stpcpy (cp, prefix); ++ ++ cp = mempcpy (mempcpy (cp, dir, dir_len), gconv_conf_filename, ++ sizeof (gconv_conf_filename)); + + /* Read the gconv-modules configuration file first. */ + found = read_conf_file (buf, dir, dir_len); +diff --git a/iconv/iconvconfig.c b/iconv/iconvconfig.c +index 777da870d2f8e99a..b1fd4100b5cbc9d2 100644 +--- a/iconv/iconvconfig.c ++++ b/iconv/iconvconfig.c +@@ -653,13 +653,21 @@ add_module (char *rp, const char *directory, + static int + handle_dir (const char *dir) + { ++ char *newp = NULL; + size_t dirlen = strlen (dir); + bool found = false; + +- char *fulldir = xasprintf ("%s%s%s", dir[0] == '/' ? prefix : "", +- dir, dir[dirlen - 1] != '/' ? "/" : ""); ++ /* End directory path with a '/' if it doesn't already. */ ++ if (dir[dirlen - 1] != '/') ++ { ++ newp = xmalloc (dirlen + 2); ++ memcpy (newp, dir, dirlen); ++ newp[dirlen++] = '/'; ++ newp[dirlen] = '\0'; ++ dir = newp; ++ } + +- found = gconv_parseconfdir (fulldir, strlen (fulldir)); ++ found = gconv_parseconfdir (dir[0] == '/' ? prefix : NULL, dir, dirlen); + + if (!found) + { +@@ -671,7 +679,7 @@ handle_dir (const char *dir) + "configuration files with names ending in .conf."); + } + +- free (fulldir); ++ free (newp); + + return found ? 0 : 1; + } diff --git a/SOURCES/glibc-rh1971664-2.patch b/SOURCES/glibc-rh1971664-2.patch new file mode 100644 index 0000000..06119e0 --- /dev/null +++ b/SOURCES/glibc-rh1971664-2.patch @@ -0,0 +1,109 @@ +commit 3979c3e1bae20459d9b6d424bdb49927d9cd6fec +Author: Siddhesh Poyarekar +Date: Mon Jun 7 14:22:18 2021 +0530 + + iconvconfig: Read configuration from gconv-modules.d subdirectory + + In addition to GCONV_PATH/gconv-modules, also read module + configuration from *.conf files in GCONV_PATH/gconv-modules.d. This + allows a single gconv directory to have multiple sets of gconv modules + but at the same time, a single modules cache. + + With this feature, one could separate the glibc supported gconv + modules into a minimal essential set (ISO-8859-*, UTF, etc.) from the + remaining modules. In future, these could be further segregated into + langpack-associated sets with their own + gconv-modules.d/someconfig.conf. + + Reviewed-by: DJ Delorie + +diff --git a/iconv/iconvconfig.c b/iconv/iconvconfig.c +index 2b3c587bc77cfdcd..fafc686ae25fb5c1 100644 +--- a/iconv/iconvconfig.c ++++ b/iconv/iconvconfig.c +@@ -18,6 +18,7 @@ + + #include + #include ++#include + #include + #include + #include +@@ -33,6 +34,7 @@ + #include + #include + #include ++#include + #include + + #include "iconvconfig.h" +@@ -710,6 +712,7 @@ handle_file (const char *dir, const char *infile) + static int + handle_dir (const char *dir) + { ++#define BUF_LEN prefix_len + dirlen + sizeof "gconv-modules.d" + char *cp; + size_t dirlen = strlen (dir); + bool found = false; +@@ -722,20 +725,55 @@ handle_dir (const char *dir) + newp[dirlen] = '\0'; + } + +- char infile[prefix_len + dirlen + sizeof "gconv-modules"]; +- cp = infile; ++ /* First, look for a gconv-modules file. */ ++ char buf[BUF_LEN]; ++ cp = buf; + if (dir[0] == '/') + cp = mempcpy (cp, prefix, prefix_len); +- strcpy (mempcpy (cp, dir, dirlen), "gconv-modules"); ++ cp = mempcpy (cp, dir, dirlen); ++ cp = stpcpy (cp, "gconv-modules"); + +- found |= handle_file (dir, infile); ++ found |= handle_file (dir, buf); ++ ++ /* Next, see if there is a gconv-modules.d directory containing configuration ++ files and if it is non-empty. */ ++ cp[0] = '.'; ++ cp[1] = 'd'; ++ cp[2] = '\0'; ++ ++ DIR *confdir = opendir (buf); ++ if (confdir != NULL) ++ { ++ struct dirent *ent; ++ while ((ent = readdir (confdir)) != NULL) ++ { ++ if (ent->d_type != DT_REG) ++ continue; ++ ++ size_t len = strlen (ent->d_name); ++ const char *suffix = ".conf"; ++ ++ if (len > strlen (suffix) ++ && strcmp (ent->d_name + len - strlen (suffix), suffix) == 0) ++ { ++ /* LEN <= PATH_MAX so this alloca is not unbounded. */ ++ char *conf = alloca (BUF_LEN + len + 1); ++ cp = stpcpy (conf, buf); ++ sprintf (cp, "/%s", ent->d_name); ++ found |= handle_file (dir, conf); ++ } ++ } ++ closedir (confdir); ++ } + + if (!found) + { +- error (0, errno, "failed to open gconv configuration file in `%s'", ++ error (0, errno, "failed to open gconv configuration files in `%s'", + dir); + error (0, 0, +- "ensure that the directory contains a valid gconv-modules file."); ++ "ensure that the directory contains either a valid " ++ "gconv-modules file or a gconv-modules.d directory with " ++ "configuration files with names ending in .conf."); + } + + return found ? 0 : 1; diff --git a/SOURCES/glibc-rh1971664-3.patch b/SOURCES/glibc-rh1971664-3.patch new file mode 100644 index 0000000..a8dedd1 --- /dev/null +++ b/SOURCES/glibc-rh1971664-3.patch @@ -0,0 +1,99 @@ +commit b17d29b390154df9dfad9d21f1e6605422521fd2 +Author: Siddhesh Poyarekar +Date: Mon Jun 7 14:22:19 2021 +0530 + + gconv_conf: Read configuration files in gconv-modules.d + + Read configuration files with names ending in .conf in + GCONV_PATH/gconv-modules.d to mirror configuration flexibility in + iconvconfig into the iconv program and function. + + Reviewed-by: DJ Delorie + +diff --git a/iconv/gconv_conf.c b/iconv/gconv_conf.c +index f173cde71b2a61d7..8eb981fca7cee36a 100644 +--- a/iconv/gconv_conf.c ++++ b/iconv/gconv_conf.c +@@ -19,6 +19,7 @@ + + #include + #include ++#include + #include + #include + #include +@@ -30,6 +31,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -50,6 +52,7 @@ static const struct path_elem empty_path_elem = { NULL, 0 }; + /* Name of the file containing the module information in the directories + along the path. */ + static const char gconv_conf_filename[] = "gconv-modules"; ++static const char gconv_conf_dirname[] = "gconv-modules.d"; + + /* Filename extension for the modules. */ + #ifndef MODULE_EXT +@@ -554,18 +557,52 @@ __gconv_read_conf (void) + + for (cnt = 0; __gconv_path_elem[cnt].name != NULL; ++cnt) + { ++#define BUF_LEN elem_len + sizeof (gconv_conf_dirname) ++ + const char *elem = __gconv_path_elem[cnt].name; + size_t elem_len = __gconv_path_elem[cnt].len; +- char *filename; ++ char *buf; + + /* No slash needs to be inserted between elem and gconv_conf_filename; + elem already ends in a slash. */ +- filename = alloca (elem_len + sizeof (gconv_conf_filename)); +- __mempcpy (__mempcpy (filename, elem, elem_len), +- gconv_conf_filename, sizeof (gconv_conf_filename)); ++ buf = alloca (BUF_LEN); ++ char *cp = __mempcpy (__mempcpy (buf, elem, elem_len), ++ gconv_conf_filename, sizeof (gconv_conf_filename)); ++ ++ /* Read the gconv-modules configuration file first. */ ++ read_conf_file (buf, elem, elem_len, &modules, &nmodules); ++ ++ /* Next, see if there is a gconv-modules.d directory containing ++ configuration files and if it is non-empty. */ ++ cp--; ++ cp[0] = '.'; ++ cp[1] = 'd'; ++ cp[2] = '\0'; ++ ++ DIR *confdir = __opendir (buf); ++ if (confdir != NULL) ++ { ++ struct dirent *ent; ++ while ((ent = __readdir (confdir)) != NULL) ++ { ++ if (ent->d_type != DT_REG) ++ continue; ++ ++ size_t len = strlen (ent->d_name); ++ const char *suffix = ".conf"; + +- /* Read the next configuration file. */ +- read_conf_file (filename, elem, elem_len, &modules, &nmodules); ++ if (len > strlen (suffix) ++ && strcmp (ent->d_name + len - strlen (suffix), suffix) == 0) ++ { ++ /* LEN <= PATH_MAX so this alloca is not unbounded. */ ++ char *conf = alloca (BUF_LEN + len + 1); ++ cp = stpcpy (conf, buf); ++ sprintf (cp, "/%s", ent->d_name); ++ read_conf_file (conf, elem, elem_len, &modules, &nmodules); ++ } ++ } ++ __closedir (confdir); ++ } + } + #endif + diff --git a/SOURCES/glibc-rh1971664-4.patch b/SOURCES/glibc-rh1971664-4.patch new file mode 100644 index 0000000..e6cc136 --- /dev/null +++ b/SOURCES/glibc-rh1971664-4.patch @@ -0,0 +1,179 @@ +commit fc5bfade69ca12d034967dc6b929dbe3dd715172 +Author: Siddhesh Poyarekar +Date: Mon Jun 7 14:22:20 2021 +0530 + + iconvdata: Move gconv-modules configuration to gconv-modules.conf + + Move all gconv-modules configuration files to gconv-modules.conf. + That is, the S390 extensions now become gconv-modules-s390.conf. Move + both configuration files into gconv-modules.d. + + Now GCONV_PATH/gconv-modules is read only for backward compatibility + for third-party gconv modules directories. + + Reviewed-by: DJ Delorie + +# Conflicts: +# iconvdata/Makefile + +diff --git a/iconvdata/Makefile b/iconvdata/Makefile +index 32656ad31d9b434b..fc403e8abe3cc11f 100644 +--- a/iconvdata/Makefile ++++ b/iconvdata/Makefile +@@ -136,10 +136,13 @@ charmaps = ../localedata/charmaps + extra-modules-left := $(modules) + include extra-module.mk + ++gconv-modules = gconv-modules.conf ++modpfx = $(objpfx)gconv-modules.d/ + + extra-objs += $(modules.so) + install-others = $(addprefix $(inst_gconvdir)/, $(modules.so)) \ +- $(inst_gconvdir)/gconv-modules ++ $(addprefix $(inst_gconvdir)/gconv-modules.d/, \ ++ $(gconv-modules)) + + # We can build the conversion tables for numerous charsets automatically. + +@@ -181,7 +184,7 @@ generated += $(generated-modules:=.h) $(generated-modules:=.stmp) \ + iconv-test.out iconv-rules tst-loading.mtrace \ + mtrace-tst-loading.out tst-tables.out iconv-test.xxx + ifdef objpfx +-generated += gconv-modules ++generated += $(addprefix gconv-modules.d/,$(gconv-modules)) + endif + + # Rules to generate the headers. +@@ -249,7 +252,8 @@ headers: $(addprefix $(objpfx), $(generated-modules:=.h)) + $(addprefix $(inst_gconvdir)/, $(modules.so)): \ + $(inst_gconvdir)/%: $(objpfx)% $(+force) + $(do-install-program) +-$(inst_gconvdir)/gconv-modules: $(objpfx)gconv-modules $(+force) ++$(addprefix $(inst_gconvdir)/gconv-modules.d/, $(gconv-modules)): \ ++ $(inst_gconvdir)/gconv-modules.d/%: $(modpfx)% $(+force) + $(do-install) + ifeq (no,$(cross-compiling)) + # Update the $(prefix)/lib/gconv/gconv-modules.cache file. This is necessary +@@ -297,29 +301,30 @@ $(objpfx)mtrace-tst-loading.out: $(objpfx)tst-loading.out + $(common-objpfx)malloc/mtrace $(objpfx)tst-loading.mtrace > $@; \ + $(evaluate-test) + +-$(objpfx)bug-iconv1.out: $(objpfx)gconv-modules \ ++$(objpfx)bug-iconv1.out: $(addprefix $(modpfx), $(gconv-modules)) \ + $(addprefix $(objpfx),$(modules.so)) +-$(objpfx)bug-iconv2.out: $(objpfx)gconv-modules \ ++$(objpfx)bug-iconv2.out: $(addprefix $(modpfx), $(gconv-modules)) \ + $(addprefix $(objpfx),$(modules.so)) + $(objpfx)bug-iconv3: $(libdl) +-$(objpfx)bug-iconv3.out: $(objpfx)gconv-modules \ ++$(objpfx)bug-iconv3.out: $(addprefix $(modpfx), $(gconv-modules)) \ + $(addprefix $(objpfx),$(modules.so)) +-$(objpfx)bug-iconv5.out: $(objpfx)gconv-modules \ ++$(objpfx)bug-iconv5.out: $(addprefix $(modpfx), $(gconv-modules)) \ + $(addprefix $(objpfx),$(modules.so)) +-$(objpfx)tst-loading.out: $(objpfx)gconv-modules \ ++$(objpfx)tst-loading.out: $(addprefix $(modpfx), $(gconv-modules)) \ + $(addprefix $(objpfx),$(modules.so)) +-$(objpfx)tst-iconv4.out: $(objpfx)gconv-modules \ ++$(objpfx)tst-iconv4.out: $(addprefix $(modpfx), $(gconv-modules)) \ + $(addprefix $(objpfx),$(modules.so)) +-$(objpfx)tst-iconv7.out: $(objpfx)gconv-modules \ ++$(objpfx)tst-iconv7.out: $(addprefix $(modpfx), $(gconv-modules)) \ + $(addprefix $(objpfx),$(modules.so)) +-$(objpfx)bug-iconv10.out: $(objpfx)gconv-modules \ ++$(objpfx)bug-iconv10.out: $(addprefix $(modpfx), $(gconv-modules)) \ + $(addprefix $(objpfx),$(modules.so)) +-$(objpfx)bug-iconv12.out: $(objpfx)gconv-modules \ ++$(objpfx)bug-iconv12.out: $(addprefix $(modpfx), $(gconv-modules)) \ + $(addprefix $(objpfx),$(modules.so)) +-$(objpfx)bug-iconv14.out: $(objpfx)gconv-modules \ ++$(objpfx)bug-iconv14.out: $(addprefix $(modpfx), $(gconv-modules)) \ + $(addprefix $(objpfx),$(modules.so)) + +-$(objpfx)iconv-test.out: run-iconv-test.sh $(objpfx)gconv-modules \ ++$(objpfx)iconv-test.out: run-iconv-test.sh \ ++ $(addprefix $(modpfx), $(gconv-modules)) \ + $(addprefix $(objpfx),$(modules.so)) \ + $(common-objdir)/iconv/iconv_prog TESTS + iconv_modules="$(modules)" \ +@@ -327,7 +332,8 @@ $(objpfx)iconv-test.out: run-iconv-test.sh $(objpfx)gconv-modules \ + '$(run-program-env)' > $@; \ + $(evaluate-test) + +-$(objpfx)tst-tables.out: tst-tables.sh $(objpfx)gconv-modules \ ++$(objpfx)tst-tables.out: tst-tables.sh \ ++ $(addprefix $(modpfx), $(gconv-modules)) \ + $(addprefix $(objpfx),$(modules.so)) \ + $(objpfx)tst-table-from $(objpfx)tst-table-to + $(SHELL) $< $(common-objpfx) $(common-objpfx)iconvdata/ \ +@@ -340,5 +346,8 @@ do-tests-clean common-mostlyclean: tst-tables-clean + tst-tables-clean: + -rm -f $(objpfx)tst-*.table $(objpfx)tst-EUC-TW.irreversible + +-$(objpfx)gconv-modules: gconv-modules +- cat $(sysdeps-gconv-modules) $^ > $@ ++$(modpfx): ++ mkdir -p $@ ++ ++$(modpfx)%: % $(modpfx) ++ cp $< $@ +diff --git a/iconvdata/gconv-modules b/iconvdata/gconv-modules.conf +similarity index 100% +rename from iconvdata/gconv-modules +rename to iconvdata/gconv-modules.conf +diff --git a/localedata/Makefile b/localedata/Makefile +index 14fcc37fed21e740..a5ca7a31f43d50c3 100644 +--- a/localedata/Makefile ++++ b/localedata/Makefile +@@ -179,7 +179,7 @@ install-others := $(addprefix $(inst_i18ndir)/, \ + $(locales)) + endif + +-tests: $(objdir)/iconvdata/gconv-modules ++tests: $(objdir)/iconvdata/gconv-modules.d/gconv-modules.conf + + tests-static += tst-langinfo-newlocale-static tst-langinfo-setlocale-static + +@@ -442,5 +442,5 @@ $(objpfx)mtrace-tst-leaks.out: $(objpfx)tst-leaks.out + bug-setlocale1-ENV-only = LOCPATH=$(objpfx) LC_CTYPE=de_DE.UTF-8 + bug-setlocale1-static-ENV-only = $(bug-setlocale1-ENV-only) + +-$(objdir)/iconvdata/gconv-modules: ++$(objdir)/iconvdata/gconv-modules.d/gconv-modules.conf: + $(MAKE) -C ../iconvdata subdir=iconvdata $@ +diff --git a/sysdeps/s390/Makefile b/sysdeps/s390/Makefile +index 8bc82e523f9049db..5c8e1170b4d799ba 100644 +--- a/sysdeps/s390/Makefile ++++ b/sysdeps/s390/Makefile +@@ -21,13 +21,25 @@ lib := iconvdata + include $(patsubst %,$(..)libof-iterator.mk,$(cpp-srcs-left)) + + extra-objs += $(addsuffix .so, $(s390x-iconv-modules)) +-install-others += $(patsubst %, $(inst_gconvdir)/%.so, $(s390x-iconv-modules)) ++install-others += $(patsubst %, $(inst_gconvdir)/%.so, \ ++ $(s390x-iconv-modules)) \ ++ $(inst_gconvdir)/gconv-modules.d/gconv-modules-s390.conf + + $(patsubst %, $(inst_gconvdir)/%.so, $(s390x-iconv-modules)) : \ + $(inst_gconvdir)/%.so: $(objpfx)%.so $(+force) + $(do-install-program) + +-sysdeps-gconv-modules = ../sysdeps/s390/gconv-modules ++ifdef objpfx ++generated += gconv-modules.d/gconv-modules-s390.conf ++endif ++ ++$(inst_gconvdir)/gconv-modules.d/gconv-modules-s390.conf: \ ++ $(modpfx)gconv-modules-s390.conf $(+force) ++ $(do-install) ++ ++$(modpfx)gconv-modules-s390.conf: ../sysdeps/s390/gconv-modules-s390.conf \ ++ $(modpfx) ++ cp $< $@ + endif + + ifeq ($(subdir),string) +diff --git a/sysdeps/s390/gconv-modules b/sysdeps/s390/gconv-modules-s390.conf +similarity index 100% +rename from sysdeps/s390/gconv-modules +rename to sysdeps/s390/gconv-modules-s390.conf diff --git a/SOURCES/glibc-rh1971664-5.patch b/SOURCES/glibc-rh1971664-5.patch new file mode 100644 index 0000000..0e6f3df --- /dev/null +++ b/SOURCES/glibc-rh1971664-5.patch @@ -0,0 +1,3825 @@ +commit 5a5b48136567de019f35a2996513bd7bbeb8175e +Author: Siddhesh Poyarekar +Date: Mon Jun 7 14:22:21 2021 +0530 + + iconvdata: Split out non-essential gconv module configuration + + Split module configuration so that only the bare minimum charsets, + i.e. ANSI_X3.110, ISO8859-15, ISO8859-1, CP1252, UNICODE, UTF-16, + UTF-32 and UTF-7 are configured in gconv-modules.conf. The remaining + module configurations are now in gconv-modules-extra.conf. + + Reviewed-by: DJ Delorie + +# Conflicts: +# iconvdata/gconv-modules.conf + +diff --git a/iconvdata/Makefile b/iconvdata/Makefile +index fc403e8abe3cc11f..d682a98b5c4a8003 100644 +--- a/iconvdata/Makefile ++++ b/iconvdata/Makefile +@@ -136,7 +136,7 @@ charmaps = ../localedata/charmaps + extra-modules-left := $(modules) + include extra-module.mk + +-gconv-modules = gconv-modules.conf ++gconv-modules = gconv-modules.conf gconv-modules-extra.conf + modpfx = $(objpfx)gconv-modules.d/ + + extra-objs += $(modules.so) +diff --git a/iconvdata/gconv-modules-extra.conf b/iconvdata/gconv-modules-extra.conf +new file mode 100644 +index 0000000000000000..edbd4d9be4b533b9 +--- /dev/null ++++ b/iconvdata/gconv-modules-extra.conf +@@ -0,0 +1,1889 @@ ++# GNU libc iconv configuration. ++# Copyright (C) 1997-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 ++# . ++ ++# All lines contain the following information: ++ ++# If the lines start with `module' ++# fromset: either a name triple or a regular expression triple. ++# toset: a name triple or an expression with \N to get regular ++# expression matching results. ++# filename: filename of the module implementing the transformation. ++# If it is not absolute the path is made absolute by prepending ++# the directory the configuration file is found in. ++# cost: optional cost of the transformation. Default is 1. ++ ++# If the lines start with `alias' ++# alias: alias name which is not really recognized. ++# name: the real name of the character set ++ ++alias ISO-IR-4// BS_4730// ++alias ISO646-GB// BS_4730// ++alias GB// BS_4730// ++alias UK// BS_4730// ++alias CSISO4UNITEDKINGDOM// BS_4730// ++module BS_4730// INTERNAL ISO646 2 ++module INTERNAL BS_4730// ISO646 2 ++ ++alias ISO-IR-121// CSA_Z243.4-1985-1// ++alias ISO646-CA// CSA_Z243.4-1985-1// ++alias CSA7-1// CSA_Z243.4-1985-1// ++alias CA// CSA_Z243.4-1985-1// ++alias CSISO121CANADIAN1// CSA_Z243.4-1985-1// ++alias CSA_Z243.419851// CSA_Z243.4-1985-1// ++module CSA_Z243.4-1985-1// INTERNAL ISO646 2 ++module INTERNAL CSA_Z243.4-1985-1// ISO646 2 ++ ++alias ISO-IR-122// CSA_Z243.4-1985-2// ++alias ISO646-CA2// CSA_Z243.4-1985-2// ++alias CSA7-2// CSA_Z243.4-1985-2// ++alias CSISO122CANADIAN2// CSA_Z243.4-1985-2// ++alias CSA_Z243.419852// CSA_Z243.4-1985-2// ++module CSA_Z243.4-1985-2// INTERNAL ISO646 2 ++module INTERNAL CSA_Z243.4-1985-2// ISO646 2 ++ ++alias ISO-IR-21// DIN_66003// ++alias DE// DIN_66003// ++alias ISO646-DE// DIN_66003// ++alias CSISO21GERMAN// DIN_66003// ++module DIN_66003// INTERNAL ISO646 2 ++module INTERNAL DIN_66003// ISO646 2 ++ ++alias DS2089// DS_2089// ++alias ISO646-DK// DS_2089// ++alias DK// DS_2089// ++alias CSISO646DANISH// DS_2089// ++module DS_2089// INTERNAL ISO646 2 ++module INTERNAL DS_2089// ISO646 2 ++ ++alias ISO-IR-17// ES// ++alias ISO646-ES// ES// ++alias CSISO17SPANISH// ES// ++module ES// INTERNAL ISO646 2 ++module INTERNAL ES// ISO646 2 ++ ++alias ISO-IR-85// ES2// ++alias ISO646-ES2// ES2// ++alias CSISO85SPANISH2// ES2// ++module ES2// INTERNAL ISO646 2 ++module INTERNAL ES2// ISO646 2 ++ ++alias ISO-IR-57// GB_1988-80// ++alias CN// GB_1988-80// ++alias ISO646-CN// GB_1988-80// ++alias CSISO58GB1988// GB_1988-80// ++alias GB_198880// GB_1988-80// ++module GB_1988-80// INTERNAL ISO646 2 ++module INTERNAL GB_1988-80// ISO646 2 ++ ++alias ISO-IR-15// IT// ++alias ISO646-IT// IT// ++alias CSISO15ITALIAN// IT// ++module IT// INTERNAL ISO646 2 ++module INTERNAL IT// ISO646 2 ++ ++alias ISO-IR-14// JIS_C6220-1969-RO// ++alias JP// JIS_C6220-1969-RO// ++alias ISO646-JP// JIS_C6220-1969-RO// ++alias CSISO14JISC6220RO// JIS_C6220-1969-RO// ++alias JIS_C62201969RO// JIS_C6220-1969-RO// ++module JIS_C6220-1969-RO// INTERNAL ISO646 2 ++module INTERNAL JIS_C6220-1969-RO// ISO646 2 ++ ++alias ISO-IR-92// JIS_C6229-1984-B// ++alias ISO646-JP-OCR-B// JIS_C6229-1984-B// ++alias JP-OCR-B// JIS_C6229-1984-B// ++alias CSISO92JISC62991984B// JIS_C6229-1984-B// ++alias JIS_C62291984B// JIS_C6229-1984-B// ++module JIS_C6229-1984-B// INTERNAL ISO646 2 ++module INTERNAL JIS_C6229-1984-B// ISO646 2 ++ ++alias ISO-IR-141// JUS_I.B1.002// ++alias ISO646-YU// JUS_I.B1.002// ++alias JS// JUS_I.B1.002// ++alias YU// JUS_I.B1.002// ++alias CSISO141JUSIB1002// JUS_I.B1.002// ++module JUS_I.B1.002// INTERNAL ISO646 2 ++module INTERNAL JUS_I.B1.002// ISO646 2 ++ ++alias ISO646-KR// KSC5636// ++alias CSKSC5636// KSC5636// ++module KSC5636// INTERNAL ISO646 2 ++module INTERNAL KSC5636// ISO646 2 ++ ++alias ISO-IR-86// MSZ_7795.3// ++alias ISO646-HU// MSZ_7795.3// ++alias HU// MSZ_7795.3// ++alias CSISO86HUNGARIAN// MSZ_7795.3// ++module MSZ_7795.3// INTERNAL ISO646 2 ++module INTERNAL MSZ_7795.3// ISO646 2 ++ ++alias CUBA// NC_NC00-10// ++alias NC_NC00-10:81// NC_NC00-10// ++alias ISO-IR-151// NC_NC00-10// ++alias ISO646-CU// NC_NC00-10// ++alias CSISO151CUBA// NC_NC00-10// ++alias NC_NC0010// NC_NC00-10// ++module NC_NC00-10// INTERNAL ISO646 2 ++module INTERNAL NC_NC00-10// ISO646 2 ++ ++alias ISO-IR-69// NF_Z_62-010// ++alias ISO646-FR// NF_Z_62-010// ++alias FR// NF_Z_62-010// ++alias CSISO69FRENCH// NF_Z_62-010// ++alias NF_Z_62010// NF_Z_62-010// ++module NF_Z_62-010// INTERNAL ISO646 2 ++module INTERNAL NF_Z_62-010// ISO646 2 ++ ++alias ISO-IR-25// NF_Z_62-010_1973// ++alias ISO646-FR1// NF_Z_62-010_1973// ++alias NF_Z_62-010_(1973)// NF_Z_62-010_1973// ++alias CSISO25FRENCH// NF_Z_62-010_1973// ++alias NF_Z_62010_1973// NF_Z_62-010_1973// ++module NF_Z_62-010_1973// INTERNAL ISO646 2 ++module INTERNAL NF_Z_62-010_1973// ISO646 2 ++ ++alias ISO-IR-60// NS_4551-1// ++alias ISO646-NO// NS_4551-1// ++alias NO// NS_4551-1// ++alias CSISO60DANISHNORWEGIAN// NS_4551-1// ++alias CSISO60NORWEGIAN1// NS_4551-1// ++alias NS_45511// NS_4551-1// ++module NS_4551-1// INTERNAL ISO646 2 ++module INTERNAL NS_4551-1// ISO646 2 ++ ++alias ISO646-NO2// NS_4551-2// ++alias ISO-IR-61// NS_4551-2// ++alias NO2// NS_4551-2// ++alias CSISO61NORWEGIAN2// NS_4551-2// ++alias NS_45512// NS_4551-2// ++module NS_4551-2// INTERNAL ISO646 2 ++module INTERNAL NS_4551-2// ISO646 2 ++ ++alias ISO-IR-16// PT// ++alias ISO646-PT// PT// ++alias CSISO16PORTUGESE// PT// ++module PT// INTERNAL ISO646 2 ++module INTERNAL PT// ISO646 2 ++ ++alias ISO-IR-84// PT2// ++alias ISO646-PT2// PT2// ++alias CSISO84PORTUGUESE2// PT2// ++module PT2// INTERNAL ISO646 2 ++module INTERNAL PT2// ISO646 2 ++ ++alias ISO-IR-10// SEN_850200_B// ++alias FI// SEN_850200_B// ++alias ISO646-FI// SEN_850200_B// ++alias ISO646-SE// SEN_850200_B// ++alias SE// SEN_850200_B// ++alias CSISO10SWEDISH// SEN_850200_B// ++alias SS636127// SEN_850200_B// ++module SEN_850200_B// INTERNAL ISO646 2 ++module INTERNAL SEN_850200_B// ISO646 2 ++ ++alias ISO-IR-11// SEN_850200_C// ++alias ISO646-SE2// SEN_850200_C// ++alias SE2// SEN_850200_C// ++alias CSISO11SWEDISHFORNAMES// SEN_850200_C// ++module SEN_850200_C// INTERNAL ISO646 2 ++module INTERNAL SEN_850200_C// ISO646 2 ++ ++# from to module cost ++alias ISO-IR-101// ISO-8859-2// ++alias ISO_8859-2:1987// ISO-8859-2// ++alias ISO_8859-2// ISO-8859-2// ++alias ISO8859-2// ISO-8859-2// ++alias ISO88592// ISO-8859-2// ++alias LATIN2// ISO-8859-2// ++alias L2// ISO-8859-2// ++alias CSISOLATIN2// ISO-8859-2// ++alias 8859_2// ISO-8859-2// ++alias OSF00010002// ISO-8859-2// ++alias IBM912// ISO-8859-2// ++alias CP912// ISO-8859-2// ++module ISO-8859-2// INTERNAL ISO8859-2 1 ++module INTERNAL ISO-8859-2// ISO8859-2 1 ++ ++# from to module cost ++alias ISO-IR-109// ISO-8859-3// ++alias ISO_8859-3:1988// ISO-8859-3// ++alias ISO_8859-3// ISO-8859-3// ++alias ISO8859-3// ISO-8859-3// ++alias ISO88593// ISO-8859-3// ++alias LATIN3// ISO-8859-3// ++alias L3// ISO-8859-3// ++alias CSISOLATIN3// ISO-8859-3// ++alias 8859_3// ISO-8859-3// ++alias OSF00010003// ISO-8859-3// ++module ISO-8859-3// INTERNAL ISO8859-3 1 ++module INTERNAL ISO-8859-3// ISO8859-3 1 ++ ++# from to module cost ++alias ISO-IR-110// ISO-8859-4// ++alias ISO_8859-4:1988// ISO-8859-4// ++alias ISO_8859-4// ISO-8859-4// ++alias ISO8859-4// ISO-8859-4// ++alias ISO88594// ISO-8859-4// ++alias LATIN4// ISO-8859-4// ++alias L4// ISO-8859-4// ++alias CSISOLATIN4// ISO-8859-4// ++alias 8859_4// ISO-8859-4// ++alias OSF00010004// ISO-8859-4// ++module ISO-8859-4// INTERNAL ISO8859-4 1 ++module INTERNAL ISO-8859-4// ISO8859-4 1 ++ ++# from to module cost ++alias ISO-IR-144// ISO-8859-5// ++alias ISO_8859-5:1988// ISO-8859-5// ++alias ISO_8859-5// ISO-8859-5// ++alias ISO8859-5// ISO-8859-5// ++alias ISO88595// ISO-8859-5// ++alias CYRILLIC// ISO-8859-5// ++alias CSISOLATINCYRILLIC// ISO-8859-5// ++alias 8859_5// ISO-8859-5// ++alias OSF00010005// ISO-8859-5// ++alias IBM915// ISO-8859-5// ++alias CP915// ISO-8859-5// ++module ISO-8859-5// INTERNAL ISO8859-5 1 ++module INTERNAL ISO-8859-5// ISO8859-5 1 ++ ++# from to module cost ++alias ISO-IR-127// ISO-8859-6// ++alias ISO_8859-6:1987// ISO-8859-6// ++alias ISO_8859-6// ISO-8859-6// ++alias ISO8859-6// ISO-8859-6// ++alias ISO88596// ISO-8859-6// ++alias ECMA-114// ISO-8859-6// ++alias ASMO-708// ISO-8859-6// ++alias ARABIC// ISO-8859-6// ++alias CSISOLATINARABIC// ISO-8859-6// ++alias 8859_6// ISO-8859-6// ++alias OSF00010006// ISO-8859-6// ++alias IBM1089// ISO-8859-6// ++alias CP1089// ISO-8859-6// ++module ISO-8859-6// INTERNAL ISO8859-6 1 ++module INTERNAL ISO-8859-6// ISO8859-6 1 ++ ++# from to module cost ++alias ISO-IR-126// ISO-8859-7// ++alias ISO_8859-7:2003// ISO-8859-7// ++alias ISO_8859-7:1987// ISO-8859-7// ++alias ISO_8859-7// ISO-8859-7// ++alias ISO8859-7// ISO-8859-7// ++alias ISO88597// ISO-8859-7// ++alias ELOT_928// ISO-8859-7// ++alias ECMA-118// ISO-8859-7// ++alias GREEK// ISO-8859-7// ++alias GREEK8// ISO-8859-7// ++alias CSISOLATINGREEK// ISO-8859-7// ++alias 8859_7// ISO-8859-7// ++alias OSF00010007// ISO-8859-7// ++alias IBM813// ISO-8859-7// ++alias CP813// ISO-8859-7// ++module ISO-8859-7// INTERNAL ISO8859-7 1 ++module INTERNAL ISO-8859-7// ISO8859-7 1 ++ ++# from to module cost ++alias ISO-IR-138// ISO-8859-8// ++alias ISO_8859-8:1988// ISO-8859-8// ++alias ISO_8859-8// ISO-8859-8// ++alias ISO8859-8// ISO-8859-8// ++alias ISO88598// ISO-8859-8// ++alias HEBREW// ISO-8859-8// ++alias CSISOLATINHEBREW// ISO-8859-8// ++alias 8859_8// ISO-8859-8// ++alias OSF00010008// ISO-8859-8// ++alias IBM916// ISO-8859-8// ++alias CP916// ISO-8859-8// ++module ISO-8859-8// INTERNAL ISO8859-8 1 ++module INTERNAL ISO-8859-8// ISO8859-8 1 ++ ++# from to module cost ++alias ISO-IR-148// ISO-8859-9// ++alias ISO_8859-9:1989// ISO-8859-9// ++alias ISO_8859-9// ISO-8859-9// ++alias ISO8859-9// ISO-8859-9// ++alias ISO88599// ISO-8859-9// ++alias LATIN5// ISO-8859-9// ++alias L5// ISO-8859-9// ++alias CSISOLATIN5// ISO-8859-9// ++alias 8859_9// ISO-8859-9// ++alias OSF00010009// ISO-8859-9// ++alias IBM920// ISO-8859-9// ++alias CP920// ISO-8859-9// ++alias TS-5881// ISO-8859-9// ++alias ECMA-128// ISO-8859-9// ++module ISO-8859-9// INTERNAL ISO8859-9 1 ++module INTERNAL ISO-8859-9// ISO8859-9 1 ++ ++# from to module cost ++alias ISO-IR-157// ISO-8859-10// ++alias ISO_8859-10:1992// ISO-8859-10// ++alias ISO_8859-10// ISO-8859-10// ++alias ISO8859-10// ISO-8859-10// ++alias ISO885910// ISO-8859-10// ++alias LATIN6// ISO-8859-10// ++alias L6// ISO-8859-10// ++alias CSISOLATIN6// ISO-8859-10// ++alias OSF0001000A// ISO-8859-10// ++module ISO-8859-10// INTERNAL ISO8859-10 1 ++module INTERNAL ISO-8859-10// ISO8859-10 1 ++ ++# from to module cost ++alias ISO8859-11// ISO-8859-11// ++alias ISO885911// ISO-8859-11// ++module ISO-8859-11// INTERNAL ISO8859-11 1 ++module INTERNAL ISO-8859-11// ISO8859-11 1 ++ ++# from to module cost ++alias ISO8859-13// ISO-8859-13// ++alias ISO885913// ISO-8859-13// ++alias ISO-IR-179// ISO-8859-13// ++alias LATIN7// ISO-8859-13// ++alias L7// ISO-8859-13// ++alias BALTIC// ISO-8859-13// ++module ISO-8859-13// INTERNAL ISO8859-13 1 ++module INTERNAL ISO-8859-13// ISO8859-13 1 ++ ++# from to module cost ++alias ISO8859-14// ISO-8859-14// ++alias ISO885914// ISO-8859-14// ++alias ISO-IR-199// ISO-8859-14// ++alias LATIN8// ISO-8859-14// ++alias L8// ISO-8859-14// ++alias ISO_8859-14:1998// ISO-8859-14// ++alias ISO_8859-14// ISO-8859-14// ++alias ISO-CELTIC// ISO-8859-14// ++module ISO-8859-14// INTERNAL ISO8859-14 1 ++module INTERNAL ISO-8859-14// ISO8859-14 1 ++ ++# from to module cost ++alias ISO8859-16// ISO-8859-16// ++alias ISO885916// ISO-8859-16// ++alias ISO-IR-226// ISO-8859-16// ++alias LATIN10// ISO-8859-16// ++alias L10// ISO-8859-16// ++alias ISO_8859-16:2001// ISO-8859-16// ++alias ISO_8859-16// ISO-8859-16// ++module ISO-8859-16// INTERNAL ISO8859-16 1 ++module INTERNAL ISO-8859-16// ISO8859-16 1 ++ ++# from to module cost ++alias T.61// T.61-8BIT// ++alias ISO-IR-103// T.61-8BIT// ++alias CSISO103T618BIT// T.61-8BIT// ++alias T.618BIT// T.61-8BIT// ++module T.61-8BIT// INTERNAL T.61 1 ++module INTERNAL T.61-8BIT// T.61 1 ++ ++# from to module cost ++alias ISO-IR-156// ISO_6937// ++alias ISO_6937:1992// ISO_6937// ++alias ISO6937// ISO_6937// ++module ISO_6937// INTERNAL ISO_6937 1 ++module INTERNAL ISO_6937// ISO_6937 1 ++ ++ ++# from to module cost ++alias ISO-IR-90// ISO_6937-2// ++alias ISO_6937-2:1983// ISO_6937-2// ++alias CSISO90// ISO_6937-2// ++alias ISO_69372// ISO_6937-2// ++module ISO_6937-2// INTERNAL ISO_6937-2 1 ++module INTERNAL ISO_6937-2// ISO_6937-2 1 ++ ++# from to module cost ++alias SHIFT-JIS// SJIS// ++alias SHIFT_JIS// SJIS// ++alias MS_KANJI// SJIS// ++alias CSSHIFTJIS// SJIS// ++module SJIS// INTERNAL SJIS 1 ++module INTERNAL SJIS// SJIS 1 ++ ++# from to module cost ++alias WINDOWS-31J// CP932// ++alias MS932// CP932// ++alias SJIS-OPEN// CP932// ++alias SJIS-WIN// CP932// ++alias CSWINDOWS31J// CP932// ++module CP932// INTERNAL CP932 1 ++module INTERNAL CP932// CP932 1 ++ ++# from to module cost ++alias KOI8// KOI-8// ++module KOI-8// INTERNAL KOI-8 1 ++module INTERNAL KOI-8// KOI-8 1 ++ ++# from to module cost ++alias CSKOI8R// KOI8-R// ++alias KOI8R// KOI8-R// ++module KOI8-R// INTERNAL KOI8-R 1 ++module INTERNAL KOI8-R// KOI8-R 1 ++ ++# from to module cost ++alias ISO-IR-19// LATIN-GREEK// ++alias CSISO19LATINGREEK// LATIN-GREEK// ++alias LATINGREEK// LATIN-GREEK// ++module LATIN-GREEK// INTERNAL LATIN-GREEK 1 ++module INTERNAL LATIN-GREEK// LATIN-GREEK 1 ++ ++# from to module cost ++alias ISO-IR-27// LATIN-GREEK-1// ++alias CSISO27LATINGREEK1// LATIN-GREEK-1// ++alias LATINGREEK1// LATIN-GREEK-1// ++module LATIN-GREEK-1// INTERNAL LATIN-GREEK-1 1 ++module INTERNAL LATIN-GREEK-1// LATIN-GREEK-1 1 ++ ++# from to module cost ++alias ROMAN8// HP-ROMAN8// ++alias R8// HP-ROMAN8// ++alias CSHPROMAN8// HP-ROMAN8// ++alias OSF10010001// HP-ROMAN8// ++alias HPROMAN8// HP-ROMAN8// ++module HP-ROMAN8// INTERNAL HP-ROMAN8 1 ++module INTERNAL HP-ROMAN8// HP-ROMAN8 1 ++ ++# from to module cost ++alias CSEBCDICATDE// EBCDIC-AT-DE// ++alias EBCDICATDE// EBCDIC-AT-DE// ++module EBCDIC-AT-DE// INTERNAL EBCDIC-AT-DE 1 ++module INTERNAL EBCDIC-AT-DE// EBCDIC-AT-DE 1 ++ ++# from to module cost ++alias CSEBCDICATDEA// EBCDIC-AT-DE-A// ++alias EBCDICATDEA// EBCDIC-AT-DE-A// ++module EBCDIC-AT-DE-A// INTERNAL EBCDIC-AT-DE-A 1 ++module INTERNAL EBCDIC-AT-DE-A// EBCDIC-AT-DE-A 1 ++ ++# from to module cost ++alias CSEBCDICCAFR// EBCDIC-CA-FR// ++alias EBCDICCAFR// EBCDIC-CA-FR// ++module EBCDIC-CA-FR// INTERNAL EBCDIC-CA-FR 1 ++module INTERNAL EBCDIC-CA-FR// EBCDIC-CA-FR 1 ++ ++# from to module cost ++alias CSEBCDICDKNO// EBCDIC-DK-NO// ++alias EBCDICDKNO// EBCDIC-DK-NO// ++module EBCDIC-DK-NO// INTERNAL EBCDIC-DK-NO 1 ++module INTERNAL EBCDIC-DK-NO// EBCDIC-DK-NO 1 ++ ++# from to module cost ++alias CSEBCDICDKNOA// EBCDIC-DK-NO-A// ++alias EBCDICDKNOA// EBCDIC-DK-NO-A// ++module EBCDIC-DK-NO-A// INTERNAL EBCDIC-DK-NO-A 1 ++module INTERNAL EBCDIC-DK-NO-A// EBCDIC-DK-NO-A 1 ++ ++# from to module cost ++alias CSEBCDICES// EBCDIC-ES// ++alias EBCDICES// EBCDIC-ES// ++module EBCDIC-ES// INTERNAL EBCDIC-ES 1 ++module INTERNAL EBCDIC-ES// EBCDIC-ES 1 ++ ++# from to module cost ++alias CSEBCDICESA// EBCDIC-ES-A// ++alias EBCDICESA// EBCDIC-ES-A// ++module EBCDIC-ES-A// INTERNAL EBCDIC-ES-A 1 ++module INTERNAL EBCDIC-ES-A// EBCDIC-ES-A 1 ++ ++# from to module cost ++alias CSEBCDICESS// EBCDIC-ES-S// ++alias EBCDICESS// EBCDIC-ES-S// ++module EBCDIC-ES-S// INTERNAL EBCDIC-ES-S 1 ++module INTERNAL EBCDIC-ES-S// EBCDIC-ES-S 1 ++ ++# from to module cost ++alias CSEBCDICFISE// EBCDIC-FI-SE// ++alias EBCDICFISE// EBCDIC-FI-SE// ++module EBCDIC-FI-SE// INTERNAL EBCDIC-FI-SE 1 ++module INTERNAL EBCDIC-FI-SE// EBCDIC-FI-SE 1 ++ ++# from to module cost ++alias CSEBCDICFISEA// EBCDIC-FI-SE-A// ++alias EBCDICFISEA// EBCDIC-FI-SE-A// ++module EBCDIC-FI-SE-A// INTERNAL EBCDIC-FI-SE-A 1 ++module INTERNAL EBCDIC-FI-SE-A// EBCDIC-FI-SE-A 1 ++ ++# from to module cost ++alias CSEBCDICFR// EBCDIC-FR// ++alias EBCDICFR// EBCDIC-FR// ++module EBCDIC-FR// INTERNAL EBCDIC-FR 1 ++module INTERNAL EBCDIC-FR// EBCDIC-FR 1 ++ ++# from to module cost ++alias EBCDICISFRISS// EBCDIC-IS-FRISS// ++module EBCDIC-IS-FRISS// INTERNAL EBCDIC-IS-FRISS 1 ++module INTERNAL EBCDIC-IS-FRISS// EBCDIC-IS-FRISS 1 ++ ++# from to module cost ++alias CSEBCDICIT// EBCDIC-IT// ++alias EBCDICIT// EBCDIC-IT// ++module EBCDIC-IT// INTERNAL EBCDIC-IT 1 ++module INTERNAL EBCDIC-IT// EBCDIC-IT 1 ++ ++# from to module cost ++alias CSEBCDICPT// EBCDIC-PT// ++alias EBCDICPT// EBCDIC-PT// ++module EBCDIC-PT// INTERNAL EBCDIC-PT 1 ++module INTERNAL EBCDIC-PT// EBCDIC-PT 1 ++ ++# from to module cost ++alias CSEBCDICUK// EBCDIC-UK// ++alias EBCDICUK// EBCDIC-UK// ++module EBCDIC-UK// INTERNAL EBCDIC-UK 1 ++module INTERNAL EBCDIC-UK// EBCDIC-UK 1 ++ ++# from to module cost ++alias CSEBCDICUS// EBCDIC-US// ++alias EBCDICUS// EBCDIC-US// ++module EBCDIC-US// INTERNAL EBCDIC-US 1 ++module INTERNAL EBCDIC-US// EBCDIC-US 1 ++ ++# from to module cost ++alias CP037// IBM037// ++alias EBCDIC-CP-US// IBM037// ++alias EBCDIC-CP-CA// IBM037// ++alias EBCDIC-CP-WT// IBM037// ++alias EBCDIC-CP-NL// IBM037// ++alias CSIBM037// IBM037// ++alias OSF10020025// IBM037// ++alias CP1070// IBM037// ++alias CP282// IBM037// ++module IBM037// INTERNAL IBM037 1 ++module INTERNAL IBM037// IBM037 1 ++ ++# from to module cost ++alias EBCDIC-INT// IBM038// ++alias CP038// IBM038// ++alias CSIBM038// IBM038// ++module IBM038// INTERNAL IBM038 1 ++module INTERNAL IBM038// IBM038 1 ++ ++# from to module cost ++alias EBCDIC-INT1// IBM256// ++module IBM256// INTERNAL IBM256 1 ++module INTERNAL IBM256// IBM256 1 ++ ++# from to module cost ++alias CP273// IBM273// ++alias CSIBM273// IBM273// ++alias OSF10020111// IBM273// ++module IBM273// INTERNAL IBM273 1 ++module INTERNAL IBM273// IBM273 1 ++ ++# from to module cost ++alias EBCDIC-BE// IBM274// ++alias CP274// IBM274// ++alias CSIBM274// IBM274// ++module IBM274// INTERNAL IBM274 1 ++module INTERNAL IBM274// IBM274 1 ++ ++# from to module cost ++alias EBCDIC-BR// IBM275// ++alias CP275// IBM275// ++alias CSIBM275// IBM275// ++module IBM275// INTERNAL IBM275 1 ++module INTERNAL IBM275// IBM275 1 ++ ++# from to module cost ++alias EBCDIC-CP-DK// IBM277// ++alias EBCDIC-CP-NO// IBM277// ++alias CSIBM277// IBM277// ++alias OSF10020115// IBM277// ++module IBM277// INTERNAL IBM277 1 ++module INTERNAL IBM277// IBM277 1 ++ ++# from to module cost ++alias CP278// IBM278// ++alias EBCDIC-CP-FI// IBM278// ++alias EBCDIC-CP-SE// IBM278// ++alias CSIBM278// IBM278// ++alias OSF10020116// IBM278// ++module IBM278// INTERNAL IBM278 1 ++module INTERNAL IBM278// IBM278 1 ++ ++# from to module cost ++alias CP280// IBM280// ++alias EBCDIC-CP-IT// IBM280// ++alias CSIBM280// IBM280// ++alias OSF10020118// IBM280// ++module IBM280// INTERNAL IBM280 1 ++module INTERNAL IBM280// IBM280 1 ++ ++# from to module cost ++alias EBCDIC-JP-E// IBM281// ++alias CP281// IBM281// ++alias CSIBM281// IBM281// ++module IBM281// INTERNAL IBM281 1 ++module INTERNAL IBM281// IBM281 1 ++ ++# from to module cost ++alias CP284// IBM284// ++alias EBCDIC-CP-ES// IBM284// ++alias CSIBM284// IBM284// ++alias OSF1002011C// IBM284// ++alias CP1079// IBM284// ++module IBM284// INTERNAL IBM284 1 ++module INTERNAL IBM284// IBM284 1 ++ ++# from to module cost ++alias CP285// IBM285// ++alias EBCDIC-CP-GB// IBM285// ++alias CSIBM285// IBM285// ++alias OSF1002011D// IBM285// ++module IBM285// INTERNAL IBM285 1 ++module INTERNAL IBM285// IBM285 1 ++ ++# from to module cost ++alias CP290// IBM290// ++alias EBCDIC-JP-KANA// IBM290// ++alias CSIBM290// IBM290// ++alias OSF10020122// IBM290// ++module IBM290// INTERNAL IBM290 1 ++module INTERNAL IBM290// IBM290 1 ++ ++# from to module cost ++alias CP297// IBM297// ++alias EBCDIC-CP-FR// IBM297// ++alias CSIBM297// IBM297// ++alias OSF10020129// IBM297// ++alias CP1081// IBM297// ++module IBM297// INTERNAL IBM297 1 ++module INTERNAL IBM297// IBM297 1 ++ ++# from to module cost ++alias CP420// IBM420// ++alias EBCDIC-CP-AR1// IBM420// ++alias CSIBM420// IBM420// ++alias OSF100201A4// IBM420// ++module IBM420// INTERNAL IBM420 1 ++module INTERNAL IBM420// IBM420 1 ++ ++# from to module cost ++alias CP423// IBM423// ++alias EBCDIC-CP-GR// IBM423// ++alias CSIBM423// IBM423// ++module IBM423// INTERNAL IBM423 1 ++module INTERNAL IBM423// IBM423 1 ++ ++# from to module cost ++alias CP424// IBM424// ++alias EBCDIC-CP-HE// IBM424// ++alias CSIBM424// IBM424// ++alias OSF100201A8// IBM424// ++module IBM424// INTERNAL IBM424 1 ++module INTERNAL IBM424// IBM424 1 ++ ++# from to module cost ++alias CP437// IBM437// ++alias 437// IBM437// ++alias CSPC8CODEPAGE437// IBM437// ++alias OSF100201B5// IBM437// ++module IBM437// INTERNAL IBM437 1 ++module INTERNAL IBM437// IBM437 1 ++ ++# from to module cost ++alias CP500// IBM500// ++alias 500// IBM500// ++alias 500V1// IBM500// ++alias EBCDIC-CP-BE// IBM500// ++alias EBCDIC-CP-CH// IBM500// ++alias CSIBM500// IBM500// ++alias OSF100201F4// IBM500// ++alias CP1084// IBM500// ++module IBM500// INTERNAL IBM500 1 ++module INTERNAL IBM500// IBM500 1 ++ ++# from to module cost ++alias CP850// IBM850// ++alias 850// IBM850// ++alias CSPC850MULTILINGUAL// IBM850// ++alias OSF10020352// IBM850// ++module IBM850// INTERNAL IBM850 1 ++module INTERNAL IBM850// IBM850 1 ++ ++# from to module cost ++alias CP858// IBM858// ++alias 858// IBM858// ++alias CSPC858MULTILINGUAL// IBM858// ++module IBM858// INTERNAL IBM858 1 ++module INTERNAL IBM858// IBM858 1 ++ ++# from to module cost ++alias CP851// IBM851// ++alias 851// IBM851// ++alias CSIBM851// IBM851// ++module IBM851// INTERNAL IBM851 1 ++module INTERNAL IBM851// IBM851 1 ++ ++# from to module cost ++alias CP852// IBM852// ++alias 852// IBM852// ++alias CSPCP852// IBM852// ++alias OSF10020354// IBM852// ++module IBM852// INTERNAL IBM852 1 ++module INTERNAL IBM852// IBM852 1 ++ ++# from to module cost ++alias CP855// IBM855// ++alias 855// IBM855// ++alias CSIBM855// IBM855// ++alias OSF10020357// IBM855// ++module IBM855// INTERNAL IBM855 1 ++module INTERNAL IBM855// IBM855 1 ++ ++# from to module cost ++alias IBM-856// IBM856// ++alias CP856// IBM856// ++alias 856// IBM856// ++alias CSIBM856// IBM856// ++module IBM856// INTERNAL IBM856 1 ++module INTERNAL IBM856// IBM856 1 ++ ++# from to module cost ++alias CP857// IBM857// ++alias 857// IBM857// ++alias CSIBM857// IBM857// ++alias OSF10020359// IBM857// ++module IBM857// INTERNAL IBM857 1 ++module INTERNAL IBM857// IBM857 1 ++ ++# from to module cost ++alias CP860// IBM860// ++alias 860// IBM860// ++alias CSIBM860// IBM860// ++module IBM860// INTERNAL IBM860 1 ++module INTERNAL IBM860// IBM860 1 ++ ++# from to module cost ++alias CP861// IBM861// ++alias 861// IBM861// ++alias CPIBM861// IBM861// ++alias OSF1002035D// IBM861// ++module IBM861// INTERNAL IBM861 1 ++module INTERNAL IBM861// IBM861 1 ++ ++# from to module cost ++alias CP862// IBM862// ++alias 862// IBM862// ++alias CSPC862LATINHEBREW// IBM862// ++alias OSF1002035E// IBM862// ++module IBM862// INTERNAL IBM862 1 ++module INTERNAL IBM862// IBM862 1 ++ ++# from to module cost ++alias CP863// IBM863// ++alias 863// IBM863// ++alias CSIBM863// IBM863// ++alias OSF1002035F// IBM863// ++module IBM863// INTERNAL IBM863 1 ++module INTERNAL IBM863// IBM863 1 ++ ++# from to module cost ++alias CP864// IBM864// ++alias 864// IBM864// ++alias CSIBM864// IBM864// ++alias OSF10020360// IBM864// ++module IBM864// INTERNAL IBM864 1 ++module INTERNAL IBM864// IBM864 1 ++ ++# from to module cost ++alias CP865// IBM865// ++alias 865// IBM865// ++alias CSIBM865// IBM865// ++module IBM865// INTERNAL IBM865 1 ++module INTERNAL IBM865// IBM865 1 ++ ++# from to module cost ++alias CP866// IBM866// ++alias 866// IBM866// ++alias CSIBM866// IBM866// ++module IBM866// INTERNAL IBM866 1 ++module INTERNAL IBM866// IBM866 1 ++ ++# from to module cost ++alias CP866NAV// IBM866NAV// ++alias 866NAV// IBM866NAV// ++module IBM866NAV// INTERNAL IBM866NAV 1 ++module INTERNAL IBM866NAV// IBM866NAV 1 ++ ++# from to module cost ++alias CP868// IBM868// ++alias CP-AR// IBM868// ++alias CSIBM868// IBM868// ++alias OSF10020364// IBM868// ++module IBM868// INTERNAL IBM868 1 ++module INTERNAL IBM868// IBM868 1 ++ ++# from to module cost ++alias CP869// IBM869// ++alias 869// IBM869// ++alias CP-GR// IBM869// ++alias CSIBM869// IBM869// ++alias OSF10020365// IBM869// ++module IBM869// INTERNAL IBM869 1 ++module INTERNAL IBM869// IBM869 1 ++ ++# from to module cost ++alias CP870// IBM870// ++alias EBCDIC-CP-ROECE// IBM870// ++alias EBCDIC-CP-YU// IBM870// ++alias CSIBM870// IBM870// ++alias OSF10020366// IBM870// ++module IBM870// INTERNAL IBM870 1 ++module INTERNAL IBM870// IBM870 1 ++ ++# from to module cost ++alias CP871// IBM871// ++alias EBCDIC-CP-IS// IBM871// ++alias CSIBM871// IBM871// ++alias OSF10020367// IBM871// ++module IBM871// INTERNAL IBM871 1 ++module INTERNAL IBM871// IBM871 1 ++ ++# from to module cost ++alias CP875// IBM875// ++alias EBCDIC-GREEK// IBM875// ++alias OSF1002036B// IBM875// ++module IBM875// INTERNAL IBM875 1 ++module INTERNAL IBM875// IBM875 1 ++ ++# from to module cost ++alias CP880// IBM880// ++alias EBCDIC-CYRILLIC// IBM880// ++alias CSIBM880// IBM880// ++alias OSF10020370// IBM880// ++module IBM880// INTERNAL IBM880 1 ++module INTERNAL IBM880// IBM880 1 ++ ++# from to module cost ++alias CP891// IBM891// ++alias CSIBM891// IBM891// ++alias OSF1002037B// IBM891// ++module IBM891// INTERNAL IBM891 1 ++module INTERNAL IBM891// IBM891 1 ++ ++# from to module cost ++alias CP903// IBM903// ++alias CSIBM903// IBM903// ++alias OSF10020387// IBM903// ++module IBM903// INTERNAL IBM903 1 ++module INTERNAL IBM903// IBM903 1 ++ ++# from to module cost ++alias CP904// IBM904// ++alias 904// IBM904// ++alias CSIBM904// IBM904// ++alias OSF10020388// IBM904// ++module IBM904// INTERNAL IBM904 1 ++module INTERNAL IBM904// IBM904 1 ++ ++# from to module cost ++alias CP905// IBM905// ++alias EBCDIC-CP-TR// IBM905// ++alias CSIBM905// IBM905// ++module IBM905// INTERNAL IBM905 1 ++module INTERNAL IBM905// IBM905 1 ++ ++# from to module cost ++alias CP918// IBM918// ++alias EBCDIC-CP-AR2// IBM918// ++alias CSIBM918// IBM918// ++alias OSF10020396// IBM918// ++module IBM918// INTERNAL IBM918 1 ++module INTERNAL IBM918// IBM918 1 ++ ++# from to module cost ++alias IBM-922// IBM922// ++alias CP922// IBM922// ++alias CSIBM922// IBM922// ++module IBM922// INTERNAL IBM922 1 ++module INTERNAL IBM922// IBM922 1 ++ ++# from to module cost ++alias IBM-930// IBM930// ++alias CP930// IBM930// ++alias CSIBM930// IBM930// ++module IBM930// INTERNAL IBM930 1 ++module INTERNAL IBM930// IBM930 1 ++ ++# from to module cost ++alias IBM-932// IBM932// ++alias CSIBM932// IBM932// ++module IBM932// INTERNAL IBM932 1 ++module INTERNAL IBM932// IBM932 1 ++ ++# from to module cost ++alias IBM-933// IBM933// ++alias CP933// IBM933// ++alias CSIBM933// IBM933// ++module IBM933// INTERNAL IBM933 1 ++module INTERNAL IBM933// IBM933 1 ++ ++# from to module cost ++alias IBM-935// IBM935// ++alias CP935// IBM935// ++alias CSIBM935// IBM935// ++module IBM935// INTERNAL IBM935 1 ++module INTERNAL IBM935// IBM935 1 ++ ++# from to module cost ++alias IBM-937// IBM937// ++alias CP937// IBM937// ++alias CSIBM937// IBM937// ++module IBM937// INTERNAL IBM937 1 ++module INTERNAL IBM937// IBM937 1 ++ ++# from to module cost ++alias IBM-939// IBM939// ++alias CP939// IBM939// ++alias CSIBM939// IBM939// ++module IBM939// INTERNAL IBM939 1 ++module INTERNAL IBM939// IBM939 1 ++ ++# from to module cost ++alias IBM-943// IBM943// ++alias CSIBM943// IBM943// ++module IBM943// INTERNAL IBM943 1 ++module INTERNAL IBM943// IBM943 1 ++ ++# from to module cost ++alias CP1004// IBM1004// ++alias OS2LATIN1// IBM1004// ++module IBM1004// INTERNAL IBM1004 1 ++module INTERNAL IBM1004// IBM1004 1 ++ ++# from to module cost ++alias CP1026// IBM1026// ++alias 1026// IBM1026// ++alias CSIBM1026// IBM1026// ++alias OSF10020402// IBM1026// ++module IBM1026// INTERNAL IBM1026 1 ++module INTERNAL IBM1026// IBM1026 1 ++ ++# from to module cost ++alias IBM-1046// IBM1046// ++alias CP1046// IBM1046// ++alias 1046// IBM1046// ++module IBM1046// INTERNAL IBM1046 1 ++module INTERNAL IBM1046// IBM1046 1 ++ ++# from to module cost ++alias IBM-1047// IBM1047// ++alias CP1047// IBM1047// ++alias 1047// IBM1047// ++alias OSF10020417// IBM1047// ++module IBM1047// INTERNAL IBM1047 1 ++module INTERNAL IBM1047// IBM1047 1 ++ ++# from to module cost ++alias IBM-1124// IBM1124// ++alias CP1124// IBM1124// ++alias CSIBM1124// IBM1124// ++module IBM1124// INTERNAL IBM1124 1 ++module INTERNAL IBM1124// IBM1124 1 ++ ++# from to module cost ++alias IBM-1129// IBM1129// ++alias CP1129// IBM1129// ++alias CSIBM1129// IBM1129// ++module IBM1129// INTERNAL IBM1129 1 ++module INTERNAL IBM1129// IBM1129 1 ++ ++# from to module cost ++alias IBM-1160// IBM1160// ++alias CP1160// IBM1160// ++alias CSIBM1160// IBM1160// ++module IBM1160// INTERNAL IBM1160 1 ++module INTERNAL IBM1160// IBM1160 1 ++ ++# from to module cost ++alias IBM-1161// IBM1161// ++alias CP1161// IBM1161// ++alias CSIBM1161// IBM1161// ++module IBM1161// INTERNAL IBM1161 1 ++module INTERNAL IBM1161// IBM1161 1 ++ ++# from to module cost ++alias IBM-1132// IBM1132// ++alias CP1132// IBM1132// ++alias CSIBM1132// IBM1132// ++module IBM1132// INTERNAL IBM1132 1 ++module INTERNAL IBM1132// IBM1132 1 ++ ++# from to module cost ++alias IBM-1133// IBM1133// ++alias CP1133// IBM1133// ++alias CSIBM1133// IBM1133// ++module IBM1133// INTERNAL IBM1133 1 ++module INTERNAL IBM1133// IBM1133 1 ++ ++# from to module cost ++alias IBM-1162// IBM1162// ++alias CP1162// IBM1162// ++alias CSIBM11621162// IBM1162// ++module IBM1162// INTERNAL IBM1162 1 ++module INTERNAL IBM1162// IBM1162 1 ++ ++# from to module cost ++alias IBM-1163// IBM1163// ++alias CP1163// IBM1163// ++alias CSIBM1163// IBM1163// ++module IBM1163// INTERNAL IBM1163 1 ++module INTERNAL IBM1163// IBM1163 1 ++ ++# from to module cost ++alias IBM-1164// IBM1164// ++alias CP1164// IBM1164// ++alias CSIBM1164// IBM1164// ++module IBM1164// INTERNAL IBM1164 1 ++module INTERNAL IBM1164// IBM1164 1 ++ ++# from to module cost ++alias EUCKR// EUC-KR// ++alias CSEUCKR// EUC-KR// ++alias OSF0004000a// EUC-KR// ++module EUC-KR// INTERNAL EUC-KR 1 ++module INTERNAL EUC-KR// EUC-KR 1 ++ ++# from to module cost ++alias MSCP949// UHC// ++alias CP949// UHC// ++alias OSF100203B5// UHC// ++module UHC// INTERNAL UHC 1 ++module INTERNAL UHC// UHC 1 ++ ++# from to module cost ++alias MSCP1361// JOHAB// ++alias CP1361// JOHAB// ++module JOHAB// INTERNAL JOHAB 1 ++module INTERNAL JOHAB// JOHAB 1 ++ ++# from to module cost ++alias BIG-FIVE// BIG5// ++alias BIGFIVE// BIG5// ++alias BIG-5// BIG5// ++alias CN-BIG5// BIG5// ++alias CP950// BIG5// ++module BIG5// INTERNAL BIG5 1 ++module INTERNAL BIG5// BIG5 1 ++ ++# from to module cost ++alias BIG5-HKSCS// BIG5HKSCS// ++module BIG5HKSCS// INTERNAL BIG5HKSCS 1 ++module INTERNAL BIG5HKSCS// BIG5HKSCS 1 ++ ++# from to module cost ++alias EUCJP-MS// EUC-JP-MS// ++alias EUCJP-OPEN// EUC-JP-MS// ++alias EUCJP-WIN// EUC-JP-MS// ++module EUC-JP-MS// INTERNAL EUC-JP-MS 1 ++module INTERNAL EUC-JP-MS// EUC-JP-MS 1 ++ ++# from to module cost ++alias EUCJP// EUC-JP// ++alias CSEUCPKDFMTJAPANESE// EUC-JP// ++alias OSF00030010// EUC-JP// ++alias UJIS// EUC-JP// ++module EUC-JP// INTERNAL EUC-JP 1 ++module INTERNAL EUC-JP// EUC-JP 1 ++ ++# from to module cost ++alias EUCCN// EUC-CN// ++alias GB2312// EUC-CN// ++alias csGB2312// EUC-CN// ++alias CN-GB// EUC-CN// ++module EUC-CN// INTERNAL EUC-CN 1 ++module INTERNAL EUC-CN// EUC-CN 1 ++ ++# from to module cost ++module EUC-CN// BIG5// GBBIG5 1 ++module BIG5// EUC-CN// GBBIG5 1 ++ ++# from to module cost ++alias GB13000// GBK// ++alias CP936// GBK// ++alias MS936// GBK// ++alias WINDOWS-936// GBK// ++module GBK// INTERNAL GBK 1 ++module INTERNAL GBK// GBK 1 ++ ++# from to module cost ++module GBK// EUC-CN// GBGBK 1 ++module EUC-CN// GBK// GBGBK 1 ++ ++# from to module cost ++alias EUCTW// EUC-TW// ++alias OSF0005000a// EUC-TW// ++module EUC-TW// INTERNAL EUC-TW 1 ++module INTERNAL EUC-TW// EUC-TW 1 ++ ++# from to module cost ++alias RUSCII// CP1125// ++alias IBM848// CP1125// ++module CP1125// INTERNAL CP1125 1 ++module INTERNAL CP1125// CP1125 1 ++ ++# from to module cost ++alias MS-EE// CP1250// ++alias WINDOWS-1250// CP1250// ++module CP1250// INTERNAL CP1250 1 ++module INTERNAL CP1250// CP1250 1 ++ ++# from to module cost ++alias MS-CYRL// CP1251// ++alias WINDOWS-1251// CP1251// ++module CP1251// INTERNAL CP1251 1 ++module INTERNAL CP1251// CP1251 1 ++ ++# from to module cost ++alias MS-GREEK// CP1253// ++alias WINDOWS-1253// CP1253// ++module CP1253// INTERNAL CP1253 1 ++module INTERNAL CP1253// CP1253 1 ++ ++# from to module cost ++alias MS-TURK// CP1254// ++alias WINDOWS-1254// CP1254// ++module CP1254// INTERNAL CP1254 1 ++module INTERNAL CP1254// CP1254 1 ++ ++# from to module cost ++alias MS-HEBR// CP1255// ++alias WINDOWS-1255// CP1255// ++module CP1255// INTERNAL CP1255 1 ++module INTERNAL CP1255// CP1255 1 ++ ++# from to module cost ++alias MS-ARAB// CP1256// ++alias WINDOWS-1256// CP1256// ++module CP1256// INTERNAL CP1256 1 ++module INTERNAL CP1256// CP1256 1 ++ ++# from to module cost ++alias WINBALTRIM// CP1257// ++alias WINDOWS-1257// CP1257// ++module CP1257// INTERNAL CP1257 1 ++module INTERNAL CP1257// CP1257 1 ++ ++# from to module cost ++alias WINDOWS-1258// CP1258// ++module CP1258// INTERNAL CP1258 1 ++module INTERNAL CP1258// CP1258 1 ++ ++# from to module cost ++alias 874// IBM874// ++alias CP874// IBM874// ++alias WINDOWS-874// IBM874// ++module IBM874// INTERNAL IBM874 1 ++module INTERNAL IBM874// IBM874 1 ++ ++# from to module cost ++module CP737// INTERNAL CP737 1 ++module INTERNAL CP737// CP737 1 ++ ++# from to module cost ++module CP770// INTERNAL CP770 1 ++module INTERNAL CP770// CP770 1 ++ ++# from to module cost ++module CP771// INTERNAL CP771 1 ++module INTERNAL CP771// CP771 1 ++ ++# from to module cost ++module CP772// INTERNAL CP772 1 ++module INTERNAL CP772// CP772 1 ++ ++# from to module cost ++module CP773// INTERNAL CP773 1 ++module INTERNAL CP773// CP773 1 ++ ++# from to module cost ++module CP774// INTERNAL CP774 1 ++module INTERNAL CP774// CP774 1 ++ ++# from to module cost ++alias IBM775// CP775// ++alias CSPC775BALTIC// CP775// ++module CP775// INTERNAL CP775 1 ++module INTERNAL CP775// CP775 1 ++ ++# from to module cost ++alias CSISO2022JP// ISO-2022-JP// ++alias ISO2022JP// ISO-2022-JP// ++module ISO-2022-JP// INTERNAL ISO-2022-JP 1 ++module INTERNAL ISO-2022-JP// ISO-2022-JP 1 ++ ++# from to module cost ++alias CSISO2022JP2// ISO-2022-JP-2// ++alias ISO2022JP2// ISO-2022-JP-2// ++module ISO-2022-JP-2// INTERNAL ISO-2022-JP 1 ++module INTERNAL ISO-2022-JP-2// ISO-2022-JP 1 ++ ++# from to module cost ++module ISO-2022-JP-3// INTERNAL ISO-2022-JP-3 1 ++module INTERNAL ISO-2022-JP-3// ISO-2022-JP-3 1 ++ ++# from to module cost ++alias CSISO2022KR// ISO-2022-KR// ++alias ISO2022KR// ISO-2022-KR// ++module ISO-2022-KR// INTERNAL ISO-2022-KR 1 ++module INTERNAL ISO-2022-KR// ISO-2022-KR 1 ++ ++# from to module cost ++alias CSISO2022CN// ISO-2022-CN// ++alias ISO2022CN// ISO-2022-CN// ++module ISO-2022-CN// INTERNAL ISO-2022-CN 1 ++module INTERNAL ISO-2022-CN// ISO-2022-CN 1 ++ ++# from to module cost ++alias ISO2022CNEXT// ISO-2022-CN-EXT// ++module ISO-2022-CN-EXT// INTERNAL ISO-2022-CN-EXT 1 ++module INTERNAL ISO-2022-CN-EXT// ISO-2022-CN-EXT 1 ++ ++# from to module cost ++alias MAC// MACINTOSH// ++alias CSMACINTOSH// MACINTOSH// ++module MACINTOSH// INTERNAL MACINTOSH 1 ++module INTERNAL MACINTOSH// MACINTOSH 1 ++ ++# from to module cost ++alias ISO-IR-143// IEC_P27-1// ++alias CSISO143IECP271// IEC_P27-1// ++alias IEC_P271// IEC_P27-1// ++module IEC_P27-1// INTERNAL IEC_P27-1 1 ++module INTERNAL IEC_P27-1// IEC_P27-1 1 ++ ++# from to module cost ++alias ISO_9036// ASMO_449// ++alias ARABIC7// ASMO_449// ++alias ISO-IR-89// ASMO_449// ++alias CSISO89ASMO449// ASMO_449// ++module ASMO_449// INTERNAL ASMO_449 1 ++module INTERNAL ASMO_449// ASMO_449 1 ++ ++# from to module cost ++alias ISO-IR-139// CSN_369103// ++alias CSISO139CSN369103// CSN_369103// ++module CSN_369103// INTERNAL CSN_369103 1 ++module INTERNAL CSN_369103// CSN_369103 1 ++ ++# from to module cost ++alias CWI-2// CWI// ++alias CP-HU// CWI// ++module CWI// INTERNAL CWI 1 ++module INTERNAL CWI// CWI 1 ++ ++# from to module cost ++alias DEC// DEC-MCS// ++alias CSDECMCS// DEC-MCS// ++alias DECMCS// DEC-MCS// ++module DEC-MCS// INTERNAL DEC-MCS 1 ++module INTERNAL DEC-MCS// DEC-MCS 1 ++ ++# from to module cost ++alias ISO-IR-111// ECMA-CYRILLIC// ++alias CSISO111ECMACYRILLIC// ECMA-CYRILLIC// ++alias ECMACYRILLIC// ECMA-CYRILLIC// ++module ECMA-CYRILLIC// INTERNAL ECMA-CYRILLIC 1 ++module INTERNAL ECMA-CYRILLIC// ECMA-CYRILLIC 1 ++ ++# from to module cost ++alias ST_SEV_358-88// GOST_19768-74// ++alias GOST_19768// GOST_19768-74// ++alias ISO-IR-153// GOST_19768-74// ++alias CSISO153GOST1976874// GOST_19768-74// ++alias GOST_1976874// GOST_19768-74// ++module GOST_19768-74// INTERNAL GOST_19768-74 1 ++module INTERNAL GOST_19768-74// GOST_19768-74 1 ++ ++# from to module cost ++alias ISO-IR-150// GREEK-CCITT// ++alias CSISO150// GREEK-CCITT// ++alias CSISO150GREEKCCITT// GREEK-CCITT// ++alias GREEKCCITT// GREEK-CCITT// ++module GREEK-CCITT// INTERNAL GREEK-CCITT 1 ++module INTERNAL GREEK-CCITT// GREEK-CCITT 1 ++ ++# from to module cost ++alias ISO-IR-88// GREEK7// ++alias CSISO88GREEK7// GREEK7// ++module GREEK7// INTERNAL GREEK7 1 ++module INTERNAL GREEK7// GREEK7 1 ++ ++# from to module cost ++alias ISO-IR-18// GREEK7-OLD// ++alias CSISO18GREEK7OLD// GREEK7-OLD// ++alias GREEK7OLD// GREEK7-OLD// ++module GREEK7-OLD// INTERNAL GREEK7-OLD 1 ++module INTERNAL GREEK7-OLD// GREEK7-OLD 1 ++ ++# from to module cost ++alias ISO-IR-49// INIS// ++alias CSISO49INIS// INIS// ++module INIS// INTERNAL INIS 1 ++module INTERNAL INIS// INIS 1 ++ ++# from to module cost ++alias ISO-IR-50// INIS-8// ++alias CSISO50INIS8// INIS-8// ++alias INIS8// INIS-8// ++module INIS-8// INTERNAL INIS-8 1 ++module INTERNAL INIS-8// INIS-8 1 ++ ++# from to module cost ++alias ISO-IR-51// INIS-CYRILLIC// ++alias CSISO51INISCYRILLIC// INIS-CYRILLIC// ++alias INISCYRILLIC// INIS-CYRILLIC// ++module INIS-CYRILLIC// INTERNAL INIS-CYRILLIC 1 ++module INTERNAL INIS-CYRILLIC// INIS-CYRILLIC 1 ++ ++# from to module cost ++alias ISO-IR-98// ISO_2033// ++alias ISO_2033-1983// ISO_2033// ++alias E13B// ISO_2033// ++alias CSISO2033// ISO_2033// ++module ISO_2033// INTERNAL ISO_2033 1 ++module INTERNAL ISO_2033// ISO_2033 1 ++ ++# from to module cost ++alias ISO-IR-37// ISO_5427// ++alias KOI-7// ISO_5427// ++alias CSISO5427CYRILLIC// ISO_5427// ++module ISO_5427// INTERNAL ISO_5427 1 ++module INTERNAL ISO_5427// ISO_5427 1 ++ ++# from to module cost ++alias ISO-IR-54// ISO_5427-EXT// ++alias ISO_5427:1981// ISO_5427-EXT// ++alias CSISO5427CYRILLIC1981// ISO_5427-EXT// ++alias ISO_5427EXT// ISO_5427-EXT// ++module ISO_5427-EXT// INTERNAL ISO_5427-EXT 1 ++module INTERNAL ISO_5427-EXT// ISO_5427-EXT 1 ++ ++# from to module cost ++alias ISO-IR-55// ISO_5428// ++alias ISO_5428:1980// ISO_5428// ++alias CSISO5428GREEK// ISO_5428// ++module ISO_5428// INTERNAL ISO_5428 1 ++module INTERNAL ISO_5428// ISO_5428 1 ++ ++# from to module cost ++alias ISO-IR-155// ISO_10367-BOX// ++alias CSISO10367BOX// ISO_10367-BOX// ++alias ISO_10367BOX// ISO_10367-BOX// ++module ISO_10367-BOX// INTERNAL ISO_10367-BOX 1 ++module INTERNAL ISO_10367-BOX// ISO_10367-BOX 1 ++ ++# from to module cost ++alias MACIS// MAC-IS// ++module MAC-IS// INTERNAL MAC-IS 1 ++module INTERNAL MAC-IS// MAC-IS 1 ++ ++# from to module cost ++alias MACUK// MAC-UK// ++alias MACUKRAINIAN// MAC-UK// ++alias MAC-CYRILLIC// MAC-UK// ++alias MACCYRILLIC// MAC-UK// ++module MAC-UK// INTERNAL MAC-UK 1 ++module INTERNAL MAC-UK// MAC-UK 1 ++ ++# from to module cost ++alias MS-MAC-CYRILLIC// CP10007// ++alias MSMACCYRILLIC// CP10007// ++module CP10007// INTERNAL CP10007 1 ++module INTERNAL CP10007// CP10007 1 ++ ++# from to module cost ++alias ISO-IR-9-1// NATS-DANO// ++alias CSNATSDANO// NATS-DANO// ++alias NATSDANO// NATS-DANO// ++module NATS-DANO// INTERNAL NATS-DANO 1 ++module INTERNAL NATS-DANO// NATS-DANO 1 ++ ++# from to module cost ++alias ISO-IR-8-1// NATS-SEFI// ++alias CSNATSSEFI// NATS-SEFI// ++alias NATSSEFI// NATS-SEFI// ++module NATS-SEFI// INTERNAL NATS-SEFI 1 ++module INTERNAL NATS-SEFI// NATS-SEFI 1 ++ ++# from to module cost ++alias WS2// WIN-SAMI-2// ++alias WINSAMI2// WIN-SAMI-2// ++module WIN-SAMI-2// INTERNAL SAMI-WS2 1 ++module INTERNAL WIN-SAMI-2// SAMI-WS2 1 ++ ++# from to module cost ++module ISO-IR-197// INTERNAL ISO-IR-197 1 ++module INTERNAL ISO-IR-197// ISO-IR-197 1 ++ ++# from to module cost ++alias TIS620// TIS-620// ++alias TIS620-0// TIS-620// ++alias TIS620.2529-1// TIS-620// ++alias TIS620.2533-0// TIS-620// ++alias ISO-IR-166// TIS-620// ++module TIS-620// INTERNAL TIS-620 1 ++module INTERNAL TIS-620// TIS-620 1 ++ ++# from to module cost ++alias KOI8U// KOI8-U// ++module KOI8-U// INTERNAL KOI8-U 1 ++module INTERNAL KOI8-U// KOI8-U 1 ++ ++# from to module cost ++alias ISIRI3342// ISIRI-3342// ++module ISIRI-3342// INTERNAL ISIRI-3342 1 ++module INTERNAL ISIRI-3342// ISIRI-3342 1 ++ ++# from to module cost ++module GB18030// INTERNAL GB18030 1 ++module INTERNAL GB18030// GB18030 1 ++ ++# from to module cost ++module VISCII// INTERNAL VISCII 1 ++module INTERNAL VISCII// VISCII 1 ++ ++# from to module cost ++module KOI8-T// INTERNAL KOI8-T 1 ++module INTERNAL KOI8-T// KOI8-T 1 ++ ++# from to module cost ++module GEORGIAN-PS// INTERNAL GEORGIAN-PS 1 ++module INTERNAL GEORGIAN-PS// GEORGIAN-PS 1 ++ ++# from to module cost ++module GEORGIAN-ACADEMY// INTERNAL GEORGIAN-ACADEMY 1 ++module INTERNAL GEORGIAN-ACADEMY// GEORGIAN-ACADEMY 1 ++ ++# from to module cost ++module ISO-IR-209// INTERNAL ISO-IR-209 1 ++module INTERNAL ISO-IR-209// ISO-IR-209 1 ++ ++# from to module cost ++module MAC-SAMI// INTERNAL MAC-SAMI 1 ++module INTERNAL MAC-SAMI// MAC-SAMI 1 ++ ++# from to module cost ++alias ARMSCII8// ARMSCII-8// ++module ARMSCII-8// INTERNAL ARMSCII-8 1 ++module INTERNAL ARMSCII-8// ARMSCII-8 1 ++ ++# from to module cost ++alias TCVN// TCVN5712-1// ++alias TCVN-5712// TCVN5712-1// ++alias TCVN5712-1:1993// TCVN5712-1// ++module TCVN5712-1// INTERNAL TCVN5712-1 1 ++module INTERNAL TCVN5712-1// TCVN5712-1 1 ++ ++# from to module cost ++module EUC-JISX0213// INTERNAL EUC-JISX0213 1 ++module INTERNAL EUC-JISX0213// EUC-JISX0213 1 ++ ++# from to module cost ++alias ShiftJISX0213// Shift_JISX0213// ++module Shift_JISX0213// INTERNAL SHIFT_JISX0213 1 ++module INTERNAL Shift_JISX0213// SHIFT_JISX0213 1 ++ ++# from to module cost ++module TSCII// INTERNAL TSCII 1 ++module INTERNAL TSCII// TSCII 1 ++ ++# from to module cost ++module PT154// INTERNAL PT154 1 ++module INTERNAL PT154// PT154 1 ++ ++# from to module cost ++alias STRK1048-2002// RK1048// ++module RK1048// INTERNAL RK1048 1 ++module INTERNAL RK1048// RK1048 1 ++ ++# from to module cost ++alias IBM-1025// IBM1025// ++alias CP1025// IBM1025// ++alias CSIBM1025// IBM1025// ++module IBM1025// INTERNAL IBM1025 1 ++module INTERNAL IBM1025// IBM1025 1 ++ ++# from to module cost ++alias IBM-1122// IBM1122// ++alias CP1122// IBM1122// ++alias CSIBM1122// IBM1122// ++module IBM1122// INTERNAL IBM1122 1 ++module INTERNAL IBM1122// IBM1122 1 ++ ++# from to module cost ++alias IBM-1137// IBM1137// ++alias CP1137// IBM1137// ++alias CSIBM1137// IBM1137// ++module IBM1137// INTERNAL IBM1137 1 ++module INTERNAL IBM1137// IBM1137 1 ++ ++# from to module cost ++alias IBM-1153// IBM1153// ++alias CP1153// IBM1153// ++alias CSIBM1153// IBM1153// ++module IBM1153// INTERNAL IBM1153 1 ++module INTERNAL IBM1153// IBM1153 1 ++ ++# from to module cost ++alias IBM-1154// IBM1154// ++alias CP1154// IBM1154// ++alias CSIBM1154// IBM1154// ++module IBM1154// INTERNAL IBM1154 1 ++module INTERNAL IBM1154// IBM1154 1 ++ ++# from to module cost ++alias IBM-1155// IBM1155// ++alias CP1155// IBM1155// ++alias CSIBM1155// IBM1155// ++module IBM1155// INTERNAL IBM1155 1 ++module INTERNAL IBM1155// IBM1155 1 ++ ++# from to module cost ++alias IBM-1156// IBM1156// ++alias CP1156// IBM1156// ++alias CSIBM1156// IBM1156// ++module IBM1156// INTERNAL IBM1156 1 ++module INTERNAL IBM1156// IBM1156 1 ++ ++# from to module cost ++alias IBM-1157// IBM1157// ++alias CP1157// IBM1157// ++alias CSIBM1157// IBM1157// ++module IBM1157// INTERNAL IBM1157 1 ++module INTERNAL IBM1157// IBM1157 1 ++ ++# from to module cost ++alias IBM-1158// IBM1158// ++alias CP1158// IBM1158// ++alias CSIBM1158// IBM1158// ++module IBM1158// INTERNAL IBM1158 1 ++module INTERNAL IBM1158// IBM1158 1 ++ ++# from to module cost ++alias IBM-803// IBM803// ++alias CP803// IBM803// ++alias CSIBM803// IBM803// ++module IBM803// INTERNAL IBM803 1 ++module INTERNAL IBM803// IBM803 1 ++ ++# from to module cost ++alias IBM-901// IBM901// ++alias CP901// IBM901// ++alias CSIBM901// IBM901// ++module IBM901// INTERNAL IBM901 1 ++module INTERNAL IBM901// IBM901 1 ++ ++# from to module cost ++alias IBM-902// IBM902// ++alias CP902// IBM902// ++alias CSIBM902// IBM902// ++module IBM902// INTERNAL IBM902 1 ++module INTERNAL IBM902// IBM902 1 ++ ++# from to module cost ++alias IBM-921// IBM921// ++alias CP921// IBM921// ++alias CSIBM921// IBM921// ++module IBM921// INTERNAL IBM921 1 ++module INTERNAL IBM921// IBM921 1 ++ ++# from to module cost ++alias IBM-1008// IBM1008// ++alias CP1008// IBM1008// ++alias CSIBM1008// IBM1008// ++module IBM1008// INTERNAL IBM1008 1 ++module INTERNAL IBM1008// IBM1008 1 ++ ++# from to module cost ++module IBM1008// IBM420// IBM1008_420 1 ++module IBM420// IBM1008// IBM1008_420 1 ++ ++# from to module cost ++alias IBM-1097// IBM1097// ++alias CP1097// IBM1097// ++alias CSIBM1097// IBM1097// ++module IBM1097// INTERNAL IBM1097 1 ++module INTERNAL IBM1097// IBM1097 1 ++ ++# from to module cost ++alias IBM-1112// IBM1112// ++alias CP1112// IBM1112// ++alias CSIBM1112// IBM1112// ++module IBM1112// INTERNAL IBM1112 1 ++module INTERNAL IBM1112// IBM1112 1 ++ ++# from to module cost ++alias IBM-1123// IBM1123// ++alias CP1123// IBM1123// ++alias CSIBM1123// IBM1123// ++module IBM1123// INTERNAL IBM1123 1 ++module INTERNAL IBM1123// IBM1123 1 ++ ++# from to module cost ++alias IBM-1130// IBM1130// ++alias CP1130// IBM1130// ++alias CSIBM1130// IBM1130// ++module IBM1130// INTERNAL IBM1130 1 ++module INTERNAL IBM1130// IBM1130 1 ++ ++# from to module cost ++alias IBM-1140// IBM1140// ++alias CP1140// IBM1140// ++alias CSIBM1140// IBM1140// ++module IBM1140// INTERNAL IBM1140 1 ++module INTERNAL IBM1140// IBM1140 1 ++ ++# from to module cost ++alias IBM-1141// IBM1141// ++alias CP1141// IBM1141// ++alias CSIBM1141// IBM1141// ++module IBM1141// INTERNAL IBM1141 1 ++module INTERNAL IBM1141// IBM1141 1 ++ ++# from to module cost ++alias IBM-1142// IBM1142// ++alias CP1142// IBM1142// ++alias CSIBM1142// IBM1142// ++module IBM1142// INTERNAL IBM1142 1 ++module INTERNAL IBM1142// IBM1142 1 ++ ++# from to module cost ++alias IBM-1143// IBM1143// ++alias CP1143// IBM1143// ++alias CSIBM1143// IBM1143// ++module IBM1143// INTERNAL IBM1143 1 ++module INTERNAL IBM1143// IBM1143 1 ++ ++# from to module cost ++alias IBM-1144// IBM1144// ++alias CP1144// IBM1144// ++alias CSIBM1144// IBM1144// ++module IBM1144// INTERNAL IBM1144 1 ++module INTERNAL IBM1144// IBM1144 1 ++ ++# from to module cost ++alias IBM-1145// IBM1145// ++alias CP1145// IBM1145// ++alias CSIBM1145// IBM1145// ++module IBM1145// INTERNAL IBM1145 1 ++module INTERNAL IBM1145// IBM1145 1 ++ ++# from to module cost ++alias IBM-1146// IBM1146// ++alias CP1146// IBM1146// ++alias CSIBM1146// IBM1146// ++module IBM1146// INTERNAL IBM1146 1 ++module INTERNAL IBM1146// IBM1146 1 ++ ++# from to module cost ++alias IBM-1147// IBM1147// ++alias CP1147// IBM1147// ++alias CSIBM1147// IBM1147// ++module IBM1147// INTERNAL IBM1147 1 ++module INTERNAL IBM1147// IBM1147 1 ++ ++# from to module cost ++alias IBM-1148// IBM1148// ++alias CP1148// IBM1148// ++alias CSIBM1148// IBM1148// ++module IBM1148// INTERNAL IBM1148 1 ++module INTERNAL IBM1148// IBM1148 1 ++ ++# from to module cost ++alias IBM-1149// IBM1149// ++alias CP1149// IBM1149// ++alias CSIBM1149// IBM1149// ++module IBM1149// INTERNAL IBM1149 1 ++module INTERNAL IBM1149// IBM1149 1 ++ ++# from to module cost ++alias IBM-1166// IBM1166// ++alias CP1166// IBM1166// ++alias CSIBM1166// IBM1166// ++module IBM1166// INTERNAL IBM1166 1 ++module INTERNAL IBM1166// IBM1166 1 ++ ++# from to module cost ++alias IBM-1167// IBM1167// ++alias CP1167// IBM1167// ++alias CSIBM1167// IBM1167// ++module IBM1167// INTERNAL IBM1167 1 ++module INTERNAL IBM1167// IBM1167 1 ++ ++# from to module cost ++alias IBM-4517// IBM4517// ++alias CP4517// IBM4517// ++alias CSIBM4517// IBM4517// ++module IBM4517// INTERNAL IBM4517 1 ++module INTERNAL IBM4517// IBM4517 1 ++ ++# from to module cost ++alias IBM-4899// IBM4899// ++alias CP4899// IBM4899// ++alias CSIBM4899// IBM4899// ++module IBM4899// INTERNAL IBM4899 1 ++module INTERNAL IBM4899// IBM4899 1 ++ ++# from to module cost ++alias IBM-4909// IBM4909// ++alias CP4909// IBM4909// ++alias CSIBM4909// IBM4909// ++module IBM4909// INTERNAL IBM4909 1 ++module INTERNAL IBM4909// IBM4909 1 ++ ++# from to module cost ++alias IBM-4971// IBM4971// ++alias CP4971// IBM4971// ++alias CSIBM4971// IBM4971// ++module IBM4971// INTERNAL IBM4971 1 ++module INTERNAL IBM4971// IBM4971 1 ++ ++# from to module cost ++alias IBM-5347// IBM5347// ++alias CP5347// IBM5347// ++alias CSIBM5347// IBM5347// ++module IBM5347// INTERNAL IBM5347 1 ++module INTERNAL IBM5347// IBM5347 1 ++ ++# from to module cost ++alias IBM-9030// IBM9030// ++alias CP9030// IBM9030// ++alias CSIBM9030// IBM9030// ++module IBM9030// INTERNAL IBM9030 1 ++module INTERNAL IBM9030// IBM9030 1 ++ ++# from to module cost ++alias IBM-9066// IBM9066// ++alias CP9066// IBM9066// ++alias CSIBM9066// IBM9066// ++module IBM9066// INTERNAL IBM9066 1 ++module INTERNAL IBM9066// IBM9066 1 ++ ++# from to module cost ++alias IBM-9448// IBM9448// ++alias CP9448// IBM9448// ++alias CSIBM9448// IBM9448// ++module IBM9448// INTERNAL IBM9448 1 ++module INTERNAL IBM9448// IBM9448 1 ++ ++# from to module cost ++alias IBM-12712// IBM12712// ++alias CP12712// IBM12712// ++alias CSIBM12712// IBM12712// ++module IBM12712// INTERNAL IBM12712 1 ++module INTERNAL IBM12712// IBM12712 1 ++ ++# from to module cost ++alias IBM-16804// IBM16804// ++alias CP16804// IBM16804// ++alias CSIBM16804// IBM16804// ++module IBM16804// INTERNAL IBM16804 1 ++module INTERNAL IBM16804// IBM16804 1 ++ ++# from to module cost ++alias IBM-1364// IBM1364// ++alias CP1364// IBM1364// ++alias CSIBM1364// IBM1364// ++module IBM1364// INTERNAL IBM1364 1 ++module INTERNAL IBM1364// IBM1364 1 ++ ++# from to module cost ++alias IBM-1371// IBM1371// ++alias CP1371// IBM1371// ++alias CSIBM1371// IBM1371// ++module IBM1371// INTERNAL IBM1371 1 ++module INTERNAL IBM1371// IBM1371 1 ++ ++# from to module cost ++alias IBM-1388// IBM1388// ++alias CP1388// IBM1388// ++alias CSIBM1388// IBM1388// ++module IBM1388// INTERNAL IBM1388 1 ++module INTERNAL IBM1388// IBM1388 1 ++ ++# from to module cost ++alias IBM-1390// IBM1390// ++alias CP1390// IBM1390// ++alias CSIBM1390// IBM1390// ++module IBM1390// INTERNAL IBM1390 1 ++module INTERNAL IBM1390// IBM1390 1 ++ ++# from to module cost ++alias IBM-1399// IBM1399// ++alias CP1399// IBM1399// ++alias CSIBM1399// IBM1399// ++module IBM1399// INTERNAL IBM1399 1 ++module INTERNAL IBM1399// IBM1399 1 ++ ++# from to module cost ++alias ISO/TR_11548-1/ ISO_11548-1// ++alias ISO11548-1// ISO_11548-1// ++module ISO_11548-1// INTERNAL ISO_11548-1 1 ++module INTERNAL ISO_11548-1// ISO_11548-1 1 ++ ++# from to module cost ++module MIK// INTERNAL MIK 1 ++module INTERNAL MIK// MIK 1 ++ ++# from to module cost ++module BRF// INTERNAL BRF 1 ++module INTERNAL BRF// BRF 1 ++ ++# from to module cost ++alias CP1282// MAC-CENTRALEUROPE// ++module MAC-CENTRALEUROPE// INTERNAL MAC-CENTRALEUROPE 1 ++module INTERNAL MAC-CENTRALEUROPE// MAC-CENTRALEUROPE 1 ++ ++# from to module cost ++module KOI8-RU// INTERNAL KOI8-RU 1 ++module INTERNAL KOI8-RU// KOI8-RU 1 ++ ++# from to module cost ++alias ISO_8859-9E// ISO-8859-9E// ++alias ISO8859-9E// ISO-8859-9E// ++alias ISO88599E// ISO-8859-9E// ++module ISO-8859-9E// INTERNAL ISO8859-9E 1 ++module INTERNAL ISO-8859-9E// ISO8859-9E 1 ++ ++# from to module cost ++alias ROMAN9// HP-ROMAN9// ++alias R9// HP-ROMAN9// ++alias HPROMAN9// HP-ROMAN9// ++module HP-ROMAN9// INTERNAL HP-ROMAN9 1 ++module INTERNAL HP-ROMAN9// HP-ROMAN9 1 ++ ++# from to module cost ++alias TURKISH8// HP-TURKISH8// ++alias HPTURKISH8// HP-TURKISH8// ++alias OSF10010006// HP-TURKISH8// ++module HP-TURKISH8// INTERNAL HP-TURKISH8 1 ++module INTERNAL HP-TURKISH8// HP-TURKISH8 1 ++ ++# from to module cost ++alias THAI8// HP-THAI8// ++alias HPTHAI8// HP-THAI8// ++module HP-THAI8// INTERNAL HP-THAI8 1 ++module INTERNAL HP-THAI8// HP-THAI8 1 ++ ++# from to module cost ++alias HPGREEK8// HP-GREEK8// ++alias OSF10010004// HP-GREEK8// ++module HP-GREEK8// INTERNAL HP-GREEK8 1 ++module INTERNAL HP-GREEK8// HP-GREEK8 1 +diff --git a/iconvdata/gconv-modules.conf b/iconvdata/gconv-modules.conf +index e12b0aa2ed41a234..e63dda673d749001 100644 +--- a/iconvdata/gconv-modules.conf ++++ b/iconvdata/gconv-modules.conf +@@ -31,178 +31,6 @@ + # alias: alias name which is not really recognized. + # name: the real name of the character set + +-alias ISO-IR-4// BS_4730// +-alias ISO646-GB// BS_4730// +-alias GB// BS_4730// +-alias UK// BS_4730// +-alias CSISO4UNITEDKINGDOM// BS_4730// +-module BS_4730// INTERNAL ISO646 2 +-module INTERNAL BS_4730// ISO646 2 +- +-alias ISO-IR-121// CSA_Z243.4-1985-1// +-alias ISO646-CA// CSA_Z243.4-1985-1// +-alias CSA7-1// CSA_Z243.4-1985-1// +-alias CA// CSA_Z243.4-1985-1// +-alias CSISO121CANADIAN1// CSA_Z243.4-1985-1// +-alias CSA_Z243.419851// CSA_Z243.4-1985-1// +-module CSA_Z243.4-1985-1// INTERNAL ISO646 2 +-module INTERNAL CSA_Z243.4-1985-1// ISO646 2 +- +-alias ISO-IR-122// CSA_Z243.4-1985-2// +-alias ISO646-CA2// CSA_Z243.4-1985-2// +-alias CSA7-2// CSA_Z243.4-1985-2// +-alias CSISO122CANADIAN2// CSA_Z243.4-1985-2// +-alias CSA_Z243.419852// CSA_Z243.4-1985-2// +-module CSA_Z243.4-1985-2// INTERNAL ISO646 2 +-module INTERNAL CSA_Z243.4-1985-2// ISO646 2 +- +-alias ISO-IR-21// DIN_66003// +-alias DE// DIN_66003// +-alias ISO646-DE// DIN_66003// +-alias CSISO21GERMAN// DIN_66003// +-module DIN_66003// INTERNAL ISO646 2 +-module INTERNAL DIN_66003// ISO646 2 +- +-alias DS2089// DS_2089// +-alias ISO646-DK// DS_2089// +-alias DK// DS_2089// +-alias CSISO646DANISH// DS_2089// +-module DS_2089// INTERNAL ISO646 2 +-module INTERNAL DS_2089// ISO646 2 +- +-alias ISO-IR-17// ES// +-alias ISO646-ES// ES// +-alias CSISO17SPANISH// ES// +-module ES// INTERNAL ISO646 2 +-module INTERNAL ES// ISO646 2 +- +-alias ISO-IR-85// ES2// +-alias ISO646-ES2// ES2// +-alias CSISO85SPANISH2// ES2// +-module ES2// INTERNAL ISO646 2 +-module INTERNAL ES2// ISO646 2 +- +-alias ISO-IR-57// GB_1988-80// +-alias CN// GB_1988-80// +-alias ISO646-CN// GB_1988-80// +-alias CSISO58GB1988// GB_1988-80// +-alias GB_198880// GB_1988-80// +-module GB_1988-80// INTERNAL ISO646 2 +-module INTERNAL GB_1988-80// ISO646 2 +- +-alias ISO-IR-15// IT// +-alias ISO646-IT// IT// +-alias CSISO15ITALIAN// IT// +-module IT// INTERNAL ISO646 2 +-module INTERNAL IT// ISO646 2 +- +-alias ISO-IR-14// JIS_C6220-1969-RO// +-alias JP// JIS_C6220-1969-RO// +-alias ISO646-JP// JIS_C6220-1969-RO// +-alias CSISO14JISC6220RO// JIS_C6220-1969-RO// +-alias JIS_C62201969RO// JIS_C6220-1969-RO// +-module JIS_C6220-1969-RO// INTERNAL ISO646 2 +-module INTERNAL JIS_C6220-1969-RO// ISO646 2 +- +-alias ISO-IR-92// JIS_C6229-1984-B// +-alias ISO646-JP-OCR-B// JIS_C6229-1984-B// +-alias JP-OCR-B// JIS_C6229-1984-B// +-alias CSISO92JISC62991984B// JIS_C6229-1984-B// +-alias JIS_C62291984B// JIS_C6229-1984-B// +-module JIS_C6229-1984-B// INTERNAL ISO646 2 +-module INTERNAL JIS_C6229-1984-B// ISO646 2 +- +-alias ISO-IR-141// JUS_I.B1.002// +-alias ISO646-YU// JUS_I.B1.002// +-alias JS// JUS_I.B1.002// +-alias YU// JUS_I.B1.002// +-alias CSISO141JUSIB1002// JUS_I.B1.002// +-module JUS_I.B1.002// INTERNAL ISO646 2 +-module INTERNAL JUS_I.B1.002// ISO646 2 +- +-alias ISO646-KR// KSC5636// +-alias CSKSC5636// KSC5636// +-module KSC5636// INTERNAL ISO646 2 +-module INTERNAL KSC5636// ISO646 2 +- +-alias ISO-IR-86// MSZ_7795.3// +-alias ISO646-HU// MSZ_7795.3// +-alias HU// MSZ_7795.3// +-alias CSISO86HUNGARIAN// MSZ_7795.3// +-module MSZ_7795.3// INTERNAL ISO646 2 +-module INTERNAL MSZ_7795.3// ISO646 2 +- +-alias CUBA// NC_NC00-10// +-alias NC_NC00-10:81// NC_NC00-10// +-alias ISO-IR-151// NC_NC00-10// +-alias ISO646-CU// NC_NC00-10// +-alias CSISO151CUBA// NC_NC00-10// +-alias NC_NC0010// NC_NC00-10// +-module NC_NC00-10// INTERNAL ISO646 2 +-module INTERNAL NC_NC00-10// ISO646 2 +- +-alias ISO-IR-69// NF_Z_62-010// +-alias ISO646-FR// NF_Z_62-010// +-alias FR// NF_Z_62-010// +-alias CSISO69FRENCH// NF_Z_62-010// +-alias NF_Z_62010// NF_Z_62-010// +-module NF_Z_62-010// INTERNAL ISO646 2 +-module INTERNAL NF_Z_62-010// ISO646 2 +- +-alias ISO-IR-25// NF_Z_62-010_1973// +-alias ISO646-FR1// NF_Z_62-010_1973// +-alias NF_Z_62-010_(1973)// NF_Z_62-010_1973// +-alias CSISO25FRENCH// NF_Z_62-010_1973// +-alias NF_Z_62010_1973// NF_Z_62-010_1973// +-module NF_Z_62-010_1973// INTERNAL ISO646 2 +-module INTERNAL NF_Z_62-010_1973// ISO646 2 +- +-alias ISO-IR-60// NS_4551-1// +-alias ISO646-NO// NS_4551-1// +-alias NO// NS_4551-1// +-alias CSISO60DANISHNORWEGIAN// NS_4551-1// +-alias CSISO60NORWEGIAN1// NS_4551-1// +-alias NS_45511// NS_4551-1// +-module NS_4551-1// INTERNAL ISO646 2 +-module INTERNAL NS_4551-1// ISO646 2 +- +-alias ISO646-NO2// NS_4551-2// +-alias ISO-IR-61// NS_4551-2// +-alias NO2// NS_4551-2// +-alias CSISO61NORWEGIAN2// NS_4551-2// +-alias NS_45512// NS_4551-2// +-module NS_4551-2// INTERNAL ISO646 2 +-module INTERNAL NS_4551-2// ISO646 2 +- +-alias ISO-IR-16// PT// +-alias ISO646-PT// PT// +-alias CSISO16PORTUGESE// PT// +-module PT// INTERNAL ISO646 2 +-module INTERNAL PT// ISO646 2 +- +-alias ISO-IR-84// PT2// +-alias ISO646-PT2// PT2// +-alias CSISO84PORTUGUESE2// PT2// +-module PT2// INTERNAL ISO646 2 +-module INTERNAL PT2// ISO646 2 +- +-alias ISO-IR-10// SEN_850200_B// +-alias FI// SEN_850200_B// +-alias ISO646-FI// SEN_850200_B// +-alias ISO646-SE// SEN_850200_B// +-alias SE// SEN_850200_B// +-alias CSISO10SWEDISH// SEN_850200_B// +-alias SS636127// SEN_850200_B// +-module SEN_850200_B// INTERNAL ISO646 2 +-module INTERNAL SEN_850200_B// ISO646 2 +- +-alias ISO-IR-11// SEN_850200_C// +-alias ISO646-SE2// SEN_850200_C// +-alias SE2// SEN_850200_C// +-alias CSISO11SWEDISHFORNAMES// SEN_850200_C// +-module SEN_850200_C// INTERNAL ISO646 2 +-module INTERNAL SEN_850200_C// ISO646 2 +- + # from to module cost + alias ISO-IR-100// ISO-8859-1// + alias ISO_8859-1:1987// ISO-8859-1// +@@ -219,175 +47,6 @@ alias OSF00010001// ISO-8859-1// + module ISO-8859-1// INTERNAL ISO8859-1 1 + module INTERNAL ISO-8859-1// ISO8859-1 1 + +-# from to module cost +-alias ISO-IR-101// ISO-8859-2// +-alias ISO_8859-2:1987// ISO-8859-2// +-alias ISO_8859-2// ISO-8859-2// +-alias ISO8859-2// ISO-8859-2// +-alias ISO88592// ISO-8859-2// +-alias LATIN2// ISO-8859-2// +-alias L2// ISO-8859-2// +-alias CSISOLATIN2// ISO-8859-2// +-alias 8859_2// ISO-8859-2// +-alias OSF00010002// ISO-8859-2// +-alias IBM912// ISO-8859-2// +-alias CP912// ISO-8859-2// +-module ISO-8859-2// INTERNAL ISO8859-2 1 +-module INTERNAL ISO-8859-2// ISO8859-2 1 +- +-# from to module cost +-alias ISO-IR-109// ISO-8859-3// +-alias ISO_8859-3:1988// ISO-8859-3// +-alias ISO_8859-3// ISO-8859-3// +-alias ISO8859-3// ISO-8859-3// +-alias ISO88593// ISO-8859-3// +-alias LATIN3// ISO-8859-3// +-alias L3// ISO-8859-3// +-alias CSISOLATIN3// ISO-8859-3// +-alias 8859_3// ISO-8859-3// +-alias OSF00010003// ISO-8859-3// +-module ISO-8859-3// INTERNAL ISO8859-3 1 +-module INTERNAL ISO-8859-3// ISO8859-3 1 +- +-# from to module cost +-alias ISO-IR-110// ISO-8859-4// +-alias ISO_8859-4:1988// ISO-8859-4// +-alias ISO_8859-4// ISO-8859-4// +-alias ISO8859-4// ISO-8859-4// +-alias ISO88594// ISO-8859-4// +-alias LATIN4// ISO-8859-4// +-alias L4// ISO-8859-4// +-alias CSISOLATIN4// ISO-8859-4// +-alias 8859_4// ISO-8859-4// +-alias OSF00010004// ISO-8859-4// +-module ISO-8859-4// INTERNAL ISO8859-4 1 +-module INTERNAL ISO-8859-4// ISO8859-4 1 +- +-# from to module cost +-alias ISO-IR-144// ISO-8859-5// +-alias ISO_8859-5:1988// ISO-8859-5// +-alias ISO_8859-5// ISO-8859-5// +-alias ISO8859-5// ISO-8859-5// +-alias ISO88595// ISO-8859-5// +-alias CYRILLIC// ISO-8859-5// +-alias CSISOLATINCYRILLIC// ISO-8859-5// +-alias 8859_5// ISO-8859-5// +-alias OSF00010005// ISO-8859-5// +-alias IBM915// ISO-8859-5// +-alias CP915// ISO-8859-5// +-module ISO-8859-5// INTERNAL ISO8859-5 1 +-module INTERNAL ISO-8859-5// ISO8859-5 1 +- +-# from to module cost +-alias ISO-IR-127// ISO-8859-6// +-alias ISO_8859-6:1987// ISO-8859-6// +-alias ISO_8859-6// ISO-8859-6// +-alias ISO8859-6// ISO-8859-6// +-alias ISO88596// ISO-8859-6// +-alias ECMA-114// ISO-8859-6// +-alias ASMO-708// ISO-8859-6// +-alias ARABIC// ISO-8859-6// +-alias CSISOLATINARABIC// ISO-8859-6// +-alias 8859_6// ISO-8859-6// +-alias OSF00010006// ISO-8859-6// +-alias IBM1089// ISO-8859-6// +-alias CP1089// ISO-8859-6// +-module ISO-8859-6// INTERNAL ISO8859-6 1 +-module INTERNAL ISO-8859-6// ISO8859-6 1 +- +-# from to module cost +-alias ISO-IR-126// ISO-8859-7// +-alias ISO_8859-7:2003// ISO-8859-7// +-alias ISO_8859-7:1987// ISO-8859-7// +-alias ISO_8859-7// ISO-8859-7// +-alias ISO8859-7// ISO-8859-7// +-alias ISO88597// ISO-8859-7// +-alias ELOT_928// ISO-8859-7// +-alias ECMA-118// ISO-8859-7// +-alias GREEK// ISO-8859-7// +-alias GREEK8// ISO-8859-7// +-alias CSISOLATINGREEK// ISO-8859-7// +-alias 8859_7// ISO-8859-7// +-alias OSF00010007// ISO-8859-7// +-alias IBM813// ISO-8859-7// +-alias CP813// ISO-8859-7// +-module ISO-8859-7// INTERNAL ISO8859-7 1 +-module INTERNAL ISO-8859-7// ISO8859-7 1 +- +-# from to module cost +-alias ISO-IR-138// ISO-8859-8// +-alias ISO_8859-8:1988// ISO-8859-8// +-alias ISO_8859-8// ISO-8859-8// +-alias ISO8859-8// ISO-8859-8// +-alias ISO88598// ISO-8859-8// +-alias HEBREW// ISO-8859-8// +-alias CSISOLATINHEBREW// ISO-8859-8// +-alias 8859_8// ISO-8859-8// +-alias OSF00010008// ISO-8859-8// +-alias IBM916// ISO-8859-8// +-alias CP916// ISO-8859-8// +-module ISO-8859-8// INTERNAL ISO8859-8 1 +-module INTERNAL ISO-8859-8// ISO8859-8 1 +- +-# from to module cost +-alias ISO-IR-148// ISO-8859-9// +-alias ISO_8859-9:1989// ISO-8859-9// +-alias ISO_8859-9// ISO-8859-9// +-alias ISO8859-9// ISO-8859-9// +-alias ISO88599// ISO-8859-9// +-alias LATIN5// ISO-8859-9// +-alias L5// ISO-8859-9// +-alias CSISOLATIN5// ISO-8859-9// +-alias 8859_9// ISO-8859-9// +-alias OSF00010009// ISO-8859-9// +-alias IBM920// ISO-8859-9// +-alias CP920// ISO-8859-9// +-alias TS-5881// ISO-8859-9// +-alias ECMA-128// ISO-8859-9// +-module ISO-8859-9// INTERNAL ISO8859-9 1 +-module INTERNAL ISO-8859-9// ISO8859-9 1 +- +-# from to module cost +-alias ISO-IR-157// ISO-8859-10// +-alias ISO_8859-10:1992// ISO-8859-10// +-alias ISO_8859-10// ISO-8859-10// +-alias ISO8859-10// ISO-8859-10// +-alias ISO885910// ISO-8859-10// +-alias LATIN6// ISO-8859-10// +-alias L6// ISO-8859-10// +-alias CSISOLATIN6// ISO-8859-10// +-alias OSF0001000A// ISO-8859-10// +-module ISO-8859-10// INTERNAL ISO8859-10 1 +-module INTERNAL ISO-8859-10// ISO8859-10 1 +- +-# from to module cost +-alias ISO8859-11// ISO-8859-11// +-alias ISO885911// ISO-8859-11// +-module ISO-8859-11// INTERNAL ISO8859-11 1 +-module INTERNAL ISO-8859-11// ISO8859-11 1 +- +-# from to module cost +-alias ISO8859-13// ISO-8859-13// +-alias ISO885913// ISO-8859-13// +-alias ISO-IR-179// ISO-8859-13// +-alias LATIN7// ISO-8859-13// +-alias L7// ISO-8859-13// +-alias BALTIC// ISO-8859-13// +-module ISO-8859-13// INTERNAL ISO8859-13 1 +-module INTERNAL ISO-8859-13// ISO8859-13 1 +- +-# from to module cost +-alias ISO8859-14// ISO-8859-14// +-alias ISO885914// ISO-8859-14// +-alias ISO-IR-199// ISO-8859-14// +-alias LATIN8// ISO-8859-14// +-alias L8// ISO-8859-14// +-alias ISO_8859-14:1998// ISO-8859-14// +-alias ISO_8859-14// ISO-8859-14// +-alias ISO-CELTIC// ISO-8859-14// +-module ISO-8859-14// INTERNAL ISO8859-14 1 +-module INTERNAL ISO-8859-14// ISO8859-14 1 +- + # from to module cost + alias ISO8859-15// ISO-8859-15// + alias ISO885915// ISO-8859-15// +@@ -399,916 +58,12 @@ alias ISO_8859-15:1998// ISO-8859-15// + module ISO-8859-15// INTERNAL ISO8859-15 1 + module INTERNAL ISO-8859-15// ISO8859-15 1 + +-# from to module cost +-alias ISO8859-16// ISO-8859-16// +-alias ISO885916// ISO-8859-16// +-alias ISO-IR-226// ISO-8859-16// +-alias LATIN10// ISO-8859-16// +-alias L10// ISO-8859-16// +-alias ISO_8859-16:2001// ISO-8859-16// +-alias ISO_8859-16// ISO-8859-16// +-module ISO-8859-16// INTERNAL ISO8859-16 1 +-module INTERNAL ISO-8859-16// ISO8859-16 1 +- +-# from to module cost +-alias T.61// T.61-8BIT// +-alias ISO-IR-103// T.61-8BIT// +-alias CSISO103T618BIT// T.61-8BIT// +-alias T.618BIT// T.61-8BIT// +-module T.61-8BIT// INTERNAL T.61 1 +-module INTERNAL T.61-8BIT// T.61 1 +- +-# from to module cost +-alias ISO-IR-156// ISO_6937// +-alias ISO_6937:1992// ISO_6937// +-alias ISO6937// ISO_6937// +-module ISO_6937// INTERNAL ISO_6937 1 +-module INTERNAL ISO_6937// ISO_6937 1 +- +- +-# from to module cost +-alias ISO-IR-90// ISO_6937-2// +-alias ISO_6937-2:1983// ISO_6937-2// +-alias CSISO90// ISO_6937-2// +-alias ISO_69372// ISO_6937-2// +-module ISO_6937-2// INTERNAL ISO_6937-2 1 +-module INTERNAL ISO_6937-2// ISO_6937-2 1 +- +-# from to module cost +-alias SHIFT-JIS// SJIS// +-alias SHIFT_JIS// SJIS// +-alias MS_KANJI// SJIS// +-alias CSSHIFTJIS// SJIS// +-module SJIS// INTERNAL SJIS 1 +-module INTERNAL SJIS// SJIS 1 +- +-# from to module cost +-alias WINDOWS-31J// CP932// +-alias MS932// CP932// +-alias SJIS-OPEN// CP932// +-alias SJIS-WIN// CP932// +-alias CSWINDOWS31J// CP932// +-module CP932// INTERNAL CP932 1 +-module INTERNAL CP932// CP932 1 +- +-# from to module cost +-alias KOI8// KOI-8// +-module KOI-8// INTERNAL KOI-8 1 +-module INTERNAL KOI-8// KOI-8 1 +- +-# from to module cost +-alias CSKOI8R// KOI8-R// +-alias KOI8R// KOI8-R// +-module KOI8-R// INTERNAL KOI8-R 1 +-module INTERNAL KOI8-R// KOI8-R 1 +- +-# from to module cost +-alias ISO-IR-19// LATIN-GREEK// +-alias CSISO19LATINGREEK// LATIN-GREEK// +-alias LATINGREEK// LATIN-GREEK// +-module LATIN-GREEK// INTERNAL LATIN-GREEK 1 +-module INTERNAL LATIN-GREEK// LATIN-GREEK 1 +- +-# from to module cost +-alias ISO-IR-27// LATIN-GREEK-1// +-alias CSISO27LATINGREEK1// LATIN-GREEK-1// +-alias LATINGREEK1// LATIN-GREEK-1// +-module LATIN-GREEK-1// INTERNAL LATIN-GREEK-1 1 +-module INTERNAL LATIN-GREEK-1// LATIN-GREEK-1 1 +- +-# from to module cost +-alias ROMAN8// HP-ROMAN8// +-alias R8// HP-ROMAN8// +-alias CSHPROMAN8// HP-ROMAN8// +-alias OSF10010001// HP-ROMAN8// +-alias HPROMAN8// HP-ROMAN8// +-module HP-ROMAN8// INTERNAL HP-ROMAN8 1 +-module INTERNAL HP-ROMAN8// HP-ROMAN8 1 +- +-# from to module cost +-alias CSEBCDICATDE// EBCDIC-AT-DE// +-alias EBCDICATDE// EBCDIC-AT-DE// +-module EBCDIC-AT-DE// INTERNAL EBCDIC-AT-DE 1 +-module INTERNAL EBCDIC-AT-DE// EBCDIC-AT-DE 1 +- +-# from to module cost +-alias CSEBCDICATDEA// EBCDIC-AT-DE-A// +-alias EBCDICATDEA// EBCDIC-AT-DE-A// +-module EBCDIC-AT-DE-A// INTERNAL EBCDIC-AT-DE-A 1 +-module INTERNAL EBCDIC-AT-DE-A// EBCDIC-AT-DE-A 1 +- +-# from to module cost +-alias CSEBCDICCAFR// EBCDIC-CA-FR// +-alias EBCDICCAFR// EBCDIC-CA-FR// +-module EBCDIC-CA-FR// INTERNAL EBCDIC-CA-FR 1 +-module INTERNAL EBCDIC-CA-FR// EBCDIC-CA-FR 1 +- +-# from to module cost +-alias CSEBCDICDKNO// EBCDIC-DK-NO// +-alias EBCDICDKNO// EBCDIC-DK-NO// +-module EBCDIC-DK-NO// INTERNAL EBCDIC-DK-NO 1 +-module INTERNAL EBCDIC-DK-NO// EBCDIC-DK-NO 1 +- +-# from to module cost +-alias CSEBCDICDKNOA// EBCDIC-DK-NO-A// +-alias EBCDICDKNOA// EBCDIC-DK-NO-A// +-module EBCDIC-DK-NO-A// INTERNAL EBCDIC-DK-NO-A 1 +-module INTERNAL EBCDIC-DK-NO-A// EBCDIC-DK-NO-A 1 +- +-# from to module cost +-alias CSEBCDICES// EBCDIC-ES// +-alias EBCDICES// EBCDIC-ES// +-module EBCDIC-ES// INTERNAL EBCDIC-ES 1 +-module INTERNAL EBCDIC-ES// EBCDIC-ES 1 +- +-# from to module cost +-alias CSEBCDICESA// EBCDIC-ES-A// +-alias EBCDICESA// EBCDIC-ES-A// +-module EBCDIC-ES-A// INTERNAL EBCDIC-ES-A 1 +-module INTERNAL EBCDIC-ES-A// EBCDIC-ES-A 1 +- +-# from to module cost +-alias CSEBCDICESS// EBCDIC-ES-S// +-alias EBCDICESS// EBCDIC-ES-S// +-module EBCDIC-ES-S// INTERNAL EBCDIC-ES-S 1 +-module INTERNAL EBCDIC-ES-S// EBCDIC-ES-S 1 +- +-# from to module cost +-alias CSEBCDICFISE// EBCDIC-FI-SE// +-alias EBCDICFISE// EBCDIC-FI-SE// +-module EBCDIC-FI-SE// INTERNAL EBCDIC-FI-SE 1 +-module INTERNAL EBCDIC-FI-SE// EBCDIC-FI-SE 1 +- +-# from to module cost +-alias CSEBCDICFISEA// EBCDIC-FI-SE-A// +-alias EBCDICFISEA// EBCDIC-FI-SE-A// +-module EBCDIC-FI-SE-A// INTERNAL EBCDIC-FI-SE-A 1 +-module INTERNAL EBCDIC-FI-SE-A// EBCDIC-FI-SE-A 1 +- +-# from to module cost +-alias CSEBCDICFR// EBCDIC-FR// +-alias EBCDICFR// EBCDIC-FR// +-module EBCDIC-FR// INTERNAL EBCDIC-FR 1 +-module INTERNAL EBCDIC-FR// EBCDIC-FR 1 +- +-# from to module cost +-alias EBCDICISFRISS// EBCDIC-IS-FRISS// +-module EBCDIC-IS-FRISS// INTERNAL EBCDIC-IS-FRISS 1 +-module INTERNAL EBCDIC-IS-FRISS// EBCDIC-IS-FRISS 1 +- +-# from to module cost +-alias CSEBCDICIT// EBCDIC-IT// +-alias EBCDICIT// EBCDIC-IT// +-module EBCDIC-IT// INTERNAL EBCDIC-IT 1 +-module INTERNAL EBCDIC-IT// EBCDIC-IT 1 +- +-# from to module cost +-alias CSEBCDICPT// EBCDIC-PT// +-alias EBCDICPT// EBCDIC-PT// +-module EBCDIC-PT// INTERNAL EBCDIC-PT 1 +-module INTERNAL EBCDIC-PT// EBCDIC-PT 1 +- +-# from to module cost +-alias CSEBCDICUK// EBCDIC-UK// +-alias EBCDICUK// EBCDIC-UK// +-module EBCDIC-UK// INTERNAL EBCDIC-UK 1 +-module INTERNAL EBCDIC-UK// EBCDIC-UK 1 +- +-# from to module cost +-alias CSEBCDICUS// EBCDIC-US// +-alias EBCDICUS// EBCDIC-US// +-module EBCDIC-US// INTERNAL EBCDIC-US 1 +-module INTERNAL EBCDIC-US// EBCDIC-US 1 +- +-# from to module cost +-alias CP037// IBM037// +-alias EBCDIC-CP-US// IBM037// +-alias EBCDIC-CP-CA// IBM037// +-alias EBCDIC-CP-WT// IBM037// +-alias EBCDIC-CP-NL// IBM037// +-alias CSIBM037// IBM037// +-alias OSF10020025// IBM037// +-alias CP1070// IBM037// +-alias CP282// IBM037// +-module IBM037// INTERNAL IBM037 1 +-module INTERNAL IBM037// IBM037 1 +- +-# from to module cost +-alias EBCDIC-INT// IBM038// +-alias CP038// IBM038// +-alias CSIBM038// IBM038// +-module IBM038// INTERNAL IBM038 1 +-module INTERNAL IBM038// IBM038 1 +- +-# from to module cost +-alias EBCDIC-INT1// IBM256// +-module IBM256// INTERNAL IBM256 1 +-module INTERNAL IBM256// IBM256 1 +- +-# from to module cost +-alias CP273// IBM273// +-alias CSIBM273// IBM273// +-alias OSF10020111// IBM273// +-module IBM273// INTERNAL IBM273 1 +-module INTERNAL IBM273// IBM273 1 +- +-# from to module cost +-alias EBCDIC-BE// IBM274// +-alias CP274// IBM274// +-alias CSIBM274// IBM274// +-module IBM274// INTERNAL IBM274 1 +-module INTERNAL IBM274// IBM274 1 +- +-# from to module cost +-alias EBCDIC-BR// IBM275// +-alias CP275// IBM275// +-alias CSIBM275// IBM275// +-module IBM275// INTERNAL IBM275 1 +-module INTERNAL IBM275// IBM275 1 +- +-# from to module cost +-alias EBCDIC-CP-DK// IBM277// +-alias EBCDIC-CP-NO// IBM277// +-alias CSIBM277// IBM277// +-alias OSF10020115// IBM277// +-module IBM277// INTERNAL IBM277 1 +-module INTERNAL IBM277// IBM277 1 +- +-# from to module cost +-alias CP278// IBM278// +-alias EBCDIC-CP-FI// IBM278// +-alias EBCDIC-CP-SE// IBM278// +-alias CSIBM278// IBM278// +-alias OSF10020116// IBM278// +-module IBM278// INTERNAL IBM278 1 +-module INTERNAL IBM278// IBM278 1 +- +-# from to module cost +-alias CP280// IBM280// +-alias EBCDIC-CP-IT// IBM280// +-alias CSIBM280// IBM280// +-alias OSF10020118// IBM280// +-module IBM280// INTERNAL IBM280 1 +-module INTERNAL IBM280// IBM280 1 +- +-# from to module cost +-alias EBCDIC-JP-E// IBM281// +-alias CP281// IBM281// +-alias CSIBM281// IBM281// +-module IBM281// INTERNAL IBM281 1 +-module INTERNAL IBM281// IBM281 1 +- +-# from to module cost +-alias CP284// IBM284// +-alias EBCDIC-CP-ES// IBM284// +-alias CSIBM284// IBM284// +-alias OSF1002011C// IBM284// +-alias CP1079// IBM284// +-module IBM284// INTERNAL IBM284 1 +-module INTERNAL IBM284// IBM284 1 +- +-# from to module cost +-alias CP285// IBM285// +-alias EBCDIC-CP-GB// IBM285// +-alias CSIBM285// IBM285// +-alias OSF1002011D// IBM285// +-module IBM285// INTERNAL IBM285 1 +-module INTERNAL IBM285// IBM285 1 +- +-# from to module cost +-alias CP290// IBM290// +-alias EBCDIC-JP-KANA// IBM290// +-alias CSIBM290// IBM290// +-alias OSF10020122// IBM290// +-module IBM290// INTERNAL IBM290 1 +-module INTERNAL IBM290// IBM290 1 +- +-# from to module cost +-alias CP297// IBM297// +-alias EBCDIC-CP-FR// IBM297// +-alias CSIBM297// IBM297// +-alias OSF10020129// IBM297// +-alias CP1081// IBM297// +-module IBM297// INTERNAL IBM297 1 +-module INTERNAL IBM297// IBM297 1 +- +-# from to module cost +-alias CP420// IBM420// +-alias EBCDIC-CP-AR1// IBM420// +-alias CSIBM420// IBM420// +-alias OSF100201A4// IBM420// +-module IBM420// INTERNAL IBM420 1 +-module INTERNAL IBM420// IBM420 1 +- +-# from to module cost +-alias CP423// IBM423// +-alias EBCDIC-CP-GR// IBM423// +-alias CSIBM423// IBM423// +-module IBM423// INTERNAL IBM423 1 +-module INTERNAL IBM423// IBM423 1 +- +-# from to module cost +-alias CP424// IBM424// +-alias EBCDIC-CP-HE// IBM424// +-alias CSIBM424// IBM424// +-alias OSF100201A8// IBM424// +-module IBM424// INTERNAL IBM424 1 +-module INTERNAL IBM424// IBM424 1 +- +-# from to module cost +-alias CP437// IBM437// +-alias 437// IBM437// +-alias CSPC8CODEPAGE437// IBM437// +-alias OSF100201B5// IBM437// +-module IBM437// INTERNAL IBM437 1 +-module INTERNAL IBM437// IBM437 1 +- +-# from to module cost +-alias CP500// IBM500// +-alias 500// IBM500// +-alias 500V1// IBM500// +-alias EBCDIC-CP-BE// IBM500// +-alias EBCDIC-CP-CH// IBM500// +-alias CSIBM500// IBM500// +-alias OSF100201F4// IBM500// +-alias CP1084// IBM500// +-module IBM500// INTERNAL IBM500 1 +-module INTERNAL IBM500// IBM500 1 +- +-# from to module cost +-alias CP850// IBM850// +-alias 850// IBM850// +-alias CSPC850MULTILINGUAL// IBM850// +-alias OSF10020352// IBM850// +-module IBM850// INTERNAL IBM850 1 +-module INTERNAL IBM850// IBM850 1 +- +-# from to module cost +-alias CP858// IBM858// +-alias 858// IBM858// +-alias CSPC858MULTILINGUAL// IBM858// +-module IBM858// INTERNAL IBM858 1 +-module INTERNAL IBM858// IBM858 1 +- +-# from to module cost +-alias CP851// IBM851// +-alias 851// IBM851// +-alias CSIBM851// IBM851// +-module IBM851// INTERNAL IBM851 1 +-module INTERNAL IBM851// IBM851 1 +- +-# from to module cost +-alias CP852// IBM852// +-alias 852// IBM852// +-alias CSPCP852// IBM852// +-alias OSF10020354// IBM852// +-module IBM852// INTERNAL IBM852 1 +-module INTERNAL IBM852// IBM852 1 +- +-# from to module cost +-alias CP855// IBM855// +-alias 855// IBM855// +-alias CSIBM855// IBM855// +-alias OSF10020357// IBM855// +-module IBM855// INTERNAL IBM855 1 +-module INTERNAL IBM855// IBM855 1 +- +-# from to module cost +-alias IBM-856// IBM856// +-alias CP856// IBM856// +-alias 856// IBM856// +-alias CSIBM856// IBM856// +-module IBM856// INTERNAL IBM856 1 +-module INTERNAL IBM856// IBM856 1 +- +-# from to module cost +-alias CP857// IBM857// +-alias 857// IBM857// +-alias CSIBM857// IBM857// +-alias OSF10020359// IBM857// +-module IBM857// INTERNAL IBM857 1 +-module INTERNAL IBM857// IBM857 1 +- +-# from to module cost +-alias CP860// IBM860// +-alias 860// IBM860// +-alias CSIBM860// IBM860// +-module IBM860// INTERNAL IBM860 1 +-module INTERNAL IBM860// IBM860 1 +- +-# from to module cost +-alias CP861// IBM861// +-alias 861// IBM861// +-alias CPIBM861// IBM861// +-alias OSF1002035D// IBM861// +-module IBM861// INTERNAL IBM861 1 +-module INTERNAL IBM861// IBM861 1 +- +-# from to module cost +-alias CP862// IBM862// +-alias 862// IBM862// +-alias CSPC862LATINHEBREW// IBM862// +-alias OSF1002035E// IBM862// +-module IBM862// INTERNAL IBM862 1 +-module INTERNAL IBM862// IBM862 1 +- +-# from to module cost +-alias CP863// IBM863// +-alias 863// IBM863// +-alias CSIBM863// IBM863// +-alias OSF1002035F// IBM863// +-module IBM863// INTERNAL IBM863 1 +-module INTERNAL IBM863// IBM863 1 +- +-# from to module cost +-alias CP864// IBM864// +-alias 864// IBM864// +-alias CSIBM864// IBM864// +-alias OSF10020360// IBM864// +-module IBM864// INTERNAL IBM864 1 +-module INTERNAL IBM864// IBM864 1 +- +-# from to module cost +-alias CP865// IBM865// +-alias 865// IBM865// +-alias CSIBM865// IBM865// +-module IBM865// INTERNAL IBM865 1 +-module INTERNAL IBM865// IBM865 1 +- +-# from to module cost +-alias CP866// IBM866// +-alias 866// IBM866// +-alias CSIBM866// IBM866// +-module IBM866// INTERNAL IBM866 1 +-module INTERNAL IBM866// IBM866 1 +- +-# from to module cost +-alias CP866NAV// IBM866NAV// +-alias 866NAV// IBM866NAV// +-module IBM866NAV// INTERNAL IBM866NAV 1 +-module INTERNAL IBM866NAV// IBM866NAV 1 +- +-# from to module cost +-alias CP868// IBM868// +-alias CP-AR// IBM868// +-alias CSIBM868// IBM868// +-alias OSF10020364// IBM868// +-module IBM868// INTERNAL IBM868 1 +-module INTERNAL IBM868// IBM868 1 +- +-# from to module cost +-alias CP869// IBM869// +-alias 869// IBM869// +-alias CP-GR// IBM869// +-alias CSIBM869// IBM869// +-alias OSF10020365// IBM869// +-module IBM869// INTERNAL IBM869 1 +-module INTERNAL IBM869// IBM869 1 +- +-# from to module cost +-alias CP870// IBM870// +-alias EBCDIC-CP-ROECE// IBM870// +-alias EBCDIC-CP-YU// IBM870// +-alias CSIBM870// IBM870// +-alias OSF10020366// IBM870// +-module IBM870// INTERNAL IBM870 1 +-module INTERNAL IBM870// IBM870 1 +- +-# from to module cost +-alias CP871// IBM871// +-alias EBCDIC-CP-IS// IBM871// +-alias CSIBM871// IBM871// +-alias OSF10020367// IBM871// +-module IBM871// INTERNAL IBM871 1 +-module INTERNAL IBM871// IBM871 1 +- +-# from to module cost +-alias CP875// IBM875// +-alias EBCDIC-GREEK// IBM875// +-alias OSF1002036B// IBM875// +-module IBM875// INTERNAL IBM875 1 +-module INTERNAL IBM875// IBM875 1 +- +-# from to module cost +-alias CP880// IBM880// +-alias EBCDIC-CYRILLIC// IBM880// +-alias CSIBM880// IBM880// +-alias OSF10020370// IBM880// +-module IBM880// INTERNAL IBM880 1 +-module INTERNAL IBM880// IBM880 1 +- +-# from to module cost +-alias CP891// IBM891// +-alias CSIBM891// IBM891// +-alias OSF1002037B// IBM891// +-module IBM891// INTERNAL IBM891 1 +-module INTERNAL IBM891// IBM891 1 +- +-# from to module cost +-alias CP903// IBM903// +-alias CSIBM903// IBM903// +-alias OSF10020387// IBM903// +-module IBM903// INTERNAL IBM903 1 +-module INTERNAL IBM903// IBM903 1 +- +-# from to module cost +-alias CP904// IBM904// +-alias 904// IBM904// +-alias CSIBM904// IBM904// +-alias OSF10020388// IBM904// +-module IBM904// INTERNAL IBM904 1 +-module INTERNAL IBM904// IBM904 1 +- +-# from to module cost +-alias CP905// IBM905// +-alias EBCDIC-CP-TR// IBM905// +-alias CSIBM905// IBM905// +-module IBM905// INTERNAL IBM905 1 +-module INTERNAL IBM905// IBM905 1 +- +-# from to module cost +-alias CP918// IBM918// +-alias EBCDIC-CP-AR2// IBM918// +-alias CSIBM918// IBM918// +-alias OSF10020396// IBM918// +-module IBM918// INTERNAL IBM918 1 +-module INTERNAL IBM918// IBM918 1 +- +-# from to module cost +-alias IBM-922// IBM922// +-alias CP922// IBM922// +-alias CSIBM922// IBM922// +-module IBM922// INTERNAL IBM922 1 +-module INTERNAL IBM922// IBM922 1 +- +-# from to module cost +-alias IBM-930// IBM930// +-alias CP930// IBM930// +-alias CSIBM930// IBM930// +-module IBM930// INTERNAL IBM930 1 +-module INTERNAL IBM930// IBM930 1 +- +-# from to module cost +-alias IBM-932// IBM932// +-alias CSIBM932// IBM932// +-module IBM932// INTERNAL IBM932 1 +-module INTERNAL IBM932// IBM932 1 +- +-# from to module cost +-alias IBM-933// IBM933// +-alias CP933// IBM933// +-alias CSIBM933// IBM933// +-module IBM933// INTERNAL IBM933 1 +-module INTERNAL IBM933// IBM933 1 +- +-# from to module cost +-alias IBM-935// IBM935// +-alias CP935// IBM935// +-alias CSIBM935// IBM935// +-module IBM935// INTERNAL IBM935 1 +-module INTERNAL IBM935// IBM935 1 +- +-# from to module cost +-alias IBM-937// IBM937// +-alias CP937// IBM937// +-alias CSIBM937// IBM937// +-module IBM937// INTERNAL IBM937 1 +-module INTERNAL IBM937// IBM937 1 +- +-# from to module cost +-alias IBM-939// IBM939// +-alias CP939// IBM939// +-alias CSIBM939// IBM939// +-module IBM939// INTERNAL IBM939 1 +-module INTERNAL IBM939// IBM939 1 +- +-# from to module cost +-alias IBM-943// IBM943// +-alias CSIBM943// IBM943// +-module IBM943// INTERNAL IBM943 1 +-module INTERNAL IBM943// IBM943 1 +- +-# from to module cost +-alias CP1004// IBM1004// +-alias OS2LATIN1// IBM1004// +-module IBM1004// INTERNAL IBM1004 1 +-module INTERNAL IBM1004// IBM1004 1 +- +-# from to module cost +-alias CP1026// IBM1026// +-alias 1026// IBM1026// +-alias CSIBM1026// IBM1026// +-alias OSF10020402// IBM1026// +-module IBM1026// INTERNAL IBM1026 1 +-module INTERNAL IBM1026// IBM1026 1 +- +-# from to module cost +-alias IBM-1046// IBM1046// +-alias CP1046// IBM1046// +-alias 1046// IBM1046// +-module IBM1046// INTERNAL IBM1046 1 +-module INTERNAL IBM1046// IBM1046 1 +- +-# from to module cost +-alias IBM-1047// IBM1047// +-alias CP1047// IBM1047// +-alias 1047// IBM1047// +-alias OSF10020417// IBM1047// +-module IBM1047// INTERNAL IBM1047 1 +-module INTERNAL IBM1047// IBM1047 1 +- +-# from to module cost +-alias IBM-1124// IBM1124// +-alias CP1124// IBM1124// +-alias CSIBM1124// IBM1124// +-module IBM1124// INTERNAL IBM1124 1 +-module INTERNAL IBM1124// IBM1124 1 +- +-# from to module cost +-alias IBM-1129// IBM1129// +-alias CP1129// IBM1129// +-alias CSIBM1129// IBM1129// +-module IBM1129// INTERNAL IBM1129 1 +-module INTERNAL IBM1129// IBM1129 1 +- +-# from to module cost +-alias IBM-1160// IBM1160// +-alias CP1160// IBM1160// +-alias CSIBM1160// IBM1160// +-module IBM1160// INTERNAL IBM1160 1 +-module INTERNAL IBM1160// IBM1160 1 +- +-# from to module cost +-alias IBM-1161// IBM1161// +-alias CP1161// IBM1161// +-alias CSIBM1161// IBM1161// +-module IBM1161// INTERNAL IBM1161 1 +-module INTERNAL IBM1161// IBM1161 1 +- +-# from to module cost +-alias IBM-1132// IBM1132// +-alias CP1132// IBM1132// +-alias CSIBM1132// IBM1132// +-module IBM1132// INTERNAL IBM1132 1 +-module INTERNAL IBM1132// IBM1132 1 +- +-# from to module cost +-alias IBM-1133// IBM1133// +-alias CP1133// IBM1133// +-alias CSIBM1133// IBM1133// +-module IBM1133// INTERNAL IBM1133 1 +-module INTERNAL IBM1133// IBM1133 1 +- +-# from to module cost +-alias IBM-1162// IBM1162// +-alias CP1162// IBM1162// +-alias CSIBM11621162// IBM1162// +-module IBM1162// INTERNAL IBM1162 1 +-module INTERNAL IBM1162// IBM1162 1 +- +-# from to module cost +-alias IBM-1163// IBM1163// +-alias CP1163// IBM1163// +-alias CSIBM1163// IBM1163// +-module IBM1163// INTERNAL IBM1163 1 +-module INTERNAL IBM1163// IBM1163 1 +- +-# from to module cost +-alias IBM-1164// IBM1164// +-alias CP1164// IBM1164// +-alias CSIBM1164// IBM1164// +-module IBM1164// INTERNAL IBM1164 1 +-module INTERNAL IBM1164// IBM1164 1 +- +-# from to module cost +-alias EUCKR// EUC-KR// +-alias CSEUCKR// EUC-KR// +-alias OSF0004000a// EUC-KR// +-module EUC-KR// INTERNAL EUC-KR 1 +-module INTERNAL EUC-KR// EUC-KR 1 +- +-# from to module cost +-alias MSCP949// UHC// +-alias CP949// UHC// +-alias OSF100203B5// UHC// +-module UHC// INTERNAL UHC 1 +-module INTERNAL UHC// UHC 1 +- +-# from to module cost +-alias MSCP1361// JOHAB// +-alias CP1361// JOHAB// +-module JOHAB// INTERNAL JOHAB 1 +-module INTERNAL JOHAB// JOHAB 1 +- +-# from to module cost +-alias BIG-FIVE// BIG5// +-alias BIGFIVE// BIG5// +-alias BIG-5// BIG5// +-alias CN-BIG5// BIG5// +-alias CP950// BIG5// +-module BIG5// INTERNAL BIG5 1 +-module INTERNAL BIG5// BIG5 1 +- +-# from to module cost +-alias BIG5-HKSCS// BIG5HKSCS// +-module BIG5HKSCS// INTERNAL BIG5HKSCS 1 +-module INTERNAL BIG5HKSCS// BIG5HKSCS 1 +- +-# from to module cost +-alias EUCJP-MS// EUC-JP-MS// +-alias EUCJP-OPEN// EUC-JP-MS// +-alias EUCJP-WIN// EUC-JP-MS// +-module EUC-JP-MS// INTERNAL EUC-JP-MS 1 +-module INTERNAL EUC-JP-MS// EUC-JP-MS 1 +- +-# from to module cost +-alias EUCJP// EUC-JP// +-alias CSEUCPKDFMTJAPANESE// EUC-JP// +-alias OSF00030010// EUC-JP// +-alias UJIS// EUC-JP// +-module EUC-JP// INTERNAL EUC-JP 1 +-module INTERNAL EUC-JP// EUC-JP 1 +- +-# from to module cost +-alias EUCCN// EUC-CN// +-alias GB2312// EUC-CN// +-alias csGB2312// EUC-CN// +-alias CN-GB// EUC-CN// +-module EUC-CN// INTERNAL EUC-CN 1 +-module INTERNAL EUC-CN// EUC-CN 1 +- +-# from to module cost +-module EUC-CN// BIG5// GBBIG5 1 +-module BIG5// EUC-CN// GBBIG5 1 +- +-# from to module cost +-alias GB13000// GBK// +-alias CP936// GBK// +-alias MS936// GBK// +-alias WINDOWS-936// GBK// +-module GBK// INTERNAL GBK 1 +-module INTERNAL GBK// GBK 1 +- +-# from to module cost +-module GBK// EUC-CN// GBGBK 1 +-module EUC-CN// GBK// GBGBK 1 +- +-# from to module cost +-alias EUCTW// EUC-TW// +-alias OSF0005000a// EUC-TW// +-module EUC-TW// INTERNAL EUC-TW 1 +-module INTERNAL EUC-TW// EUC-TW 1 +- +-# from to module cost +-alias RUSCII// CP1125// +-alias IBM848// CP1125// +-module CP1125// INTERNAL CP1125 1 +-module INTERNAL CP1125// CP1125 1 +- +-# from to module cost +-alias MS-EE// CP1250// +-alias WINDOWS-1250// CP1250// +-module CP1250// INTERNAL CP1250 1 +-module INTERNAL CP1250// CP1250 1 +- +-# from to module cost +-alias MS-CYRL// CP1251// +-alias WINDOWS-1251// CP1251// +-module CP1251// INTERNAL CP1251 1 +-module INTERNAL CP1251// CP1251 1 +- + # from to module cost + alias MS-ANSI// CP1252// + alias WINDOWS-1252// CP1252// + module CP1252// INTERNAL CP1252 1 + module INTERNAL CP1252// CP1252 1 + +-# from to module cost +-alias MS-GREEK// CP1253// +-alias WINDOWS-1253// CP1253// +-module CP1253// INTERNAL CP1253 1 +-module INTERNAL CP1253// CP1253 1 +- +-# from to module cost +-alias MS-TURK// CP1254// +-alias WINDOWS-1254// CP1254// +-module CP1254// INTERNAL CP1254 1 +-module INTERNAL CP1254// CP1254 1 +- +-# from to module cost +-alias MS-HEBR// CP1255// +-alias WINDOWS-1255// CP1255// +-module CP1255// INTERNAL CP1255 1 +-module INTERNAL CP1255// CP1255 1 +- +-# from to module cost +-alias MS-ARAB// CP1256// +-alias WINDOWS-1256// CP1256// +-module CP1256// INTERNAL CP1256 1 +-module INTERNAL CP1256// CP1256 1 +- +-# from to module cost +-alias WINBALTRIM// CP1257// +-alias WINDOWS-1257// CP1257// +-module CP1257// INTERNAL CP1257 1 +-module INTERNAL CP1257// CP1257 1 +- +-# from to module cost +-alias WINDOWS-1258// CP1258// +-module CP1258// INTERNAL CP1258 1 +-module INTERNAL CP1258// CP1258 1 +- +-# from to module cost +-alias 874// IBM874// +-alias CP874// IBM874// +-alias WINDOWS-874// IBM874// +-module IBM874// INTERNAL IBM874 1 +-module INTERNAL IBM874// IBM874 1 +- +-# from to module cost +-module CP737// INTERNAL CP737 1 +-module INTERNAL CP737// CP737 1 +- +-# from to module cost +-module CP770// INTERNAL CP770 1 +-module INTERNAL CP770// CP770 1 +- +-# from to module cost +-module CP771// INTERNAL CP771 1 +-module INTERNAL CP771// CP771 1 +- +-# from to module cost +-module CP772// INTERNAL CP772 1 +-module INTERNAL CP772// CP772 1 +- +-# from to module cost +-module CP773// INTERNAL CP773 1 +-module INTERNAL CP773// CP773 1 +- +-# from to module cost +-module CP774// INTERNAL CP774 1 +-module INTERNAL CP774// CP774 1 +- +-# from to module cost +-alias IBM775// CP775// +-alias CSPC775BALTIC// CP775// +-module CP775// INTERNAL CP775 1 +-module INTERNAL CP775// CP775 1 +- +-# from to module cost +-alias CSISO2022JP// ISO-2022-JP// +-alias ISO2022JP// ISO-2022-JP// +-module ISO-2022-JP// INTERNAL ISO-2022-JP 1 +-module INTERNAL ISO-2022-JP// ISO-2022-JP 1 +- +-# from to module cost +-alias CSISO2022JP2// ISO-2022-JP-2// +-alias ISO2022JP2// ISO-2022-JP-2// +-module ISO-2022-JP-2// INTERNAL ISO-2022-JP 1 +-module INTERNAL ISO-2022-JP-2// ISO-2022-JP 1 +- +-# from to module cost +-module ISO-2022-JP-3// INTERNAL ISO-2022-JP-3 1 +-module INTERNAL ISO-2022-JP-3// ISO-2022-JP-3 1 +- +-# from to module cost +-alias CSISO2022KR// ISO-2022-KR// +-alias ISO2022KR// ISO-2022-KR// +-module ISO-2022-KR// INTERNAL ISO-2022-KR 1 +-module INTERNAL ISO-2022-KR// ISO-2022-KR 1 +- +-# from to module cost +-alias CSISO2022CN// ISO-2022-CN// +-alias ISO2022CN// ISO-2022-CN// +-module ISO-2022-CN// INTERNAL ISO-2022-CN 1 +-module INTERNAL ISO-2022-CN// ISO-2022-CN 1 +- +-# from to module cost +-alias ISO2022CNEXT// ISO-2022-CN-EXT// +-module ISO-2022-CN-EXT// INTERNAL ISO-2022-CN-EXT 1 +-module INTERNAL ISO-2022-CN-EXT// ISO-2022-CN-EXT 1 +- +-# from to module cost +-alias MAC// MACINTOSH// +-alias CSMACINTOSH// MACINTOSH// +-module MACINTOSH// INTERNAL MACINTOSH 1 +-module INTERNAL MACINTOSH// MACINTOSH 1 +- +-# from to module cost +-alias ISO-IR-143// IEC_P27-1// +-alias CSISO143IECP271// IEC_P27-1// +-alias IEC_P271// IEC_P27-1// +-module IEC_P27-1// INTERNAL IEC_P27-1 1 +-module INTERNAL IEC_P27-1// IEC_P27-1 1 +- +-# from to module cost +-alias ISO_9036// ASMO_449// +-alias ARABIC7// ASMO_449// +-alias ISO-IR-89// ASMO_449// +-alias CSISO89ASMO449// ASMO_449// +-module ASMO_449// INTERNAL ASMO_449 1 +-module INTERNAL ASMO_449// ASMO_449 1 +- + # from to module cost + alias ANSI_X3.110-1983// ANSI_X3.110// + alias ISO-IR-99// ANSI_X3.110// +@@ -1319,181 +74,6 @@ alias CSISO99NAPLPS// ANSI_X3.110// + module ANSI_X3.110// INTERNAL ANSI_X3.110 1 + module INTERNAL ANSI_X3.110// ANSI_X3.110 1 + +-# from to module cost +-alias ISO-IR-139// CSN_369103// +-alias CSISO139CSN369103// CSN_369103// +-module CSN_369103// INTERNAL CSN_369103 1 +-module INTERNAL CSN_369103// CSN_369103 1 +- +-# from to module cost +-alias CWI-2// CWI// +-alias CP-HU// CWI// +-module CWI// INTERNAL CWI 1 +-module INTERNAL CWI// CWI 1 +- +-# from to module cost +-alias DEC// DEC-MCS// +-alias CSDECMCS// DEC-MCS// +-alias DECMCS// DEC-MCS// +-module DEC-MCS// INTERNAL DEC-MCS 1 +-module INTERNAL DEC-MCS// DEC-MCS 1 +- +-# from to module cost +-alias ISO-IR-111// ECMA-CYRILLIC// +-alias CSISO111ECMACYRILLIC// ECMA-CYRILLIC// +-alias ECMACYRILLIC// ECMA-CYRILLIC// +-module ECMA-CYRILLIC// INTERNAL ECMA-CYRILLIC 1 +-module INTERNAL ECMA-CYRILLIC// ECMA-CYRILLIC 1 +- +-# from to module cost +-alias ST_SEV_358-88// GOST_19768-74// +-alias GOST_19768// GOST_19768-74// +-alias ISO-IR-153// GOST_19768-74// +-alias CSISO153GOST1976874// GOST_19768-74// +-alias GOST_1976874// GOST_19768-74// +-module GOST_19768-74// INTERNAL GOST_19768-74 1 +-module INTERNAL GOST_19768-74// GOST_19768-74 1 +- +-# from to module cost +-alias ISO-IR-150// GREEK-CCITT// +-alias CSISO150// GREEK-CCITT// +-alias CSISO150GREEKCCITT// GREEK-CCITT// +-alias GREEKCCITT// GREEK-CCITT// +-module GREEK-CCITT// INTERNAL GREEK-CCITT 1 +-module INTERNAL GREEK-CCITT// GREEK-CCITT 1 +- +-# from to module cost +-alias ISO-IR-88// GREEK7// +-alias CSISO88GREEK7// GREEK7// +-module GREEK7// INTERNAL GREEK7 1 +-module INTERNAL GREEK7// GREEK7 1 +- +-# from to module cost +-alias ISO-IR-18// GREEK7-OLD// +-alias CSISO18GREEK7OLD// GREEK7-OLD// +-alias GREEK7OLD// GREEK7-OLD// +-module GREEK7-OLD// INTERNAL GREEK7-OLD 1 +-module INTERNAL GREEK7-OLD// GREEK7-OLD 1 +- +-# from to module cost +-alias ISO-IR-49// INIS// +-alias CSISO49INIS// INIS// +-module INIS// INTERNAL INIS 1 +-module INTERNAL INIS// INIS 1 +- +-# from to module cost +-alias ISO-IR-50// INIS-8// +-alias CSISO50INIS8// INIS-8// +-alias INIS8// INIS-8// +-module INIS-8// INTERNAL INIS-8 1 +-module INTERNAL INIS-8// INIS-8 1 +- +-# from to module cost +-alias ISO-IR-51// INIS-CYRILLIC// +-alias CSISO51INISCYRILLIC// INIS-CYRILLIC// +-alias INISCYRILLIC// INIS-CYRILLIC// +-module INIS-CYRILLIC// INTERNAL INIS-CYRILLIC 1 +-module INTERNAL INIS-CYRILLIC// INIS-CYRILLIC 1 +- +-# from to module cost +-alias ISO-IR-98// ISO_2033// +-alias ISO_2033-1983// ISO_2033// +-alias E13B// ISO_2033// +-alias CSISO2033// ISO_2033// +-module ISO_2033// INTERNAL ISO_2033 1 +-module INTERNAL ISO_2033// ISO_2033 1 +- +-# from to module cost +-alias ISO-IR-37// ISO_5427// +-alias KOI-7// ISO_5427// +-alias CSISO5427CYRILLIC// ISO_5427// +-module ISO_5427// INTERNAL ISO_5427 1 +-module INTERNAL ISO_5427// ISO_5427 1 +- +-# from to module cost +-alias ISO-IR-54// ISO_5427-EXT// +-alias ISO_5427:1981// ISO_5427-EXT// +-alias CSISO5427CYRILLIC1981// ISO_5427-EXT// +-alias ISO_5427EXT// ISO_5427-EXT// +-module ISO_5427-EXT// INTERNAL ISO_5427-EXT 1 +-module INTERNAL ISO_5427-EXT// ISO_5427-EXT 1 +- +-# from to module cost +-alias ISO-IR-55// ISO_5428// +-alias ISO_5428:1980// ISO_5428// +-alias CSISO5428GREEK// ISO_5428// +-module ISO_5428// INTERNAL ISO_5428 1 +-module INTERNAL ISO_5428// ISO_5428 1 +- +-# from to module cost +-alias ISO-IR-155// ISO_10367-BOX// +-alias CSISO10367BOX// ISO_10367-BOX// +-alias ISO_10367BOX// ISO_10367-BOX// +-module ISO_10367-BOX// INTERNAL ISO_10367-BOX 1 +-module INTERNAL ISO_10367-BOX// ISO_10367-BOX 1 +- +-# from to module cost +-alias MACIS// MAC-IS// +-module MAC-IS// INTERNAL MAC-IS 1 +-module INTERNAL MAC-IS// MAC-IS 1 +- +-# from to module cost +-alias MACUK// MAC-UK// +-alias MACUKRAINIAN// MAC-UK// +-alias MAC-CYRILLIC// MAC-UK// +-alias MACCYRILLIC// MAC-UK// +-module MAC-UK// INTERNAL MAC-UK 1 +-module INTERNAL MAC-UK// MAC-UK 1 +- +-# from to module cost +-alias MS-MAC-CYRILLIC// CP10007// +-alias MSMACCYRILLIC// CP10007// +-module CP10007// INTERNAL CP10007 1 +-module INTERNAL CP10007// CP10007 1 +- +-# from to module cost +-alias ISO-IR-9-1// NATS-DANO// +-alias CSNATSDANO// NATS-DANO// +-alias NATSDANO// NATS-DANO// +-module NATS-DANO// INTERNAL NATS-DANO 1 +-module INTERNAL NATS-DANO// NATS-DANO 1 +- +-# from to module cost +-alias ISO-IR-8-1// NATS-SEFI// +-alias CSNATSSEFI// NATS-SEFI// +-alias NATSSEFI// NATS-SEFI// +-module NATS-SEFI// INTERNAL NATS-SEFI 1 +-module INTERNAL NATS-SEFI// NATS-SEFI 1 +- +-# from to module cost +-alias WS2// WIN-SAMI-2// +-alias WINSAMI2// WIN-SAMI-2// +-module WIN-SAMI-2// INTERNAL SAMI-WS2 1 +-module INTERNAL WIN-SAMI-2// SAMI-WS2 1 +- +-# from to module cost +-module ISO-IR-197// INTERNAL ISO-IR-197 1 +-module INTERNAL ISO-IR-197// ISO-IR-197 1 +- +-# from to module cost +-alias TIS620// TIS-620// +-alias TIS620-0// TIS-620// +-alias TIS620.2529-1// TIS-620// +-alias TIS620.2533-0// TIS-620// +-alias ISO-IR-166// TIS-620// +-module TIS-620// INTERNAL TIS-620 1 +-module INTERNAL TIS-620// TIS-620 1 +- +-# from to module cost +-alias KOI8U// KOI8-U// +-module KOI8-U// INTERNAL KOI8-U 1 +-module INTERNAL KOI8-U// KOI8-U 1 +- +-# from to module cost +-alias ISIRI3342// ISIRI-3342// +-module ISIRI-3342// INTERNAL ISIRI-3342 1 +-module INTERNAL ISIRI-3342// ISIRI-3342 1 +- + # from to module cost + alias UTF16// UTF-16// + module UTF-16// INTERNAL UTF-16 1 +@@ -1534,442 +114,5 @@ alias UTF7// UTF-7// + module UTF-7// INTERNAL UTF-7 1 + module INTERNAL UTF-7// UTF-7 1 + +-# from to module cost +-module GB18030// INTERNAL GB18030 1 +-module INTERNAL GB18030// GB18030 1 +- +-# from to module cost +-module VISCII// INTERNAL VISCII 1 +-module INTERNAL VISCII// VISCII 1 +- +-# from to module cost +-module KOI8-T// INTERNAL KOI8-T 1 +-module INTERNAL KOI8-T// KOI8-T 1 +- +-# from to module cost +-module GEORGIAN-PS// INTERNAL GEORGIAN-PS 1 +-module INTERNAL GEORGIAN-PS// GEORGIAN-PS 1 +- +-# from to module cost +-module GEORGIAN-ACADEMY// INTERNAL GEORGIAN-ACADEMY 1 +-module INTERNAL GEORGIAN-ACADEMY// GEORGIAN-ACADEMY 1 +- +-# from to module cost +-module ISO-IR-209// INTERNAL ISO-IR-209 1 +-module INTERNAL ISO-IR-209// ISO-IR-209 1 +- +-# from to module cost +-module MAC-SAMI// INTERNAL MAC-SAMI 1 +-module INTERNAL MAC-SAMI// MAC-SAMI 1 +- +-# from to module cost +-alias ARMSCII8// ARMSCII-8// +-module ARMSCII-8// INTERNAL ARMSCII-8 1 +-module INTERNAL ARMSCII-8// ARMSCII-8 1 +- +-# from to module cost +-alias TCVN// TCVN5712-1// +-alias TCVN-5712// TCVN5712-1// +-alias TCVN5712-1:1993// TCVN5712-1// +-module TCVN5712-1// INTERNAL TCVN5712-1 1 +-module INTERNAL TCVN5712-1// TCVN5712-1 1 +- +-# from to module cost +-module EUC-JISX0213// INTERNAL EUC-JISX0213 1 +-module INTERNAL EUC-JISX0213// EUC-JISX0213 1 +- +-# from to module cost +-alias ShiftJISX0213// Shift_JISX0213// +-module Shift_JISX0213// INTERNAL SHIFT_JISX0213 1 +-module INTERNAL Shift_JISX0213// SHIFT_JISX0213 1 +- +-# from to module cost +-module TSCII// INTERNAL TSCII 1 +-module INTERNAL TSCII// TSCII 1 +- +-# from to module cost +-module PT154// INTERNAL PT154 1 +-module INTERNAL PT154// PT154 1 +- +-# from to module cost +-alias STRK1048-2002// RK1048// +-module RK1048// INTERNAL RK1048 1 +-module INTERNAL RK1048// RK1048 1 +- +-# from to module cost +-alias IBM-1025// IBM1025// +-alias CP1025// IBM1025// +-alias CSIBM1025// IBM1025// +-module IBM1025// INTERNAL IBM1025 1 +-module INTERNAL IBM1025// IBM1025 1 +- +-# from to module cost +-alias IBM-1122// IBM1122// +-alias CP1122// IBM1122// +-alias CSIBM1122// IBM1122// +-module IBM1122// INTERNAL IBM1122 1 +-module INTERNAL IBM1122// IBM1122 1 +- +-# from to module cost +-alias IBM-1137// IBM1137// +-alias CP1137// IBM1137// +-alias CSIBM1137// IBM1137// +-module IBM1137// INTERNAL IBM1137 1 +-module INTERNAL IBM1137// IBM1137 1 +- +-# from to module cost +-alias IBM-1153// IBM1153// +-alias CP1153// IBM1153// +-alias CSIBM1153// IBM1153// +-module IBM1153// INTERNAL IBM1153 1 +-module INTERNAL IBM1153// IBM1153 1 +- +-# from to module cost +-alias IBM-1154// IBM1154// +-alias CP1154// IBM1154// +-alias CSIBM1154// IBM1154// +-module IBM1154// INTERNAL IBM1154 1 +-module INTERNAL IBM1154// IBM1154 1 +- +-# from to module cost +-alias IBM-1155// IBM1155// +-alias CP1155// IBM1155// +-alias CSIBM1155// IBM1155// +-module IBM1155// INTERNAL IBM1155 1 +-module INTERNAL IBM1155// IBM1155 1 +- +-# from to module cost +-alias IBM-1156// IBM1156// +-alias CP1156// IBM1156// +-alias CSIBM1156// IBM1156// +-module IBM1156// INTERNAL IBM1156 1 +-module INTERNAL IBM1156// IBM1156 1 +- +-# from to module cost +-alias IBM-1157// IBM1157// +-alias CP1157// IBM1157// +-alias CSIBM1157// IBM1157// +-module IBM1157// INTERNAL IBM1157 1 +-module INTERNAL IBM1157// IBM1157 1 +- +-# from to module cost +-alias IBM-1158// IBM1158// +-alias CP1158// IBM1158// +-alias CSIBM1158// IBM1158// +-module IBM1158// INTERNAL IBM1158 1 +-module INTERNAL IBM1158// IBM1158 1 +- +-# from to module cost +-alias IBM-803// IBM803// +-alias CP803// IBM803// +-alias CSIBM803// IBM803// +-module IBM803// INTERNAL IBM803 1 +-module INTERNAL IBM803// IBM803 1 +- +-# from to module cost +-alias IBM-901// IBM901// +-alias CP901// IBM901// +-alias CSIBM901// IBM901// +-module IBM901// INTERNAL IBM901 1 +-module INTERNAL IBM901// IBM901 1 +- +-# from to module cost +-alias IBM-902// IBM902// +-alias CP902// IBM902// +-alias CSIBM902// IBM902// +-module IBM902// INTERNAL IBM902 1 +-module INTERNAL IBM902// IBM902 1 +- +-# from to module cost +-alias IBM-921// IBM921// +-alias CP921// IBM921// +-alias CSIBM921// IBM921// +-module IBM921// INTERNAL IBM921 1 +-module INTERNAL IBM921// IBM921 1 +- +-# from to module cost +-alias IBM-1008// IBM1008// +-alias CP1008// IBM1008// +-alias CSIBM1008// IBM1008// +-module IBM1008// INTERNAL IBM1008 1 +-module INTERNAL IBM1008// IBM1008 1 +- +-# from to module cost +-module IBM1008// IBM420// IBM1008_420 1 +-module IBM420// IBM1008// IBM1008_420 1 +- +-# from to module cost +-alias IBM-1097// IBM1097// +-alias CP1097// IBM1097// +-alias CSIBM1097// IBM1097// +-module IBM1097// INTERNAL IBM1097 1 +-module INTERNAL IBM1097// IBM1097 1 +- +-# from to module cost +-alias IBM-1112// IBM1112// +-alias CP1112// IBM1112// +-alias CSIBM1112// IBM1112// +-module IBM1112// INTERNAL IBM1112 1 +-module INTERNAL IBM1112// IBM1112 1 +- +-# from to module cost +-alias IBM-1123// IBM1123// +-alias CP1123// IBM1123// +-alias CSIBM1123// IBM1123// +-module IBM1123// INTERNAL IBM1123 1 +-module INTERNAL IBM1123// IBM1123 1 +- +-# from to module cost +-alias IBM-1130// IBM1130// +-alias CP1130// IBM1130// +-alias CSIBM1130// IBM1130// +-module IBM1130// INTERNAL IBM1130 1 +-module INTERNAL IBM1130// IBM1130 1 +- +-# from to module cost +-alias IBM-1140// IBM1140// +-alias CP1140// IBM1140// +-alias CSIBM1140// IBM1140// +-module IBM1140// INTERNAL IBM1140 1 +-module INTERNAL IBM1140// IBM1140 1 +- +-# from to module cost +-alias IBM-1141// IBM1141// +-alias CP1141// IBM1141// +-alias CSIBM1141// IBM1141// +-module IBM1141// INTERNAL IBM1141 1 +-module INTERNAL IBM1141// IBM1141 1 +- +-# from to module cost +-alias IBM-1142// IBM1142// +-alias CP1142// IBM1142// +-alias CSIBM1142// IBM1142// +-module IBM1142// INTERNAL IBM1142 1 +-module INTERNAL IBM1142// IBM1142 1 +- +-# from to module cost +-alias IBM-1143// IBM1143// +-alias CP1143// IBM1143// +-alias CSIBM1143// IBM1143// +-module IBM1143// INTERNAL IBM1143 1 +-module INTERNAL IBM1143// IBM1143 1 +- +-# from to module cost +-alias IBM-1144// IBM1144// +-alias CP1144// IBM1144// +-alias CSIBM1144// IBM1144// +-module IBM1144// INTERNAL IBM1144 1 +-module INTERNAL IBM1144// IBM1144 1 +- +-# from to module cost +-alias IBM-1145// IBM1145// +-alias CP1145// IBM1145// +-alias CSIBM1145// IBM1145// +-module IBM1145// INTERNAL IBM1145 1 +-module INTERNAL IBM1145// IBM1145 1 +- +-# from to module cost +-alias IBM-1146// IBM1146// +-alias CP1146// IBM1146// +-alias CSIBM1146// IBM1146// +-module IBM1146// INTERNAL IBM1146 1 +-module INTERNAL IBM1146// IBM1146 1 +- +-# from to module cost +-alias IBM-1147// IBM1147// +-alias CP1147// IBM1147// +-alias CSIBM1147// IBM1147// +-module IBM1147// INTERNAL IBM1147 1 +-module INTERNAL IBM1147// IBM1147 1 +- +-# from to module cost +-alias IBM-1148// IBM1148// +-alias CP1148// IBM1148// +-alias CSIBM1148// IBM1148// +-module IBM1148// INTERNAL IBM1148 1 +-module INTERNAL IBM1148// IBM1148 1 +- +-# from to module cost +-alias IBM-1149// IBM1149// +-alias CP1149// IBM1149// +-alias CSIBM1149// IBM1149// +-module IBM1149// INTERNAL IBM1149 1 +-module INTERNAL IBM1149// IBM1149 1 +- +-# from to module cost +-alias IBM-1166// IBM1166// +-alias CP1166// IBM1166// +-alias CSIBM1166// IBM1166// +-module IBM1166// INTERNAL IBM1166 1 +-module INTERNAL IBM1166// IBM1166 1 +- +-# from to module cost +-alias IBM-1167// IBM1167// +-alias CP1167// IBM1167// +-alias CSIBM1167// IBM1167// +-module IBM1167// INTERNAL IBM1167 1 +-module INTERNAL IBM1167// IBM1167 1 +- +-# from to module cost +-alias IBM-4517// IBM4517// +-alias CP4517// IBM4517// +-alias CSIBM4517// IBM4517// +-module IBM4517// INTERNAL IBM4517 1 +-module INTERNAL IBM4517// IBM4517 1 +- +-# from to module cost +-alias IBM-4899// IBM4899// +-alias CP4899// IBM4899// +-alias CSIBM4899// IBM4899// +-module IBM4899// INTERNAL IBM4899 1 +-module INTERNAL IBM4899// IBM4899 1 +- +-# from to module cost +-alias IBM-4909// IBM4909// +-alias CP4909// IBM4909// +-alias CSIBM4909// IBM4909// +-module IBM4909// INTERNAL IBM4909 1 +-module INTERNAL IBM4909// IBM4909 1 +- +-# from to module cost +-alias IBM-4971// IBM4971// +-alias CP4971// IBM4971// +-alias CSIBM4971// IBM4971// +-module IBM4971// INTERNAL IBM4971 1 +-module INTERNAL IBM4971// IBM4971 1 +- +-# from to module cost +-alias IBM-5347// IBM5347// +-alias CP5347// IBM5347// +-alias CSIBM5347// IBM5347// +-module IBM5347// INTERNAL IBM5347 1 +-module INTERNAL IBM5347// IBM5347 1 +- +-# from to module cost +-alias IBM-9030// IBM9030// +-alias CP9030// IBM9030// +-alias CSIBM9030// IBM9030// +-module IBM9030// INTERNAL IBM9030 1 +-module INTERNAL IBM9030// IBM9030 1 +- +-# from to module cost +-alias IBM-9066// IBM9066// +-alias CP9066// IBM9066// +-alias CSIBM9066// IBM9066// +-module IBM9066// INTERNAL IBM9066 1 +-module INTERNAL IBM9066// IBM9066 1 +- +-# from to module cost +-alias IBM-9448// IBM9448// +-alias CP9448// IBM9448// +-alias CSIBM9448// IBM9448// +-module IBM9448// INTERNAL IBM9448 1 +-module INTERNAL IBM9448// IBM9448 1 +- +-# from to module cost +-alias IBM-12712// IBM12712// +-alias CP12712// IBM12712// +-alias CSIBM12712// IBM12712// +-module IBM12712// INTERNAL IBM12712 1 +-module INTERNAL IBM12712// IBM12712 1 +- +-# from to module cost +-alias IBM-16804// IBM16804// +-alias CP16804// IBM16804// +-alias CSIBM16804// IBM16804// +-module IBM16804// INTERNAL IBM16804 1 +-module INTERNAL IBM16804// IBM16804 1 +- +-# from to module cost +-alias IBM-1364// IBM1364// +-alias CP1364// IBM1364// +-alias CSIBM1364// IBM1364// +-module IBM1364// INTERNAL IBM1364 1 +-module INTERNAL IBM1364// IBM1364 1 +- +-# from to module cost +-alias IBM-1371// IBM1371// +-alias CP1371// IBM1371// +-alias CSIBM1371// IBM1371// +-module IBM1371// INTERNAL IBM1371 1 +-module INTERNAL IBM1371// IBM1371 1 +- +-# from to module cost +-alias IBM-1388// IBM1388// +-alias CP1388// IBM1388// +-alias CSIBM1388// IBM1388// +-module IBM1388// INTERNAL IBM1388 1 +-module INTERNAL IBM1388// IBM1388 1 +- +-# from to module cost +-alias IBM-1390// IBM1390// +-alias CP1390// IBM1390// +-alias CSIBM1390// IBM1390// +-module IBM1390// INTERNAL IBM1390 1 +-module INTERNAL IBM1390// IBM1390 1 +- +-# from to module cost +-alias IBM-1399// IBM1399// +-alias CP1399// IBM1399// +-alias CSIBM1399// IBM1399// +-module IBM1399// INTERNAL IBM1399 1 +-module INTERNAL IBM1399// IBM1399 1 +- +-# from to module cost +-alias ISO/TR_11548-1/ ISO_11548-1// +-alias ISO11548-1// ISO_11548-1// +-module ISO_11548-1// INTERNAL ISO_11548-1 1 +-module INTERNAL ISO_11548-1// ISO_11548-1 1 +- +-# from to module cost +-module MIK// INTERNAL MIK 1 +-module INTERNAL MIK// MIK 1 +- +-# from to module cost +-module BRF// INTERNAL BRF 1 +-module INTERNAL BRF// BRF 1 +- +-# from to module cost +-alias CP1282// MAC-CENTRALEUROPE// +-module MAC-CENTRALEUROPE// INTERNAL MAC-CENTRALEUROPE 1 +-module INTERNAL MAC-CENTRALEUROPE// MAC-CENTRALEUROPE 1 +- +-# from to module cost +-module KOI8-RU// INTERNAL KOI8-RU 1 +-module INTERNAL KOI8-RU// KOI8-RU 1 +- +-# from to module cost +-alias ISO_8859-9E// ISO-8859-9E// +-alias ISO8859-9E// ISO-8859-9E// +-alias ISO88599E// ISO-8859-9E// +-module ISO-8859-9E// INTERNAL ISO8859-9E 1 +-module INTERNAL ISO-8859-9E// ISO8859-9E 1 +- +-# from to module cost +-alias ROMAN9// HP-ROMAN9// +-alias R9// HP-ROMAN9// +-alias HPROMAN9// HP-ROMAN9// +-module HP-ROMAN9// INTERNAL HP-ROMAN9 1 +-module INTERNAL HP-ROMAN9// HP-ROMAN9 1 +- +-# from to module cost +-alias TURKISH8// HP-TURKISH8// +-alias HPTURKISH8// HP-TURKISH8// +-alias OSF10010006// HP-TURKISH8// +-module HP-TURKISH8// INTERNAL HP-TURKISH8 1 +-module INTERNAL HP-TURKISH8// HP-TURKISH8 1 +- +-# from to module cost +-alias THAI8// HP-THAI8// +-alias HPTHAI8// HP-THAI8// +-module HP-THAI8// INTERNAL HP-THAI8 1 +-module INTERNAL HP-THAI8// HP-THAI8 1 +- +-# from to module cost +-alias HPGREEK8// HP-GREEK8// +-alias OSF10010004// HP-GREEK8// +-module HP-GREEK8// INTERNAL HP-GREEK8 1 +-module INTERNAL HP-GREEK8// HP-GREEK8 1 +- + alias ISO-10646-UCS-2// UNICODE// + alias ISO-10646-UCS-2// ISO-10646/UTF8/ diff --git a/SOURCES/glibc-rh1971664-6.patch b/SOURCES/glibc-rh1971664-6.patch new file mode 100644 index 0000000..b0d40a0 --- /dev/null +++ b/SOURCES/glibc-rh1971664-6.patch @@ -0,0 +1,137 @@ +commit 06a1b794073c4d6adbfb2e4b11339985a14d7a00 +Author: Siddhesh Poyarekar +Date: Mon Jun 14 11:09:56 2021 +0530 + + Reinstate gconv-modules as the default configuration file + + Reinstate gconv-modules as the main file so that the configuration + files in gconv-modules.d/ become add-on configuration. With this, the + effective user visible change is that GCONV_PATH can now have + supplementary configuration in GCONV_PATH/gconv-modules.d/ in addition + to the main GCONV_PATH/gconv-modules file. + +# Conflicts: +# iconvdata/Makefile + +diff --git a/iconvdata/Makefile b/iconvdata/Makefile +index d682a98b5c4a8003..95e5fb8f722a513b 100644 +--- a/iconvdata/Makefile ++++ b/iconvdata/Makefile +@@ -136,13 +136,12 @@ charmaps = ../localedata/charmaps + extra-modules-left := $(modules) + include extra-module.mk + +-gconv-modules = gconv-modules.conf gconv-modules-extra.conf ++gconv-modules = gconv-modules gconv-modules.d/gconv-modules-extra.conf + modpfx = $(objpfx)gconv-modules.d/ + + extra-objs += $(modules.so) + install-others = $(addprefix $(inst_gconvdir)/, $(modules.so)) \ +- $(addprefix $(inst_gconvdir)/gconv-modules.d/, \ +- $(gconv-modules)) ++ $(addprefix $(inst_gconvdir)/, $(gconv-modules)) + + # We can build the conversion tables for numerous charsets automatically. + +@@ -184,7 +183,7 @@ generated += $(generated-modules:=.h) $(generated-modules:=.stmp) \ + iconv-test.out iconv-rules tst-loading.mtrace \ + mtrace-tst-loading.out tst-tables.out iconv-test.xxx + ifdef objpfx +-generated += $(addprefix gconv-modules.d/,$(gconv-modules)) ++generated += $(gconv-modules) + endif + + # Rules to generate the headers. +@@ -252,8 +251,8 @@ headers: $(addprefix $(objpfx), $(generated-modules:=.h)) + $(addprefix $(inst_gconvdir)/, $(modules.so)): \ + $(inst_gconvdir)/%: $(objpfx)% $(+force) + $(do-install-program) +-$(addprefix $(inst_gconvdir)/gconv-modules.d/, $(gconv-modules)): \ +- $(inst_gconvdir)/gconv-modules.d/%: $(modpfx)% $(+force) ++$(addprefix $(inst_gconvdir)/, $(gconv-modules)): \ ++ $(inst_gconvdir)/%: $(objpfx)% $(+force) + $(do-install) + ifeq (no,$(cross-compiling)) + # Update the $(prefix)/lib/gconv/gconv-modules.cache file. This is necessary +@@ -301,30 +300,30 @@ $(objpfx)mtrace-tst-loading.out: $(objpfx)tst-loading.out + $(common-objpfx)malloc/mtrace $(objpfx)tst-loading.mtrace > $@; \ + $(evaluate-test) + +-$(objpfx)bug-iconv1.out: $(addprefix $(modpfx), $(gconv-modules)) \ ++$(objpfx)bug-iconv1.out: $(addprefix $(objpfx), $(gconv-modules)) \ + $(addprefix $(objpfx),$(modules.so)) +-$(objpfx)bug-iconv2.out: $(addprefix $(modpfx), $(gconv-modules)) \ ++$(objpfx)bug-iconv2.out: $(addprefix $(objpfx), $(gconv-modules)) \ + $(addprefix $(objpfx),$(modules.so)) + $(objpfx)bug-iconv3: $(libdl) +-$(objpfx)bug-iconv3.out: $(addprefix $(modpfx), $(gconv-modules)) \ ++$(objpfx)bug-iconv3.out: $(addprefix $(objpfx), $(gconv-modules)) \ + $(addprefix $(objpfx),$(modules.so)) +-$(objpfx)bug-iconv5.out: $(addprefix $(modpfx), $(gconv-modules)) \ ++$(objpfx)bug-iconv5.out: $(addprefix $(objpfx), $(gconv-modules)) \ + $(addprefix $(objpfx),$(modules.so)) +-$(objpfx)tst-loading.out: $(addprefix $(modpfx), $(gconv-modules)) \ ++$(objpfx)tst-loading.out: $(addprefix $(objpfx), $(gconv-modules)) \ + $(addprefix $(objpfx),$(modules.so)) +-$(objpfx)tst-iconv4.out: $(addprefix $(modpfx), $(gconv-modules)) \ ++$(objpfx)tst-iconv4.out: $(addprefix $(objpfx), $(gconv-modules)) \ + $(addprefix $(objpfx),$(modules.so)) +-$(objpfx)tst-iconv7.out: $(addprefix $(modpfx), $(gconv-modules)) \ ++$(objpfx)tst-iconv7.out: $(addprefix $(objpfx), $(gconv-modules)) \ + $(addprefix $(objpfx),$(modules.so)) +-$(objpfx)bug-iconv10.out: $(addprefix $(modpfx), $(gconv-modules)) \ ++$(objpfx)bug-iconv10.out: $(addprefix $(objpfx), $(gconv-modules)) \ + $(addprefix $(objpfx),$(modules.so)) +-$(objpfx)bug-iconv12.out: $(addprefix $(modpfx), $(gconv-modules)) \ ++$(objpfx)bug-iconv12.out: $(addprefix $(objpfx), $(gconv-modules)) \ + $(addprefix $(objpfx),$(modules.so)) +-$(objpfx)bug-iconv14.out: $(addprefix $(modpfx), $(gconv-modules)) \ ++$(objpfx)bug-iconv14.out: $(addprefix $(objpfx), $(gconv-modules)) \ + $(addprefix $(objpfx),$(modules.so)) + + $(objpfx)iconv-test.out: run-iconv-test.sh \ +- $(addprefix $(modpfx), $(gconv-modules)) \ ++ $(addprefix $(objpfx), $(gconv-modules)) \ + $(addprefix $(objpfx),$(modules.so)) \ + $(common-objdir)/iconv/iconv_prog TESTS + iconv_modules="$(modules)" \ +@@ -333,7 +332,7 @@ $(objpfx)iconv-test.out: run-iconv-test.sh \ + $(evaluate-test) + + $(objpfx)tst-tables.out: tst-tables.sh \ +- $(addprefix $(modpfx), $(gconv-modules)) \ ++ $(addprefix $(objpfx), $(gconv-modules)) \ + $(addprefix $(objpfx),$(modules.so)) \ + $(objpfx)tst-table-from $(objpfx)tst-table-to + $(SHELL) $< $(common-objpfx) $(common-objpfx)iconvdata/ \ +@@ -351,3 +350,6 @@ $(modpfx): + + $(modpfx)%: % $(modpfx) + cp $< $@ ++ ++$(objpfx)gconv-modules: gconv-modules ++ cp $^ $@ +diff --git a/iconvdata/gconv-modules.conf b/iconvdata/gconv-modules +similarity index 100% +rename from iconvdata/gconv-modules.conf +rename to iconvdata/gconv-modules +diff --git a/localedata/Makefile b/localedata/Makefile +index a5ca7a31f43d50c3..14fcc37fed21e740 100644 +--- a/localedata/Makefile ++++ b/localedata/Makefile +@@ -179,7 +179,7 @@ install-others := $(addprefix $(inst_i18ndir)/, \ + $(locales)) + endif + +-tests: $(objdir)/iconvdata/gconv-modules.d/gconv-modules.conf ++tests: $(objdir)/iconvdata/gconv-modules + + tests-static += tst-langinfo-newlocale-static tst-langinfo-setlocale-static + +@@ -442,5 +442,5 @@ $(objpfx)mtrace-tst-leaks.out: $(objpfx)tst-leaks.out + bug-setlocale1-ENV-only = LOCPATH=$(objpfx) LC_CTYPE=de_DE.UTF-8 + bug-setlocale1-static-ENV-only = $(bug-setlocale1-ENV-only) + +-$(objdir)/iconvdata/gconv-modules.d/gconv-modules.conf: ++$(objdir)/iconvdata/gconv-modules: + $(MAKE) -C ../iconvdata subdir=iconvdata $@ diff --git a/SOURCES/glibc-rh1971664-7.patch b/SOURCES/glibc-rh1971664-7.patch new file mode 100644 index 0000000..f7c4dd8 --- /dev/null +++ b/SOURCES/glibc-rh1971664-7.patch @@ -0,0 +1,107 @@ +commit e3217c7fd9e67aa2d53700bb1da9a966e73b9684 +Author: Siddhesh Poyarekar +Date: Thu Jun 10 00:41:35 2021 +0530 + + iconv: Remove alloca use in gconv-modules configuration parsing + + The alloca sizes ought to be constrained to PATH_MAX, but replace them + with dynamic allocation to be safe. A static PATH_MAX array would + have worked too but Hurd does not have PATH_MAX and the code path is + not hot enough to micro-optimise this allocation. Revisit if any of + those realities change. + + Reviewed-by: DJ Delorie + +diff --git a/iconv/gconv_conf.c b/iconv/gconv_conf.c +index 8eb981fca7cee36a..3099bf192adce711 100644 +--- a/iconv/gconv_conf.c ++++ b/iconv/gconv_conf.c +@@ -557,15 +557,15 @@ __gconv_read_conf (void) + + for (cnt = 0; __gconv_path_elem[cnt].name != NULL; ++cnt) + { +-#define BUF_LEN elem_len + sizeof (gconv_conf_dirname) +- + const char *elem = __gconv_path_elem[cnt].name; + size_t elem_len = __gconv_path_elem[cnt].len; +- char *buf; + + /* No slash needs to be inserted between elem and gconv_conf_filename; + elem already ends in a slash. */ +- buf = alloca (BUF_LEN); ++ char *buf = malloc (elem_len + sizeof (gconv_conf_dirname)); ++ if (buf == NULL) ++ continue; ++ + char *cp = __mempcpy (__mempcpy (buf, elem, elem_len), + gconv_conf_filename, sizeof (gconv_conf_filename)); + +@@ -594,15 +594,16 @@ __gconv_read_conf (void) + if (len > strlen (suffix) + && strcmp (ent->d_name + len - strlen (suffix), suffix) == 0) + { +- /* LEN <= PATH_MAX so this alloca is not unbounded. */ +- char *conf = alloca (BUF_LEN + len + 1); +- cp = stpcpy (conf, buf); +- sprintf (cp, "/%s", ent->d_name); ++ char *conf; ++ if (__asprintf (&conf, "%s/%s", buf, ent->d_name) < 0) ++ continue; + read_conf_file (conf, elem, elem_len, &modules, &nmodules); ++ free (conf); + } + } + __closedir (confdir); + } ++ free (buf); + } + #endif + +diff --git a/iconv/iconvconfig.c b/iconv/iconvconfig.c +index fafc686ae25fb5c1..2f9d5f45ad3a8159 100644 +--- a/iconv/iconvconfig.c ++++ b/iconv/iconvconfig.c +@@ -712,7 +712,6 @@ handle_file (const char *dir, const char *infile) + static int + handle_dir (const char *dir) + { +-#define BUF_LEN prefix_len + dirlen + sizeof "gconv-modules.d" + char *cp; + size_t dirlen = strlen (dir); + bool found = false; +@@ -726,7 +725,10 @@ handle_dir (const char *dir) + } + + /* First, look for a gconv-modules file. */ +- char buf[BUF_LEN]; ++ char *buf = malloc (prefix_len + dirlen + sizeof "gconv-modules.d"); ++ if (buf == NULL) ++ goto out; ++ + cp = buf; + if (dir[0] == '/') + cp = mempcpy (cp, prefix, prefix_len); +@@ -756,16 +758,19 @@ handle_dir (const char *dir) + if (len > strlen (suffix) + && strcmp (ent->d_name + len - strlen (suffix), suffix) == 0) + { +- /* LEN <= PATH_MAX so this alloca is not unbounded. */ +- char *conf = alloca (BUF_LEN + len + 1); +- cp = stpcpy (conf, buf); +- sprintf (cp, "/%s", ent->d_name); ++ char *conf; ++ if (asprintf (&conf, "%s/%s", buf, ent->d_name) < 0) ++ continue; + found |= handle_file (dir, conf); ++ free (conf); + } + } + closedir (confdir); + } + ++ free (buf); ++ ++out: + if (!found) + { + error (0, errno, "failed to open gconv configuration files in `%s'", diff --git a/SOURCES/glibc-rh1971664-8.patch b/SOURCES/glibc-rh1971664-8.patch new file mode 100644 index 0000000..ec11f7b --- /dev/null +++ b/SOURCES/glibc-rh1971664-8.patch @@ -0,0 +1,113 @@ +commit 23e15ea1ae80ec2120afdf643691359644cf2873 +Author: Siddhesh Poyarekar +Date: Thu Jun 10 09:51:50 2021 +0530 + + gconv_conf: Remove unused variables + + The modules and nmodules parameters passed to add_modules, add_alias, + etc. are not used and are hence unnecessary. Remove them so that + their signatures match the functions in iconvconfig. + + Reviewed-by: DJ Delorie + Reviewed-by: Andreas Schwab + +diff --git a/iconv/gconv_conf.c b/iconv/gconv_conf.c +index 3099bf192adce711..dc12ce24844474cc 100644 +--- a/iconv/gconv_conf.c ++++ b/iconv/gconv_conf.c +@@ -125,7 +125,7 @@ detect_conflict (const char *alias) + + /* The actual code to add aliases. */ + static void +-add_alias2 (const char *from, const char *to, const char *wp, void *modules) ++add_alias2 (const char *from, const char *to, const char *wp) + { + /* Test whether this alias conflicts with any available module. */ + if (detect_conflict (from)) +@@ -154,7 +154,7 @@ add_alias2 (const char *from, const char *to, const char *wp, void *modules) + + /* Add new alias. */ + static void +-add_alias (char *rp, void *modules) ++add_alias (char *rp) + { + /* We now expect two more string. The strings are normalized + (converted to UPPER case) and strored in the alias database. */ +@@ -179,7 +179,7 @@ add_alias (char *rp, void *modules) + return; + *wp++ = '\0'; + +- add_alias2 (from, to, wp, modules); ++ add_alias2 (from, to, wp); + } + + +@@ -243,8 +243,7 @@ insert_module (struct gconv_module *newp, int tobefreed) + + /* Add new module. */ + static void +-add_module (char *rp, const char *directory, size_t dir_len, void **modules, +- size_t *nmodules, int modcounter) ++add_module (char *rp, const char *directory, size_t dir_len, int modcounter) + { + /* We expect now + 1. `from' name +@@ -357,8 +356,7 @@ add_module (char *rp, const char *directory, size_t dir_len, void **modules, + + /* Read the next configuration file. */ + static void +-read_conf_file (const char *filename, const char *directory, size_t dir_len, +- void **modules, size_t *nmodules) ++read_conf_file (const char *filename, const char *directory, size_t dir_len) + { + /* Note the file is opened with cancellation in the I/O functions + disabled. */ +@@ -408,10 +406,10 @@ read_conf_file (const char *filename, const char *directory, size_t dir_len, + + if (rp - word == sizeof ("alias") - 1 + && memcmp (word, "alias", sizeof ("alias") - 1) == 0) +- add_alias (rp, *modules); ++ add_alias (rp); + else if (rp - word == sizeof ("module") - 1 + && memcmp (word, "module", sizeof ("module") - 1) == 0) +- add_module (rp, directory, dir_len, modules, nmodules, modcounter++); ++ add_module (rp, directory, dir_len, modcounter++); + /* else */ + /* Otherwise ignore the line. */ + } +@@ -537,8 +535,6 @@ void + attribute_hidden + __gconv_read_conf (void) + { +- void *modules = NULL; +- size_t nmodules = 0; + int save_errno = errno; + size_t cnt; + +@@ -570,7 +566,7 @@ __gconv_read_conf (void) + gconv_conf_filename, sizeof (gconv_conf_filename)); + + /* Read the gconv-modules configuration file first. */ +- read_conf_file (buf, elem, elem_len, &modules, &nmodules); ++ read_conf_file (buf, elem, elem_len); + + /* Next, see if there is a gconv-modules.d directory containing + configuration files and if it is non-empty. */ +@@ -597,7 +593,7 @@ __gconv_read_conf (void) + char *conf; + if (__asprintf (&conf, "%s/%s", buf, ent->d_name) < 0) + continue; +- read_conf_file (conf, elem, elem_len, &modules, &nmodules); ++ read_conf_file (conf, elem, elem_len); + free (conf); + } + } +@@ -631,7 +627,7 @@ __gconv_read_conf (void) + const char *to = __rawmemchr (from, '\0') + 1; + cp = __rawmemchr (to, '\0') + 1; + +- add_alias2 (from, to, cp, modules); ++ add_alias2 (from, to, cp); + } + while (*cp != '\0'); + diff --git a/SOURCES/glibc-rh1971664-9.patch b/SOURCES/glibc-rh1971664-9.patch new file mode 100644 index 0000000..c1c1369 --- /dev/null +++ b/SOURCES/glibc-rh1971664-9.patch @@ -0,0 +1,360 @@ +commit d8e8097f3be5b3c49fc741fa19e1da0b0431384c +Author: Siddhesh Poyarekar +Date: Thu Jun 10 14:07:27 2021 +0530 + + gconv_conf: Split out configuration file processing + + Split configuration file processing into a separate header file and + include it. Macroize all calls that need to go through internal + interfaces so that iconvconfig can also use them. + + Reviewed-by: DJ Delorie + +# Conflicts: +# iconv/gconv_conf.c + +diff --git a/iconv/gconv_conf.c b/iconv/gconv_conf.c +index dc12ce24844474cc..ce64faa928dc1c52 100644 +--- a/iconv/gconv_conf.c ++++ b/iconv/gconv_conf.c +@@ -19,7 +19,6 @@ + + #include + #include +-#include + #include + #include + #include +@@ -31,11 +30,10 @@ + #include + #include + #include +-#include + + #include + #include +- ++#include + + /* This is the default path where we look for module lists. */ + static const char default_gconv_path[] = GCONV_PATH; +@@ -49,11 +47,6 @@ size_t __gconv_max_path_elem_len; + /* We use the following struct if we couldn't allocate memory. */ + static const struct path_elem empty_path_elem = { NULL, 0 }; + +-/* Name of the file containing the module information in the directories +- along the path. */ +-static const char gconv_conf_filename[] = "gconv-modules"; +-static const char gconv_conf_dirname[] = "gconv-modules.d"; +- + /* Filename extension for the modules. */ + #ifndef MODULE_EXT + # define MODULE_EXT ".so" +@@ -92,9 +85,6 @@ static const char builtin_aliases[] = + #undef BUILTIN_ALIAS + }; + +-#include +-#define __getdelim(line, len, c, fp) _IO_getdelim (line, len, c, fp) +- + + /* Value of the GCONV_PATH environment variable. */ + const char *__gconv_path_envvar; +@@ -354,72 +344,6 @@ add_module (char *rp, const char *directory, size_t dir_len, int modcounter) + } + + +-/* Read the next configuration file. */ +-static void +-read_conf_file (const char *filename, const char *directory, size_t dir_len) +-{ +- /* Note the file is opened with cancellation in the I/O functions +- disabled. */ +- FILE *fp = fopen (filename, "rce"); +- char *line = NULL; +- size_t line_len = 0; +- static int modcounter; +- +- /* Don't complain if a file is not present or readable, simply silently +- ignore it. */ +- if (fp == NULL) +- return; +- +- /* No threads reading from this stream. */ +- __fsetlocking (fp, FSETLOCKING_BYCALLER); +- +- /* Process the known entries of the file. Comments start with `#' and +- end with the end of the line. Empty lines are ignored. */ +- while (!__feof_unlocked (fp)) +- { +- char *rp, *endp, *word; +- ssize_t n = __getdelim (&line, &line_len, '\n', fp); +- if (n < 0) +- /* An error occurred. */ +- break; +- +- rp = line; +- /* Terminate the line (excluding comments or newline) by an NUL byte +- to simplify the following code. */ +- endp = strchr (rp, '#'); +- if (endp != NULL) +- *endp = '\0'; +- else +- if (rp[n - 1] == '\n') +- rp[n - 1] = '\0'; +- +- while (__isspace_l (*rp, _nl_C_locobj_ptr)) +- ++rp; +- +- /* If this is an empty line go on with the next one. */ +- if (rp == endp) +- continue; +- +- word = rp; +- while (*rp != '\0' && !__isspace_l (*rp, _nl_C_locobj_ptr)) +- ++rp; +- +- if (rp - word == sizeof ("alias") - 1 +- && memcmp (word, "alias", sizeof ("alias") - 1) == 0) +- add_alias (rp); +- else if (rp - word == sizeof ("module") - 1 +- && memcmp (word, "module", sizeof ("module") - 1) == 0) +- add_module (rp, directory, dir_len, modcounter++); +- /* else */ +- /* Otherwise ignore the line. */ +- } +- +- free (line); +- +- fclose (fp); +-} +- +- + /* Determine the directories we are looking for data in. */ + void + __gconv_get_path (void) +@@ -552,55 +476,8 @@ __gconv_read_conf (void) + __gconv_get_path (); + + for (cnt = 0; __gconv_path_elem[cnt].name != NULL; ++cnt) +- { +- const char *elem = __gconv_path_elem[cnt].name; +- size_t elem_len = __gconv_path_elem[cnt].len; +- +- /* No slash needs to be inserted between elem and gconv_conf_filename; +- elem already ends in a slash. */ +- char *buf = malloc (elem_len + sizeof (gconv_conf_dirname)); +- if (buf == NULL) +- continue; +- +- char *cp = __mempcpy (__mempcpy (buf, elem, elem_len), +- gconv_conf_filename, sizeof (gconv_conf_filename)); +- +- /* Read the gconv-modules configuration file first. */ +- read_conf_file (buf, elem, elem_len); +- +- /* Next, see if there is a gconv-modules.d directory containing +- configuration files and if it is non-empty. */ +- cp--; +- cp[0] = '.'; +- cp[1] = 'd'; +- cp[2] = '\0'; +- +- DIR *confdir = __opendir (buf); +- if (confdir != NULL) +- { +- struct dirent *ent; +- while ((ent = __readdir (confdir)) != NULL) +- { +- if (ent->d_type != DT_REG) +- continue; +- +- size_t len = strlen (ent->d_name); +- const char *suffix = ".conf"; +- +- if (len > strlen (suffix) +- && strcmp (ent->d_name + len - strlen (suffix), suffix) == 0) +- { +- char *conf; +- if (__asprintf (&conf, "%s/%s", buf, ent->d_name) < 0) +- continue; +- read_conf_file (conf, elem, elem_len); +- free (conf); +- } +- } +- __closedir (confdir); +- } +- free (buf); +- } ++ gconv_parseconfdir (__gconv_path_elem[cnt].name, ++ __gconv_path_elem[cnt].len); + #endif + + /* Add the internal modules. */ +diff --git a/iconv/gconv_parseconfdir.h b/iconv/gconv_parseconfdir.h +new file mode 100644 +index 0000000000000000..3d4d58d4be10a250 +--- /dev/null ++++ b/iconv/gconv_parseconfdir.h +@@ -0,0 +1,161 @@ ++/* Handle configuration data. ++ 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 ++ ++#if IS_IN (libc) ++# include ++# define __getdelim(line, len, c, fp) _IO_getdelim (line, len, c, fp) ++ ++# undef isspace ++# define isspace(__c) __isspace_l ((__c), _nl_C_locobj_ptr) ++# define asprintf __asprintf ++# define opendir __opendir ++# define readdir __readdir ++# define closedir __closedir ++# define mempcpy __mempcpy ++#endif ++ ++/* Name of the file containing the module information in the directories ++ along the path. */ ++static const char gconv_conf_filename[] = "gconv-modules"; ++static const char gconv_conf_dirname[] = "gconv-modules.d"; ++ ++static void add_alias (char *); ++static void add_module (char *, const char *, size_t, int); ++ ++/* Read the next configuration file. */ ++static bool ++read_conf_file (const char *filename, const char *directory, size_t dir_len) ++{ ++ /* Note the file is opened with cancellation in the I/O functions ++ disabled. */ ++ FILE *fp = fopen (filename, "rce"); ++ char *line = NULL; ++ size_t line_len = 0; ++ static int modcounter; ++ ++ /* Don't complain if a file is not present or readable, simply silently ++ ignore it. */ ++ if (fp == NULL) ++ return false; ++ ++ /* No threads reading from this stream. */ ++ __fsetlocking (fp, FSETLOCKING_BYCALLER); ++ ++ /* Process the known entries of the file. Comments start with `#' and ++ end with the end of the line. Empty lines are ignored. */ ++ while (!__feof_unlocked (fp)) ++ { ++ char *rp, *endp, *word; ++ ssize_t n = __getdelim (&line, &line_len, '\n', fp); ++ if (n < 0) ++ /* An error occurred. */ ++ break; ++ ++ rp = line; ++ /* Terminate the line (excluding comments or newline) by an NUL byte ++ to simplify the following code. */ ++ endp = strchr (rp, '#'); ++ if (endp != NULL) ++ *endp = '\0'; ++ else ++ if (rp[n - 1] == '\n') ++ rp[n - 1] = '\0'; ++ ++ while (isspace (*rp)) ++ ++rp; ++ ++ /* If this is an empty line go on with the next one. */ ++ if (rp == endp) ++ continue; ++ ++ word = rp; ++ while (*rp != '\0' && !isspace (*rp)) ++ ++rp; ++ ++ if (rp - word == sizeof ("alias") - 1 ++ && memcmp (word, "alias", sizeof ("alias") - 1) == 0) ++ add_alias (rp); ++ else if (rp - word == sizeof ("module") - 1 ++ && memcmp (word, "module", sizeof ("module") - 1) == 0) ++ add_module (rp, directory, dir_len, modcounter++); ++ /* else */ ++ /* Otherwise ignore the line. */ ++ } ++ ++ free (line); ++ ++ fclose (fp); ++ return true; ++} ++ ++static __always_inline bool ++gconv_parseconfdir (const char *dir, size_t dir_len) ++{ ++ /* No slash needs to be inserted between dir and gconv_conf_filename; ++ dir already ends in a slash. */ ++ char *buf = malloc (dir_len + sizeof (gconv_conf_dirname)); ++ bool found = false; ++ ++ if (buf == NULL) ++ return false; ++ ++ char *cp = mempcpy (mempcpy (buf, dir, dir_len), gconv_conf_filename, ++ sizeof (gconv_conf_filename)); ++ ++ /* Read the gconv-modules configuration file first. */ ++ found = read_conf_file (buf, dir, dir_len); ++ ++ /* Next, see if there is a gconv-modules.d directory containing ++ configuration files and if it is non-empty. */ ++ cp--; ++ cp[0] = '.'; ++ cp[1] = 'd'; ++ cp[2] = '\0'; ++ ++ DIR *confdir = opendir (buf); ++ if (confdir != NULL) ++ { ++ struct dirent *ent; ++ while ((ent = readdir (confdir)) != NULL) ++ { ++ if (ent->d_type != DT_REG) ++ continue; ++ ++ size_t len = strlen (ent->d_name); ++ const char *suffix = ".conf"; ++ ++ if (len > strlen (suffix) ++ && strcmp (ent->d_name + len - strlen (suffix), suffix) == 0) ++ { ++ char *conf; ++ if (asprintf (&conf, "%s/%s", buf, ent->d_name) < 0) ++ continue; ++ found |= read_conf_file (conf, dir, dir_len); ++ free (conf); ++ } ++ } ++ closedir (confdir); ++ } ++ free (buf); ++ return found; ++} diff --git a/SOURCES/glibc-rh1977614.patch b/SOURCES/glibc-rh1977614.patch new file mode 100644 index 0000000..078dc68 --- /dev/null +++ b/SOURCES/glibc-rh1977614.patch @@ -0,0 +1,33 @@ +commit dfec225ee1972488bb48a8b67a2c4a13010c334a +Author: JeffyChen +Date: Fri Jul 2 17:39:24 2021 +0200 + + malloc: Initiate tcache shutdown even without allocations [BZ #28028] + + After commit 1e26d35193efbb29239c710a4c46a64708643320 ("malloc: Fix + tcache leak after thread destruction [BZ #22111]"), + tcache_shutting_down is still not early enough. When we detach a + thread with no tcache allocated, tcache_shutting_down would still be + false. + + Reviewed-by: DJ Delorie + +diff --git a/malloc/malloc.c b/malloc/malloc.c +index 00a37f218c0ab3b2..61f7bdc76064c340 100644 +--- a/malloc/malloc.c ++++ b/malloc/malloc.c +@@ -2960,12 +2960,13 @@ tcache_thread_shutdown (void) + int i; + tcache_perthread_struct *tcache_tmp = tcache; + ++ tcache_shutting_down = true; ++ + if (!tcache) + return; + + /* Disable the tcache and prevent it from being reinitialized. */ + tcache = NULL; +- tcache_shutting_down = true; + + /* Free all of the entries and the tcache itself back to the arena + heap for coalescing. */ diff --git a/SOURCES/glibc-rh1979127.patch b/SOURCES/glibc-rh1979127.patch new file mode 100644 index 0000000..4a21d5a --- /dev/null +++ b/SOURCES/glibc-rh1979127.patch @@ -0,0 +1,33 @@ +commit 5adda61f62b77384718b4c0d8336ade8f2b4b35c +Author: Andreas Schwab +Date: Fri Jun 25 15:02:47 2021 +0200 + + wordexp: handle overflow in positional parameter number (bug 28011) + + Use strtoul instead of atoi so that overflow can be detected. + +diff --git a/posix/wordexp-test.c b/posix/wordexp-test.c +index cc29840355e047cc..30c1dd65efcc0b49 100644 +--- a/posix/wordexp-test.c ++++ b/posix/wordexp-test.c +@@ -200,6 +200,7 @@ struct test_case_struct + { 0, NULL, "$var", 0, 0, { NULL, }, IFS }, + { 0, NULL, "\"\\n\"", 0, 1, { "\\n", }, IFS }, + { 0, NULL, "", 0, 0, { NULL, }, IFS }, ++ { 0, NULL, "${1234567890123456789012}", 0, 0, { NULL, }, IFS }, + + /* Flags not already covered (testit() has special handling for these) */ + { 0, NULL, "one two", WRDE_DOOFFS, 2, { "one", "two", }, IFS }, +diff --git a/posix/wordexp.c b/posix/wordexp.c +index 048a8068544c81fa..4061969c720f1f34 100644 +--- a/posix/wordexp.c ++++ b/posix/wordexp.c +@@ -1420,7 +1420,7 @@ envsubst: + /* Is it a numeric parameter? */ + else if (isdigit (env[0])) + { +- int n = atoi (env); ++ unsigned long n = strtoul (env, NULL, 10); + + if (n >= __libc_argc) + /* Substitute NULL. */ diff --git a/SOURCES/glibc-rh1982608.patch b/SOURCES/glibc-rh1982608.patch new file mode 100644 index 0000000..6f67ed6 --- /dev/null +++ b/SOURCES/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/SOURCES/glibc-rh1983203-1.patch b/SOURCES/glibc-rh1983203-1.patch new file mode 100644 index 0000000..07e1431 --- /dev/null +++ b/SOURCES/glibc-rh1983203-1.patch @@ -0,0 +1,306 @@ +commit a55e2da2702e235fa0ae66a116d304d1bffc060a +Author: Lucas A. M. Magalhaes +Date: Thu May 6 17:01:52 2021 -0300 + + powerpc: Optimized memcmp for power10 + + This patch was based on the __memcmp_power8 and the recent + __strlen_power10. + + Improvements from __memcmp_power8: + + 1. Don't need alignment code. + + On POWER10 lxvp and lxvl do not generate alignment interrupts, so + they are safe for use on caching-inhibited memory. Notice that the + comparison on the main loop will wait for both VSR to be ready. + Therefore aligning one of the input address does not improve + performance. In order to align both registers a vperm is necessary + which add too much overhead. + + 2. Uses new POWER10 instructions + + This code uses lxvp to decrease contention on load by loading 32 bytes + per instruction. + The vextractbm is used to have a smaller tail code for calculating the + return value. + + 3. Performance improvement + + This version has around 35% better performance on average. I saw no + performance regressions for any length or alignment. + + Thanks Matheus for helping me out with some details. + + Co-authored-by: Matheus Castanho + Reviewed-by: Raphael M Zinsly + +diff --git a/sysdeps/powerpc/powerpc64/le/power10/memcmp.S b/sysdeps/powerpc/powerpc64/le/power10/memcmp.S +new file mode 100644 +index 0000000000000000..52f244e7e77cbdf9 +--- /dev/null ++++ b/sysdeps/powerpc/powerpc64/le/power10/memcmp.S +@@ -0,0 +1,179 @@ ++/* Optimized memcmp implementation for POWER10. ++ 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 ++ ++/* TODO: Replace macros by the actual instructions when minimum binutils becomes ++ >= 2.35. This is used to keep compatibility with older versions. */ ++#define VEXTRACTBM(rt,vrb) \ ++ .long(((4)<<(32-6)) \ ++ | ((rt)<<(32-11)) \ ++ | ((8)<<(32-16)) \ ++ | ((vrb)<<(32-21)) \ ++ | 1602) ++ ++#define LXVP(xtp,dq,ra) \ ++ .long(((6)<<(32-6)) \ ++ | ((((xtp)-32)>>1)<<(32-10)) \ ++ | ((1)<<(32-11)) \ ++ | ((ra)<<(32-16)) \ ++ | dq) ++ ++/* Compare 32 bytes. */ ++#define COMPARE_32(vr1,vr2,offset,tail_1,tail_2)\ ++ LXVP(32+vr1,offset,r3); \ ++ LXVP(32+vr2,offset,r4); \ ++ vcmpneb. v5,vr1+1,vr2+1; \ ++ bne cr6,L(tail_2); \ ++ vcmpneb. v4,vr1,vr2; \ ++ bne cr6,L(tail_1); \ ++ ++#define TAIL(v_res,s1,s2) \ ++ vctzlsbb r7,v_res; \ ++ vextubrx r8,r7,s1; \ ++ vextubrx r9,r7,s2; \ ++ subf r3,r9,r8; \ ++ blr; \ ++ ++/* int [r3] memcmp (const char *s1 [r3], const char *s2 [r4], ++ size_t size [r5]) */ ++ ++#ifndef MEMCMP ++# define MEMCMP memcmp ++#endif ++ .machine power9 ++ENTRY_TOCLESS (MEMCMP, 4) ++ CALL_MCOUNT 3 ++ ++ cmpldi cr6,r5,64 ++ bgt cr6,L(loop_head) ++ ++/* Compare 64 bytes. This section is used for lengths <= 64 and for the last ++ bytes for larger lengths. */ ++L(last_compare): ++ li r8,16 ++ ++ sldi r9,r5,56 ++ sldi r8,r8,56 ++ addi r6,r3,16 ++ addi r7,r4,16 ++ ++ /* Align up to 16 bytes. */ ++ lxvl 32+v0,r3,r9 ++ lxvl 32+v2,r4,r9 ++ ++ /* The sub. and vcmpneb. results are concatenated by the crnand in order ++ to do a single branch. It's doing a NOT(CR0.GT AND CR6.EQ) then ++ loading to CR0.LT. That means r9 is not bigger than 0 and v4 is not ++ all equal to 0. */ ++ sub. r9,r9,r8 ++ vcmpneb. v4,v0,v2 ++ crnand 4*cr0+lt,4*cr0+gt,4*cr6+eq ++ bt 4*cr0+lt,L(tail1) ++ ++ addi r3,r3,32 ++ addi r4,r4,32 ++ ++ lxvl 32+v1,r6,r9 ++ lxvl 32+v3,r7,r9 ++ sub. r9,r9,r8 ++ vcmpneb. v5,v1,v3 ++ crnand 4*cr0+lt,4*cr0+gt,4*cr6+eq ++ bt 4*cr0+lt,L(tail2) ++ ++ addi r6,r3,16 ++ addi r7,r4,16 ++ ++ lxvl 32+v6,r3,r9 ++ lxvl 32+v8,r4,r9 ++ sub. r9,r9,r8 ++ vcmpneb. v4,v6,v8 ++ crnand 4*cr0+lt,4*cr0+gt,4*cr6+eq ++ bt 4*cr0+lt,L(tail3) ++ ++ lxvl 32+v7,r6,r9 ++ lxvl 32+v9,r7,r9 ++ vcmpneb. v5,v7,v9 ++ bne cr6,L(tail4) ++ ++L(finish): ++ /* The contents are equal. */ ++ li r3,0 ++ blr ++ ++L(loop_head): ++ /* Calculate how many loops to run. */ ++ srdi. r8,r5,7 ++ beq L(loop_tail) ++ mtctr r8 ++ ++/* Main loop. Compares 128 bytes each loop. */ ++ .p2align 5 ++L(loop_128): ++ COMPARE_32(v0,v2,0,tail1,tail2) ++ COMPARE_32(v6,v8,32,tail3,tail4) ++ COMPARE_32(v10,v12,64,tail5,tail6) ++ COMPARE_32(v14,v16,96,tail7,tail8) ++ ++ addi r3,r3,128 ++ addi r4,r4,128 ++ bdnz L(loop_128) ++ ++ /* Account loop comparisons. */ ++ clrldi. r5,r5,57 ++ beq L(finish) ++ ++/* Compares 64 bytes if length is still bigger than 64 bytes. */ ++ .p2align 5 ++L(loop_tail): ++ cmpldi r5,64 ++ ble L(last_compare) ++ COMPARE_32(v0,v2,0,tail1,tail2) ++ COMPARE_32(v6,v8,32,tail3,tail4) ++ addi r3,r3,64 ++ addi r4,r4,64 ++ subi r5,r5,64 ++ b L(last_compare) ++ ++L(tail1): ++ TAIL(v4,v0,v2) ++ ++L(tail2): ++ TAIL(v5,v1,v3) ++ ++L(tail3): ++ TAIL(v4,v6,v8) ++ ++L(tail4): ++ TAIL(v5,v7,v9) ++ ++L(tail5): ++ TAIL(v4,v10,v12) ++ ++L(tail6): ++ TAIL(v5,v11,v13) ++ ++L(tail7): ++ TAIL(v4,v14,v16) ++ ++L(tail8): ++ TAIL(v5,v15,v17) ++ ++END (MEMCMP) ++libc_hidden_builtin_def (memcmp) ++weak_alias (memcmp, bcmp) +diff --git a/sysdeps/powerpc/powerpc64/multiarch/Makefile b/sysdeps/powerpc/powerpc64/multiarch/Makefile +index ac2446aca62cc4ab..ee98417f4a383356 100644 +--- a/sysdeps/powerpc/powerpc64/multiarch/Makefile ++++ b/sysdeps/powerpc/powerpc64/multiarch/Makefile +@@ -32,7 +32,7 @@ sysdep_routines += memcpy-power8-cached memcpy-power7 memcpy-a2 memcpy-power6 \ + strncase-power8 + + ifneq (,$(filter %le,$(config-machine))) +-sysdep_routines += memcpy-power10 memmove-power10 memset-power10 \ ++sysdep_routines += memcmp-power10 memcpy-power10 memmove-power10 memset-power10 \ + rawmemchr-power9 rawmemchr-power10 \ + strcmp-power9 strncmp-power9 strcpy-power9 stpcpy-power9 \ + strlen-power9 strncpy-power9 stpncpy-power9 strlen-power10 +diff --git a/sysdeps/powerpc/powerpc64/multiarch/ifunc-impl-list.c b/sysdeps/powerpc/powerpc64/multiarch/ifunc-impl-list.c +index 127af84b32a8196f..5213abdf87c79c88 100644 +--- a/sysdeps/powerpc/powerpc64/multiarch/ifunc-impl-list.c ++++ b/sysdeps/powerpc/powerpc64/multiarch/ifunc-impl-list.c +@@ -184,6 +184,12 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + + /* Support sysdeps/powerpc/powerpc64/multiarch/memcmp.c. */ + IFUNC_IMPL (i, name, memcmp, ++#ifdef __LITTLE_ENDIAN__ ++ IFUNC_IMPL_ADD (array, i, memcmp, ++ hwcap2 & PPC_FEATURE2_ARCH_3_1 ++ && hwcap & PPC_FEATURE_HAS_VSX, ++ __memcmp_power10) ++#endif + IFUNC_IMPL_ADD (array, i, memcmp, hwcap2 & PPC_FEATURE2_ARCH_2_07, + __memcmp_power8) + IFUNC_IMPL_ADD (array, i, memcmp, hwcap & PPC_FEATURE_HAS_VSX, +diff --git a/sysdeps/powerpc/powerpc64/multiarch/memcmp-power10.S b/sysdeps/powerpc/powerpc64/multiarch/memcmp-power10.S +new file mode 100644 +index 0000000000000000..73a0debd4a811d8e +--- /dev/null ++++ b/sysdeps/powerpc/powerpc64/multiarch/memcmp-power10.S +@@ -0,0 +1,26 @@ ++/* Optimized memcmp implementation for POWER10. ++ Copyright (C) 2017-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 MEMCMP __memcmp_power10 ++ ++#undef libc_hidden_builtin_def ++#define libc_hidden_builtin_def(name) ++#undef weak_alias ++#define weak_alias(name,alias) ++ ++#include +diff --git a/sysdeps/powerpc/powerpc64/multiarch/memcmp.c b/sysdeps/powerpc/powerpc64/multiarch/memcmp.c +index 2c7a083a6560f920..0b8c0c1d8aa3f90a 100644 +--- a/sysdeps/powerpc/powerpc64/multiarch/memcmp.c ++++ b/sysdeps/powerpc/powerpc64/multiarch/memcmp.c +@@ -27,11 +27,17 @@ extern __typeof (memcmp) __memcmp_ppc attribute_hidden; + extern __typeof (memcmp) __memcmp_power4 attribute_hidden; + extern __typeof (memcmp) __memcmp_power7 attribute_hidden; + extern __typeof (memcmp) __memcmp_power8 attribute_hidden; ++extern __typeof (memcmp) __memcmp_power10 attribute_hidden; + # undef memcmp + + /* Avoid DWARF definition DIE on ifunc symbol so that GDB can handle + ifunc symbol properly. */ + libc_ifunc_redirected (__redirect_memcmp, memcmp, ++#ifdef __LITTLE_ENDIAN__ ++ (hwcap2 & PPC_FEATURE2_ARCH_3_1 ++ && hwcap & PPC_FEATURE_HAS_VSX) ++ ? __memcmp_power10 : ++#endif + (hwcap2 & PPC_FEATURE2_ARCH_2_07) + ? __memcmp_power8 : + (hwcap & PPC_FEATURE_HAS_VSX) diff --git a/SOURCES/glibc-rh1983203-2.patch b/SOURCES/glibc-rh1983203-2.patch new file mode 100644 index 0000000..eb06d39 --- /dev/null +++ b/SOURCES/glibc-rh1983203-2.patch @@ -0,0 +1,278 @@ +commit 813c6ec808556553be9d39e900a3fc97ceb32330 +Author: Pedro Franco de Carvalho +Date: Wed Jun 30 12:36:07 2021 -0300 + + powerpc: optimize strcpy/stpcpy for POWER9/10 + + This patch modifies the current POWER9 implementation of strcpy and + stpcpy to optimize it for POWER9/10. + + Since no new POWER10 instructions are used, the original POWER9 strcpy is + modified instead of creating a new implementation for POWER10. This + implementation is based on both the original POWER9 implementation of + strcpy and the preamble of the new POWER10 implementation of strlen. + + The changes also affect stpcpy, which uses the same implementation with + some additional code before returning. + + On POWER9, averaging improvements across the benchmark + inputs (length/source alignment/destination alignment), for an + experiment that ran the benchmark five times, bench-strcpy showed an + improvement of 5.23%, and bench-stpcpy showed an improvement of 6.59%. + + On POWER10, bench-strcpy showed 13.16%, and bench-stpcpy showed 13.59%. + + The changes are: + + 1. Removed the null string optimization. + + Although this results in a few extra cycles for the null string, in + combination with the second change, this resulted in improvements for + for other cases. + + 2. Adapted the preamble from strlen for POWER10. + + This is the part of the function that handles up to the first 16 bytes + of the string. + + 3. Increased number of unrolled iterations in the main loop to 6. + + Reviewed-by: Matheus Castanho + Tested-by: Matheus Castanho + +diff --git a/sysdeps/powerpc/powerpc64/le/power9/strcpy.S b/sysdeps/powerpc/powerpc64/le/power9/strcpy.S +index ce8f50329177fd06..9845a1d4cf0e1e5d 100644 +--- a/sysdeps/powerpc/powerpc64/le/power9/strcpy.S ++++ b/sysdeps/powerpc/powerpc64/le/power9/strcpy.S +@@ -45,91 +45,78 @@ + The implementation can load bytes past a null terminator, but only + up to the next 16B boundary, so it never crosses a page. */ + ++/* Load quadword at addr+offset to vreg, check for null bytes, ++ and branch to label if any are found. */ ++#define CHECK16(vreg,offset,addr,label) \ ++ lxv vreg+32,offset(addr); \ ++ vcmpequb. v6,vreg,v18; \ ++ bne cr6,L(label); ++ + .machine power9 + ENTRY_TOCLESS (FUNC_NAME, 4) + CALL_MCOUNT 2 + +- /* NULL string optimisation */ +- lbz r0,0(r4) +- stb r0,0(r3) +- cmpwi r0,0 +- beqlr +- +- addi r4,r4,1 +- addi r11,r3,1 +- + vspltisb v18,0 /* Zeroes in v18 */ ++ vspltisb v19,-1 /* 0xFF bytes in v19 */ + +- neg r5,r4 +- rldicl r9,r5,0,60 /* How many bytes to get source 16B aligned? */ ++ /* Next 16B-aligned address. Prepare address for L(loop). */ ++ addi r5,r4,16 ++ clrrdi r5,r5,4 ++ subf r8,r4,r5 ++ add r11,r3,r8 + +- /* Get source 16B aligned */ ++ /* Align data and fill bytes not loaded with non matching char. */ + lvx v0,0,r4 + lvsr v1,0,r4 +- vperm v0,v18,v0,v1 +- +- vcmpequb v6,v0,v18 /* 0xff if byte is NULL, 0x00 otherwise */ +- vctzlsbb r7,v6 /* Number of trailing zeroes */ +- addi r8,r7,1 /* Add null terminator */ ++ vperm v0,v19,v0,v1 + +- /* r8 = bytes including null +- r9 = bytes to get source 16B aligned +- if r8 > r9 +- no null, copy r9 bytes +- else +- there is a null, copy r8 bytes and return. */ +- cmpd r8,r9 +- bgt L(no_null) ++ vcmpequb. v6,v0,v18 /* 0xff if byte is NULL, 0x00 otherwise */ ++ beq cr6,L(no_null) + +- sldi r10,r8,56 /* stxvl wants size in top 8 bits */ +- stxvl 32+v0,r11,r10 /* Partial store */ ++ /* There's a null byte. */ ++ vctzlsbb r8,v6 /* Number of trailing zeroes */ ++ addi r9,r8,1 /* Add null byte. */ ++ sldi r10,r9,56 /* stxvl wants size in top 8 bits. */ ++ stxvl 32+v0,r3,r10 /* Partial store */ + + #ifdef USE_AS_STPCPY + /* stpcpy returns the dest address plus the size not counting the + final '\0'. */ +- add r3,r11,r7 ++ add r3,r3,r8 + #endif + blr + + L(no_null): +- sldi r10,r9,56 /* stxvl wants size in top 8 bits */ +- stxvl 32+v0,r11,r10 /* Partial store */ +- +- add r4,r4,r9 +- add r11,r11,r9 ++ sldi r10,r8,56 /* stxvl wants size in top 8 bits */ ++ stxvl 32+v0,r3,r10 /* Partial store */ + ++ .p2align 4 + L(loop): +- lxv 32+v0,0(r4) +- vcmpequb. v6,v0,v18 /* Any zero bytes? */ +- bne cr6,L(tail1) +- +- lxv 32+v1,16(r4) +- vcmpequb. v6,v1,v18 /* Any zero bytes? */ +- bne cr6,L(tail2) +- +- lxv 32+v2,32(r4) +- vcmpequb. v6,v2,v18 /* Any zero bytes? */ +- bne cr6,L(tail3) +- +- lxv 32+v3,48(r4) +- vcmpequb. v6,v3,v18 /* Any zero bytes? */ +- bne cr6,L(tail4) ++ CHECK16(v0,0,r5,tail1) ++ CHECK16(v1,16,r5,tail2) ++ CHECK16(v2,32,r5,tail3) ++ CHECK16(v3,48,r5,tail4) ++ CHECK16(v4,64,r5,tail5) ++ CHECK16(v5,80,r5,tail6) + + stxv 32+v0,0(r11) + stxv 32+v1,16(r11) + stxv 32+v2,32(r11) + stxv 32+v3,48(r11) ++ stxv 32+v4,64(r11) ++ stxv 32+v5,80(r11) + +- addi r4,r4,64 +- addi r11,r11,64 ++ addi r5,r5,96 ++ addi r11,r11,96 + + b L(loop) + ++ .p2align 4 + L(tail1): +- vctzlsbb r8,v6 +- addi r9,r8,1 ++ vctzlsbb r8,v6 /* Number of trailing zeroes */ ++ addi r9,r8,1 /* Add null terminator */ + sldi r9,r9,56 /* stxvl wants size in top 8 bits */ +- stxvl 32+v0,r11,r9 ++ stxvl 32+v0,r11,r9 /* Partial store */ + #ifdef USE_AS_STPCPY + /* stpcpy returns the dest address plus the size not counting the + final '\0'. */ +@@ -137,50 +124,81 @@ L(tail1): + #endif + blr + ++ .p2align 4 + L(tail2): + stxv 32+v0,0(r11) +- vctzlsbb r8,v6 /* Number of trailing zeroes */ +- addi r9,r8,1 /* Add null terminator */ +- sldi r10,r9,56 /* stxvl wants size in top 8 bits */ ++ vctzlsbb r8,v6 ++ addi r9,r8,1 ++ sldi r9,r9,56 + addi r11,r11,16 +- stxvl 32+v1,r11,r10 /* Partial store */ ++ stxvl 32+v1,r11,r9 + #ifdef USE_AS_STPCPY +- /* stpcpy returns the dest address plus the size not counting the +- final '\0'. */ + add r3,r11,r8 + #endif + blr + ++ .p2align 4 + L(tail3): + stxv 32+v0,0(r11) + stxv 32+v1,16(r11) +- vctzlsbb r8,v6 /* Number of trailing zeroes */ +- addi r9,r8,1 /* Add null terminator */ +- sldi r10,r9,56 /* stxvl wants size in top 8 bits */ ++ vctzlsbb r8,v6 ++ addi r9,r8,1 ++ sldi r9,r9,56 + addi r11,r11,32 +- stxvl 32+v2,r11,r10 /* Partial store */ ++ stxvl 32+v2,r11,r9 + #ifdef USE_AS_STPCPY +- /* stpcpy returns the dest address plus the size not counting the +- final '\0'. */ + add r3,r11,r8 + #endif + blr + ++ .p2align 4 + L(tail4): + stxv 32+v0,0(r11) + stxv 32+v1,16(r11) + stxv 32+v2,32(r11) +- vctzlsbb r8,v6 /* Number of trailing zeroes */ +- addi r9,r8,1 /* Add null terminator */ +- sldi r10,r9,56 /* stxvl wants size in top 8 bits */ ++ vctzlsbb r8,v6 ++ addi r9,r8,1 ++ sldi r9,r9,56 + addi r11,r11,48 +- stxvl 32+v3,r11,r10 /* Partial store */ ++ stxvl 32+v3,r11,r9 + #ifdef USE_AS_STPCPY +- /* stpcpy returns the dest address plus the size not counting the +- final '\0'. */ + add r3,r11,r8 + #endif + blr ++ ++ .p2align 4 ++L(tail5): ++ stxv 32+v0,0(r11) ++ stxv 32+v1,16(r11) ++ stxv 32+v2,32(r11) ++ stxv 32+v3,48(r11) ++ vctzlsbb r8,v6 ++ addi r9,r8,1 ++ sldi r9,r9,56 ++ addi r11,r11,64 ++ stxvl 32+v4,r11,r9 ++#ifdef USE_AS_STPCPY ++ add r3,r11,r8 ++#endif ++ blr ++ ++ .p2align 4 ++L(tail6): ++ stxv 32+v0,0(r11) ++ stxv 32+v1,16(r11) ++ stxv 32+v2,32(r11) ++ stxv 32+v3,48(r11) ++ stxv 32+v4,64(r11) ++ vctzlsbb r8,v6 ++ addi r9,r8,1 ++ sldi r9,r9,56 ++ addi r11,r11,80 ++ stxvl 32+v5,r11,r9 ++#ifdef USE_AS_STPCPY ++ add r3,r11,r8 ++#endif ++ blr ++ + END (FUNC_NAME) + #ifndef USE_AS_STPCPY + libc_hidden_builtin_def (strcpy) diff --git a/SOURCES/glibc-rh1984802-1.patch b/SOURCES/glibc-rh1984802-1.patch new file mode 100644 index 0000000..47fcc60 --- /dev/null +++ b/SOURCES/glibc-rh1984802-1.patch @@ -0,0 +1,50 @@ +From 756c306502498f999fdd494477b9cea1b45e4faf Mon Sep 17 00:00:00 2001 +From: Stefan Liebler +Date: Fri, 21 Aug 2020 11:23:17 +0200 +Subject: [PATCH] S390: Sync HWCAP names with kernel by adding aliases [BZ + #25971] + +Unfortunately some HWCAP names like HWCAP_S390_VX differs between +kernel (see /arch/s390/include/asm/elf.h) and glibc. + +Therefore, those HWCAP names from kernel are now introduced as alias +--- + sysdeps/s390/dl-procinfo.h | 3 +++ + sysdeps/unix/sysv/linux/s390/bits/hwcap.h | 3 +++ + 2 files changed, 6 insertions(+) + +diff --git a/sysdeps/s390/dl-procinfo.h b/sysdeps/s390/dl-procinfo.h +index 0db4bc39c7..08eee109f7 100644 +--- a/sysdeps/s390/dl-procinfo.h ++++ b/sysdeps/s390/dl-procinfo.h +@@ -51,8 +51,11 @@ enum + HWCAP_S390_HIGH_GPRS = 1 << 9, + HWCAP_S390_TE = 1 << 10, + HWCAP_S390_VX = 1 << 11, ++ HWCAP_S390_VXRS = HWCAP_S390_VX, + HWCAP_S390_VXD = 1 << 12, ++ HWCAP_S390_VXRS_BCD = HWCAP_S390_VXD, + HWCAP_S390_VXE = 1 << 13, ++ HWCAP_S390_VXRS_EXT = HWCAP_S390_VXE, + HWCAP_S390_GS = 1 << 14, + HWCAP_S390_VXRS_EXT2 = 1 << 15, + HWCAP_S390_VXRS_PDE = 1 << 16, +diff --git a/sysdeps/unix/sysv/linux/s390/bits/hwcap.h b/sysdeps/unix/sysv/linux/s390/bits/hwcap.h +index 6adbec018b..f2998ff131 100644 +--- a/sysdeps/unix/sysv/linux/s390/bits/hwcap.h ++++ b/sysdeps/unix/sysv/linux/s390/bits/hwcap.h +@@ -36,8 +36,11 @@ + #define HWCAP_S390_HIGH_GPRS 512 + #define HWCAP_S390_TE 1024 + #define HWCAP_S390_VX 2048 ++#define HWCAP_S390_VXRS HWCAP_S390_VX + #define HWCAP_S390_VXD 4096 ++#define HWCAP_S390_VXRS_BCD HWCAP_S390_VXD + #define HWCAP_S390_VXE 8192 ++#define HWCAP_S390_VXRS_EXT HWCAP_S390_VXE + #define HWCAP_S390_GS 16384 + #define HWCAP_S390_VXRS_EXT2 32768 + #define HWCAP_S390_VXRS_PDE 65536 +-- +2.31.1 + diff --git a/SOURCES/glibc-rh1984802-2.patch b/SOURCES/glibc-rh1984802-2.patch new file mode 100644 index 0000000..4d7d4b5 --- /dev/null +++ b/SOURCES/glibc-rh1984802-2.patch @@ -0,0 +1,67 @@ +From 25251c0707fe34f30a27381a5fabc35435a96621 Mon Sep 17 00:00:00 2001 +From: Stefan Liebler +Date: Tue, 16 Feb 2021 16:18:56 +0100 +Subject: [PATCH] S390: Add new hwcap values. + +The new hwcap values indicate support for arch14 architecture. +--- + sysdeps/s390/dl-procinfo.c | 5 +++-- + sysdeps/s390/dl-procinfo.h | 4 +++- + sysdeps/unix/sysv/linux/s390/bits/hwcap.h | 2 ++ + 3 files changed, 8 insertions(+), 3 deletions(-) + +diff --git a/sysdeps/s390/dl-procinfo.c b/sysdeps/s390/dl-procinfo.c +index 0c334a2551..c174e27b35 100644 +--- a/sysdeps/s390/dl-procinfo.c ++++ b/sysdeps/s390/dl-procinfo.c +@@ -46,12 +46,13 @@ + #if !defined PROCINFO_DECL && defined SHARED + ._dl_s390_cap_flags + #else +-PROCINFO_CLASS const char _dl_s390_cap_flags[19][9] ++PROCINFO_CLASS const char _dl_s390_cap_flags[21][9] + #endif + #ifndef PROCINFO_DECL + = { + "esan3", "zarch", "stfle", "msa", "ldisp", "eimm", "dfp", "edat", "etf3eh", +- "highgprs", "te", "vx", "vxd", "vxe", "gs", "vxe2", "vxp", "sort", "dflt" ++ "highgprs", "te", "vx", "vxd", "vxe", "gs", "vxe2", "vxp", "sort", "dflt", ++ "vxp2", "nnpa" + } + #endif + #if !defined SHARED || defined PROCINFO_DECL +diff --git a/sysdeps/s390/dl-procinfo.h b/sysdeps/s390/dl-procinfo.h +index 9e1a8c7ba9..2d9c305808 100644 +--- a/sysdeps/s390/dl-procinfo.h ++++ b/sysdeps/s390/dl-procinfo.h +@@ -21,7 +21,7 @@ + #define _DL_PROCINFO_H 1 + #include + +-#define _DL_HWCAP_COUNT 19 ++#define _DL_HWCAP_COUNT 21 + + #define _DL_PLATFORMS_COUNT 10 + +@@ -61,6 +61,8 @@ enum + HWCAP_S390_VXRS_PDE = 1 << 16, + HWCAP_S390_SORT = 1 << 17, + HWCAP_S390_DFLT = 1 << 18, ++ HWCAP_S390_VXRS_PDE2 = 1 << 19, ++ HWCAP_S390_NNPA = 1 << 20, + }; + + #define HWCAP_IMPORTANT (HWCAP_S390_ZARCH | HWCAP_S390_LDISP \ +diff --git a/sysdeps/unix/sysv/linux/s390/bits/hwcap.h b/sysdeps/unix/sysv/linux/s390/bits/hwcap.h +index 696616e779..e9bd3684db 100644 +--- a/sysdeps/unix/sysv/linux/s390/bits/hwcap.h ++++ b/sysdeps/unix/sysv/linux/s390/bits/hwcap.h +@@ -46,3 +46,5 @@ + #define HWCAP_S390_VXRS_PDE 65536 + #define HWCAP_S390_SORT 131072 + #define HWCAP_S390_DFLT 262144 ++#define HWCAP_S390_VXRS_PDE2 524288 ++#define HWCAP_S390_NNPA 1048576 +-- +2.31.1 + diff --git a/SOURCES/glibc-rh1984802-3.patch b/SOURCES/glibc-rh1984802-3.patch new file mode 100644 index 0000000..c0412b4 --- /dev/null +++ b/SOURCES/glibc-rh1984802-3.patch @@ -0,0 +1,88 @@ +From f2e06656d04a9fcb0603802a4f8ce7aa3a1f055e Mon Sep 17 00:00:00 2001 +From: Stefan Liebler +Date: Tue, 5 Oct 2021 16:14:10 +0200 +Subject: [PATCH] S390: Add PCI_MIO and SIE HWCAPs + +Both new HWCAPs were introduced in these kernel commits: +- 7e8403ecaf884f307b627f3c371475913dd29292 + "s390: add HWCAP_S390_PCI_MIO to ELF hwcaps" +- 7e82523f2583e9813e4109df3656707162541297 + "s390/hwcaps: make sie capability regular hwcap" + +Also note that the kernel commit 511ad531afd4090625def4d9aba1f5227bd44b8e +"s390/hwcaps: shorten HWCAP defines" has shortened the prefix of the macros +from "HWCAP_S390_" to "HWCAP_". For compatibility reasons, we do not +change the prefix in public glibc header file. +--- + sysdeps/s390/dl-procinfo.c | 4 ++-- + sysdeps/s390/dl-procinfo.h | 4 +++- + sysdeps/unix/sysv/linux/s390/bits/hwcap.h | 7 +++++++ + 3 files changed, 12 insertions(+), 3 deletions(-) + +diff --git a/sysdeps/s390/dl-procinfo.c b/sysdeps/s390/dl-procinfo.c +index 7314c31b15..97be34fe9d 100644 +--- a/sysdeps/s390/dl-procinfo.c ++++ b/sysdeps/s390/dl-procinfo.c +@@ -45,13 +45,13 @@ + #if !defined PROCINFO_DECL && defined SHARED + ._dl_s390_cap_flags + #else +-PROCINFO_CLASS const char _dl_s390_cap_flags[21][9] ++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" ++ "vxp2", "nnpa", "pcimio", "sie" + } + #endif + #if !defined SHARED || defined PROCINFO_DECL +diff --git a/sysdeps/s390/dl-procinfo.h b/sysdeps/s390/dl-procinfo.h +index 2502dd2604..d9a3b264ff 100644 +--- a/sysdeps/s390/dl-procinfo.h ++++ b/sysdeps/s390/dl-procinfo.h +@@ -20,7 +20,7 @@ + #define _DL_PROCINFO_H 1 + #include + +-#define _DL_HWCAP_COUNT 21 ++#define _DL_HWCAP_COUNT 23 + + #define _DL_PLATFORMS_COUNT 10 + +@@ -62,6 +62,8 @@ enum + HWCAP_S390_DFLT = 1 << 18, + HWCAP_S390_VXRS_PDE2 = 1 << 19, + HWCAP_S390_NNPA = 1 << 20, ++ HWCAP_S390_PCI_MIO = 1 << 21, ++ HWCAP_S390_SIE = 1 << 22, + }; + + #define HWCAP_IMPORTANT (HWCAP_S390_ZARCH | HWCAP_S390_LDISP \ +diff --git a/sysdeps/unix/sysv/linux/s390/bits/hwcap.h b/sysdeps/unix/sysv/linux/s390/bits/hwcap.h +index e9bd3684db..00e73a3e3b 100644 +--- a/sysdeps/unix/sysv/linux/s390/bits/hwcap.h ++++ b/sysdeps/unix/sysv/linux/s390/bits/hwcap.h +@@ -22,6 +22,11 @@ + + /* + * The following must match the kernels asm/elf.h. ++ * Note: The kernel commit 511ad531afd4090625def4d9aba1f5227bd44b8e ++ * "s390/hwcaps: shorten HWCAP defines" has shortened the prefix of the macros ++ * from "HWCAP_S390_" to "HWCAP_". For compatibility reasons, we do not ++ * change the prefix in public glibc header file. ++ * + * Note that these are *not* the same as the STORE FACILITY LIST bits. + */ + #define HWCAP_S390_ESAN3 1 +@@ -48,3 +53,5 @@ + #define HWCAP_S390_DFLT 262144 + #define HWCAP_S390_VXRS_PDE2 524288 + #define HWCAP_S390_NNPA 1048576 ++#define HWCAP_S390_PCI_MIO 2097152 ++#define HWCAP_S390_SIE 4194304 +-- +2.31.1 + diff --git a/SOURCES/glibc-rh1991001-1.patch b/SOURCES/glibc-rh1991001-1.patch new file mode 100644 index 0000000..6d09fa0 --- /dev/null +++ b/SOURCES/glibc-rh1991001-1.patch @@ -0,0 +1,30 @@ +commit ad78d702757a189b1fa552d607e8aaa22252a45f +Author: Florian Weimer +Date: Tue May 12 19:06:18 2020 +0200 + + elf: Remove redundant add_to_global_resize_failure call from dl_open_args + + The second call does not do anything because the data structures have + already been resized by the call that comes before the demarcation + point. Fixes commit a509eb117fac1d764b15eba64993f4bdb63d7f3c + ("Avoid late dlopen failure due to scope, TLS slotinfo updates + [BZ #25112]"). + + Reviewed-by: Carlos O'Donell + +diff --git a/elf/dl-open.c b/elf/dl-open.c +index 3d49a84596e99bf6..b052bb0bc2cd17aa 100644 +--- a/elf/dl-open.c ++++ b/elf/dl-open.c +@@ -769,11 +769,6 @@ dl_open_worker (void *a) + DL_STATIC_INIT (new); + #endif + +- /* Perform the necessary allocations for adding new global objects +- to the global scope below, via add_to_global_update. */ +- if (mode & RTLD_GLOBAL) +- add_to_global_resize (new); +- + /* Run the initializer functions of new objects. Temporarily + disable the exception handler, so that lazy binding failures are + fatal. */ diff --git a/SOURCES/glibc-rh1991001-10.patch b/SOURCES/glibc-rh1991001-10.patch new file mode 100644 index 0000000..7263cc7 --- /dev/null +++ b/SOURCES/glibc-rh1991001-10.patch @@ -0,0 +1,23 @@ +commit 52290d8c04569615fb011ee286d52dc5147afbd7 +Author: Szabolcs Nagy +Date: Thu Apr 15 09:57:10 2021 +0100 + + elf: Fix missing include in test case [BZ #27136] + + Broken test was introduced in + + commit 8f85075a2e9c26ff7486d4bbaf358999807d215c + elf: Add a DTV setup test [BZ #27136] + +diff --git a/elf/tst-tls20.c b/elf/tst-tls20.c +index ac5f8c8d39b66dd6..9977ec803208b9c8 100644 +--- a/elf/tst-tls20.c ++++ b/elf/tst-tls20.c +@@ -21,6 +21,7 @@ + #include + #include + #include ++#include + #include + #include + diff --git a/SOURCES/glibc-rh1991001-11.patch b/SOURCES/glibc-rh1991001-11.patch new file mode 100644 index 0000000..a704d26 --- /dev/null +++ b/SOURCES/glibc-rh1991001-11.patch @@ -0,0 +1,160 @@ +commit 2208066603a136f95cfb815ca9281262e6465784 +Author: Szabolcs Nagy +Date: Thu Feb 11 13:24:47 2021 +0000 + + elf: Remove lazy tlsdesc relocation related code + + Remove generic tlsdesc code related to lazy tlsdesc processing since + lazy tlsdesc relocation is no longer supported. This includes removing + GL(dl_load_lock) from _dl_make_tlsdesc_dynamic which is only called at + load time when that lock is already held. + + Added a documentation comment too. + + Reviewed-by: Adhemerval Zanella + +diff --git a/elf/tlsdeschtab.h b/elf/tlsdeschtab.h +index fea9eefe72edcd6b..c20857e5b4264f00 100644 +--- a/elf/tlsdeschtab.h ++++ b/elf/tlsdeschtab.h +@@ -78,6 +78,10 @@ map_generation (struct link_map *map) + return GL(dl_tls_generation) + 1; + } + ++/* Returns the data pointer for a given map and tls offset that is used ++ to fill in one of the GOT entries referenced by a TLSDESC relocation ++ when using dynamic TLS. This requires allocation, returns NULL on ++ allocation failure. */ + void * + _dl_make_tlsdesc_dynamic (struct link_map *map, size_t ti_offset) + { +@@ -85,18 +89,12 @@ _dl_make_tlsdesc_dynamic (struct link_map *map, size_t ti_offset) + void **entry; + struct tlsdesc_dynamic_arg *td, test; + +- /* FIXME: We could use a per-map lock here, but is it worth it? */ +- __rtld_lock_lock_recursive (GL(dl_load_lock)); +- + ht = map->l_mach.tlsdesc_table; + if (! ht) + { + ht = htab_create (); + if (! ht) +- { +- __rtld_lock_unlock_recursive (GL(dl_load_lock)); +- return 0; +- } ++ return 0; + map->l_mach.tlsdesc_table = ht; + } + +@@ -104,15 +102,11 @@ _dl_make_tlsdesc_dynamic (struct link_map *map, size_t ti_offset) + test.tlsinfo.ti_offset = ti_offset; + entry = htab_find_slot (ht, &test, 1, hash_tlsdesc, eq_tlsdesc); + if (! entry) +- { +- __rtld_lock_unlock_recursive (GL(dl_load_lock)); +- return 0; +- } ++ return 0; + + if (*entry) + { + td = *entry; +- __rtld_lock_unlock_recursive (GL(dl_load_lock)); + return td; + } + +@@ -122,44 +116,9 @@ _dl_make_tlsdesc_dynamic (struct link_map *map, size_t ti_offset) + thread. */ + td->gen_count = map_generation (map); + td->tlsinfo = test.tlsinfo; +- +- __rtld_lock_unlock_recursive (GL(dl_load_lock)); + return td; + } + + # endif /* SHARED */ + +-/* The idea of the following two functions is to stop multiple threads +- from attempting to resolve the same TLS descriptor without busy +- waiting. Ideally, we should be able to release the lock right +- after changing td->entry, and then using say a condition variable +- or a futex wake to wake up any waiting threads, but let's try to +- avoid introducing such dependencies. */ +- +-static int +-__attribute__ ((unused)) +-_dl_tlsdesc_resolve_early_return_p (struct tlsdesc volatile *td, void *caller) +-{ +- if (caller != atomic_load_relaxed (&td->entry)) +- return 1; +- +- __rtld_lock_lock_recursive (GL(dl_load_lock)); +- if (caller != atomic_load_relaxed (&td->entry)) +- { +- __rtld_lock_unlock_recursive (GL(dl_load_lock)); +- return 1; +- } +- +- atomic_store_relaxed (&td->entry, _dl_tlsdesc_resolve_hold); +- +- return 0; +-} +- +-static void +-__attribute__ ((unused)) +-_dl_tlsdesc_wake_up_held_fixups (void) +-{ +- __rtld_lock_unlock_recursive (GL(dl_load_lock)); +-} +- + #endif +diff --git a/sysdeps/aarch64/tlsdesc.c b/sysdeps/aarch64/tlsdesc.c +index 357465f23d76e2bd..1ead73ab8250e29c 100644 +--- a/sysdeps/aarch64/tlsdesc.c ++++ b/sysdeps/aarch64/tlsdesc.c +@@ -22,7 +22,6 @@ + #include + #include + #include +-#define _dl_tlsdesc_resolve_hold 0 + #include + + /* Unmap the dynamic object, but also release its TLS descriptor table +diff --git a/sysdeps/arm/tlsdesc.c b/sysdeps/arm/tlsdesc.c +index d142d7a2c91e9adb..b78e3f65785bf587 100644 +--- a/sysdeps/arm/tlsdesc.c ++++ b/sysdeps/arm/tlsdesc.c +@@ -20,7 +20,6 @@ + #include + #include + #include +-#define _dl_tlsdesc_resolve_hold 0 + #include + + /* Unmap the dynamic object, but also release its TLS descriptor table +diff --git a/sysdeps/i386/tlsdesc.c b/sysdeps/i386/tlsdesc.c +index 1b4227c8381e1b3d..c242ffce726d50e4 100644 +--- a/sysdeps/i386/tlsdesc.c ++++ b/sysdeps/i386/tlsdesc.c +@@ -20,7 +20,6 @@ + #include + #include + #include +-#define _dl_tlsdesc_resolve_hold 0 + #include + + /* Unmap the dynamic object, but also release its TLS descriptor table +diff --git a/sysdeps/x86_64/tlsdesc.c b/sysdeps/x86_64/tlsdesc.c +index 61a19ae26944c84f..a9325827d0e5e31b 100644 +--- a/sysdeps/x86_64/tlsdesc.c ++++ b/sysdeps/x86_64/tlsdesc.c +@@ -20,7 +20,6 @@ + #include + #include + #include +-#define _dl_tlsdesc_resolve_hold 0 + #include + + /* Unmap the dynamic object, but also release its TLS descriptor table diff --git a/SOURCES/glibc-rh1991001-12.patch b/SOURCES/glibc-rh1991001-12.patch new file mode 100644 index 0000000..67f9bab --- /dev/null +++ b/SOURCES/glibc-rh1991001-12.patch @@ -0,0 +1,182 @@ +commit 1387ad6225c2222f027790e3f460e31aa5dd2c54 +Author: Szabolcs Nagy +Date: Wed Dec 30 19:19:37 2020 +0000 + + elf: Fix data races in pthread_create and TLS access [BZ #19329] + + DTV setup at thread creation (_dl_allocate_tls_init) is changed + to take the dlopen lock, GL(dl_load_lock). Avoiding data races + here without locks would require design changes: the map that is + accessed for static TLS initialization here may be concurrently + freed by dlclose. That use after free may be solved by only + locking around static TLS setup or by ensuring dlclose does not + free modules with static TLS, however currently every link map + with TLS has to be accessed at least to see if it needs static + TLS. And even if that's solved, still a lot of atomics would be + needed to synchronize DTV related globals without a lock. So fix + both bug 19329 and bug 27111 with a lock that prevents DTV setup + running concurrently with dlopen or dlclose. + + _dl_update_slotinfo at TLS access still does not use any locks + so CONCURRENCY NOTES are added to explain the synchronization. + The early exit from the slotinfo walk when max_modid is reached + is not strictly necessary, but does not hurt either. + + An incorrect acquire load was removed from _dl_resize_dtv: it + did not synchronize with any release store or fence and + synchronization is now handled separately at thread creation + and TLS access time. + + There are still a number of racy read accesses to globals that + will be changed to relaxed MO atomics in a followup patch. This + should not introduce regressions compared to existing behaviour + and avoid cluttering the main part of the fix. + + Not all TLS access related data races got fixed here: there are + additional races at lazy tlsdesc relocations see bug 27137. + + Reviewed-by: Adhemerval Zanella + +diff --git a/elf/dl-tls.c b/elf/dl-tls.c +index 15ed01d795a8627a..da83cd6ae2ee6504 100644 +--- a/elf/dl-tls.c ++++ b/elf/dl-tls.c +@@ -471,14 +471,11 @@ extern dtv_t _dl_static_dtv[]; + #endif + + static dtv_t * +-_dl_resize_dtv (dtv_t *dtv) ++_dl_resize_dtv (dtv_t *dtv, size_t max_modid) + { + /* Resize the dtv. */ + dtv_t *newp; +- /* Load GL(dl_tls_max_dtv_idx) atomically since it may be written to by +- other threads concurrently. */ +- size_t newsize +- = atomic_load_acquire (&GL(dl_tls_max_dtv_idx)) + DTV_SURPLUS; ++ size_t newsize = max_modid + DTV_SURPLUS; + size_t oldsize = dtv[-1].counter; + + if (dtv == GL(dl_initial_dtv)) +@@ -524,11 +521,14 @@ _dl_allocate_tls_init (void *result) + size_t total = 0; + size_t maxgen = 0; + ++ /* Protects global dynamic TLS related state. */ ++ __rtld_lock_lock_recursive (GL(dl_load_lock)); ++ + /* Check if the current dtv is big enough. */ + if (dtv[-1].counter < GL(dl_tls_max_dtv_idx)) + { + /* Resize the dtv. */ +- dtv = _dl_resize_dtv (dtv); ++ dtv = _dl_resize_dtv (dtv, GL(dl_tls_max_dtv_idx)); + + /* Install this new dtv in the thread data structures. */ + INSTALL_DTV (result, &dtv[-1]); +@@ -596,6 +596,7 @@ _dl_allocate_tls_init (void *result) + listp = listp->next; + assert (listp != NULL); + } ++ __rtld_lock_unlock_recursive (GL(dl_load_lock)); + + /* The DTV version is up-to-date now. */ + dtv[0].counter = maxgen; +@@ -730,12 +731,29 @@ _dl_update_slotinfo (unsigned long int req_modid) + + if (dtv[0].counter < listp->slotinfo[idx].gen) + { +- /* The generation counter for the slot is higher than what the +- current dtv implements. We have to update the whole dtv but +- only those entries with a generation counter <= the one for +- the entry we need. */ ++ /* CONCURRENCY NOTES: ++ ++ Here the dtv needs to be updated to new_gen generation count. ++ ++ This code may be called during TLS access when GL(dl_load_lock) ++ is not held. In that case the user code has to synchronize with ++ dlopen and dlclose calls of relevant modules. A module m is ++ relevant if the generation of m <= new_gen and dlclose of m is ++ synchronized: a memory access here happens after the dlopen and ++ before the dlclose of relevant modules. The dtv entries for ++ relevant modules need to be updated, other entries can be ++ arbitrary. ++ ++ This e.g. means that the first part of the slotinfo list can be ++ accessed race free, but the tail may be concurrently extended. ++ Similarly relevant slotinfo entries can be read race free, but ++ other entries are racy. However updating a non-relevant dtv ++ entry does not affect correctness. For a relevant module m, ++ max_modid >= modid of m. */ + size_t new_gen = listp->slotinfo[idx].gen; + size_t total = 0; ++ size_t max_modid = atomic_load_relaxed (&GL(dl_tls_max_dtv_idx)); ++ assert (max_modid >= req_modid); + + /* We have to look through the entire dtv slotinfo list. */ + listp = GL(dl_tls_dtv_slotinfo_list); +@@ -745,12 +763,14 @@ _dl_update_slotinfo (unsigned long int req_modid) + { + size_t modid = total + cnt; + ++ /* Later entries are not relevant. */ ++ if (modid > max_modid) ++ break; ++ + size_t gen = listp->slotinfo[cnt].gen; + + if (gen > new_gen) +- /* This is a slot for a generation younger than the +- one we are handling now. It might be incompletely +- set up so ignore it. */ ++ /* Not relevant. */ + continue; + + /* If the entry is older than the current dtv layout we +@@ -767,7 +787,7 @@ _dl_update_slotinfo (unsigned long int req_modid) + continue; + + /* Resize the dtv. */ +- dtv = _dl_resize_dtv (dtv); ++ dtv = _dl_resize_dtv (dtv, max_modid); + + assert (modid <= dtv[-1].counter); + +@@ -789,8 +809,17 @@ _dl_update_slotinfo (unsigned long int req_modid) + } + + total += listp->len; ++ if (total > max_modid) ++ break; ++ ++ /* Synchronize with _dl_add_to_slotinfo. Ideally this would ++ be consume MO since we only need to order the accesses to ++ the next node after the read of the address and on most ++ hardware (other than alpha) a normal load would do that ++ because of the address dependency. */ ++ listp = atomic_load_acquire (&listp->next); + } +- while ((listp = listp->next) != NULL); ++ while (listp != NULL); + + /* This will be the new maximum generation counter. */ + dtv[0].counter = new_gen; +@@ -982,7 +1011,7 @@ _dl_add_to_slotinfo (struct link_map *l, bool do_add) + the first slot. */ + assert (idx == 0); + +- listp = prevp->next = (struct dtv_slotinfo_list *) ++ listp = (struct dtv_slotinfo_list *) + malloc (sizeof (struct dtv_slotinfo_list) + + TLS_SLOTINFO_SURPLUS * sizeof (struct dtv_slotinfo)); + if (listp == NULL) +@@ -996,6 +1025,8 @@ cannot create TLS data structures")); + listp->next = NULL; + memset (listp->slotinfo, '\0', + TLS_SLOTINFO_SURPLUS * sizeof (struct dtv_slotinfo)); ++ /* Synchronize with _dl_update_slotinfo. */ ++ atomic_store_release (&prevp->next, listp); + } + + /* Add the information into the slotinfo data structure. */ diff --git a/SOURCES/glibc-rh1991001-13.patch b/SOURCES/glibc-rh1991001-13.patch new file mode 100644 index 0000000..524eb3c --- /dev/null +++ b/SOURCES/glibc-rh1991001-13.patch @@ -0,0 +1,193 @@ +commit f4f8f4d4e0f92488431b268c8cd9555730b9afe9 +Author: Szabolcs Nagy +Date: Wed Dec 30 19:19:37 2020 +0000 + + elf: Use relaxed atomics for racy accesses [BZ #19329] + + This is a follow up patch to the fix for bug 19329. This adds relaxed + MO atomics to accesses that were previously data races but are now + race conditions, and where relaxed MO is sufficient. + + The race conditions all follow the pattern that the write is behind the + dlopen lock, but a read can happen concurrently (e.g. during tls access) + without holding the lock. For slotinfo entries the read value only + matters if it reads from a synchronized write in dlopen or dlclose, + otherwise the related dtv entry is not valid to access so it is fine + to leave it in an inconsistent state. The same applies for + GL(dl_tls_max_dtv_idx) and GL(dl_tls_generation), but there the + algorithm relies on the fact that the read of the last synchronized + write is an increasing value. + + Reviewed-by: Adhemerval Zanella + +diff --git a/elf/dl-close.c b/elf/dl-close.c +index 1ece0ae1dd062d1e..7d2dc2272cd643f5 100644 +--- a/elf/dl-close.c ++++ b/elf/dl-close.c +@@ -79,9 +79,10 @@ remove_slotinfo (size_t idx, struct dtv_slotinfo_list *listp, size_t disp, + { + assert (old_map->l_tls_modid == idx); + +- /* Mark the entry as unused. */ +- listp->slotinfo[idx - disp].gen = GL(dl_tls_generation) + 1; +- listp->slotinfo[idx - disp].map = NULL; ++ /* Mark the entry as unused. These can be read concurrently. */ ++ atomic_store_relaxed (&listp->slotinfo[idx - disp].gen, ++ GL(dl_tls_generation) + 1); ++ atomic_store_relaxed (&listp->slotinfo[idx - disp].map, NULL); + } + + /* If this is not the last currently used entry no need to look +@@ -96,8 +97,8 @@ remove_slotinfo (size_t idx, struct dtv_slotinfo_list *listp, size_t disp, + + if (listp->slotinfo[idx - disp].map != NULL) + { +- /* Found a new last used index. */ +- GL(dl_tls_max_dtv_idx) = idx; ++ /* Found a new last used index. This can be read concurrently. */ ++ atomic_store_relaxed (&GL(dl_tls_max_dtv_idx), idx); + return true; + } + } +@@ -571,7 +572,9 @@ _dl_close_worker (struct link_map *map, bool force) + GL(dl_tls_dtv_slotinfo_list), 0, + imap->l_init_called)) + /* All dynamically loaded modules with TLS are unloaded. */ +- GL(dl_tls_max_dtv_idx) = GL(dl_tls_static_nelem); ++ /* Can be read concurrently. */ ++ atomic_store_relaxed (&GL(dl_tls_max_dtv_idx), ++ GL(dl_tls_static_nelem)); + + if (imap->l_tls_offset != NO_TLS_OFFSET + && imap->l_tls_offset != FORCED_DYNAMIC_TLS_OFFSET) +@@ -769,8 +772,11 @@ _dl_close_worker (struct link_map *map, bool force) + /* If we removed any object which uses TLS bump the generation counter. */ + if (any_tls) + { +- if (__glibc_unlikely (++GL(dl_tls_generation) == 0)) ++ size_t newgen = GL(dl_tls_generation) + 1; ++ if (__glibc_unlikely (newgen == 0)) + _dl_fatal_printf ("TLS generation counter wrapped! Please report as described in "REPORT_BUGS_TO".\n"); ++ /* Can be read concurrently. */ ++ atomic_store_relaxed (&GL(dl_tls_generation), newgen); + + if (tls_free_end == GL(dl_tls_static_used)) + GL(dl_tls_static_used) = tls_free_start; +diff --git a/elf/dl-open.c b/elf/dl-open.c +index b052bb0bc2cd17aa..a67fb3aee40860e1 100644 +--- a/elf/dl-open.c ++++ b/elf/dl-open.c +@@ -395,9 +395,12 @@ update_tls_slotinfo (struct link_map *new) + } + } + +- if (__builtin_expect (++GL(dl_tls_generation) == 0, 0)) ++ size_t newgen = GL(dl_tls_generation) + 1; ++ if (__glibc_unlikely (newgen == 0)) + _dl_fatal_printf (N_("\ + TLS generation counter wrapped! Please report this.")); ++ /* Can be read concurrently. */ ++ atomic_store_relaxed (&GL(dl_tls_generation), newgen); + + /* We need a second pass for static tls data, because + _dl_update_slotinfo must not be run while calls to +diff --git a/elf/dl-tls.c b/elf/dl-tls.c +index da83cd6ae2ee6504..801eafad3961573c 100644 +--- a/elf/dl-tls.c ++++ b/elf/dl-tls.c +@@ -175,7 +175,9 @@ _dl_next_tls_modid (void) + /* No gaps, allocate a new entry. */ + nogaps: + +- result = ++GL(dl_tls_max_dtv_idx); ++ result = GL(dl_tls_max_dtv_idx) + 1; ++ /* Can be read concurrently. */ ++ atomic_store_relaxed (&GL(dl_tls_max_dtv_idx), result); + } + + return result; +@@ -359,10 +361,12 @@ allocate_dtv (void *result) + dtv_t *dtv; + size_t dtv_length; + ++ /* Relaxed MO, because the dtv size is later rechecked, not relied on. */ ++ size_t max_modid = atomic_load_relaxed (&GL(dl_tls_max_dtv_idx)); + /* We allocate a few more elements in the dtv than are needed for the + initial set of modules. This should avoid in most cases expansions + of the dtv. */ +- dtv_length = GL(dl_tls_max_dtv_idx) + DTV_SURPLUS; ++ dtv_length = max_modid + DTV_SURPLUS; + dtv = calloc (dtv_length + 2, sizeof (dtv_t)); + if (dtv != NULL) + { +@@ -767,7 +771,7 @@ _dl_update_slotinfo (unsigned long int req_modid) + if (modid > max_modid) + break; + +- size_t gen = listp->slotinfo[cnt].gen; ++ size_t gen = atomic_load_relaxed (&listp->slotinfo[cnt].gen); + + if (gen > new_gen) + /* Not relevant. */ +@@ -779,7 +783,8 @@ _dl_update_slotinfo (unsigned long int req_modid) + continue; + + /* If there is no map this means the entry is empty. */ +- struct link_map *map = listp->slotinfo[cnt].map; ++ struct link_map *map ++ = atomic_load_relaxed (&listp->slotinfo[cnt].map); + /* Check whether the current dtv array is large enough. */ + if (dtv[-1].counter < modid) + { +@@ -923,7 +928,12 @@ __tls_get_addr (GET_ADDR_ARGS) + { + dtv_t *dtv = THREAD_DTV (); + +- if (__glibc_unlikely (dtv[0].counter != GL(dl_tls_generation))) ++ /* Update is needed if dtv[0].counter < the generation of the accessed ++ module. The global generation counter is used here as it is easier ++ to check. Synchronization for the relaxed MO access is guaranteed ++ by user code, see CONCURRENCY NOTES in _dl_update_slotinfo. */ ++ size_t gen = atomic_load_relaxed (&GL(dl_tls_generation)); ++ if (__glibc_unlikely (dtv[0].counter != gen)) + return update_get_addr (GET_ADDR_PARAM); + + void *p = dtv[GET_ADDR_MODULE].pointer.val; +@@ -946,7 +956,10 @@ _dl_tls_get_addr_soft (struct link_map *l) + return NULL; + + dtv_t *dtv = THREAD_DTV (); +- if (__glibc_unlikely (dtv[0].counter != GL(dl_tls_generation))) ++ /* This may be called without holding the GL(dl_load_lock). Reading ++ arbitrary gen value is fine since this is best effort code. */ ++ size_t gen = atomic_load_relaxed (&GL(dl_tls_generation)); ++ if (__glibc_unlikely (dtv[0].counter != gen)) + { + /* This thread's DTV is not completely current, + but it might already cover this module. */ +@@ -1032,7 +1045,9 @@ cannot create TLS data structures")); + /* Add the information into the slotinfo data structure. */ + if (do_add) + { +- listp->slotinfo[idx].map = l; +- listp->slotinfo[idx].gen = GL(dl_tls_generation) + 1; ++ /* Can be read concurrently. See _dl_update_slotinfo. */ ++ atomic_store_relaxed (&listp->slotinfo[idx].map, l); ++ atomic_store_relaxed (&listp->slotinfo[idx].gen, ++ GL(dl_tls_generation) + 1); + } + } +diff --git a/sysdeps/x86_64/dl-tls.c b/sysdeps/x86_64/dl-tls.c +index 533ee2b3a6e85ad8..bc543dcc264ea361 100644 +--- a/sysdeps/x86_64/dl-tls.c ++++ b/sysdeps/x86_64/dl-tls.c +@@ -40,7 +40,8 @@ __tls_get_addr_slow (GET_ADDR_ARGS) + { + dtv_t *dtv = THREAD_DTV (); + +- if (__glibc_unlikely (dtv[0].counter != GL(dl_tls_generation))) ++ size_t gen = atomic_load_relaxed (&GL(dl_tls_generation)); ++ if (__glibc_unlikely (dtv[0].counter != gen)) + return update_get_addr (GET_ADDR_PARAM); + + return tls_get_addr_tail (GET_ADDR_PARAM, dtv, NULL); diff --git a/SOURCES/glibc-rh1991001-14.patch b/SOURCES/glibc-rh1991001-14.patch new file mode 100644 index 0000000..3467532 --- /dev/null +++ b/SOURCES/glibc-rh1991001-14.patch @@ -0,0 +1,133 @@ +commit 9d0e30329c23b5ad736fda3f174208c25970dbce +Author: Szabolcs Nagy +Date: Tue Dec 13 12:28:41 2016 +0000 + + elf: Add test case for [BZ #19329] + + Test concurrent dlopen and pthread_create when the loaded modules have + TLS. This triggers dl-tls assertion failures more reliably than the + nptl/tst-stack4 test. + + The dlopened module has 100 DT_NEEDED dependencies with TLS, they were + reused from an existing TLS test. The number of created threads during + dlopen depends on filesystem speed and hardware, but at most 3 threads + are alive at a time to limit resource usage. + + Reviewed-by: Adhemerval Zanella + +Conflicts: + elf/Makefile + (usual testing differences) + +diff --git a/elf/Makefile b/elf/Makefile +index 0995d810b57d0dda..be40e3761cf91c4a 100644 +--- a/elf/Makefile ++++ b/elf/Makefile +@@ -210,7 +210,7 @@ tests += restest1 preloadtest loadfail multiload origtest resolvfail \ + tst-tls-ie tst-tls-ie-dlmopen \ + argv0test \ + tst-glibc-hwcaps tst-glibc-hwcaps-prepend tst-glibc-hwcaps-mask \ +- tst-tls20 ++ tst-tls20 tst-tls21 + # reldep9 + tests-internal += loadtest unload unload2 circleload1 \ + neededtest neededtest2 neededtest3 neededtest4 \ +@@ -333,7 +333,7 @@ modules-names = testobj1 testobj2 testobj3 testobj4 testobj5 testobj6 \ + libmarkermod2-1 libmarkermod2-2 \ + libmarkermod3-1 libmarkermod3-2 libmarkermod3-3 \ + libmarkermod4-1 libmarkermod4-2 libmarkermod4-3 libmarkermod4-4 \ +- tst-tls20mod-bad ++ tst-tls20mod-bad tst-tls21mod \ + + # Most modules build with _ISOMAC defined, but those filtered out + # depend on internal headers. +@@ -1836,3 +1836,8 @@ tst-tls20mod-bad.so-no-z-defs = yes + $(objpfx)tst-tls20: $(libdl) $(shared-thread-library) + $(objpfx)tst-tls20.out: $(objpfx)tst-tls20mod-bad.so \ + $(tst-tls-many-dynamic-modules:%=$(objpfx)%.so) ++ ++# Reuses tst-tls-many-dynamic-modules ++$(objpfx)tst-tls21: $(libdl) $(shared-thread-library) ++$(objpfx)tst-tls21.out: $(objpfx)tst-tls21mod.so ++$(objpfx)tst-tls21mod.so: $(tst-tls-many-dynamic-modules:%=$(objpfx)%.so) +diff --git a/elf/tst-tls21.c b/elf/tst-tls21.c +new file mode 100644 +index 0000000000000000..560bf5813a746417 +--- /dev/null ++++ b/elf/tst-tls21.c +@@ -0,0 +1,68 @@ ++/* Test concurrent dlopen and pthread_create: BZ 19329. ++ 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 ++ ++#define THREADS 10000 ++ ++static atomic_int done; ++ ++static void * ++start (void *a) ++{ ++ /* Load a module with many dependencies that each have TLS. */ ++ xdlopen ("tst-tls21mod.so", RTLD_LAZY); ++ atomic_store_explicit (&done, 1, memory_order_release); ++ return 0; ++} ++ ++static void * ++nop (void *a) ++{ ++ return 0; ++} ++ ++static int ++do_test (void) ++{ ++ pthread_t t1, t2; ++ int i; ++ ++ /* Load a module with lots of dependencies and TLS. */ ++ t1 = xpthread_create (0, start, 0); ++ ++ /* Concurrently create lots of threads until dlopen is observably done. */ ++ for (i = 0; i < THREADS; i++) ++ { ++ if (atomic_load_explicit (&done, memory_order_acquire) != 0) ++ break; ++ t2 = xpthread_create (0, nop, 0); ++ xpthread_join (t2); ++ } ++ ++ xpthread_join (t1); ++ printf ("threads created during dlopen: %d\n", i); ++ return 0; ++} ++ ++#include +diff --git a/elf/tst-tls21mod.c b/elf/tst-tls21mod.c +new file mode 100644 +index 0000000000000000..206ece4fb34622a9 +--- /dev/null ++++ b/elf/tst-tls21mod.c +@@ -0,0 +1 @@ ++int __thread x; diff --git a/SOURCES/glibc-rh1991001-15.patch b/SOURCES/glibc-rh1991001-15.patch new file mode 100644 index 0000000..553ecfb --- /dev/null +++ b/SOURCES/glibc-rh1991001-15.patch @@ -0,0 +1,81 @@ +commit 572bd547d57a39b6cf0ea072545dc4048921f4c3 +Author: Szabolcs Nagy +Date: Thu Dec 31 13:59:38 2020 +0000 + + elf: Fix DTV gap reuse logic [BZ #27135] + + For some reason only dlopen failure caused dtv gaps to be reused. + + It is possible that the intent was to never reuse modids for a + different module, but after dlopen failure all gaps are reused + not just the ones caused by the unfinished dlopened. + + So the code has to handle reused modids already which seems to + work, however the data races at thread creation and tls access + (see bug 19329 and bug 27111) may be more severe if slots are + reused so this is scheduled after those fixes. I think fixing + the races are not simpler if reuse is disallowed and reuse has + other benefits, so set GL(dl_tls_dtv_gaps) whenever entries are + removed from the middle of the slotinfo list. The value does + not have to be correct: incorrect true value causes the next + modid query to do a slotinfo walk, incorrect false will leave + gaps and new entries are added at the end. + + Fixes bug 27135. + + Reviewed-by: Adhemerval Zanella + +diff --git a/elf/dl-close.c b/elf/dl-close.c +index 7d2dc2272cd643f5..41cb6c58491c364b 100644 +--- a/elf/dl-close.c ++++ b/elf/dl-close.c +@@ -88,7 +88,11 @@ remove_slotinfo (size_t idx, struct dtv_slotinfo_list *listp, size_t disp, + /* If this is not the last currently used entry no need to look + further. */ + if (idx != GL(dl_tls_max_dtv_idx)) +- return true; ++ { ++ /* There is an unused dtv entry in the middle. */ ++ GL(dl_tls_dtv_gaps) = true; ++ return true; ++ } + } + + while (idx - disp > (disp == 0 ? 1 + GL(dl_tls_static_nelem) : 0)) +diff --git a/elf/dl-open.c b/elf/dl-open.c +index a67fb3aee40860e1..54727402750f4c0c 100644 +--- a/elf/dl-open.c ++++ b/elf/dl-open.c +@@ -896,16 +896,6 @@ no more namespaces available for dlmopen()")); + state if relocation failed, for example. */ + if (args.map) + { +- /* Maybe some of the modules which were loaded use TLS. +- Since it will be removed in the following _dl_close call +- we have to mark the dtv array as having gaps to fill the +- holes. This is a pessimistic assumption which won't hurt +- if not true. There is no need to do this when we are +- loading the auditing DSOs since TLS has not yet been set +- up. */ +- if ((mode & __RTLD_AUDIT) == 0) +- GL(dl_tls_dtv_gaps) = true; +- + _dl_close_worker (args.map, true); + + /* All l_nodelete_pending objects should have been deleted +diff --git a/elf/dl-tls.c b/elf/dl-tls.c +index 801eafad3961573c..bacb4101e2e2c4e5 100644 +--- a/elf/dl-tls.c ++++ b/elf/dl-tls.c +@@ -187,10 +187,7 @@ _dl_next_tls_modid (void) + size_t + _dl_count_modids (void) + { +- /* It is rare that we have gaps; see elf/dl-open.c (_dl_open) where +- we fail to load a module and unload it leaving a gap. If we don't +- have gaps then the number of modids is the current maximum so +- return that. */ ++ /* The count is the max unless dlclose or failed dlopen created gaps. */ + if (__glibc_likely (!GL(dl_tls_dtv_gaps))) + return GL(dl_tls_max_dtv_idx); + diff --git a/SOURCES/glibc-rh1991001-16.patch b/SOURCES/glibc-rh1991001-16.patch new file mode 100644 index 0000000..d1902a7 --- /dev/null +++ b/SOURCES/glibc-rh1991001-16.patch @@ -0,0 +1,71 @@ +commit 40ebfd016ad284872f434bdd76dbe9c708db4d6b +Author: Florian Weimer +Date: Fri Jun 25 08:09:08 2021 +0200 + + elf: Disable most of TLS modid gaps processing [BZ #27135] + + Revert "elf: Fix DTV gap reuse logic [BZ #27135]" + + This reverts commit 572bd547d57a39b6cf0ea072545dc4048921f4c3. + + It turns out that the _dl_next_tls_modid in _dl_map_object_from_fd keeps + returning the same modid over and over again if there is a gap and + more than TLS-using module is loaded in one dlopen call. This corrupts + TLS data structures. The bug is still present after a revert, but + empirically it is much more difficult to trigger (because it involves a + dlopen failure). + +diff --git a/elf/dl-close.c b/elf/dl-close.c +index 41cb6c58491c364b..7d2dc2272cd643f5 100644 +--- a/elf/dl-close.c ++++ b/elf/dl-close.c +@@ -88,11 +88,7 @@ remove_slotinfo (size_t idx, struct dtv_slotinfo_list *listp, size_t disp, + /* If this is not the last currently used entry no need to look + further. */ + if (idx != GL(dl_tls_max_dtv_idx)) +- { +- /* There is an unused dtv entry in the middle. */ +- GL(dl_tls_dtv_gaps) = true; +- return true; +- } ++ return true; + } + + while (idx - disp > (disp == 0 ? 1 + GL(dl_tls_static_nelem) : 0)) +diff --git a/elf/dl-open.c b/elf/dl-open.c +index 54727402750f4c0c..a67fb3aee40860e1 100644 +--- a/elf/dl-open.c ++++ b/elf/dl-open.c +@@ -896,6 +896,16 @@ no more namespaces available for dlmopen()")); + state if relocation failed, for example. */ + if (args.map) + { ++ /* Maybe some of the modules which were loaded use TLS. ++ Since it will be removed in the following _dl_close call ++ we have to mark the dtv array as having gaps to fill the ++ holes. This is a pessimistic assumption which won't hurt ++ if not true. There is no need to do this when we are ++ loading the auditing DSOs since TLS has not yet been set ++ up. */ ++ if ((mode & __RTLD_AUDIT) == 0) ++ GL(dl_tls_dtv_gaps) = true; ++ + _dl_close_worker (args.map, true); + + /* All l_nodelete_pending objects should have been deleted +diff --git a/elf/dl-tls.c b/elf/dl-tls.c +index bacb4101e2e2c4e5..801eafad3961573c 100644 +--- a/elf/dl-tls.c ++++ b/elf/dl-tls.c +@@ -187,7 +187,10 @@ _dl_next_tls_modid (void) + size_t + _dl_count_modids (void) + { +- /* The count is the max unless dlclose or failed dlopen created gaps. */ ++ /* It is rare that we have gaps; see elf/dl-open.c (_dl_open) where ++ we fail to load a module and unload it leaving a gap. If we don't ++ have gaps then the number of modids is the current maximum so ++ return that. */ + if (__glibc_likely (!GL(dl_tls_dtv_gaps))) + return GL(dl_tls_max_dtv_idx); + diff --git a/SOURCES/glibc-rh1991001-17.patch b/SOURCES/glibc-rh1991001-17.patch new file mode 100644 index 0000000..cb1a041 --- /dev/null +++ b/SOURCES/glibc-rh1991001-17.patch @@ -0,0 +1,585 @@ +commit ba33937be210da5d07f7f01709323743f66011ce +Author: Adhemerval Zanella +Date: Fri Jun 25 10:54:12 2021 -0300 + + elf: Fix DTV gap reuse logic (BZ #27135) + + This is updated version of the 572bd547d57a (reverted by 40ebfd016ad2) + that fixes the _dl_next_tls_modid issues. + + This issue with 572bd547d57a patch is the DTV entry will be only + update on dl_open_worker() with the update_tls_slotinfo() call after + all dependencies are being processed by _dl_map_object_deps(). However + _dl_map_object_deps() itself might call _dl_next_tls_modid(), and since + the _dl_tls_dtv_slotinfo_list::map is not yet set the entry will be + wrongly reused. + + This patch fixes by renaming the _dl_next_tls_modid() function to + _dl_assign_tls_modid() and by passing the link_map so it can set + the slotinfo value so a subsequente _dl_next_tls_modid() call will + see the entry as allocated. + + The intermediary value is cleared up on remove_slotinfo() for the case + a library fails to load with RTLD_NOW. + + This patch fixes BZ #27135. + + Checked on x86_64-linux-gnu. + + Reviewed-by: Szabolcs Nagy + +Conflicts: + elf/Makefile + (testing differences; libdl removal upstream) + +diff --git a/elf/Makefile b/elf/Makefile +index be40e3761cf91c4a..3e71939d3234c4c3 100644 +--- a/elf/Makefile ++++ b/elf/Makefile +@@ -242,6 +242,13 @@ one-hundred = $(foreach x,0 1 2 3 4 5 6 7 8 9, \ + 0$x 1$x 2$x 3$x 4$x 5$x 6$x 7$x 8$x 9$x) + tst-tls-many-dynamic-modules := \ + $(foreach n,$(one-hundred),tst-tls-manydynamic$(n)mod) ++tst-tls-many-dynamic-modules-dep-suffixes = 0 1 2 3 4 5 6 7 8 9 10 11 12 13 \ ++ 14 15 16 17 18 19 ++tst-tls-many-dynamic-modules-dep = \ ++ $(foreach n,$(tst-tls-many-dynamic-modules-dep-suffixes),tst-tls-manydynamic$(n)mod-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 +@@ -314,6 +321,8 @@ modules-names = testobj1 testobj2 testobj3 testobj4 testobj5 testobj6 \ + 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 \ +@@ -1832,10 +1841,63 @@ $(objpfx)tst-rtld-help.out: $(objpfx)ld.so + $(evaluate-test) + + # Reuses tst-tls-many-dynamic-modules ++$(patsubst %,$(objpfx)%.os,$(tst-tls-many-dynamic-modules-dep)): \ ++ $(objpfx)tst-tls-manydynamic%mod-dep.os : tst-tls-manydynamicmod.c ++ $(compile-command.c) \ ++ -DNAME=tls_global_$* -DSETTER=set_value_$* -DGETTER=get_value_$* ++$(patsubst %,$(objpfx)%.os,$(tst-tls-many-dynamic-modules-dep-bad)): \ ++ $(objpfx)tst-tls-manydynamic%mod-dep-bad.os : tst-tls-manydynamicmod.c ++ $(compile-command.c) \ ++ -DNAME=tls_global_$* -DSETTER=set_value_$* -DGETTER=get_value_$* + tst-tls20mod-bad.so-no-z-defs = yes ++# Single dependency. ++$(objpfx)tst-tls-manydynamic0mod-dep.so: $(objpfx)tst-tls-manydynamic1mod-dep.so ++# Double dependencies. ++$(objpfx)tst-tls-manydynamic2mod-dep.so: $(objpfx)tst-tls-manydynamic3mod-dep.so \ ++ $(objpfx)tst-tls-manydynamic4mod-dep.so ++# Double dependencies with each dependency depent of another module. ++$(objpfx)tst-tls-manydynamic5mod-dep.so: $(objpfx)tst-tls-manydynamic6mod-dep.so \ ++ $(objpfx)tst-tls-manydynamic7mod-dep.so ++$(objpfx)tst-tls-manydynamic6mod-dep.so: $(objpfx)tst-tls-manydynamic8mod-dep.so ++$(objpfx)tst-tls-manydynamic7mod-dep.so: $(objpfx)tst-tls-manydynamic8mod-dep.so ++# Long chain with one double dependency in the middle ++$(objpfx)tst-tls-manydynamic9mod-dep.so: $(objpfx)tst-tls-manydynamic10mod-dep.so \ ++ $(objpfx)tst-tls-manydynamic11mod-dep.so ++$(objpfx)tst-tls-manydynamic10mod-dep.so: $(objpfx)tst-tls-manydynamic12mod-dep.so ++$(objpfx)tst-tls-manydynamic12mod-dep.so: $(objpfx)tst-tls-manydynamic13mod-dep.so ++# Long chain with two double depedencies in the middle ++$(objpfx)tst-tls-manydynamic14mod-dep.so: $(objpfx)tst-tls-manydynamic15mod-dep.so ++$(objpfx)tst-tls-manydynamic15mod-dep.so: $(objpfx)tst-tls-manydynamic16mod-dep.so \ ++ $(objpfx)tst-tls-manydynamic17mod-dep.so ++$(objpfx)tst-tls-manydynamic16mod-dep.so: $(objpfx)tst-tls-manydynamic18mod-dep.so \ ++ $(objpfx)tst-tls-manydynamic19mod-dep.so ++# Same but with an invalid module. ++# Single dependency. ++$(objpfx)tst-tls-manydynamic0mod-dep-bad.so: $(objpfx)tst-tls20mod-bad.so ++# Double dependencies. ++$(objpfx)tst-tls-manydynamic1mod-dep-bad.so: $(objpfx)tst-tls-manydynamic2mod-dep-bad.so \ ++ $(objpfx)tst-tls20mod-bad.so ++# Double dependencies with each dependency depent of another module. ++$(objpfx)tst-tls-manydynamic3mod-dep-bad.so: $(objpfx)tst-tls-manydynamic4mod-dep-bad.so \ ++ $(objpfx)tst-tls-manydynamic5mod-dep-bad.so ++$(objpfx)tst-tls-manydynamic4mod-dep-bad.so: $(objpfx)tst-tls20mod-bad.so ++$(objpfx)tst-tls-manydynamic5mod-dep-bad.so: $(objpfx)tst-tls20mod-bad.so ++# Long chain with one double dependency in the middle ++$(objpfx)tst-tls-manydynamic6mod-dep-bad.so: $(objpfx)tst-tls-manydynamic7mod-dep-bad.so \ ++ $(objpfx)tst-tls-manydynamic8mod-dep-bad.so ++$(objpfx)tst-tls-manydynamic7mod-dep-bad.so: $(objpfx)tst-tls-manydynamic9mod-dep-bad.so ++$(objpfx)tst-tls-manydynamic9mod-dep-bad.so: $(objpfx)tst-tls20mod-bad.so ++# Long chain with two double depedencies in the middle ++$(objpfx)tst-tls-manydynamic10mod-dep-bad.so: $(objpfx)tst-tls-manydynamic11mod-dep-bad.so ++$(objpfx)tst-tls-manydynamic11mod-dep-bad.so: $(objpfx)tst-tls-manydynamic12mod-dep-bad.so \ ++ $(objpfx)tst-tls-manydynamic13mod-dep-bad.so ++$(objpfx)tst-tls-manydynamic12mod-dep-bad.so: $(objpfx)tst-tls-manydynamic14mod-dep-bad.so \ ++ $(objpfx)tst-tls20mod-bad.so + $(objpfx)tst-tls20: $(libdl) $(shared-thread-library) + $(objpfx)tst-tls20.out: $(objpfx)tst-tls20mod-bad.so \ +- $(tst-tls-many-dynamic-modules:%=$(objpfx)%.so) ++ $(tst-tls-many-dynamic-modules:%=$(objpfx)%.so) \ ++ $(tst-tls-many-dynamic-modules-dep:%=$(objpfx)%.so) \ ++ $(tst-tls-many-dynamic-modules-dep-bad:%=$(objpfx)%.so) \ + + # Reuses tst-tls-many-dynamic-modules + $(objpfx)tst-tls21: $(libdl) $(shared-thread-library) +diff --git a/elf/dl-close.c b/elf/dl-close.c +index 7d2dc2272cd643f5..18227fe992029364 100644 +--- a/elf/dl-close.c ++++ b/elf/dl-close.c +@@ -77,8 +77,6 @@ remove_slotinfo (size_t idx, struct dtv_slotinfo_list *listp, size_t disp, + object that wasn't fully set up. */ + if (__glibc_likely (old_map != NULL)) + { +- assert (old_map->l_tls_modid == idx); +- + /* Mark the entry as unused. These can be read concurrently. */ + atomic_store_relaxed (&listp->slotinfo[idx - disp].gen, + GL(dl_tls_generation) + 1); +@@ -88,7 +86,11 @@ remove_slotinfo (size_t idx, struct dtv_slotinfo_list *listp, size_t disp, + /* If this is not the last currently used entry no need to look + further. */ + if (idx != GL(dl_tls_max_dtv_idx)) +- return true; ++ { ++ /* There is an unused dtv entry in the middle. */ ++ GL(dl_tls_dtv_gaps) = true; ++ return true; ++ } + } + + while (idx - disp > (disp == 0 ? 1 + GL(dl_tls_static_nelem) : 0)) +diff --git a/elf/dl-load.c b/elf/dl-load.c +index 80fc38041a936c3c..cdb5d4b5b67f1ca1 100644 +--- a/elf/dl-load.c ++++ b/elf/dl-load.c +@@ -1419,7 +1419,7 @@ cannot enable executable stack as shared object requires"); + not set up TLS data structures, so don't use them now. */ + || __glibc_likely (GL(dl_tls_dtv_slotinfo_list) != NULL))) + /* Assign the next available module ID. */ +- l->l_tls_modid = _dl_next_tls_modid (); ++ _dl_assign_tls_modid (l); + + #ifdef DL_AFTER_LOAD + DL_AFTER_LOAD (l); +diff --git a/elf/dl-open.c b/elf/dl-open.c +index a67fb3aee40860e1..54727402750f4c0c 100644 +--- a/elf/dl-open.c ++++ b/elf/dl-open.c +@@ -896,16 +896,6 @@ no more namespaces available for dlmopen()")); + state if relocation failed, for example. */ + if (args.map) + { +- /* Maybe some of the modules which were loaded use TLS. +- Since it will be removed in the following _dl_close call +- we have to mark the dtv array as having gaps to fill the +- holes. This is a pessimistic assumption which won't hurt +- if not true. There is no need to do this when we are +- loading the auditing DSOs since TLS has not yet been set +- up. */ +- if ((mode & __RTLD_AUDIT) == 0) +- GL(dl_tls_dtv_gaps) = true; +- + _dl_close_worker (args.map, true); + + /* All l_nodelete_pending objects should have been deleted +diff --git a/elf/dl-tls.c b/elf/dl-tls.c +index 801eafad3961573c..8c0f9e972d7a0eac 100644 +--- a/elf/dl-tls.c ++++ b/elf/dl-tls.c +@@ -122,8 +122,8 @@ oom (void) + } + + +-size_t +-_dl_next_tls_modid (void) ++void ++_dl_assign_tls_modid (struct link_map *l) + { + size_t result; + +@@ -153,7 +153,11 @@ _dl_next_tls_modid (void) + } + + if (result - disp < runp->len) +- break; ++ { ++ /* Mark the entry as used, so any dependency see it. */ ++ atomic_store_relaxed (&runp->slotinfo[result - disp].map, l); ++ break; ++ } + + disp += runp->len; + } +@@ -180,17 +184,14 @@ _dl_next_tls_modid (void) + atomic_store_relaxed (&GL(dl_tls_max_dtv_idx), result); + } + +- return result; ++ l->l_tls_modid = result; + } + + + size_t + _dl_count_modids (void) + { +- /* It is rare that we have gaps; see elf/dl-open.c (_dl_open) where +- we fail to load a module and unload it leaving a gap. If we don't +- have gaps then the number of modids is the current maximum so +- return that. */ ++ /* The count is the max unless dlclose or failed dlopen created gaps. */ + if (__glibc_likely (!GL(dl_tls_dtv_gaps))) + return GL(dl_tls_max_dtv_idx); + +diff --git a/elf/rtld.c b/elf/rtld.c +index 992f825ba00762a7..118c454a2329573f 100644 +--- a/elf/rtld.c ++++ b/elf/rtld.c +@@ -1693,7 +1693,7 @@ ERROR: '%s': cannot process note segment.\n", _dl_argv[0]); + /* Add the dynamic linker to the TLS list if it also uses TLS. */ + if (GL(dl_rtld_map).l_tls_blocksize != 0) + /* Assign a module ID. Do this before loading any audit modules. */ +- GL(dl_rtld_map).l_tls_modid = _dl_next_tls_modid (); ++ _dl_assign_tls_modid (&GL(dl_rtld_map)); + + audit_list_add_dynamic_tag (&state.audit_list, main_map, DT_AUDIT); + audit_list_add_dynamic_tag (&state.audit_list, main_map, DT_DEPAUDIT); +diff --git a/elf/tst-tls20.c b/elf/tst-tls20.c +index 9977ec803208b9c8..d8d04fe574597f35 100644 +--- a/elf/tst-tls20.c ++++ b/elf/tst-tls20.c +@@ -16,12 +16,14 @@ + License along with the GNU C Library; if not, see + . */ + ++#include + #include + #include + #include + #include + #include + #include ++#include + #include + #include + +@@ -59,28 +61,75 @@ access (int i) + char *buf = xasprintf ("tls_global_%02d", i); + dlerror (); + int *p = dlsym (mod[i], buf); +- printf ("mod[%d]: &tls = %p\n", i, p); ++ if (test_verbose) ++ printf ("mod[%d]: &tls = %p\n", i, p); + if (p == NULL) + FAIL_EXIT1 ("dlsym failed: %s\n", dlerror ()); ++ TEST_COMPARE (*p, 0); + ++*p; + free (buf); + } + ++static void ++access_mod (const char *modname, void *mod, int i) ++{ ++ char *modsym = xasprintf ("tls_global_%d", i); ++ dlerror (); ++ int *p = dlsym (mod, modsym); ++ if (test_verbose) ++ printf ("%s: &tls = %p\n", modname, p); ++ if (p == NULL) ++ FAIL_EXIT1 ("dlsym failed: %s\n", dlerror ()); ++ TEST_COMPARE (*p, 0); ++ ++*p; ++ free (modsym); ++} ++ ++static void ++access_dep (int i) ++{ ++ char *modname = xasprintf ("tst-tls-manydynamic%dmod-dep.so", i); ++ void *moddep = xdlopen (modname, RTLD_LAZY); ++ access_mod (modname, moddep, i); ++ free (modname); ++ xdlclose (moddep); ++} ++ ++struct start_args ++{ ++ const char *modname; ++ void *mod; ++ int modi; ++ int ndeps; ++ const int *deps; ++}; ++ + static void * + start (void *a) + { ++ struct start_args *args = a; ++ + for (int i = 0; i < NMOD; i++) + if (mod[i] != NULL) + access (i); ++ ++ if (args != NULL) ++ { ++ access_mod (args->modname, args->mod, args->modi); ++ for (int n = 0; n < args->ndeps; n++) ++ access_dep (args->deps[n]); ++ } ++ + return 0; + } + +-static int +-do_test (void) ++/* This test gaps with shared libraries with dynamic TLS that has no ++ dependencies. The DTV gap is set with by trying to load an invalid ++ module, the entry should be used on the dlopen. */ ++static void ++do_test_no_depedency (void) + { +- int i; +- +- for (i = 0; i < NMOD; i++) ++ for (int i = 0; i < NMOD; i++) + { + load_mod (i); + /* Bump the generation of mod[0] without using new dtv slot. */ +@@ -91,8 +140,220 @@ do_test (void) + pthread_t t = xpthread_create (0, start, 0); + xpthread_join (t); + } +- for (i = 0; i < NMOD; i++) ++ for (int i = 0; i < NMOD; i++) + unload_mod (i); ++} ++ ++/* The following test check DTV gaps handling with shared libraries that has ++ dependencies. It defines 5 different sets: ++ ++ 1. Single dependency: ++ mod0 -> mod1 ++ 2. Double dependency: ++ mod2 -> [mod3,mod4] ++ 3. Double dependency with each dependency depent of another module: ++ mod5 -> [mod6,mod7] -> mod8 ++ 4. Long chain with one double dependency in the middle: ++ mod9 -> [mod10, mod11] -> mod12 -> mod13 ++ 5. Long chain with two double depedencies in the middle: ++ mod14 -> mod15 -> [mod16, mod17] ++ mod15 -> [mod18, mod19] ++ ++ This does not cover all the possible gaps and configuration, but it ++ should check if different dynamic shared sets are placed correctly in ++ different gaps configurations. */ ++ ++static int ++nmodules (uint32_t v) ++{ ++ unsigned int r = 0; ++ while (v >>= 1) ++ r++; ++ return r + 1; ++} ++ ++static inline bool ++is_mod_set (uint32_t g, uint32_t n) ++{ ++ return (1U << (n - 1)) & g; ++} ++ ++static void ++print_gap (uint32_t g) ++{ ++ if (!test_verbose) ++ return; ++ printf ("gap: "); ++ int nmods = nmodules (g); ++ for (int n = 1; n <= nmods; n++) ++ printf ("%c", ((1 << (n - 1)) & g) == 0 ? 'G' : 'M'); ++ printf ("\n"); ++} ++ ++static void ++do_test_dependency (void) ++{ ++ /* Maps the module and its dependencies, use thread to access the TLS on ++ each loaded module. */ ++ static const int tlsmanydeps0[] = { 1 }; ++ static const int tlsmanydeps1[] = { 3, 4 }; ++ static const int tlsmanydeps2[] = { 6, 7, 8 }; ++ static const int tlsmanydeps3[] = { 10, 11, 12 }; ++ static const int tlsmanydeps4[] = { 15, 16, 17, 18, 19 }; ++ static const struct tlsmanydeps_t ++ { ++ int modi; ++ int ndeps; ++ const int *deps; ++ } tlsmanydeps[] = ++ { ++ { 0, array_length (tlsmanydeps0), tlsmanydeps0 }, ++ { 2, array_length (tlsmanydeps1), tlsmanydeps1 }, ++ { 5, array_length (tlsmanydeps2), tlsmanydeps2 }, ++ { 9, array_length (tlsmanydeps3), tlsmanydeps3 }, ++ { 14, array_length (tlsmanydeps4), tlsmanydeps4 }, ++ }; ++ ++ /* The gap configuration is defined as a bitmap: the bit set represents a ++ loaded module prior the tests execution, while a bit unsed is a module ++ unloaded. Not all permtation will show gaps, but it is simpler than ++ define each one independently. */ ++ for (uint32_t g = 0; g < 64; g++) ++ { ++ print_gap (g); ++ int nmods = nmodules (g); ++ ++ int mods[nmods]; ++ /* We use '0' as indication for a gap, to avoid the dlclose on iteration ++ cleanup. */ ++ for (int n = 1; n <= nmods; n++) ++ { ++ load_mod (n); ++ mods[n] = n; ++ } ++ for (int n = 1; n <= nmods; n++) ++ { ++ if (!is_mod_set (g, n)) ++ { ++ unload_mod (n); ++ mods[n] = 0; ++ } ++ } ++ ++ for (int t = 0; t < array_length (tlsmanydeps); t++) ++ { ++ char *moddepname = xasprintf ("tst-tls-manydynamic%dmod-dep.so", ++ tlsmanydeps[t].modi); ++ void *moddep = xdlopen (moddepname, RTLD_LAZY); ++ ++ /* Access TLS in all loaded modules. */ ++ struct start_args args = ++ { ++ moddepname, ++ moddep, ++ tlsmanydeps[t].modi, ++ tlsmanydeps[t].ndeps, ++ tlsmanydeps[t].deps ++ }; ++ pthread_t t = xpthread_create (0, start, &args); ++ xpthread_join (t); ++ ++ free (moddepname); ++ xdlclose (moddep); ++ } ++ ++ for (int n = 1; n <= nmods; n++) ++ if (mods[n] != 0) ++ unload_mod (n); ++ } ++} ++ ++/* The following test check DTV gaps handling with shared libraries that has ++ invalid dependencies. It defines 5 different sets: ++ ++ 1. Single dependency: ++ mod0 -> invalid ++ 2. Double dependency: ++ mod1 -> [mod2,invalid] ++ 3. Double dependency with each dependency depent of another module: ++ mod3 -> [mod4,mod5] -> invalid ++ 4. Long chain with one double dependency in the middle: ++ mod6 -> [mod7, mod8] -> mod12 -> invalid ++ 5. Long chain with two double depedencies in the middle: ++ mod10 -> mod11 -> [mod12, mod13] ++ mod12 -> [mod14, invalid] ++ ++ This does not cover all the possible gaps and configuration, but it ++ should check if different dynamic shared sets are placed correctly in ++ different gaps configurations. */ ++ ++static void ++do_test_invalid_dependency (bool bind_now) ++{ ++ static const int tlsmanydeps[] = { 0, 1, 3, 6, 10 }; ++ ++ /* The gap configuration is defined as a bitmap: the bit set represents a ++ loaded module prior the tests execution, while a bit unsed is a module ++ unloaded. Not all permtation will show gaps, but it is simpler than ++ define each one independently. */ ++ for (uint32_t g = 0; g < 64; g++) ++ { ++ print_gap (g); ++ int nmods = nmodules (g); ++ ++ int mods[nmods]; ++ /* We use '0' as indication for a gap, to avoid the dlclose on iteration ++ cleanup. */ ++ for (int n = 1; n <= nmods; n++) ++ { ++ load_mod (n); ++ mods[n] = n; ++ } ++ for (int n = 1; n <= nmods; n++) ++ { ++ if (!is_mod_set (g, n)) ++ { ++ unload_mod (n); ++ mods[n] = 0; ++ } ++ } ++ ++ for (int t = 0; t < array_length (tlsmanydeps); t++) ++ { ++ char *moddepname = xasprintf ("tst-tls-manydynamic%dmod-dep-bad.so", ++ tlsmanydeps[t]); ++ void *moddep; ++ if (bind_now) ++ { ++ moddep = dlopen (moddepname, RTLD_NOW); ++ TEST_VERIFY (moddep == 0); ++ } ++ else ++ moddep = dlopen (moddepname, RTLD_LAZY); ++ ++ /* Access TLS in all loaded modules. */ ++ pthread_t t = xpthread_create (0, start, NULL); ++ xpthread_join (t); ++ ++ free (moddepname); ++ if (!bind_now) ++ xdlclose (moddep); ++ } ++ ++ for (int n = 1; n <= nmods; n++) ++ if (mods[n] != 0) ++ unload_mod (n); ++ } ++} ++ ++static int ++do_test (void) ++{ ++ do_test_no_depedency (); ++ do_test_dependency (); ++ do_test_invalid_dependency (true); ++ do_test_invalid_dependency (false); ++ + return 0; + } + +diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h +index 6cbbaa808a596f77..0138353ccb41c5f1 100644 +--- a/sysdeps/generic/ldsodefs.h ++++ b/sysdeps/generic/ldsodefs.h +@@ -1111,8 +1111,8 @@ extern ElfW(Addr) _dl_sysdep_start (void **start_argptr, + extern void _dl_sysdep_start_cleanup (void) attribute_hidden; + + +-/* Determine next available module ID. */ +-extern size_t _dl_next_tls_modid (void) attribute_hidden; ++/* Determine next available module ID and set the L l_tls_modid. */ ++extern void _dl_assign_tls_modid (struct link_map *l) attribute_hidden; + + /* Count the modules with TLS segments. */ + extern size_t _dl_count_modids (void) attribute_hidden; diff --git a/SOURCES/glibc-rh1991001-18.patch b/SOURCES/glibc-rh1991001-18.patch new file mode 100644 index 0000000..340b345 --- /dev/null +++ b/SOURCES/glibc-rh1991001-18.patch @@ -0,0 +1,42 @@ +commit 881b68e45c3a518319dcf5a3c4a2b3ec59e1c1e5 +Author: Adhemerval Zanella +Date: Fri Jul 16 08:32:05 2021 -0300 + + elf: Fix a wrong array access on tst-tls20 + + Check on x86_64-linux-gnu with --enable-stack-protector=all. + +diff --git a/elf/tst-tls20.c b/elf/tst-tls20.c +index d8d04fe574597f35..831c3336c914790d 100644 +--- a/elf/tst-tls20.c ++++ b/elf/tst-tls20.c +@@ -226,12 +226,12 @@ do_test_dependency (void) + int mods[nmods]; + /* We use '0' as indication for a gap, to avoid the dlclose on iteration + cleanup. */ +- for (int n = 1; n <= nmods; n++) ++ for (int n = 1; n < nmods; n++) + { + load_mod (n); + mods[n] = n; + } +- for (int n = 1; n <= nmods; n++) ++ for (int n = 1; n < nmods; n++) + { + if (!is_mod_set (g, n)) + { +@@ -304,12 +304,12 @@ do_test_invalid_dependency (bool bind_now) + int mods[nmods]; + /* We use '0' as indication for a gap, to avoid the dlclose on iteration + cleanup. */ +- for (int n = 1; n <= nmods; n++) ++ for (int n = 1; n < nmods; n++) + { + load_mod (n); + mods[n] = n; + } +- for (int n = 1; n <= nmods; n++) ++ for (int n = 1; n < nmods; n++) + { + if (!is_mod_set (g, n)) + { diff --git a/SOURCES/glibc-rh1991001-19.patch b/SOURCES/glibc-rh1991001-19.patch new file mode 100644 index 0000000..48995ad --- /dev/null +++ b/SOURCES/glibc-rh1991001-19.patch @@ -0,0 +1,468 @@ +commit 83b5323261bb72313bffcf37476c1b8f0847c736 +Author: Szabolcs Nagy +Date: Wed Sep 15 15:16:19 2021 +0100 + + elf: Avoid deadlock between pthread_create and ctors [BZ #28357] + + The fix for bug 19329 caused a regression such that pthread_create can + deadlock when concurrent ctors from dlopen are waiting for it to finish. + Use a new GL(dl_load_tls_lock) in pthread_create that is not taken + around ctors in dlopen. + + The new lock is also used in __tls_get_addr instead of GL(dl_load_lock). + + The new lock is held in _dl_open_worker and _dl_close_worker around + most of the logic before/after the init/fini routines. When init/fini + routines are running then TLS is in a consistent, usable state. + In _dl_open_worker the new lock requires catching and reraising dlopen + failures that happen in the critical section. + + The new lock is reinitialized in a fork child, to keep the existing + behaviour and it is kept recursive in case malloc interposition or TLS + access from signal handlers can retake it. It is not obvious if this + is necessary or helps, but avoids changing the preexisting behaviour. + + The new lock may be more appropriate for dl_iterate_phdr too than + GL(dl_load_write_lock), since TLS state of an incompletely loaded + module may be accessed. If the new lock can replace the old one, + that can be a separate change. + + Fixes bug 28357. + + Reviewed-by: Adhemerval Zanella + +Conflicts: + posix/fork.c + (reworked due to file rename upstream and libpthread integration) + sysdeps/pthread/Makefile + (htl testing support was missing downstream, reconstituted here; + added $(libdl) required downstream) + +diff --git a/elf/dl-close.c b/elf/dl-close.c +index 18227fe992029364..7fe91bdd9aaf694e 100644 +--- a/elf/dl-close.c ++++ b/elf/dl-close.c +@@ -549,6 +549,9 @@ _dl_close_worker (struct link_map *map, bool force) + size_t tls_free_end; + tls_free_start = tls_free_end = NO_TLS_OFFSET; + ++ /* Protects global and module specitic TLS state. */ ++ __rtld_lock_lock_recursive (GL(dl_load_tls_lock)); ++ + /* We modify the list of loaded objects. */ + __rtld_lock_lock_recursive (GL(dl_load_write_lock)); + +@@ -784,6 +787,9 @@ _dl_close_worker (struct link_map *map, bool force) + GL(dl_tls_static_used) = tls_free_start; + } + ++ /* TLS is cleaned up for the unloaded modules. */ ++ __rtld_lock_unlock_recursive (GL(dl_load_tls_lock)); ++ + #ifdef SHARED + /* Auditing checkpoint: we have deleted all objects. */ + if (__glibc_unlikely (do_audit)) +diff --git a/elf/dl-open.c b/elf/dl-open.c +index 54727402750f4c0c..736df62ce6e46d34 100644 +--- a/elf/dl-open.c ++++ b/elf/dl-open.c +@@ -65,6 +65,9 @@ struct dl_open_args + libc_map value in the namespace in case of a dlopen failure. */ + bool libc_already_loaded; + ++ /* Set to true if the end of dl_open_worker_begin was reached. */ ++ bool worker_continue; ++ + /* Original parameters to the program and the current environment. */ + int argc; + char **argv; +@@ -481,7 +484,7 @@ call_dl_init (void *closure) + } + + static void +-dl_open_worker (void *a) ++dl_open_worker_begin (void *a) + { + struct dl_open_args *args = a; + const char *file = args->file; +@@ -772,6 +775,36 @@ dl_open_worker (void *a) + DL_STATIC_INIT (new); + #endif + ++ args->worker_continue = true; ++} ++ ++static void ++dl_open_worker (void *a) ++{ ++ struct dl_open_args *args = a; ++ ++ args->worker_continue = false; ++ ++ { ++ /* Protects global and module specific TLS state. */ ++ __rtld_lock_lock_recursive (GL(dl_load_tls_lock)); ++ ++ struct dl_exception ex; ++ int err = _dl_catch_exception (&ex, dl_open_worker_begin, args); ++ ++ __rtld_lock_unlock_recursive (GL(dl_load_tls_lock)); ++ ++ if (__glibc_unlikely (ex.errstring != NULL)) ++ /* Reraise the error. */ ++ _dl_signal_exception (err, &ex, NULL); ++ } ++ ++ if (!args->worker_continue) ++ return; ++ ++ int mode = args->mode; ++ struct link_map *new = args->map; ++ + /* Run the initializer functions of new objects. Temporarily + disable the exception handler, so that lazy binding failures are + fatal. */ +diff --git a/elf/dl-support.c b/elf/dl-support.c +index 34be8e5babfb6af3..3e5531138eaa18f8 100644 +--- a/elf/dl-support.c ++++ b/elf/dl-support.c +@@ -212,6 +212,13 @@ __rtld_lock_define_initialized_recursive (, _dl_load_lock) + list of loaded objects while an object is added to or removed from + that list. */ + __rtld_lock_define_initialized_recursive (, _dl_load_write_lock) ++ /* This lock protects global and module specific TLS related data. ++ E.g. it is held in dlopen and dlclose when GL(dl_tls_generation), ++ GL(dl_tls_max_dtv_idx) or GL(dl_tls_dtv_slotinfo_list) are ++ accessed and when TLS related relocations are processed for a ++ module. It was introduced to keep pthread_create accessing TLS ++ state that is being set up. */ ++__rtld_lock_define_initialized_recursive (, _dl_load_tls_lock) + + + #ifdef HAVE_AUX_VECTOR +diff --git a/elf/dl-tls.c b/elf/dl-tls.c +index 8c0f9e972d7a0eac..7865fc390c3f3f0a 100644 +--- a/elf/dl-tls.c ++++ b/elf/dl-tls.c +@@ -527,7 +527,7 @@ _dl_allocate_tls_init (void *result) + size_t maxgen = 0; + + /* Protects global dynamic TLS related state. */ +- __rtld_lock_lock_recursive (GL(dl_load_lock)); ++ __rtld_lock_lock_recursive (GL(dl_load_tls_lock)); + + /* Check if the current dtv is big enough. */ + if (dtv[-1].counter < GL(dl_tls_max_dtv_idx)) +@@ -601,7 +601,7 @@ _dl_allocate_tls_init (void *result) + listp = listp->next; + assert (listp != NULL); + } +- __rtld_lock_unlock_recursive (GL(dl_load_lock)); ++ __rtld_lock_unlock_recursive (GL(dl_load_tls_lock)); + + /* The DTV version is up-to-date now. */ + dtv[0].counter = maxgen; +@@ -740,7 +740,7 @@ _dl_update_slotinfo (unsigned long int req_modid) + + Here the dtv needs to be updated to new_gen generation count. + +- This code may be called during TLS access when GL(dl_load_lock) ++ This code may be called during TLS access when GL(dl_load_tls_lock) + is not held. In that case the user code has to synchronize with + dlopen and dlclose calls of relevant modules. A module m is + relevant if the generation of m <= new_gen and dlclose of m is +@@ -862,11 +862,11 @@ tls_get_addr_tail (GET_ADDR_ARGS, dtv_t *dtv, struct link_map *the_map) + if (__glibc_unlikely (the_map->l_tls_offset + != FORCED_DYNAMIC_TLS_OFFSET)) + { +- __rtld_lock_lock_recursive (GL(dl_load_lock)); ++ __rtld_lock_lock_recursive (GL(dl_load_tls_lock)); + if (__glibc_likely (the_map->l_tls_offset == NO_TLS_OFFSET)) + { + the_map->l_tls_offset = FORCED_DYNAMIC_TLS_OFFSET; +- __rtld_lock_unlock_recursive (GL(dl_load_lock)); ++ __rtld_lock_unlock_recursive (GL(dl_load_tls_lock)); + } + else if (__glibc_likely (the_map->l_tls_offset + != FORCED_DYNAMIC_TLS_OFFSET)) +@@ -878,7 +878,7 @@ tls_get_addr_tail (GET_ADDR_ARGS, dtv_t *dtv, struct link_map *the_map) + #else + # error "Either TLS_TCB_AT_TP or TLS_DTV_AT_TP must be defined" + #endif +- __rtld_lock_unlock_recursive (GL(dl_load_lock)); ++ __rtld_lock_unlock_recursive (GL(dl_load_tls_lock)); + + dtv[GET_ADDR_MODULE].pointer.to_free = NULL; + dtv[GET_ADDR_MODULE].pointer.val = p; +@@ -886,7 +886,7 @@ tls_get_addr_tail (GET_ADDR_ARGS, dtv_t *dtv, struct link_map *the_map) + return (char *) p + GET_ADDR_OFFSET; + } + else +- __rtld_lock_unlock_recursive (GL(dl_load_lock)); ++ __rtld_lock_unlock_recursive (GL(dl_load_tls_lock)); + } + struct dtv_pointer result = allocate_and_init (the_map); + dtv[GET_ADDR_MODULE].pointer = result; +@@ -957,7 +957,7 @@ _dl_tls_get_addr_soft (struct link_map *l) + return NULL; + + dtv_t *dtv = THREAD_DTV (); +- /* This may be called without holding the GL(dl_load_lock). Reading ++ /* This may be called without holding the GL(dl_load_tls_lock). Reading + arbitrary gen value is fine since this is best effort code. */ + size_t gen = atomic_load_relaxed (&GL(dl_tls_generation)); + if (__glibc_unlikely (dtv[0].counter != gen)) +diff --git a/elf/rtld.c b/elf/rtld.c +index 118c454a2329573f..9e09896da078274d 100644 +--- a/elf/rtld.c ++++ b/elf/rtld.c +@@ -317,6 +317,7 @@ struct rtld_global _rtld_global = + #ifdef _LIBC_REENTRANT + ._dl_load_lock = _RTLD_LOCK_RECURSIVE_INITIALIZER, + ._dl_load_write_lock = _RTLD_LOCK_RECURSIVE_INITIALIZER, ++ ._dl_load_tls_lock = _RTLD_LOCK_RECURSIVE_INITIALIZER, + #endif + ._dl_nns = 1, + ._dl_ns = +diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h +index 0138353ccb41c5f1..7b0a667629ddc06a 100644 +--- a/sysdeps/generic/ldsodefs.h ++++ b/sysdeps/generic/ldsodefs.h +@@ -373,6 +373,13 @@ struct rtld_global + list of loaded objects while an object is added to or removed + from that list. */ + __rtld_lock_define_recursive (EXTERN, _dl_load_write_lock) ++ /* This lock protects global and module specific TLS related data. ++ E.g. it is held in dlopen and dlclose when GL(dl_tls_generation), ++ GL(dl_tls_max_dtv_idx) or GL(dl_tls_dtv_slotinfo_list) are ++ accessed and when TLS related relocations are processed for a ++ module. It was introduced to keep pthread_create accessing TLS ++ state that is being set up. */ ++ __rtld_lock_define_recursive (EXTERN, _dl_load_tls_lock) + + /* Incremented whenever something may have been added to dl_loaded. */ + EXTERN unsigned long long _dl_load_adds; +@@ -1192,7 +1199,7 @@ extern int _dl_scope_free (void *) attribute_hidden; + + /* Add module to slot information data. If DO_ADD is false, only the + required memory is allocated. Must be called with GL +- (dl_load_lock) acquired. If the function has already been called ++ (dl_load_tls_lock) acquired. If the function has already been called + for the link map L with !do_add, then this function will not raise + an exception, otherwise it is possible that it encounters a memory + allocation failure. */ +diff --git a/sysdeps/nptl/fork.c b/sysdeps/nptl/fork.c +index 37db30f3d1e846b6..b4d20fa652f4ba3b 100644 +--- a/sysdeps/nptl/fork.c ++++ b/sysdeps/nptl/fork.c +@@ -125,6 +125,9 @@ __libc_fork (void) + /* Reset the lock the dynamic loader uses to protect its data. */ + __rtld_lock_initialize (GL(dl_load_lock)); + ++ /* Reset the lock protecting dynamic TLS related data. */ ++ __rtld_lock_initialize (GL(dl_load_tls_lock)); ++ + /* Run the handlers registered for the child. */ + __run_fork_handlers (atfork_run_child, multiple_threads); + } +diff --git a/sysdeps/pthread/Makefile b/sysdeps/pthread/Makefile +index ea4f8894891b2636..98a92f8d6bb119ba 100644 +--- a/sysdeps/pthread/Makefile ++++ b/sysdeps/pthread/Makefile +@@ -25,3 +25,24 @@ $(objpfx)tst-timer: $(objpfx)librt.a $(static-thread-library) + endif + + endif ++ ++ifneq (,$(filter $(subdir),htl nptl)) ++ifeq ($(build-shared),yes) ++tests += tst-create1 ++endif ++ ++tst-create1mod.so-no-z-defs = yes ++ ++ifeq ($(build-shared),yes) ++# Build all the modules even when not actually running test programs. ++tests: $(test-modules) ++endif ++ ++modules-names += tst-create1mod ++test-modules = $(addprefix $(objpfx),$(addsuffix .so,$(modules-names))) ++ ++LDFLAGS-tst-create1 = -Wl,-export-dynamic ++$(objpfx)tst-create1: $(libdl) $(shared-thread-library) ++$(objpfx)tst-create1.out: $(objpfx)tst-create1mod.so ++ ++endif +diff --git a/sysdeps/pthread/tst-create1.c b/sysdeps/pthread/tst-create1.c +new file mode 100644 +index 0000000000000000..932586c30990d1d4 +--- /dev/null ++++ b/sysdeps/pthread/tst-create1.c +@@ -0,0 +1,119 @@ ++/* Verify that pthread_create does not deadlock when ctors take locks. ++ 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 ++ ++/* ++Check if ctor and pthread_create deadlocks in ++ ++thread 1: dlopen -> ctor -> lock(user_lock) ++thread 2: lock(user_lock) -> pthread_create ++ ++or in ++ ++thread 1: dlclose -> dtor -> lock(user_lock) ++thread 2: lock(user_lock) -> pthread_create ++*/ ++ ++static pthread_barrier_t bar_ctor; ++static pthread_barrier_t bar_dtor; ++static pthread_mutex_t user_lock = PTHREAD_MUTEX_INITIALIZER; ++ ++void ++ctor (void) ++{ ++ xpthread_barrier_wait (&bar_ctor); ++ dprintf (1, "thread 1: in ctor: started.\n"); ++ xpthread_mutex_lock (&user_lock); ++ dprintf (1, "thread 1: in ctor: locked user_lock.\n"); ++ xpthread_mutex_unlock (&user_lock); ++ dprintf (1, "thread 1: in ctor: unlocked user_lock.\n"); ++ dprintf (1, "thread 1: in ctor: done.\n"); ++} ++ ++void ++dtor (void) ++{ ++ xpthread_barrier_wait (&bar_dtor); ++ dprintf (1, "thread 1: in dtor: started.\n"); ++ xpthread_mutex_lock (&user_lock); ++ dprintf (1, "thread 1: in dtor: locked user_lock.\n"); ++ xpthread_mutex_unlock (&user_lock); ++ dprintf (1, "thread 1: in dtor: unlocked user_lock.\n"); ++ dprintf (1, "thread 1: in dtor: done.\n"); ++} ++ ++static void * ++thread3 (void *a) ++{ ++ dprintf (1, "thread 3: started.\n"); ++ dprintf (1, "thread 3: done.\n"); ++ return 0; ++} ++ ++static void * ++thread2 (void *a) ++{ ++ pthread_t t3; ++ dprintf (1, "thread 2: started.\n"); ++ ++ xpthread_mutex_lock (&user_lock); ++ dprintf (1, "thread 2: locked user_lock.\n"); ++ xpthread_barrier_wait (&bar_ctor); ++ t3 = xpthread_create (0, thread3, 0); ++ xpthread_mutex_unlock (&user_lock); ++ dprintf (1, "thread 2: unlocked user_lock.\n"); ++ xpthread_join (t3); ++ ++ xpthread_mutex_lock (&user_lock); ++ dprintf (1, "thread 2: locked user_lock.\n"); ++ xpthread_barrier_wait (&bar_dtor); ++ t3 = xpthread_create (0, thread3, 0); ++ xpthread_mutex_unlock (&user_lock); ++ dprintf (1, "thread 2: unlocked user_lock.\n"); ++ xpthread_join (t3); ++ ++ dprintf (1, "thread 2: done.\n"); ++ return 0; ++} ++ ++static void ++thread1 (void) ++{ ++ dprintf (1, "thread 1: started.\n"); ++ xpthread_barrier_init (&bar_ctor, NULL, 2); ++ xpthread_barrier_init (&bar_dtor, NULL, 2); ++ pthread_t t2 = xpthread_create (0, thread2, 0); ++ void *p = xdlopen ("tst-create1mod.so", RTLD_NOW | RTLD_GLOBAL); ++ dprintf (1, "thread 1: dlopen done.\n"); ++ xdlclose (p); ++ dprintf (1, "thread 1: dlclose done.\n"); ++ xpthread_join (t2); ++ dprintf (1, "thread 1: done.\n"); ++} ++ ++static int ++do_test (void) ++{ ++ thread1 (); ++ return 0; ++} ++ ++#include +diff --git a/sysdeps/pthread/tst-create1mod.c b/sysdeps/pthread/tst-create1mod.c +new file mode 100644 +index 0000000000000000..62c9006961683177 +--- /dev/null ++++ b/sysdeps/pthread/tst-create1mod.c +@@ -0,0 +1,41 @@ ++/* Verify that pthread_create does not deadlock when ctors take locks. ++ 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 ++ ++/* Require TLS setup for the module. */ ++__thread int tlsvar; ++ ++void ctor (void); ++void dtor (void); ++ ++static void __attribute__ ((constructor)) ++do_init (void) ++{ ++ dprintf (1, "constructor started: %d.\n", tlsvar++); ++ ctor (); ++ dprintf (1, "constructor done: %d.\n", tlsvar++); ++} ++ ++static void __attribute__ ((destructor)) ++do_end (void) ++{ ++ dprintf (1, "destructor started: %d.\n", tlsvar++); ++ dtor (); ++ dprintf (1, "destructor done: %d.\n", tlsvar++); ++} diff --git a/SOURCES/glibc-rh1991001-2.patch b/SOURCES/glibc-rh1991001-2.patch new file mode 100644 index 0000000..468fc03 --- /dev/null +++ b/SOURCES/glibc-rh1991001-2.patch @@ -0,0 +1,28 @@ +commit d2b997c7172e9a00895a9deb379f8782fbd2e36f +Author: Szabolcs Nagy +Date: Wed Dec 30 23:40:14 2020 +0000 + + elf: Fix a DTV setup issue [BZ #27136] + + The max modid is a valid index in the dtv, it should not be skipped. + + The bug is observable if the last module has modid == 64 and its + generation is same or less than the max generation of the previous + modules. Then dtv[0].counter implies dtv[64] is initialized but + it isn't. Fixes bug 27136. + + Reviewed-by: Adhemerval Zanella + +diff --git a/elf/dl-tls.c b/elf/dl-tls.c +index cccf74b33481b866..0b96b1dceed99d58 100644 +--- a/elf/dl-tls.c ++++ b/elf/dl-tls.c +@@ -590,7 +590,7 @@ _dl_allocate_tls_init (void *result) + } + + total += cnt; +- if (total >= GL(dl_tls_max_dtv_idx)) ++ if (total > GL(dl_tls_max_dtv_idx)) + break; + + listp = listp->next; diff --git a/SOURCES/glibc-rh1991001-20.patch b/SOURCES/glibc-rh1991001-20.patch new file mode 100644 index 0000000..d8aedcc --- /dev/null +++ b/SOURCES/glibc-rh1991001-20.patch @@ -0,0 +1,20 @@ +commit 3c7c5117826816021f9d3f352f49e0dd0236cbad +Author: Florian Weimer +Date: Tue Nov 30 14:35:54 2021 +0100 + + elf: Include in tst-tls20.c + + The test uses standard integer types. + +diff --git a/elf/tst-tls20.c b/elf/tst-tls20.c +index 831c3336c914790d..18067e6b0a6093f9 100644 +--- a/elf/tst-tls20.c ++++ b/elf/tst-tls20.c +@@ -19,6 +19,7 @@ + #include + #include + #include ++#include + #include + #include + #include diff --git a/SOURCES/glibc-rh1991001-21.patch b/SOURCES/glibc-rh1991001-21.patch new file mode 100644 index 0000000..c4e1316 --- /dev/null +++ b/SOURCES/glibc-rh1991001-21.patch @@ -0,0 +1,20 @@ +commit df4cb2280e32187380520f71bd27ab32252cbc85 +Author: Florian Weimer +Date: Tue Nov 30 15:39:17 2021 +0100 + + elf: Include in tst-tls20.c + + The test uses the bool type. + +diff --git a/elf/tst-tls20.c b/elf/tst-tls20.c +index 18067e6b0a6093f9..200dacb748af21a8 100644 +--- a/elf/tst-tls20.c ++++ b/elf/tst-tls20.c +@@ -19,6 +19,7 @@ + #include + #include + #include ++#include + #include + #include + #include diff --git a/SOURCES/glibc-rh1991001-22.patch b/SOURCES/glibc-rh1991001-22.patch new file mode 100644 index 0000000..490e909 --- /dev/null +++ b/SOURCES/glibc-rh1991001-22.patch @@ -0,0 +1,62 @@ +commit 5cc338565479a620244c2f8ff35956629c4dbf81 +Author: Florian Weimer +Date: Fri Dec 10 05:14:24 2021 +0100 + + nptl: Add one more barrier to nptl/tst-create1 + + Without the bar_ctor_finish barrier, it was possible that thread2 + re-locked user_lock before ctor had a chance to lock it. ctor then + blocked in its locking operation, xdlopen from the main thread + did not return, and thread2 was stuck waiting in bar_dtor: + + thread 1: started. + thread 2: started. + thread 2: locked user_lock. + constructor started: 0. + thread 1: in ctor: started. + thread 3: started. + thread 3: done. + thread 2: unlocked user_lock. + thread 2: locked user_lock. + + Fixes the test in commit 83b5323261bb72313bffcf37476c1b8f0847c736 + ("elf: Avoid deadlock between pthread_create and ctors [BZ #28357]"). + + Reviewed-by: Szabolcs Nagy + +diff --git a/sysdeps/pthread/tst-create1.c b/sysdeps/pthread/tst-create1.c +index 932586c30990d1d4..763ded8d7956f943 100644 +--- a/sysdeps/pthread/tst-create1.c ++++ b/sysdeps/pthread/tst-create1.c +@@ -33,6 +33,7 @@ thread 2: lock(user_lock) -> pthread_create + */ + + static pthread_barrier_t bar_ctor; ++static pthread_barrier_t bar_ctor_finish; + static pthread_barrier_t bar_dtor; + static pthread_mutex_t user_lock = PTHREAD_MUTEX_INITIALIZER; + +@@ -46,6 +47,7 @@ ctor (void) + xpthread_mutex_unlock (&user_lock); + dprintf (1, "thread 1: in ctor: unlocked user_lock.\n"); + dprintf (1, "thread 1: in ctor: done.\n"); ++ xpthread_barrier_wait (&bar_ctor_finish); + } + + void +@@ -81,6 +83,7 @@ thread2 (void *a) + xpthread_mutex_unlock (&user_lock); + dprintf (1, "thread 2: unlocked user_lock.\n"); + xpthread_join (t3); ++ xpthread_barrier_wait (&bar_ctor_finish); + + xpthread_mutex_lock (&user_lock); + dprintf (1, "thread 2: locked user_lock.\n"); +@@ -99,6 +102,7 @@ thread1 (void) + { + dprintf (1, "thread 1: started.\n"); + xpthread_barrier_init (&bar_ctor, NULL, 2); ++ xpthread_barrier_init (&bar_ctor_finish, NULL, 2); + xpthread_barrier_init (&bar_dtor, NULL, 2); + pthread_t t2 = xpthread_create (0, thread2, 0); + void *p = xdlopen ("tst-create1mod.so", RTLD_NOW | RTLD_GLOBAL); diff --git a/SOURCES/glibc-rh1991001-3.patch b/SOURCES/glibc-rh1991001-3.patch new file mode 100644 index 0000000..85a9cd7 --- /dev/null +++ b/SOURCES/glibc-rh1991001-3.patch @@ -0,0 +1,163 @@ +commit 8f85075a2e9c26ff7486d4bbaf358999807d215c +Author: Szabolcs Nagy +Date: Thu Dec 31 12:24:38 2020 +0000 + + elf: Add a DTV setup test [BZ #27136] + + The test dlopens a large number of modules with TLS, they are reused + from an existing test. + + The test relies on the reuse of slotinfo entries after dlclose, without + bug 27135 fixed this needs a failing dlopen. With a slotinfo list that + has non-monotone increasing generation counters, bug 27136 can trigger. + + Reviewed-by: Adhemerval Zanella + +Conflicts: + elf/Makefile + (usual test differences) + +diff --git a/elf/Makefile b/elf/Makefile +index 82fb019a634caf81..0995d810b57d0dda 100644 +--- a/elf/Makefile ++++ b/elf/Makefile +@@ -209,7 +209,8 @@ tests += restest1 preloadtest loadfail multiload origtest resolvfail \ + 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-glibc-hwcaps tst-glibc-hwcaps-prepend tst-glibc-hwcaps-mask \ ++ tst-tls20 + # reldep9 + tests-internal += loadtest unload unload2 circleload1 \ + neededtest neededtest2 neededtest3 neededtest4 \ +@@ -332,6 +333,7 @@ modules-names = testobj1 testobj2 testobj3 testobj4 testobj5 testobj6 \ + libmarkermod2-1 libmarkermod2-2 \ + libmarkermod3-1 libmarkermod3-2 libmarkermod3-3 \ + libmarkermod4-1 libmarkermod4-2 libmarkermod4-3 libmarkermod4-4 \ ++ tst-tls20mod-bad + + # Most modules build with _ISOMAC defined, but those filtered out + # depend on internal headers. +@@ -1828,3 +1830,9 @@ $(objpfx)tst-rtld-help.out: $(objpfx)ld.so + fi; \ + (exit $$status); \ + $(evaluate-test) ++ ++# Reuses tst-tls-many-dynamic-modules ++tst-tls20mod-bad.so-no-z-defs = yes ++$(objpfx)tst-tls20: $(libdl) $(shared-thread-library) ++$(objpfx)tst-tls20.out: $(objpfx)tst-tls20mod-bad.so \ ++ $(tst-tls-many-dynamic-modules:%=$(objpfx)%.so) +diff --git a/elf/tst-tls20.c b/elf/tst-tls20.c +new file mode 100644 +index 0000000000000000..ac5f8c8d39b66dd6 +--- /dev/null ++++ b/elf/tst-tls20.c +@@ -0,0 +1,98 @@ ++/* Test dtv setup if entries don't have monotone increasing generation. ++ 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 ++ ++#define NMOD 100 ++static void *mod[NMOD]; ++ ++static void ++load_fail (void) ++{ ++ /* Expected to fail because of a missing symbol. */ ++ void *m = dlopen ("tst-tls20mod-bad.so", RTLD_NOW); ++ if (m != NULL) ++ FAIL_EXIT1 ("dlopen of tst-tls20mod-bad.so succeeded\n"); ++} ++ ++static void ++load_mod (int i) ++{ ++ char *buf = xasprintf ("tst-tls-manydynamic%02dmod.so", i); ++ mod[i] = xdlopen (buf, RTLD_LAZY); ++ free (buf); ++} ++ ++static void ++unload_mod (int i) ++{ ++ if (mod[i] != NULL) ++ xdlclose (mod[i]); ++ mod[i] = NULL; ++} ++ ++static void ++access (int i) ++{ ++ char *buf = xasprintf ("tls_global_%02d", i); ++ dlerror (); ++ int *p = dlsym (mod[i], buf); ++ printf ("mod[%d]: &tls = %p\n", i, p); ++ if (p == NULL) ++ FAIL_EXIT1 ("dlsym failed: %s\n", dlerror ()); ++ ++*p; ++ free (buf); ++} ++ ++static void * ++start (void *a) ++{ ++ for (int i = 0; i < NMOD; i++) ++ if (mod[i] != NULL) ++ access (i); ++ return 0; ++} ++ ++static int ++do_test (void) ++{ ++ int i; ++ ++ for (i = 0; i < NMOD; i++) ++ { ++ load_mod (i); ++ /* Bump the generation of mod[0] without using new dtv slot. */ ++ unload_mod (0); ++ load_fail (); /* Ensure GL(dl_tls_dtv_gaps) is true: see bug 27135. */ ++ load_mod (0); ++ /* Access TLS in all loaded modules. */ ++ pthread_t t = xpthread_create (0, start, 0); ++ xpthread_join (t); ++ } ++ for (i = 0; i < NMOD; i++) ++ unload_mod (i); ++ return 0; ++} ++ ++#include +diff --git a/elf/tst-tls20mod-bad.c b/elf/tst-tls20mod-bad.c +new file mode 100644 +index 0000000000000000..c1aed8ea7deffd22 +--- /dev/null ++++ b/elf/tst-tls20mod-bad.c +@@ -0,0 +1,2 @@ ++void missing_symbol (void); ++void f (void) {missing_symbol ();} diff --git a/SOURCES/glibc-rh1991001-4.patch b/SOURCES/glibc-rh1991001-4.patch new file mode 100644 index 0000000..c8650bb --- /dev/null +++ b/SOURCES/glibc-rh1991001-4.patch @@ -0,0 +1,41 @@ +commit c489c35054c39d7f2437ca61b369e3ede448f022 +Author: Szabolcs Nagy +Date: Wed Nov 30 11:44:25 2016 +0000 + + elf: Fix comments and logic in _dl_add_to_slotinfo + + Since + + commit a509eb117fac1d764b15eba64993f4bdb63d7f3c + Avoid late dlopen failure due to scope, TLS slotinfo updates [BZ #25112] + + the generation counter update is not needed in the failure path. + That commit ensures allocation in _dl_add_to_slotinfo happens before + the demarcation point in dlopen (it is called twice, first time is for + allocation only where dlopen can still be reverted on failure, then + second time actual dtv updates are done which then cannot fail). + + Reviewed-by: Adhemerval Zanella + +diff --git a/elf/dl-tls.c b/elf/dl-tls.c +index 0b96b1dceed99d58..9375650a3ab5247d 100644 +--- a/elf/dl-tls.c ++++ b/elf/dl-tls.c +@@ -998,16 +998,7 @@ _dl_add_to_slotinfo (struct link_map *l, bool do_add) + + TLS_SLOTINFO_SURPLUS * sizeof (struct dtv_slotinfo)); + if (listp == NULL) + { +- /* We ran out of memory. We will simply fail this +- call but don't undo anything we did so far. The +- application will crash or be terminated anyway very +- soon. */ +- +- /* We have to do this since some entries in the dtv +- slotinfo array might already point to this +- generation. */ +- ++GL(dl_tls_generation); +- ++ /* We ran out of memory while resizing the dtv slotinfo list. */ + _dl_signal_error (ENOMEM, "dlopen", NULL, N_("\ + cannot create TLS data structures")); + } diff --git a/SOURCES/glibc-rh1991001-5.patch b/SOURCES/glibc-rh1991001-5.patch new file mode 100644 index 0000000..735e348 --- /dev/null +++ b/SOURCES/glibc-rh1991001-5.patch @@ -0,0 +1,58 @@ +commit c0669ae1a629e16b536bf11cdd0865e0dbcf4bee +Author: Szabolcs Nagy +Date: Wed Dec 30 21:52:38 2020 +0000 + + elf: Refactor _dl_update_slotinfo to avoid use after free + + map is not valid to access here because it can be freed by a concurrent + dlclose: during tls access (via __tls_get_addr) _dl_update_slotinfo is + called without holding dlopen locks. So don't check the modid of map. + + The map == 0 and map != 0 code paths can be shared (avoiding the dtv + resize in case of map == 0 is just an optimization: larger dtv than + necessary would be fine too). + + Reviewed-by: Adhemerval Zanella + +diff --git a/elf/dl-tls.c b/elf/dl-tls.c +index 9375650a3ab5247d..15ed01d795a8627a 100644 +--- a/elf/dl-tls.c ++++ b/elf/dl-tls.c +@@ -743,6 +743,8 @@ _dl_update_slotinfo (unsigned long int req_modid) + { + for (size_t cnt = total == 0 ? 1 : 0; cnt < listp->len; ++cnt) + { ++ size_t modid = total + cnt; ++ + size_t gen = listp->slotinfo[cnt].gen; + + if (gen > new_gen) +@@ -758,25 +760,12 @@ _dl_update_slotinfo (unsigned long int req_modid) + + /* If there is no map this means the entry is empty. */ + struct link_map *map = listp->slotinfo[cnt].map; +- if (map == NULL) +- { +- if (dtv[-1].counter >= total + cnt) +- { +- /* If this modid was used at some point the memory +- might still be allocated. */ +- free (dtv[total + cnt].pointer.to_free); +- dtv[total + cnt].pointer.val = TLS_DTV_UNALLOCATED; +- dtv[total + cnt].pointer.to_free = NULL; +- } +- +- continue; +- } +- + /* Check whether the current dtv array is large enough. */ +- size_t modid = map->l_tls_modid; +- assert (total + cnt == modid); + if (dtv[-1].counter < modid) + { ++ if (map == NULL) ++ continue; ++ + /* Resize the dtv. */ + dtv = _dl_resize_dtv (dtv); + diff --git a/SOURCES/glibc-rh1991001-6.patch b/SOURCES/glibc-rh1991001-6.patch new file mode 100644 index 0000000..03505b0 --- /dev/null +++ b/SOURCES/glibc-rh1991001-6.patch @@ -0,0 +1,48 @@ +commit 8f7e09f4dbdb5c815a18b8285fbc5d5d7bc17d86 +Author: Szabolcs Nagy +Date: Thu Feb 11 11:29:23 2021 +0000 + + x86_64: Avoid lazy relocation of tlsdesc [BZ #27137] + + Lazy tlsdesc relocation is racy because the static tls optimization and + tlsdesc management operations are done without holding the dlopen lock. + + This similar to the commit b7cf203b5c17dd6d9878537d41e0c7cc3d270a67 + for aarch64, but it fixes a different race: bug 27137. + + Another issue is that ld auditing ignores DT_BIND_NOW and thus tries to + relocate tlsdesc lazily, but that does not work in a BIND_NOW module + due to missing DT_TLSDESC_PLT. Unconditionally relocating tlsdesc at + load time fixes this bug 27721 too. + +diff --git a/sysdeps/x86_64/dl-machine.h b/sysdeps/x86_64/dl-machine.h +index e308b662d245cc63..ef5740ba281c7282 100644 +--- a/sysdeps/x86_64/dl-machine.h ++++ b/sysdeps/x86_64/dl-machine.h +@@ -563,12 +563,21 @@ elf_machine_lazy_rel (struct link_map *map, + } + else if (__glibc_likely (r_type == R_X86_64_TLSDESC)) + { +- struct tlsdesc volatile * __attribute__((__unused__)) td = +- (struct tlsdesc volatile *)reloc_addr; ++ const Elf_Symndx symndx = ELFW (R_SYM) (reloc->r_info); ++ const ElfW (Sym) *symtab = (const void *)D_PTR (map, l_info[DT_SYMTAB]); ++ const ElfW (Sym) *sym = &symtab[symndx]; ++ const struct r_found_version *version = NULL; + +- td->arg = (void*)reloc; +- td->entry = (void*)(D_PTR (map, l_info[ADDRIDX (DT_TLSDESC_PLT)]) +- + map->l_addr); ++ if (map->l_info[VERSYMIDX (DT_VERSYM)] != NULL) ++ { ++ const ElfW (Half) *vernum = ++ (const void *)D_PTR (map, l_info[VERSYMIDX (DT_VERSYM)]); ++ version = &map->l_versions[vernum[symndx] & 0x7fff]; ++ } ++ ++ /* 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); + } + else if (__glibc_unlikely (r_type == R_X86_64_IRELATIVE)) + { diff --git a/SOURCES/glibc-rh1991001-7.patch b/SOURCES/glibc-rh1991001-7.patch new file mode 100644 index 0000000..0d7da7f --- /dev/null +++ b/SOURCES/glibc-rh1991001-7.patch @@ -0,0 +1,116 @@ +commit ddcacd91cc10ff92d6201eda87047d029c14158d +Author: Szabolcs Nagy +Date: Thu Feb 11 11:40:11 2021 +0000 + + i386: Avoid lazy relocation of tlsdesc [BZ #27137] + + Lazy tlsdesc relocation is racy because the static tls optimization and + tlsdesc management operations are done without holding the dlopen lock. + + This similar to the commit b7cf203b5c17dd6d9878537d41e0c7cc3d270a67 + for aarch64, but it fixes a different race: bug 27137. + + On i386 the code is a bit more complicated than on x86_64 because both + rel and rela relocs are supported. + +diff --git a/sysdeps/i386/dl-machine.h b/sysdeps/i386/dl-machine.h +index e5776ef7bc8ad749..3a30671591284d79 100644 +--- a/sysdeps/i386/dl-machine.h ++++ b/sysdeps/i386/dl-machine.h +@@ -679,50 +679,32 @@ elf_machine_lazy_rel (struct link_map *map, + } + else if (__glibc_likely (r_type == R_386_TLS_DESC)) + { +- struct tlsdesc volatile * __attribute__((__unused__)) td = +- (struct tlsdesc volatile *)reloc_addr; +- +- /* Handle relocations that reference the local *ABS* in a simple +- way, so as to preserve a potential addend. */ +- if (ELF32_R_SYM (reloc->r_info) == 0) +- td->entry = _dl_tlsdesc_resolve_abs_plus_addend; +- /* Given a known-zero addend, we can store a pointer to the +- reloc in the arg position. */ +- else if (td->arg == 0) +- { +- td->arg = (void*)reloc; +- td->entry = _dl_tlsdesc_resolve_rel; +- } +- else +- { +- /* We could handle non-*ABS* relocations with non-zero addends +- by allocating dynamically an arg to hold a pointer to the +- reloc, but that sounds pointless. */ +- const Elf32_Rel *const r = reloc; +- /* The code below was borrowed from elf_dynamic_do_rel(). */ +- const ElfW(Sym) *const symtab = +- (const void *) D_PTR (map, l_info[DT_SYMTAB]); ++ const Elf32_Rel *const r = reloc; ++ /* The code below was borrowed from elf_dynamic_do_rel(). */ ++ const ElfW(Sym) *const symtab = ++ (const void *) D_PTR (map, l_info[DT_SYMTAB]); + ++ /* Always initialize TLS descriptors completely at load time, in ++ case static TLS is allocated for it that requires locking. */ + # ifdef RTLD_BOOTSTRAP +- /* The dynamic linker always uses versioning. */ +- assert (map->l_info[VERSYMIDX (DT_VERSYM)] != NULL); ++ /* The dynamic linker always uses versioning. */ ++ assert (map->l_info[VERSYMIDX (DT_VERSYM)] != NULL); + # else +- if (map->l_info[VERSYMIDX (DT_VERSYM)]) ++ if (map->l_info[VERSYMIDX (DT_VERSYM)]) + # endif +- { +- 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)], +- &map->l_versions[ndx], +- (void *) (l_addr + r->r_offset), skip_ifunc); +- } ++ { ++ 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)], ++ &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, +- (void *) (l_addr + r->r_offset), skip_ifunc); ++ else ++ elf_machine_rel (map, r, &symtab[ELFW(R_SYM) (r->r_info)], NULL, ++ (void *) (l_addr + r->r_offset), skip_ifunc); + # endif +- } + } + else if (__glibc_unlikely (r_type == R_386_IRELATIVE)) + { +@@ -749,11 +731,21 @@ elf_machine_lazy_rela (struct link_map *map, + ; + else if (__glibc_likely (r_type == R_386_TLS_DESC)) + { +- struct tlsdesc volatile * __attribute__((__unused__)) td = +- (struct tlsdesc volatile *)reloc_addr; ++ const Elf_Symndx symndx = ELFW (R_SYM) (reloc->r_info); ++ const ElfW (Sym) *symtab = (const void *)D_PTR (map, l_info[DT_SYMTAB]); ++ const ElfW (Sym) *sym = &symtab[symndx]; ++ const struct r_found_version *version = NULL; ++ ++ if (map->l_info[VERSYMIDX (DT_VERSYM)] != NULL) ++ { ++ const ElfW (Half) *vernum = ++ (const void *)D_PTR (map, l_info[VERSYMIDX (DT_VERSYM)]); ++ version = &map->l_versions[vernum[symndx] & 0x7fff]; ++ } + +- td->arg = (void*)reloc; +- td->entry = _dl_tlsdesc_resolve_rela; ++ /* 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); + } + else if (__glibc_unlikely (r_type == R_386_IRELATIVE)) + { diff --git a/SOURCES/glibc-rh1991001-8.patch b/SOURCES/glibc-rh1991001-8.patch new file mode 100644 index 0000000..3a1b147 --- /dev/null +++ b/SOURCES/glibc-rh1991001-8.patch @@ -0,0 +1,277 @@ +commit 55c9f3238080e9aba733bc0902779c46cfa16446 +Author: Szabolcs Nagy +Date: Thu Feb 11 11:52:24 2021 +0000 + + x86_64: Remove lazy tlsdesc relocation related code + + _dl_tlsdesc_resolve_rela and _dl_tlsdesc_resolve_hold are only used for + lazy tlsdesc relocation processing which is no longer supported. + +diff --git a/sysdeps/x86_64/dl-machine.h b/sysdeps/x86_64/dl-machine.h +index ef5740ba281c7282..b94d3b39ec1dca64 100644 +--- a/sysdeps/x86_64/dl-machine.h ++++ b/sysdeps/x86_64/dl-machine.h +@@ -127,10 +127,6 @@ elf_machine_runtime_setup (struct link_map *l, int lazy, int profile) + } + } + +- if (l->l_info[ADDRIDX (DT_TLSDESC_GOT)] && lazy) +- *(ElfW(Addr)*)(D_PTR (l, l_info[ADDRIDX (DT_TLSDESC_GOT)]) + l->l_addr) +- = (ElfW(Addr)) &_dl_tlsdesc_resolve_rela; +- + return lazy; + } + +diff --git a/sysdeps/x86_64/dl-tlsdesc.S b/sysdeps/x86_64/dl-tlsdesc.S +index 80d771cd887dd626..77e78cf0a6d8babc 100644 +--- a/sysdeps/x86_64/dl-tlsdesc.S ++++ b/sysdeps/x86_64/dl-tlsdesc.S +@@ -148,107 +148,3 @@ _dl_tlsdesc_dynamic: + cfi_endproc + .size _dl_tlsdesc_dynamic, .-_dl_tlsdesc_dynamic + #endif /* SHARED */ +- +- /* This function is a wrapper for a lazy resolver for TLS_DESC +- RELA relocations. The incoming 0(%rsp) points to the caller's +- link map, pushed by the dynamic object's internal lazy TLS +- resolver front-end before tail-calling us. We need to pop it +- ourselves. %rax points to a TLS descriptor, such that 0(%rax) +- holds the address of the internal resolver front-end (unless +- some other thread beat us to resolving it) and 8(%rax) holds a +- pointer to the relocation. +- +- When the actual resolver returns, it will have adjusted the +- TLS descriptor such that we can tail-call it for it to return +- the TP offset of the symbol. */ +- +- .hidden _dl_tlsdesc_resolve_rela +- .global _dl_tlsdesc_resolve_rela +- .type _dl_tlsdesc_resolve_rela,@function +- cfi_startproc +- .align 16 +- /* The PLT entry will have pushed the link_map pointer. */ +-_dl_tlsdesc_resolve_rela: +- _CET_ENDBR +- cfi_adjust_cfa_offset (8) +- /* Save all call-clobbered registers. Add 8 bytes for push in +- the PLT entry to align the stack. */ +- subq $80, %rsp +- cfi_adjust_cfa_offset (80) +- movq %rax, (%rsp) +- movq %rdi, 8(%rsp) +- movq %rax, %rdi /* Pass tlsdesc* in %rdi. */ +- movq %rsi, 16(%rsp) +- movq 80(%rsp), %rsi /* Pass link_map* in %rsi. */ +- movq %r8, 24(%rsp) +- movq %r9, 32(%rsp) +- movq %r10, 40(%rsp) +- movq %r11, 48(%rsp) +- movq %rdx, 56(%rsp) +- movq %rcx, 64(%rsp) +- call _dl_tlsdesc_resolve_rela_fixup +- movq (%rsp), %rax +- movq 8(%rsp), %rdi +- movq 16(%rsp), %rsi +- movq 24(%rsp), %r8 +- movq 32(%rsp), %r9 +- movq 40(%rsp), %r10 +- movq 48(%rsp), %r11 +- movq 56(%rsp), %rdx +- movq 64(%rsp), %rcx +- addq $88, %rsp +- cfi_adjust_cfa_offset (-88) +- jmp *(%rax) +- cfi_endproc +- .size _dl_tlsdesc_resolve_rela, .-_dl_tlsdesc_resolve_rela +- +- /* This function is a placeholder for lazy resolving of TLS +- relocations. Once some thread starts resolving a TLS +- relocation, it sets up the TLS descriptor to use this +- resolver, such that other threads that would attempt to +- resolve it concurrently may skip the call to the original lazy +- resolver and go straight to a condition wait. +- +- When the actual resolver returns, it will have adjusted the +- TLS descriptor such that we can tail-call it for it to return +- the TP offset of the symbol. */ +- +- .hidden _dl_tlsdesc_resolve_hold +- .global _dl_tlsdesc_resolve_hold +- .type _dl_tlsdesc_resolve_hold,@function +- cfi_startproc +- .align 16 +-_dl_tlsdesc_resolve_hold: +-0: +- _CET_ENDBR +- /* Save all call-clobbered registers. */ +- subq $72, %rsp +- cfi_adjust_cfa_offset (72) +- movq %rax, (%rsp) +- movq %rdi, 8(%rsp) +- movq %rax, %rdi /* Pass tlsdesc* in %rdi. */ +- movq %rsi, 16(%rsp) +- /* Pass _dl_tlsdesc_resolve_hold's address in %rsi. */ +- leaq . - _dl_tlsdesc_resolve_hold(%rip), %rsi +- movq %r8, 24(%rsp) +- movq %r9, 32(%rsp) +- movq %r10, 40(%rsp) +- movq %r11, 48(%rsp) +- movq %rdx, 56(%rsp) +- movq %rcx, 64(%rsp) +- call _dl_tlsdesc_resolve_hold_fixup +-1: +- movq (%rsp), %rax +- movq 8(%rsp), %rdi +- movq 16(%rsp), %rsi +- movq 24(%rsp), %r8 +- movq 32(%rsp), %r9 +- movq 40(%rsp), %r10 +- movq 48(%rsp), %r11 +- movq 56(%rsp), %rdx +- movq 64(%rsp), %rcx +- addq $72, %rsp +- cfi_adjust_cfa_offset (-72) +- jmp *(%rax) +- cfi_endproc +- .size _dl_tlsdesc_resolve_hold, .-_dl_tlsdesc_resolve_hold +diff --git a/sysdeps/x86_64/dl-tlsdesc.h b/sysdeps/x86_64/dl-tlsdesc.h +index 66e659bb5c7ede74..1cde1ee9664f4908 100644 +--- a/sysdeps/x86_64/dl-tlsdesc.h ++++ b/sysdeps/x86_64/dl-tlsdesc.h +@@ -55,9 +55,7 @@ struct tlsdesc_dynamic_arg + + extern ptrdiff_t attribute_hidden + _dl_tlsdesc_return(struct tlsdesc *on_rax), +- _dl_tlsdesc_undefweak(struct tlsdesc *on_rax), +- _dl_tlsdesc_resolve_rela(struct tlsdesc *on_rax), +- _dl_tlsdesc_resolve_hold(struct tlsdesc *on_rax); ++ _dl_tlsdesc_undefweak(struct tlsdesc *on_rax); + + # ifdef SHARED + extern void *_dl_make_tlsdesc_dynamic (struct link_map *map, +diff --git a/sysdeps/x86_64/tlsdesc.c b/sysdeps/x86_64/tlsdesc.c +index 302d097dbb0c4f1e..61a19ae26944c84f 100644 +--- a/sysdeps/x86_64/tlsdesc.c ++++ b/sysdeps/x86_64/tlsdesc.c +@@ -16,120 +16,13 @@ + License along with the GNU C Library; if not, see + . */ + +-#include + #include +-#include + #include + #include + #include ++#define _dl_tlsdesc_resolve_hold 0 + #include + +-/* The following 2 functions take a caller argument, that contains the +- address expected to be in the TLS descriptor. If it's changed, we +- want to return immediately. */ +- +-/* This function is used to lazily resolve TLS_DESC RELA relocations. +- The argument location is used to hold a pointer to the relocation. */ +- +-void +-attribute_hidden +-_dl_tlsdesc_resolve_rela_fixup (struct tlsdesc volatile *td, +- struct link_map *l) +-{ +- const ElfW(Rela) *reloc = td->arg; +- +- if (_dl_tlsdesc_resolve_early_return_p +- (td, (void*)(D_PTR (l, l_info[ADDRIDX (DT_TLSDESC_PLT)]) + l->l_addr))) +- return; +- +- /* The code below was borrowed from _dl_fixup(). */ +- const ElfW(Sym) *const symtab +- = (const void *) D_PTR (l, l_info[DT_SYMTAB]); +- const char *strtab = (const void *) D_PTR (l, l_info[DT_STRTAB]); +- const ElfW(Sym) *sym = &symtab[ELFW(R_SYM) (reloc->r_info)]; +- lookup_t result; +- +- /* Look up the target symbol. If the normal lookup rules are not +- used don't look in the global scope. */ +- if (ELFW(ST_BIND) (sym->st_info) != STB_LOCAL +- && __builtin_expect (ELFW(ST_VISIBILITY) (sym->st_other), 0) == 0) +- { +- const struct r_found_version *version = NULL; +- +- if (l->l_info[VERSYMIDX (DT_VERSYM)] != NULL) +- { +- const ElfW(Half) *vernum = +- (const void *) D_PTR (l, l_info[VERSYMIDX (DT_VERSYM)]); +- ElfW(Half) ndx = vernum[ELFW(R_SYM) (reloc->r_info)] & 0x7fff; +- version = &l->l_versions[ndx]; +- if (version->hash == 0) +- version = NULL; +- } +- +- result = _dl_lookup_symbol_x (strtab + sym->st_name, l, &sym, +- l->l_scope, version, ELF_RTYPE_CLASS_PLT, +- DL_LOOKUP_ADD_DEPENDENCY, NULL); +- } +- else +- { +- /* We already found the symbol. The module (and therefore its load +- address) is also known. */ +- result = l; +- } +- +- if (! sym) +- { +- td->arg = (void*)reloc->r_addend; +- td->entry = _dl_tlsdesc_undefweak; +- } +- else +- { +-# ifndef SHARED +- CHECK_STATIC_TLS (l, result); +-# else +- if (!TRY_STATIC_TLS (l, result)) +- { +- td->arg = _dl_make_tlsdesc_dynamic (result, sym->st_value +- + reloc->r_addend); +- td->entry = _dl_tlsdesc_dynamic; +- } +- else +-# endif +- { +- td->arg = (void*)(sym->st_value - result->l_tls_offset +- + reloc->r_addend); +- td->entry = _dl_tlsdesc_return; +- } +- } +- +- _dl_tlsdesc_wake_up_held_fixups (); +-} +- +-/* This function is used to avoid busy waiting for other threads to +- complete the lazy relocation. Once another thread wins the race to +- relocate a TLS descriptor, it sets the descriptor up such that this +- function is called to wait until the resolver releases the +- lock. */ +- +-void +-attribute_hidden +-_dl_tlsdesc_resolve_hold_fixup (struct tlsdesc volatile *td, +- void *caller) +-{ +- /* Maybe we're lucky and can return early. */ +- if (caller != td->entry) +- return; +- +- /* Locking here will stop execution until the running resolver runs +- _dl_tlsdesc_wake_up_held_fixups(), releasing the lock. +- +- FIXME: We'd be better off waiting on a condition variable, such +- that we didn't have to hold the lock throughout the relocation +- processing. */ +- __rtld_lock_lock_recursive (GL(dl_load_lock)); +- __rtld_lock_unlock_recursive (GL(dl_load_lock)); +-} +- + /* Unmap the dynamic object, but also release its TLS descriptor table + if there is one. */ + diff --git a/SOURCES/glibc-rh1991001-9.patch b/SOURCES/glibc-rh1991001-9.patch new file mode 100644 index 0000000..116739a --- /dev/null +++ b/SOURCES/glibc-rh1991001-9.patch @@ -0,0 +1,443 @@ +commit a75a02a696f9f869d77b17b99964823aa8833a8b +Author: Szabolcs Nagy +Date: Thu Feb 11 11:58:20 2021 +0000 + + i386: Remove lazy tlsdesc relocation related code + + Like in commit e75711ebfa976d5468ec292282566a18b07e4d67 for x86_64, + remove unused lazy tlsdesc relocation processing code: + + _dl_tlsdesc_resolve_abs_plus_addend + _dl_tlsdesc_resolve_rel + _dl_tlsdesc_resolve_rela + _dl_tlsdesc_resolve_hold + +diff --git a/sysdeps/i386/dl-tlsdesc.S b/sysdeps/i386/dl-tlsdesc.S +index 128f0af3188f46bb..22ecb2c6adc6cc6e 100644 +--- a/sysdeps/i386/dl-tlsdesc.S ++++ b/sysdeps/i386/dl-tlsdesc.S +@@ -138,159 +138,3 @@ _dl_tlsdesc_dynamic: + cfi_endproc + .size _dl_tlsdesc_dynamic, .-_dl_tlsdesc_dynamic + #endif /* SHARED */ +- +- /* This function is a wrapper for a lazy resolver for TLS_DESC +- REL relocations that reference the *ABS* segment in their own +- link maps. %ebx points to the caller's GOT. %eax points to a +- TLS descriptor, such that 0(%eax) holds the address of the +- resolver wrapper itself (unless some other thread beat us to +- it) and 4(%eax) holds the addend in the relocation. +- +- When the actual resolver returns, it will have adjusted the +- TLS descriptor such that we can tail-call it for it to return +- the TP offset of the symbol. */ +- +- .hidden _dl_tlsdesc_resolve_abs_plus_addend +- .global _dl_tlsdesc_resolve_abs_plus_addend +- .type _dl_tlsdesc_resolve_abs_plus_addend,@function +- cfi_startproc +- .align 16 +-_dl_tlsdesc_resolve_abs_plus_addend: +-0: +- _CET_ENDBR +- pushl %eax +- cfi_adjust_cfa_offset (4) +- pushl %ecx +- cfi_adjust_cfa_offset (4) +- pushl %edx +- cfi_adjust_cfa_offset (4) +- movl $1f - 0b, %ecx +- movl 4(%ebx), %edx +- call _dl_tlsdesc_resolve_abs_plus_addend_fixup +-1: +- popl %edx +- cfi_adjust_cfa_offset (-4) +- popl %ecx +- cfi_adjust_cfa_offset (-4) +- popl %eax +- cfi_adjust_cfa_offset (-4) +- jmp *(%eax) +- cfi_endproc +- .size _dl_tlsdesc_resolve_abs_plus_addend, .-_dl_tlsdesc_resolve_abs_plus_addend +- +- /* This function is a wrapper for a lazy resolver for TLS_DESC +- REL relocations that had zero addends. %ebx points to the +- caller's GOT. %eax points to a TLS descriptor, such that +- 0(%eax) holds the address of the resolver wrapper itself +- (unless some other thread beat us to it) and 4(%eax) holds a +- pointer to the relocation. +- +- When the actual resolver returns, it will have adjusted the +- TLS descriptor such that we can tail-call it for it to return +- the TP offset of the symbol. */ +- +- .hidden _dl_tlsdesc_resolve_rel +- .global _dl_tlsdesc_resolve_rel +- .type _dl_tlsdesc_resolve_rel,@function +- cfi_startproc +- .align 16 +-_dl_tlsdesc_resolve_rel: +-0: +- _CET_ENDBR +- pushl %eax +- cfi_adjust_cfa_offset (4) +- pushl %ecx +- cfi_adjust_cfa_offset (4) +- pushl %edx +- cfi_adjust_cfa_offset (4) +- movl $1f - 0b, %ecx +- movl 4(%ebx), %edx +- call _dl_tlsdesc_resolve_rel_fixup +-1: +- popl %edx +- cfi_adjust_cfa_offset (-4) +- popl %ecx +- cfi_adjust_cfa_offset (-4) +- popl %eax +- cfi_adjust_cfa_offset (-4) +- jmp *(%eax) +- cfi_endproc +- .size _dl_tlsdesc_resolve_rel, .-_dl_tlsdesc_resolve_rel +- +- /* This function is a wrapper for a lazy resolver for TLS_DESC +- RELA relocations. %ebx points to the caller's GOT. %eax +- points to a TLS descriptor, such that 0(%eax) holds the +- address of the resolver wrapper itself (unless some other +- thread beat us to it) and 4(%eax) holds a pointer to the +- relocation. +- +- When the actual resolver returns, it will have adjusted the +- TLS descriptor such that we can tail-call it for it to return +- the TP offset of the symbol. */ +- +- .hidden _dl_tlsdesc_resolve_rela +- .global _dl_tlsdesc_resolve_rela +- .type _dl_tlsdesc_resolve_rela,@function +- cfi_startproc +- .align 16 +-_dl_tlsdesc_resolve_rela: +-0: +- _CET_ENDBR +- pushl %eax +- cfi_adjust_cfa_offset (4) +- pushl %ecx +- cfi_adjust_cfa_offset (4) +- pushl %edx +- cfi_adjust_cfa_offset (4) +- movl $1f - 0b, %ecx +- movl 4(%ebx), %edx +- call _dl_tlsdesc_resolve_rela_fixup +-1: +- popl %edx +- cfi_adjust_cfa_offset (-4) +- popl %ecx +- cfi_adjust_cfa_offset (-4) +- popl %eax +- cfi_adjust_cfa_offset (-4) +- jmp *(%eax) +- cfi_endproc +- .size _dl_tlsdesc_resolve_rela, .-_dl_tlsdesc_resolve_rela +- +- /* This function is a placeholder for lazy resolving of TLS +- relocations. Once some thread starts resolving a TLS +- relocation, it sets up the TLS descriptor to use this +- resolver, such that other threads that would attempt to +- resolve it concurrently may skip the call to the original lazy +- resolver and go straight to a condition wait. +- +- When the actual resolver returns, it will have adjusted the +- TLS descriptor such that we can tail-call it for it to return +- the TP offset of the symbol. */ +- +- .hidden _dl_tlsdesc_resolve_hold +- .global _dl_tlsdesc_resolve_hold +- .type _dl_tlsdesc_resolve_hold,@function +- cfi_startproc +- .align 16 +-_dl_tlsdesc_resolve_hold: +-0: +- _CET_ENDBR +- pushl %eax +- cfi_adjust_cfa_offset (4) +- pushl %ecx +- cfi_adjust_cfa_offset (4) +- pushl %edx +- cfi_adjust_cfa_offset (4) +- movl $1f - 0b, %ecx +- movl 4(%ebx), %edx +- call _dl_tlsdesc_resolve_hold_fixup +-1: +- popl %edx +- cfi_adjust_cfa_offset (-4) +- popl %ecx +- cfi_adjust_cfa_offset (-4) +- popl %eax +- cfi_adjust_cfa_offset (-4) +- jmp *(%eax) +- cfi_endproc +- .size _dl_tlsdesc_resolve_hold, .-_dl_tlsdesc_resolve_hold +diff --git a/sysdeps/i386/dl-tlsdesc.h b/sysdeps/i386/dl-tlsdesc.h +index c8a1e056150dc418..1a1a22c303baf85b 100644 +--- a/sysdeps/i386/dl-tlsdesc.h ++++ b/sysdeps/i386/dl-tlsdesc.h +@@ -43,11 +43,7 @@ struct tlsdesc_dynamic_arg + + extern ptrdiff_t attribute_hidden __attribute__ ((regparm (1))) + _dl_tlsdesc_return (struct tlsdesc *), +- _dl_tlsdesc_undefweak (struct tlsdesc *), +- _dl_tlsdesc_resolve_abs_plus_addend (struct tlsdesc *), +- _dl_tlsdesc_resolve_rel (struct tlsdesc *), +- _dl_tlsdesc_resolve_rela (struct tlsdesc *), +- _dl_tlsdesc_resolve_hold (struct tlsdesc *); ++ _dl_tlsdesc_undefweak (struct tlsdesc *); + + # ifdef SHARED + extern void *_dl_make_tlsdesc_dynamic (struct link_map *map, +diff --git a/sysdeps/i386/tlsdesc.c b/sysdeps/i386/tlsdesc.c +index 82fa8a1d35fd1912..1b4227c8381e1b3d 100644 +--- a/sysdeps/i386/tlsdesc.c ++++ b/sysdeps/i386/tlsdesc.c +@@ -16,242 +16,13 @@ + License along with the GNU C Library; if not, see + . */ + +-#include + #include +-#include + #include + #include + #include ++#define _dl_tlsdesc_resolve_hold 0 + #include + +-/* The following 4 functions take an entry_check_offset argument. +- It's computed by the caller as an offset between its entry point +- and the call site, such that by adding the built-in return address +- that is implicitly passed to the function with this offset, we can +- easily obtain the caller's entry point to compare with the entry +- point given in the TLS descriptor. If it's changed, we want to +- return immediately. */ +- +-/* This function is used to lazily resolve TLS_DESC REL relocations +- that reference the *ABS* segment in their own link maps. The +- argument is the addend originally stored there. */ +- +-void +-__attribute__ ((regparm (3))) attribute_hidden +-_dl_tlsdesc_resolve_abs_plus_addend_fixup (struct tlsdesc volatile *td, +- struct link_map *l, +- ptrdiff_t entry_check_offset) +-{ +- ptrdiff_t addend = (ptrdiff_t) td->arg; +- +- if (_dl_tlsdesc_resolve_early_return_p (td, __builtin_return_address (0) +- - entry_check_offset)) +- return; +- +-#ifndef SHARED +- CHECK_STATIC_TLS (l, l); +-#else +- if (!TRY_STATIC_TLS (l, l)) +- { +- td->arg = _dl_make_tlsdesc_dynamic (l, addend); +- td->entry = _dl_tlsdesc_dynamic; +- } +- else +-#endif +- { +- td->arg = (void*) (addend - l->l_tls_offset); +- td->entry = _dl_tlsdesc_return; +- } +- +- _dl_tlsdesc_wake_up_held_fixups (); +-} +- +-/* This function is used to lazily resolve TLS_DESC REL relocations +- that originally had zero addends. The argument location, that +- originally held the addend, is used to hold a pointer to the +- relocation, but it has to be restored before we call the function +- that applies relocations. */ +- +-void +-__attribute__ ((regparm (3))) attribute_hidden +-_dl_tlsdesc_resolve_rel_fixup (struct tlsdesc volatile *td, +- struct link_map *l, +- ptrdiff_t entry_check_offset) +-{ +- const ElfW(Rel) *reloc = td->arg; +- +- if (_dl_tlsdesc_resolve_early_return_p (td, __builtin_return_address (0) +- - entry_check_offset)) +- return; +- +- /* The code below was borrowed from _dl_fixup(), +- except for checking for STB_LOCAL. */ +- const ElfW(Sym) *const symtab +- = (const void *) D_PTR (l, l_info[DT_SYMTAB]); +- const char *strtab = (const void *) D_PTR (l, l_info[DT_STRTAB]); +- const ElfW(Sym) *sym = &symtab[ELFW(R_SYM) (reloc->r_info)]; +- lookup_t result; +- +- /* Look up the target symbol. If the normal lookup rules are not +- used don't look in the global scope. */ +- if (ELFW(ST_BIND) (sym->st_info) != STB_LOCAL +- && __builtin_expect (ELFW(ST_VISIBILITY) (sym->st_other), 0) == 0) +- { +- const struct r_found_version *version = NULL; +- +- if (l->l_info[VERSYMIDX (DT_VERSYM)] != NULL) +- { +- const ElfW(Half) *vernum = +- (const void *) D_PTR (l, l_info[VERSYMIDX (DT_VERSYM)]); +- ElfW(Half) ndx = vernum[ELFW(R_SYM) (reloc->r_info)] & 0x7fff; +- version = &l->l_versions[ndx]; +- if (version->hash == 0) +- version = NULL; +- } +- +- result = _dl_lookup_symbol_x (strtab + sym->st_name, l, &sym, +- l->l_scope, version, ELF_RTYPE_CLASS_PLT, +- DL_LOOKUP_ADD_DEPENDENCY, NULL); +- } +- else +- { +- /* We already found the symbol. The module (and therefore its load +- address) is also known. */ +- result = l; +- } +- +- if (!sym) +- { +- td->arg = 0; +- td->entry = _dl_tlsdesc_undefweak; +- } +- else +- { +-# ifndef SHARED +- CHECK_STATIC_TLS (l, result); +-# else +- if (!TRY_STATIC_TLS (l, result)) +- { +- td->arg = _dl_make_tlsdesc_dynamic (result, sym->st_value); +- td->entry = _dl_tlsdesc_dynamic; +- } +- else +-# endif +- { +- td->arg = (void*)(sym->st_value - result->l_tls_offset); +- td->entry = _dl_tlsdesc_return; +- } +- } +- +- _dl_tlsdesc_wake_up_held_fixups (); +-} +- +-/* This function is used to lazily resolve TLS_DESC RELA relocations. +- The argument location is used to hold a pointer to the relocation. */ +- +-void +-__attribute__ ((regparm (3))) attribute_hidden +-_dl_tlsdesc_resolve_rela_fixup (struct tlsdesc volatile *td, +- struct link_map *l, +- ptrdiff_t entry_check_offset) +-{ +- const ElfW(Rela) *reloc = td->arg; +- +- if (_dl_tlsdesc_resolve_early_return_p (td, __builtin_return_address (0) +- - entry_check_offset)) +- return; +- +- /* The code below was borrowed from _dl_fixup(), +- except for checking for STB_LOCAL. */ +- const ElfW(Sym) *const symtab +- = (const void *) D_PTR (l, l_info[DT_SYMTAB]); +- const char *strtab = (const void *) D_PTR (l, l_info[DT_STRTAB]); +- const ElfW(Sym) *sym = &symtab[ELFW(R_SYM) (reloc->r_info)]; +- lookup_t result; +- +- /* Look up the target symbol. If the normal lookup rules are not +- used don't look in the global scope. */ +- if (ELFW(ST_BIND) (sym->st_info) != STB_LOCAL +- && __builtin_expect (ELFW(ST_VISIBILITY) (sym->st_other), 0) == 0) +- { +- const struct r_found_version *version = NULL; +- +- if (l->l_info[VERSYMIDX (DT_VERSYM)] != NULL) +- { +- const ElfW(Half) *vernum = +- (const void *) D_PTR (l, l_info[VERSYMIDX (DT_VERSYM)]); +- ElfW(Half) ndx = vernum[ELFW(R_SYM) (reloc->r_info)] & 0x7fff; +- version = &l->l_versions[ndx]; +- if (version->hash == 0) +- version = NULL; +- } +- +- result = _dl_lookup_symbol_x (strtab + sym->st_name, l, &sym, +- l->l_scope, version, ELF_RTYPE_CLASS_PLT, +- DL_LOOKUP_ADD_DEPENDENCY, NULL); +- } +- else +- { +- /* We already found the symbol. The module (and therefore its load +- address) is also known. */ +- result = l; +- } +- +- if (!sym) +- { +- td->arg = (void*) reloc->r_addend; +- td->entry = _dl_tlsdesc_undefweak; +- } +- else +- { +-# ifndef SHARED +- CHECK_STATIC_TLS (l, result); +-# else +- if (!TRY_STATIC_TLS (l, result)) +- { +- td->arg = _dl_make_tlsdesc_dynamic (result, sym->st_value +- + reloc->r_addend); +- td->entry = _dl_tlsdesc_dynamic; +- } +- else +-# endif +- { +- td->arg = (void*) (sym->st_value - result->l_tls_offset +- + reloc->r_addend); +- td->entry = _dl_tlsdesc_return; +- } +- } +- +- _dl_tlsdesc_wake_up_held_fixups (); +-} +- +-/* This function is used to avoid busy waiting for other threads to +- complete the lazy relocation. Once another thread wins the race to +- relocate a TLS descriptor, it sets the descriptor up such that this +- function is called to wait until the resolver releases the +- lock. */ +- +-void +-__attribute__ ((regparm (3))) attribute_hidden +-_dl_tlsdesc_resolve_hold_fixup (struct tlsdesc volatile *td, +- struct link_map *l __attribute__((__unused__)), +- ptrdiff_t entry_check_offset) +-{ +- /* Maybe we're lucky and can return early. */ +- if (__builtin_return_address (0) - entry_check_offset != td->entry) +- return; +- +- /* Locking here will stop execution until the running resolver runs +- _dl_tlsdesc_wake_up_held_fixups(), releasing the lock. +- +- FIXME: We'd be better off waiting on a condition variable, such +- that we didn't have to hold the lock throughout the relocation +- processing. */ +- __rtld_lock_lock_recursive (GL(dl_load_lock)); +- __rtld_lock_unlock_recursive (GL(dl_load_lock)); +-} +- +- + /* Unmap the dynamic object, but also release its TLS descriptor table + if there is one. */ + diff --git a/SOURCES/glibc-rh2000374.patch b/SOURCES/glibc-rh2000374.patch new file mode 100644 index 0000000..1d510ae --- /dev/null +++ b/SOURCES/glibc-rh2000374.patch @@ -0,0 +1,205 @@ +Bug RHEL #2000374 +Bugs Upstream #24046, #25923 + +This patch provides 12-hour time for the English language UTF-8 locale as a +new locale en_US@ampm.UTF-8. + +Two upstream commits were applied to en_US to create the new file en_US@ampm: + Upstream commit: 7395f3a0efad9fc51bb54fa383ef6524702e0c49 + Upstream commit: 8cde977077b3568310c743b21a905ca9ab286724 + +en_US remains unchanged and the new file en_US@ampm is now supported. + + +diff -Nrup a/localedata/locales/en_US@ampm b/localedata/locales/en_US@ampm +--- a/localedata/locales/en_US@ampm 1969-12-31 19:00:00.000000000 -0500 ++++ b/localedata/locales/en_US@ampm 2021-11-17 17:19:15.338720307 -0500 +@@ -0,0 +1,177 @@ ++comment_char % ++escape_char / ++ ++% This file is part of the GNU C Library and contains locale data. ++% The Free Software Foundation does not claim any copyright interest ++% in the locale data contained in this file. The foregoing does not ++% affect the license of the GNU C Library as a whole. It does not ++% exempt you from the conditions of the license if your use would ++% otherwise be governed by that license. ++ ++% Locale for English locale in the USA ++% Contributed by Ulrich Drepper , 2000 ++ ++LC_IDENTIFICATION ++title "English locale for the USA" ++source "Free Software Foundation, Inc." ++address "http:////www.gnu.org//software//libc//" ++contact "" ++email "bug-glibc-locales@gnu.org" ++tel "" ++fax "" ++language "American English" ++territory "United States" ++revision "1.0" ++date "2000-06-24" ++ ++category "i18n:2012";LC_IDENTIFICATION ++category "i18n:2012";LC_CTYPE ++category "i18n:2012";LC_COLLATE ++category "i18n:2012";LC_TIME ++category "i18n:2012";LC_NUMERIC ++category "i18n:2012";LC_MONETARY ++category "i18n:2012";LC_MESSAGES ++category "i18n:2012";LC_PAPER ++category "i18n:2012";LC_NAME ++category "i18n:2012";LC_ADDRESS ++category "i18n:2012";LC_TELEPHONE ++category "i18n:2012";LC_MEASUREMENT ++END LC_IDENTIFICATION ++ ++LC_CTYPE ++copy "en_GB" ++END LC_CTYPE ++ ++LC_COLLATE ++ ++% Copy the template from ISO/IEC 14651 ++copy "iso14651_t1" ++ ++END LC_COLLATE ++ ++LC_MONETARY ++int_curr_symbol "USD " ++currency_symbol "$" ++mon_decimal_point "." ++mon_thousands_sep "," ++mon_grouping 3;3 ++positive_sign "" ++negative_sign "-" ++int_frac_digits 2 ++frac_digits 2 ++p_cs_precedes 1 ++int_p_sep_by_space 1 ++p_sep_by_space 0 ++n_cs_precedes 1 ++int_n_sep_by_space 1 ++n_sep_by_space 0 ++p_sign_posn 1 ++n_sign_posn 1 ++% ++END LC_MONETARY ++ ++LC_NUMERIC ++decimal_point "." ++thousands_sep "," ++grouping 3;3 ++END LC_NUMERIC ++ ++LC_TIME ++abday "Sun";"Mon";"Tue";"Wed";"Thu";"Fri";"Sat" ++day "Sunday";/ ++ "Monday";/ ++ "Tuesday";/ ++ "Wednesday";/ ++ "Thursday";/ ++ "Friday";/ ++ "Saturday" ++ ++week 7;19971130;1 ++abmon "Jan";"Feb";/ ++ "Mar";"Apr";/ ++ "May";"Jun";/ ++ "Jul";"Aug";/ ++ "Sep";"Oct";/ ++ "Nov";"Dec" ++mon "January";/ ++ "February";/ ++ "March";/ ++ "April";/ ++ "May";/ ++ "June";/ ++ "July";/ ++ "August";/ ++ "September";/ ++ "October";/ ++ "November";/ ++ "December" ++% Appropriate date and time representation (%c) ++d_t_fmt "%a %d %b %Y %r %Z" ++% ++% Appropriate date representation (%x) ++d_fmt "%m//%d//%Y" ++% ++% Appropriate time representation (%X) ++t_fmt "%r" ++% ++% Appropriate AM/PM time representation (%r) ++t_fmt_ampm "%I:%M:%S %p" ++% ++% Appropriate date and time representation for date(1). This is ++% different from d_t_fmt for historical reasons and has been different ++% since 2000 when date_fmt was added as a GNU extension. At the end ++% of 2018 it was adjusted to use 12H time (bug 24046) instead of 24H. ++date_fmt "%a %b %e %r %Z %Y" ++% ++% Strings for AM/PM ++% ++am_pm "AM";"PM" ++END LC_TIME ++ ++LC_MESSAGES ++yesexpr "^[+1yY]" ++noexpr "^[-0nN]" ++yesstr "yes" ++nostr "no" ++END LC_MESSAGES ++ ++LC_PAPER ++height 279 ++width 216 ++END LC_PAPER ++ ++LC_NAME ++name_fmt "%d%t%g%t%m%t%f" ++name_miss "Miss." ++name_mr "Mr." ++name_mrs "Mrs." ++name_ms "Ms." ++END LC_NAME ++ ++ ++LC_ADDRESS ++postal_fmt "%a%N%f%N%d%N%b%N%h %s %e %r%N%T, %S %z%N%c%N" ++country_name "United States" ++country_post "USA" ++country_ab2 "US" ++country_ab3 "USA" ++country_num 840 ++country_car "USA" ++country_isbn 0 ++lang_name "English" ++lang_ab "en" ++lang_term "eng" ++lang_lib "eng" ++END LC_ADDRESS ++ ++LC_TELEPHONE ++tel_int_fmt "+%c (%a) %l" ++tel_dom_fmt "(%a) %l" ++int_select "11" ++int_prefix "1" ++END LC_TELEPHONE ++ ++LC_MEASUREMENT ++% US customary units. ++measurement 2 ++END LC_MEASUREMENT +diff -Nrup a/localedata/SUPPORTED b/localedata/SUPPORTED +--- a/localedata/SUPPORTED 2021-11-17 17:14:33.831631483 -0500 ++++ b/localedata/SUPPORTED 2021-11-17 17:21:16.418188595 -0500 +@@ -159,6 +159,7 @@ 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_ZA.UTF-8/UTF-8 \ + en_ZA/ISO-8859-1 \ + en_ZM/UTF-8 \ diff --git a/SOURCES/glibc-rh2007327-1.patch b/SOURCES/glibc-rh2007327-1.patch new file mode 100644 index 0000000..2c6379e --- /dev/null +++ b/SOURCES/glibc-rh2007327-1.patch @@ -0,0 +1,92 @@ +commit 28c30a6232aa9a54783c146590498a061fc0112a +Author: Samuel Thibault +Date: Sun Feb 9 19:50:21 2020 +0000 + + pthread: Move most once tests from nptl to sysdeps/pthread + + So they can be checked with htl too. + +# Conflicts: +# sysdeps/pthread/Makefile +# (Moved only the tests in this commit which subsequently +# needed for the pthread_once fix) + +diff --git a/nptl/Makefile b/nptl/Makefile +index b14de3ffb330c10b..dcf3868869767015 100644 +--- a/nptl/Makefile ++++ b/nptl/Makefile +@@ -260,7 +260,7 @@ tests = tst-attr1 tst-attr2 tst-attr3 tst-default-attr \ + tst-rwlock4 tst-rwlock5 tst-rwlock6 tst-rwlock7 tst-rwlock8 \ + tst-rwlock9 tst-rwlock10 tst-rwlock11 tst-rwlock12 tst-rwlock13 \ + tst-rwlock14 tst-rwlock15 tst-rwlock16 tst-rwlock17 tst-rwlock18 \ +- tst-once1 tst-once2 tst-once3 tst-once4 tst-once5 \ ++ tst-once5 \ + tst-key1 tst-key2 tst-key3 tst-key4 \ + tst-sem1 tst-sem2 tst-sem3 tst-sem4 tst-sem5 tst-sem6 tst-sem7 \ + tst-sem8 tst-sem9 tst-sem10 tst-sem14 \ +@@ -384,8 +384,7 @@ tests += tst-cancelx2 tst-cancelx3 tst-cancelx4 tst-cancelx5 \ + tst-cancelx6 tst-cancelx7 tst-cancelx8 tst-cancelx9 tst-cancelx10 \ + tst-cancelx11 tst-cancelx12 tst-cancelx13 tst-cancelx14 tst-cancelx15 \ + tst-cancelx16 tst-cancelx17 tst-cancelx18 tst-cancelx20 tst-cancelx21 \ +- tst-cleanupx0 tst-cleanupx1 tst-cleanupx2 tst-cleanupx3 tst-cleanupx4 \ +- tst-oncex3 tst-oncex4 ++ 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 +@@ -525,8 +524,6 @@ CFLAGS-tst-cleanupx2.c += -fexceptions + CFLAGS-tst-cleanupx3.c += -fexceptions + CFLAGS-tst-cleanupx4.c += -fexceptions + CFLAGS-tst-cleanupx4aux.c += -fexceptions +-CFLAGS-tst-oncex3.c += -fexceptions +-CFLAGS-tst-oncex4.c += -fexceptions + CFLAGS-tst-align.c += $(stack-align-test-flags) + CFLAGS-tst-align3.c += $(stack-align-test-flags) + CFLAGS-tst-initializers1.c += -W -Wall -Werror +diff --git a/sysdeps/pthread/Makefile b/sysdeps/pthread/Makefile +index 98a92f8d6bb119ba..14ef04247cb84ad3 100644 +--- a/sysdeps/pthread/Makefile ++++ b/sysdeps/pthread/Makefile +@@ -33,11 +33,18 @@ endif + + tst-create1mod.so-no-z-defs = yes + ++tests += tst-once1 tst-once2 tst-once3 tst-once4 ++ ++tests += tst-oncex3 tst-oncex4 ++ + ifeq ($(build-shared),yes) + # Build all the modules even when not actually running test programs. + tests: $(test-modules) + endif + ++CFLAGS-tst-oncex3.c += -fexceptions ++CFLAGS-tst-oncex4.c += -fexceptions ++ + modules-names += tst-create1mod + test-modules = $(addprefix $(objpfx),$(addsuffix .so,$(modules-names))) + +diff --git a/nptl/tst-once1.c b/sysdeps/pthread/tst-once1.c +similarity index 100% +rename from nptl/tst-once1.c +rename to sysdeps/pthread/tst-once1.c +diff --git a/nptl/tst-once2.c b/sysdeps/pthread/tst-once2.c +similarity index 100% +rename from nptl/tst-once2.c +rename to sysdeps/pthread/tst-once2.c +diff --git a/nptl/tst-once3.c b/sysdeps/pthread/tst-once3.c +similarity index 100% +rename from nptl/tst-once3.c +rename to sysdeps/pthread/tst-once3.c +diff --git a/nptl/tst-once4.c b/sysdeps/pthread/tst-once4.c +similarity index 100% +rename from nptl/tst-once4.c +rename to sysdeps/pthread/tst-once4.c +diff --git a/nptl/tst-oncex3.c b/sysdeps/pthread/tst-oncex3.c +similarity index 100% +rename from nptl/tst-oncex3.c +rename to sysdeps/pthread/tst-oncex3.c +diff --git a/nptl/tst-oncex4.c b/sysdeps/pthread/tst-oncex4.c +similarity index 100% +rename from nptl/tst-oncex4.c +rename to sysdeps/pthread/tst-oncex4.c diff --git a/SOURCES/glibc-rh2007327-2.patch b/SOURCES/glibc-rh2007327-2.patch new file mode 100644 index 0000000..29e67f9 --- /dev/null +++ b/SOURCES/glibc-rh2007327-2.patch @@ -0,0 +1,200 @@ +commit f0419e6a10740a672b28e112c409ae24f5e890ab +Author: Jakub Jelinek +Date: Thu Mar 4 15:15:33 2021 +0100 + + [PATCH] pthread_once hangs when init routine throws an exception [BZ #18435] + + This is another attempt at making pthread_once handle throwing exceptions + from the init routine callback. As the new testcases show, just switching + to the cleanup attribute based cleanup does fix the tst-once5 test, but + breaks the new tst-oncey3 test. That is because when throwing exceptions, + only the unwind info registered cleanups (i.e. C++ destructors or cleanup + attribute), when cancelling threads and there has been unwind info from the + cancellation point up to whatever needs cleanup both unwind info registered + cleanups and THREAD_SETMEM (self, cleanup, ...) registered cleanups are + invoked, but once we hit some frame with no unwind info, only the + THREAD_SETMEM (self, cleanup, ...) registered cleanups are invoked. + So, to stay fully backwards compatible (allow init routines without + unwind info which encounter cancellation points) and handle exception throwing + we actually need to register the pthread_once cleanups in both unwind info + and in the THREAD_SETMEM (self, cleanup, ...) way. + If an exception is thrown, only the former will happen and we in that case + need to also unregister the THREAD_SETMEM (self, cleanup, ...) registered + handler, because otherwise after catching the exception the user code could + call deeper into the stack some cancellation point, get cancelled and then + a stale cleanup handler would clobber stack and probably crash. + If a thread calling init routine is cancelled and unwind info ends before + the pthread_once frame, it will be cleaned up through self->cleanup as + before. And if unwind info is present, unwind_stop first calls the + self->cleanup registered handler for the frame, then it will call the + unwind info registered handler but that will already see __do_it == 0 + and do nothing. + +# Conflicts: +# nptl/Makefile +# (The usual cleanups because they don't match.) +# sysdeps/pthread/Makefile +# (The usual cleanups because all the other tests aren't moved.) + +diff --git a/nptl/Makefile b/nptl/Makefile +index dcf3868869767015..70a3be23ecfcd9c9 100644 +--- a/nptl/Makefile ++++ b/nptl/Makefile +@@ -334,10 +334,6 @@ xtests = tst-setuid1 tst-setuid1-static tst-setuid2 \ + tst-mutexpp1 tst-mutexpp6 tst-mutexpp10 + test-srcs = tst-oddstacklimit + +-# Test expected to fail on most targets (except x86_64) due to bug +-# 18435 - pthread_once hangs when init routine throws an exception. +-test-xfail-tst-once5 = yes +- + # Files which must not be linked with libpthread. + tests-nolibpthread = tst-unload + +diff --git a/nptl/pthreadP.h b/nptl/pthreadP.h +index a2d48b2015cd385c..7ddc166cf32414c4 100644 +--- a/nptl/pthreadP.h ++++ b/nptl/pthreadP.h +@@ -571,6 +571,67 @@ extern void __pthread_cleanup_pop (struct _pthread_cleanup_buffer *buffer, + # undef pthread_cleanup_pop + # define pthread_cleanup_pop(execute) \ + __pthread_cleanup_pop (&_buffer, (execute)); } ++ ++# if defined __EXCEPTIONS && !defined __cplusplus ++/* Structure to hold the cleanup handler information. */ ++struct __pthread_cleanup_combined_frame ++{ ++ void (*__cancel_routine) (void *); ++ void *__cancel_arg; ++ int __do_it; ++ struct _pthread_cleanup_buffer __buffer; ++}; ++ ++/* Special cleanup macros which register cleanup both using ++ __pthread_cleanup_{push,pop} and using cleanup attribute. This is needed ++ for pthread_once, so that it supports both throwing exceptions from the ++ pthread_once callback (only cleanup attribute works there) and cancellation ++ of the thread running the callback if the callback or some routines it ++ calls don't have unwind information. */ ++ ++static __always_inline void ++__pthread_cleanup_combined_routine (struct __pthread_cleanup_combined_frame ++ *__frame) ++{ ++ if (__frame->__do_it) ++ { ++ __frame->__cancel_routine (__frame->__cancel_arg); ++ __frame->__do_it = 0; ++ __pthread_cleanup_pop (&__frame->__buffer, 0); ++ } ++} ++ ++static inline void ++__pthread_cleanup_combined_routine_voidptr (void *__arg) ++{ ++ struct __pthread_cleanup_combined_frame *__frame ++ = (struct __pthread_cleanup_combined_frame *) __arg; ++ if (__frame->__do_it) ++ { ++ __frame->__cancel_routine (__frame->__cancel_arg); ++ __frame->__do_it = 0; ++ } ++} ++ ++# define pthread_cleanup_combined_push(routine, arg) \ ++ do { \ ++ void (*__cancel_routine) (void *) = (routine); \ ++ struct __pthread_cleanup_combined_frame __clframe \ ++ __attribute__ ((__cleanup__ (__pthread_cleanup_combined_routine))) \ ++ = { .__cancel_routine = __cancel_routine, .__cancel_arg = (arg), \ ++ .__do_it = 1 }; \ ++ __pthread_cleanup_push (&__clframe.__buffer, \ ++ __pthread_cleanup_combined_routine_voidptr, \ ++ &__clframe); ++ ++# define pthread_cleanup_combined_pop(execute) \ ++ __pthread_cleanup_pop (&__clframe.__buffer, 0); \ ++ __clframe.__do_it = 0; \ ++ if (execute) \ ++ __cancel_routine (__clframe.__cancel_arg); \ ++ } while (0) ++ ++# endif + #endif + + extern void __pthread_cleanup_push_defer (struct _pthread_cleanup_buffer *buffer, +diff --git a/nptl/pthread_once.c b/nptl/pthread_once.c +index 1653226286dc3539..45e965e8743d9412 100644 +--- a/nptl/pthread_once.c ++++ b/nptl/pthread_once.c +@@ -111,11 +111,11 @@ __pthread_once_slow (pthread_once_t *once_control, void (*init_routine) (void)) + /* This thread is the first here. Do the initialization. + Register a cleanup handler so that in case the thread gets + interrupted the initialization can be restarted. */ +- pthread_cleanup_push (clear_once_control, once_control); ++ pthread_cleanup_combined_push (clear_once_control, once_control); + + init_routine (); + +- pthread_cleanup_pop (0); ++ pthread_cleanup_combined_pop (0); + + + /* Mark *once_control as having finished the initialization. We need +diff --git a/nptl/tst-once5.cc b/nptl/tst-once5.cc +index d232266c3ace89d9..dda18e610c9114bc 100644 +--- a/nptl/tst-once5.cc ++++ b/nptl/tst-once5.cc +@@ -59,7 +59,7 @@ do_test (void) + " throwing an exception", stderr); + } + catch (OnceException) { +- if (1 < niter) ++ if (niter > 1) + fputs ("pthread_once unexpectedly threw", stderr); + result = 0; + } +@@ -75,7 +75,5 @@ do_test (void) + return result; + } + +-// The test currently hangs and is XFAILed. Reduce the timeout. +-#define TIMEOUT 1 + #define TEST_FUNCTION do_test () + #include "../test-skeleton.c" +diff --git a/sysdeps/pthread/Makefile b/sysdeps/pthread/Makefile +index 14ef04247cb84ad3..80a71f3f9f0e72ae 100644 +--- a/sysdeps/pthread/Makefile ++++ b/sysdeps/pthread/Makefile +@@ -35,7 +35,7 @@ tst-create1mod.so-no-z-defs = yes + + tests += tst-once1 tst-once2 tst-once3 tst-once4 + +-tests += tst-oncex3 tst-oncex4 ++tests += tst-oncex3 tst-oncex4 tst-oncey3 tst-oncey4 + + ifeq ($(build-shared),yes) + # Build all the modules even when not actually running test programs. +@@ -44,6 +44,8 @@ endif + + CFLAGS-tst-oncex3.c += -fexceptions + CFLAGS-tst-oncex4.c += -fexceptions ++CFLAGS-tst-oncey3.c += -fno-exceptions -fno-asynchronous-unwind-tables ++CFLAGS-tst-oncey4.c += -fno-exceptions -fno-asynchronous-unwind-tables + + modules-names += tst-create1mod + test-modules = $(addprefix $(objpfx),$(addsuffix .so,$(modules-names))) +diff --git a/sysdeps/pthread/tst-oncey3.c b/sysdeps/pthread/tst-oncey3.c +new file mode 100644 +index 0000000000000000..08225b88dc06b979 +--- /dev/null ++++ b/sysdeps/pthread/tst-oncey3.c +@@ -0,0 +1 @@ ++#include "tst-once3.c" +diff --git a/sysdeps/pthread/tst-oncey4.c b/sysdeps/pthread/tst-oncey4.c +new file mode 100644 +index 0000000000000000..9b4d98f3f13c265a +--- /dev/null ++++ b/sysdeps/pthread/tst-oncey4.c +@@ -0,0 +1 @@ ++#include "tst-once4.c" diff --git a/SOURCES/glibc-rh2021452.patch b/SOURCES/glibc-rh2021452.patch new file mode 100644 index 0000000..3dad2df --- /dev/null +++ b/SOURCES/glibc-rh2021452.patch @@ -0,0 +1,40 @@ +commit 98966749f2b418825ff2ea496a0ee89fe63d2cc8 +Author: Florian Weimer +Date: Wed Nov 10 15:21:37 2021 +0100 + + s390: Use long branches across object boundaries (jgh instead of jh) + + Depending on the layout chosen by the linker, the 16-bit displacement + of the jh instruction is insufficient to reach the target label. + + Analysis of the linker failure was carried out by Nick Clifton. + + Reviewed-by: Carlos O'Donell + Reviewed-by: Stefan Liebler + +diff --git a/sysdeps/s390/memmem-arch13.S b/sysdeps/s390/memmem-arch13.S +index b59d60acf0f6aaa0..4faede0cd2f942e3 100644 +--- a/sysdeps/s390/memmem-arch13.S ++++ b/sysdeps/s390/memmem-arch13.S +@@ -41,7 +41,7 @@ ENTRY(MEMMEM_ARCH13) + # error The arch13 variant of memmem needs the z13 variant of memmem! + # endif + clgfi %r5,9 +- jh MEMMEM_Z13 ++ jgh MEMMEM_Z13 + + aghik %r0,%r5,-1 /* vll needs highest index. */ + bc 4,0(%r14) /* cc==1: return if needle-len == 0. */ +diff --git a/sysdeps/s390/strstr-arch13.S b/sysdeps/s390/strstr-arch13.S +index faa969849e09c2e1..ffc34c2523ce635a 100644 +--- a/sysdeps/s390/strstr-arch13.S ++++ b/sysdeps/s390/strstr-arch13.S +@@ -49,7 +49,7 @@ ENTRY(STRSTR_ARCH13) + # error The arch13 variant of strstr needs the z13 variant of strstr! + # endif + clgfi %r4,9 +- jh STRSTR_Z13 ++ jgh STRSTR_Z13 + + /* In case of a partial match, the vstrs instruction returns the index + of the partial match in a vector-register. Then we have to diff --git a/SOURCES/glibc-rh2023420-1.patch b/SOURCES/glibc-rh2023420-1.patch new file mode 100644 index 0000000..3b8d299 --- /dev/null +++ b/SOURCES/glibc-rh2023420-1.patch @@ -0,0 +1,304 @@ +commit 86f65dffc2396d408beb628f1cad2b8f63e197bd +Author: H.J. Lu +Date: Sun Jul 12 06:04:53 2020 -0700 + + ld.so: Add --list-tunables to print tunable values + + Pass --list-tunables to ld.so to print tunables with min and max values. + + Reviewed-by: Adhemerval Zanella + +Conflicts: + elf/Makefile + (different backporting order) + +diff --git a/elf/Makefile b/elf/Makefile +index 3e71939d3234c4c3..aa65ec59f143bccf 100644 +--- a/elf/Makefile ++++ b/elf/Makefile +@@ -44,6 +44,10 @@ dl-routines += dl-tunables + tunables-type = $(addprefix TUNABLES_FRONTEND_,$(have-tunables)) + CPPFLAGS-dl-tunables.c += -DTUNABLES_FRONTEND=$(tunables-type) + ++ifeq (yesyes,$(build-shared)$(run-built-tests)) ++tests-special += $(objpfx)list-tunables.out ++endif ++ + # Make sure that the compiler does not insert any library calls in tunables + # code paths. + ifeq (yes,$(have-loop-to-function)) +@@ -1825,6 +1829,13 @@ $(objpfx)tst-glibc-hwcaps-mask.out: \ + # tst-glibc-hwcaps-cache. + $(objpfx)tst-glibc-hwcaps-cache.out: $(objpfx)tst-glibc-hwcaps + ++$(objpfx)list-tunables.out: tst-rtld-list-tunables.sh $(objpfx)ld.so ++ $(SHELL) $< $(objpfx)ld.so '$(test-wrapper-env)' \ ++ '$(run_program_env)' > $(objpfx)/tst-rtld-list-tunables.out ++ cmp tst-rtld-list-tunables.exp \ ++ $(objpfx)/tst-rtld-list-tunables.out > $@; \ ++ $(evaluate-test) ++ + tst-dst-static-ENV = LD_LIBRARY_PATH='$$ORIGIN' + + $(objpfx)tst-rtld-help.out: $(objpfx)ld.so +diff --git a/elf/dl-main.h b/elf/dl-main.h +index 566713a0d10cfdb7..9e7b51d8f010e904 100644 +--- a/elf/dl-main.h ++++ b/elf/dl-main.h +@@ -63,7 +63,7 @@ struct audit_list + enum rtld_mode + { + rtld_mode_normal, rtld_mode_list, rtld_mode_verify, rtld_mode_trace, +- rtld_mode_help, ++ rtld_mode_list_tunables, rtld_mode_help, + }; + + /* Aggregated state information extracted from environment variables +diff --git a/elf/dl-tunables.c b/elf/dl-tunables.c +index bbc3679e3564a766..3c84809d44381241 100644 +--- a/elf/dl-tunables.c ++++ b/elf/dl-tunables.c +@@ -26,6 +26,7 @@ + #include + #include + #include ++#include + + #define TUNABLES_INTERNAL 1 + #include "dl-tunables.h" +@@ -359,6 +360,48 @@ __tunables_init (char **envp) + } + } + ++void ++__tunables_print (void) ++{ ++ for (int i = 0; i < array_length (tunable_list); i++) ++ { ++ const tunable_t *cur = &tunable_list[i]; ++ if (cur->type.type_code == TUNABLE_TYPE_STRING ++ && cur->val.strval == NULL) ++ _dl_printf ("%s:\n", cur->name); ++ else ++ { ++ _dl_printf ("%s: ", cur->name); ++ switch (cur->type.type_code) ++ { ++ case TUNABLE_TYPE_INT_32: ++ _dl_printf ("%d (min: %d, max: %d)\n", ++ (int) cur->val.numval, ++ (int) cur->type.min, ++ (int) cur->type.max); ++ break; ++ case TUNABLE_TYPE_UINT_64: ++ _dl_printf ("0x%lx (min: 0x%lx, max: 0x%lx)\n", ++ (long int) cur->val.numval, ++ (long int) cur->type.min, ++ (long int) cur->type.max); ++ break; ++ case TUNABLE_TYPE_SIZE_T: ++ _dl_printf ("0x%Zx (min: 0x%Zx, max: 0x%Zx)\n", ++ (size_t) cur->val.numval, ++ (size_t) cur->type.min, ++ (size_t) cur->type.max); ++ break; ++ case TUNABLE_TYPE_STRING: ++ _dl_printf ("%s\n", cur->val.strval); ++ break; ++ default: ++ __builtin_unreachable (); ++ } ++ } ++ } ++} ++ + /* Set the tunable value. This is called by the module that the tunable exists + in. */ + void +diff --git a/elf/dl-tunables.h b/elf/dl-tunables.h +index 7f181f3316cd9fc1..f4f2cfaeb9828599 100644 +--- a/elf/dl-tunables.h ++++ b/elf/dl-tunables.h +@@ -69,9 +69,11 @@ typedef struct _tunable tunable_t; + # include "dl-tunable-list.h" + + extern void __tunables_init (char **); ++extern void __tunables_print (void); + extern void __tunable_get_val (tunable_id_t, void *, tunable_callback_t); + extern void __tunable_set_val (tunable_id_t, void *); + rtld_hidden_proto (__tunables_init) ++rtld_hidden_proto (__tunables_print) + rtld_hidden_proto (__tunable_get_val) + + /* Define TUNABLE_GET and TUNABLE_SET in short form if TOP_NAMESPACE and +diff --git a/elf/dl-usage.c b/elf/dl-usage.c +index e22a9c39427187d1..908b4894b3014b2d 100644 +--- a/elf/dl-usage.c ++++ b/elf/dl-usage.c +@@ -255,7 +255,12 @@ setting environment variables (which would be inherited by subprocesses).\n\ + in LIST\n\ + --audit LIST use objects named in LIST as auditors\n\ + --preload LIST preload objects named in LIST\n\ +- --argv0 STRING set argv[0] to STRING before running\n\ ++ --argv0 STRING set argv[0] to STRING before running\n" ++#if HAVE_TUNABLES ++"\ ++ --list-tunables list all tunables with minimum and maximum values\n" ++#endif ++"\ + --help display this help and exit\n\ + --version output version information and exit\n\ + \n\ +diff --git a/elf/rtld.c b/elf/rtld.c +index 9e09896da078274d..54b621ec5ca014fa 100644 +--- a/elf/rtld.c ++++ b/elf/rtld.c +@@ -47,6 +47,7 @@ + #include + #include + #include ++#include + + #include + +@@ -1262,6 +1263,16 @@ dl_main (const ElfW(Phdr) *phdr, + _dl_argc -= 2; + _dl_argv += 2; + } ++#if HAVE_TUNABLES ++ else if (! strcmp (_dl_argv[1], "--list-tunables")) ++ { ++ state.mode = rtld_mode_list_tunables; ++ ++ ++_dl_skip_args; ++ --_dl_argc; ++ ++_dl_argv; ++ } ++#endif + else if (strcmp (_dl_argv[1], "--help") == 0) + { + state.mode = rtld_mode_help; +@@ -1282,6 +1293,14 @@ dl_main (const ElfW(Phdr) *phdr, + else + break; + ++#if HAVE_TUNABLES ++ if (__glibc_unlikely (state.mode == rtld_mode_list_tunables)) ++ { ++ __tunables_print (); ++ _exit (0); ++ } ++#endif ++ + /* If we have no further argument the program was called incorrectly. + Grant the user some education. */ + if (_dl_argc < 2) +diff --git a/elf/tst-rtld-list-tunables.exp b/elf/tst-rtld-list-tunables.exp +new file mode 100644 +index 0000000000000000..4f3f7ee4e30a2b42 +--- /dev/null ++++ b/elf/tst-rtld-list-tunables.exp +@@ -0,0 +1,14 @@ ++glibc.malloc.arena_max: 0x0 (min: 0x1, max: 0x[f]+) ++glibc.malloc.arena_test: 0x0 (min: 0x1, max: 0x[f]+) ++glibc.malloc.check: 0 (min: 0, max: 3) ++glibc.malloc.mmap_max: 0 (min: -2147483648, max: 2147483647) ++glibc.malloc.mmap_threshold: 0x0 (min: 0x0, max: 0x[f]+) ++glibc.malloc.mxfast: 0x0 (min: 0x0, max: 0x[f]+) ++glibc.malloc.perturb: 0 (min: 0, max: 255) ++glibc.malloc.tcache_count: 0x0 (min: 0x0, max: 0x[f]+) ++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.nns: 0x4 (min: 0x1, max: 0x10) ++glibc.rtld.optional_static_tls: 0x200 (min: 0x0, max: 0x[f]+) +diff --git a/elf/tst-rtld-list-tunables.sh b/elf/tst-rtld-list-tunables.sh +new file mode 100755 +index 0000000000000000..e7bbdde94952b872 +--- /dev/null ++++ b/elf/tst-rtld-list-tunables.sh +@@ -0,0 +1,34 @@ ++#!/bin/sh ++# Test for --list-tunables option ld.so. ++# 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 ++# . ++ ++set -e ++ ++rtld=$1 ++test_wrapper_env=$2 ++run_program_env=$3 ++ ++LC_ALL=C ++export LC_ALL ++ ++${test_wrapper_env} \ ++${run_program_env} \ ++$rtld --list-tunables \ ++| sort -u \ ++| egrep "(rtld|malloc)" \ ++| sed -e "s/0xf\+/0x[f]+/" +diff --git a/manual/tunables.texi b/manual/tunables.texi +index 07887981748bc44b..43272cf885d1e3e6 100644 +--- a/manual/tunables.texi ++++ b/manual/tunables.texi +@@ -28,6 +28,44 @@ Finally, the set of tunables available may vary between distributions as + the tunables feature allows distributions to add their own tunables under + their own namespace. + ++Passing @option{--list-tunables} to the dynamic loader to print all ++tunables with minimum and maximum values: ++ ++@example ++$ /lib64/ld-linux-x86-64.so.2 --list-tunables ++glibc.rtld.nns: 0x4 (min: 0x1, max: 0x10) ++glibc.elision.skip_lock_after_retries: 3 (min: -2147483648, max: 2147483647) ++glibc.malloc.trim_threshold: 0x0 (min: 0x0, max: 0xffffffffffffffff) ++glibc.malloc.perturb: 0 (min: 0, max: 255) ++glibc.cpu.x86_shared_cache_size: 0x100000 (min: 0x0, max: 0xffffffffffffffff) ++glibc.mem.tagging: 0 (min: 0, max: 255) ++glibc.elision.tries: 3 (min: -2147483648, max: 2147483647) ++glibc.elision.enable: 0 (min: 0, max: 1) ++glibc.cpu.x86_rep_movsb_threshold: 0x1000 (min: 0x100, max: 0xffffffffffffffff) ++glibc.malloc.mxfast: 0x0 (min: 0x0, max: 0xffffffffffffffff) ++glibc.elision.skip_lock_busy: 3 (min: -2147483648, max: 2147483647) ++glibc.malloc.top_pad: 0x0 (min: 0x0, max: 0xffffffffffffffff) ++glibc.cpu.x86_rep_stosb_threshold: 0x800 (min: 0x1, max: 0xffffffffffffffff) ++glibc.cpu.x86_non_temporal_threshold: 0xc0000 (min: 0x0, max: 0xffffffffffffffff) ++glibc.cpu.x86_shstk: ++glibc.cpu.hwcap_mask: 0x6 (min: 0x0, max: 0xffffffffffffffff) ++glibc.malloc.mmap_max: 0 (min: -2147483648, max: 2147483647) ++glibc.elision.skip_trylock_internal_abort: 3 (min: -2147483648, max: 2147483647) ++glibc.malloc.tcache_unsorted_limit: 0x0 (min: 0x0, max: 0xffffffffffffffff) ++glibc.cpu.x86_ibt: ++glibc.cpu.hwcaps: ++glibc.elision.skip_lock_internal_abort: 3 (min: -2147483648, max: 2147483647) ++glibc.malloc.arena_max: 0x0 (min: 0x1, max: 0xffffffffffffffff) ++glibc.malloc.mmap_threshold: 0x0 (min: 0x0, max: 0xffffffffffffffff) ++glibc.cpu.x86_data_cache_size: 0x8000 (min: 0x0, max: 0xffffffffffffffff) ++glibc.malloc.tcache_count: 0x0 (min: 0x0, max: 0xffffffffffffffff) ++glibc.malloc.arena_test: 0x0 (min: 0x1, max: 0xffffffffffffffff) ++glibc.pthread.mutex_spin_count: 100 (min: 0, max: 32767) ++glibc.rtld.optional_static_tls: 0x200 (min: 0x0, max: 0xffffffffffffffff) ++glibc.malloc.tcache_max: 0x0 (min: 0x0, max: 0xffffffffffffffff) ++glibc.malloc.check: 0 (min: 0, max: 3) ++@end example ++ + @menu + * Tunable names:: The structure of a tunable name + * Memory Allocation Tunables:: Tunables in the memory allocation subsystem diff --git a/SOURCES/glibc-rh2023420-2.patch b/SOURCES/glibc-rh2023420-2.patch new file mode 100644 index 0000000..23e3da5 --- /dev/null +++ b/SOURCES/glibc-rh2023420-2.patch @@ -0,0 +1,30 @@ +commit d2d12c7a988a9a04aec23b5e4af549db61b0a005 +Author: H.J. Lu +Date: Tue Feb 2 09:31:56 2021 -0800 + + tst-rtld-list-tunables.sh: Unset glibc tunables + + Unset glibc tunables and their aliases for --list-tunables test. + +diff --git a/elf/tst-rtld-list-tunables.sh b/elf/tst-rtld-list-tunables.sh +index e7bbdde94952b872..78f4ed2ebbd3db2c 100755 +--- a/elf/tst-rtld-list-tunables.sh ++++ b/elf/tst-rtld-list-tunables.sh +@@ -26,6 +26,17 @@ run_program_env=$3 + LC_ALL=C + export LC_ALL + ++# Unset tunables and their aliases. ++GLIBC_TUNABLES= ++MALLOC_ARENA_MAX= ++MALLOC_ARENA_TEST= ++MALLOC_CHECK_= ++MALLOC_MMAP_MAX_= ++MALLOC_MMAP_THRESHOLD_= ++MALLOC_PERTURB_= ++MALLOC_TOP_PAD_= ++MALLOC_TRIM_THRESHOLD_= ++ + ${test_wrapper_env} \ + ${run_program_env} \ + $rtld --list-tunables \ diff --git a/SOURCES/glibc-rh2023420-3.patch b/SOURCES/glibc-rh2023420-3.patch new file mode 100644 index 0000000..1e8307c --- /dev/null +++ b/SOURCES/glibc-rh2023420-3.patch @@ -0,0 +1,578 @@ +commit 851f32cf7bf7067f73b991610778915edd57d7b4 +Author: Florian Weimer +Date: Tue Mar 2 14:38:42 2021 +0100 + + ld.so: Implement the --list-diagnostics option + +diff --git a/elf/Makefile b/elf/Makefile +index aa65ec59f143bccf..d246f1c0d9e019fd 100644 +--- a/elf/Makefile ++++ b/elf/Makefile +@@ -64,7 +64,7 @@ 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-usage dl-diagnostics dl-diagnostics-kernel dl-diagnostics-cpu + all-rtld-routines = $(rtld-routines) $(sysdep-rtld-routines) + + CFLAGS-dl-runtime.c += -fexceptions -fasynchronous-unwind-tables +@@ -672,6 +672,9 @@ CFLAGS-cache.c += $(SYSCONF-FLAGS) + CFLAGS-rtld.c += $(SYSCONF-FLAGS) + CFLAGS-dl-usage.c += $(SYSCONF-FLAGS) \ + -D'RTLD="$(rtlddir)/$(rtld-installed-name)"' ++CFLAGS-dl-diagnostics.c += $(SYSCONF-FLAGS) \ ++ -D'PREFIX="$(prefix)"' \ ++ -D'RTLD="$(rtlddir)/$(rtld-installed-name)"' + + cpp-srcs-left := $(all-rtld-routines:=.os) + lib := rtld +diff --git a/elf/dl-diagnostics-cpu.c b/elf/dl-diagnostics-cpu.c +new file mode 100644 +index 0000000000000000..f7d149764bcb35a1 +--- /dev/null ++++ b/elf/dl-diagnostics-cpu.c +@@ -0,0 +1,24 @@ ++/* Print CPU diagnostics data in ld.so. Stub 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 ++ . */ ++ ++#include ++ ++void ++_dl_diagnostics_cpu (void) ++{ ++} +diff --git a/elf/dl-diagnostics-kernel.c b/elf/dl-diagnostics-kernel.c +new file mode 100644 +index 0000000000000000..831c358f1463cbf4 +--- /dev/null ++++ b/elf/dl-diagnostics-kernel.c +@@ -0,0 +1,24 @@ ++/* Print kernel diagnostics data in ld.so. Stub 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 ++ . */ ++ ++#include ++ ++void ++_dl_diagnostics_kernel (void) ++{ ++} +diff --git a/elf/dl-diagnostics.c b/elf/dl-diagnostics.c +new file mode 100644 +index 0000000000000000..bef224b36cbf5fc3 +--- /dev/null ++++ b/elf/dl-diagnostics.c +@@ -0,0 +1,265 @@ ++/* Print diagnostics data in ld.so. ++ 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 "trusted-dirs.h" ++#include "version.h" ++ ++/* Write CH to standard output. */ ++static void ++_dl_putc (char ch) ++{ ++ _dl_write (STDOUT_FILENO, &ch, 1); ++} ++ ++/* Print CH to standard output, quoting it if necessary. */ ++static void ++print_quoted_char (char ch) ++{ ++ if (ch < ' ' || ch > '~') ++ { ++ char buf[4]; ++ buf[0] = '\\'; ++ buf[1] = '0' + ((ch >> 6) & 7); ++ buf[2] = '0' + ((ch >> 6) & 7); ++ buf[3] = '0' + (ch & 7); ++ _dl_write (STDOUT_FILENO, buf, 4); ++ } ++ else ++ { ++ if (ch == '\\' || ch == '"') ++ _dl_putc ('\\'); ++ _dl_putc (ch); ++ } ++} ++ ++/* Print S of LEN bytes to standard output, quoting characters as ++ needed. */ ++static void ++print_string_length (const char *s, size_t len) ++{ ++ _dl_putc ('"'); ++ for (size_t i = 0; i < len; ++i) ++ print_quoted_char (s[i]); ++ _dl_putc ('"'); ++} ++ ++void ++_dl_diagnostics_print_string (const char *s) ++{ ++ if (s == NULL) ++ { ++ _dl_printf ("0x0"); ++ return; ++ } ++ ++ _dl_putc ('"'); ++ while (*s != '\0') ++ { ++ print_quoted_char (*s); ++ ++s; ++ } ++ _dl_putc ('"'); ++} ++ ++void ++_dl_diagnostics_print_labeled_string (const char *label, const char *s) ++{ ++ _dl_printf ("%s=", label); ++ _dl_diagnostics_print_string (s); ++ _dl_putc ('\n'); ++} ++ ++void ++_dl_diagnostics_print_labeled_value (const char *label, uint64_t value) ++{ ++ if (sizeof (value) == sizeof (unsigned long int)) ++ /* _dl_printf can print 64-bit values directly. */ ++ _dl_printf ("%s=0x%lx\n", label, (unsigned long int) value); ++ else ++ { ++ uint32_t high = value >> 32; ++ uint32_t low = value; ++ if (high == 0) ++ _dl_printf ("%s=0x%x\n", label, low); ++ else ++ _dl_printf ("%s=0x%x%08x\n", label, high, low); ++ } ++} ++ ++/* Return true if ENV is an unfiltered environment variable. */ ++static bool ++unfiltered_envvar (const char *env, size_t *name_length) ++{ ++ char *env_equal = strchr (env, '='); ++ if (env_equal == NULL) ++ { ++ /* Always dump malformed entries. */ ++ *name_length = strlen (env); ++ return true; ++ } ++ size_t envname_length = env_equal - env; ++ *name_length = envname_length; ++ ++ /* LC_ and LD_ variables. */ ++ if (env[0] == 'L' && (env[1] == 'C' || env[1] == 'D') ++ && env[2] == '_') ++ return true; ++ ++ /* MALLOC_ variables. */ ++ if (strncmp (env, "MALLOC_", strlen ("MALLOC_")) == 0) ++ return true; ++ ++ static const char unfiltered[] = ++ "DATEMSK\0" ++ "GCONV_PATH\0" ++ "GETCONF_DIR\0" ++ "GETCONF_DIR\0" ++ "GLIBC_TUNABLES\0" ++ "GMON_OUTPUT_PREFIX\0" ++ "HESIOD_CONFIG\0" ++ "HES_DOMAIN\0" ++ "HOSTALIASES\0" ++ "I18NPATH\0" ++ "IFS\0" ++ "LANG\0" ++ "LOCALDOMAIN\0" ++ "LOCPATH\0" ++ "MSGVERB\0" ++ "NIS_DEFAULTS\0" ++ "NIS_GROUP\0" ++ "NIS_PATH\0" ++ "NLSPATH\0" ++ "PATH\0" ++ "POSIXLY_CORRECT\0" ++ "RESOLV_HOST_CONF\0" ++ "RES_OPTIONS\0" ++ "SEV_LEVEL\0" ++ "TMPDIR\0" ++ "TZ\0" ++ "TZDIR\0" ++ /* Two null bytes at the end to mark the end of the list via an ++ empty substring. */ ++ ; ++ for (const char *candidate = unfiltered; *candidate != '\0'; ) ++ { ++ size_t candidate_length = strlen (candidate); ++ if (candidate_length == envname_length ++ && memcmp (candidate, env, candidate_length) == 0) ++ return true; ++ candidate += candidate_length + 1; ++ } ++ ++ return false; ++} ++ ++/* Dump the process environment. */ ++static void ++print_environ (char **environ) ++{ ++ unsigned int index = 0; ++ for (char **envp = environ; *envp != NULL; ++envp) ++ { ++ char *env = *envp; ++ size_t name_length; ++ bool unfiltered = unfiltered_envvar (env, &name_length); ++ _dl_printf ("env%s[0x%x]=", ++ unfiltered ? "" : "_filtered", index); ++ if (unfiltered) ++ _dl_diagnostics_print_string (env); ++ else ++ print_string_length (env, name_length); ++ _dl_putc ('\n'); ++ ++index; ++ } ++} ++ ++/* Print configured paths and the built-in search path. */ ++static void ++print_paths (void) ++{ ++ _dl_diagnostics_print_labeled_string ("path.prefix", PREFIX); ++ _dl_diagnostics_print_labeled_string ("path.rtld", RTLD); ++ _dl_diagnostics_print_labeled_string ("path.sysconfdir", SYSCONFDIR); ++ ++ unsigned int index = 0; ++ static const char *system_dirs = SYSTEM_DIRS "\0"; ++ for (const char *e = system_dirs; *e != '\0'; ) ++ { ++ size_t len = strlen (e); ++ _dl_printf ("path.system_dirs[0x%x]=", index); ++ print_string_length (e, len); ++ _dl_putc ('\n'); ++ ++index; ++ e += len + 1; ++ } ++} ++ ++/* Print information about the glibc version. */ ++static void ++print_version (void) ++{ ++ _dl_diagnostics_print_labeled_string ("version.release", RELEASE); ++ _dl_diagnostics_print_labeled_string ("version.version", VERSION); ++} ++ ++void ++_dl_print_diagnostics (char **environ) ++{ ++#ifdef HAVE_DL_DISCOVER_OSVERSION ++ _dl_diagnostics_print_labeled_value ++ ("dl_discover_osversion", _dl_discover_osversion ()); ++#endif ++ _dl_diagnostics_print_labeled_string ("dl_dst_lib", DL_DST_LIB); ++ _dl_diagnostics_print_labeled_value ("dl_hwcap", GLRO (dl_hwcap)); ++ _dl_diagnostics_print_labeled_value ("dl_hwcap_important", HWCAP_IMPORTANT); ++ _dl_diagnostics_print_labeled_value ("dl_hwcap2", GLRO (dl_hwcap2)); ++ _dl_diagnostics_print_labeled_string ++ ("dl_hwcaps_subdirs", _dl_hwcaps_subdirs); ++ _dl_diagnostics_print_labeled_value ++ ("dl_hwcaps_subdirs_active", _dl_hwcaps_subdirs_active ()); ++ _dl_diagnostics_print_labeled_value ("dl_osversion", GLRO (dl_osversion)); ++ _dl_diagnostics_print_labeled_value ("dl_pagesize", GLRO (dl_pagesize)); ++ _dl_diagnostics_print_labeled_string ("dl_platform", GLRO (dl_platform)); ++ _dl_diagnostics_print_labeled_string ++ ("dl_profile_output", GLRO (dl_profile_output)); ++ _dl_diagnostics_print_labeled_value ++ ("dl_string_platform", _dl_string_platform ( GLRO (dl_platform))); ++ ++ _dl_diagnostics_print_labeled_string ("dso.ld", LD_SO); ++ _dl_diagnostics_print_labeled_string ("dso.libc", LIBC_SO); ++ ++ print_environ (environ); ++ print_paths (); ++ print_version (); ++ ++ _dl_diagnostics_kernel (); ++ _dl_diagnostics_cpu (); ++ ++ _exit (EXIT_SUCCESS); ++} +diff --git a/elf/dl-diagnostics.h b/elf/dl-diagnostics.h +new file mode 100644 +index 0000000000000000..27dcb12bca12e5b6 +--- /dev/null ++++ b/elf/dl-diagnostics.h +@@ -0,0 +1,46 @@ ++/* Interfaces for printing diagnostics in ld.so. ++ 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_DIAGNOSTICS_H ++#define _DL_DIAGNOSTICS_H ++ ++#include ++ ++/* Write the null-terminated string to standard output, surrounded in ++ quotation marks. */ ++void _dl_diagnostics_print_string (const char *s) attribute_hidden; ++ ++/* Like _dl_diagnostics_print_string, but add a LABEL= prefix, and a ++ newline character as a suffix. */ ++void _dl_diagnostics_print_labeled_string (const char *label, const char *s) ++ attribute_hidden; ++ ++/* Print LABEL=VALUE to standard output, followed by a newline ++ character. */ ++void _dl_diagnostics_print_labeled_value (const char *label, uint64_t value) ++ attribute_hidden; ++ ++/* Print diagnostics data for the kernel. Called from ++ _dl_print_diagnostics. */ ++void _dl_diagnostics_kernel (void) attribute_hidden; ++ ++/* Print diagnostics data for the CPU(s). Called from ++ _dl_print_diagnostics. */ ++void _dl_diagnostics_cpu (void) attribute_hidden; ++ ++#endif /* _DL_DIAGNOSTICS_H */ +diff --git a/elf/dl-main.h b/elf/dl-main.h +index 9e7b51d8f010e904..9fbbdb0fac09adf3 100644 +--- a/elf/dl-main.h ++++ b/elf/dl-main.h +@@ -63,7 +63,7 @@ struct audit_list + enum rtld_mode + { + rtld_mode_normal, rtld_mode_list, rtld_mode_verify, rtld_mode_trace, +- rtld_mode_list_tunables, rtld_mode_help, ++ rtld_mode_list_tunables, rtld_mode_list_diagnostics, rtld_mode_help, + }; + + /* Aggregated state information extracted from environment variables +@@ -121,4 +121,7 @@ _Noreturn void _dl_version (void) attribute_hidden; + _Noreturn void _dl_help (const char *argv0, struct dl_main_state *state) + attribute_hidden; + ++/* Print a diagnostics dump. */ ++_Noreturn void _dl_print_diagnostics (char **environ) attribute_hidden; ++ + #endif /* _DL_MAIN */ +diff --git a/elf/dl-usage.c b/elf/dl-usage.c +index 908b4894b3014b2d..e19e1791d9169da2 100644 +--- a/elf/dl-usage.c ++++ b/elf/dl-usage.c +@@ -261,6 +261,7 @@ setting environment variables (which would be inherited by subprocesses).\n\ + --list-tunables list all tunables with minimum and maximum values\n" + #endif + "\ ++ --list-diagnostics list diagnostics information\n\ + --help display this help and exit\n\ + --version output version information and exit\n\ + \n\ +diff --git a/elf/rtld.c b/elf/rtld.c +index 54b621ec5ca014fa..d14c388f548d6d51 100644 +--- a/elf/rtld.c ++++ b/elf/rtld.c +@@ -138,6 +138,7 @@ static void dl_main_state_init (struct dl_main_state *state); + /* Process all environments variables the dynamic linker must recognize. + Since all of them start with `LD_' we are a bit smarter while finding + all the entries. */ ++extern char **_environ attribute_hidden; + static void process_envvars (struct dl_main_state *state); + + #ifdef DL_ARGV_NOT_RELRO +@@ -1273,6 +1274,14 @@ dl_main (const ElfW(Phdr) *phdr, + ++_dl_argv; + } + #endif ++ else if (! strcmp (_dl_argv[1], "--list-diagnostics")) ++ { ++ state.mode = rtld_mode_list_diagnostics; ++ ++ ++_dl_skip_args; ++ --_dl_argc; ++ ++_dl_argv; ++ } + else if (strcmp (_dl_argv[1], "--help") == 0) + { + state.mode = rtld_mode_help; +@@ -1301,6 +1310,9 @@ dl_main (const ElfW(Phdr) *phdr, + } + #endif + ++ if (state.mode == rtld_mode_list_diagnostics) ++ _dl_print_diagnostics (_environ); ++ + /* If we have no further argument the program was called incorrectly. + Grant the user some education. */ + if (_dl_argc < 2) +@@ -2623,12 +2635,6 @@ a filename can be specified using the LD_DEBUG_OUTPUT environment variable.\n"); + } + } + +-/* Process all environments variables the dynamic linker must recognize. +- Since all of them start with `LD_' we are a bit smarter while finding +- all the entries. */ +-extern char **_environ attribute_hidden; +- +- + static void + process_envvars (struct dl_main_state *state) + { +diff --git a/sysdeps/unix/sysv/linux/dl-diagnostics-kernel.c b/sysdeps/unix/sysv/linux/dl-diagnostics-kernel.c +new file mode 100644 +index 0000000000000000..59f6402c547ba590 +--- /dev/null ++++ b/sysdeps/unix/sysv/linux/dl-diagnostics-kernel.c +@@ -0,0 +1,77 @@ ++/* Print kernel diagnostics data in ld.so. Linux 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 ++ . */ ++ ++#include ++#include ++#include ++ ++/* Dump the auxiliary vector to standard output. */ ++static void ++print_auxv (void) ++{ ++ /* See _dl_show_auxv. The code below follows the general output ++ format for diagnostic dumps. */ ++ unsigned int index = 0; ++ for (ElfW(auxv_t) *av = GLRO(dl_auxv); av->a_type != AT_NULL; ++av) ++ { ++ _dl_printf ("auxv[0x%x].a_type=0x%lx\n" ++ "auxv[0x%x].a_val=", ++ index, (unsigned long int) av->a_type, index); ++ if (av->a_type == AT_EXECFN ++ || av->a_type == AT_PLATFORM ++ || av->a_type == AT_BASE_PLATFORM) ++ /* The address of the strings is not useful at all, so print ++ the strings themselvs. */ ++ _dl_diagnostics_print_string ((const char *) av->a_un.a_val); ++ else ++ _dl_printf ("0x%lx", (unsigned long int) av->a_un.a_val); ++ _dl_printf ("\n"); ++ ++index; ++ } ++} ++ ++/* Print one uname entry. */ ++static void ++print_utsname_entry (const char *field, const char *value) ++{ ++ _dl_printf ("uname."); ++ _dl_diagnostics_print_labeled_string (field, value); ++} ++ ++/* Print information from uname, including the kernel version. */ ++static void ++print_uname (void) ++{ ++ struct utsname uts; ++ if (__uname (&uts) == 0) ++ { ++ print_utsname_entry ("sysname", uts.sysname); ++ print_utsname_entry ("nodename", uts.nodename); ++ print_utsname_entry ("release", uts.release); ++ print_utsname_entry ("version", uts.version); ++ print_utsname_entry ("machine", uts.machine); ++ print_utsname_entry ("domainname", uts.domainname); ++ } ++} ++ ++void ++_dl_diagnostics_kernel (void) ++{ ++ print_auxv (); ++ print_uname (); ++} diff --git a/SOURCES/glibc-rh2023420-4.patch b/SOURCES/glibc-rh2023420-4.patch new file mode 100644 index 0000000..bf1a407 --- /dev/null +++ b/SOURCES/glibc-rh2023420-4.patch @@ -0,0 +1,117 @@ +commit e4933c8a92ea08eecdf3ab45e7f76c95dc3d20ac +Author: Florian Weimer +Date: Tue Mar 2 14:58:05 2021 +0100 + + x86: Automate generation of PREFERRED_FEATURE_INDEX_1 bitfield + + Use a .def file to define the bitfield layout, so that it is possible + to iterate over field members using the preprocessor. + +Conflicts: + sysdeps/x86/include/cpu-features.h + (re-did the change from scratch) + sysdeps/x86/include/cpu-features-preferred_feature_index_1.def + (adjusted to the downstream bits) + +diff --git a/sysdeps/x86/include/cpu-features-preferred_feature_index_1.def b/sysdeps/x86/include/cpu-features-preferred_feature_index_1.def +new file mode 100644 +index 0000000000000000..17a5cc428c1dabea +--- /dev/null ++++ b/sysdeps/x86/include/cpu-features-preferred_feature_index_1.def +@@ -0,0 +1,34 @@ ++/* Bits in the PREFERRED_FEATURE_INDEX_1 bitfield of . ++ 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 ++ . */ ++ ++BIT (I586) ++BIT (I686) ++BIT (Fast_Rep_String) ++BIT (Fast_Copy_Backward) ++BIT (Fast_Unaligned_Load) ++BIT (Fast_Unaligned_Copy) ++BIT (Slow_BSF) ++BIT (Slow_SSE4_2) ++BIT (AVX_Fast_Unaligned_Load) ++BIT (Prefer_MAP_32BIT_EXEC) ++BIT (Prefer_PMINUB_for_stringop) ++BIT (Prefer_No_VZEROUPPER) ++BIT (Prefer_ERMS) ++BIT (Prefer_FSRM) ++BIT (Prefer_No_AVX512) ++BIT (MathVec_Prefer_No_AVX512) +diff --git a/sysdeps/x86/include/cpu-features.h b/sysdeps/x86/include/cpu-features.h +index f62be0b9b3746675..f43e22f677b249a9 100644 +--- a/sysdeps/x86/include/cpu-features.h ++++ b/sysdeps/x86/include/cpu-features.h +@@ -80,40 +80,23 @@ enum + # define HAS_ARCH_FEATURE(name) \ + CPU_FEATURE_PREFERRED (name) + +-/* PREFERRED_FEATURE_INDEX_1. */ +-# define bit_arch_I586 (1u << 0) +-# define bit_arch_I686 (1u << 1) +-# define bit_arch_Fast_Rep_String (1u << 2) +-# define bit_arch_Fast_Copy_Backward (1u << 3) +-# define bit_arch_Fast_Unaligned_Load (1u << 4) +-# define bit_arch_Fast_Unaligned_Copy (1u << 5) +-# define bit_arch_Slow_BSF (1u << 6) +-# define bit_arch_Slow_SSE4_2 (1u << 7) +-# define bit_arch_AVX_Fast_Unaligned_Load (1u << 8) +-# define bit_arch_Prefer_MAP_32BIT_EXEC (1u << 9) +-# define bit_arch_Prefer_PMINUB_for_stringop (1u << 10) +-# define bit_arch_Prefer_No_VZEROUPPER (1u << 11) +-# define bit_arch_Prefer_ERMS (1u << 12) +-# define bit_arch_Prefer_FSRM (1u << 13) +-# define bit_arch_Prefer_No_AVX512 (1u << 14) +-# define bit_arch_MathVec_Prefer_No_AVX512 (1u << 15) +- +-# define index_arch_Fast_Rep_String PREFERRED_FEATURE_INDEX_1 +-# define index_arch_Fast_Copy_Backward PREFERRED_FEATURE_INDEX_1 +-# define index_arch_Slow_BSF PREFERRED_FEATURE_INDEX_1 +-# define index_arch_Fast_Unaligned_Load PREFERRED_FEATURE_INDEX_1 +-# define index_arch_Prefer_PMINUB_for_stringop PREFERRED_FEATURE_INDEX_1 +-# define index_arch_Fast_Unaligned_Copy PREFERRED_FEATURE_INDEX_1 +-# define index_arch_I586 PREFERRED_FEATURE_INDEX_1 +-# define index_arch_I686 PREFERRED_FEATURE_INDEX_1 +-# define index_arch_Slow_SSE4_2 PREFERRED_FEATURE_INDEX_1 +-# define index_arch_AVX_Fast_Unaligned_Load PREFERRED_FEATURE_INDEX_1 +-# define index_arch_Prefer_MAP_32BIT_EXEC PREFERRED_FEATURE_INDEX_1 +-# define index_arch_Prefer_No_VZEROUPPER PREFERRED_FEATURE_INDEX_1 +-# define index_arch_Prefer_ERMS PREFERRED_FEATURE_INDEX_1 +-# define index_arch_Prefer_No_AVX512 PREFERRED_FEATURE_INDEX_1 +-# define index_arch_MathVec_Prefer_No_AVX512 PREFERRED_FEATURE_INDEX_1 +-# define index_arch_Prefer_FSRM PREFERRED_FEATURE_INDEX_1 ++/* PREFERRED_FEATURE_INDEX_1. First define the bitindex values ++ sequentially, then define the bit_arch* and index_arch_* lookup ++ constants. */ ++enum ++ { ++#define BIT(x) _bitindex_arch_##x , ++#include "cpu-features-preferred_feature_index_1.def" ++#undef BIT ++ }; ++enum ++ { ++#define BIT(x) \ ++ bit_arch_##x = 1u << _bitindex_arch_##x , \ ++ index_arch_##x = PREFERRED_FEATURE_INDEX_1, ++#include "cpu-features-preferred_feature_index_1.def" ++#undef BIT ++ }; + + /* XCR0 Feature flags. */ + # define bit_XMM_state (1u << 1) diff --git a/SOURCES/glibc-rh2023420-5.patch b/SOURCES/glibc-rh2023420-5.patch new file mode 100644 index 0000000..0d3ca97 --- /dev/null +++ b/SOURCES/glibc-rh2023420-5.patch @@ -0,0 +1,131 @@ +commit 01a5746b6c8a44dc29d33e056b63485075a6a3cc +Author: Florian Weimer +Date: Wed Feb 24 13:12:04 2021 +0100 + + x86: Add CPU-specific diagnostics to ld.so --list-diagnostics + +Conflicts: + sysdeps/x86/dl-diagnostics-cpu.c + (reworked due to struct differences, different knobs + downstream) + +diff --git a/sysdeps/x86/dl-diagnostics-cpu.c b/sysdeps/x86/dl-diagnostics-cpu.c +new file mode 100644 +index 0000000000000000..0ba286a828b69937 +--- /dev/null ++++ b/sysdeps/x86/dl-diagnostics-cpu.c +@@ -0,0 +1,101 @@ ++/* Print CPU diagnostics data in ld.so. 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 ++ . */ ++ ++#include ++#include ++ ++static void ++print_cpu_features_value (const char *label, uint64_t value) ++{ ++ _dl_printf ("x86.cpu_features."); ++ _dl_diagnostics_print_labeled_value (label, value); ++} ++ ++static void ++print_cpu_feature_internal (unsigned int index, const char *kind, ++ unsigned int reg, uint32_t value) ++{ ++ _dl_printf ("x86.cpu_features.features[0x%x].%s[0x%x]=0x%x\n", ++ index, kind, reg, value); ++} ++ ++static void ++print_cpu_feature_preferred (const char *label, unsigned int flag) ++{ ++ _dl_printf("x86.cpu_features.preferred.%s=0x%x\n", label, flag); ++} ++ ++void ++_dl_diagnostics_cpu (void) ++{ ++ const struct cpu_features *cpu_features = __get_cpu_features (); ++ ++ print_cpu_features_value ("basic.kind", cpu_features->basic.kind); ++ print_cpu_features_value ("basic.max_cpuid", cpu_features->basic.max_cpuid); ++ print_cpu_features_value ("basic.family", cpu_features->basic.family); ++ print_cpu_features_value ("basic.model", cpu_features->basic.model); ++ print_cpu_features_value ("basic.stepping", cpu_features->basic.stepping); ++ ++ for (unsigned int index = 0; index < COMMON_CPUID_INDEX_MAX; ++index) ++ { ++ /* Downstream, these constants are not part of the ABI yet, so ++ analysis needs to take the precise glibc version into ++ account. */ ++ print_cpu_feature_internal ++ (index, "cpuid", 0, cpu_features->features[index].cpuid.eax); ++ print_cpu_feature_internal ++ (index, "cpuid", 1, cpu_features->features[index].cpuid.ebx); ++ print_cpu_feature_internal ++ (index, "cpuid", 2, cpu_features->features[index].cpuid.ecx); ++ print_cpu_feature_internal ++ (index, "cpuid", 3, cpu_features->features[index].cpuid.edx); ++ print_cpu_feature_internal ++ (index, "usable", 0, cpu_features->features[index].usable.eax); ++ print_cpu_feature_internal ++ (index, "usable", 1, cpu_features->features[index].usable.ebx); ++ print_cpu_feature_internal ++ (index, "usable", 2, cpu_features->features[index].usable.ecx); ++ print_cpu_feature_internal ++ (index, "usable", 3, cpu_features->features[index].usable.edx); ++ } ++ ++ /* The preferred indicators are not part of the ABI and need to be ++ translated. */ ++#define BIT(x) \ ++ print_cpu_feature_preferred (#x, CPU_FEATURE_PREFERRED_P (cpu_features, x)); ++#include "cpu-features-preferred_feature_index_1.def" ++#undef BIT ++ ++ print_cpu_features_value ("xsave_state_size", ++ cpu_features->xsave_state_size); ++ print_cpu_features_value ("xsave_state_full_size", ++ cpu_features->xsave_state_full_size); ++ print_cpu_features_value ("data_cache_size", cpu_features->data_cache_size); ++ print_cpu_features_value ("shared_cache_size", ++ cpu_features->shared_cache_size); ++ print_cpu_features_value ("non_temporal_threshold", ++ cpu_features->non_temporal_threshold); ++ print_cpu_features_value ("rep_movsb_threshold", ++ cpu_features->rep_movsb_threshold); ++ print_cpu_features_value ("rep_stosb_threshold", ++ cpu_features->rep_stosb_threshold); ++ _Static_assert (offsetof (struct cpu_features, rep_stosb_threshold) ++ + sizeof (cpu_features->rep_stosb_threshold) ++ == sizeof (*cpu_features), ++ "last cpu_features field has been printed"); ++} +diff --git a/sysdeps/x86/include/cpu-features.h b/sysdeps/x86/include/cpu-features.h +index f43e22f677b249a9..536643b209425198 100644 +--- a/sysdeps/x86/include/cpu-features.h ++++ b/sysdeps/x86/include/cpu-features.h +@@ -107,6 +107,8 @@ enum + # define bit_XTILECFG_state (1u << 17) + # define bit_XTILEDATA_state (1u << 18) + ++/* NB: When adding new fields, update sysdeps/x86/dl-diagnostics-cpu.c ++ to print them. */ + struct cpu_features + { + struct cpu_features_basic basic; diff --git a/SOURCES/glibc-rh2023420-6.patch b/SOURCES/glibc-rh2023420-6.patch new file mode 100644 index 0000000..a05a690 --- /dev/null +++ b/SOURCES/glibc-rh2023420-6.patch @@ -0,0 +1,255 @@ +commit c1cb2deeca1a85c6fc5bd41b90816d48a95bc434 +Author: Florian Weimer +Date: Sun Dec 5 11:28:34 2021 +0100 + + elf: execve statically linked programs instead of crashing [BZ #28648] + + Programs without dynamic dependencies and without a program + interpreter are now run via execve. + + Previously, the dynamic linker either crashed while attempting to + read a non-existing dynamic segment (looking for DT_AUDIT/DT_DEPAUDIT + data), or the self-relocated in the static PIE executable crashed + because the outer dynamic linker had already applied RELRO protection. + + is needed because execve is not available in the + dynamic loader on Hurd. + + Reviewed-by: H.J. Lu + +Conflicts: + elf/Makefile + (some missing backports) + elf/rtld.c + (missing rework of ld.so self-relocation downstream, + always print error as a number due to missing + sterrorname_np, also fix errcode/errno glitch) + sysdeps/unix/sysv/linux/dl-execve.h + (missing INTERNAL_SYSCALL_CALL refactoring to Linux-like + calling convention) + +diff --git a/elf/Makefile b/elf/Makefile +index d246f1c0d9e019fd..b3e8ab2792608de7 100644 +--- a/elf/Makefile ++++ b/elf/Makefile +@@ -214,7 +214,8 @@ tests += restest1 preloadtest loadfail multiload origtest resolvfail \ + tst-tls-ie tst-tls-ie-dlmopen \ + argv0test \ + tst-glibc-hwcaps tst-glibc-hwcaps-prepend tst-glibc-hwcaps-mask \ +- tst-tls20 tst-tls21 ++ tst-tls20 tst-tls21 \ ++ tst-rtld-run-static \ + # reldep9 + tests-internal += loadtest unload unload2 circleload1 \ + neededtest neededtest2 neededtest3 neededtest4 \ +@@ -1917,3 +1918,5 @@ $(objpfx)tst-tls20.out: $(objpfx)tst-tls20mod-bad.so \ + $(objpfx)tst-tls21: $(libdl) $(shared-thread-library) + $(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 +diff --git a/elf/rtld.c b/elf/rtld.c +index d14c388f548d6d51..461d8c114a875a9b 100644 +--- a/elf/rtld.c ++++ b/elf/rtld.c +@@ -48,6 +48,7 @@ + #include + #include + #include ++#include + + #include + +@@ -1114,6 +1115,40 @@ load_audit_modules (struct link_map *main_map, struct audit_list *audit_list) + } + } + ++/* Check if the executable is not actualy dynamically linked, and ++ invoke it directly in that case. */ ++static void ++rtld_chain_load (struct link_map *main_map, char *argv0) ++{ ++ /* The dynamic loader run against itself. */ ++ const char *rtld_soname ++ = ((const char *) D_PTR (&GL(dl_rtld_map), l_info[DT_STRTAB]) ++ + GL(dl_rtld_map).l_info[DT_SONAME]->d_un.d_val); ++ if (main_map->l_info[DT_SONAME] != NULL ++ && strcmp (rtld_soname, ++ ((const char *) D_PTR (main_map, l_info[DT_STRTAB]) ++ + main_map->l_info[DT_SONAME]->d_un.d_val)) == 0) ++ _dl_fatal_printf ("%s: loader cannot load itself\n", rtld_soname); ++ ++ /* With DT_NEEDED dependencies, the executable is dynamically ++ linked. */ ++ if (__glibc_unlikely (main_map->l_info[DT_NEEDED] != NULL)) ++ return; ++ ++ /* If the executable has program interpreter, it is dynamically ++ linked. */ ++ for (size_t i = 0; i < main_map->l_phnum; ++i) ++ if (main_map->l_phdr[i].p_type == PT_INTERP) ++ return; ++ ++ const char *pathname = _dl_argv[0]; ++ if (argv0 != NULL) ++ _dl_argv[0] = argv0; ++ int errcode = __rtld_execve (pathname, _dl_argv, _environ); ++ _dl_fatal_printf("%s: cannot execute %s: %d\n", ++ rtld_soname, pathname, errcode); ++} ++ + static void + dl_main (const ElfW(Phdr) *phdr, + ElfW(Word) phnum, +@@ -1384,14 +1419,8 @@ dl_main (const ElfW(Phdr) *phdr, + /* Now the map for the main executable is available. */ + main_map = GL(dl_ns)[LM_ID_BASE]._ns_loaded; + +- if (__glibc_likely (state.mode == rtld_mode_normal) +- && GL(dl_rtld_map).l_info[DT_SONAME] != NULL +- && main_map->l_info[DT_SONAME] != NULL +- && strcmp ((const char *) D_PTR (&GL(dl_rtld_map), l_info[DT_STRTAB]) +- + GL(dl_rtld_map).l_info[DT_SONAME]->d_un.d_val, +- (const char *) D_PTR (main_map, l_info[DT_STRTAB]) +- + main_map->l_info[DT_SONAME]->d_un.d_val) == 0) +- _dl_fatal_printf ("loader cannot load itself\n"); ++ if (__glibc_likely (state.mode == rtld_mode_normal)) ++ rtld_chain_load (main_map, argv0); + + phdr = main_map->l_phdr; + phnum = main_map->l_phnum; +diff --git a/elf/tst-rtld-run-static.c b/elf/tst-rtld-run-static.c +new file mode 100644 +index 0000000000000000..7281093504b675c4 +--- /dev/null ++++ b/elf/tst-rtld-run-static.c +@@ -0,0 +1,62 @@ ++/* Test running statically linked programs using ld.so. ++ 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 ++ ++static int ++do_test (void) ++{ ++ char *ldconfig_path = xasprintf ("%s/elf/ldconfig", support_objdir_root); ++ ++ { ++ char *argv[] = { (char *) "ld.so", ldconfig_path, (char *) "--help", NULL }; ++ struct support_capture_subprocess cap ++ = support_capture_subprogram (support_objdir_elf_ldso, argv); ++ support_capture_subprocess_check (&cap, "no --argv0", 0, sc_allow_stdout); ++ puts ("info: output without --argv0:"); ++ puts (cap.out.buffer); ++ TEST_VERIFY (strstr (cap.out.buffer, "Usage: ldconfig [OPTION...]\n") ++ == cap.out.buffer); ++ support_capture_subprocess_free (&cap); ++ } ++ ++ { ++ char *argv[] = ++ { ++ (char *) "ld.so", (char *) "--argv0", (char *) "ldconfig-argv0", ++ ldconfig_path, (char *) "--help", NULL ++ }; ++ struct support_capture_subprocess cap ++ = support_capture_subprogram (support_objdir_elf_ldso, argv); ++ support_capture_subprocess_check (&cap, "with --argv0", 0, sc_allow_stdout); ++ puts ("info: output with --argv0:"); ++ puts (cap.out.buffer); ++ TEST_VERIFY (strstr (cap.out.buffer, "Usage: ldconfig-argv0 [OPTION...]\n") ++ == cap.out.buffer); ++ support_capture_subprocess_free (&cap); ++ } ++ ++ free (ldconfig_path); ++ return 0; ++} ++ ++#include +diff --git a/sysdeps/generic/dl-execve.h b/sysdeps/generic/dl-execve.h +new file mode 100644 +index 0000000000000000..5fd097df69e1770c +--- /dev/null ++++ b/sysdeps/generic/dl-execve.h +@@ -0,0 +1,25 @@ ++/* execve for the dynamic linker. Generic stub 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 ++ . */ ++ ++#include ++ ++static int ++__rtld_execve (const char *path, char *const *argv, char *const *envp) ++{ ++ return ENOSYS; ++} +diff --git a/sysdeps/unix/sysv/linux/dl-execve.h b/sysdeps/unix/sysv/linux/dl-execve.h +new file mode 100644 +index 0000000000000000..9ec6539286bb0589 +--- /dev/null ++++ b/sysdeps/unix/sysv/linux/dl-execve.h +@@ -0,0 +1,30 @@ ++/* execve for the dynamic linker. Linux 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 ++ . */ ++ ++#include ++ ++static inline int ++__rtld_execve (const char *path, char *const *argv, char *const *envp) ++{ ++ INTERNAL_SYSCALL_DECL (err); ++ long int r = INTERNAL_SYSCALL_CALL (execve, err, path, argv, envp); ++ if (INTERNAL_SYSCALL_ERROR_P (r, err)) ++ return INTERNAL_SYSCALL_ERRNO (r, err); ++ else ++ return 0; ++} diff --git a/SOURCES/glibc-rh2023420-7.patch b/SOURCES/glibc-rh2023420-7.patch new file mode 100644 index 0000000..c14031c --- /dev/null +++ b/SOURCES/glibc-rh2023420-7.patch @@ -0,0 +1,41 @@ +commit 2e75604f8337fa4332977f72a8f6726309679edf +Author: Florian Weimer +Date: Fri Dec 10 16:06:36 2021 +0100 + + elf: Install a symbolic link to ld.so as /usr/bin/ld.so + + This makes ld.so features such as --preload, --audit, + and --list-diagnostics more accessible to end users because they + do not need to know the ABI name of the dynamic loader. + + Reviewed-by: Carlos O'Donell + + Conflicts: + elf/Makefile + (versioned shared objects downstream) + +diff --git a/elf/Makefile b/elf/Makefile +index b3e8ab2792608de7..c552aff350c2faac 100644 +--- a/elf/Makefile ++++ b/elf/Makefile +@@ -99,7 +99,7 @@ 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 +-install-others = $(inst_rtlddir)/$(rtld-installed-name) ++install-others = $(inst_rtlddir)/$(rtld-installed-name) $(inst_bindir)/ld.so + install-bin-script = ldd + endif + +@@ -622,6 +622,11 @@ $(inst_rtlddir)/$(rtld-installed-name): \ + $(make-target-directory) + $(make-shlib-link) + ++# Creates the relative /usr/bin/ld.so symbolic link. ++$(inst_bindir)/ld.so: $(inst_rtlddir)/$(rtld-installed-name) ++ $(make-target-directory) ++ $(make-link) ++ + # Special target called by parent to install just the dynamic linker. + .PHONY: ldso_install + ldso_install: $(inst_rtlddir)/$(rtld-installed-name) diff --git a/SOURCES/glibc-rh2032281-1.patch b/SOURCES/glibc-rh2032281-1.patch new file mode 100644 index 0000000..6308350 --- /dev/null +++ b/SOURCES/glibc-rh2032281-1.patch @@ -0,0 +1,64 @@ +commit a7e9dbb7742954814643a8562dcad09abb0b0e5d +Author: Alexandra Hájková +Date: Sat Dec 26 18:45:13 2020 +0100 + + Add xchdir to libsupport. + +diff --git a/support/Makefile b/support/Makefile +index dcf3c4baa2a31070..fb95a69ed9158e78 100644 +--- a/support/Makefile ++++ b/support/Makefile +@@ -82,6 +82,7 @@ libsupport-routines = \ + xasprintf \ + xbind \ + xcalloc \ ++ xchdir \ + xchroot \ + xclose \ + xconnect \ +diff --git a/support/xchdir.c b/support/xchdir.c +new file mode 100644 +index 0000000000000000..beb4feff72832065 +--- /dev/null ++++ b/support/xchdir.c +@@ -0,0 +1,28 @@ ++/* chdir with error checking. ++ 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 ++ ++void ++xchdir (const char *path) ++{ ++ if (chdir (path) != 0) ++ FAIL_EXIT1 ("chdir (\"%s\"): %m", path); ++} +diff --git a/support/xunistd.h b/support/xunistd.h +index f99f362cb4763c5b..74fd2771d12c36fe 100644 +--- a/support/xunistd.h ++++ b/support/xunistd.h +@@ -44,6 +44,7 @@ long xsysconf (int name); + long long xlseek (int fd, long long offset, int whence); + void xftruncate (int fd, long long length); + void xsymlink (const char *target, const char *linkpath); ++void xchdir (const char *path); + + /* Equivalent of "mkdir -p". */ + void xmkdirp (const char *, mode_t); diff --git a/SOURCES/glibc-rh2032281-2.patch b/SOURCES/glibc-rh2032281-2.patch new file mode 100644 index 0000000..feac384 --- /dev/null +++ b/SOURCES/glibc-rh2032281-2.patch @@ -0,0 +1,74 @@ +Additionally include stdbool.h to fix issues with bool keyword usage. + +commit 60854f40ea2d420867ed2f0f052ee7fca661dbff +Author: Adhemerval Zanella +Date: Thu Oct 15 15:14:22 2020 -0300 + + support: Add create_temp_file_in_dir + + It allows created a temporary file in a specified directory. + +diff --git a/support/support.h b/support/support.h +index f50f8cc1496d657d..96833bd4e992e6d3 100644 +--- a/support/support.h ++++ b/support/support.h +@@ -23,6 +23,7 @@ + #ifndef SUPPORT_H + #define SUPPORT_H + ++#include + #include + #include + /* For mode_t. */ +diff --git a/support/temp_file.c b/support/temp_file.c +index 0bbc7f997264f758..5a2728c94a9c32ae 100644 +--- a/support/temp_file.c ++++ b/support/temp_file.c +@@ -60,14 +60,12 @@ add_temp_file (const char *name) + } + + int +-create_temp_file (const char *base, char **filename) ++create_temp_file_in_dir (const char *base, const char *dir, char **filename) + { + char *fname; + int fd; + +- fname = (char *) xmalloc (strlen (test_dir) + 1 + strlen (base) +- + sizeof ("XXXXXX")); +- strcpy (stpcpy (stpcpy (stpcpy (fname, test_dir), "/"), base), "XXXXXX"); ++ fname = xasprintf ("%s/%sXXXXXX", dir, base); + + fd = mkstemp (fname); + if (fd == -1) +@@ -86,6 +84,12 @@ create_temp_file (const char *base, char **filename) + return fd; + } + ++int ++create_temp_file (const char *base, char **filename) ++{ ++ return create_temp_file_in_dir (base, test_dir, filename); ++} ++ + char * + support_create_temp_directory (const char *base) + { +diff --git a/support/temp_file.h b/support/temp_file.h +index c7795cc577ca22a9..d64563f41f1f50cd 100644 +--- a/support/temp_file.h ++++ b/support/temp_file.h +@@ -32,6 +32,13 @@ void add_temp_file (const char *name); + *FILENAME. */ + int create_temp_file (const char *base, char **filename); + ++/* Create a temporary file in directory DIR. Return the opened file ++ descriptor on success, or -1 on failure. Write the file name to ++ *FILENAME if FILENAME is not NULL. In this case, the caller is ++ expected to free *FILENAME. */ ++int create_temp_file_in_dir (const char *base, const char *dir, ++ char **filename); ++ + /* Create a temporary directory and schedule it for deletion. BASE is + used as a prefix for the unique directory name, which the function + returns. The caller should free this string. */ diff --git a/SOURCES/glibc-rh2032281-3.patch b/SOURCES/glibc-rh2032281-3.patch new file mode 100644 index 0000000..7cb306d --- /dev/null +++ b/SOURCES/glibc-rh2032281-3.patch @@ -0,0 +1,278 @@ +commit fb7bff12e81c677a6622f724edd4d4987dd9d971 +Author: Siddhesh Poyarekar +Date: Tue Jan 18 13:29:36 2022 +0530 + + support: Add helpers to create paths longer than PATH_MAX + + Add new helpers support_create_and_chdir_toolong_temp_directory and + support_chdir_toolong_temp_directory to create and descend into + directory trees longer than PATH_MAX. + + Reviewed-by: Adhemerval Zanella + Signed-off-by: Siddhesh Poyarekar + +# Conflicts: +# support/temp_file.c + +diff --git a/support/temp_file.c b/support/temp_file.c +index 5a2728c94a9c32ae..661c86bad5c0121f 100644 +--- a/support/temp_file.c ++++ b/support/temp_file.c +@@ -1,5 +1,6 @@ + /* Temporary file handling for tests. +- Copyright (C) 1998-2018 Free Software Foundation, Inc. ++ Copyright (C) 1998-2022 Free Software Foundation, Inc. ++ Copyright The GNU Tools Authors. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or +@@ -20,15 +21,17 @@ + some 32-bit platforms. */ + #define _FILE_OFFSET_BITS 64 + ++#include + #include + #include + #include + ++#include + #include + #include + #include + #include +-#include ++#include + + /* List of temporary files. */ + static struct temp_name_list +@@ -36,14 +39,20 @@ static struct temp_name_list + struct temp_name_list *next; + char *name; + pid_t owner; ++ bool toolong; + } *temp_name_list; + + /* Location of the temporary files. Set by the test skeleton via + support_set_test_dir. The string is not be freed. */ + static const char *test_dir = _PATH_TMP; + +-void +-add_temp_file (const char *name) ++/* Name of subdirectories in a too long temporary directory tree. */ ++static char toolong_subdir[NAME_MAX + 1]; ++static bool toolong_initialized; ++static size_t toolong_path_max; ++ ++static void ++add_temp_file_internal (const char *name, bool toolong) + { + struct temp_name_list *newp + = (struct temp_name_list *) xcalloc (sizeof (*newp), 1); +@@ -53,12 +62,19 @@ add_temp_file (const char *name) + newp->name = newname; + newp->next = temp_name_list; + newp->owner = getpid (); ++ newp->toolong = toolong; + temp_name_list = newp; + } + else + free (newp); + } + ++void ++add_temp_file (const char *name) ++{ ++ add_temp_file_internal (name, false); ++} ++ + int + create_temp_file_in_dir (const char *base, const char *dir, char **filename) + { +@@ -90,8 +106,8 @@ create_temp_file (const char *base, char **filename) + return create_temp_file_in_dir (base, test_dir, filename); + } + +-char * +-support_create_temp_directory (const char *base) ++static char * ++create_temp_directory_internal (const char *base, bool toolong) + { + char *path = xasprintf ("%s/%sXXXXXX", test_dir, base); + if (mkdtemp (path) == NULL) +@@ -99,16 +115,132 @@ support_create_temp_directory (const char *base) + printf ("error: mkdtemp (\"%s\"): %m", path); + exit (1); + } +- add_temp_file (path); ++ add_temp_file_internal (path, toolong); + return path; + } + +-/* Helper functions called by the test skeleton follow. */ ++char * ++support_create_temp_directory (const char *base) ++{ ++ return create_temp_directory_internal (base, false); ++} ++ ++static void ++ensure_toolong_initialized (void) ++{ ++ if (!toolong_initialized) ++ FAIL_EXIT1 ("uninitialized toolong directory tree\n"); ++} ++ ++static void ++initialize_toolong (const char *base) ++{ ++ long name_max = pathconf (base, _PC_NAME_MAX); ++ name_max = (name_max < 0 ? 64 ++ : (name_max < sizeof (toolong_subdir) ? name_max ++ : sizeof (toolong_subdir) - 1)); ++ ++ long path_max = pathconf (base, _PC_PATH_MAX); ++ path_max = (path_max < 0 ? 1024 ++ : path_max <= PTRDIFF_MAX ? path_max : PTRDIFF_MAX); ++ ++ /* Sanity check to ensure that the test does not create temporary directories ++ in different filesystems because this API doesn't support it. */ ++ if (toolong_initialized) ++ { ++ if (name_max != strlen (toolong_subdir)) ++ FAIL_UNSUPPORTED ("name_max: Temporary directories in different" ++ " filesystems not supported yet\n"); ++ if (path_max != toolong_path_max) ++ FAIL_UNSUPPORTED ("path_max: Temporary directories in different" ++ " filesystems not supported yet\n"); ++ return; ++ } ++ ++ toolong_path_max = path_max; ++ ++ size_t len = name_max; ++ memset (toolong_subdir, 'X', len); ++ toolong_initialized = true; ++} ++ ++char * ++support_create_and_chdir_toolong_temp_directory (const char *basename) ++{ ++ char *base = create_temp_directory_internal (basename, true); ++ xchdir (base); ++ ++ initialize_toolong (base); ++ ++ size_t sz = strlen (toolong_subdir); ++ ++ /* Create directories and descend into them so that the final path is larger ++ than PATH_MAX. */ ++ for (size_t i = 0; i <= toolong_path_max / sz; i++) ++ { ++ int ret = mkdir (toolong_subdir, S_IRWXU); ++ if (ret != 0 && errno == ENAMETOOLONG) ++ FAIL_UNSUPPORTED ("Filesystem does not support creating too long " ++ "directory trees\n"); ++ else if (ret != 0) ++ FAIL_EXIT1 ("Failed to create directory tree: %m\n"); ++ xchdir (toolong_subdir); ++ } ++ return base; ++} + + void +-support_set_test_dir (const char *path) ++support_chdir_toolong_temp_directory (const char *base) + { +- test_dir = path; ++ ensure_toolong_initialized (); ++ ++ xchdir (base); ++ ++ size_t sz = strlen (toolong_subdir); ++ for (size_t i = 0; i <= toolong_path_max / sz; i++) ++ xchdir (toolong_subdir); ++} ++ ++/* Helper functions called by the test skeleton follow. */ ++ ++static void ++remove_toolong_subdirs (const char *base) ++{ ++ ensure_toolong_initialized (); ++ ++ if (chdir (base) != 0) ++ { ++ printf ("warning: toolong cleanup base failed: chdir (\"%s\"): %m\n", ++ base); ++ return; ++ } ++ ++ /* Descend. */ ++ int levels = 0; ++ size_t sz = strlen (toolong_subdir); ++ for (levels = 0; levels <= toolong_path_max / sz; levels++) ++ if (chdir (toolong_subdir) != 0) ++ { ++ printf ("warning: toolong cleanup failed: chdir (\"%s\"): %m\n", ++ toolong_subdir); ++ break; ++ } ++ ++ /* Ascend and remove. */ ++ while (--levels >= 0) ++ { ++ if (chdir ("..") != 0) ++ { ++ printf ("warning: toolong cleanup failed: chdir (\"..\"): %m\n"); ++ return; ++ } ++ if (remove (toolong_subdir) != 0) ++ { ++ printf ("warning: could not remove subdirectory: %s: %m\n", ++ toolong_subdir); ++ return; ++ } ++ } + } + + void +@@ -123,6 +255,9 @@ support_delete_temp_files (void) + around, to prevent PID reuse.) */ + if (temp_name_list->owner == pid) + { ++ if (temp_name_list->toolong) ++ remove_toolong_subdirs (temp_name_list->name); ++ + if (remove (temp_name_list->name) != 0) + printf ("warning: could not remove temporary file: %s: %m\n", + temp_name_list->name); +@@ -147,3 +282,9 @@ support_print_temp_files (FILE *f) + fprintf (f, ")\n"); + } + } ++ ++void ++support_set_test_dir (const char *path) ++{ ++ test_dir = path; ++} +diff --git a/support/temp_file.h b/support/temp_file.h +index d64563f41f1f50cd..055e31dcfb843ba6 100644 +--- a/support/temp_file.h ++++ b/support/temp_file.h +@@ -44,6 +44,15 @@ int create_temp_file_in_dir (const char *base, const char *dir, + returns. The caller should free this string. */ + char *support_create_temp_directory (const char *base); + ++/* Create a temporary directory tree that is longer than PATH_MAX and schedule ++ it for deletion. BASENAME is used as a prefix for the unique directory ++ name, which the function returns. The caller should free this string. */ ++char *support_create_and_chdir_toolong_temp_directory (const char *basename); ++ ++/* Change into the innermost directory of the directory tree BASE, which was ++ created using support_create_and_chdir_toolong_temp_directory. */ ++void support_chdir_toolong_temp_directory (const char *base); ++ + __END_DECLS + + #endif /* SUPPORT_TEMP_FILE_H */ diff --git a/SOURCES/glibc-rh2032281-4.patch b/SOURCES/glibc-rh2032281-4.patch new file mode 100644 index 0000000..65ba651 --- /dev/null +++ b/SOURCES/glibc-rh2032281-4.patch @@ -0,0 +1,331 @@ +commit 23e0e8f5f1fb5ed150253d986ecccdc90c2dcd5e +Author: Siddhesh Poyarekar +Date: Fri Jan 21 23:32:56 2022 +0530 + + getcwd: Set errno to ERANGE for size == 1 (CVE-2021-3999) + + No valid path returned by getcwd would fit into 1 byte, so reject the + size early and return NULL with errno set to ERANGE. This change is + prompted by CVE-2021-3999, which describes a single byte buffer + underflow and overflow when all of the following conditions are met: + + - The buffer size (i.e. the second argument of getcwd) is 1 byte + - The current working directory is too long + - '/' is also mounted on the current working directory + + Sequence of events: + + - In sysdeps/unix/sysv/linux/getcwd.c, the syscall returns ENAMETOOLONG + because the linux kernel checks for name length before it checks + buffer size + + - The code falls back to the generic getcwd in sysdeps/posix + + - In the generic func, the buf[0] is set to '\0' on line 250 + + - this while loop on line 262 is bypassed: + + while (!(thisdev == rootdev && thisino == rootino)) + + since the rootfs (/) is bind mounted onto the directory and the flow + goes on to line 449, where it puts a '/' in the byte before the + buffer. + + - Finally on line 458, it moves 2 bytes (the underflowed byte and the + '\0') to the buf[0] and buf[1], resulting in a 1 byte buffer overflow. + + - buf is returned on line 469 and errno is not set. + + This resolves BZ #28769. + + Reviewed-by: Andreas Schwab + Reviewed-by: Adhemerval Zanella + Signed-off-by: Qualys Security Advisory + Signed-off-by: Siddhesh Poyarekar + +# Conflicts: +# sysdeps/posix/getcwd.c +# sysdeps/unix/sysv/linux/Makefile + +diff --git a/sysdeps/posix/getcwd.c b/sysdeps/posix/getcwd.c +index b53433a2dc77fafa..fcd7aaea79c6477b 100644 +--- a/sysdeps/posix/getcwd.c ++++ b/sysdeps/posix/getcwd.c +@@ -238,6 +238,13 @@ __getcwd (char *buf, size_t size) + bool fd_needs_closing = false; + int fd = AT_FDCWD; + ++ /* A size of 1 byte is never useful. */ ++ if (size == 1) ++ { ++ __set_errno (ERANGE); ++ return NULL; ++ } ++ + char *path; + #ifndef NO_ALLOCATION + size_t allocated = size; +diff --git a/sysdeps/unix/sysv/linux/Makefile b/sysdeps/unix/sysv/linux/Makefile +index 688cf9fa9dea23a6..bb055f9d6b841ff5 100644 +--- a/sysdeps/unix/sysv/linux/Makefile ++++ b/sysdeps/unix/sysv/linux/Makefile +@@ -180,7 +180,11 @@ sysdep_routines += xstatconv internal_statvfs internal_statvfs64 \ + + sysdep_headers += bits/fcntl-linux.h + +-tests += tst-fallocate tst-fallocate64 ++tests += \ ++ tst-fallocate \ ++ tst-fallocate64 \ ++ tst-getcwd-smallbuff \ ++# tests + endif + + ifeq ($(subdir),elf) +diff --git a/sysdeps/unix/sysv/linux/tst-getcwd-smallbuff.c b/sysdeps/unix/sysv/linux/tst-getcwd-smallbuff.c +new file mode 100644 +index 0000000000000000..d460d6e7662dc5e4 +--- /dev/null ++++ b/sysdeps/unix/sysv/linux/tst-getcwd-smallbuff.c +@@ -0,0 +1,241 @@ ++/* Verify that getcwd returns ERANGE for size 1 byte and does not underflow ++ buffer when the CWD is too long and is also a mount target of /. See bug ++ #28769 or CVE-2021-3999 for more context. ++ 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 ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++static char *base; ++#define BASENAME "tst-getcwd-smallbuff" ++#define MOUNT_NAME "mpoint" ++static int sockfd[2]; ++ ++static void ++do_cleanup (void) ++{ ++ support_chdir_toolong_temp_directory (base); ++ TEST_VERIFY_EXIT (rmdir (MOUNT_NAME) == 0); ++ free (base); ++} ++ ++static void ++send_fd (const int sock, const int fd) ++{ ++ struct msghdr msg = {0}; ++ union ++ { ++ struct cmsghdr hdr; ++ char buf[CMSG_SPACE (sizeof (int))]; ++ } cmsgbuf = {0}; ++ struct cmsghdr *cmsg; ++ struct iovec vec; ++ char ch = 'A'; ++ ssize_t n; ++ ++ msg.msg_control = &cmsgbuf.buf; ++ msg.msg_controllen = sizeof (cmsgbuf.buf); ++ ++ cmsg = CMSG_FIRSTHDR (&msg); ++ cmsg->cmsg_len = CMSG_LEN (sizeof (int)); ++ cmsg->cmsg_level = SOL_SOCKET; ++ cmsg->cmsg_type = SCM_RIGHTS; ++ memcpy (CMSG_DATA (cmsg), &fd, sizeof (fd)); ++ ++ vec.iov_base = &ch; ++ vec.iov_len = 1; ++ msg.msg_iov = &vec; ++ msg.msg_iovlen = 1; ++ ++ while ((n = sendmsg (sock, &msg, 0)) == -1 && errno == EINTR); ++ ++ TEST_VERIFY_EXIT (n == 1); ++} ++ ++static int ++recv_fd (const int sock) ++{ ++ struct msghdr msg = {0}; ++ union ++ { ++ struct cmsghdr hdr; ++ char buf[CMSG_SPACE(sizeof(int))]; ++ } cmsgbuf = {0}; ++ struct cmsghdr *cmsg; ++ struct iovec vec; ++ ssize_t n; ++ char ch = '\0'; ++ int fd = -1; ++ ++ vec.iov_base = &ch; ++ vec.iov_len = 1; ++ msg.msg_iov = &vec; ++ msg.msg_iovlen = 1; ++ ++ msg.msg_control = &cmsgbuf.buf; ++ msg.msg_controllen = sizeof (cmsgbuf.buf); ++ ++ while ((n = recvmsg (sock, &msg, 0)) == -1 && errno == EINTR); ++ if (n != 1 || ch != 'A') ++ return -1; ++ ++ cmsg = CMSG_FIRSTHDR (&msg); ++ if (cmsg == NULL) ++ return -1; ++ if (cmsg->cmsg_type != SCM_RIGHTS) ++ return -1; ++ memcpy (&fd, CMSG_DATA (cmsg), sizeof (fd)); ++ if (fd < 0) ++ return -1; ++ return fd; ++} ++ ++static int ++child_func (void * const arg) ++{ ++ xclose (sockfd[0]); ++ const int sock = sockfd[1]; ++ char ch; ++ ++ TEST_VERIFY_EXIT (read (sock, &ch, 1) == 1); ++ TEST_VERIFY_EXIT (ch == '1'); ++ ++ if (mount ("/", MOUNT_NAME, NULL, MS_BIND | MS_REC, NULL)) ++ FAIL_EXIT1 ("mount failed: %m\n"); ++ const int fd = xopen ("mpoint", ++ O_RDONLY | O_PATH | O_DIRECTORY | O_NOFOLLOW, 0); ++ ++ send_fd (sock, fd); ++ xclose (fd); ++ ++ TEST_VERIFY_EXIT (read (sock, &ch, 1) == 1); ++ TEST_VERIFY_EXIT (ch == 'a'); ++ ++ xclose (sock); ++ return 0; ++} ++ ++static void ++update_map (char * const mapping, const char * const map_file) ++{ ++ const size_t map_len = strlen (mapping); ++ ++ const int fd = xopen (map_file, O_WRONLY, 0); ++ xwrite (fd, mapping, map_len); ++ xclose (fd); ++} ++ ++static void ++proc_setgroups_write (const long child_pid, const char * const str) ++{ ++ const size_t str_len = strlen(str); ++ ++ char setgroups_path[sizeof ("/proc//setgroups") + INT_STRLEN_BOUND (long)]; ++ ++ snprintf (setgroups_path, sizeof (setgroups_path), ++ "/proc/%ld/setgroups", child_pid); ++ ++ const int fd = open (setgroups_path, O_WRONLY); ++ ++ if (fd < 0) ++ { ++ TEST_VERIFY_EXIT (errno == ENOENT); ++ FAIL_UNSUPPORTED ("/proc/%ld/setgroups not found\n", child_pid); ++ } ++ ++ xwrite (fd, str, str_len); ++ xclose(fd); ++} ++ ++static char child_stack[1024 * 1024]; ++ ++int ++do_test (void) ++{ ++ base = support_create_and_chdir_toolong_temp_directory (BASENAME); ++ ++ xmkdir (MOUNT_NAME, S_IRWXU); ++ atexit (do_cleanup); ++ ++ TEST_VERIFY_EXIT (socketpair (AF_UNIX, SOCK_STREAM, 0, sockfd) == 0); ++ pid_t child_pid = xclone (child_func, NULL, child_stack, ++ sizeof (child_stack), ++ CLONE_NEWUSER | CLONE_NEWNS | SIGCHLD); ++ ++ xclose (sockfd[1]); ++ const int sock = sockfd[0]; ++ ++ char map_path[sizeof ("/proc//uid_map") + INT_STRLEN_BOUND (long)]; ++ char map_buf[sizeof ("0 1") + INT_STRLEN_BOUND (long)]; ++ ++ snprintf (map_path, sizeof (map_path), "/proc/%ld/uid_map", ++ (long) child_pid); ++ snprintf (map_buf, sizeof (map_buf), "0 %ld 1", (long) getuid()); ++ update_map (map_buf, map_path); ++ ++ proc_setgroups_write ((long) child_pid, "deny"); ++ snprintf (map_path, sizeof (map_path), "/proc/%ld/gid_map", ++ (long) child_pid); ++ snprintf (map_buf, sizeof (map_buf), "0 %ld 1", (long) getgid()); ++ update_map (map_buf, map_path); ++ ++ TEST_VERIFY_EXIT (send (sock, "1", 1, MSG_NOSIGNAL) == 1); ++ const int fd = recv_fd (sock); ++ TEST_VERIFY_EXIT (fd >= 0); ++ TEST_VERIFY_EXIT (fchdir (fd) == 0); ++ ++ static char buf[2 * 10 + 1]; ++ memset (buf, 'A', sizeof (buf)); ++ ++ /* Finally, call getcwd and check if it resulted in a buffer underflow. */ ++ char * cwd = getcwd (buf + sizeof (buf) / 2, 1); ++ TEST_VERIFY (cwd == NULL); ++ TEST_VERIFY (errno == ERANGE); ++ ++ for (int i = 0; i < sizeof (buf); i++) ++ if (buf[i] != 'A') ++ { ++ printf ("buf[%d] = %02x\n", i, (unsigned int) buf[i]); ++ support_record_failure (); ++ } ++ ++ TEST_VERIFY_EXIT (send (sock, "a", 1, MSG_NOSIGNAL) == 1); ++ xclose (sock); ++ TEST_VERIFY_EXIT (xwaitpid (child_pid, NULL, 0) == child_pid); ++ ++ return 0; ++} ++ ++#define CLEANUP_HANDLER do_cleanup ++#include diff --git a/SOURCES/glibc-rh2032281-5.patch b/SOURCES/glibc-rh2032281-5.patch new file mode 100644 index 0000000..f761b9d --- /dev/null +++ b/SOURCES/glibc-rh2032281-5.patch @@ -0,0 +1,121 @@ +commit de8995a2a04163617c1a233b4b81356ef9f9741f +Author: Adhemerval Zanella +Date: Wed Mar 10 12:26:30 2021 -0300 + + support: Add xclone + + It is a wrapper for Linux clone syscall, to simplify the call to the + use only the most common arguments and remove architecture specific + handling (such as ia64 different name and signature). + +# Conflicts: +# support/Makefile + +diff --git a/support/Makefile b/support/Makefile +index fb95a69ed9158e78..d2b95539403e416c 100644 +--- a/support/Makefile ++++ b/support/Makefile +@@ -84,6 +84,7 @@ libsupport-routines = \ + xcalloc \ + xchdir \ + xchroot \ ++ xclone \ + xclose \ + xconnect \ + xcopy_file_range \ +diff --git a/support/xclone.c b/support/xclone.c +new file mode 100644 +index 0000000000000000..924d2b875402a819 +--- /dev/null ++++ b/support/xclone.c +@@ -0,0 +1,50 @@ ++/* Auxiliary functions to issue the clone syscall. ++ 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 ++ . */ ++ ++#ifdef __linux__ ++# include ++# include /* For _STACK_GROWS_{UP,DOWN}. */ ++# include ++ ++pid_t ++xclone (int (*fn) (void *arg), void *arg, void *stack, size_t stack_size, ++ int flags) ++{ ++ pid_t r = -1; ++ ++# ifdef __ia64__ ++ extern int __clone2 (int (*fn) (void *arg), void *stack, size_t stack_size, ++ int flags, void *arg, ...); ++ r = __clone2 (f, stack, stack_size, flags, arg, /* ptid */ NULL, ++ /* tls */ NULL, /* ctid */ ctid); ++# else ++# if _STACK_GROWS_DOWN ++ r = clone (fn, stack + stack_size, flags, arg, /* ptid */ NULL, ++ /* tls */ NULL, /* ctid */ NULL); ++# elif _STACK_GROWS_UP ++ r = clone (fn, stack, flags, arg, /* ptid */ NULL, /* tls */ NULL, ++ &ctid); ++# endif ++# endif ++ ++ if (r < 0) ++ FAIL_EXIT1 ("clone: %m"); ++ ++ return r; ++} ++#endif +diff --git a/support/xsched.h b/support/xsched.h +new file mode 100644 +index 0000000000000000..eefd731940187b39 +--- /dev/null ++++ b/support/xsched.h +@@ -0,0 +1,34 @@ ++/* Wrapper for sched.h 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 SUPPORT_XSCHED_H ++#define SUPPORT_XSCHED_H ++ ++__BEGIN_DECLS ++ ++#include ++#include ++ ++#ifdef __linux__ ++pid_t xclone (int (*fn) (void *arg), void *arg, void *stack, ++ size_t stack_size, int flags); ++#endif ++ ++__END_DECLS ++ ++#endif diff --git a/SOURCES/glibc-rh2032281-6.patch b/SOURCES/glibc-rh2032281-6.patch new file mode 100644 index 0000000..a8bc55b --- /dev/null +++ b/SOURCES/glibc-rh2032281-6.patch @@ -0,0 +1,46 @@ +commit 5b8e7980c5dabd9aaefeba4f0208baa8cf7653ee +Author: Florian Weimer +Date: Mon Jan 24 18:14:24 2022 +0100 + + Linux: Detect user namespace support in io/tst-getcwd-smallbuff + + Otherwise the test fails with certain container runtimes. + + Reviewed-by: Siddhesh Poyarekar + +diff --git a/sysdeps/unix/sysv/linux/tst-getcwd-smallbuff.c b/sysdeps/unix/sysv/linux/tst-getcwd-smallbuff.c +index d460d6e7662dc5e4..55362f6060a2b3be 100644 +--- a/sysdeps/unix/sysv/linux/tst-getcwd-smallbuff.c ++++ b/sysdeps/unix/sysv/linux/tst-getcwd-smallbuff.c +@@ -34,6 +34,7 @@ + #include + #include + #include ++#include + #include + #include + +@@ -188,6 +189,23 @@ do_test (void) + xmkdir (MOUNT_NAME, S_IRWXU); + atexit (do_cleanup); + ++ /* Check whether user namespaces are supported. */ ++ { ++ pid_t pid = xfork (); ++ if (pid == 0) ++ { ++ if (unshare (CLONE_NEWUSER | CLONE_NEWNS) != 0) ++ _exit (EXIT_UNSUPPORTED); ++ else ++ _exit (0); ++ } ++ int status; ++ xwaitpid (pid, &status, 0); ++ TEST_VERIFY_EXIT (WIFEXITED (status)); ++ if (WEXITSTATUS (status) != 0) ++ return WEXITSTATUS (status); ++ } ++ + TEST_VERIFY_EXIT (socketpair (AF_UNIX, SOCK_STREAM, 0, sockfd) == 0); + pid_t child_pid = xclone (child_func, NULL, child_stack, + sizeof (child_stack), diff --git a/SOURCES/glibc-rh2032281-7.patch b/SOURCES/glibc-rh2032281-7.patch new file mode 100644 index 0000000..60ea205 --- /dev/null +++ b/SOURCES/glibc-rh2032281-7.patch @@ -0,0 +1,24 @@ +commit 3842ba494963b1d76ad5f68b8d1e5c2279160e31 +Author: Szabolcs Nagy +Date: Tue Jun 1 09:23:40 2021 +0100 + + aarch64: align stack in clone [BZ #27939] + + The AArch64 PCS requires 16 byte aligned stack. Previously if the + caller passed an unaligned stack to clone then the child crashed. + + Fixes bug 27939. + +diff --git a/sysdeps/unix/sysv/linux/aarch64/clone.S b/sysdeps/unix/sysv/linux/aarch64/clone.S +index e0653048259dd9a3..4a1a999447ee5cf1 100644 +--- a/sysdeps/unix/sysv/linux/aarch64/clone.S ++++ b/sysdeps/unix/sysv/linux/aarch64/clone.S +@@ -48,6 +48,8 @@ ENTRY(__clone) + /* Sanity check args. */ + mov x0, #-EINVAL + cbz x10, .Lsyscall_error ++ /* Align sp. */ ++ and x1, x1, -16 + cbz x1, .Lsyscall_error + + /* Do the system call. */ diff --git a/SOURCES/glibc-rh2033648-1.patch b/SOURCES/glibc-rh2033648-1.patch new file mode 100644 index 0000000..8717167 --- /dev/null +++ b/SOURCES/glibc-rh2033648-1.patch @@ -0,0 +1,51 @@ +commit c36f64aa6dff13b12a1e03a185e75a50fa9f6a4c +Author: Hans-Peter Nilsson +Date: Fri Dec 17 21:38:00 2021 +0100 + + timezone: handle truncated timezones from tzcode-2021d and later (BZ #28707) + + When using a timezone file with a truncated starting time, + generated by the zic in IANA tzcode-2021d a.k.a. tzlib-2021d + (also in tzlib-2021e; current as of this writing), glibc + asserts in __tzfile_read (on e.g. tzset() for this file) and + you may find lines matching "tzfile.c:435: __tzfile_read: + Assertion `num_types == 1' failed" in your syslog. + + One example of such a file is the tzfile for Asuncion + generated by tzlib-2021e as follows, using the tzlib-2021e zic: + "zic -d DEST -r @1546300800 -L /dev/null -b slim + SOURCE/southamerica". Note that in its type 2 header, it has + two entries in its "time-types" array (types), but only one + entry in its "transition types" array (type_idxs). + + This is valid and expected already in the published RFC8536, and + not even frowned upon: "Local time for timestamps before the + first transition is specified by the first time type (time type + 0)" ... "every nonzero local time type index SHOULD appear at + least once in the transition type array". Note the "nonzero ... + index". Until the 2021d zic, index 0 has been shared by the + first valid transition but with 2021d it's separate, set apart + as a placeholder and only "implicitly" indexed. (A draft update + of the RFC mandates that the entry at index 0 is a placeholder + in this case, hence can no longer be shared.) + + * time/tzfile.c (__tzfile_read): Don't assert when no transitions + are found. + + Co-authored-by: Christopher Wong + +diff --git a/time/tzfile.c b/time/tzfile.c +index 190a777152..8668392ad3 100644 +--- a/time/tzfile.c ++++ b/time/tzfile.c +@@ -431,8 +431,8 @@ __tzfile_read (const char *file, size_t extra, char **extrap) + if (__tzname[0] == NULL) + { + /* This should only happen if there are no transition rules. +- In this case there should be only one single type. */ +- assert (num_types == 1); ++ In this case there's usually only one single type, unless ++ e.g. the data file has a truncated time-range. */ + __tzname[0] = __tzstring (zone_names); + } + if (__tzname[1] == NULL) diff --git a/SOURCES/glibc-rh2033648-2.patch b/SOURCES/glibc-rh2033648-2.patch new file mode 100644 index 0000000..1a8c41a --- /dev/null +++ b/SOURCES/glibc-rh2033648-2.patch @@ -0,0 +1,126 @@ +commit ebe899af0dc3215159a9c896ac6f35b72a18cb6e +Author: Hans-Peter Nilsson +Date: Fri Dec 17 21:45:54 2021 +0100 + + timezone: test-case for BZ #28707 + + This test-case is the tzfile for Asuncion generated by + tzlib-2021e as follows, using the tzlib-2021e zic: "zic -d + DEST -r @1546300800 -L /dev/null -b slim + SOURCE/southamerica". Note that in its type 2 header, it + has two entries in its "time-types" array (types), but only + one entry in its "transition types" array (type_idxs). + + * timezone/Makefile, timezone/tst-pr28707.c, + timezone/testdata/gen-XT5.sh: New test. + + Co-authored-by: Christopher Wong + + Reworked due to timezone/Makefile difference. + +diff -Nrup a/timezone/Makefile b/timezone/Makefile +--- a/timezone/Makefile 2021-07-06 15:04:00.000000000 -0400 ++++ b/timezone/Makefile 2022-01-05 15:03:57.433756574 -0500 +@@ -23,7 +23,7 @@ subdir := timezone + include ../Makeconfig + + others := zdump zic +-tests := test-tz tst-timezone tst-tzset ++tests := test-tz tst-timezone tst-tzset tst-bz28707 + + generated-dirs += testdata + +@@ -85,10 +85,12 @@ $(objpfx)tst-timezone.out: $(addprefix $ + America/Sao_Paulo Asia/Tokyo \ + Europe/London) + $(objpfx)tst-tzset.out: $(addprefix $(testdata)/XT, 1 2 3 4) ++$(objpfx)tst-bz28707.out: $(testdata)/XT5 + + test-tz-ENV = TZDIR=$(testdata) + tst-timezone-ENV = TZDIR=$(testdata) + tst-tzset-ENV = TZDIR=$(testdata) ++tst-bz28707-ENV = TZDIR=$(testdata) + + # Note this must come second in the deps list for $(built-program-cmd) to work. + zic-deps = $(objpfx)zic $(leapseconds) yearistype +@@ -122,6 +124,10 @@ $(testdata)/XT%: testdata/XT% + $(make-target-directory) + cp $< $@ + ++$(testdata)/XT%: testdata/gen-XT%.sh ++ $(SHELL) $< > $@.tmp ++ mv $@.tmp $@ ++ + $(objpfx)tzselect: tzselect.ksh $(common-objpfx)config.make + sed -e 's|/bin/bash|$(BASH)|' \ + -e 's|TZDIR=[^}]*|TZDIR=$(zonedir)|' \ +diff -Nrup a/timezone/testdata/gen-XT5.sh b/timezone/testdata/gen-XT5.sh +--- a/timezone/testdata/gen-XT5.sh 1969-12-31 19:00:00.000000000 -0500 ++++ b/timezone/testdata/gen-XT5.sh 2022-01-05 12:50:01.666972313 -0500 +@@ -0,0 +1,16 @@ ++#! /bin/sh ++ ++# This test-case is the tzfile for America/Asuncion ++# generated by tzlib-2021e as follows, using the tzlib-2021e ++# zic: "zic -d DEST -r @1546300800 -L /dev/null -b slim ++# SOURCE/southamerica". Note that in its type 2 header, it ++# has two entries in its "time-types" array (types), but ++# only one entry in its "transition types" array ++# (type_idxs). ++ ++printf \ ++'TZif2\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0'\ ++'\0\0\0\0\0\0\0\1\0\0\0\1\0\0\0\0\0\0\0TZif2\0\0\0\0\0\0\0\0'\ ++'\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\1\0\0\0\2\0\0\0\b\0'\ ++'\0\0\0\*\255\200\1\0\0\0\0\0\0\377\377\325\320\1\4-00\0-03\0\n'\ ++'<-04>4<-03>,M10.1.0/0,M3.4.0/0\n' +diff -Nrup a/timezone/tst-bz28707.c b/timezone/tst-bz28707.c +--- a/timezone/tst-bz28707.c 1969-12-31 19:00:00.000000000 -0500 ++++ b/timezone/tst-bz28707.c 2022-01-05 12:50:01.666972313 -0500 +@@ -0,0 +1,46 @@ ++/* 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 ++ ++/* Test that we can use a truncated timezone-file, where the time-type ++ at index 0 is not indexed by the transition-types array (and the ++ transition-types array does not contain at least both one DST and one ++ normal time members). */ ++ ++static int ++do_test (void) ++{ ++ if (setenv ("TZ", "XT5", 1)) ++ { ++ puts ("setenv failed."); ++ return 1; ++ } ++ ++ tzset (); ++ ++ return ++ /* Sanity-check that we got the right timezone-name for DST. For ++ normal time, we're likely to get "-00" (the "unspecified" marker), ++ even though the POSIX timezone string says "-04". Let's not test ++ that. */ ++ !(strcmp (tzname[1], "-03") == 0); ++} ++#include diff --git a/SOURCES/glibc-rh2033655.patch b/SOURCES/glibc-rh2033655.patch new file mode 100644 index 0000000..96a3488 --- /dev/null +++ b/SOURCES/glibc-rh2033655.patch @@ -0,0 +1,185 @@ +commit ff012870b2c02a62598c04daa1e54632e020fd7d +Author: Nikita Popov +Date: Tue Nov 2 13:21:42 2021 +0500 + + gconv: Do not emit spurious NUL character in ISO-2022-JP-3 (bug 28524) + + Bugfix 27256 has introduced another issue: + In conversion from ISO-2022-JP-3 encoding, it is possible + to force iconv to emit extra NUL character on internal state reset. + To do this, it is sufficient to feed iconv with escape sequence + which switches active character set. + The simplified check 'data->__statep->__count != ASCII_set' + introduced by the aforementioned bugfix picks that case and + behaves as if '\0' character has been queued thus emitting it. + + To eliminate this issue, these steps are taken: + * Restore original condition + '(data->__statep->__count & ~7) != ASCII_set'. + It is necessary since bits 0-2 may contain + number of buffered input characters. + * Check that queued character is not NUL. + Similar step is taken for main conversion loop. + + Bundled test case follows following logic: + * Try to convert ISO-2022-JP-3 escape sequence + switching active character set + * Reset internal state by providing NULL as input buffer + * Ensure that nothing has been converted. + + Signed-off-by: Nikita Popov + +Conflicts: + iconvdata/Makefile + (Copyright header. Usual test backporting differences.) + iconvdata/iso-2022-jp-3.c + (Copyright header.) + +diff --git a/iconvdata/Makefile b/iconvdata/Makefile +index 95e5fb8f722a513b..646e2ccd11478646 100644 +--- a/iconvdata/Makefile ++++ b/iconvdata/Makefile +@@ -1,4 +1,5 @@ +-# Copyright (C) 1997-2018 Free Software Foundation, Inc. ++# Copyright (C) 1997-2021 Free Software Foundation, Inc. ++# Copyright (C) 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 +@@ -73,7 +74,8 @@ modules.so := $(addsuffix .so, $(modules)) + ifeq (yes,$(build-shared)) + tests = bug-iconv1 bug-iconv2 tst-loading tst-e2big tst-iconv4 bug-iconv4 \ + tst-iconv6 bug-iconv5 bug-iconv6 tst-iconv7 bug-iconv8 bug-iconv9 \ +- bug-iconv10 bug-iconv11 bug-iconv12 bug-iconv13 bug-iconv14 ++ bug-iconv10 bug-iconv11 bug-iconv12 bug-iconv13 bug-iconv14 \ ++ bug-iconv15 + ifeq ($(have-thread-library),yes) + tests += bug-iconv3 + endif +@@ -321,6 +323,8 @@ $(objpfx)bug-iconv12.out: $(addprefix $(objpfx), $(gconv-modules)) \ + $(addprefix $(objpfx),$(modules.so)) + $(objpfx)bug-iconv14.out: $(addprefix $(objpfx), $(gconv-modules)) \ + $(addprefix $(objpfx),$(modules.so)) ++$(objpfx)bug-iconv15.out: $(addprefix $(objpfx), $(gconv-modules)) \ ++ $(addprefix $(objpfx),$(modules.so)) + + $(objpfx)iconv-test.out: run-iconv-test.sh \ + $(addprefix $(objpfx), $(gconv-modules)) \ +diff --git a/iconvdata/bug-iconv15.c b/iconvdata/bug-iconv15.c +new file mode 100644 +index 0000000000000000..cc04bd0313a68786 +--- /dev/null ++++ b/iconvdata/bug-iconv15.c +@@ -0,0 +1,60 @@ ++/* Bug 28524: Conversion from ISO-2022-JP-3 with iconv ++ may emit spurious NUL character on state reset. ++ Copyright (C) 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 ++ ++static int ++do_test (void) ++{ ++ char in[] = "\x1b(I"; ++ char *inbuf = in; ++ size_t inleft = sizeof (in) - 1; ++ char out[1]; ++ char *outbuf = out; ++ size_t outleft = sizeof (out); ++ iconv_t cd; ++ ++ cd = iconv_open ("UTF8", "ISO-2022-JP-3"); ++ TEST_VERIFY_EXIT (cd != (iconv_t) -1); ++ ++ /* First call to iconv should alter internal state. ++ Now, JISX0201_Kana_set is selected and ++ state value != ASCII_set. */ ++ TEST_VERIFY (iconv (cd, &inbuf, &inleft, &outbuf, &outleft) != (size_t) -1); ++ ++ /* No bytes should have been added to ++ the output buffer at this point. */ ++ TEST_VERIFY (outbuf == out); ++ TEST_VERIFY (outleft == sizeof (out)); ++ ++ /* Second call shall emit spurious NUL character in unpatched glibc. */ ++ TEST_VERIFY (iconv (cd, NULL, NULL, &outbuf, &outleft) != (size_t) -1); ++ ++ /* No characters are expected to be produced. */ ++ TEST_VERIFY (outbuf == out); ++ TEST_VERIFY (outleft == sizeof (out)); ++ ++ TEST_VERIFY_EXIT (iconv_close (cd) != -1); ++ ++ return 0; ++} ++ ++#include +diff --git a/iconvdata/iso-2022-jp-3.c b/iconvdata/iso-2022-jp-3.c +index 047fab8e8dfbde7e..a2b33b171e56392a 100644 +--- a/iconvdata/iso-2022-jp-3.c ++++ b/iconvdata/iso-2022-jp-3.c +@@ -1,5 +1,6 @@ + /* Conversion module for ISO-2022-JP-3. +- Copyright (C) 1998-2018 Free Software Foundation, Inc. ++ Copyright (C) 1998-2021 Free Software Foundation, Inc. ++ Copyright (C) The GNU Toolchain Authors. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper , 1998, + and Bruno Haible , 2002. +@@ -81,20 +82,31 @@ enum + the output state to the initial state. This has to be done during the + flushing. */ + #define EMIT_SHIFT_TO_INIT \ +- if (data->__statep->__count != ASCII_set) \ ++ if ((data->__statep->__count & ~7) != ASCII_set) \ + { \ + if (FROM_DIRECTION) \ + { \ +- if (__glibc_likely (outbuf + 4 <= outend)) \ ++ uint32_t ch = data->__statep->__count >> 6; \ ++ \ ++ if (__glibc_unlikely (ch != 0)) \ + { \ +- /* Write out the last character. */ \ +- *((uint32_t *) outbuf) = data->__statep->__count >> 6; \ +- outbuf += sizeof (uint32_t); \ +- data->__statep->__count = ASCII_set; \ ++ if (__glibc_likely (outbuf + 4 <= outend)) \ ++ { \ ++ /* Write out the last character. */ \ ++ put32u (outbuf, ch); \ ++ outbuf += 4; \ ++ data->__statep->__count &= 7; \ ++ data->__statep->__count |= ASCII_set; \ ++ } \ ++ else \ ++ /* We don't have enough room in the output buffer. */ \ ++ status = __GCONV_FULL_OUTPUT; \ + } \ + else \ +- /* We don't have enough room in the output buffer. */ \ +- status = __GCONV_FULL_OUTPUT; \ ++ { \ ++ data->__statep->__count &= 7; \ ++ data->__statep->__count |= ASCII_set; \ ++ } \ + } \ + else \ + { \ diff --git a/SOURCES/glibc-rh2033684-1.patch b/SOURCES/glibc-rh2033684-1.patch new file mode 100644 index 0000000..8734628 --- /dev/null +++ b/SOURCES/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/SOURCES/glibc-rh2033684-10.patch b/SOURCES/glibc-rh2033684-10.patch new file mode 100644 index 0000000..94b4519 --- /dev/null +++ b/SOURCES/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/SOURCES/glibc-rh2033684-11.patch b/SOURCES/glibc-rh2033684-11.patch new file mode 100644 index 0000000..41ce66c --- /dev/null +++ b/SOURCES/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/SOURCES/glibc-rh2033684-12.patch b/SOURCES/glibc-rh2033684-12.patch new file mode 100644 index 0000000..9c9c98f --- /dev/null +++ b/SOURCES/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/SOURCES/glibc-rh2033684-2.patch b/SOURCES/glibc-rh2033684-2.patch new file mode 100644 index 0000000..4651008 --- /dev/null +++ b/SOURCES/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/SOURCES/glibc-rh2033684-3.patch b/SOURCES/glibc-rh2033684-3.patch new file mode 100644 index 0000000..b8d0093 --- /dev/null +++ b/SOURCES/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/SOURCES/glibc-rh2033684-4.patch b/SOURCES/glibc-rh2033684-4.patch new file mode 100644 index 0000000..ebd0c33 --- /dev/null +++ b/SOURCES/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/SOURCES/glibc-rh2033684-5.patch b/SOURCES/glibc-rh2033684-5.patch new file mode 100644 index 0000000..8c1f7f3 --- /dev/null +++ b/SOURCES/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/SOURCES/glibc-rh2033684-6.patch b/SOURCES/glibc-rh2033684-6.patch new file mode 100644 index 0000000..b183d70 --- /dev/null +++ b/SOURCES/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/SOURCES/glibc-rh2033684-7.patch b/SOURCES/glibc-rh2033684-7.patch new file mode 100644 index 0000000..7cb18a6 --- /dev/null +++ b/SOURCES/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/SOURCES/glibc-rh2033684-8.patch b/SOURCES/glibc-rh2033684-8.patch new file mode 100644 index 0000000..5b90b20 --- /dev/null +++ b/SOURCES/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/SOURCES/glibc-rh2033684-9.patch b/SOURCES/glibc-rh2033684-9.patch new file mode 100644 index 0000000..467ece4 --- /dev/null +++ b/SOURCES/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/SOURCES/glibc-rh2036955.patch b/SOURCES/glibc-rh2036955.patch new file mode 100644 index 0000000..48b0f4a --- /dev/null +++ b/SOURCES/glibc-rh2036955.patch @@ -0,0 +1,54 @@ +commit e5fa62b8db546f8792ec9e5c61e6419f4f8e3f4d +Author: Wilco Dijkstra +Date: Thu Jan 6 14:36:28 2022 +0000 + + AArch64: Check for SVE in ifuncs [BZ #28744] + + Add a check for SVE in the A64FX ifuncs for memcpy, memset and memmove. + This fixes BZ #28744. + +Conflicts: + sysdeps/aarch64/multiarch/memcpy.c + sysdeps/aarch64/multiarch/memmove.c + sysdeps/aarch64/multiarch/memset.c + (IFUNC resolver differences in the backport.) + +diff --git a/sysdeps/aarch64/multiarch/memcpy.c b/sysdeps/aarch64/multiarch/memcpy.c +index e0313c42e82a7b86..a6ebeb06d3bda00f 100644 +--- a/sysdeps/aarch64/multiarch/memcpy.c ++++ b/sysdeps/aarch64/multiarch/memcpy.c +@@ -44,7 +44,7 @@ libc_ifunc (__libc_memcpy, + : (IS_THUNDERX2 (midr) || IS_THUNDERX2PA (midr) + ? __memcpy_thunderx2 + # if HAVE_AARCH64_SVE_ASM +- : (IS_A64FX (midr) ++ : (IS_A64FX (midr) && sve + ? __memcpy_a64fx + : __memcpy_generic))))); + # else +diff --git a/sysdeps/aarch64/multiarch/memmove.c b/sysdeps/aarch64/multiarch/memmove.c +index d96612b9cf7c3a4e..bea72b3eddde54c0 100644 +--- a/sysdeps/aarch64/multiarch/memmove.c ++++ b/sysdeps/aarch64/multiarch/memmove.c +@@ -41,7 +41,7 @@ libc_ifunc (__libc_memmove, + : (IS_FALKOR (midr) || IS_PHECDA (midr) + ? __memmove_falkor + # if HAVE_AARCH64_SVE_ASM +- : (IS_A64FX (midr) ++ : (IS_A64FX (midr) && sve + ? __memmove_a64fx + : __memmove_generic)))); + # else +diff --git a/sysdeps/aarch64/multiarch/memset.c b/sysdeps/aarch64/multiarch/memset.c +index 2c8cc72bb0b18474..e7bd412377533f18 100644 +--- a/sysdeps/aarch64/multiarch/memset.c ++++ b/sysdeps/aarch64/multiarch/memset.c +@@ -38,7 +38,7 @@ libc_ifunc (__libc_memset, + ((IS_FALKOR (midr) || IS_PHECDA (midr)) && zva_size == 64 + ? __memset_falkor + # if HAVE_AARCH64_SVE_ASM +- : (IS_A64FX (midr) ++ : (IS_A64FX (midr) && sve + ? __memset_a64fx + : __memset_generic))); + # else diff --git a/SOURCES/glibc-rh2037416-1.patch b/SOURCES/glibc-rh2037416-1.patch new file mode 100644 index 0000000..3fddefe --- /dev/null +++ b/SOURCES/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/SOURCES/glibc-rh2037416-2.patch b/SOURCES/glibc-rh2037416-2.patch new file mode 100644 index 0000000..e991e91 --- /dev/null +++ b/SOURCES/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/SOURCES/glibc-rh2037416-3.patch b/SOURCES/glibc-rh2037416-3.patch new file mode 100644 index 0000000..3ac7aa2 --- /dev/null +++ b/SOURCES/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/SOURCES/glibc-rh2037416-4.patch b/SOURCES/glibc-rh2037416-4.patch new file mode 100644 index 0000000..e057eeb --- /dev/null +++ b/SOURCES/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/SOURCES/glibc-rh2037416-5.patch b/SOURCES/glibc-rh2037416-5.patch new file mode 100644 index 0000000..c92c2cf --- /dev/null +++ b/SOURCES/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/SOURCES/glibc-rh2037416-6.patch b/SOURCES/glibc-rh2037416-6.patch new file mode 100644 index 0000000..b2522ad --- /dev/null +++ b/SOURCES/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/SOURCES/glibc-rh2037416-7.patch b/SOURCES/glibc-rh2037416-7.patch new file mode 100644 index 0000000..e57fef7 --- /dev/null +++ b/SOURCES/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/SOURCES/glibc-rh2037416-8.patch b/SOURCES/glibc-rh2037416-8.patch new file mode 100644 index 0000000..6a68332 --- /dev/null +++ b/SOURCES/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/SOURCES/glibc-rh2045063-1.patch b/SOURCES/glibc-rh2045063-1.patch new file mode 100644 index 0000000..2885e3f --- /dev/null +++ b/SOURCES/glibc-rh2045063-1.patch @@ -0,0 +1,164 @@ +commit e368b12f6c16b6888dda99ba641e999b9c9643c8 +Author: Florian Weimer +Date: Mon Jan 17 10:21:34 2022 +0100 + + socket: Add the __sockaddr_un_set function + + Reviewed-by: Siddhesh Poyarekar + +# Conflicts: +# socket/Makefile + +diff --git a/include/sys/un.h b/include/sys/un.h +index bdbee999806930f4..152afd9fc7426d8b 100644 +--- a/include/sys/un.h ++++ b/include/sys/un.h +@@ -1 +1,13 @@ + #include ++ ++#ifndef _ISOMAC ++ ++/* Set ADDR->sun_family to AF_UNIX and ADDR->sun_path to PATHNAME. ++ Return 0 on success or -1 on failure (due to overlong PATHNAME). ++ The caller should always use sizeof (struct sockaddr_un) as the ++ socket address length, disregaring the length of PATHNAME. ++ Only concrete (non-abstract) pathnames are supported. */ ++int __sockaddr_un_set (struct sockaddr_un *addr, const char *pathname) ++ attribute_hidden; ++ ++#endif /* _ISOMAC */ +diff --git a/socket/Makefile b/socket/Makefile +index b41eb071507a6271..8975a65c2aabbfbc 100644 +--- a/socket/Makefile ++++ b/socket/Makefile +@@ -29,10 +29,14 @@ headers := sys/socket.h sys/un.h bits/sockaddr.h bits/socket.h \ + routines := accept bind connect getpeername getsockname getsockopt \ + listen recv recvfrom recvmsg send sendmsg sendto \ + setsockopt shutdown socket socketpair isfdtype opensock \ +- sockatmark accept4 recvmmsg sendmmsg ++ sockatmark accept4 recvmmsg sendmmsg sockaddr_un_set + + tests := tst-accept4 + ++tests-internal := \ ++ tst-sockaddr_un_set \ ++ # tests-internal ++ + aux := sa_len + + include ../Rules +diff --git a/socket/sockaddr_un_set.c b/socket/sockaddr_un_set.c +new file mode 100644 +index 0000000000000000..0bd40dc34e3d7efc +--- /dev/null ++++ b/socket/sockaddr_un_set.c +@@ -0,0 +1,41 @@ ++/* Set the sun_path member of struct sockaddr_un. ++ 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 ++ ++int ++__sockaddr_un_set (struct sockaddr_un *addr, const char *pathname) ++{ ++ size_t name_length = strlen (pathname); ++ ++ /* The kernel supports names of exactly sizeof (addr->sun_path) ++ bytes, without a null terminator, but userspace does not; see the ++ SUN_LEN macro. */ ++ if (name_length >= sizeof (addr->sun_path)) ++ { ++ __set_errno (EINVAL); /* Error code used by the kernel. */ ++ return -1; ++ } ++ ++ addr->sun_family = AF_UNIX; ++ memcpy (addr->sun_path, pathname, name_length + 1); ++ return 0; ++} +diff --git a/socket/tst-sockaddr_un_set.c b/socket/tst-sockaddr_un_set.c +new file mode 100644 +index 0000000000000000..29c2a81afda81b5e +--- /dev/null ++++ b/socket/tst-sockaddr_un_set.c +@@ -0,0 +1,62 @@ ++/* Test the __sockaddr_un_set function. ++ Copyright (C) 2022 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++/* Re-compile the function because the version in libc is not ++ exported. */ ++#include "sockaddr_un_set.c" ++ ++#include ++ ++static int ++do_test (void) ++{ ++ struct sockaddr_un sun; ++ ++ memset (&sun, 0xcc, sizeof (sun)); ++ __sockaddr_un_set (&sun, ""); ++ TEST_COMPARE (sun.sun_family, AF_UNIX); ++ TEST_COMPARE (__sockaddr_un_set (&sun, ""), 0); ++ ++ memset (&sun, 0xcc, sizeof (sun)); ++ TEST_COMPARE (__sockaddr_un_set (&sun, "/example"), 0); ++ TEST_COMPARE_STRING (sun.sun_path, "/example"); ++ ++ { ++ char pathname[108]; /* Length of sun_path (ABI constant). */ ++ memset (pathname, 'x', sizeof (pathname)); ++ pathname[sizeof (pathname) - 1] = '\0'; ++ memset (&sun, 0xcc, sizeof (sun)); ++ TEST_COMPARE (__sockaddr_un_set (&sun, pathname), 0); ++ TEST_COMPARE (sun.sun_family, AF_UNIX); ++ TEST_COMPARE_STRING (sun.sun_path, pathname); ++ } ++ ++ { ++ char pathname[109]; ++ memset (pathname, 'x', sizeof (pathname)); ++ pathname[sizeof (pathname) - 1] = '\0'; ++ memset (&sun, 0xcc, sizeof (sun)); ++ errno = 0; ++ TEST_COMPARE (__sockaddr_un_set (&sun, pathname), -1); ++ TEST_COMPARE (errno, EINVAL); ++ } ++ ++ return 0; ++} ++ ++#include diff --git a/SOURCES/glibc-rh2045063-2.patch b/SOURCES/glibc-rh2045063-2.patch new file mode 100644 index 0000000..9e74607 --- /dev/null +++ b/SOURCES/glibc-rh2045063-2.patch @@ -0,0 +1,32 @@ +commit 226b46770c82899b555986583294b049c6ec9b40 +Author: Florian Weimer +Date: Mon Jan 17 10:21:34 2022 +0100 + + CVE-2022-23219: Buffer overflow in sunrpc clnt_create for "unix" (bug 22542) + + Processing an overlong pathname in the sunrpc clnt_create function + results in a stack-based buffer overflow. + + Reviewed-by: Siddhesh Poyarekar + +diff --git a/sunrpc/clnt_gen.c b/sunrpc/clnt_gen.c +index 13ced8994e49d4ee..b44357cd88e60599 100644 +--- a/sunrpc/clnt_gen.c ++++ b/sunrpc/clnt_gen.c +@@ -57,9 +57,13 @@ clnt_create (const char *hostname, u_long prog, u_long vers, + + if (strcmp (proto, "unix") == 0) + { +- memset ((char *)&sun, 0, sizeof (sun)); +- sun.sun_family = AF_UNIX; +- strcpy (sun.sun_path, hostname); ++ if (__sockaddr_un_set (&sun, hostname) < 0) ++ { ++ struct rpc_createerr *ce = &get_rpc_createerr (); ++ ce->cf_stat = RPC_SYSTEMERROR; ++ ce->cf_error.re_errno = errno; ++ return NULL; ++ } + sock = RPC_ANYSOCK; + client = clntunix_create (&sun, prog, vers, &sock, 0, 0); + if (client == NULL) diff --git a/SOURCES/glibc-rh2045063-3.patch b/SOURCES/glibc-rh2045063-3.patch new file mode 100644 index 0000000..cd1e55d --- /dev/null +++ b/SOURCES/glibc-rh2045063-3.patch @@ -0,0 +1,80 @@ +commit ef972a4c50014a16132b5c75571cfb6b30bef136 +Author: Martin Sebor +Date: Mon Jan 17 10:21:34 2022 +0100 + + sunrpc: Test case for clnt_create "unix" buffer overflow (bug 22542) + + Reviewed-by: Siddhesh Poyarekar + +# Conflicts: +# sunrpc/Makefile + +diff --git a/sunrpc/Makefile b/sunrpc/Makefile +index 85b0b3356aaf81a3..2f8f0597c99e117f 100644 +--- a/sunrpc/Makefile ++++ b/sunrpc/Makefile +@@ -95,7 +95,8 @@ others += rpcgen + endif + + tests = tst-xdrmem tst-xdrmem2 test-rpcent tst-udp-error tst-udp-timeout \ +- tst-udp-nonblocking ++ tst-udp-nonblocking tst-bug22542 ++ + xtests := tst-getmyaddr + + ifeq ($(have-thread-library),yes) +@@ -246,3 +247,4 @@ $(objpfx)tst-udp-timeout: $(common-objpfx)linkobj/libc.so + $(objpfx)tst-udp-nonblocking: $(common-objpfx)linkobj/libc.so + $(objpfx)tst-udp-garbage: \ + $(common-objpfx)linkobj/libc.so $(shared-thread-library) ++$(objpfx)tst-bug22542: $(common-objpfx)linkobj/libc.so +diff --git a/sunrpc/tst-bug22542.c b/sunrpc/tst-bug22542.c +new file mode 100644 +index 0000000000000000..d6cd79787bdef21d +--- /dev/null ++++ b/sunrpc/tst-bug22542.c +@@ -0,0 +1,44 @@ ++/* Test to verify that overlong hostname is rejected by clnt_create ++ and doesn't cause a buffer overflow (bug 22542). ++ ++ 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 ++ ++static int ++do_test (void) ++{ ++ /* Create an arbitrary hostname that's longer than fits in sun_path. */ ++ char name [sizeof ((struct sockaddr_un*)0)->sun_path * 2]; ++ memset (name, 'x', sizeof name - 1); ++ name [sizeof name - 1] = '\0'; ++ ++ errno = 0; ++ CLIENT *clnt = clnt_create (name, 0, 0, "unix"); ++ ++ TEST_VERIFY (clnt == NULL); ++ TEST_COMPARE (errno, EINVAL); ++ return 0; ++} ++ ++#include diff --git a/SOURCES/glibc-rh2045063-4.patch b/SOURCES/glibc-rh2045063-4.patch new file mode 100644 index 0000000..489c315 --- /dev/null +++ b/SOURCES/glibc-rh2045063-4.patch @@ -0,0 +1,101 @@ +commit f545ad4928fa1f27a3075265182b38a4f939a5f7 +Author: Florian Weimer +Date: Mon Jan 17 10:21:34 2022 +0100 + + CVE-2022-23218: Buffer overflow in sunrpc svcunix_create (bug 28768) + + The sunrpc function svcunix_create suffers from a stack-based buffer + overflow with overlong pathname arguments. + + Reviewed-by: Siddhesh Poyarekar + +diff --git a/sunrpc/Makefile b/sunrpc/Makefile +index 2f8f0597c99e117f..5f7087aee494cc2e 100644 +--- a/sunrpc/Makefile ++++ b/sunrpc/Makefile +@@ -95,7 +95,7 @@ others += rpcgen + endif + + tests = tst-xdrmem tst-xdrmem2 test-rpcent tst-udp-error tst-udp-timeout \ +- tst-udp-nonblocking tst-bug22542 ++ tst-udp-nonblocking tst-bug22542 tst-bug28768 + + xtests := tst-getmyaddr + +diff --git a/sunrpc/svc_unix.c b/sunrpc/svc_unix.c +index c2c076aa87f0a2ad..8fac2b35da1d38a5 100644 +--- a/sunrpc/svc_unix.c ++++ b/sunrpc/svc_unix.c +@@ -154,7 +154,10 @@ svcunix_create (int sock, u_int sendsize, u_int recvsize, char *path) + SVCXPRT *xprt; + struct unix_rendezvous *r; + struct sockaddr_un addr; +- socklen_t len = sizeof (struct sockaddr_in); ++ socklen_t len = sizeof (addr); ++ ++ if (__sockaddr_un_set (&addr, path) < 0) ++ return NULL; + + if (sock == RPC_ANYSOCK) + { +@@ -165,12 +168,6 @@ svcunix_create (int sock, u_int sendsize, u_int recvsize, char *path) + } + madesock = TRUE; + } +- memset (&addr, '\0', sizeof (addr)); +- addr.sun_family = AF_UNIX; +- len = strlen (path) + 1; +- memcpy (addr.sun_path, path, len); +- len += sizeof (addr.sun_family); +- + __bind (sock, (struct sockaddr *) &addr, len); + + if (__getsockname (sock, (struct sockaddr *) &addr, &len) != 0 +diff --git a/sunrpc/tst-bug28768.c b/sunrpc/tst-bug28768.c +new file mode 100644 +index 0000000000000000..35a4b7b0b3d34350 +--- /dev/null ++++ b/sunrpc/tst-bug28768.c +@@ -0,0 +1,42 @@ ++/* Test to verify that long path is rejected by svcunix_create (bug 28768). ++ 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 ++ ++/* svcunix_create does not have a default version in linkobj/libc.so. */ ++compat_symbol_reference (libc, svcunix_create, svcunix_create, GLIBC_2_1); ++ ++static int ++do_test (void) ++{ ++ char pathname[109]; ++ memset (pathname, 'x', sizeof (pathname)); ++ pathname[sizeof (pathname) - 1] = '\0'; ++ ++ errno = 0; ++ TEST_VERIFY (svcunix_create (RPC_ANYSOCK, 4096, 4096, pathname) == NULL); ++ TEST_COMPARE (errno, EINVAL); ++ ++ return 0; ++} ++ ++#include diff --git a/SOURCES/glibc-rh2045063-5.patch b/SOURCES/glibc-rh2045063-5.patch new file mode 100644 index 0000000..3d7b71e --- /dev/null +++ b/SOURCES/glibc-rh2045063-5.patch @@ -0,0 +1,54 @@ +commit 36f6e408845c8c539128f3fb9cb132bf1845a2c8 +Author: Florian Weimer +Date: Tue Mar 9 21:07:24 2021 +0100 + + : Support compat_symbol_reference for _ISOMAC + + This is helpful for testing compat symbols in cases where _ISOMAC + is activated implicitly due to -DMODULE_NAME=testsuite and cannot + be disabled easily. + +diff --git a/include/libc-symbols.h b/include/libc-symbols.h +index 41436050d060b89f..44e12b63d40cc572 100644 +--- a/include/libc-symbols.h ++++ b/include/libc-symbols.h +@@ -59,6 +59,19 @@ + # define IN_MODULE (-1) + #endif + ++/* Use symbol_version_reference to specify the version a symbol ++ reference should link to. Use symbol_version or ++ default_symbol_version for the definition of a versioned symbol. ++ The difference is that the latter is a no-op in non-shared ++ builds. */ ++#ifdef __ASSEMBLER__ ++# define symbol_version_reference(real, name, version) \ ++ .symver real, name##@##version ++#else /* !__ASSEMBLER__ */ ++# define symbol_version_reference(real, name, version) \ ++ __asm__ (".symver " #real "," #name "@" #version) ++#endif ++ + #ifndef _ISOMAC + + /* This is defined for the compilation of all C library code. features.h +@@ -388,19 +401,6 @@ for linking") + past the last element in SET. */ + #define symbol_set_end_p(set, ptr) ((ptr) >= (void *const *) &__stop_##set) + +-/* Use symbol_version_reference to specify the version a symbol +- reference should link to. Use symbol_version or +- default_symbol_version for the definition of a versioned symbol. +- The difference is that the latter is a no-op in non-shared +- builds. */ +-#ifdef __ASSEMBLER__ +-# define symbol_version_reference(real, name, version) \ +- .symver real, name##@##version +-#else /* !__ASSEMBLER__ */ +-# define symbol_version_reference(real, name, version) \ +- __asm__ (".symver " #real "," #name "@" #version) +-#endif +- + #ifdef SHARED + # define symbol_version(real, name, version) \ + symbol_version_reference(real, name, version) diff --git a/SOURCES/glibc-rh2047981-1.patch b/SOURCES/glibc-rh2047981-1.patch new file mode 100644 index 0000000..e1a085d --- /dev/null +++ b/SOURCES/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/SOURCES/glibc-rh2047981-10.patch b/SOURCES/glibc-rh2047981-10.patch new file mode 100644 index 0000000..00b7a71 --- /dev/null +++ b/SOURCES/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/SOURCES/glibc-rh2047981-11.patch b/SOURCES/glibc-rh2047981-11.patch new file mode 100644 index 0000000..a0cde6c --- /dev/null +++ b/SOURCES/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/SOURCES/glibc-rh2047981-12.patch b/SOURCES/glibc-rh2047981-12.patch new file mode 100644 index 0000000..8588aaa --- /dev/null +++ b/SOURCES/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/SOURCES/glibc-rh2047981-13.patch b/SOURCES/glibc-rh2047981-13.patch new file mode 100644 index 0000000..d67e40f --- /dev/null +++ b/SOURCES/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/SOURCES/glibc-rh2047981-14.patch b/SOURCES/glibc-rh2047981-14.patch new file mode 100644 index 0000000..1d1295c --- /dev/null +++ b/SOURCES/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/SOURCES/glibc-rh2047981-15.patch b/SOURCES/glibc-rh2047981-15.patch new file mode 100644 index 0000000..7da5392 --- /dev/null +++ b/SOURCES/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/SOURCES/glibc-rh2047981-16.patch b/SOURCES/glibc-rh2047981-16.patch new file mode 100644 index 0000000..eec1516 --- /dev/null +++ b/SOURCES/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/SOURCES/glibc-rh2047981-17.patch b/SOURCES/glibc-rh2047981-17.patch new file mode 100644 index 0000000..4a22e82 --- /dev/null +++ b/SOURCES/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/SOURCES/glibc-rh2047981-18.patch b/SOURCES/glibc-rh2047981-18.patch new file mode 100644 index 0000000..b866295 --- /dev/null +++ b/SOURCES/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/SOURCES/glibc-rh2047981-19.patch b/SOURCES/glibc-rh2047981-19.patch new file mode 100644 index 0000000..2c55405 --- /dev/null +++ b/SOURCES/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/SOURCES/glibc-rh2047981-2.patch b/SOURCES/glibc-rh2047981-2.patch new file mode 100644 index 0000000..02bc403 --- /dev/null +++ b/SOURCES/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/SOURCES/glibc-rh2047981-20.patch b/SOURCES/glibc-rh2047981-20.patch new file mode 100644 index 0000000..bce1f3d --- /dev/null +++ b/SOURCES/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/SOURCES/glibc-rh2047981-21.patch b/SOURCES/glibc-rh2047981-21.patch new file mode 100644 index 0000000..ea5003f --- /dev/null +++ b/SOURCES/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/SOURCES/glibc-rh2047981-22.patch b/SOURCES/glibc-rh2047981-22.patch new file mode 100644 index 0000000..17c35d5 --- /dev/null +++ b/SOURCES/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/SOURCES/glibc-rh2047981-23.patch b/SOURCES/glibc-rh2047981-23.patch new file mode 100644 index 0000000..b2e83f8 --- /dev/null +++ b/SOURCES/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/SOURCES/glibc-rh2047981-24.patch b/SOURCES/glibc-rh2047981-24.patch new file mode 100644 index 0000000..c6fc26a --- /dev/null +++ b/SOURCES/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/SOURCES/glibc-rh2047981-25.patch b/SOURCES/glibc-rh2047981-25.patch new file mode 100644 index 0000000..14cbb8d --- /dev/null +++ b/SOURCES/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/SOURCES/glibc-rh2047981-26.patch b/SOURCES/glibc-rh2047981-26.patch new file mode 100644 index 0000000..b05628f --- /dev/null +++ b/SOURCES/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/SOURCES/glibc-rh2047981-27.patch b/SOURCES/glibc-rh2047981-27.patch new file mode 100644 index 0000000..08f1448 --- /dev/null +++ b/SOURCES/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/SOURCES/glibc-rh2047981-28.patch b/SOURCES/glibc-rh2047981-28.patch new file mode 100644 index 0000000..9fb9d98 --- /dev/null +++ b/SOURCES/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/SOURCES/glibc-rh2047981-29.patch b/SOURCES/glibc-rh2047981-29.patch new file mode 100644 index 0000000..3581baa --- /dev/null +++ b/SOURCES/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/SOURCES/glibc-rh2047981-3.patch b/SOURCES/glibc-rh2047981-3.patch new file mode 100644 index 0000000..aa0aaaf --- /dev/null +++ b/SOURCES/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/SOURCES/glibc-rh2047981-30.patch b/SOURCES/glibc-rh2047981-30.patch new file mode 100644 index 0000000..d52225f --- /dev/null +++ b/SOURCES/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/SOURCES/glibc-rh2047981-31.patch b/SOURCES/glibc-rh2047981-31.patch new file mode 100644 index 0000000..48de026 --- /dev/null +++ b/SOURCES/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/SOURCES/glibc-rh2047981-32.patch b/SOURCES/glibc-rh2047981-32.patch new file mode 100644 index 0000000..2706fe8 --- /dev/null +++ b/SOURCES/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/SOURCES/glibc-rh2047981-33.patch b/SOURCES/glibc-rh2047981-33.patch new file mode 100644 index 0000000..6ce117c --- /dev/null +++ b/SOURCES/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/SOURCES/glibc-rh2047981-34.patch b/SOURCES/glibc-rh2047981-34.patch new file mode 100644 index 0000000..8809b82 --- /dev/null +++ b/SOURCES/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/SOURCES/glibc-rh2047981-35.patch b/SOURCES/glibc-rh2047981-35.patch new file mode 100644 index 0000000..92ecdc6 --- /dev/null +++ b/SOURCES/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/SOURCES/glibc-rh2047981-36.patch b/SOURCES/glibc-rh2047981-36.patch new file mode 100644 index 0000000..ceaec72 --- /dev/null +++ b/SOURCES/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/SOURCES/glibc-rh2047981-37.patch b/SOURCES/glibc-rh2047981-37.patch new file mode 100644 index 0000000..8591468 --- /dev/null +++ b/SOURCES/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/SOURCES/glibc-rh2047981-38.patch b/SOURCES/glibc-rh2047981-38.patch new file mode 100644 index 0000000..5e7b79f --- /dev/null +++ b/SOURCES/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/SOURCES/glibc-rh2047981-39.patch b/SOURCES/glibc-rh2047981-39.patch new file mode 100644 index 0000000..36247b1 --- /dev/null +++ b/SOURCES/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/SOURCES/glibc-rh2047981-4.patch b/SOURCES/glibc-rh2047981-4.patch new file mode 100644 index 0000000..86468bd --- /dev/null +++ b/SOURCES/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/SOURCES/glibc-rh2047981-40.patch b/SOURCES/glibc-rh2047981-40.patch new file mode 100644 index 0000000..f1f4e80 --- /dev/null +++ b/SOURCES/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/SOURCES/glibc-rh2047981-41.patch b/SOURCES/glibc-rh2047981-41.patch new file mode 100644 index 0000000..a92e82d --- /dev/null +++ b/SOURCES/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/SOURCES/glibc-rh2047981-42.patch b/SOURCES/glibc-rh2047981-42.patch new file mode 100644 index 0000000..d280e1a --- /dev/null +++ b/SOURCES/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/SOURCES/glibc-rh2047981-43.patch b/SOURCES/glibc-rh2047981-43.patch new file mode 100644 index 0000000..13691c9 --- /dev/null +++ b/SOURCES/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/SOURCES/glibc-rh2047981-44.patch b/SOURCES/glibc-rh2047981-44.patch new file mode 100644 index 0000000..e5f9389 --- /dev/null +++ b/SOURCES/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/SOURCES/glibc-rh2047981-45.patch b/SOURCES/glibc-rh2047981-45.patch new file mode 100644 index 0000000..0111ab9 --- /dev/null +++ b/SOURCES/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/SOURCES/glibc-rh2047981-46.patch b/SOURCES/glibc-rh2047981-46.patch new file mode 100644 index 0000000..3bbd90a --- /dev/null +++ b/SOURCES/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/SOURCES/glibc-rh2047981-47.patch b/SOURCES/glibc-rh2047981-47.patch new file mode 100644 index 0000000..c5baf0d --- /dev/null +++ b/SOURCES/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/SOURCES/glibc-rh2047981-5.patch b/SOURCES/glibc-rh2047981-5.patch new file mode 100644 index 0000000..43af14e --- /dev/null +++ b/SOURCES/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/SOURCES/glibc-rh2047981-6.patch b/SOURCES/glibc-rh2047981-6.patch new file mode 100644 index 0000000..09a5bf8 --- /dev/null +++ b/SOURCES/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/SOURCES/glibc-rh2047981-7.patch b/SOURCES/glibc-rh2047981-7.patch new file mode 100644 index 0000000..d1640be --- /dev/null +++ b/SOURCES/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/SOURCES/glibc-rh2047981-8.patch b/SOURCES/glibc-rh2047981-8.patch new file mode 100644 index 0000000..885aad4 --- /dev/null +++ b/SOURCES/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/SOURCES/glibc-rh2047981-9.patch b/SOURCES/glibc-rh2047981-9.patch new file mode 100644 index 0000000..690027f --- /dev/null +++ b/SOURCES/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/SOURCES/glibc-rh2054790.patch b/SOURCES/glibc-rh2054790.patch new file mode 100644 index 0000000..6af769e --- /dev/null +++ b/SOURCES/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/SOURCES/glibc-rh2063042.patch b/SOURCES/glibc-rh2063042.patch new file mode 100644 index 0000000..921add1 --- /dev/null +++ b/SOURCES/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/SOURCES/glibc-rh2063712.patch b/SOURCES/glibc-rh2063712.patch new file mode 100644 index 0000000..b66fce4 --- /dev/null +++ b/SOURCES/glibc-rh2063712.patch @@ -0,0 +1,208 @@ +This is a downstream rework of this upstream patch: + + [PATCH v2 2/2] nss: Protect against errno changes in function lookup (bug 28953) + + +The NSS module loading code has been rewritten upstream, which is why +only the test can be reused. NSS_DECLARE_MODULE_FUNCTIONS does not yet +exist downstream, so this part had to be skipped. + +diff --git a/nss/Makefile b/nss/Makefile +index d5c28a6b5ed3661c..e8a7d9c7b3cefcdf 100644 +--- a/nss/Makefile ++++ b/nss/Makefile +@@ -59,7 +59,8 @@ tests = test-netdb test-digits-dots tst-nss-getpwent bug17079 \ + tst-nss-test2 \ + tst-nss-test3 \ + tst-nss-test4 \ +- tst-nss-test5 ++ tst-nss-test5 \ ++ tst-nss-test_errno + xtests = bug-erange + + tests-container = \ +@@ -130,7 +131,7 @@ routines += $(libnss_files-routines) + static-only-routines += $(libnss_files-routines) + tests-static += tst-nss-static + endif +-extra-test-objs += nss_test1.os nss_test2.os ++extra-test-objs += nss_test1.os nss_test2.os nss_test_errno.os + + include ../Rules + +@@ -166,10 +167,13 @@ rtld-tests-LDFLAGS += -Wl,--dynamic-list=nss_test.ver + + libof-nss_test1 = extramodules + libof-nss_test2 = extramodules ++libof-nss_test_errno = extramodules + $(objpfx)/libnss_test1.so: $(objpfx)nss_test1.os $(link-libc-deps) + $(build-module) + $(objpfx)/libnss_test2.so: $(objpfx)nss_test2.os $(link-libc-deps) + $(build-module) ++$(objpfx)/libnss_test_errno.so: $(objpfx)nss_test_errno.os $(link-libc-deps) ++ $(build-module) + $(objpfx)nss_test2.os : nss_test1.c + ifdef libnss_test1.so-version + $(objpfx)/libnss_test1.so$(libnss_test1.so-version): $(objpfx)/libnss_test1.so +@@ -179,9 +183,13 @@ ifdef libnss_test2.so-version + $(objpfx)/libnss_test2.so$(libnss_test2.so-version): $(objpfx)/libnss_test2.so + $(make-link) + endif ++$(objpfx)/libnss_test_errno.so$(libnss_files.so-version): \ ++ $(objpfx)/libnss_test_errno.so ++ $(make-link) + $(patsubst %,$(objpfx)%.out,$(tests)) : \ + $(objpfx)/libnss_test1.so$(libnss_test1.so-version) \ +- $(objpfx)/libnss_test2.so$(libnss_test2.so-version) ++ $(objpfx)/libnss_test2.so$(libnss_test2.so-version) \ ++ $(objpfx)/libnss_test_errno.so$(libnss_files.so-version) + + ifeq (yes,$(have-thread-library)) + $(objpfx)tst-cancel-getpwuid_r: $(shared-thread-library) +diff --git a/nss/nss_test_errno.c b/nss/nss_test_errno.c +new file mode 100644 +index 0000000000000000..ca75c890aa057869 +--- /dev/null ++++ b/nss/nss_test_errno.c +@@ -0,0 +1,53 @@ ++/* NSS service provider with errno clobber. ++ 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 __attribute__ ((constructor)) ++init (void) ++{ ++ /* An arbitrary error code which is otherwise not used. */ ++ errno = ELIBBAD; ++} ++ ++/* Lookup functions for pwd follow that do not return any data. */ ++ ++enum nss_status ++_nss_test_errno_setpwent (int stayopen) ++{ ++ setenv ("_nss_test_errno_setpwent", "yes", 1); ++ return NSS_STATUS_SUCCESS; ++} ++ ++enum nss_status ++_nss_test_errno_getpwent_r (struct passwd *result, ++ char *buffer, size_t size, int *errnop) ++{ ++ setenv ("_nss_test_errno_getpwent_r", "yes", 1); ++ return NSS_STATUS_NOTFOUND; ++} ++ ++enum nss_status ++_nss_test_errno_endpwent (void) ++{ ++ setenv ("_nss_test_errno_endpwent", "yes", 1); ++ return NSS_STATUS_SUCCESS; ++} +diff --git a/nss/nsswitch.c b/nss/nsswitch.c +index 17adf1ef03f93d60..e59ab674e0426b26 100644 +--- a/nss/nsswitch.c ++++ b/nss/nsswitch.c +@@ -401,6 +401,7 @@ void * + __nss_lookup_function (service_user *ni, const char *fct_name) + { + void **found, *result; ++ int saved_errno = errno; + + /* We now modify global data. Protect it. */ + __libc_lock_lock (lock); +@@ -523,6 +524,8 @@ __nss_lookup_function (service_user *ni, const char *fct_name) + /* Remove the lock. */ + __libc_lock_unlock (lock); + ++ __set_errno (saved_errno); ++ + return result; + } + libc_hidden_def (__nss_lookup_function) +diff --git a/nss/tst-nss-test_errno.c b/nss/tst-nss-test_errno.c +new file mode 100644 +index 0000000000000000..d2c42dd363a38b0e +--- /dev/null ++++ b/nss/tst-nss-test_errno.c +@@ -0,0 +1,61 @@ ++/* getpwent failure when dlopen clobbers errno (bug 28953). ++ 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 ++ ++static int ++do_test (void) ++{ ++ __nss_configure_lookup ("passwd", "files test_errno"); ++ ++ errno = 0; ++ setpwent (); ++ TEST_COMPARE (errno, 0); ++ ++ bool root_seen = false; ++ while (true) ++ { ++ errno = 0; ++ struct passwd *e = getpwent (); ++ if (e == NULL) ++ break; ++ if (strcmp (e->pw_name, "root")) ++ root_seen = true; ++ } ++ ++ TEST_COMPARE (errno, 0); ++ TEST_VERIFY (root_seen); ++ ++ errno = 0; ++ endpwent (); ++ TEST_COMPARE (errno, 0); ++ ++ TEST_COMPARE_STRING (getenv ("_nss_test_errno_setpwent"), "yes"); ++ TEST_COMPARE_STRING (getenv ("_nss_test_errno_getpwent_r"), "yes"); ++ TEST_COMPARE_STRING (getenv ("_nss_test_errno_endpwent"), "yes"); ++ ++ return 0; ++} ++ ++#include diff --git a/SOURCES/glibc-rh2065588-1.patch b/SOURCES/glibc-rh2065588-1.patch new file mode 100644 index 0000000..3b4db3f --- /dev/null +++ b/SOURCES/glibc-rh2065588-1.patch @@ -0,0 +1,253 @@ +commit 2a973ab7f1a6f6cd9be1c7257fd7b5d331515eab +Author: Adhemerval Zanella +Date: Wed Sep 12 10:30:46 2018 -0300 + + posix: Add internal symbols for posix_spawn interface + + This patch adds internal hidden definition for mostly of the posix_spawn + function so it can be used internally on both popen and system + implementations. + + Checked on x86_64-linux-gnu. + + * include/spawn.h (__posix_spawn, posix_spawn_file_actions_addclose, + __posix_spawn_file_actions_adddup2, __posix_spawn_file_actions_destroy, + __posix_spawn_file_actions_init, __posix_spawnattr_init, + __posix_spawnattr_destroy, __posix_spawnattr_setflags, + __posix_spawnattr_setsigdefault, __posix_spawnattr_setsigmask): New + prototype. + * posix/spawn.c (__posix_spawn): Add libc_hidden_def. + * posix/spawn_faction_addclose.c + (__posix_spawn_file_actions_addclose): Add hidden definition. + * posix/spawn_faction_adddup2.c + (__posix_spawn_file_actions_adddup2): Likewise. + * posix/spawn_faction_destroy.c + (__posix_spawn_file_actions_destroy): Likewise. + * posix/spawn_faction_init.c (__posix_spawn_file_actions_init): + Likewise. + * posix/spawnattr_destroy.c (__posix_spawnattr_destroy): Likewise. + * posix/spawnattr_init.c (__posix_spawnattr_init): Likewise. + * posix/spawnattr_setdefault.c (__posix_spawnattr_setsigdefault): + Likewise. + * posix/spawnattr_setflags.c (__posix_spawnattr_setflags): Likewise. + * posix/spawnattr_setsigmask.c (__posix_spawnattr_setsigmask): + Likewise. + +diff --git a/include/spawn.h b/include/spawn.h +index a6c7a8adc361927e..7fdd965bd780f8de 100644 +--- a/include/spawn.h ++++ b/include/spawn.h +@@ -1 +1,36 @@ ++#ifndef _SPAWN_H + #include ++ ++# ifndef _ISOMAC ++__typeof (posix_spawn) __posix_spawn; ++libc_hidden_proto (__posix_spawn) ++ ++__typeof (posix_spawn_file_actions_addclose) ++ __posix_spawn_file_actions_addclose attribute_hidden; ++ ++__typeof (posix_spawn_file_actions_adddup2) ++ __posix_spawn_file_actions_adddup2 attribute_hidden; ++ ++__typeof (posix_spawn_file_actions_destroy) ++ __posix_spawn_file_actions_destroy attribute_hidden; ++ ++__typeof (posix_spawn_file_actions_init) __posix_spawn_file_actions_init ++ attribute_hidden; ++ ++__typeof (posix_spawnattr_init) __posix_spawnattr_init ++ attribute_hidden; ++ ++__typeof (posix_spawnattr_destroy) __posix_spawnattr_destroy ++ attribute_hidden; ++ ++__typeof (posix_spawnattr_setflags) __posix_spawnattr_setflags ++ attribute_hidden; ++ ++__typeof (posix_spawnattr_setsigdefault) __posix_spawnattr_setsigdefault ++ attribute_hidden; ++ ++__typeof (posix_spawnattr_setsigmask) __posix_spawnattr_setsigmask ++ attribute_hidden; ++ ++# endif /* !_ISOMAC */ ++#endif /* spawn.h */ +diff --git a/posix/spawn.c b/posix/spawn.c +index 51f67b2755bd4949..a82f1c84e299f018 100644 +--- a/posix/spawn.c ++++ b/posix/spawn.c +@@ -30,6 +30,7 @@ __posix_spawn (pid_t *pid, const char *path, + return __spawni (pid, path, file_actions, attrp, argv, envp, 0); + } + versioned_symbol (libc, __posix_spawn, posix_spawn, GLIBC_2_15); ++libc_hidden_def (__posix_spawn) + + + #if SHLIB_COMPAT (libc, GLIBC_2_2, GLIBC_2_15) +diff --git a/posix/spawn_faction_addclose.c b/posix/spawn_faction_addclose.c +index 21081e19b55db44c..e1fafe438cf15c91 100644 +--- a/posix/spawn_faction_addclose.c ++++ b/posix/spawn_faction_addclose.c +@@ -24,8 +24,8 @@ + /* Add an action to FILE-ACTIONS which tells the implementation to call + `close' for the given file descriptor during the `spawn' call. */ + int +-posix_spawn_file_actions_addclose (posix_spawn_file_actions_t *file_actions, +- int fd) ++__posix_spawn_file_actions_addclose (posix_spawn_file_actions_t *file_actions, ++ int fd) + { + struct __spawn_action *rec; + +@@ -48,3 +48,5 @@ posix_spawn_file_actions_addclose (posix_spawn_file_actions_t *file_actions, + + return 0; + } ++weak_alias (__posix_spawn_file_actions_addclose, ++ posix_spawn_file_actions_addclose) +diff --git a/posix/spawn_faction_adddup2.c b/posix/spawn_faction_adddup2.c +index 363bc29ae502bd60..371b1de3e6f1979a 100644 +--- a/posix/spawn_faction_adddup2.c ++++ b/posix/spawn_faction_adddup2.c +@@ -24,8 +24,8 @@ + /* Add an action to FILE-ACTIONS which tells the implementation to call + `dup2' for the given file descriptors during the `spawn' call. */ + int +-posix_spawn_file_actions_adddup2 (posix_spawn_file_actions_t *file_actions, +- int fd, int newfd) ++__posix_spawn_file_actions_adddup2 (posix_spawn_file_actions_t *file_actions, ++ int fd, int newfd) + { + struct __spawn_action *rec; + +@@ -49,3 +49,5 @@ posix_spawn_file_actions_adddup2 (posix_spawn_file_actions_t *file_actions, + + return 0; + } ++weak_alias (__posix_spawn_file_actions_adddup2, ++ posix_spawn_file_actions_adddup2) +diff --git a/posix/spawn_faction_destroy.c b/posix/spawn_faction_destroy.c +index 46061ee3473d4475..2a2de4e41d6bd6d0 100644 +--- a/posix/spawn_faction_destroy.c ++++ b/posix/spawn_faction_destroy.c +@@ -22,7 +22,7 @@ + + /* Deallocate the file actions. */ + int +-posix_spawn_file_actions_destroy (posix_spawn_file_actions_t *file_actions) ++__posix_spawn_file_actions_destroy (posix_spawn_file_actions_t *file_actions) + { + /* Free the paths in the open actions. */ + for (int i = 0; i < file_actions->__used; ++i) +@@ -44,3 +44,5 @@ posix_spawn_file_actions_destroy (posix_spawn_file_actions_t *file_actions) + free (file_actions->__actions); + return 0; + } ++weak_alias (__posix_spawn_file_actions_destroy, ++ posix_spawn_file_actions_destroy) +diff --git a/posix/spawn_faction_init.c b/posix/spawn_faction_init.c +index ddb42e6a77ba41ec..98432067c645021e 100644 +--- a/posix/spawn_faction_init.c ++++ b/posix/spawn_faction_init.c +@@ -45,9 +45,10 @@ __posix_spawn_file_actions_realloc (posix_spawn_file_actions_t *file_actions) + + /* Initialize data structure for file attribute for `spawn' call. */ + int +-posix_spawn_file_actions_init (posix_spawn_file_actions_t *file_actions) ++__posix_spawn_file_actions_init (posix_spawn_file_actions_t *file_actions) + { + /* Simply clear all the elements. */ + memset (file_actions, '\0', sizeof (*file_actions)); + return 0; + } ++weak_alias (__posix_spawn_file_actions_init, posix_spawn_file_actions_init) +diff --git a/posix/spawnattr_destroy.c b/posix/spawnattr_destroy.c +index 603e00fffefae2bf..043386778588913a 100644 +--- a/posix/spawnattr_destroy.c ++++ b/posix/spawnattr_destroy.c +@@ -19,8 +19,9 @@ + + /* Initialize data structure for file attribute for `spawn' call. */ + int +-posix_spawnattr_destroy (posix_spawnattr_t *attr) ++__posix_spawnattr_destroy (posix_spawnattr_t *attr) + { + /* Nothing to do in the moment. */ + return 0; + } ++weak_alias (__posix_spawnattr_destroy, posix_spawnattr_destroy) +diff --git a/posix/spawnattr_init.c b/posix/spawnattr_init.c +index bab464e62bdf7889..4e1218ab44e3f779 100644 +--- a/posix/spawnattr_init.c ++++ b/posix/spawnattr_init.c +@@ -20,7 +20,7 @@ + + /* Initialize data structure for file attribute for `spawn' call. */ + int +-posix_spawnattr_init (posix_spawnattr_t *attr) ++__posix_spawnattr_init (posix_spawnattr_t *attr) + { + /* All elements have to be initialized to the default values which + is generally zero. */ +@@ -28,3 +28,4 @@ posix_spawnattr_init (posix_spawnattr_t *attr) + + return 0; + } ++weak_alias (__posix_spawnattr_init, posix_spawnattr_init) +diff --git a/posix/spawnattr_setdefault.c b/posix/spawnattr_setdefault.c +index c77cda59be3dda20..174bcfa423dc5666 100644 +--- a/posix/spawnattr_setdefault.c ++++ b/posix/spawnattr_setdefault.c +@@ -20,11 +20,12 @@ + + /* Set signal mask for signals with default handling in ATTR to SIGDEFAULT. */ + int +-posix_spawnattr_setsigdefault (posix_spawnattr_t *attr, +- const sigset_t *sigdefault) ++__posix_spawnattr_setsigdefault (posix_spawnattr_t *attr, ++ const sigset_t *sigdefault) + { + /* Copy the sigset_t data to the user buffer. */ + memcpy (&attr->__sd, sigdefault, sizeof (sigset_t)); + + return 0; + } ++weak_alias (__posix_spawnattr_setsigdefault, posix_spawnattr_setsigdefault) +diff --git a/posix/spawnattr_setflags.c b/posix/spawnattr_setflags.c +index cf9a60181dc91ccd..0a42e94770224a94 100644 +--- a/posix/spawnattr_setflags.c ++++ b/posix/spawnattr_setflags.c +@@ -30,7 +30,7 @@ + + /* Store flags in the attribute structure. */ + int +-posix_spawnattr_setflags (posix_spawnattr_t *attr, short int flags) ++__posix_spawnattr_setflags (posix_spawnattr_t *attr, short int flags) + { + /* Check no invalid bits are set. */ + if (flags & ~ALL_FLAGS) +@@ -41,3 +41,4 @@ posix_spawnattr_setflags (posix_spawnattr_t *attr, short int flags) + + return 0; + } ++weak_alias (__posix_spawnattr_setflags, posix_spawnattr_setflags) +diff --git a/posix/spawnattr_setsigmask.c b/posix/spawnattr_setsigmask.c +index 7ae81ad47025db6f..12c0111af441dd13 100644 +--- a/posix/spawnattr_setsigmask.c ++++ b/posix/spawnattr_setsigmask.c +@@ -20,7 +20,7 @@ + + /* Set signal mask for the new process in ATTR to SIGMASK. */ + int +-posix_spawnattr_setsigmask (posix_spawnattr_t *attr, ++__posix_spawnattr_setsigmask (posix_spawnattr_t *attr, + const sigset_t *sigmask) + { + /* Copy the sigset_t data to the user buffer. */ +@@ -28,3 +28,4 @@ posix_spawnattr_setsigmask (posix_spawnattr_t *attr, + + return 0; + } ++weak_alias (__posix_spawnattr_setsigmask, posix_spawnattr_setsigmask) diff --git a/SOURCES/glibc-rh2065588-10.patch b/SOURCES/glibc-rh2065588-10.patch new file mode 100644 index 0000000..3016994 --- /dev/null +++ b/SOURCES/glibc-rh2065588-10.patch @@ -0,0 +1,21 @@ +commit 5fce0e095bc413f908f472074c2235198cd76bf4 +Author: Adhemerval Zanella +Date: Tue Mar 24 15:36:23 2020 -0300 + + support/shell-container.c: Return 127 if execve fails + + Reviewed-by: DJ Delorie + +diff --git a/support/shell-container.c b/support/shell-container.c +index e87ac5cf1baa84e5..e9eea64bca7e949d 100644 +--- a/support/shell-container.c ++++ b/support/shell-container.c +@@ -238,7 +238,7 @@ run_command_array (char **argv) + + fprintf (stderr, "sh: execing %s failed: %s", + argv[0], strerror (errno)); +- exit (1); ++ exit (127); + } + + waitpid (pid, &status, 0); diff --git a/SOURCES/glibc-rh2065588-11.patch b/SOURCES/glibc-rh2065588-11.patch new file mode 100644 index 0000000..a1ef4a7 --- /dev/null +++ b/SOURCES/glibc-rh2065588-11.patch @@ -0,0 +1,39 @@ +commit 5a5a3a3234bc220a5192d620e0cbc5360da46f14 +Author: Adhemerval Zanella +Date: Tue Mar 24 15:40:36 2020 -0300 + + support/shell-container.c: Add builtin exit + + Reviewed-by: DJ Delorie + +diff --git a/support/shell-container.c b/support/shell-container.c +index e9eea64bca7e949d..aeaf6d2733abce61 100644 +--- a/support/shell-container.c ++++ b/support/shell-container.c +@@ -135,6 +135,18 @@ copy_func (char **argv) + + } + ++/* Emulate the 'exit' builtin. The exit value is optional. */ ++static int ++exit_func (char **argv) ++{ ++ int exit_val = 0; ++ ++ if (argv[0] != 0) ++ exit_val = atoi (argv[0]) & 0xff; ++ exit (exit_val); ++ return 0; ++} ++ + /* This is a list of all the built-in commands we understand. */ + static struct { + const char *name; +@@ -143,6 +155,7 @@ static struct { + { "true", true_func }, + { "echo", echo_func }, + { "cp", copy_func }, ++ { "exit", exit_func }, + { NULL, NULL } + }; + diff --git a/SOURCES/glibc-rh2065588-12.patch b/SOURCES/glibc-rh2065588-12.patch new file mode 100644 index 0000000..7f4223f --- /dev/null +++ b/SOURCES/glibc-rh2065588-12.patch @@ -0,0 +1,60 @@ +commit 1c17100c43c0913ec94f3bcc966bf3792236c690 +Author: Adhemerval Zanella +Date: Tue Mar 24 15:47:13 2020 -0300 + + support/shell-container.c: Add builtin kill + + No options supported. + + Reviewed-by: DJ Delorie + +diff --git a/support/shell-container.c b/support/shell-container.c +index aeaf6d2733abce61..3869e14683fb74dd 100644 +--- a/support/shell-container.c ++++ b/support/shell-container.c +@@ -147,6 +147,25 @@ exit_func (char **argv) + return 0; + } + ++/* Emulate the "/bin/kill" command. Options are ignored. */ ++static int ++kill_func (char **argv) ++{ ++ int signum = SIGTERM; ++ int i; ++ ++ for (i = 0; argv[i]; i++) ++ { ++ pid_t pid; ++ if (strcmp (argv[i], "$$") == 0) ++ pid = getpid (); ++ else ++ pid = atoi (argv[i]); ++ kill (pid, signum); ++ } ++ return 0; ++} ++ + /* This is a list of all the built-in commands we understand. */ + static struct { + const char *name; +@@ -156,6 +175,7 @@ static struct { + { "echo", echo_func }, + { "cp", copy_func }, + { "exit", exit_func }, ++ { "kill", kill_func }, + { NULL, NULL } + }; + +@@ -264,6 +284,11 @@ run_command_array (char **argv) + if (rv) + exit (rv); + } ++ else if (WIFSIGNALED (status)) ++ { ++ int sig = WTERMSIG (status); ++ raise (sig); ++ } + else + exit (1); + } diff --git a/SOURCES/glibc-rh2065588-13.patch b/SOURCES/glibc-rh2065588-13.patch new file mode 100644 index 0000000..e4e9d70 --- /dev/null +++ b/SOURCES/glibc-rh2065588-13.patch @@ -0,0 +1,66 @@ +commit 75fe6d1a1620d84e0e487868feba9b2c0f109610 +Author: Siddhesh Poyarekar +Date: Wed May 12 10:13:41 2021 +0530 + + support: Close fds in copy_func + + copy_func may leave file descriptors open on error, so close them on + function exit. + +diff --git a/support/shell-container.c b/support/shell-container.c +index 3869e14683fb74dd..f0a9814ae230d167 100644 +--- a/support/shell-container.c ++++ b/support/shell-container.c +@@ -93,8 +93,9 @@ copy_func (char **argv) + { + char *sname = argv[0]; + char *dname = argv[1]; +- int sfd, dfd; ++ int sfd = -1, dfd = -1; + struct stat st; ++ int ret = 1; + + sfd = open (sname, O_RDONLY); + if (sfd < 0) +@@ -108,7 +109,7 @@ copy_func (char **argv) + { + fprintf (stderr, "cp: unable to fstat %s: %s\n", + sname, strerror (errno)); +- return 1; ++ goto out; + } + + dfd = open (dname, O_WRONLY | O_TRUNC | O_CREAT, 0600); +@@ -116,22 +117,26 @@ copy_func (char **argv) + { + fprintf (stderr, "cp: unable to open %s for writing: %s\n", + dname, strerror (errno)); +- return 1; ++ goto out; + } + + if (support_copy_file_range (sfd, 0, dfd, 0, st.st_size, 0) != st.st_size) + { + fprintf (stderr, "cp: cannot copy file %s to %s: %s\n", + sname, dname, strerror (errno)); +- return 1; ++ goto out; + } + +- close (sfd); +- close (dfd); +- ++ ret = 0; + chmod (dname, st.st_mode & 0777); + +- return 0; ++out: ++ if (sfd >= 0) ++ close (sfd); ++ if (dfd >= 0) ++ close (dfd); ++ ++ return ret; + + } + diff --git a/SOURCES/glibc-rh2065588-2.patch b/SOURCES/glibc-rh2065588-2.patch new file mode 100644 index 0000000..c671cf9 --- /dev/null +++ b/SOURCES/glibc-rh2065588-2.patch @@ -0,0 +1,231 @@ +commit 14d0e87d9b8caaa2eca7ca81f1189596671fe4fb +Author: Adhemerval Zanella +Date: Wed Sep 12 10:32:05 2018 -0300 + + posix: Use posix_spawn on popen + + This patch uses posix_spawn on popen instead of fork and execl. On Linux + this has the advantage of much lower memory consumption (usually 32 Kb + minimum for the mmap stack area). + + Two issues are also fixed with this change: + + * BZ#17490: although POSIX pthread_atfork description only list 'fork' + as the function that should execute the atfork handlers, popen + description states that: + + '[...] shall be *as if* a child process were created within the popen() + call using the fork() function [...]' + + Other libc/system seems to follow the idea atfork handlers should not be + executed for popen: + + libc/system | run atfork handles | notes + ------------|----------------------|--------------------------------------- + Freebsd | no | uses vfork + Solaris 11 | no | + MacOSX 11 | no | implemented through posix_spawn syscall + ------------|----------------------|---------------------------------------- + + Similar to posix_spawn and system, popen idea is to spawn a different + binary so all the POSIX rationale to run the atfork handlers to avoid + internal process inconsistency is not really required and in some cases + might be unsafe. + + * BZ#22834: the described scenario, where the forked process might access + invalid memory due an inconsistent state in multithreaded environment, + should not happen because posix_spawn does not access the affected + data structure (proc_file_chain). + + Checked on x86_64-linux-gnu and i686-linux-gnu. + + [BZ #22834] + [BZ #17490] + * NEWS: Add new semantic for atfork with popen and system. + * libio/iopopen.c (_IO_new_proc_open): use posix_spawn instead of + fork and execl. + +diff --git a/libio/iopopen.c b/libio/iopopen.c +index 2eff45b4c80b5cd6..c768295180fdf809 100644 +--- a/libio/iopopen.c ++++ b/libio/iopopen.c +@@ -34,7 +34,8 @@ + #include + #include + #include +-#include ++#include ++#include + + struct _IO_proc_file + { +@@ -59,13 +60,60 @@ unlock (void *not_used) + } + #endif + ++/* POSIX states popen shall ensure that any streams from previous popen() ++ calls that remain open in the parent process should be closed in the new ++ child process. ++ To avoid a race-condition between checking which file descriptors need to ++ 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 ++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) ++{ ++ ++ for (struct _IO_proc_file *p = proc_file_chain; p; p = p->next) ++ { ++ int fd = _IO_fileno ((FILE *) p); ++ ++ /* 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 (__posix_spawn (&((_IO_proc_file *) fp)->pid, _PATH_BSHELL, fa, 0, ++ (char *const[]){ (char*) "sh", (char*) "-c", ++ (char *) command, NULL }, __environ) != 0) ++ return false; ++ ++ __close_nocancel (pipe_fds[child_end]); ++ ++ if (!do_cloexec) ++ /* Undo the effects of the pipe2 call which set the ++ close-on-exec flag. */ ++ __fcntl (pipe_fds[parent_end], F_SETFD, 0); ++ ++ _IO_fileno (fp) = pipe_fds[parent_end]; ++ ++ ((_IO_proc_file *) fp)->next = proc_file_chain; ++ proc_file_chain = (_IO_proc_file *) fp; ++ ++ return true; ++} ++ + FILE * + _IO_new_proc_open (FILE *fp, const char *command, const char *mode) + { + int read_or_write; ++ /* These are indexes for pipe_fds. */ + int parent_end, child_end; + int pipe_fds[2]; +- pid_t child_pid; ++ int child_pipe_fd; ++ bool spawn_ok; + + int do_read = 0; + int do_write = 0; +@@ -108,72 +156,62 @@ _IO_new_proc_open (FILE *fp, const char *command, const char *mode) + + if (do_read) + { +- parent_end = pipe_fds[0]; +- child_end = pipe_fds[1]; ++ parent_end = 0; ++ child_end = 1; + read_or_write = _IO_NO_WRITES; ++ child_pipe_fd = 1; + } + else + { +- parent_end = pipe_fds[1]; +- child_end = pipe_fds[0]; ++ parent_end = 1; ++ child_end = 0; + read_or_write = _IO_NO_READS; ++ child_pipe_fd = 0; + } + +- ((_IO_proc_file *) fp)->pid = child_pid = __fork (); +- if (child_pid == 0) +- { +- int child_std_end = do_read ? 1 : 0; +- struct _IO_proc_file *p; +- +- if (child_end != child_std_end) +- __dup2 (child_end, child_std_end); +- else +- /* The descriptor is already the one we will use. But it must +- not be marked close-on-exec. Undo the effects. */ +- __fcntl (child_end, F_SETFD, 0); +- /* POSIX.2: "popen() shall ensure that any streams from previous +- popen() calls that remain open in the parent process are closed +- in the new child process." */ +- for (p = proc_file_chain; p; p = p->next) +- { +- int fd = _IO_fileno ((FILE *) p); ++ posix_spawn_file_actions_t fa; ++ /* posix_spawn_file_actions_init does not fail. */ ++ __posix_spawn_file_actions_init (&fa); + +- /* If any stream from previous popen() calls has fileno +- child_std_end, it has been already closed by the dup2 syscall +- above. */ +- if (fd != child_std_end) +- __close_nocancel (fd); +- } +- +- execl ("/bin/sh", "sh", "-c", command, (char *) 0); +- _exit (127); +- } +- __close_nocancel (child_end); +- if (child_pid < 0) ++ /* The descriptor is already the one the child will use. In this case ++ it must be moved to another one otherwise, there is no safe way to ++ remove the close-on-exec flag in the child without creating a FD leak ++ race in the parent. */ ++ if (pipe_fds[child_end] == child_pipe_fd) + { +- __close_nocancel (parent_end); +- return NULL; ++ int tmp = __fcntl (child_pipe_fd, F_DUPFD_CLOEXEC, 0); ++ if (tmp < 0) ++ goto spawn_failure; ++ __close_nocancel (pipe_fds[child_end]); ++ pipe_fds[child_end] = tmp; + } + +- if (!do_cloexec) +- /* Undo the effects of the pipe2 call which set the +- close-on-exec flag. */ +- __fcntl (parent_end, F_SETFD, 0); ++ if (__posix_spawn_file_actions_adddup2 (&fa, pipe_fds[child_end], ++ child_pipe_fd) != 0) ++ goto spawn_failure; + +- _IO_fileno (fp) = parent_end; +- +- /* Link into proc_file_chain. */ + #ifdef _IO_MTSAFE_IO + _IO_cleanup_region_start_noarg (unlock); + _IO_lock_lock (proc_file_chain_lock); + #endif +- ((_IO_proc_file *) fp)->next = proc_file_chain; +- proc_file_chain = (_IO_proc_file *) fp; ++ spawn_ok = 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); + #endif + ++ __posix_spawn_file_actions_destroy (&fa); ++ ++ if (!spawn_ok) ++ { ++ spawn_failure: ++ __close_nocancel (pipe_fds[child_end]); ++ __close_nocancel (pipe_fds[parent_end]); ++ __set_errno (ENOMEM); ++ return NULL; ++ } ++ + _IO_mask_flags (fp, read_or_write, _IO_NO_READS|_IO_NO_WRITES); + return fp; + } diff --git a/SOURCES/glibc-rh2065588-3.patch b/SOURCES/glibc-rh2065588-3.patch new file mode 100644 index 0000000..d168d88 --- /dev/null +++ b/SOURCES/glibc-rh2065588-3.patch @@ -0,0 +1,527 @@ +commit 5fb7fc96350575c9adb1316833e48ca11553be49 +Author: Adhemerval Zanella +Date: Wed Oct 24 16:29:38 2018 -0300 + + posix: Use posix_spawn on system + + This patch uses posix_spawn on system implementation. On Linux this has + the advantage of much lower memory consumption (usually 32 Kb minimum for + the mmap stack area). + + Although POSIX does not require, glibc system implementation aims to be + thread and cancellation safe. The cancellation code is moved to generic + implementation and enabled iff SIGCANCEL is defined (similar on how the + cancellation handler is enabled on nptl-init.c). + + Checked on x86_64-linux-gnu, i686-linux-gnu, aarch64-linux-gnu, + arm-linux-gnueabihf, and powerpc64le-linux-gnu. + + * sysdeps/unix/sysv/linux/spawni.c (__spawni_child): Use + __sigismember instead of sigismember. + * sysdeps/posix/system.c [SIGCANCEL] (cancel_handler_args, + cancel_handler): New definitions. + (CLEANUP_HANDLER, CLEANUP_RESET): Likewise. + (DO_LOCK, DO_UNLOCK, INIT_LOCK, ADD_REF, SUB_REF): Remove. + (do_system): Use posix_spawn instead of fork and execl and remove + reentracy code. + * sysdeps/generic/not-errno.h (__kill_noerrno): New prototype. + * sysdeps/unix/sysv/linux/not-errno.h (__kill_noerrno): Likewise. + * sysdeps/unix/sysv/linux/ia64/system.c: Remove file. + * sysdeps/unix/sysv/linux/s390/system.c: Likewise. + * sysdeps/unix/sysv/linux/sparc/system.c: Likewise. + * sysdeps/unix/sysv/linux/system.c: Likewise. + +diff --git a/sysdeps/generic/not-errno.h b/sysdeps/generic/not-errno.h +index 93617a3266fd4aad..0fd66b5c5ed82315 100644 +--- a/sysdeps/generic/not-errno.h ++++ b/sysdeps/generic/not-errno.h +@@ -17,3 +17,5 @@ + . */ + + extern __typeof (__access) __access_noerrno attribute_hidden; ++ ++extern __typeof (__kill) __kill_noerrno attribute_hidden; +diff --git a/sysdeps/posix/system.c b/sysdeps/posix/system.c +index d7594436ed59906f..8a51a6b9919ec39b 100644 +--- a/sysdeps/posix/system.c ++++ b/sysdeps/posix/system.c +@@ -17,20 +17,36 @@ + + #include + #include +-#include + #include + #include ++#include ++#include ++#include + #include + #include +-#include +-#include +-#include ++#include + ++#include ++#include ++#include ++#include + + #define SHELL_PATH "/bin/sh" /* Path of the shell. */ + #define SHELL_NAME "sh" /* Name to give it. */ + + ++/* This system implementation aims to be thread-safe, which requires to ++ restore the signal dispositions for SIGINT and SIGQUIT correctly and to ++ deal with cancellation by terminating the child process. ++ ++ The signal disposition restoration on the single-thread case is ++ straighfoward. For multithreaded case, a reference-counter with a lock ++ is used, so the first thread will set the SIGINT/SIGQUIT dispositions and ++ last thread will restore them. ++ ++ Cancellation handling is done with thread cancellation clean-up handlers ++ on waitpid call. */ ++ + #ifdef _LIBC_REENTRANT + static struct sigaction intr, quit; + static int sa_refcntr; +@@ -50,17 +66,45 @@ __libc_lock_define_initialized (static, lock); + #endif + + ++#if defined(_LIBC_REENTRANT) && defined(SIGCANCEL) ++struct cancel_handler_args ++{ ++ struct sigaction *quit; ++ struct sigaction *intr; ++ pid_t pid; ++}; ++ ++static void ++cancel_handler (void *arg) ++{ ++ struct cancel_handler_args *args = (struct cancel_handler_args *) (arg); ++ ++ __kill_noerrno (args->pid, SIGKILL); ++ ++ TEMP_FAILURE_RETRY (__waitpid_nocancel (args->pid, NULL, 0)); ++ ++ DO_LOCK (); ++ if (SUB_REF () == 0) ++ { ++ __sigaction (SIGQUIT, args->quit, NULL); ++ __sigaction (SIGINT, args->intr, NULL); ++ } ++ DO_UNLOCK (); ++} ++#endif ++ + /* Execute LINE as a shell command, returning its status. */ + static int + do_system (const char *line) + { +- int status, save; ++ int status; + pid_t pid; + struct sigaction sa; + #ifndef _LIBC_REENTRANT + struct sigaction intr, quit; + #endif + sigset_t omask; ++ sigset_t reset; + + sa.sa_handler = SIG_IGN; + sa.sa_flags = 0; +@@ -69,105 +113,72 @@ do_system (const char *line) + DO_LOCK (); + if (ADD_REF () == 0) + { +- if (__sigaction (SIGINT, &sa, &intr) < 0) +- { +- (void) SUB_REF (); +- goto out; +- } +- if (__sigaction (SIGQUIT, &sa, &quit) < 0) +- { +- save = errno; +- (void) SUB_REF (); +- goto out_restore_sigint; +- } ++ /* sigaction can not fail with SIGINT/SIGQUIT used with SIG_IGN. */ ++ __sigaction (SIGINT, &sa, &intr); ++ __sigaction (SIGQUIT, &sa, &quit); + } + DO_UNLOCK (); + +- /* We reuse the bitmap in the 'sa' structure. */ + __sigaddset (&sa.sa_mask, SIGCHLD); +- save = errno; +- if (__sigprocmask (SIG_BLOCK, &sa.sa_mask, &omask) < 0) ++ /* sigprocmask can not fail with SIG_BLOCK used with valid input ++ arguments. */ ++ __sigprocmask (SIG_BLOCK, &sa.sa_mask, &omask); ++ ++ __sigemptyset (&reset); ++ if (intr.sa_handler != SIG_IGN) ++ __sigaddset(&reset, SIGINT); ++ if (quit.sa_handler != SIG_IGN) ++ __sigaddset(&reset, SIGQUIT); ++ ++ posix_spawnattr_t spawn_attr; ++ /* None of the posix_spawnattr_* function returns an error, including ++ posix_spawnattr_setflags for the follow specific usage (using valid ++ flags). */ ++ __posix_spawnattr_init (&spawn_attr); ++ __posix_spawnattr_setsigmask (&spawn_attr, &omask); ++ __posix_spawnattr_setsigdefault (&spawn_attr, &reset); ++ __posix_spawnattr_setflags (&spawn_attr, ++ POSIX_SPAWN_SETSIGDEF | POSIX_SPAWN_SETSIGMASK); ++ ++ status = __posix_spawn (&pid, SHELL_PATH, 0, &spawn_attr, ++ (char *const[]){ (char*) SHELL_NAME, ++ (char*) "-c", ++ (char *) line, NULL }, ++ __environ); ++ __posix_spawnattr_destroy (&spawn_attr); ++ ++ if (status == 0) + { +-#ifndef _LIBC +- if (errno == ENOSYS) +- __set_errno (save); +- else +-#endif +- { +- DO_LOCK (); +- if (SUB_REF () == 0) +- { +- save = errno; +- (void) __sigaction (SIGQUIT, &quit, (struct sigaction *) NULL); +- out_restore_sigint: +- (void) __sigaction (SIGINT, &intr, (struct sigaction *) NULL); +- __set_errno (save); +- } +- out: +- DO_UNLOCK (); +- return -1; +- } +- } +- +-#ifdef CLEANUP_HANDLER +- CLEANUP_HANDLER; +-#endif +- +-#ifdef FORK +- pid = FORK (); +-#else +- pid = __fork (); ++ /* Cancellation results in cleanup handlers running as exceptions in ++ the block where they were installed, so it is safe to reference ++ stack variable allocate in the broader scope. */ ++#if defined(_LIBC_REENTRANT) && defined(SIGCANCEL) ++ struct cancel_handler_args cancel_args = ++ { ++ .quit = &quit, ++ .intr = &intr, ++ .pid = pid ++ }; ++ __libc_cleanup_region_start (1, cancel_handler, &cancel_args); + #endif +- if (pid == (pid_t) 0) +- { +- /* Child side. */ +- const char *new_argv[4]; +- new_argv[0] = SHELL_NAME; +- new_argv[1] = "-c"; +- new_argv[2] = line; +- new_argv[3] = NULL; +- +- /* Restore the signals. */ +- (void) __sigaction (SIGINT, &intr, (struct sigaction *) NULL); +- (void) __sigaction (SIGQUIT, &quit, (struct sigaction *) NULL); +- (void) __sigprocmask (SIG_SETMASK, &omask, (sigset_t *) NULL); +- INIT_LOCK (); +- +- /* Exec the shell. */ +- (void) __execve (SHELL_PATH, (char *const *) new_argv, __environ); +- _exit (127); +- } +- else if (pid < (pid_t) 0) +- /* The fork failed. */ +- status = -1; +- else +- /* Parent side. */ +- { + /* Note the system() is a cancellation point. But since we call + waitpid() which itself is a cancellation point we do not + have to do anything here. */ + if (TEMP_FAILURE_RETRY (__waitpid (pid, &status, 0)) != pid) + status = -1; +- } +- +-#ifdef CLEANUP_HANDLER +- CLEANUP_RESET; ++#if defined(_LIBC_REENTRANT) && defined(SIGCANCEL) ++ __libc_cleanup_region_end (0); + #endif ++ } + +- save = errno; + DO_LOCK (); +- if ((SUB_REF () == 0 +- && (__sigaction (SIGINT, &intr, (struct sigaction *) NULL) +- | __sigaction (SIGQUIT, &quit, (struct sigaction *) NULL)) != 0) +- || __sigprocmask (SIG_SETMASK, &omask, (sigset_t *) NULL) != 0) ++ if (SUB_REF () == 0) + { +-#ifndef _LIBC +- /* glibc cannot be used on systems without waitpid. */ +- if (errno == ENOSYS) +- __set_errno (save); +- else +-#endif +- status = -1; ++ /* sigaction can not fail with SIGINT/SIGQUIT used with old ++ disposition. Same applies for sigprocmask. */ ++ __sigaction (SIGINT, &intr, NULL); ++ __sigaction (SIGQUIT, &quit, NULL); ++ __sigprocmask (SIG_SETMASK, &omask, NULL); + } + DO_UNLOCK (); + +diff --git a/sysdeps/unix/sysv/linux/ia64/system.c b/sysdeps/unix/sysv/linux/ia64/system.c +deleted file mode 100644 +index d09fefefe64753ab..0000000000000000 +--- a/sysdeps/unix/sysv/linux/ia64/system.c ++++ /dev/null +@@ -1,30 +0,0 @@ +-/* 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 +- . */ +- +-/* We have to and actually can handle cancelable system(). The big +- problem: we have to kill the child process if necessary. To do +- this a cleanup handler has to be registered and is has to be able +- to find the PID of the child. The main problem is to reliable have +- the PID when needed. It is not necessary for the parent thread to +- return. It might still be in the kernel when the cancellation +- request comes. Therefore we have to use the clone() calls ability +- to have the kernel write the PID into the user-level variable. */ +-#define FORK() \ +- INLINE_SYSCALL (clone2, 6, CLONE_PARENT_SETTID | SIGCHLD, NULL, 0, \ +- &pid, NULL, NULL) +- +-#include +diff --git a/sysdeps/unix/sysv/linux/not-errno.h b/sysdeps/unix/sysv/linux/not-errno.h +index 106ba5c72e3d7dda..b2f72cfb3d412c56 100644 +--- a/sysdeps/unix/sysv/linux/not-errno.h ++++ b/sysdeps/unix/sysv/linux/not-errno.h +@@ -16,6 +16,9 @@ + License along with the GNU C Library; if not, see + . */ + ++#include ++#include ++ + /* This function is used on maybe_enable_malloc_check (elf/dl-tunables.c) + and to avoid having to build/use multiple versions if stack protection + in enabled it is defined as inline. */ +@@ -33,3 +36,14 @@ __access_noerrno (const char *pathname, int mode) + return INTERNAL_SYSCALL_ERRNO (res, err); + return 0; + } ++ ++static inline int ++__kill_noerrno (pid_t pid, int sig) ++{ ++ int res; ++ INTERNAL_SYSCALL_DECL (err); ++ res = INTERNAL_SYSCALL_CALL (kill, err, pid, sig); ++ if (INTERNAL_SYSCALL_ERROR_P (res, err)) ++ return INTERNAL_SYSCALL_ERRNO (res, err); ++ return 0; ++} +diff --git a/sysdeps/unix/sysv/linux/s390/system.c b/sysdeps/unix/sysv/linux/s390/system.c +deleted file mode 100644 +index d8ef46133419dd89..0000000000000000 +--- a/sysdeps/unix/sysv/linux/s390/system.c ++++ /dev/null +@@ -1,29 +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 +- . */ +- +-/* We have to and actually can handle cancelable system(). The big +- problem: we have to kill the child process if necessary. To do +- this a cleanup handler has to be registered and is has to be able +- to find the PID of the child. The main problem is to reliable have +- the PID when needed. It is not necessary for the parent thread to +- return. It might still be in the kernel when the cancellation +- request comes. Therefore we have to use the clone() calls ability +- to have the kernel write the PID into the user-level variable. */ +-#define FORK() \ +- INLINE_SYSCALL (clone, 3, 0, CLONE_PARENT_SETTID | SIGCHLD, &pid) +- +-#include "../system.c" +diff --git a/sysdeps/unix/sysv/linux/sparc/system.c b/sysdeps/unix/sysv/linux/sparc/system.c +deleted file mode 100644 +index 1f65c83399f920d6..0000000000000000 +--- a/sysdeps/unix/sysv/linux/sparc/system.c ++++ /dev/null +@@ -1,29 +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 +- . */ +- +-/* We have to and actually can handle cancelable system(). The big +- problem: we have to kill the child process if necessary. To do +- this a cleanup handler has to be registered and is has to be able +- to find the PID of the child. The main problem is to reliable have +- the PID when needed. It is not necessary for the parent thread to +- return. It might still be in the kernel when the cancellation +- request comes. Therefore we have to use the clone() calls ability +- to have the kernel write the PID into the user-level variable. */ +-#define FORK() \ +- INLINE_CLONE_SYSCALL (CLONE_PARENT_SETTID | SIGCHLD, 0, &pid, NULL, NULL) +- +-#include "../system.c" +diff --git a/sysdeps/unix/sysv/linux/spawni.c b/sysdeps/unix/sysv/linux/spawni.c +index 85239cedbf2a5ab5..6a8bd2ed2e1c29b7 100644 +--- a/sysdeps/unix/sysv/linux/spawni.c ++++ b/sysdeps/unix/sysv/linux/spawni.c +@@ -138,11 +138,11 @@ __spawni_child (void *arguments) + for (int sig = 1; sig < _NSIG; ++sig) + { + if ((attr->__flags & POSIX_SPAWN_SETSIGDEF) +- && sigismember (&attr->__sd, sig)) ++ && __sigismember (&attr->__sd, sig)) + { + sa.sa_handler = SIG_DFL; + } +- else if (sigismember (&hset, sig)) ++ else if (__sigismember (&hset, sig)) + { + if (__is_internal_signal (sig)) + sa.sa_handler = SIG_IGN; +diff --git a/sysdeps/unix/sysv/linux/system.c b/sysdeps/unix/sysv/linux/system.c +deleted file mode 100644 +index 7cc68a1528ee8f99..0000000000000000 +--- a/sysdeps/unix/sysv/linux/system.c ++++ /dev/null +@@ -1,76 +0,0 @@ +-/* 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 +- . */ +- +-#include +-#include +-#include /* For the real memset prototype. */ +-#include +-#include +-#include +-#include +- +-/* We have to and actually can handle cancelable system(). The big +- problem: we have to kill the child process if necessary. To do +- this a cleanup handler has to be registered and is has to be able +- to find the PID of the child. The main problem is to reliable have +- the PID when needed. It is not necessary for the parent thread to +- return. It might still be in the kernel when the cancellation +- request comes. Therefore we have to use the clone() calls ability +- to have the kernel write the PID into the user-level variable. */ +-#ifndef FORK +-# define FORK() \ +- INLINE_SYSCALL (clone, 3, CLONE_PARENT_SETTID | SIGCHLD, 0, &pid) +-#endif +- +-#ifdef _LIBC_REENTRANT +-static void cancel_handler (void *arg); +- +-# define CLEANUP_HANDLER \ +- __libc_cleanup_region_start (1, cancel_handler, &pid) +- +-# define CLEANUP_RESET \ +- __libc_cleanup_region_end (0) +-#endif +- +- +-/* Linux has waitpid(), so override the generic unix version. */ +-#include +- +- +-#ifdef _LIBC_REENTRANT +-/* The cancellation handler. */ +-static void +-cancel_handler (void *arg) +-{ +- pid_t child = *(pid_t *) arg; +- +- INTERNAL_SYSCALL_DECL (err); +- INTERNAL_SYSCALL (kill, err, 2, child, SIGKILL); +- +- TEMP_FAILURE_RETRY (__waitpid (child, NULL, 0)); +- +- DO_LOCK (); +- +- if (SUB_REF () == 0) +- { +- (void) __sigaction (SIGQUIT, &quit, (struct sigaction *) NULL); +- (void) __sigaction (SIGINT, &intr, (struct sigaction *) NULL); +- } +- +- DO_UNLOCK (); +-} +-#endif diff --git a/SOURCES/glibc-rh2065588-4.patch b/SOURCES/glibc-rh2065588-4.patch new file mode 100644 index 0000000..33a0cce --- /dev/null +++ b/SOURCES/glibc-rh2065588-4.patch @@ -0,0 +1,194 @@ +commit f09542c584b121da0322fde4b55306d512b85d93 +Author: Adhemerval Zanella +Date: Mon Mar 23 15:23:20 2020 -0300 + + posix: Fix system error return value [BZ #25715] + + It fixes 5fb7fc9635 when posix_spawn fails. + + Checked on x86_64-linux-gnu and i686-linux-gnu. + + Reviewed-by: Carlos O'Donell + +diff --git a/stdlib/tst-system.c b/stdlib/tst-system.c +index d14839f3ec3a7bad..b61bd347df7ec46a 100644 +--- a/stdlib/tst-system.c ++++ b/stdlib/tst-system.c +@@ -17,14 +17,128 @@ + . */ + + #include ++#include ++#include ++#include ++#include + ++#include ++#include ++#include ++#include ++ ++static char *tmpdir; ++static long int namemax; ++ ++static void ++do_prepare (int argc, char *argv[]) ++{ ++ tmpdir = support_create_temp_directory ("tst-system-"); ++ /* Include the last '/0'. */ ++ namemax = pathconf (tmpdir, _PC_NAME_MAX) + 1; ++ TEST_VERIFY_EXIT (namemax != -1); ++} ++#define PREPARE do_prepare ++ ++struct args ++{ ++ const char *command; ++ int exit_status; ++ int term_sig; ++ const char *path; ++}; ++ ++static void ++call_system (void *closure) ++{ ++ struct args *args = (struct args *) closure; ++ int ret; ++ ++ if (args->path != NULL) ++ TEST_COMPARE (setenv ("PATH", args->path, 1), 0); ++ ret = system (args->command); ++ if (args->term_sig == 0) ++ { ++ /* Expect regular termination. */ ++ TEST_VERIFY (WIFEXITED (ret) != 0); ++ TEST_COMPARE (WEXITSTATUS (ret), args->exit_status); ++ } ++ else ++ { ++ /* status_or_signal < 0. Expect termination by signal. */ ++ TEST_VERIFY (WIFSIGNALED (ret) != 0); ++ TEST_COMPARE (WTERMSIG (ret), args->term_sig); ++ } ++} + + static int + do_test (void) + { +- return system (":"); +-} ++ TEST_VERIFY (system (NULL) != 0); + ++ { ++ char cmd[namemax]; ++ memset (cmd, 'a', sizeof(cmd)); ++ cmd[sizeof(cmd) - 1] = '\0'; ++ ++ struct support_capture_subprocess result; ++ result = support_capture_subprocess (call_system, ++ &(struct args) { ++ cmd, 127, 0, tmpdir ++ }); ++ support_capture_subprocess_check (&result, "system", 0, sc_allow_stderr); ++ ++ char *returnerr = xasprintf ("%s: 1: %s: not found\n", ++ basename(_PATH_BSHELL), cmd); ++ TEST_COMPARE_STRING (result.err.buffer, returnerr); ++ free (returnerr); ++ } ++ ++ { ++ char cmd[namemax + 1]; ++ memset (cmd, 'a', sizeof(cmd)); ++ cmd[sizeof(cmd) - 1] = '\0'; ++ ++ struct support_capture_subprocess result; ++ result = support_capture_subprocess (call_system, ++ &(struct args) { ++ cmd, 127, 0, tmpdir ++ }); ++ support_capture_subprocess_check (&result, "system", 0, sc_allow_stderr); ++ ++ char *returnerr = xasprintf ("%s: 1: %s: File name too long\n", ++ basename(_PATH_BSHELL), cmd); ++ TEST_COMPARE_STRING (result.err.buffer, returnerr); ++ free (returnerr); ++ } ++ ++ { ++ struct support_capture_subprocess result; ++ result = support_capture_subprocess (call_system, ++ &(struct args) { ++ "kill -USR1 $$", 0, SIGUSR1 ++ }); ++ support_capture_subprocess_check (&result, "system", 0, sc_allow_none); ++ } ++ ++ { ++ struct support_capture_subprocess result; ++ result = support_capture_subprocess (call_system, ++ &(struct args) { "echo ...", 0 }); ++ support_capture_subprocess_check (&result, "system", 0, sc_allow_stdout); ++ TEST_COMPARE_STRING (result.out.buffer, "...\n"); ++ } ++ ++ { ++ struct support_capture_subprocess result; ++ result = support_capture_subprocess (call_system, ++ &(struct args) { "exit 1", 1 }); ++ support_capture_subprocess_check (&result, "system", 0, sc_allow_none); ++ } ++ ++ TEST_COMPARE (system (":"), 0); ++ ++ return 0; ++} + +-#define TEST_FUNCTION do_test () +-#include "../test-skeleton.c" ++#include +diff --git a/sysdeps/posix/system.c b/sysdeps/posix/system.c +index 8a51a6b9919ec39b..7db09a05c3fbca43 100644 +--- a/sysdeps/posix/system.c ++++ b/sysdeps/posix/system.c +@@ -97,7 +97,8 @@ cancel_handler (void *arg) + static int + do_system (const char *line) + { +- int status; ++ int status = -1; ++ int ret; + pid_t pid; + struct sigaction sa; + #ifndef _LIBC_REENTRANT +@@ -140,14 +141,14 @@ do_system (const char *line) + __posix_spawnattr_setflags (&spawn_attr, + POSIX_SPAWN_SETSIGDEF | POSIX_SPAWN_SETSIGMASK); + +- status = __posix_spawn (&pid, SHELL_PATH, 0, &spawn_attr, +- (char *const[]){ (char*) SHELL_NAME, +- (char*) "-c", +- (char *) line, NULL }, +- __environ); ++ ret = __posix_spawn (&pid, SHELL_PATH, 0, &spawn_attr, ++ (char *const[]){ (char *) SHELL_NAME, ++ (char *) "-c", ++ (char *) line, NULL }, ++ __environ); + __posix_spawnattr_destroy (&spawn_attr); + +- if (status == 0) ++ if (ret == 0) + { + /* Cancellation results in cleanup handlers running as exceptions in + the block where they were installed, so it is safe to reference +@@ -182,6 +183,9 @@ do_system (const char *line) + } + DO_UNLOCK (); + ++ if (ret != 0) ++ __set_errno (ret); ++ + return status; + } + diff --git a/SOURCES/glibc-rh2065588-5.patch b/SOURCES/glibc-rh2065588-5.patch new file mode 100644 index 0000000..368e759 --- /dev/null +++ b/SOURCES/glibc-rh2065588-5.patch @@ -0,0 +1,64 @@ +commit 7a7226543611897103c7483bec160547294dcf0d +Author: Alexandra Hájková +Date: Sat Dec 26 20:44:34 2020 +0100 + + Add xfchmod to libsupport + +diff --git a/support/Makefile b/support/Makefile +index d2b95539403e416c..4875f52495ef292d 100644 +--- a/support/Makefile ++++ b/support/Makefile +@@ -91,6 +91,7 @@ libsupport-routines = \ + xdlfcn \ + xdlmopen \ + xdup2 \ ++ xfchmod \ + xfclose \ + xfopen \ + xfork \ +diff --git a/support/xfchmod.c b/support/xfchmod.c +new file mode 100644 +index 0000000000000000..4323b9ca8e078c98 +--- /dev/null ++++ b/support/xfchmod.c +@@ -0,0 +1,28 @@ ++/* fchmod with error checking. ++ 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 ++ ++void ++xfchmod (int fd, mode_t mode) ++{ ++ if (fchmod (fd, mode) != 0) ++ FAIL_EXIT1 ("fchmod (%d, 0%o): %m", fd, mode); ++} +diff --git a/support/xunistd.h b/support/xunistd.h +index 74fd2771d12c36fe..ced8cb1dd9ee356c 100644 +--- a/support/xunistd.h ++++ b/support/xunistd.h +@@ -45,6 +45,7 @@ long long xlseek (int fd, long long offset, int whence); + void xftruncate (int fd, long long length); + void xsymlink (const char *target, const char *linkpath); + void xchdir (const char *path); ++void xfchmod (int fd, mode_t mode); + + /* Equivalent of "mkdir -p". */ + void xmkdirp (const char *, mode_t); diff --git a/SOURCES/glibc-rh2065588-6.patch b/SOURCES/glibc-rh2065588-6.patch new file mode 100644 index 0000000..16fdb47 --- /dev/null +++ b/SOURCES/glibc-rh2065588-6.patch @@ -0,0 +1,56 @@ +commit 7b9c3260bcca73781dda6bc2ddee84869bedfb8c +Author: Adhemerval Zanella +Date: Mon Dec 14 11:42:33 2020 -0300 + + support: Add xchmod wrapper + + Checked on x86_64-linux-gnu. + +diff --git a/support/xchmod.c b/support/xchmod.c +new file mode 100644 +index 0000000000000000..5e403c7cc2705aef +--- /dev/null ++++ b/support/xchmod.c +@@ -0,0 +1,30 @@ ++/* chmod with error checking. ++ 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 ++ ++void ++xchmod (const char *pathname, mode_t mode) ++{ ++ int r = chmod (pathname, mode); ++ if (r < 0) ++ FAIL_EXIT1 ("chmod (%s, %d): %m", pathname, mode); ++} +diff --git a/support/xunistd.h b/support/xunistd.h +index ced8cb1dd9ee356c..e92056c65efe8d6a 100644 +--- a/support/xunistd.h ++++ b/support/xunistd.h +@@ -46,6 +46,7 @@ void xftruncate (int fd, long long length); + void xsymlink (const char *target, const char *linkpath); + void xchdir (const char *path); + void xfchmod (int fd, mode_t mode); ++void xchmod (const char *pathname, mode_t mode); + + /* Equivalent of "mkdir -p". */ + void xmkdirp (const char *, mode_t); diff --git a/SOURCES/glibc-rh2065588-7.patch b/SOURCES/glibc-rh2065588-7.patch new file mode 100644 index 0000000..b16b79e --- /dev/null +++ b/SOURCES/glibc-rh2065588-7.patch @@ -0,0 +1,73 @@ +commit 4eda036f5b897fa8bc20ddd2099b5a6ed4239dc9 +Author: Adhemerval Zanella +Date: Tue Mar 24 15:48:34 2020 -0300 + + stdlib: Move tst-system to tests-container + + Fix some issues with different shell and error messages. + + Checked on x86_64-linux-gnu and i686-linux-gnu. + +diff --git a/stdlib/Makefile b/stdlib/Makefile +index 01194bbf7cc96851..9d0edcf6a7749b28 100644 +--- a/stdlib/Makefile ++++ b/stdlib/Makefile +@@ -70,7 +70,7 @@ tests := tst-strtol tst-strtod testmb testrand testsort testdiv \ + test-canon test-canon2 tst-strtoll tst-environ \ + tst-xpg-basename tst-random tst-random2 tst-bsearch \ + tst-limits tst-rand48 bug-strtod tst-setcontext \ +- tst-setcontext2 test-a64l tst-qsort tst-system testmb2 \ ++ tst-setcontext2 test-a64l tst-qsort testmb2 \ + bug-strtod2 tst-atof1 tst-atof2 tst-strtod2 \ + tst-rand48-2 tst-makecontext tst-strtod5 \ + tst-qsort2 tst-makecontext2 tst-strtod6 tst-unsetenv1 \ +@@ -92,6 +92,7 @@ tests := tst-strtol tst-strtod testmb testrand testsort testdiv \ + tests-internal := tst-strtod1i tst-strtod3 tst-strtod4 tst-strtod5i \ + tst-tls-atexit tst-tls-atexit-nodelete + tests-static := tst-secure-getenv ++tests-container := tst-system + + ifeq ($(build-hardcoded-path-in-tests),yes) + tests += tst-empty-env +diff --git a/stdlib/tst-system.c b/stdlib/tst-system.c +index b61bd347df7ec46a..194e09828dd5c206 100644 +--- a/stdlib/tst-system.c ++++ b/stdlib/tst-system.c +@@ -88,7 +88,8 @@ do_test (void) + }); + support_capture_subprocess_check (&result, "system", 0, sc_allow_stderr); + +- char *returnerr = xasprintf ("%s: 1: %s: not found\n", ++ char *returnerr = xasprintf ("%s: execing %s failed: " ++ "No such file or directory", + basename(_PATH_BSHELL), cmd); + TEST_COMPARE_STRING (result.err.buffer, returnerr); + free (returnerr); +@@ -106,7 +107,8 @@ do_test (void) + }); + support_capture_subprocess_check (&result, "system", 0, sc_allow_stderr); + +- char *returnerr = xasprintf ("%s: 1: %s: File name too long\n", ++ char *returnerr = xasprintf ("%s: execing %s failed: " ++ "File name too long", + basename(_PATH_BSHELL), cmd); + TEST_COMPARE_STRING (result.err.buffer, returnerr); + free (returnerr); +@@ -116,7 +118,7 @@ do_test (void) + struct support_capture_subprocess result; + result = support_capture_subprocess (call_system, + &(struct args) { +- "kill -USR1 $$", 0, SIGUSR1 ++ "kill $$", 0, SIGTERM + }); + support_capture_subprocess_check (&result, "system", 0, sc_allow_none); + } +@@ -136,7 +138,7 @@ do_test (void) + support_capture_subprocess_check (&result, "system", 0, sc_allow_none); + } + +- TEST_COMPARE (system (":"), 0); ++ TEST_COMPARE (system (""), 0); + + return 0; + } diff --git a/SOURCES/glibc-rh2065588-8.patch b/SOURCES/glibc-rh2065588-8.patch new file mode 100644 index 0000000..102b72a --- /dev/null +++ b/SOURCES/glibc-rh2065588-8.patch @@ -0,0 +1,74 @@ +commit 42dda89dcb0407f6799dbfd0b9dab1529666ad51 +Author: Adhemerval Zanella +Date: Fri Dec 11 15:23:05 2020 -0300 + + posix: Fix return value of system if shell can not be executed [BZ #27053] + + POSIX states that system returned code for failure to execute the shell + shall be as if the shell had terminated using _exit(127). This + behaviour was removed with 5fb7fc96350575. + + Checked on x86_64-linux-gnu. + +diff --git a/stdlib/tst-system.c b/stdlib/tst-system.c +index 194e09828dd5c206..8681584f15ef3b47 100644 +--- a/stdlib/tst-system.c ++++ b/stdlib/tst-system.c +@@ -26,6 +26,7 @@ + #include + #include + #include ++#include + + static char *tmpdir; + static long int namemax; +@@ -138,6 +139,22 @@ do_test (void) + support_capture_subprocess_check (&result, "system", 0, sc_allow_none); + } + ++ { ++ struct stat64 st; ++ xstat (_PATH_BSHELL, &st); ++ mode_t mode = st.st_mode; ++ xchmod (_PATH_BSHELL, mode & ~(S_IXUSR | S_IXGRP | S_IXOTH)); ++ ++ struct support_capture_subprocess result; ++ result = support_capture_subprocess (call_system, ++ &(struct args) { ++ "exit 1", 127, 0 ++ }); ++ support_capture_subprocess_check (&result, "system", 0, sc_allow_none); ++ ++ xchmod (_PATH_BSHELL, st.st_mode); ++ } ++ + TEST_COMPARE (system (""), 0); + + return 0; +diff --git a/support/Makefile b/support/Makefile +index 4875f52495ef292d..09b41b0d57e9239a 100644 +--- a/support/Makefile ++++ b/support/Makefile +@@ -86,6 +86,7 @@ libsupport-routines = \ + xchroot \ + xclone \ + xclose \ ++ xchmod \ + xconnect \ + xcopy_file_range \ + xdlfcn \ +diff --git a/sysdeps/posix/system.c b/sysdeps/posix/system.c +index 7db09a05c3fbca43..047ded4badfddcab 100644 +--- a/sysdeps/posix/system.c ++++ b/sysdeps/posix/system.c +@@ -171,6 +171,10 @@ do_system (const char *line) + __libc_cleanup_region_end (0); + #endif + } ++ else ++ /* POSIX states that failure to execute the shell should return ++ as if the shell had terminated using _exit(127). */ ++ status = W_EXITCODE (127, 0); + + DO_LOCK (); + if (SUB_REF () == 0) diff --git a/SOURCES/glibc-rh2065588-9.patch b/SOURCES/glibc-rh2065588-9.patch new file mode 100644 index 0000000..6d259d8 --- /dev/null +++ b/SOURCES/glibc-rh2065588-9.patch @@ -0,0 +1,21 @@ +commit 542160f0b6a7c26758c9575a8876f6624a5dd65f +Author: Girish Joshi +Date: Mon Mar 2 15:19:29 2020 -0500 + + Fixed typo in run_command_array() in support/shell-container.c + + https://sourceware.org/bugzilla/show_bug.cgi?id=23991 + +diff --git a/support/shell-container.c b/support/shell-container.c +index 9bd90d3f60529079..e87ac5cf1baa84e5 100644 +--- a/support/shell-container.c ++++ b/support/shell-container.c +@@ -228,7 +228,7 @@ run_command_array (char **argv) + if (new_stderr != 2) + { + dup2 (new_stderr, 2); +- close (new_stdout); ++ close (new_stderr); + } + + if (builtin_func != NULL) diff --git a/SOURCES/glibc-rh2071745.patch b/SOURCES/glibc-rh2071745.patch new file mode 100644 index 0000000..8fbfffb --- /dev/null +++ b/SOURCES/glibc-rh2071745.patch @@ -0,0 +1,23 @@ +commit 62db87ab24f9ca483f97f5e52ea92445f6a63c6f +Author: Adhemerval Zanella +Date: Mon Jan 10 10:17:18 2022 -0300 + + timezone: Fix tst-bz28707 Makefile rule + + The $(testdata)/XT5 rule is ambiguous and it may not be correct + evaluated. + +diff --git a/timezone/Makefile b/timezone/Makefile +index ac7f483c130b5b4a..c4a63daadb8d5dc5 100644 +--- a/timezone/Makefile ++++ b/timezone/Makefile +@@ -123,7 +123,8 @@ $(testdata)/XT%: testdata/XT% + $(make-target-directory) + cp $< $@ + +-$(testdata)/XT%: testdata/gen-XT%.sh ++$(testdata)/XT5: testdata/gen-XT5.sh ++ $(make-target-directory) + $(SHELL) $< > $@.tmp + mv $@.tmp $@ + diff --git a/SOURCES/glibc-rh2072329.patch b/SOURCES/glibc-rh2072329.patch new file mode 100644 index 0000000..e26331e --- /dev/null +++ b/SOURCES/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/SOURCES/glibc-rh2077835.patch b/SOURCES/glibc-rh2077835.patch new file mode 100644 index 0000000..7323d49 --- /dev/null +++ b/SOURCES/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/SOURCES/glibc-rh2080349-1.patch b/SOURCES/glibc-rh2080349-1.patch new file mode 100644 index 0000000..0bc7524 --- /dev/null +++ b/SOURCES/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/SOURCES/glibc-rh2080349-2.patch b/SOURCES/glibc-rh2080349-2.patch new file mode 100644 index 0000000..6084110 --- /dev/null +++ b/SOURCES/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/SOURCES/glibc-rh2080349-3.patch b/SOURCES/glibc-rh2080349-3.patch new file mode 100644 index 0000000..7293e03 --- /dev/null +++ b/SOURCES/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/SOURCES/glibc-rh2080349-4.patch b/SOURCES/glibc-rh2080349-4.patch new file mode 100644 index 0000000..205b903 --- /dev/null +++ b/SOURCES/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/SOURCES/glibc-rh2080349-5.patch b/SOURCES/glibc-rh2080349-5.patch new file mode 100644 index 0000000..b042917 --- /dev/null +++ b/SOURCES/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/SOURCES/glibc-rh2080349-6.patch b/SOURCES/glibc-rh2080349-6.patch new file mode 100644 index 0000000..333f362 --- /dev/null +++ b/SOURCES/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/SOURCES/glibc-rh2080349-7.patch b/SOURCES/glibc-rh2080349-7.patch new file mode 100644 index 0000000..067f10e --- /dev/null +++ b/SOURCES/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/SOURCES/glibc-rh2080349-8.patch b/SOURCES/glibc-rh2080349-8.patch new file mode 100644 index 0000000..5e6fa9f --- /dev/null +++ b/SOURCES/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/SOURCES/glibc-rh2080349-9.patch b/SOURCES/glibc-rh2080349-9.patch new file mode 100644 index 0000000..080811e --- /dev/null +++ b/SOURCES/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/SOURCES/glibc-rh2086853.patch b/SOURCES/glibc-rh2086853.patch new file mode 100644 index 0000000..d11e4cb --- /dev/null +++ b/SOURCES/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/SOURCES/glibc-rh2089247-1.patch b/SOURCES/glibc-rh2089247-1.patch new file mode 100644 index 0000000..b3e05ef --- /dev/null +++ b/SOURCES/glibc-rh2089247-1.patch @@ -0,0 +1,47 @@ +commit e1df30fbc2e2167a982c0e77a7ebee28f4dd0800 +Author: Adhemerval Zanella +Date: Thu Jul 25 11:22:17 2019 -0300 + + Get new entropy on each attempt __gen_tempname (BZ #15813) + + This is missing bit for fully fix BZ#15813 (the other two were fixed + by 359653aaacad463). + + Checked on x86_64-linux-gnu. + + [BZ #15813] + sysdeps/posix/tempname.c (__gen_tempname): get entrypy on each + attempt. + +diff --git a/sysdeps/posix/tempname.c b/sysdeps/posix/tempname.c +index 3d26f378021680ae..61d7a9f36d37abae 100644 +--- a/sysdeps/posix/tempname.c ++++ b/sysdeps/posix/tempname.c +@@ -186,7 +186,6 @@ __gen_tempname (char *tmpl, int suffixlen, int flags, int kind) + { + int len; + char *XXXXXX; +- uint64_t value; + unsigned int count; + int fd = -1; + int save_errno = errno; +@@ -218,13 +217,13 @@ __gen_tempname (char *tmpl, int suffixlen, int flags, int kind) + /* This is where the Xs start. */ + XXXXXX = &tmpl[len - 6 - suffixlen]; + +- /* Get some more or less random data. */ +- RANDOM_BITS (value); +- value ^= (uint64_t)__getpid () << 32; +- +- for (count = 0; count < attempts; value += 7777, ++count) ++ uint64_t pid = (uint64_t) __getpid () << 32; ++ for (count = 0; count < attempts; ++count) + { +- uint64_t v = value; ++ uint64_t v; ++ /* Get some more or less random data. */ ++ RANDOM_BITS (v); ++ v ^= pid; + + /* Fill in the random bits. */ + XXXXXX[0] = letters[v % 62]; diff --git a/SOURCES/glibc-rh2089247-2.patch b/SOURCES/glibc-rh2089247-2.patch new file mode 100644 index 0000000..84c6ac2 --- /dev/null +++ b/SOURCES/glibc-rh2089247-2.patch @@ -0,0 +1,87 @@ +commit 8eaf34eda256ba3647ed6e7ed5c7c9aa19955d17 +Author: Samuel Thibault +Date: Fri Dec 13 10:10:59 2019 +0100 + + hurd: Fix local PLT + + * include/sys/random.h (__getrandom): Add hidden prototype. + * stdlib/getrandom.c (getrandom): Rename to hidden definition __getrandom. + Add weak alias. + * sysdeps/mach/hurd/getrandom.c (getrandom): Likewise. + * sysdeps/unix/sysv/linux/getrandom.c (getrandom): Likewise. + * sysdeps/mach/hurd/getentropy.c (getentropy): Use __getrandom instead of + getrandom. + +Conflicts: + include/sys/random.h + (Missing backport of include/ consistency patch, + commit ebd32784ce2029d0461a90a79bc4e37f8d051765 upstream.) + sysdeps/mach/hurd/getentropy.c + (Hurd change has been dropped.) + sysdeps/unix/sysv/linux/dl-write.c + (Mismerge of sysdeps/mach/hurd/getrandom.c.) + +diff --git a/include/sys/random.h b/include/sys/random.h +new file mode 100644 +index 0000000000000000..6aa313d35dbdce8a +--- /dev/null ++++ b/include/sys/random.h +@@ -0,0 +1,11 @@ ++#ifndef _SYS_RANDOM_H ++#include ++ ++# ifndef _ISOMAC ++ ++extern ssize_t __getrandom (void *__buffer, size_t __length, ++ unsigned int __flags) __wur; ++libc_hidden_proto (__getrandom) ++ ++# endif /* !_ISOMAC */ ++#endif +diff --git a/stdlib/getrandom.c b/stdlib/getrandom.c +index 45234bea17c5c86c..f8056688e40a0215 100644 +--- a/stdlib/getrandom.c ++++ b/stdlib/getrandom.c +@@ -22,10 +22,12 @@ + /* Write up to LENGTH bytes of randomness starting at BUFFER. + Return the number of bytes written, or -1 on error. */ + ssize_t +-getrandom (void *buffer, size_t length, unsigned int flags) ++__getrandom (void *buffer, size_t length, unsigned int flags) + { + __set_errno (ENOSYS); + return -1; + } +- + stub_warning (getrandom) ++ ++libc_hidden_def (__getrandom) ++weak_alias (__getrandom, getrandom) +diff --git a/sysdeps/unix/sysv/linux/getrandom.c b/sysdeps/unix/sysv/linux/getrandom.c +index 435b037399665654..e34d7fdcd89d9b06 100644 +--- a/sysdeps/unix/sysv/linux/getrandom.c ++++ b/sysdeps/unix/sysv/linux/getrandom.c +@@ -25,7 +25,7 @@ + /* Write up to LENGTH bytes of randomness starting at BUFFER. + Return the number of bytes written, or -1 on error. */ + ssize_t +-getrandom (void *buffer, size_t length, unsigned int flags) ++__getrandom (void *buffer, size_t length, unsigned int flags) + { + return SYSCALL_CANCEL (getrandom, buffer, length, flags); + } +@@ -33,7 +33,7 @@ getrandom (void *buffer, size_t length, unsigned int flags) + /* Always provide a definition, even if the kernel headers lack the + system call number. */ + ssize_t +-getrandom (void *buffer, size_t length, unsigned int flags) ++__getrandom (void *buffer, size_t length, unsigned int flags) + { + /* Ideally, we would add a cancellation point here, but we currently + cannot do so inside libc. */ +@@ -41,3 +41,5 @@ getrandom (void *buffer, size_t length, unsigned int flags) + return -1; + } + #endif ++libc_hidden_def (__getrandom) ++weak_alias (__getrandom, getrandom) diff --git a/SOURCES/glibc-rh2089247-3.patch b/SOURCES/glibc-rh2089247-3.patch new file mode 100644 index 0000000..b7f72e6 --- /dev/null +++ b/SOURCES/glibc-rh2089247-3.patch @@ -0,0 +1,67 @@ +Partial backport of: + +commit 04986243d1af37ac0177ed2f9db0a066ebd2b212 +Author: Adhemerval Zanella +Date: Wed Jul 15 19:35:58 2020 +0000 + + Remove internal usage of extensible stat functions + + It replaces the internal usage of __{f,l}xstat{at}{64} with the + __{f,l}stat{at}{64}. It should not change the generate code since + sys/stat.h explicit defines redirections to internal calls back to + xstat* symbols. + + Checked with a build for all affected ABIs. I also check on + x86_64-linux-gnu and i686-linux-gnu. + + Reviewed-by: Lukasz Majewski + +Only the changes to include/sys/stat.h and sysdeps/posix/tempname.c +are included here. + +diff --git a/include/sys/stat.h b/include/sys/stat.h +index b82d4527801d4797..c5b1938b87c9c5c3 100644 +--- a/include/sys/stat.h ++++ b/include/sys/stat.h +@@ -52,6 +52,7 @@ extern __typeof (__fxstatat64) __fxstatat64 attribute_hidden; + #define lstat64(fname, buf) __lxstat64 (_STAT_VER, fname, buf) + #define __lstat64(fname, buf) __lxstat64 (_STAT_VER, fname, buf) + #define stat64(fname, buf) __xstat64 (_STAT_VER, fname, buf) ++#define __stat64(fname, buf) __xstat64 (_STAT_VER, fname, buf) + #define fstat64(fd, buf) __fxstat64 (_STAT_VER, fd, buf) + #define __fstat64(fd, buf) __fxstat64 (_STAT_VER, fd, buf) + #define fstat(fd, buf) __fxstat (_STAT_VER, fd, buf) +diff --git a/sysdeps/posix/tempname.c b/sysdeps/posix/tempname.c +index 61d7a9f36d37abae..a7b404cf4410cb00 100644 +--- a/sysdeps/posix/tempname.c ++++ b/sysdeps/posix/tempname.c +@@ -66,7 +66,6 @@ + # define __gettimeofday gettimeofday + # define __mkdir mkdir + # define __open open +-# define __lxstat64(version, file, buf) lstat (file, buf) + # define __secure_getenv secure_getenv + #endif + +@@ -97,7 +96,7 @@ static int + direxists (const char *dir) + { + struct_stat64 buf; +- return __xstat64 (_STAT_VER, dir, &buf) == 0 && S_ISDIR (buf.st_mode); ++ return __stat64 (dir, &buf) == 0 && S_ISDIR (buf.st_mode); + } + + /* Path search algorithm, for tmpnam, tmpfile, etc. If DIR is +@@ -252,10 +251,10 @@ __gen_tempname (char *tmpl, int suffixlen, int flags, int kind) + + case __GT_NOCREATE: + /* This case is backward from the other three. __gen_tempname +- succeeds if __xstat fails because the name does not exist. ++ succeeds if lstat fails because the name does not exist. + Note the continue to bypass the common logic at the bottom + of the loop. */ +- if (__lxstat64 (_STAT_VER, tmpl, &st) < 0) ++ if (__lstat64 (tmpl, &st) < 0) + { + if (errno == ENOENT) + { diff --git a/SOURCES/glibc-rh2089247-4.patch b/SOURCES/glibc-rh2089247-4.patch new file mode 100644 index 0000000..878739a --- /dev/null +++ b/SOURCES/glibc-rh2089247-4.patch @@ -0,0 +1,440 @@ +commit 4dddd7e9cbecad4aa03ee5a9b9edb596e3d4e909 +Author: Adhemerval Zanella +Date: Tue Sep 29 08:56:07 2020 -0300 + + posix: Sync tempname with gnulib [BZ #26648] + + It syncs with gnulib commit b1268f22f443e8e4b9e. The try_tempname_len + now uses getrandom on each iteration to get entropy and only uses the + clock plus ASLR as source of entropy if getrandom fails. + + Checked on x86_64-linux-gnu and i686-linux-gnu. + +Conflicts: + sysdeps/posix/tempname.c + (Missing tree-wide __gettimeofday to clock_gettime change, + commit 4a39c34c4f85de57fb4e648cfa1e774437d69680 upstream. + File was rebased to the upstream version.) + +diff --git a/sysdeps/posix/tempname.c b/sysdeps/posix/tempname.c +index a7b404cf4410cb00..f199b25a7a227751 100644 +--- a/sysdeps/posix/tempname.c ++++ b/sysdeps/posix/tempname.c +@@ -1,4 +1,4 @@ +-/* Copyright (C) 1991-2018 Free Software Foundation, Inc. ++/* Copyright (C) 1991-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 +@@ -13,10 +13,10 @@ + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see +- . */ ++ . */ + + #if !_LIBC +-# include ++# include + # include "tempname.h" + #endif + +@@ -24,9 +24,6 @@ + #include + + #include +-#ifndef __set_errno +-# define __set_errno(Val) errno = (Val) +-#endif + + #include + #ifndef P_tmpdir +@@ -36,12 +33,12 @@ + # define TMP_MAX 238328 + #endif + #ifndef __GT_FILE +-# define __GT_FILE 0 +-# define __GT_DIR 1 +-# define __GT_NOCREATE 2 ++# define __GT_FILE 0 ++# define __GT_DIR 1 ++# define __GT_NOCREATE 2 + #endif +-#if !_LIBC && (GT_FILE != __GT_FILE || GT_DIR != __GT_DIR \ +- || GT_NOCREATE != __GT_NOCREATE) ++#if !_LIBC && (GT_FILE != __GT_FILE || GT_DIR != __GT_DIR \ ++ || GT_NOCREATE != __GT_NOCREATE) + # error report this to bug-gnulib@gnu.org + #endif + +@@ -50,11 +47,11 @@ + #include + + #include +-#include ++#include + #include +-#include +- ++#include + #include ++#include + + #if _LIBC + # define struct_stat64 struct stat64 +@@ -62,33 +59,38 @@ + #else + # define struct_stat64 struct stat + # define __gen_tempname gen_tempname +-# define __getpid getpid +-# define __gettimeofday gettimeofday + # define __mkdir mkdir + # define __open open +-# define __secure_getenv secure_getenv ++# define __lstat64(file, buf) lstat (file, buf) ++# define __stat64(file, buf) stat (file, buf) ++# define __getrandom getrandom ++# define __clock_gettime64 clock_gettime ++# define __timespec64 timespec + #endif + +-#ifdef _LIBC +-# include +-# define RANDOM_BITS(Var) ((Var) = random_bits ()) +-# else +-# define RANDOM_BITS(Var) \ +- { \ +- struct timeval tv; \ +- __gettimeofday (&tv, NULL); \ +- (Var) = ((uint64_t) tv.tv_usec << 16) ^ tv.tv_sec; \ +- } +-#endif ++/* Use getrandom if it works, falling back on a 64-bit linear ++ congruential generator that starts with Var's value ++ mixed in with a clock's low-order bits if available. */ ++typedef uint_fast64_t random_value; ++#define RANDOM_VALUE_MAX UINT_FAST64_MAX ++#define BASE_62_DIGITS 10 /* 62**10 < UINT_FAST64_MAX */ ++#define BASE_62_POWER (62LL * 62 * 62 * 62 * 62 * 62 * 62 * 62 * 62 * 62) + +-/* Use the widest available unsigned type if uint64_t is not +- available. The algorithm below extracts a number less than 62**6 +- (approximately 2**35.725) from uint64_t, so ancient hosts where +- uintmax_t is only 32 bits lose about 3.725 bits of randomness, +- which is better than not having mkstemp at all. */ +-#if !defined UINT64_MAX && !defined uint64_t +-# define uint64_t uintmax_t ++static random_value ++random_bits (random_value var) ++{ ++ random_value r; ++ /* Without GRND_NONBLOCK it can be blocked for minutes on some systems. */ ++ if (__getrandom (&r, sizeof r, GRND_NONBLOCK) == sizeof r) ++ return r; ++#if _LIBC || (defined CLOCK_MONOTONIC && HAVE_CLOCK_GETTIME) ++ /* Add entropy if getrandom did not work. */ ++ struct __timespec64 tv; ++ __clock_gettime64 (CLOCK_MONOTONIC, &tv); ++ var ^= tv.tv_nsec; + #endif ++ return 2862933555777941757 * var + 3037000493; ++} + + #if _LIBC + /* Return nonzero if DIR is an existent directory. */ +@@ -107,7 +109,7 @@ direxists (const char *dir) + enough space in TMPL. */ + int + __path_search (char *tmpl, size_t tmpl_len, const char *dir, const char *pfx, +- int try_tmpdir) ++ int try_tmpdir) + { + const char *d; + size_t dlen, plen; +@@ -121,35 +123,35 @@ __path_search (char *tmpl, size_t tmpl_len, const char *dir, const char *pfx, + { + plen = strlen (pfx); + if (plen > 5) +- plen = 5; ++ plen = 5; + } + + if (try_tmpdir) + { + d = __secure_getenv ("TMPDIR"); + if (d != NULL && direxists (d)) +- dir = d; ++ dir = d; + else if (dir != NULL && direxists (dir)) +- /* nothing */ ; ++ /* nothing */ ; + else +- dir = NULL; ++ dir = NULL; + } + if (dir == NULL) + { + if (direxists (P_tmpdir)) +- dir = P_tmpdir; ++ dir = P_tmpdir; + else if (strcmp (P_tmpdir, "/tmp") != 0 && direxists ("/tmp")) +- dir = "/tmp"; ++ dir = "/tmp"; + else +- { +- __set_errno (ENOENT); +- return -1; +- } ++ { ++ __set_errno (ENOENT); ++ return -1; ++ } + } + + dlen = strlen (dir); + while (dlen > 1 && dir[dlen - 1] == '/') +- dlen--; /* remove trailing slashes */ ++ dlen--; /* remove trailing slashes */ + + /* check we have room for "${dir}/${pfx}XXXXXX\0" */ + if (tmpl_len < dlen + 1 + plen + 6 + 1) +@@ -163,39 +165,91 @@ __path_search (char *tmpl, size_t tmpl_len, const char *dir, const char *pfx, + } + #endif /* _LIBC */ + ++#if _LIBC ++static int try_tempname_len (char *, int, void *, int (*) (char *, void *), ++ size_t); ++#endif ++ ++static int ++try_file (char *tmpl, void *flags) ++{ ++ int *openflags = flags; ++ return __open (tmpl, ++ (*openflags & ~O_ACCMODE) ++ | O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR); ++} ++ ++static int ++try_dir (char *tmpl, void *flags _GL_UNUSED) ++{ ++ return __mkdir (tmpl, S_IRUSR | S_IWUSR | S_IXUSR); ++} ++ ++static int ++try_nocreate (char *tmpl, void *flags _GL_UNUSED) ++{ ++ struct_stat64 st; ++ ++ if (__lstat64 (tmpl, &st) == 0 || errno == EOVERFLOW) ++ __set_errno (EEXIST); ++ return errno == ENOENT ? 0 : -1; ++} ++ + /* These are the characters used in temporary file names. */ + static const char letters[] = + "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; + + /* Generate a temporary file name based on TMPL. TMPL must match the +- rules for mk[s]temp (i.e. end in "XXXXXX", possibly with a suffix). ++ rules for mk[s]temp (i.e., end in at least X_SUFFIX_LEN "X"s, ++ possibly with a suffix). + The name constructed does not exist at the time of the call to +- __gen_tempname. TMPL is overwritten with the result. ++ this function. TMPL is overwritten with the result. + + KIND may be one of: +- __GT_NOCREATE: simply verify that the name does not exist +- at the time of the call. +- __GT_FILE: create the file using open(O_CREAT|O_EXCL) +- and return a read-write fd. The file is mode 0600. +- __GT_DIR: create a directory, which will be mode 0700. ++ __GT_NOCREATE: simply verify that the name does not exist ++ at the time of the call. ++ __GT_FILE: create the file using open(O_CREAT|O_EXCL) ++ and return a read-write fd. The file is mode 0600. ++ __GT_DIR: create a directory, which will be mode 0700. + + We use a clever algorithm to get hard-to-predict names. */ ++#ifdef _LIBC ++static ++#endif + int +-__gen_tempname (char *tmpl, int suffixlen, int flags, int kind) ++gen_tempname_len (char *tmpl, int suffixlen, int flags, int kind, ++ size_t x_suffix_len) + { +- int len; ++ static int (*const tryfunc[]) (char *, void *) = ++ { ++ [__GT_FILE] = try_file, ++ [__GT_DIR] = try_dir, ++ [__GT_NOCREATE] = try_nocreate ++ }; ++ return try_tempname_len (tmpl, suffixlen, &flags, tryfunc[kind], ++ x_suffix_len); ++} ++ ++#ifdef _LIBC ++static ++#endif ++int ++try_tempname_len (char *tmpl, int suffixlen, void *args, ++ int (*tryfunc) (char *, void *), size_t x_suffix_len) ++{ ++ size_t len; + char *XXXXXX; + unsigned int count; + int fd = -1; + int save_errno = errno; +- struct_stat64 st; + + /* A lower bound on the number of temporary files to attempt to + generate. The maximum total number of temporary file names that + can exist for a given template is 62**6. It should never be + necessary to try all of these combinations. Instead if a reasonable + number of names is tried (we define reasonable as 62**3) fail to +- give the system administrator the chance to remove the problems. */ ++ give the system administrator the chance to remove the problems. ++ This value requires that X_SUFFIX_LEN be at least 3. */ + #define ATTEMPTS_MIN (62 * 62 * 62) + + /* The number of times to attempt to generate a temporary file. To +@@ -206,82 +260,75 @@ __gen_tempname (char *tmpl, int suffixlen, int flags, int kind) + unsigned int attempts = ATTEMPTS_MIN; + #endif + ++ /* A random variable. The initial value is used only the for fallback path ++ on 'random_bits' on 'getrandom' failure. Its initial value tries to use ++ some entropy from the ASLR and ignore possible bits from the stack ++ alignment. */ ++ random_value v = ((uintptr_t) &v) / alignof (max_align_t); ++ ++ /* How many random base-62 digits can currently be extracted from V. */ ++ int vdigits = 0; ++ ++ /* Least unfair value for V. If V is less than this, V can generate ++ BASE_62_DIGITS digits fairly. Otherwise it might be biased. */ ++ random_value const unfair_min ++ = RANDOM_VALUE_MAX - RANDOM_VALUE_MAX % BASE_62_POWER; ++ + len = strlen (tmpl); +- if (len < 6 + suffixlen || memcmp (&tmpl[len - 6 - suffixlen], "XXXXXX", 6)) ++ if (len < x_suffix_len + suffixlen ++ || strspn (&tmpl[len - x_suffix_len - suffixlen], "X") < x_suffix_len) + { + __set_errno (EINVAL); + return -1; + } + + /* This is where the Xs start. */ +- XXXXXX = &tmpl[len - 6 - suffixlen]; ++ XXXXXX = &tmpl[len - x_suffix_len - suffixlen]; + +- uint64_t pid = (uint64_t) __getpid () << 32; + for (count = 0; count < attempts; ++count) + { +- uint64_t v; +- /* Get some more or less random data. */ +- RANDOM_BITS (v); +- v ^= pid; +- +- /* Fill in the random bits. */ +- XXXXXX[0] = letters[v % 62]; +- v /= 62; +- XXXXXX[1] = letters[v % 62]; +- v /= 62; +- XXXXXX[2] = letters[v % 62]; +- v /= 62; +- XXXXXX[3] = letters[v % 62]; +- v /= 62; +- XXXXXX[4] = letters[v % 62]; +- v /= 62; +- XXXXXX[5] = letters[v % 62]; +- +- switch (kind) +- { +- case __GT_FILE: +- fd = __open (tmpl, +- (flags & ~O_ACCMODE) +- | O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR); +- break; +- +- case __GT_DIR: +- fd = __mkdir (tmpl, S_IRUSR | S_IWUSR | S_IXUSR); +- break; +- +- case __GT_NOCREATE: +- /* This case is backward from the other three. __gen_tempname +- succeeds if lstat fails because the name does not exist. +- Note the continue to bypass the common logic at the bottom +- of the loop. */ +- if (__lstat64 (tmpl, &st) < 0) +- { +- if (errno == ENOENT) +- { +- __set_errno (save_errno); +- return 0; +- } +- else +- /* Give up now. */ +- return -1; +- } +- continue; +- +- default: +- assert (! "invalid KIND in __gen_tempname"); +- abort (); +- } +- ++ for (size_t i = 0; i < x_suffix_len; i++) ++ { ++ if (vdigits == 0) ++ { ++ do ++ v = random_bits (v); ++ while (unfair_min <= v); ++ ++ vdigits = BASE_62_DIGITS; ++ } ++ ++ XXXXXX[i] = letters[v % 62]; ++ v /= 62; ++ vdigits--; ++ } ++ ++ fd = tryfunc (tmpl, args); + if (fd >= 0) +- { +- __set_errno (save_errno); +- return fd; +- } ++ { ++ __set_errno (save_errno); ++ return fd; ++ } + else if (errno != EEXIST) +- return -1; ++ return -1; + } + + /* We got out of the loop because we ran out of combinations to try. */ + __set_errno (EEXIST); + return -1; + } ++ ++int ++__gen_tempname (char *tmpl, int suffixlen, int flags, int kind) ++{ ++ return gen_tempname_len (tmpl, suffixlen, flags, kind, 6); ++} ++ ++#if !_LIBC ++int ++try_tempname (char *tmpl, int suffixlen, void *args, ++ int (*tryfunc) (char *, void *)) ++{ ++ return try_tempname_len (tmpl, suffixlen, args, tryfunc, 6); ++} ++#endif diff --git a/SOURCES/glibc-rh2089247-5.patch b/SOURCES/glibc-rh2089247-5.patch new file mode 100644 index 0000000..ba26b89 --- /dev/null +++ b/SOURCES/glibc-rh2089247-5.patch @@ -0,0 +1,17 @@ +Downstream-only patch to use non-time64 identifiers in +sysdeps/posix/tempname.c. Upstream has switched to the time64 +symbols. + +diff --git a/sysdeps/posix/tempname.c b/sysdeps/posix/tempname.c +index f199b25a7a227751..fcab9b26364021e4 100644 +--- a/sysdeps/posix/tempname.c ++++ b/sysdeps/posix/tempname.c +@@ -56,6 +56,8 @@ + #if _LIBC + # define struct_stat64 struct stat64 + # define __secure_getenv __libc_secure_getenv ++# define __clock_gettime64 __clock_gettime ++# define __timespec64 timespec + #else + # define struct_stat64 struct stat + # define __gen_tempname gen_tempname diff --git a/SOURCES/glibc-rh2089247-6.patch b/SOURCES/glibc-rh2089247-6.patch new file mode 100644 index 0000000..713b457 --- /dev/null +++ b/SOURCES/glibc-rh2089247-6.patch @@ -0,0 +1,66 @@ +commit f430293d842031f2afc3013f156e1018065e480e +Author: Adhemerval Zanella +Date: Tue Jan 12 09:17:09 2021 -0300 + + posix: consume less entropy on tempname + + The first getrandom is used only for __GT_NOCREATE, which is inherently + insecure and can use the entropy as a small improvement. On the + second and later attempts it might help against DoS attacks. + + It sync with gnulib commit 854fbb81d91f7a0f2b463e7ace2499dee2f380f2. + + Checked on x86_64-linux-gnu. + +diff --git a/sysdeps/posix/tempname.c b/sysdeps/posix/tempname.c +index fcab9b26364021e4..3435c4bf75a01f42 100644 +--- a/sysdeps/posix/tempname.c ++++ b/sysdeps/posix/tempname.c +@@ -22,6 +22,7 @@ + + #include + #include ++#include + + #include + +@@ -79,11 +80,11 @@ typedef uint_fast64_t random_value; + #define BASE_62_POWER (62LL * 62 * 62 * 62 * 62 * 62 * 62 * 62 * 62 * 62) + + static random_value +-random_bits (random_value var) ++random_bits (random_value var, bool use_getrandom) + { + random_value r; + /* Without GRND_NONBLOCK it can be blocked for minutes on some systems. */ +- if (__getrandom (&r, sizeof r, GRND_NONBLOCK) == sizeof r) ++ if (use_getrandom && __getrandom (&r, sizeof r, GRND_NONBLOCK) == sizeof r) + return r; + #if _LIBC || (defined CLOCK_MONOTONIC && HAVE_CLOCK_GETTIME) + /* Add entropy if getrandom did not work. */ +@@ -271,6 +272,13 @@ try_tempname_len (char *tmpl, int suffixlen, void *args, + /* How many random base-62 digits can currently be extracted from V. */ + int vdigits = 0; + ++ /* Whether to consume entropy when acquiring random bits. On the ++ first try it's worth the entropy cost with __GT_NOCREATE, which ++ is inherently insecure and can use the entropy to make it a bit ++ less secure. On the (rare) second and later attempts it might ++ help against DoS attacks. */ ++ bool use_getrandom = tryfunc == try_nocreate; ++ + /* Least unfair value for V. If V is less than this, V can generate + BASE_62_DIGITS digits fairly. Otherwise it might be biased. */ + random_value const unfair_min +@@ -294,7 +302,10 @@ try_tempname_len (char *tmpl, int suffixlen, void *args, + if (vdigits == 0) + { + do +- v = random_bits (v); ++ { ++ v = random_bits (v, use_getrandom); ++ use_getrandom = true; ++ } + while (unfair_min <= v); + + vdigits = BASE_62_DIGITS; diff --git a/SOURCES/glibc-rh2091553.patch b/SOURCES/glibc-rh2091553.patch new file mode 100644 index 0000000..376eb48 --- /dev/null +++ b/SOURCES/glibc-rh2091553.patch @@ -0,0 +1,41 @@ +From 82c7441f04e3c2a653ee29672731e040a1799c6b Mon Sep 17 00:00:00 2001 +From: Matheus Castanho +Date: Tue, 7 Jun 2022 10:27:26 -0300 +Subject: powerpc: Fix VSX register number on __strncpy_power9 [BZ #29197] + +__strncpy_power9 initializes VR 18 with zeroes to be used throughout the +code, including when zero-padding the destination string. However, the +v18 reference was mistakenly being used for stxv and stxvl, which take a +VSX vector as operand. The code ended up using the uninitialized VSR 18 +register by mistake. + +Both occurrences have been changed to use the proper VSX number for VR 18 +(i.e. VSR 50). + +Tested on powerpc, powerpc64 and powerpc64le. + +Signed-off-by: Kewen Lin +(cherry picked from commit 0218463dd8265ed937622f88ac68c7d984fe0cfc) + +diff --git a/sysdeps/powerpc/powerpc64/le/power9/strncpy.S b/sysdeps/powerpc/powerpc64/le/power9/strncpy.S +index 291941c1e5..5421525ace 100644 +--- a/sysdeps/powerpc/powerpc64/le/power9/strncpy.S ++++ b/sysdeps/powerpc/powerpc64/le/power9/strncpy.S +@@ -352,7 +352,7 @@ L(zero_padding_loop): + cmpldi cr6,r5,16 /* Check if length was reached. */ + ble cr6,L(zero_padding_end) + +- stxv v18,0(r11) ++ stxv 32+v18,0(r11) + addi r11,r11,16 + addi r5,r5,-16 + +@@ -360,7 +360,7 @@ L(zero_padding_loop): + + L(zero_padding_end): + sldi r10,r5,56 /* stxvl wants size in top 8 bits */ +- stxvl v18,r11,r10 /* Partial store */ ++ stxvl 32+v18,r11,r10 /* Partial store */ + blr + + .align 4 diff --git a/SOURCES/glibc-rh2096189-1.patch b/SOURCES/glibc-rh2096189-1.patch new file mode 100644 index 0000000..33cc310 --- /dev/null +++ b/SOURCES/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/SOURCES/glibc-rh2096189-2.patch b/SOURCES/glibc-rh2096189-2.patch new file mode 100644 index 0000000..201f089 --- /dev/null +++ b/SOURCES/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/SOURCES/glibc-rh2096189-3.patch b/SOURCES/glibc-rh2096189-3.patch new file mode 100644 index 0000000..604afa4 --- /dev/null +++ b/SOURCES/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/SOURCES/glibc-rh2104907.patch b/SOURCES/glibc-rh2104907.patch new file mode 100644 index 0000000..3a65f18 --- /dev/null +++ b/SOURCES/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/SOURCES/glibc-rh2109510-1.patch b/SOURCES/glibc-rh2109510-1.patch new file mode 100644 index 0000000..52b069e --- /dev/null +++ b/SOURCES/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/SOURCES/glibc-rh2109510-10.patch b/SOURCES/glibc-rh2109510-10.patch new file mode 100644 index 0000000..31291df --- /dev/null +++ b/SOURCES/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/SOURCES/glibc-rh2109510-11.patch b/SOURCES/glibc-rh2109510-11.patch new file mode 100644 index 0000000..c7e08fc --- /dev/null +++ b/SOURCES/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/SOURCES/glibc-rh2109510-12.patch b/SOURCES/glibc-rh2109510-12.patch new file mode 100644 index 0000000..a580b1b --- /dev/null +++ b/SOURCES/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/SOURCES/glibc-rh2109510-13.patch b/SOURCES/glibc-rh2109510-13.patch new file mode 100644 index 0000000..8589a81 --- /dev/null +++ b/SOURCES/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/SOURCES/glibc-rh2109510-14.patch b/SOURCES/glibc-rh2109510-14.patch new file mode 100644 index 0000000..9448450 --- /dev/null +++ b/SOURCES/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/SOURCES/glibc-rh2109510-15.patch b/SOURCES/glibc-rh2109510-15.patch new file mode 100644 index 0000000..7979be8 --- /dev/null +++ b/SOURCES/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/SOURCES/glibc-rh2109510-16.patch b/SOURCES/glibc-rh2109510-16.patch new file mode 100644 index 0000000..38416a0 --- /dev/null +++ b/SOURCES/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/SOURCES/glibc-rh2109510-17.patch b/SOURCES/glibc-rh2109510-17.patch new file mode 100644 index 0000000..a7e5a3a --- /dev/null +++ b/SOURCES/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/SOURCES/glibc-rh2109510-18.patch b/SOURCES/glibc-rh2109510-18.patch new file mode 100644 index 0000000..83172fa --- /dev/null +++ b/SOURCES/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/SOURCES/glibc-rh2109510-19.patch b/SOURCES/glibc-rh2109510-19.patch new file mode 100644 index 0000000..f77b415 --- /dev/null +++ b/SOURCES/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/SOURCES/glibc-rh2109510-2.patch b/SOURCES/glibc-rh2109510-2.patch new file mode 100644 index 0000000..3aba395 --- /dev/null +++ b/SOURCES/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/SOURCES/glibc-rh2109510-20.patch b/SOURCES/glibc-rh2109510-20.patch new file mode 100644 index 0000000..1007e9d --- /dev/null +++ b/SOURCES/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/SOURCES/glibc-rh2109510-21.patch b/SOURCES/glibc-rh2109510-21.patch new file mode 100644 index 0000000..5e58123 --- /dev/null +++ b/SOURCES/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/SOURCES/glibc-rh2109510-22.patch b/SOURCES/glibc-rh2109510-22.patch new file mode 100644 index 0000000..e87b99f --- /dev/null +++ b/SOURCES/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/SOURCES/glibc-rh2109510-23.patch b/SOURCES/glibc-rh2109510-23.patch new file mode 100644 index 0000000..7823014 --- /dev/null +++ b/SOURCES/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/SOURCES/glibc-rh2109510-3.patch b/SOURCES/glibc-rh2109510-3.patch new file mode 100644 index 0000000..59496a7 --- /dev/null +++ b/SOURCES/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/SOURCES/glibc-rh2109510-4.patch b/SOURCES/glibc-rh2109510-4.patch new file mode 100644 index 0000000..a56943a --- /dev/null +++ b/SOURCES/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/SOURCES/glibc-rh2109510-5.patch b/SOURCES/glibc-rh2109510-5.patch new file mode 100644 index 0000000..3e93b78 --- /dev/null +++ b/SOURCES/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/SOURCES/glibc-rh2109510-6.patch b/SOURCES/glibc-rh2109510-6.patch new file mode 100644 index 0000000..61251dc --- /dev/null +++ b/SOURCES/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/SOURCES/glibc-rh2109510-7.patch b/SOURCES/glibc-rh2109510-7.patch new file mode 100644 index 0000000..3da8337 --- /dev/null +++ b/SOURCES/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/SOURCES/glibc-rh2109510-8.patch b/SOURCES/glibc-rh2109510-8.patch new file mode 100644 index 0000000..120abed --- /dev/null +++ b/SOURCES/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/SOURCES/glibc-rh2109510-9.patch b/SOURCES/glibc-rh2109510-9.patch new file mode 100644 index 0000000..289f6df --- /dev/null +++ b/SOURCES/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/SOURCES/glibc-rh2116938.patch b/SOURCES/glibc-rh2116938.patch new file mode 100644 index 0000000..f642aba --- /dev/null +++ b/SOURCES/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/SOURCES/glibc-rh2118667.patch b/SOURCES/glibc-rh2118667.patch new file mode 100644 index 0000000..64f2bcc --- /dev/null +++ b/SOURCES/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/SOURCES/glibc-rh2119304-1.patch b/SOURCES/glibc-rh2119304-1.patch new file mode 100644 index 0000000..a76e1bf --- /dev/null +++ b/SOURCES/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/SOURCES/glibc-rh2119304-2.patch b/SOURCES/glibc-rh2119304-2.patch new file mode 100644 index 0000000..a1e121b --- /dev/null +++ b/SOURCES/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/SOURCES/glibc-rh2119304-3.patch b/SOURCES/glibc-rh2119304-3.patch new file mode 100644 index 0000000..faaea99 --- /dev/null +++ b/SOURCES/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/SOURCES/glibc-rh2121746-1.patch b/SOURCES/glibc-rh2121746-1.patch new file mode 100644 index 0000000..a27c0eb --- /dev/null +++ b/SOURCES/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/SOURCES/glibc-rh2121746-2.patch b/SOURCES/glibc-rh2121746-2.patch new file mode 100644 index 0000000..5bd43c8 --- /dev/null +++ b/SOURCES/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/SOURCES/glibc-rh2122498.patch b/SOURCES/glibc-rh2122498.patch new file mode 100644 index 0000000..1699abf --- /dev/null +++ b/SOURCES/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/SOURCES/glibc-rh2122501-1.patch b/SOURCES/glibc-rh2122501-1.patch new file mode 100644 index 0000000..75d333e --- /dev/null +++ b/SOURCES/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/SOURCES/glibc-rh2122501-2.patch b/SOURCES/glibc-rh2122501-2.patch new file mode 100644 index 0000000..8cac488 --- /dev/null +++ b/SOURCES/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/SOURCES/glibc-rh2122501-3.patch b/SOURCES/glibc-rh2122501-3.patch new file mode 100644 index 0000000..331dd92 --- /dev/null +++ b/SOURCES/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/SOURCES/glibc-rh2122501-4.patch b/SOURCES/glibc-rh2122501-4.patch new file mode 100644 index 0000000..97436f4 --- /dev/null +++ b/SOURCES/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/SOURCES/glibc-rh2122501-5.patch b/SOURCES/glibc-rh2122501-5.patch new file mode 100644 index 0000000..f088e5f --- /dev/null +++ b/SOURCES/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/SOURCES/glibc-rh2125222.patch b/SOURCES/glibc-rh2125222.patch new file mode 100644 index 0000000..7ee14f4 --- /dev/null +++ b/SOURCES/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/SOURCES/glibc-rh2139875-1.patch b/SOURCES/glibc-rh2139875-1.patch new file mode 100644 index 0000000..32091ab --- /dev/null +++ b/SOURCES/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/SOURCES/glibc-rh2139875-2.patch b/SOURCES/glibc-rh2139875-2.patch new file mode 100644 index 0000000..1c3ac5b --- /dev/null +++ b/SOURCES/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/SOURCES/glibc-rh2139875-3.patch b/SOURCES/glibc-rh2139875-3.patch new file mode 100644 index 0000000..6c48115 --- /dev/null +++ b/SOURCES/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/SOURCES/glibc-rh2141989.patch b/SOURCES/glibc-rh2141989.patch new file mode 100644 index 0000000..70ab8e4 --- /dev/null +++ b/SOURCES/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/SOURCES/glibc-rh2142937-1.patch b/SOURCES/glibc-rh2142937-1.patch new file mode 100644 index 0000000..c9279a7 --- /dev/null +++ b/SOURCES/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/SOURCES/glibc-rh2142937-2.patch b/SOURCES/glibc-rh2142937-2.patch new file mode 100644 index 0000000..e9102b6 --- /dev/null +++ b/SOURCES/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/SOURCES/glibc-rh2142937-3.patch b/SOURCES/glibc-rh2142937-3.patch new file mode 100644 index 0000000..a61dfde --- /dev/null +++ b/SOURCES/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/SOURCES/glibc-rh2144568.patch b/SOURCES/glibc-rh2144568.patch new file mode 100644 index 0000000..82f86ad --- /dev/null +++ b/SOURCES/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/SOURCES/glibc-rh2154914-1.patch b/SOURCES/glibc-rh2154914-1.patch new file mode 100644 index 0000000..3eafe16 --- /dev/null +++ b/SOURCES/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/SOURCES/glibc-rh2154914-2.patch b/SOURCES/glibc-rh2154914-2.patch new file mode 100644 index 0000000..4c89744 --- /dev/null +++ b/SOURCES/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/SOURCES/glibc-rh2172949.patch b/SOURCES/glibc-rh2172949.patch new file mode 100644 index 0000000..8ce2592 --- /dev/null +++ b/SOURCES/glibc-rh2172949.patch @@ -0,0 +1,121 @@ +commit 969e9733c7d17edf1e239a73fa172f357561f440 +Author: Florian Weimer +Date: Tue Feb 21 09:20:28 2023 +0100 + + gshadow: Matching sgetsgent, sgetsgent_r ERANGE handling (bug 30151) + + Before this change, sgetsgent_r did not set errno to ERANGE, but + sgetsgent only check errno, not the return value from sgetsgent_r. + Consequently, sgetsgent did not detect any error, and reported + success to the caller, without initializing the struct sgrp object + whose address was returned. + + This commit changes sgetsgent_r to set errno as well. This avoids + similar issues in applications which only change errno. + + Reviewed-by: Siddhesh Poyarekar + +diff --git a/gshadow/Makefile b/gshadow/Makefile +index 796fbbf473..a95524593a 100644 +--- a/gshadow/Makefile ++++ b/gshadow/Makefile +@@ -26,7 +26,7 @@ headers = gshadow.h + routines = getsgent getsgnam sgetsgent fgetsgent putsgent \ + getsgent_r getsgnam_r sgetsgent_r fgetsgent_r + +-tests = tst-gshadow tst-putsgent tst-fgetsgent_r ++tests = tst-gshadow tst-putsgent tst-fgetsgent_r tst-sgetsgent + + CFLAGS-getsgent_r.c += -fexceptions + CFLAGS-getsgent.c += -fexceptions +diff --git a/gshadow/sgetsgent_r.c b/gshadow/sgetsgent_r.c +index ea085e91d7..c75624e1f7 100644 +--- a/gshadow/sgetsgent_r.c ++++ b/gshadow/sgetsgent_r.c +@@ -61,7 +61,10 @@ __sgetsgent_r (const char *string, struct sgrp *resbuf, char *buffer, + buffer[buflen - 1] = '\0'; + sp = strncpy (buffer, string, buflen); + if (buffer[buflen - 1] != '\0') +- return ERANGE; ++ { ++ __set_errno (ERANGE); ++ return ERANGE; ++ } + } + else + sp = (char *) string; +diff --git a/gshadow/tst-sgetsgent.c b/gshadow/tst-sgetsgent.c +new file mode 100644 +index 0000000000..0370c10fd0 +--- /dev/null ++++ b/gshadow/tst-sgetsgent.c +@@ -0,0 +1,69 @@ ++/* Test large input for sgetsgent (bug 30151). ++ Copyright (C) 2023 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++static int ++do_test (void) ++{ ++ /* Create a shadow group with 1000 members. */ ++ struct xmemstream mem; ++ xopen_memstream (&mem); ++ const char *passwd = "k+zD0nucwfxAo3sw1NXUj6K5vt5M16+X0TVGdE1uFvq5R8V7efJ"; ++ fprintf (mem.out, "group-name:%s::m0", passwd); ++ for (int i = 1; i < 1000; ++i) ++ fprintf (mem.out, ",m%d", i); ++ xfclose_memstream (&mem); ++ ++ /* Call sgetsgent. */ ++ char *input = mem.buffer; ++ struct sgrp *e = sgetsgent (input); ++ TEST_VERIFY_EXIT (e != NULL); ++ TEST_COMPARE_STRING (e->sg_namp, "group-name"); ++ TEST_COMPARE_STRING (e->sg_passwd, passwd); ++ /* No administrators. */ ++ TEST_COMPARE_STRING (e->sg_adm[0], NULL); ++ /* Check the members list. */ ++ for (int i = 0; i < 1000; ++i) ++ { ++ char *member = xasprintf ("m%d", i); ++ TEST_COMPARE_STRING (e->sg_mem[i], member); ++ free (member); ++ } ++ TEST_COMPARE_STRING (e->sg_mem[1000], NULL); ++ ++ /* Check that putsgent brings back the input string. */ ++ xopen_memstream (&mem); ++ TEST_COMPARE (putsgent (e, mem.out), 0); ++ xfclose_memstream (&mem); ++ /* Compare without the trailing '\n' that putsgent added. */ ++ TEST_COMPARE (mem.buffer[mem.length - 1], '\n'); ++ mem.buffer[mem.length - 1] = '\0'; ++ TEST_COMPARE_STRING (mem.buffer, input); ++ ++ free (mem.buffer); ++ free (input); ++ return 0; ++} ++ ++#include diff --git a/SOURCES/glibc-rh2176707-1.patch b/SOURCES/glibc-rh2176707-1.patch new file mode 100644 index 0000000..6d17d83 --- /dev/null +++ b/SOURCES/glibc-rh2176707-1.patch @@ -0,0 +1,144 @@ +From 436a604b7dc741fc76b5a6704c6cd8bb178518e7 Mon Sep 17 00:00:00 2001 +From: Adam Yi +Date: Tue, 7 Mar 2023 07:30:02 -0500 +Subject: posix: Fix system blocks SIGCHLD erroneously [BZ #30163] + +Fix bug that SIGCHLD is erroneously blocked forever in the following +scenario: + +1. Thread A calls system but hasn't returned yet +2. Thread B calls another system but returns + +SIGCHLD would be blocked forever in thread B after its system() returns, +even after the system() in thread A returns. + +Although POSIX does not require, glibc system implementation aims to be +thread and cancellation safe. This bug was introduced in +5fb7fc96350575c9adb1316833e48ca11553be49 when we moved reverting signal +mask to happen when the last concurrently running system returns, +despite that signal mask is per thread. This commit reverts this logic +and adds a test. + +Signed-off-by: Adam Yi +Reviewed-by: Adhemerval Zanella + +[DJ: Edited to use integer sleep() instead of nanosleep() dependency rabbit hole] +diff --git a/stdlib/tst-system.c b/stdlib/tst-system.c +index 634acfe264..47a0afe6bf 100644 +--- a/stdlib/tst-system.c ++++ b/stdlib/tst-system.c +@@ -25,6 +25,7 @@ + #include + #include + #include ++#include + #include + + static char *tmpdir; +@@ -71,6 +72,20 @@ call_system (void *closure) + } + } + ++static void * ++sleep_and_check_sigchld (void *closure) ++{ ++ double *seconds = (double *) closure; ++ char cmd[namemax]; ++ sprintf (cmd, "sleep %lf" , *seconds); ++ TEST_COMPARE (system (cmd), 0); ++ ++ sigset_t blocked = {0}; ++ TEST_COMPARE (sigprocmask (SIG_BLOCK, NULL, &blocked), 0); ++ TEST_COMPARE (sigismember (&blocked, SIGCHLD), 0); ++ return NULL; ++} ++ + static int + do_test (void) + { +@@ -154,6 +169,17 @@ do_test (void) + xchmod (_PATH_BSHELL, st.st_mode); + } + ++ { ++ pthread_t long_sleep_thread = xpthread_create (NULL, ++ sleep_and_check_sigchld, ++ &(double) { 2 }); ++ pthread_t short_sleep_thread = xpthread_create (NULL, ++ sleep_and_check_sigchld, ++ &(double) { 1 }); ++ xpthread_join (short_sleep_thread); ++ xpthread_join (long_sleep_thread); ++ } ++ + TEST_COMPARE (system (""), 0); + + return 0; +diff --git a/support/shell-container.c b/support/shell-container.c +index ffa3378b5e..b1f9e793c1 100644 +--- a/support/shell-container.c ++++ b/support/shell-container.c +@@ -169,6 +170,31 @@ kill_func (char **argv) + return 0; + } + ++/* Emulate the "/bin/sleep" command. No suffix support. Options are ++ ignored. */ ++static int ++sleep_func (char **argv) ++{ ++ if (argv[0] == NULL) ++ { ++ fprintf (stderr, "sleep: missing operand\n"); ++ return 1; ++ } ++ char *endptr = NULL; ++ long sec = strtol (argv[0], &endptr, 0); ++ if (endptr == argv[0] || errno == ERANGE || sec < 0) ++ { ++ fprintf (stderr, "sleep: invalid time interval '%s'\n", argv[0]); ++ return 1; ++ } ++ if (sleep (sec) < 0) ++ { ++ fprintf (stderr, "sleep: failed to nanosleep\n"); ++ return 1; ++ } ++ return 0; ++} ++ + /* This is a list of all the built-in commands we understand. */ + static struct { + const char *name; +@@ -179,6 +206,7 @@ static struct { + { "cp", copy_func }, + { "exit", exit_func }, + { "kill", kill_func }, ++ { "sleep", sleep_func }, + { NULL, NULL } + }; + +diff --git a/sysdeps/posix/system.c b/sysdeps/posix/system.c +index 2335a99184..d77720a625 100644 +--- a/sysdeps/posix/system.c ++++ b/sysdeps/posix/system.c +@@ -179,16 +179,16 @@ do_system (const char *line) + as if the shell had terminated using _exit(127). */ + status = W_EXITCODE (127, 0); + ++ /* sigaction can not fail with SIGINT/SIGQUIT used with old ++ disposition. Same applies for sigprocmask. */ + DO_LOCK (); + if (SUB_REF () == 0) + { +- /* sigaction can not fail with SIGINT/SIGQUIT used with old +- disposition. Same applies for sigprocmask. */ + __sigaction (SIGINT, &intr, NULL); + __sigaction (SIGQUIT, &quit, NULL); +- __sigprocmask (SIG_SETMASK, &omask, NULL); + } + DO_UNLOCK (); ++ __sigprocmask (SIG_SETMASK, &omask, NULL); + + if (ret != 0) + __set_errno (ret); diff --git a/SOURCES/glibc-rh2176707-2.patch b/SOURCES/glibc-rh2176707-2.patch new file mode 100644 index 0000000..3968fc7 --- /dev/null +++ b/SOURCES/glibc-rh2176707-2.patch @@ -0,0 +1,27 @@ +From d03094649d39949a30513bf3ffb03a28fecbccd8 Mon Sep 17 00:00:00 2001 +From: Adam Yi +Date: Wed, 8 Mar 2023 03:11:47 -0500 +Subject: hurd: fix build of tst-system.c + +We made tst-system.c depend on pthread, but that requires linking with +$(shared-thread-library). It does not fail under Linux because the +variable expands to nothing under Linux, but it fails for Hurd. + +I tested verified via cross-compiling that "make check" now works +for Hurd. + +Signed-off-by: Adam Yi +Reviewed-by: Adhemerval Zanella + +[DJ: Edited for RHEL 8] +diff -rup a/stdlib/Makefile b/stdlib/Makefile +--- a/stdlib/Makefile 2023-07-07 00:44:55.810981644 -0400 ++++ b/stdlib/Makefile 2023-07-07 00:46:47.541411091 -0400 +@@ -102,6 +102,7 @@ LDLIBS-test-atexit-race = $(shared-threa + LDLIBS-test-at_quick_exit-race = $(shared-thread-library) + LDLIBS-test-cxa_atexit-race = $(shared-thread-library) + LDLIBS-test-on_exit-race = $(shared-thread-library) ++LDLIBS-tst-system = $(shared-thread-library) + + LDLIBS-test-dlclose-exit-race = $(shared-thread-library) $(libdl) + LDFLAGS-test-dlclose-exit-race = $(LDFLAGS-rdynamic) diff --git a/SOURCES/glibc-rh2176707-3.patch b/SOURCES/glibc-rh2176707-3.patch new file mode 100644 index 0000000..0131a71 --- /dev/null +++ b/SOURCES/glibc-rh2176707-3.patch @@ -0,0 +1,42 @@ +This patch is a RHEL-only patch which modifies the custom changes +in the previous patches in this series to make the test case look +more like the upstream test case. + +diff -rup a/stdlib/tst-system.c b/stdlib/tst-system.c +--- a/stdlib/tst-system.c 2023-07-10 13:37:53.089505036 -0400 ++++ b/stdlib/tst-system.c 2023-07-10 14:04:03.922610279 -0400 +@@ -173,10 +173,10 @@ do_test (void) + { + pthread_t long_sleep_thread = xpthread_create (NULL, + sleep_and_check_sigchld, +- &(double) { 2 }); ++ &(double) { 0.2 }); + pthread_t short_sleep_thread = xpthread_create (NULL, + sleep_and_check_sigchld, +- &(double) { 1 }); ++ &(double) { 0.1 }); + xpthread_join (short_sleep_thread); + xpthread_join (long_sleep_thread); + } +diff -rup a/support/shell-container.c b/support/shell-container.c +--- a/support/shell-container.c 2023-07-10 13:37:53.089505036 -0400 ++++ b/support/shell-container.c 2023-07-10 14:03:20.392920627 -0400 +@@ -182,15 +182,15 @@ sleep_func (char **argv) + return 1; + } + char *endptr = NULL; +- long sec = strtol (argv[0], &endptr, 0); ++ double sec = strtod (argv[0], &endptr); + if (endptr == argv[0] || errno == ERANGE || sec < 0) + { + fprintf (stderr, "sleep: invalid time interval '%s'\n", argv[0]); + return 1; + } +- if (sleep (sec) < 0) ++ if (usleep ((useconds_t)(sec * 1000000.0)) < 0) + { +- fprintf (stderr, "sleep: failed to nanosleep\n"); ++ fprintf (stderr, "sleep: failed to usleep: %s\n", strerror (errno)); + return 1; + } + return 0; diff --git a/SOURCES/glibc-rh2180155-1.patch b/SOURCES/glibc-rh2180155-1.patch new file mode 100644 index 0000000..f38a0ec --- /dev/null +++ b/SOURCES/glibc-rh2180155-1.patch @@ -0,0 +1,70 @@ +commit 801af9fafd4689337ebf27260aa115335a0cb2bc +Author: Леонид Юрьев (Leonid Yuriev) +Date: Sat Feb 4 14:41:38 2023 +0300 + + gmon: Fix allocated buffer overflow (bug 29444) + + The `__monstartup()` allocates a buffer used to store all the data + accumulated by the monitor. + + The size of this buffer depends on the size of the internal structures + used and the address range for which the monitor is activated, as well + as on the maximum density of call instructions and/or callable functions + that could be potentially on a segment of executable code. + + In particular a hash table of arcs is placed at the end of this buffer. + The size of this hash table is calculated in bytes as + p->fromssize = p->textsize / HASHFRACTION; + + but actually should be + p->fromssize = ROUNDUP(p->textsize / HASHFRACTION, sizeof(*p->froms)); + + This results in writing beyond the end of the allocated buffer when an + added arc corresponds to a call near from the end of the monitored + address range, since `_mcount()` check the incoming caller address for + monitored range but not the intermediate result hash-like index that + uses to write into the table. + + It should be noted that when the results are output to `gmon.out`, the + table is read to the last element calculated from the allocated size in + bytes, so the arcs stored outside the buffer boundary did not fall into + `gprof` for analysis. Thus this "feature" help me to found this bug + during working with https://sourceware.org/bugzilla/show_bug.cgi?id=29438 + + Just in case, I will explicitly note that the problem breaks the + `make test t=gmon/tst-gmon-dso` added for Bug 29438. + There, the arc of the `f3()` call disappears from the output, since in + the DSO case, the call to `f3` is located close to the end of the + monitored range. + + Signed-off-by: Леонид Юрьев (Leonid Yuriev) + + Another minor error seems a related typo in the calculation of + `kcountsize`, but since kcounts are smaller than froms, this is + actually to align the p->froms data. + + Co-authored-by: DJ Delorie + Reviewed-by: Carlos O'Donell + +diff --git a/gmon/gmon.c b/gmon/gmon.c +index dee64803ada583d7..bf76358d5b1aa2da 100644 +--- a/gmon/gmon.c ++++ b/gmon/gmon.c +@@ -132,6 +132,8 @@ __monstartup (u_long lowpc, u_long highpc) + p->lowpc = ROUNDDOWN(lowpc, HISTFRACTION * sizeof(HISTCOUNTER)); + p->highpc = ROUNDUP(highpc, HISTFRACTION * sizeof(HISTCOUNTER)); + p->textsize = p->highpc - p->lowpc; ++ /* This looks like a typo, but it's here to align the p->froms ++ section. */ + p->kcountsize = ROUNDUP(p->textsize / HISTFRACTION, sizeof(*p->froms)); + p->hashfraction = HASHFRACTION; + p->log_hashfraction = -1; +@@ -142,7 +144,7 @@ __monstartup (u_long lowpc, u_long highpc) + instead of integer division. Precompute shift amount. */ + p->log_hashfraction = ffs(p->hashfraction * sizeof(*p->froms)) - 1; + } +- p->fromssize = p->textsize / HASHFRACTION; ++ p->fromssize = ROUNDUP(p->textsize / HASHFRACTION, sizeof(*p->froms)); + p->tolimit = p->textsize * ARCDENSITY / 100; + if (p->tolimit < MINARCS) + p->tolimit = MINARCS; diff --git a/SOURCES/glibc-rh2180155-2.patch b/SOURCES/glibc-rh2180155-2.patch new file mode 100644 index 0000000..912bc92 --- /dev/null +++ b/SOURCES/glibc-rh2180155-2.patch @@ -0,0 +1,477 @@ +This patch adds the required @order directives to preserve the +GLIBC_PRIVATE ABI. + +commit 31be941e4367c001b2009308839db5c67bf9dcbc +Author: Simon Kissane +Date: Sat Feb 11 20:12:13 2023 +1100 + + gmon: improve mcount overflow handling [BZ# 27576] + + When mcount overflows, no gmon.out file is generated, but no message is printed + to the user, leaving the user with no idea why, and thinking maybe there is + some bug - which is how BZ 27576 ended up being logged. Print a message to + stderr in this case so the user knows what is going on. + + As a comment in sys/gmon.h acknowledges, the hardcoded MAXARCS value is too + small for some large applications, including the test case in that BZ. Rather + than increase it, add tunables to enable MINARCS and MAXARCS to be overridden + at runtime (glibc.gmon.minarcs and glibc.gmon.maxarcs). So if a user gets the + mcount overflow error, they can try increasing maxarcs (they might need to + increase minarcs too if the heuristic is wrong in their case.) + + Note setting minarcs/maxarcs too large can cause monstartup to fail with an + out of memory error. If you set them large enough, it can cause an integer + overflow in calculating the buffer size. I haven't done anything to defend + against that - it would not generally be a security vulnerability, since these + tunables will be ignored in suid/sgid programs (due to the SXID_ERASE default), + and if you can set GLIBC_TUNABLES in the environment of a process, you can take + it over anyway (LD_PRELOAD, LD_LIBRARY_PATH, etc). I thought about modifying + the code of monstartup to defend against integer overflows, but doing so is + complicated, and I realise the existing code is susceptible to them even prior + to this change (e.g. try passing a pathologically large highpc argument to + monstartup), so I decided just to leave that possibility in-place. + + Add a test case which demonstrates mcount overflow and the tunables. + + Document the new tunables in the manual. + + Signed-off-by: Simon Kissane + Reviewed-by: DJ Delorie + +Conflicts: + manual/tunables.texi + (missing tunables downstream) + +diff --git a/elf/dl-tunables.list b/elf/dl-tunables.list +index f11ca5b3e8b09b43..dc2999796042dbaf 100644 +--- a/elf/dl-tunables.list ++++ b/elf/dl-tunables.list +@@ -149,4 +149,17 @@ glibc { + default: 2 + } + } ++ ++ gmon { ++ minarcs { ++ type: INT_32 ++ minval: 50 ++ default: 50 ++ } ++ maxarcs { ++ type: INT_32 ++ minval: 50 ++ default: 1048576 ++ } ++ } + } +diff --git a/gmon/Makefile b/gmon/Makefile +index d94593c9d8a882eb..54f05894d4dd8c4a 100644 +--- a/gmon/Makefile ++++ b/gmon/Makefile +@@ -25,7 +25,7 @@ include ../Makeconfig + headers := sys/gmon.h sys/gmon_out.h sys/profil.h + routines := gmon mcount profil sprofil prof-freq + +-tests = tst-sprofil tst-gmon ++tests = tst-sprofil tst-gmon tst-mcount-overflow + ifeq ($(build-profile),yes) + tests += tst-profile-static + tests-static += tst-profile-static +@@ -56,6 +56,18 @@ ifeq ($(run-built-tests),yes) + tests-special += $(objpfx)tst-gmon-gprof.out + endif + ++CFLAGS-tst-mcount-overflow.c := -fno-omit-frame-pointer -pg ++tst-mcount-overflow-no-pie = yes ++CRT-tst-mcount-overflow := $(csu-objpfx)g$(start-installed-name) ++# Intentionally use invalid config where maxarcs&1 1>/dev/null | cat ++ifeq ($(run-built-tests),yes) ++tests-special += $(objpfx)tst-mcount-overflow-check.out ++endif ++ + CFLAGS-tst-gmon-static.c := $(PIE-ccflag) -fno-omit-frame-pointer -pg + CRT-tst-gmon-static := $(csu-objpfx)gcrt1.o + tst-gmon-static-no-pie = yes +@@ -103,6 +115,14 @@ $(objpfx)tst-gmon.out: clean-tst-gmon-data + clean-tst-gmon-data: + rm -f $(objpfx)tst-gmon.data.* + ++$(objpfx)tst-mcount-overflow.o: clean-tst-mcount-overflow-data ++clean-tst-mcount-overflow-data: ++ rm -f $(objpfx)tst-mcount-overflow.data.* ++ ++$(objpfx)tst-mcount-overflow-check.out: tst-mcount-overflow-check.sh $(objpfx)tst-mcount-overflow.out ++ $(SHELL) $< $(objpfx)tst-mcount-overflow > $@; \ ++ $(evaluate-test) ++ + $(objpfx)tst-gmon-gprof.out: tst-gmon-gprof.sh $(objpfx)tst-gmon.out + $(SHELL) $< $(GPROF) $(objpfx)tst-gmon $(objpfx)tst-gmon.data.* > $@; \ + $(evaluate-test) +diff --git a/gmon/gmon.c b/gmon/gmon.c +index bf76358d5b1aa2da..689bf80141e559ca 100644 +--- a/gmon/gmon.c ++++ b/gmon/gmon.c +@@ -46,6 +46,11 @@ + #include + #include + ++#if HAVE_TUNABLES ++# define TUNABLE_NAMESPACE gmon ++# include ++#endif ++ + #ifdef PIC + # include + +@@ -124,6 +129,22 @@ __monstartup (u_long lowpc, u_long highpc) + int o; + char *cp; + struct gmonparam *p = &_gmonparam; ++ long int minarcs, maxarcs; ++ ++#if HAVE_TUNABLES ++ /* Read minarcs/maxarcs tunables. */ ++ minarcs = TUNABLE_GET (minarcs, int32_t, NULL); ++ maxarcs = TUNABLE_GET (maxarcs, int32_t, NULL); ++ if (maxarcs < minarcs) ++ { ++ ERR("monstartup: maxarcs < minarcs, setting maxarcs = minarcs\n"); ++ maxarcs = minarcs; ++ } ++#else ++ /* No tunables, we use hardcoded defaults */ ++ minarcs = MINARCS; ++ maxarcs = MAXARCS; ++#endif + + /* + * round lowpc and highpc to multiples of the density we're using +@@ -146,10 +167,10 @@ __monstartup (u_long lowpc, u_long highpc) + } + p->fromssize = ROUNDUP(p->textsize / HASHFRACTION, sizeof(*p->froms)); + p->tolimit = p->textsize * ARCDENSITY / 100; +- if (p->tolimit < MINARCS) +- p->tolimit = MINARCS; +- else if (p->tolimit > MAXARCS) +- p->tolimit = MAXARCS; ++ if (p->tolimit < minarcs) ++ p->tolimit = minarcs; ++ else if (p->tolimit > maxarcs) ++ p->tolimit = maxarcs; + p->tossize = p->tolimit * sizeof(struct tostruct); + + cp = calloc (p->kcountsize + p->fromssize + p->tossize, 1); +diff --git a/gmon/mcount.c b/gmon/mcount.c +index 9d4a1a50fa6ab21a..f7180fdb83399a14 100644 +--- a/gmon/mcount.c ++++ b/gmon/mcount.c +@@ -41,6 +41,10 @@ static char sccsid[] = "@(#)mcount.c 8.1 (Berkeley) 6/4/93"; + + #include + ++#include ++#include ++#define ERR(s) __write_nocancel (STDERR_FILENO, s, sizeof (s) - 1) ++ + /* + * mcount is called on entry to each function compiled with the profiling + * switch set. _mcount(), which is declared in a machine-dependent way +@@ -170,6 +174,7 @@ done: + return; + overflow: + p->state = GMON_PROF_ERROR; ++ ERR("mcount: call graph buffer size limit exceeded, gmon.out will not be generated\n"); + return; + } + +diff --git a/gmon/sys/gmon.h b/gmon/sys/gmon.h +index b4cc3b043a2aec77..af0582a3717085b5 100644 +--- a/gmon/sys/gmon.h ++++ b/gmon/sys/gmon.h +@@ -111,6 +111,8 @@ extern struct __bb *__bb_head; + * Always allocate at least this many tostructs. This + * hides the inadequacy of the ARCDENSITY heuristic, at least + * for small programs. ++ * ++ * Value can be overridden at runtime by glibc.gmon.minarcs tunable. + */ + #define MINARCS 50 + +@@ -124,8 +126,8 @@ extern struct __bb *__bb_head; + * Used to be max representable value of ARCINDEX minus 2, but now + * that ARCINDEX is a long, that's too large; we don't really want + * to allow a 48 gigabyte table. +- * The old value of 1<<16 wasn't high enough in practice for large C++ +- * programs; will 1<<20 be adequate for long? FIXME ++ * ++ * Value can be overridden at runtime by glibc.gmon.maxarcs tunable. + */ + #define MAXARCS (1 << 20) + +diff --git a/gmon/tst-mcount-overflow-check.sh b/gmon/tst-mcount-overflow-check.sh +new file mode 100644 +index 0000000000000000..27eb5538fd573a6e +--- /dev/null ++++ b/gmon/tst-mcount-overflow-check.sh +@@ -0,0 +1,45 @@ ++#!/bin/sh ++# Test expected messages generated when mcount overflows ++# Copyright (C) 2017-2023 Free Software Foundation, Inc. ++# Copyright The GNU Toolchain Authors. ++# This file is part of the GNU C Library. ++ ++# The GNU C Library is free software; you can redistribute it and/or ++# modify it under the terms of the GNU Lesser General Public ++# License as published by the Free Software Foundation; either ++# version 2.1 of the License, or (at your option) any later version. ++ ++# The GNU C Library is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++# Lesser General Public License for more details. ++ ++# You should have received a copy of the GNU Lesser General Public ++# License along with the GNU C Library; if not, see ++# . ++ ++LC_ALL=C ++export LC_ALL ++set -e ++exec 2>&1 ++ ++program="$1" ++ ++check_msg() { ++ if ! grep -q "$1" "$program.out"; then ++ echo "FAIL: expected message not in output: $1" ++ exit 1 ++ fi ++} ++ ++check_msg 'monstartup: maxarcs < minarcs, setting maxarcs = minarcs' ++check_msg 'mcount: call graph buffer size limit exceeded, gmon.out will not be generated' ++ ++for data_file in $1.data.*; do ++ if [ -f "$data_file" ]; then ++ echo "FAIL: expected no data files, but found $data_file" ++ exit 1 ++ fi ++done ++ ++echo PASS +diff --git a/gmon/tst-mcount-overflow.c b/gmon/tst-mcount-overflow.c +new file mode 100644 +index 0000000000000000..06cc93ef872eb7c1 +--- /dev/null ++++ b/gmon/tst-mcount-overflow.c +@@ -0,0 +1,72 @@ ++/* Test program to trigger mcount overflow in profiling collection. ++ Copyright (C) 2017-2023 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++/* Program with sufficiently complex, yet pointless, call graph ++ that it will trigger an mcount overflow, when you set the ++ minarcs/maxarcs tunables to very low values. */ ++ ++#define PREVENT_TAIL_CALL asm volatile ("") ++ ++/* Calls REP(n) macro 16 times, for n=0..15. ++ * You need to define REP(n) before using this. ++ */ ++#define REPS \ ++ REP(0) REP(1) REP(2) REP(3) REP(4) REP(5) REP(6) REP(7) \ ++ REP(8) REP(9) REP(10) REP(11) REP(12) REP(13) REP(14) REP(15) ++ ++/* Defines 16 leaf functions named f1_0 to f1_15 */ ++#define REP(n) \ ++ __attribute__ ((noinline, noclone, weak)) void f1_##n (void) {}; ++REPS ++#undef REP ++ ++/* Calls all 16 leaf functions f1_* in succession */ ++__attribute__ ((noinline, noclone, weak)) void ++f2 (void) ++{ ++# define REP(n) f1_##n(); ++ REPS ++# undef REP ++ PREVENT_TAIL_CALL; ++} ++ ++/* Defines 16 functions named f2_0 to f2_15, which all just call f2 */ ++#define REP(n) \ ++ __attribute__ ((noinline, noclone, weak)) void \ ++ f2_##n (void) { f2(); PREVENT_TAIL_CALL; }; ++REPS ++#undef REP ++ ++__attribute__ ((noinline, noclone, weak)) void ++f3 (int count) ++{ ++ for (int i = 0; i < count; ++i) ++ { ++ /* Calls f1_0(), f2_0(), f1_1(), f2_1(), f3_0(), etc */ ++# define REP(n) f1_##n(); f2_##n(); ++ REPS ++# undef REP ++ } ++} ++ ++int ++main (void) ++{ ++ f3 (1000); ++ return 0; ++} +diff --git a/manual/tunables.texi b/manual/tunables.texi +index 7b70e80391ee87f7..00eafcf44b562b9e 100644 +--- a/manual/tunables.texi ++++ b/manual/tunables.texi +@@ -73,6 +73,9 @@ glibc.malloc.check: 0 (min: 0, max: 3) + * Elision Tunables:: Tunables in elision subsystem + * Hardware Capability Tunables:: Tunables that modify the hardware + capabilities seen by @theglibc{} ++* gmon Tunables:: Tunables that control the gmon profiler, used in ++ conjunction with gprof ++ + @end menu + + @node Tunable names +@@ -506,3 +509,59 @@ instead. + + This tunable is specific to i386 and x86-64. + @end deftp ++ ++@node gmon Tunables ++@section gmon Tunables ++@cindex gmon tunables ++ ++@deftp {Tunable namespace} glibc.gmon ++This tunable namespace affects the behaviour of the gmon profiler. ++gmon is a component of @theglibc{} which is normally used in ++conjunction with gprof. ++ ++When GCC compiles a program with the @code{-pg} option, it instruments ++the program with calls to the @code{mcount} function, to record the ++program's call graph. At program startup, a memory buffer is allocated ++to store this call graph; the size of the buffer is calculated using a ++heuristic based on code size. If during execution, the buffer is found ++to be too small, profiling will be aborted and no @file{gmon.out} file ++will be produced. In that case, you will see the following message ++printed to standard error: ++ ++@example ++mcount: call graph buffer size limit exceeded, gmon.out will not be generated ++@end example ++ ++Most of the symbols discussed in this section are defined in the header ++@code{sys/gmon.h}. However, some symbols (for example @code{mcount}) ++are not defined in any header file, since they are only intended to be ++called from code generated by the compiler. ++@end deftp ++ ++@deftp Tunable glibc.mem.minarcs ++The heuristic for sizing the call graph buffer is known to be ++insufficient for small programs; hence, the calculated value is clamped ++to be at least a minimum size. The default minimum (in units of ++call graph entries, @code{struct tostruct}), is given by the macro ++@code{MINARCS}. If you have some program with an unusually complex ++call graph, for which the heuristic fails to allocate enough space, ++you can use this tunable to increase the minimum to a larger value. ++@end deftp ++ ++@deftp Tunable glibc.mem.maxarcs ++To prevent excessive memory consumption when profiling very large ++programs, the call graph buffer is allowed to have a maximum of ++@code{MAXARCS} entries. For some very large programs, the default ++value of @code{MAXARCS} defined in @file{sys/gmon.h} is too small; in ++that case, you can use this tunable to increase it. ++ ++Note the value of the @code{maxarcs} tunable must be greater or equal ++to that of the @code{minarcs} tunable; if this constraint is violated, ++a warning will printed to standard error at program startup, and ++the @code{minarcs} value will be used as the maximum as well. ++ ++Setting either tunable too high may result in a call graph buffer ++whose size exceeds the available memory; in that case, an out of memory ++error will be printed at program startup, the profiler will be ++disabled, and no @file{gmon.out} file will be generated. ++@end deftp +diff --git a/sysdeps/unix/sysv/linux/aarch64/dl-tunables.list b/sysdeps/unix/sysv/linux/aarch64/dl-tunables.list +index 5c3c5292025607a1..265f82ef2be42fd0 100644 +--- a/sysdeps/unix/sysv/linux/aarch64/dl-tunables.list ++++ b/sysdeps/unix/sysv/linux/aarch64/dl-tunables.list +@@ -24,3 +24,7 @@ + + # Tunables added in RHEL 8.8.0 + @order glibc.rtld.dynamic_sort ++ ++# Tunables added in RHEL 8.9.0 ++@order glibc.gmon.minarcs ++@order glibc.gmon.maxarcs +diff --git a/sysdeps/unix/sysv/linux/i386/dl-tunables.list b/sysdeps/unix/sysv/linux/i386/dl-tunables.list +index b9cad4af62d9f2e5..9c1ccb86501c61e7 100644 +--- a/sysdeps/unix/sysv/linux/i386/dl-tunables.list ++++ b/sysdeps/unix/sysv/linux/i386/dl-tunables.list +@@ -31,3 +31,7 @@ + + # Tunables added in RHEL 8.8.0 + @order glibc.rtld.dynamic_sort ++ ++# Tunables added in RHEL 8.9.0 ++@order glibc.gmon.minarcs ++@order glibc.gmon.maxarcs +diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/dl-tunables.list b/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/dl-tunables.list +index ee1e6fca95e1f2da..c8bb1a8ec0283ac8 100644 +--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/dl-tunables.list ++++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/dl-tunables.list +@@ -24,3 +24,7 @@ + + # Tunables added in RHEL 8.8.0 + @order glibc.rtld.dynamic_sort ++ ++# Tunables added in RHEL 8.9.0 ++@order glibc.gmon.minarcs ++@order glibc.gmon.maxarcs +diff --git a/sysdeps/unix/sysv/linux/s390/s390-64/dl-tunables.list b/sysdeps/unix/sysv/linux/s390/s390-64/dl-tunables.list +index 099e28d8f8e67944..85b3a014ffcadc45 100644 +--- a/sysdeps/unix/sysv/linux/s390/s390-64/dl-tunables.list ++++ b/sysdeps/unix/sysv/linux/s390/s390-64/dl-tunables.list +@@ -23,3 +23,7 @@ + + # Tunables added in RHEL 8.8.0 + @order glibc.rtld.dynamic_sort ++ ++# Tunables added in RHEL 8.9.0 ++@order glibc.gmon.minarcs ++@order glibc.gmon.maxarcs +diff --git a/sysdeps/unix/sysv/linux/x86_64/64/dl-tunables.list b/sysdeps/unix/sysv/linux/x86_64/64/dl-tunables.list +index b9cad4af62d9f2e5..9c1ccb86501c61e7 100644 +--- a/sysdeps/unix/sysv/linux/x86_64/64/dl-tunables.list ++++ b/sysdeps/unix/sysv/linux/x86_64/64/dl-tunables.list +@@ -31,3 +31,7 @@ + + # Tunables added in RHEL 8.8.0 + @order glibc.rtld.dynamic_sort ++ ++# Tunables added in RHEL 8.9.0 ++@order glibc.gmon.minarcs ++@order glibc.gmon.maxarcs diff --git a/SOURCES/glibc-rh2180155-3.patch b/SOURCES/glibc-rh2180155-3.patch new file mode 100644 index 0000000..af5f7ec --- /dev/null +++ b/SOURCES/glibc-rh2180155-3.patch @@ -0,0 +1,191 @@ +commit bde121872001d8f3224eeafa5b7effb871c3fbca +Author: Simon Kissane +Date: Sat Feb 11 08:58:02 2023 +1100 + + gmon: fix memory corruption issues [BZ# 30101] + + V2 of this patch fixes an issue in V1, where the state was changed to ON not + OFF at end of _mcleanup. I hadn't noticed that (counterintuitively) ON=0 and + OFF=3, hence zeroing the buffer turned it back on. So set the state to OFF + after the memset. + + 1. Prevent double free, and reads from unallocated memory, when + _mcleanup is (incorrectly) called two or more times in a row, + without an intervening call to __monstartup; with this patch, the + second and subsequent calls effectively become no-ops instead. + While setting tos=NULL is minimal fix, safest action is to zero the + whole gmonparam buffer. + + 2. Prevent memory leak when __monstartup is (incorrectly) called two + or more times in a row, without an intervening call to _mcleanup; + with this patch, the second and subsequent calls effectively become + no-ops instead. + + 3. After _mcleanup, treat __moncontrol(1) as __moncontrol(0) instead. + With zeroing of gmonparam buffer in _mcleanup, this stops the + state incorrectly being changed to GMON_PROF_ON despite profiling + actually being off. If we'd just done the minimal fix to _mcleanup + of setting tos=NULL, there is risk of far worse memory corruption: + kcount would point to deallocated memory, and the __profil syscall + would make the kernel write profiling data into that memory, + which could have since been reallocated to something unrelated. + + 4. Ensure __moncontrol(0) still turns off profiling even in error + state. Otherwise, if mcount overflows and sets state to + GMON_PROF_ERROR, when _mcleanup calls __moncontrol(0), the __profil + syscall to disable profiling will not be invoked. _mcleanup will + free the buffer, but the kernel will still be writing profiling + data into it, potentially corrupted arbitrary memory. + + Also adds a test case for (1). Issues (2)-(4) are not feasible to test. + + Signed-off-by: Simon Kissane + Reviewed-by: DJ Delorie + +Conflicts: + gmon/Makefile + (copyright year update) + +diff --git a/gmon/Makefile b/gmon/Makefile +index 54f05894d4dd8c4a..1bc4ad6e14e292a9 100644 +--- a/gmon/Makefile ++++ b/gmon/Makefile +@@ -1,4 +1,5 @@ +-# Copyright (C) 1995-2018 Free Software Foundation, Inc. ++# Copyright (C) 1995-2023 Free Software Foundation, Inc. ++# Copyright The GNU Toolchain Authors. + # This file is part of the GNU C Library. + + # The GNU C Library is free software; you can redistribute it and/or +@@ -25,7 +26,7 @@ include ../Makeconfig + headers := sys/gmon.h sys/gmon_out.h sys/profil.h + routines := gmon mcount profil sprofil prof-freq + +-tests = tst-sprofil tst-gmon tst-mcount-overflow ++tests = tst-sprofil tst-gmon tst-mcount-overflow tst-mcleanup + ifeq ($(build-profile),yes) + tests += tst-profile-static + tests-static += tst-profile-static +@@ -68,6 +69,14 @@ ifeq ($(run-built-tests),yes) + tests-special += $(objpfx)tst-mcount-overflow-check.out + endif + ++CFLAGS-tst-mcleanup.c := -fno-omit-frame-pointer -pg ++tst-mcleanup-no-pie = yes ++CRT-tst-mcleanup := $(csu-objpfx)g$(start-installed-name) ++tst-mcleanup-ENV := GMON_OUT_PREFIX=$(objpfx)tst-mcleanup.data ++ifeq ($(run-built-tests),yes) ++tests-special += $(objpfx)tst-mcleanup.out ++endif ++ + CFLAGS-tst-gmon-static.c := $(PIE-ccflag) -fno-omit-frame-pointer -pg + CRT-tst-gmon-static := $(csu-objpfx)gcrt1.o + tst-gmon-static-no-pie = yes +@@ -123,6 +132,10 @@ $(objpfx)tst-mcount-overflow-check.out: tst-mcount-overflow-check.sh $(objpfx)ts + $(SHELL) $< $(objpfx)tst-mcount-overflow > $@; \ + $(evaluate-test) + ++$(objpfx)tst-mcleanup.out: clean-tst-mcleanup-data ++clean-tst-mcleanup-data: ++ rm -f $(objpfx)tst-mcleanup.data.* ++ + $(objpfx)tst-gmon-gprof.out: tst-gmon-gprof.sh $(objpfx)tst-gmon.out + $(SHELL) $< $(GPROF) $(objpfx)tst-gmon $(objpfx)tst-gmon.data.* > $@; \ + $(evaluate-test) +diff --git a/gmon/gmon.c b/gmon/gmon.c +index 689bf80141e559ca..5e99a7351dc71666 100644 +--- a/gmon/gmon.c ++++ b/gmon/gmon.c +@@ -102,11 +102,8 @@ __moncontrol (int mode) + { + struct gmonparam *p = &_gmonparam; + +- /* Don't change the state if we ran into an error. */ +- if (p->state == GMON_PROF_ERROR) +- return; +- +- if (mode) ++ /* Treat start request as stop if error or gmon not initialized. */ ++ if (mode && p->state != GMON_PROF_ERROR && p->tos != NULL) + { + /* start */ + __profil((void *) p->kcount, p->kcountsize, p->lowpc, s_scale); +@@ -116,7 +113,9 @@ __moncontrol (int mode) + { + /* stop */ + __profil(NULL, 0, 0, 0); +- p->state = GMON_PROF_OFF; ++ /* Don't change the state if we ran into an error. */ ++ if (p->state != GMON_PROF_ERROR) ++ p->state = GMON_PROF_OFF; + } + } + libc_hidden_def (__moncontrol) +@@ -146,6 +145,14 @@ __monstartup (u_long lowpc, u_long highpc) + maxarcs = MAXARCS; + #endif + ++ /* ++ * If we are incorrectly called twice in a row (without an ++ * intervening call to _mcleanup), ignore the second call to ++ * prevent leaking memory. ++ */ ++ if (p->tos != NULL) ++ return; ++ + /* + * round lowpc and highpc to multiples of the density we're using + * so the rest of the scaling (here and in gprof) stays in ints. +@@ -463,9 +470,14 @@ _mcleanup (void) + { + __moncontrol (0); + +- if (_gmonparam.state != GMON_PROF_ERROR) ++ if (_gmonparam.state != GMON_PROF_ERROR && _gmonparam.tos != NULL) + write_gmon (); + + /* free the memory. */ + free (_gmonparam.tos); ++ ++ /* reset buffer to initial state for safety */ ++ memset(&_gmonparam, 0, sizeof _gmonparam); ++ /* somewhat confusingly, ON=0, OFF=3 */ ++ _gmonparam.state = GMON_PROF_OFF; + } +diff --git a/gmon/tst-mcleanup.c b/gmon/tst-mcleanup.c +new file mode 100644 +index 0000000000000000..b259653ec833aca4 +--- /dev/null ++++ b/gmon/tst-mcleanup.c +@@ -0,0 +1,31 @@ ++/* Test program for repeated invocation of _mcleanup ++ Copyright The GNU Toolchain Authors. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++/* Intentionally calls _mcleanup() twice: once manually, it will be ++ called again as an atexit handler. This is incorrect use of the API, ++ but the point of the test is to make sure we don't crash when the ++ API is misused in this way. */ ++ ++#include ++ ++int ++main (void) ++{ ++ _mcleanup(); ++ return 0; ++} diff --git a/SOURCES/glibc-rh2180462-1.patch b/SOURCES/glibc-rh2180462-1.patch new file mode 100644 index 0000000..3a5d685 --- /dev/null +++ b/SOURCES/glibc-rh2180462-1.patch @@ -0,0 +1,216 @@ +From af992e7abdc9049714da76cae1e5e18bc4838fb8 Mon Sep 17 00:00:00 2001 +From: Noah Goldstein +Date: Wed, 7 Jun 2023 13:18:01 -0500 +Subject: [PATCH] x86: Increase `non_temporal_threshold` to roughly `sizeof_L3 + / 4` +Content-type: text/plain; charset=UTF-8 + +Current `non_temporal_threshold` set to roughly '3/4 * sizeof_L3 / +ncores_per_socket'. This patch updates that value to roughly +'sizeof_L3 / 4` + +The original value (specifically dividing the `ncores_per_socket`) was +done to limit the amount of other threads' data a `memcpy`/`memset` +could evict. + +Dividing by 'ncores_per_socket', however leads to exceedingly low +non-temporal thresholds and leads to using non-temporal stores in +cases where REP MOVSB is multiple times faster. + +Furthermore, non-temporal stores are written directly to main memory +so using it at a size much smaller than L3 can place soon to be +accessed data much further away than it otherwise could be. As well, +modern machines are able to detect streaming patterns (especially if +REP MOVSB is used) and provide LRU hints to the memory subsystem. This +in affect caps the total amount of eviction at 1/cache_associativity, +far below meaningfully thrashing the entire cache. + +As best I can tell, the benchmarks that lead this small threshold +where done comparing non-temporal stores versus standard cacheable +stores. A better comparison (linked below) is to be REP MOVSB which, +on the measure systems, is nearly 2x faster than non-temporal stores +at the low-end of the previous threshold, and within 10% for over +100MB copies (well past even the current threshold). In cases with a +low number of threads competing for bandwidth, REP MOVSB is ~2x faster +up to `sizeof_L3`. + +The divisor of `4` is a somewhat arbitrary value. From benchmarks it +seems Skylake and Icelake both prefer a divisor of `2`, but older CPUs +such as Broadwell prefer something closer to `8`. This patch is meant +to be followed up by another one to make the divisor cpu-specific, but +in the meantime (and for easier backporting), this patch settles on +`4` as a middle-ground. + +Benchmarks comparing non-temporal stores, REP MOVSB, and cacheable +stores where done using: +https://github.com/goldsteinn/memcpy-nt-benchmarks + +Sheets results (also available in pdf on the github): +https://docs.google.com/spreadsheets/d/e/2PACX-1vS183r0rW_jRX6tG_E90m9qVuFiMbRIJvi5VAE8yYOvEOIEEc3aSNuEsrFbuXw5c3nGboxMmrupZD7K/pubhtml +Reviewed-by: DJ Delorie +Reviewed-by: Carlos O'Donell +--- + sysdeps/x86/dl-cacheinfo.h | 70 +++++++++++++++++++++++--------------- + 1 file changed, 43 insertions(+), 27 deletions(-) + +[DJ - ported to C8S] + +diff -rup a/sysdeps/x86/cacheinfo.h b/sysdeps/x86/cacheinfo.h +--- a/sysdeps/x86/cacheinfo.h 2023-08-08 11:54:09.969791421 -0400 ++++ b/sysdeps/x86/cacheinfo.h 2023-08-08 13:44:55.185333601 -0400 +@@ -46,7 +46,7 @@ long int __x86_rep_movsb_threshold attri + long int __x86_rep_stosb_threshold attribute_hidden = 2048; + + static void +-get_common_cache_info (long int *shared_ptr, unsigned int *threads_ptr, ++get_common_cache_info (long int *shared_ptr, long int * shared_per_thread_ptr, unsigned int *threads_ptr, + long int core) + { + unsigned int eax; +@@ -65,6 +65,7 @@ get_common_cache_info (long int *shared_ + unsigned int family = cpu_features->basic.family; + unsigned int model = cpu_features->basic.model; + long int shared = *shared_ptr; ++ long int shared_per_thread = *shared_per_thread_ptr; + unsigned int threads = *threads_ptr; + bool inclusive_cache = true; + bool support_count_mask = true; +@@ -80,6 +81,7 @@ get_common_cache_info (long int *shared_ + /* Try L2 otherwise. */ + level = 2; + shared = core; ++ shared_per_thread = core; + threads_l2 = 0; + threads_l3 = -1; + } +@@ -236,29 +238,28 @@ get_common_cache_info (long int *shared_ + } + else + { +-intel_bug_no_cache_info: +- /* Assume that all logical threads share the highest cache +- level. */ +- threads +- = ((cpu_features->features[COMMON_CPUID_INDEX_1].cpuid.ebx +- >> 16) & 0xff); +- } +- +- /* Cap usage of highest cache level to the number of supported +- threads. */ +- if (shared > 0 && threads > 0) +- shared /= threads; ++ intel_bug_no_cache_info: ++ /* Assume that all logical threads share the highest cache ++ level. */ ++ threads = ((cpu_features->features[COMMON_CPUID_INDEX_1].cpuid.ebx >> 16) ++ & 0xff); ++ ++ /* Get per-thread size of highest level cache. */ ++ if (shared_per_thread > 0 && threads > 0) ++ shared_per_thread /= threads; ++ } + } + + /* Account for non-inclusive L2 and L3 caches. */ + if (!inclusive_cache) + { + if (threads_l2 > 0) +- core /= threads_l2; ++ shared_per_thread += core / threads_l2; + shared += core; + } + + *shared_ptr = shared; ++ *shared_per_thread_ptr = shared_per_thread; + *threads_ptr = threads; + } + +@@ -272,6 +273,7 @@ init_cacheinfo (void) + int max_cpuid_ex; + long int data = -1; + long int shared = -1; ++ long int shared_per_thread = -1; + long int core; + unsigned int threads = 0; + const struct cpu_features *cpu_features = __get_cpu_features (); +@@ -287,22 +289,25 @@ init_cacheinfo (void) + data = handle_intel (_SC_LEVEL1_DCACHE_SIZE, cpu_features); + core = handle_intel (_SC_LEVEL2_CACHE_SIZE, cpu_features); + shared = handle_intel (_SC_LEVEL3_CACHE_SIZE, cpu_features); ++ shared_per_thread = shared; + +- get_common_cache_info (&shared, &threads, core); ++ get_common_cache_info (&shared, &shared_per_thread, &threads, core); + } + else if (cpu_features->basic.kind == arch_kind_zhaoxin) + { + data = handle_zhaoxin (_SC_LEVEL1_DCACHE_SIZE); + core = handle_zhaoxin (_SC_LEVEL2_CACHE_SIZE); + shared = handle_zhaoxin (_SC_LEVEL3_CACHE_SIZE); ++ shared_per_thread = shared; + +- get_common_cache_info (&shared, &threads, core); ++ get_common_cache_info (&shared, &shared_per_thread, &threads, core); + } + else if (cpu_features->basic.kind == arch_kind_amd) + { + data = handle_amd (_SC_LEVEL1_DCACHE_SIZE); + long int core = handle_amd (_SC_LEVEL2_CACHE_SIZE); + shared = handle_amd (_SC_LEVEL3_CACHE_SIZE); ++ shared_per_thread = shared; + + /* Get maximum extended function. */ + __cpuid (0x80000000, max_cpuid_ex, ebx, ecx, edx); +@@ -352,6 +357,9 @@ init_cacheinfo (void) + shared += core; + } + } ++ ++ if (shared_per_thread <= 0) ++ shared_per_thread = shared; + } + + if (cpu_features->data_cache_size != 0) +@@ -380,20 +388,30 @@ init_cacheinfo (void) + __x86_shared_cache_size = shared; + } + +- /* The default setting for the non_temporal threshold is 3/4 of one +- thread's share of the chip's cache. For most Intel and AMD processors +- with an initial release date between 2017 and 2020, a thread's typical +- share of the cache is from 500 KBytes to 2 MBytes. Using the 3/4 +- threshold leaves 125 KBytes to 500 KBytes of the thread's data +- in cache after a maximum temporal copy, which will maintain +- in cache a reasonable portion of the thread's stack and other +- active data. If the threshold is set higher than one thread's +- share of the cache, it has a substantial risk of negatively +- impacting the performance of other threads running on the chip. */ ++ /* The default setting for the non_temporal threshold is 1/4 of size ++ of the chip's cache. For most Intel and AMD processors with an ++ initial release date between 2017 and 2023, a thread's typical ++ share of the cache is from 18-64MB. Using the 1/4 L3 is meant to ++ estimate the point where non-temporal stores begin out-competing ++ REP MOVSB. As well the point where the fact that non-temporal ++ stores are forced back to main memory would already occurred to the ++ majority of the lines in the copy. Note, concerns about the ++ entire L3 cache being evicted by the copy are mostly alleviated ++ by the fact that modern HW detects streaming patterns and ++ provides proper LRU hints so that the maximum thrashing ++ capped at 1/associativity. */ ++ unsigned long int non_temporal_threshold = shared / 4; ++ /* If no ERMS, we use the per-thread L3 chunking. Normal cacheable stores run ++ a higher risk of actually thrashing the cache as they don't have a HW LRU ++ hint. As well, their performance in highly parallel situations is ++ noticeably worse. */ ++ if (!CPU_FEATURE_USABLE_P (cpu_features, ERMS)) ++ non_temporal_threshold = shared_per_thread * 3 / 4; ++ + __x86_shared_non_temporal_threshold + = (cpu_features->non_temporal_threshold != 0 + ? cpu_features->non_temporal_threshold +- : __x86_shared_cache_size * 3 / 4); ++ : non_temporal_threshold); + + /* NB: The REP MOVSB threshold must be greater than VEC_SIZE * 8. */ + unsigned int minimum_rep_movsb_threshold; +Only in b/sysdeps/x86: cacheinfo.h~ diff --git a/SOURCES/glibc-rh2180462-2.patch b/SOURCES/glibc-rh2180462-2.patch new file mode 100644 index 0000000..35d246b --- /dev/null +++ b/SOURCES/glibc-rh2180462-2.patch @@ -0,0 +1,47 @@ +From 47f747217811db35854ea06741be3685e8bbd44d Mon Sep 17 00:00:00 2001 +From: Noah Goldstein +Date: Mon, 17 Jul 2023 23:14:33 -0500 +Subject: [PATCH] x86: Fix slight bug in `shared_per_thread` cache size + calculation. +Content-type: text/plain; charset=UTF-8 + +After: +``` + commit af992e7abdc9049714da76cae1e5e18bc4838fb8 + Author: Noah Goldstein + Date: Wed Jun 7 13:18:01 2023 -0500 + + x86: Increase `non_temporal_threshold` to roughly `sizeof_L3 / 4` +``` + +Split `shared` (cumulative cache size) from `shared_per_thread` (cache +size per socket), the `shared_per_thread` *can* be slightly off from +the previous calculation. + +Previously we added `core` even if `threads_l2` was invalid, and only +used `threads_l2` to divide `core` if it was present. The changed +version only included `core` if `threads_l2` was valid. + +This change restores the old behavior if `threads_l2` is invalid by +adding the entire value of `core`. +Reviewed-by: DJ Delorie +--- + sysdeps/x86/dl-cacheinfo.h | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +[DJ - ported to C8S] + +diff -rup b1/sysdeps/x86/cacheinfo.h b2/sysdeps/x86/cacheinfo.h +--- b1/sysdeps/x86/cacheinfo.h 2023-08-08 13:44:55.185333601 -0400 ++++ b2/sysdeps/x86/cacheinfo.h 2023-08-08 13:55:16.474680016 -0400 +@@ -253,8 +253,8 @@ get_common_cache_info (long int *shared_ + /* Account for non-inclusive L2 and L3 caches. */ + if (!inclusive_cache) + { +- if (threads_l2 > 0) +- shared_per_thread += core / threads_l2; ++ long int core_per_thread = threads_l2 > 0 ? (core / threads_l2) : core; ++ shared_per_thread += core_per_thread; + shared += core; + } + diff --git a/SOURCES/glibc-rh2180462-3.patch b/SOURCES/glibc-rh2180462-3.patch new file mode 100644 index 0000000..fd001d3 --- /dev/null +++ b/SOURCES/glibc-rh2180462-3.patch @@ -0,0 +1,44 @@ +From 8b9a0af8ca012217bf90d1dc0694f85b49ae09da Mon Sep 17 00:00:00 2001 +From: Noah Goldstein +Date: Tue, 18 Jul 2023 10:27:59 -0500 +Subject: [PATCH] [PATCH v1] x86: Use `3/4*sizeof(per-thread-L3)` as low bound + for NT threshold. +Content-type: text/plain; charset=UTF-8 + +On some machines we end up with incomplete cache information. This can +make the new calculation of `sizeof(total-L3)/custom-divisor` end up +lower than intended (and lower than the prior value). So reintroduce +the old bound as a lower bound to avoid potentially regressing code +where we don't have complete information to make the decision. +Reviewed-by: DJ Delorie +--- + sysdeps/x86/dl-cacheinfo.h | 15 ++++++++++++--- + 1 file changed, 12 insertions(+), 3 deletions(-) + +[DJ - ported to C8S] + +diff -rup b2/sysdeps/x86/cacheinfo.h b3/sysdeps/x86/cacheinfo.h +--- b2/sysdeps/x86/cacheinfo.h 2023-08-08 13:55:16.474680016 -0400 ++++ b3/sysdeps/x86/cacheinfo.h 2023-08-08 13:59:14.507988958 -0400 +@@ -401,12 +401,20 @@ init_cacheinfo (void) + provides proper LRU hints so that the maximum thrashing + capped at 1/associativity. */ + unsigned long int non_temporal_threshold = shared / 4; ++ /* If the computed non_temporal_threshold <= 3/4 * per-thread L3, we most ++ likely have incorrect/incomplete cache info in which case, default to ++ 3/4 * per-thread L3 to avoid regressions. */ ++ unsigned long int non_temporal_threshold_lowbound ++ = shared_per_thread * 3 / 4; ++ if (non_temporal_threshold < non_temporal_threshold_lowbound) ++ non_temporal_threshold = non_temporal_threshold_lowbound; ++ + /* If no ERMS, we use the per-thread L3 chunking. Normal cacheable stores run + a higher risk of actually thrashing the cache as they don't have a HW LRU + hint. As well, their performance in highly parallel situations is + noticeably worse. */ + if (!CPU_FEATURE_USABLE_P (cpu_features, ERMS)) +- non_temporal_threshold = shared_per_thread * 3 / 4; ++ non_temporal_threshold = non_temporal_threshold_lowbound; + + __x86_shared_non_temporal_threshold + = (cpu_features->non_temporal_threshold != 0 diff --git a/SOURCES/glibc-rh2180462-4.patch b/SOURCES/glibc-rh2180462-4.patch new file mode 100644 index 0000000..e0c568a --- /dev/null +++ b/SOURCES/glibc-rh2180462-4.patch @@ -0,0 +1,39 @@ +Adjusted for backport to c8s by modifying sysdeps/x86/cacheinfo.h. + +commit 885a7f0feee951f514a121788f46f33b2867110f +Author: Noah Goldstein +Date: Fri Aug 11 12:29:11 2023 -0500 + + x86: Fix incorrect scope of setting `shared_per_thread` [BZ# 30745] + + The: + + ``` + if (shared_per_thread > 0 && threads > 0) + shared_per_thread /= threads; + ``` + + Code was accidentally moved to inside the else scope. This doesn't + match how it was previously (before af992e7abd). + + This patch fixes that by putting the division after the `else` block. + +diff --git a/sysdeps/x86/cacheinfo.h b/sysdeps/x86/cacheinfo.h +index 4dbfa979ef052eaa..e53fa25106c95253 100644 +--- a/sysdeps/x86/cacheinfo.h ++++ b/sysdeps/x86/cacheinfo.h +@@ -243,11 +243,10 @@ get_common_cache_info (long int *shared_ptr, long int * shared_per_thread_ptr, u + level. */ + threads = ((cpu_features->features[COMMON_CPUID_INDEX_1].cpuid.ebx >> 16) + & 0xff); +- +- /* Get per-thread size of highest level cache. */ +- if (shared_per_thread > 0 && threads > 0) +- shared_per_thread /= threads; + } ++ /* Get per-thread size of highest level cache. */ ++ if (shared_per_thread > 0 && threads > 0) ++ shared_per_thread /= threads; + } + + /* Account for non-inclusive L2 and L3 caches. */ diff --git a/SOURCES/glibc-rh2183081-1.patch b/SOURCES/glibc-rh2183081-1.patch new file mode 100644 index 0000000..9c3829d --- /dev/null +++ b/SOURCES/glibc-rh2183081-1.patch @@ -0,0 +1,35 @@ +commit 5d1ccdda7b0c625751661d50977f3dfbc73f8eae +Author: Florian Weimer +Date: Mon Apr 3 17:23:11 2023 +0200 + + x86_64: Fix asm constraints in feraiseexcept (bug 30305) + + The divss instruction clobbers its first argument, and the constraints + need to reflect that. Fortunately, with GCC 12, generated code does + not actually change, so there is no externally visible bug. + + Suggested-by: Jakub Jelinek + Reviewed-by: Noah Goldstein + +diff --git a/sysdeps/x86_64/fpu/fraiseexcpt.c b/sysdeps/x86_64/fpu/fraiseexcpt.c +index ca1c223053bf016b..fb886ed540b52100 100644 +--- a/sysdeps/x86_64/fpu/fraiseexcpt.c ++++ b/sysdeps/x86_64/fpu/fraiseexcpt.c +@@ -33,7 +33,7 @@ __feraiseexcept (int excepts) + /* One example of an invalid operation is 0.0 / 0.0. */ + float f = 0.0; + +- __asm__ __volatile__ ("divss %0, %0 " : : "x" (f)); ++ __asm__ __volatile__ ("divss %0, %0 " : "+x" (f)); + (void) &f; + } + +@@ -43,7 +43,7 @@ __feraiseexcept (int excepts) + float f = 1.0; + float g = 0.0; + +- __asm__ __volatile__ ("divss %1, %0" : : "x" (f), "x" (g)); ++ __asm__ __volatile__ ("divss %1, %0" : "+x" (f) : "x" (g)); + (void) &f; + } + diff --git a/SOURCES/glibc-rh2183081-2.patch b/SOURCES/glibc-rh2183081-2.patch new file mode 100644 index 0000000..215b47f --- /dev/null +++ b/SOURCES/glibc-rh2183081-2.patch @@ -0,0 +1,28 @@ +Apply a fix similar to upstream commit 5d1ccdda7b0c625751661d50977f3dfbc73f8eae +to the installed header file. Upstream, the header file has been removed +in its uncorrected state, so there is no upstream fix to backport. + +Suggested by Jakub Jelinek. + +diff --git a/sysdeps/x86/fpu/bits/fenv.h b/sysdeps/x86/fpu/bits/fenv.h +index 4103982d8c8ae014..4ae2d2a04c6754bd 100644 +--- a/sysdeps/x86/fpu/bits/fenv.h ++++ b/sysdeps/x86/fpu/bits/fenv.h +@@ -132,7 +132,7 @@ __NTH (__feraiseexcept_invalid_divbyzero (int __excepts)) + float __f = 0.0; + + # ifdef __SSE_MATH__ +- __asm__ __volatile__ ("divss %0, %0 " : : "x" (__f)); ++ __asm__ __volatile__ ("divss %0, %0 " : "+x" (__f)); + # else + __asm__ __volatile__ ("fdiv %%st, %%st(0); fwait" + : "=t" (__f) : "0" (__f)); +@@ -145,7 +145,7 @@ __NTH (__feraiseexcept_invalid_divbyzero (int __excepts)) + float __g = 0.0; + + # ifdef __SSE_MATH__ +- __asm__ __volatile__ ("divss %1, %0" : : "x" (__f), "x" (__g)); ++ __asm__ __volatile__ ("divss %1, %0" : "+x" (__f) : "x" (__g)); + # else + __asm__ __volatile__ ("fdivp %%st, %%st(1); fwait" + : "=t" (__f) : "0" (__f), "u" (__g) : "st(1)"); diff --git a/SOURCES/glibc-rh2186781.patch b/SOURCES/glibc-rh2186781.patch new file mode 100644 index 0000000..9c848c7 --- /dev/null +++ b/SOURCES/glibc-rh2186781.patch @@ -0,0 +1,46 @@ +Only backport po/it.po and po/ja.po changes for the ESTALE message +translation which we use during CI testing. + +commit 7ff33eca6860648fb909df954da4996ce853d01d +Author: Carlos O'Donell +Date: Fri Jul 7 11:27:08 2023 -0400 + + Translations: Add new ro support and update others. + + This brings in the new Romanian language translations, and updates + nine other translations. Important translations in this update + include the Italian and Japanese translations for ESTALE which + remove the mention of "NFS" from the error message translation. + +diff --git a/po/it.po b/po/it.po +index 2750575a1082f1db..6c2be3a4df5611ff 100644 +--- a/po/it.po ++++ b/po/it.po +@@ -6793,10 +6793,8 @@ msgstr "Quota disco superata" + #. TRANS Repairing this condition usually requires unmounting, possibly repairing + #. TRANS and remounting the file system. + #: sysdeps/gnu/errlist.c:788 +-#, fuzzy +-#| msgid "Stale NFS file handle" + msgid "Stale file handle" +-msgstr "Gestione del file NFS interrotta" ++msgstr "Riferimento al file obsoleto" + + # lf + #. TRANS An attempt was made to NFS-mount a remote file system with a file name that +diff --git a/po/ja.po b/po/ja.po +index bd9b7ffbbd3e3bf6..8fb598c5edbc5891 100644 +--- a/po/ja.po ++++ b/po/ja.po +@@ -6360,10 +6360,8 @@ msgstr "ディスク使用量制限を超過しました" + #. TRANS Repairing this condition usually requires unmounting, possibly repairing + #. TRANS and remounting the file system. + #: sysdeps/gnu/errlist.c:788 +-#, fuzzy +-#| msgid "Stale NFS file handle" + msgid "Stale file handle" +-msgstr "実効性のないNFSファイルハンドルです" ++msgstr "古いファイルハンドルです" + + #. TRANS An attempt was made to NFS-mount a remote file system with a file name that + #. TRANS already specifies an NFS-mounted file. diff --git a/SOURCES/glibc-rh2213909.patch b/SOURCES/glibc-rh2213909.patch new file mode 100644 index 0000000..d18d5c8 --- /dev/null +++ b/SOURCES/glibc-rh2213909.patch @@ -0,0 +1,26 @@ +From abcf8db7fa46b73fd5b8193ce11f9312301b84c7 Mon Sep 17 00:00:00 2001 +From: Andreas Schwab +Date: Wed, 7 Jun 2023 11:21:48 +0200 +Subject: resolv_conf: release lock on allocation failure (bug 30527) + +When the initial allocation of global fails, the local lock is left +locked. + +Reported by Steffen Lammel of SAP HANA development. + +diff --git a/resolv/resolv_conf.c b/resolv/resolv_conf.c +index bd5890773b..8bc9edc634 100644 +--- a/resolv/resolv_conf.c ++++ b/resolv/resolv_conf.c +@@ -93,7 +93,10 @@ get_locked_global (void) + { + global_copy = calloc (1, sizeof (*global)); + if (global_copy == NULL) +- return NULL; ++ { ++ __libc_lock_unlock (lock); ++ return NULL; ++ } + atomic_store_relaxed (&global, global_copy); + resolv_conf_array_init (&global_copy->array); + } diff --git a/SOURCES/glibc-rh2224348.patch b/SOURCES/glibc-rh2224348.patch new file mode 100644 index 0000000..dc4732f --- /dev/null +++ b/SOURCES/glibc-rh2224348.patch @@ -0,0 +1,27 @@ +commit 0fda2a41baf7e978d07322aa278e964f4dce8802 +Author: Florian Weimer +Date: Thu Jul 20 18:31:48 2023 +0200 + + debug: Mark libSegFault.so as NODELETE + + The signal handler installed in the ELF constructor cannot easily + be removed again (because the program may have changed handlers + in the meantime). Mark the object as NODELETE so that the registered + handler function is never unloaded. + + Reviewed-by: Carlos O'Donell + (cherry picked from commit 23ee92deea4c99d0e6a5f48fa7b942909b123ec5) + +diff --git a/debug/Makefile b/debug/Makefile +index b0f0b7beb6d5cef5..8bce89ddcd0a61ed 100644 +--- a/debug/Makefile ++++ b/debug/Makefile +@@ -213,6 +213,8 @@ extra-libs-others = $(extra-libs) + + libSegFault-routines = segfault + libSegFault-inhibit-o = $(filter-out .os,$(object-suffixes)) ++# libSegFault.so installs a signal handler in its ELF constructor. ++LDFLAGS-SegFault.so = -Wl,--enable-new-dtags,-z,nodelete + + libpcprofile-routines = pcprofile + libpcprofile-inhibit-o = $(filter-out .os,$(object-suffixes)) diff --git a/SOURCES/glibc-rh2234714.patch b/SOURCES/glibc-rh2234714.patch new file mode 100644 index 0000000..999840c --- /dev/null +++ b/SOURCES/glibc-rh2234714.patch @@ -0,0 +1,187 @@ +commit bd77dd7e73e3530203be1c52c8a29d08270cb25d +Author: Florian Weimer +Date: Wed Sep 13 14:10:56 2023 +0200 + + CVE-2023-4527: Stack read overflow with large TCP responses in no-aaaa mode + + Without passing alt_dns_packet_buffer, __res_context_search can only + store 2048 bytes (what fits into dns_packet_buffer). However, + the function returns the total packet size, and the subsequent + DNS parsing code in _nss_dns_gethostbyname4_r reads beyond the end + of the stack-allocated buffer. + + Fixes commit f282cdbe7f436c75864e5640a4 ("resolv: Implement no-aaaa + stub resolver option") and bug 30842. + +Conflicts: + resolv/nss_dns/dns-host.c + (missing dns_packet_buffer cleanup downstream) + +diff --git a/resolv/Makefile b/resolv/Makefile +index ab8ad49b5318ad41..4f4eaf060443c128 100644 +--- a/resolv/Makefile ++++ b/resolv/Makefile +@@ -58,6 +58,7 @@ tests += \ + tst-resolv-edns \ + tst-resolv-network \ + tst-resolv-noaaaa \ ++ tst-resolv-noaaaa-vc \ + tst-resolv-nondecimal \ + tst-resolv-res_init-multi \ + tst-resolv-search \ +@@ -202,6 +203,7 @@ $(objpfx)tst-resolv-res_init-multi: $(objpfx)libresolv.so \ + $(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-noaaaa-vc: $(objpfx)libresolv.so $(shared-thread-library) + $(objpfx)tst-resolv-nondecimal: $(objpfx)libresolv.so $(shared-thread-library) + $(objpfx)tst-resolv-qtypes: $(objpfx)libresolv.so $(shared-thread-library) + $(objpfx)tst-resolv-rotate: $(objpfx)libresolv.so $(shared-thread-library) +diff --git a/resolv/nss_dns/dns-host.c b/resolv/nss_dns/dns-host.c +index ff0a0b6f7f1f4703..f678c7d7caa3a026 100644 +--- a/resolv/nss_dns/dns-host.c ++++ b/resolv/nss_dns/dns-host.c +@@ -392,7 +392,7 @@ _nss_dns_gethostbyname4_r (const char *name, struct gaih_addrtuple **pat, + else + { + n = __res_context_search (ctx, name, C_IN, T_A, +- host_buffer.buf->buf, 2048, NULL, ++ host_buffer.buf->buf, 2048, &host_buffer.ptr, + NULL, NULL, NULL, NULL); + if (n >= 0) + status = gaih_getanswer_noaaaa (host_buffer.buf, n, +diff --git a/resolv/tst-resolv-noaaaa-vc.c b/resolv/tst-resolv-noaaaa-vc.c +new file mode 100644 +index 0000000000000000..9f5aebd99f2d74a2 +--- /dev/null ++++ b/resolv/tst-resolv-noaaaa-vc.c +@@ -0,0 +1,129 @@ ++/* Test the RES_NOAAAA resolver option with a large response. ++ Copyright (C) 2022-2023 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* Used to keep track of the number of queries. */ ++static volatile unsigned int queries; ++ ++/* If true, add a large TXT record at the start of the answer section. */ ++static volatile bool stuff_txt; ++ ++static void ++response (const struct resolv_response_context *ctx, ++ struct resolv_response_builder *b, ++ const char *qname, uint16_t qclass, uint16_t qtype) ++{ ++ /* If not using TCP, just force its use. */ ++ if (!ctx->tcp) ++ { ++ struct resolv_response_flags flags = {.tc = true}; ++ resolv_response_init (b, flags); ++ resolv_response_add_question (b, qname, qclass, qtype); ++ return; ++ } ++ ++ /* The test needs to send four queries, the first three are used to ++ grow the NSS buffer via the ERANGE handshake. */ ++ ++queries; ++ TEST_VERIFY (queries <= 4); ++ ++ /* AAAA queries are supposed to be disabled. */ ++ TEST_COMPARE (qtype, T_A); ++ TEST_COMPARE (qclass, C_IN); ++ TEST_COMPARE_STRING (qname, "example.com"); ++ ++ struct resolv_response_flags flags = {}; ++ resolv_response_init (b, flags); ++ resolv_response_add_question (b, qname, qclass, qtype); ++ ++ resolv_response_section (b, ns_s_an); ++ ++ if (stuff_txt) ++ { ++ resolv_response_open_record (b, qname, qclass, T_TXT, 60); ++ int zero = 0; ++ for (int i = 0; i <= 15000; ++i) ++ resolv_response_add_data (b, &zero, sizeof (zero)); ++ resolv_response_close_record (b); ++ } ++ ++ for (int i = 0; i < 200; ++i) ++ { ++ resolv_response_open_record (b, qname, qclass, qtype, 60); ++ char ipv4[4] = {192, 0, 2, i + 1}; ++ resolv_response_add_data (b, &ipv4, sizeof (ipv4)); ++ resolv_response_close_record (b); ++ } ++} ++ ++static int ++do_test (void) ++{ ++ struct resolv_test *obj = resolv_test_start ++ ((struct resolv_redirect_config) ++ { ++ .response_callback = response ++ }); ++ ++ _res.options |= RES_NOAAAA; ++ ++ for (int do_stuff_txt = 0; do_stuff_txt < 2; ++do_stuff_txt) ++ { ++ queries = 0; ++ stuff_txt = do_stuff_txt; ++ ++ struct addrinfo *ai = NULL; ++ int ret; ++ ret = getaddrinfo ("example.com", "80", ++ &(struct addrinfo) ++ { ++ .ai_family = AF_UNSPEC, ++ .ai_socktype = SOCK_STREAM, ++ }, &ai); ++ ++ char *expected_result; ++ { ++ struct xmemstream mem; ++ xopen_memstream (&mem); ++ for (int i = 0; i < 200; ++i) ++ fprintf (mem.out, "address: STREAM/TCP 192.0.2.%d 80\n", i + 1); ++ xfclose_memstream (&mem); ++ expected_result = mem.buffer; ++ } ++ ++ check_addrinfo ("example.com", ai, ret, expected_result); ++ ++ free (expected_result); ++ freeaddrinfo (ai); ++ } ++ ++ resolv_test_end (obj); ++ return 0; ++} ++ ++#include diff --git a/SOURCES/glibc-rh697421.patch b/SOURCES/glibc-rh697421.patch new file mode 100644 index 0000000..e909aa1 --- /dev/null +++ b/SOURCES/glibc-rh697421.patch @@ -0,0 +1,21 @@ +Short description: Add UCS-2 aliases. +Author(s): Fedora glibc team +Origin: PATCH +Bug-RHEL: #697421 +Upstream status: https://sourceware.org/ml/libc-alpha/2012-12/msg00103.html + +This is a Fedora-specific change to include new aliases for UCS-2 +data for gconv used by a certain class of users. This should be +revisited at some point to determine if those users are just using +UTF-8 at this point. + +diff -rup a/iconvdata/gconv-modules b/iconvdata/gconv-modules +--- a/iconvdata/gconv-modules 2010-05-04 05:27:23.000000000 -0600 ++++ b/iconvdata/gconv-modules 2012-01-26 10:58:24.181895489 -0700 +@@ -1954,3 +1954,6 @@ alias HPGREEK8// HP-GREEK8// + alias OSF10010004// HP-GREEK8// + module HP-GREEK8// INTERNAL HP-GREEK8 1 + module INTERNAL HP-GREEK8// HP-GREEK8 1 ++ ++alias ISO-10646-UCS-2// UNICODE// ++alias ISO-10646-UCS-2// ISO-10646/UTF8/ diff --git a/SOURCES/glibc-rh741105.patch b/SOURCES/glibc-rh741105.patch new file mode 100644 index 0000000..f7d06ca --- /dev/null +++ b/SOURCES/glibc-rh741105.patch @@ -0,0 +1,84 @@ +Short description: Work ld.so --verify crash on debuginfo files. +Author(s): Fedora glibc team +Origin: PATCH +Bug-RHEL: #741105, #767146 +Upstream status: not-needed + +This change is designed to work around running ld.so on a debuginfo +file. This is the wrong fix for this problem and should be dropped. +The correct solution is to mark debuginfo files as new types of +ELF files. + +Index: glibc-2.22-386-g95e8397/elf/dl-load.c +=================================================================== +--- glibc-2.22-386-g95e8397.orig/elf/dl-load.c ++++ glibc-2.22-386-g95e8397/elf/dl-load.c +@@ -881,7 +881,8 @@ _dl_map_object_from_fd (const char *name + + /* Get file information. */ + struct r_file_id id; +- if (__glibc_unlikely (!_dl_get_file_id (fd, &id))) ++ struct stat64 st; ++ if (__glibc_unlikely (!_dl_get_file_id (fd, &id, &st))) + { + errstring = N_("cannot stat shared object"); + call_lose_errno: +@@ -1076,6 +1077,16 @@ _dl_map_object_from_fd (const char *name + = N_("ELF load command address/offset not properly aligned"); + goto call_lose; + } ++ if (__glibc_unlikely (ph->p_offset + ph->p_filesz > st.st_size)) ++ { ++ /* If the segment requires zeroing of part of its last ++ page, we'll crash when accessing the unmapped page. ++ There's still a possibility of a race, if the shared ++ object is truncated between the fxstat above and the ++ memset below. */ ++ errstring = N_("ELF load command past end of file"); ++ goto call_lose; ++ } + + struct loadcmd *c = &loadcmds[nloadcmds++]; + c->mapstart = ALIGN_DOWN (ph->p_vaddr, GLRO(dl_pagesize)); +Index: glibc-2.22-386-g95e8397/sysdeps/generic/dl-fileid.h +=================================================================== +--- glibc-2.22-386-g95e8397.orig/sysdeps/generic/dl-fileid.h ++++ glibc-2.22-386-g95e8397/sysdeps/generic/dl-fileid.h +@@ -29,7 +29,8 @@ struct r_file_id + On error, returns false, with errno set. */ + static inline bool + _dl_get_file_id (int fd __attribute__ ((unused)), +- struct r_file_id *id __attribute__ ((unused))) ++ struct r_file_id *id __attribute__ ((unused)), ++ struct stat64_t *st __attribute__((unused))) + { + return true; + } +Index: glibc-2.22-386-g95e8397/sysdeps/posix/dl-fileid.h +=================================================================== +--- glibc-2.22-386-g95e8397.orig/sysdeps/posix/dl-fileid.h ++++ glibc-2.22-386-g95e8397/sysdeps/posix/dl-fileid.h +@@ -27,18 +27,16 @@ struct r_file_id + ino64_t ino; + }; + +-/* Sample FD to fill in *ID. Returns true on success. ++/* Sample FD to fill in *ID and *ST. Returns true on success. + On error, returns false, with errno set. */ + static inline bool +-_dl_get_file_id (int fd, struct r_file_id *id) ++_dl_get_file_id (int fd, struct r_file_id *id, struct stat64 *st) + { +- struct stat64 st; +- +- if (__glibc_unlikely (__fxstat64 (_STAT_VER, fd, &st) < 0)) ++ if (__glibc_unlikely (__fxstat64 (_STAT_VER, fd, st) < 0)) + return false; + +- id->dev = st.st_dev; +- id->ino = st.st_ino; ++ id->dev = st->st_dev; ++ id->ino = st->st_ino; + return true; + } + diff --git a/SOURCES/glibc-rh819430.patch b/SOURCES/glibc-rh819430.patch new file mode 100644 index 0000000..8b766f1 --- /dev/null +++ b/SOURCES/glibc-rh819430.patch @@ -0,0 +1,91 @@ +Short description: fnmatch() fails with MBCS. +Author(s): Fedora glibc team +Origin: PATCH +Bug-RHEL: #819430, #826149, #826151 +Bug-Upstream: #14185 +Upstream status: not-submitted + +fnmatch() fails when '*' wildcard is applied on the file name +containing multi-byte character(s) + +This needs to be reviewed thoroughly and go upstream with a +new test case. + +diff -Nrup a/posix/fnmatch.c b/posix/fnmatch.c +--- a/posix/fnmatch.c 2012-01-01 07:16:32.000000000 -0500 ++++ b/posix/fnmatch.c 2012-05-23 14:14:29.099461189 -0400 +@@ -333,6 +333,7 @@ fnmatch (pattern, string, flags) + # if HANDLE_MULTIBYTE + if (__builtin_expect (MB_CUR_MAX, 1) != 1) + { ++ const char *orig_pattern = pattern; + mbstate_t ps; + size_t n; + const char *p; +@@ -356,10 +357,8 @@ fnmatch (pattern, string, flags) + alloca_used); + n = mbsrtowcs (wpattern, &p, n + 1, &ps); + if (__glibc_unlikely (n == (size_t) -1)) +- /* Something wrong. +- XXX Do we have to set `errno' to something which mbsrtows hasn't +- already done? */ +- return -1; ++ /* Something wrong: Fall back to single byte matching. */ ++ goto try_singlebyte; + if (p) + { + memset (&ps, '\0', sizeof (ps)); +@@ -371,10 +370,8 @@ fnmatch (pattern, string, flags) + prepare_wpattern: + n = mbsrtowcs (NULL, &pattern, 0, &ps); + if (__glibc_unlikely (n == (size_t) -1)) +- /* Something wrong. +- XXX Do we have to set `errno' to something which mbsrtows hasn't +- already done? */ +- return -1; ++ /*Something wrong: Fall back to single byte matching. */ ++ goto try_singlebyte; + if (__glibc_unlikely (n >= (size_t) -1 / sizeof (wchar_t))) + { + __set_errno (ENOMEM); +@@ -401,14 +398,8 @@ fnmatch (pattern, string, flags) + alloca_used); + n = mbsrtowcs (wstring, &p, n + 1, &ps); + if (__glibc_unlikely (n == (size_t) -1)) +- { +- /* Something wrong. +- XXX Do we have to set `errno' to something which +- mbsrtows hasn't already done? */ +- free_return: +- free (wpattern_malloc); +- return -1; +- } ++ /* Something wrong: Fall back to single byte matching. */ ++ goto free_and_try_singlebyte; + if (p) + { + memset (&ps, '\0', sizeof (ps)); +@@ -420,10 +411,8 @@ fnmatch (pattern, string, flags) + prepare_wstring: + n = mbsrtowcs (NULL, &string, 0, &ps); + if (__glibc_unlikely (n == (size_t) -1)) +- /* Something wrong. +- XXX Do we have to set `errno' to something which mbsrtows hasn't +- already done? */ +- goto free_return; ++ /* Something wrong: Fall back to singlebyte matching. */ ++ goto free_and_try_singlebyte; + if (__glibc_unlikely (n >= (size_t) -1 / sizeof (wchar_t))) + { + free (wpattern_malloc); +@@ -450,6 +439,10 @@ fnmatch (pattern, string, flags) + free (wpattern_malloc); + + return res; ++ free_and_try_singlebyte: ++ free(wpattern_malloc); ++ try_singlebyte: ++ pattern = orig_pattern; + } + # endif /* mbstate_t and mbsrtowcs or _LIBC. */ + diff --git a/SOURCES/glibc-rh827510.patch b/SOURCES/glibc-rh827510.patch new file mode 100644 index 0000000..6115891 --- /dev/null +++ b/SOURCES/glibc-rh827510.patch @@ -0,0 +1,37 @@ +Short description: Fix newlocale error return. +Author(s): Fedora glibc team +Origin: PATCH +Bug-RHEL: #832516 +Bug-Fedora: #827510 +Bug-Upstream: #14247 +Upstream status: not-submitted + +This needs to go upstream right away to fix the error case for +newlocale not correctly returning an error. + +2012-06-14 Jeff Law + + * locale/loadlocale.c (_nl_load_locale): Delay setting + file->decided until we have successfully loaded the file's + data. + +diff --git a/locale/loadlocale.c b/locale/loadlocale.c +index e3fa187..9fd9216 100644 +--- a/locale/loadlocale.c ++++ b/locale/loadlocale.c +@@ -169,7 +169,6 @@ _nl_load_locale (struct loaded_l10nfile *file, int category) + int save_err; + int alloc = ld_mapped; + +- file->decided = 1; + file->data = NULL; + + fd = __open_nocancel (file->filename, O_RDONLY | O_CLOEXEC); +@@ -278,6 +277,7 @@ _nl_load_locale (struct loaded_l10nfile *file, int category) + newdata->alloc = alloc; + + file->data = newdata; ++ file->decided = 1; + } + + void diff --git a/SOURCES/glibc-with-nonshared-cflags.patch b/SOURCES/glibc-with-nonshared-cflags.patch new file mode 100644 index 0000000..af7f65b --- /dev/null +++ b/SOURCES/glibc-with-nonshared-cflags.patch @@ -0,0 +1,139 @@ +Author: Florian Weimer +Date: Wed Jul 4 11:34:36 2018 +0200 + + Add --with-nonshared-cflags option to configure + +Submitted upstream: + + https://sourceware.org/ml/libc-alpha/2018-07/msg00071.html + +diff --git a/INSTALL b/INSTALL +index 0a22aa7d01e6e87b..0f80d9d615db6d42 100644 +--- a/INSTALL ++++ b/INSTALL +@@ -90,6 +90,15 @@ 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-nonshared-cflags=CFLAGS' ++ Use additional compiler flags CFLAGS to build the parts of the ++ library which are always statically linked into applications and ++ libraries even with shared linking (that is, the object files ++ contained in 'lib*_nonshared.a' libraries). The build process will ++ automatically use the appropriate flags, but this option can be ++ used to set additional flags required for building applications and ++ libraries, to match local policy. ++ + '--disable-shared' + Don't build shared libraries even if it is possible. Not all + systems support shared libraries; you need ELF support and +diff --git a/Makeconfig b/Makeconfig +index 608ffe648c80c724..b0b27f0113ac18b8 100644 +--- a/Makeconfig ++++ b/Makeconfig +@@ -1038,7 +1038,7 @@ object-suffixes-for-libc += .oS + # Must build the routines as PIC, though, because they can end up in (users') + # shared objects. We don't want to use CFLAGS-os because users may, for + # example, make that processor-specific. +-CFLAGS-.oS = $(CFLAGS-.o) $(PIC-ccflag) ++CFLAGS-.oS = $(CFLAGS-.o) $(PIC-ccflag) $(extra-nonshared-cflags) + CPPFLAGS-.oS = $(CPPFLAGS-.o) -DPIC -DLIBC_NONSHARED=1 + libtype.oS = lib%_nonshared.a + endif +diff --git a/config.make.in b/config.make.in +index d9891b2cd8ec3fbf..a6fe48d31f4d2725 100644 +--- a/config.make.in ++++ b/config.make.in +@@ -110,6 +110,7 @@ BUILD_CC = @BUILD_CC@ + CFLAGS = @CFLAGS@ + CPPFLAGS-config = @CPPFLAGS@ + CPPUNDEFS = @CPPUNDEFS@ ++extra-nonshared-cflags = @extra_nonshared_cflags@ + ASFLAGS-config = @ASFLAGS_config@ + AR = @AR@ + NM = @NM@ +diff --git a/configure b/configure +index ef1830221522b7a5..fec0efff8216addd 100755 +--- a/configure ++++ b/configure +@@ -684,6 +684,7 @@ force_install + bindnow + hardcoded_path_in_tests + enable_timezone_tools ++extra_nonshared_cflags + use_default_link + sysheaders + ac_ct_CXX +@@ -762,6 +763,7 @@ with_binutils + with_selinux + with_headers + with_default_link ++with_nonshared_cflags + enable_sanity_checks + enable_shared + enable_profile +@@ -1479,6 +1481,8 @@ Optional Packages: + --with-headers=PATH location of system headers to use (for example + /usr/src/linux/include) [default=compiler default] + --with-default-link do not use explicit linker scripts ++ --with-nonshared-cflags=FLAGS ++ build nonshared libraries with additional FLAGS + --with-cpu=CPU select code for CPU variant + + Some influential environment variables: +@@ -3336,6 +3340,16 @@ else + fi + + ++ ++# Check whether --with-nonshared-cflags was given. ++if test "${with_nonshared_cflags+set}" = set; then : ++ withval=$with_nonshared_cflags; extra_nonshared_cflags=$withval ++else ++ extra_nonshared_cflags= ++fi ++ ++ ++ + # Check whether --enable-sanity-checks was given. + if test "${enable_sanity_checks+set}" = set; then : + enableval=$enable_sanity_checks; enable_sanity=$enableval +diff --git a/configure.ac b/configure.ac +index dc517017f588626a..154185d70de38928 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -154,6 +154,14 @@ AC_ARG_WITH([default-link], + [use_default_link=$withval], + [use_default_link=default]) + ++dnl Additional build flags injection. ++AC_ARG_WITH([nonshared-cflags], ++ AC_HELP_STRING([--with-nonshared-cflags=FLAGS], ++ [build nonshared libraries with additional FLAGS]), ++ [extra_nonshared_cflags=$withval], ++ [extra_nonshared_cflags=]) ++AC_SUBST(extra_nonshared_cflags) ++ + AC_ARG_ENABLE([sanity-checks], + AC_HELP_STRING([--disable-sanity-checks], + [really do not use threads (should not be used except in special situations) @<:@default=yes@:>@]), +diff --git a/manual/install.texi b/manual/install.texi +index 422da1447eb4dc68..eaf0cd09e7501b96 100644 +--- a/manual/install.texi ++++ b/manual/install.texi +@@ -117,6 +117,15 @@ 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-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 ++libraries even with shared linking (that is, the object files contained ++in @file{lib*_nonshared.a} libraries). The build process will ++automatically use the appropriate flags, but this option can be used to ++set additional flags required for building applications and libraries, ++to match local policy. ++ + @c disable static doesn't work currently + @c @item --disable-static + @c Don't build static libraries. Static libraries aren't that useful these diff --git a/SOURCES/nscd.conf b/SOURCES/nscd.conf new file mode 100644 index 0000000..8a24a78 --- /dev/null +++ b/SOURCES/nscd.conf @@ -0,0 +1 @@ +d /run/nscd 0755 root root diff --git a/SOURCES/power6emul.c b/SOURCES/power6emul.c new file mode 100644 index 0000000..1b0187b --- /dev/null +++ b/SOURCES/power6emul.c @@ -0,0 +1,273 @@ +/* Emulate power6 mf[tf]gpr and fri[zpmn] instructions. + Copyright (C) 2006 Red Hat, Inc. + Contributed by Jakub Jelinek , 2006. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + It is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License 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. */ + +#include +#include + +extern double frip (double), friz (double), frin (double), frim (double); +asm (".globl frip, friz, frin, frim\n.hidden frip, friz, frin, frim\n\t" +#ifdef __powerpc64__ + ".section \".toc\",\"aw\"\n" +"8:" ".tc FD_43300000_0[TC],0x4330000000000000\n" +"9:" ".tc FD_3fe00000_0[TC],0x3fe0000000000000\n\t" + ".previous\n\t" +#else + ".rodata\n\t" + ".align 2\n" +"8:" ".long 0x59800000\n" +"9:" ".long 0x3f000000\n\t" + ".previous\n\t" +#endif + "# frip == ceil\n" +"frip:" "mffs 11\n\t" +#ifdef __powerpc64__ + "lfd 13,8b@toc(2)\n\t" +#else + "mflr 11\n\t" + "bcl 20,31,1f\n" +"1:" "mflr 9\n\t" + "addis 9,9,8b-1b@ha\n\t" + "lfs 13,8b-1b@l(9)\n\t" + "mtlr 11\n\t" +#endif + "fabs 0,1\n\t" + "fsub 12,13,13\n\t" + "fcmpu 7,0,13\n\t" + "fcmpu 6,1,12\n\t" + "bnllr- 7\n\t" + "mtfsfi 7,2\n\t" + "ble- 6,2f\n\t" + "fadd 1,1,13\n\t" + "fsub 1,1,13\n\t" + "fabs 1,1\n\t" + "mtfsf 0x01,11\n\t" + "blr\n" +"2:" "bge- 6,3f\n\t" + "fsub 1,1,13\n\t" + "fadd 1,1,13\n\t" + "fnabs 1,1\n" +"3:" "mtfsf 0x01,11\n\t" + "blr\n\t" + "# friz == trunc\n" +"friz:" "mffs 11\n\t" +#ifdef __powerpc64__ + "lfd 13,8b@toc(2)\n\t" +#else + "mflr 11\n\t" + "bcl 20,31,1f\n" +"1:" "mflr 9\n\t" + "addis 9,9,8b-1b@ha\n\t" + "lfs 13,8b-1b@l(9)\n\t" + "mtlr 11\n\t" +#endif + "fabs 0,1\n\t" + "fsub 12,13,13\n\t" + "fcmpu 7,0,13\n\t" + "fcmpu 6,1,12\n\t" + "bnllr- 7\n\t" + "mtfsfi 7,1\n\t" + "ble- 6,2f\n\t" + "fadd 1,1,13\n\t" + "fsub 1,1,13\n\t" + "fabs 1,1\n\t" + "mtfsf 0x01,11\n\t" + "blr\n" +"2:" "bge- 6,3f\n\t" + "fsub 1,1,13\n\t" + "fadd 1,1,13\n\t" + "fnabs 1,1\n" +"3:" "mtfsf 0x01,11\n\t" + "blr\n\t" + "# frin == round\n" +"frin:" "mffs 11\n\t" +#ifdef __powerpc64__ + "lfd 13,8b@toc(2)\n\t" +#else + "mflr 11\n\t" + "bcl 20,31,1f\n" +"1:" "mflr 9\n\t" + "addis 9,9,8b-1b@ha\n\t" + "addi 9,9,8b-1b@l\n\t" + "mtlr 11\n\t" + "lfs 13,0(9)\n\t" +#endif + "fabs 0,1\n\t" + "fsub 12,13,13\n\t" + "fcmpu 7,0,13\n\t" + "fcmpu 6,1,12\n\t" + "bnllr- 7\n\t" + "mtfsfi 7,1\n\t" +#ifdef __powerpc64__ + "lfd 10,9b@toc(2)\n\t" +#else + "lfs 10,9b-8b(9)\n\t" +#endif + "ble- 6,2f\n\t" + "fadd 1,1,10\n\t" + "fadd 1,1,13\n\t" + "fsub 1,1,13\n\t" + "fabs 1,1\n\t" + "mtfsf 0x01,11\n\t" + "blr\n" +"2:" "fsub 9,1,10\n\t" + "bge- 6,3f\n\t" + "fsub 1,9,13\n\t" + "fadd 1,1,13\n\t" + "fnabs 1,1\n" +"3:" "mtfsf 0x01,11\n\t" + "blr\n\t" + "# frim == floor\n" +"frim:" "mffs 11\n\t" +#ifdef __powerpc64__ + "lfd 13,8b@toc(2)\n\t" +#else + "mflr 11\n\t" + "bcl 20,31,1f\n" +"1:" "mflr 9\n\t" + "addis 9,9,8b-1b@ha\n\t" + "lfs 13,8b-1b@l(9)\n\t" + "mtlr 11\n\t" +#endif + "fabs 0,1\n\t" + "fsub 12,13,13\n\t" + "fcmpu 7,0,13\n\t" + "fcmpu 6,1,12\n\t" + "bnllr- 7\n\t" + "mtfsfi 7,3\n\t" + "ble- 6,2f\n\t" + "fadd 1,1,13\n\t" + "fsub 1,1,13\n\t" + "fabs 1,1\n\t" + "mtfsf 0x01,11\n\t" + "blr\n" +"2:" "bge- 6,3f\n\t" + "fsub 1,1,13\n\t" + "fadd 1,1,13\n\t" + "fnabs 1,1\n" +"3:" "mtfsf 0x01,11\n\t" + "blr\n"); + +#ifdef __powerpc64__ +#define m1 0x5555555555555555L +#define m2 0x3333333333333333L +#define m3 0x0f0f0f0f0f0f0f0fL +#else +#define m1 0x55555555 +#define m2 0x33333333 +#define m3 0x0f0f0f0f +#endif + +static inline unsigned long +popcntb (unsigned long n) +{ + n -= (n >> 1) & m1; + n = (n & m2) + ((n >> 2) & m2); + n = (n + (n >> 4)) & m3; + return n; +} + +static void +catch_sigill (int signal, struct sigcontext *ctx) +{ + unsigned int insn = *(unsigned int *) (ctx->regs->nip); +#ifdef __powerpc64__ + if ((insn & 0xfc1f07ff) == 0x7c0005be) /* mftgpr */ + { + unsigned long *regs = (unsigned long *) ctx->regs; + unsigned fpr = (insn >> 11) & 0x1f; + unsigned gpr = (insn >> 21) & 0x1f; + regs[gpr] = regs[fpr + 0x30]; + ctx->regs->nip += 4; + return; + } + if ((insn & 0xfc1f07ff) == 0x7c0004be) /*mffgpr */ + { + unsigned long *regs = (unsigned long *) ctx->regs; + unsigned fpr = (insn >> 21) & 0x1f; + unsigned gpr = (insn >> 11) & 0x1f; + regs[fpr + 0x30] = regs[gpr]; + ctx->regs->nip += 4; + return; + } +#endif + if ((insn & 0xfc1f073f) == 0xfc000310) /* fri[pznm] */ + { +#ifdef __powerpc64__ + double *regs = (double *) (((char *) ctx->regs) + 0x30 * 8); + unsigned int *fpscr = (unsigned int *) (((char *) ctx->regs) + 0x50 * 8 + 4); +#else + double *regs = (double *) (((char *) ctx->regs) + 0x30 * 4); + unsigned int *fpscr = (unsigned int *) (((char *) ctx->regs) + 0x30 * 4 + 0x20 * 8 + 4); +#endif + unsigned dest = (insn >> 21) & 0x1f; + unsigned src = (insn >> 11) & 0x1f; + switch (insn & 0xc0) + { + case 0: + regs[dest] = frin (regs[src]); + break; + case 0x40: + regs[dest] = friz (regs[src]); + break; + case 0x80: + regs[dest] = frip (regs[src]); + break; + case 0xc0: + regs[dest] = frim (regs[src]); + break; + } + /* Update raised exceptions. */ + union { unsigned int i[2]; double d; } u; + asm volatile ("mffs %0" : "=f" (u.d)); + u.i[1] &= 0xfffe0000; /* Is this correct? */ + *fpscr |= u.i[1]; + ctx->regs->nip += 4; + return; + } + if ((insn & 0xfc00ffff) == 0x7c0000f4) /* popcntb */ + { + unsigned long *regs = (unsigned long *) ctx->regs; + unsigned dest = (insn >> 16) & 0x1f; + unsigned src = (insn >> 21) & 0x1f; + unsigned long res = 0; + int i; + + regs[dest] = popcntb (regs[src]); + ctx->regs->nip += 4; + return; + } + + struct sigaction sa; + sa.sa_handler = SIG_DFL; + sigemptyset (&sa.sa_mask); + sa.sa_flags = 0; + sigaction (signal, &sa, NULL); + raise (signal); +} + +static void +__attribute__ ((constructor)) +install_handler (void) +{ + struct sigaction sa; + sa.sa_handler = (void *) catch_sigill; + sigemptyset (&sa.sa_mask); + sa.sa_flags = SA_RESTART; + sigaction (SIGILL, &sa, NULL); +} diff --git a/SOURCES/wrap-find-debuginfo.sh b/SOURCES/wrap-find-debuginfo.sh new file mode 100755 index 0000000..8479217 --- /dev/null +++ b/SOURCES/wrap-find-debuginfo.sh @@ -0,0 +1,145 @@ +#!/bin/bash +# Wrapper script for find-debuginfo.sh +# +# Usage: +# wrap-find-debuginfo.sh SYSROOT-PATH SCRIPT-PATH SCRIPT-ARGS... +# +# The wrapper saves the original version of ld.so found in SYSROOT-PATH, +# invokes SCRIPT-PATH with SCRIPT-ARGS, and then restores the +# LDSO-PATH file, followed by note merging and DWZ compression. +# As a result, ld.so has (mostly) unchanged debuginfo even +# after debuginfo extraction. +# +# For libc.so.6 and other shared objects, a set of strategic symbols +# is preserved in .symtab that are frequently used in valgrind +# suppressions and elsewhere. + +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 + debugedit=debugedit +else + debugedit=/usr/lib/rpm/debugedit +fi + +cleanup () { + rm -f "$tar_tmp" ${libc_dlink_tmp_list[@]} $ldso_annobin_sym_tmp_list +} +trap cleanup 0 + +sysroot_path="$1" +shift +script_path="$1" +shift + +# See run_ldso setting in glibc.spec. +ldso_list=`cd "$sysroot_path"; find . -name 'ld-*.so' -type f` +libc_list=`cd "$sysroot_path"; find . -name 'libc-*.so' -type f` +libdl_list=`cd "$sysroot_path"; find . -name 'libdl-*.so' -type f` +libpthread_list=`cd "$sysroot_path"; find . -name 'libpthread-*.so' -type f` +librt_list=`cd "$sysroot_path"; find . -name 'librt-*.so' -type f` + +full_list="$ldso_list $libc_list $libdl_list $libpthread_list $librt_list" + +# Preserve the original files. +(cd "$sysroot_path"; ls -l $full_list) +(cd "$sysroot_path"; tar cvf "$tar_tmp" $full_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) + +# Reduce the size of notes. Primarily for annobin. +for p in $full_list +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 +# like to remove __GI_* symbols, but even listing them explicitly (as +# in -K __GI_strlen) still causes strip to remove them, so there is no +# filtering of __GI_* here. (Debuginfo is gone after this, so no need +# to optimize it.) +for p in $libc_list $libdl_list $libpthread_list $librt_list ; do + strip -w \ + -K '*' \ + -K '!*.c' \ + -K '!*.os' \ + -K '!.annobin_*' \ + -K '!__EI_*' \ + -K '!__PRETTY_FUNCTION__*' \ + "$sysroot_path/$p" +done + +# ld.so: Rewrite the source file paths to match the extracted +# locations. First compute the arguments for invoking debugedit. +# See find-debuginfo.sh. +debug_dest_name="/usr/src/debug" +last_arg= +while true ; do + arg="$1" + shift || break + case "$arg" in + (--unique-debug-src-base) + debug_dest_name="/usr/src/debug/$1" + shift + ;; + (-*) + ;; + (*) + last_arg="$arg" + ;; + esac +done +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. +for ldso in $ldso_list +do + dwz "$sysroot_path/$p" +done diff --git a/SPECS/glibc.spec b/SPECS/glibc.spec new file mode 100644 index 0000000..a364980 --- /dev/null +++ b/SPECS/glibc.spec @@ -0,0 +1,4536 @@ +%define glibcsrcdir glibc-2.28 +%define glibcversion 2.28 +%define glibcrelease 251%{?dist} +# Pre-release tarballs are pulled in from git using a command that is +# effectively: +# +# git archive HEAD --format=tar --prefix=$(git describe --match 'glibc-*')/ \ +# > $(git describe --match 'glibc-*').tar +# gzip -9 $(git describe --match 'glibc-*').tar +# +# glibc_release_url is only defined when we have a release tarball. +%{lua: if string.match(rpm.expand("%glibcsrcdir"), "^glibc%-[0-9.]+$") then + rpm.define("glibc_release_url https://ftp.gnu.org/gnu/glibc/") end} +############################################################################## +# We support the following options: +# --with/--without, +# * testsuite - Running the testsuite. +# * benchtests - Running and building benchmark subpackage. +# * bootstrap - Bootstrapping the package. +# * werror - Build with -Werror +# * docs - Build with documentation and the required dependencies. +# * valgrind - Run smoke tests with valgrind to verify dynamic loader. +# +# You must always run the testsuite for production builds. +# Default: Always run the testsuite. +%bcond_without testsuite +# Default: Always build the benchtests. +%bcond_without benchtests +# Default: Not bootstrapping. +%bcond_with bootstrap +# Default: Enable using -Werror +%bcond_without werror +# Default: Always build documentation. +%bcond_without docs + +# Default: Always run valgrind tests if there is architecture support. +%ifarch %{valgrind_arches} +%bcond_without valgrind +%else +%bcond_with valgrind +%endif +# Restrict %%{valgrind_arches} further in case there are problems with +# the smoke test. +%if %{with valgrind} +%ifarch ppc64 ppc64p7 +# The valgrind smoke test does not work on ppc64, ppc64p7 (bug 1273103). +%undefine with_valgrind +%endif +%endif + +%if %{with bootstrap} +# Disable benchtests, -Werror, docs, and valgrind if we're bootstrapping +%undefine with_benchtests +%undefine with_werror +%undefine with_docs +%undefine with_valgrind +%endif +############################################################################## +# Auxiliary arches are those arches that can be built in addition +# to the core supported arches. You either install an auxarch or +# you install the base arch, not both. You would do this in order +# to provide a more optimized version of the package for your arch. +%define auxarches athlon alphaev6 + +# Only some architectures have static PIE support. +%define pie_arches %{ix86} x86_64 + +# Build the POWER9 runtime on POWER, but only for downstream. +%ifarch ppc64le +%define buildpower9 0%{?rhel} > 0 +%else +%define buildpower9 0 +%endif + +# RHEL 8 does not have a working %%dnl macro. +%define comment() %{nil} + +############################################################################## +# Any architecture/kernel combination that supports running 32-bit and 64-bit +# code in userspace is considered a biarch arch. +%define biarcharches %{ix86} x86_64 %{power64} s390 s390x +############################################################################## +# If the debug information is split into two packages, the core debuginfo +# pacakge and the common debuginfo package then the arch should be listed +# here. If the arch is not listed here then a single core debuginfo package +# will be created for the architecture. +%define debuginfocommonarches %{biarcharches} alpha alphaev6 + +############################################################################## +# Utility functions for pre/post scripts. Stick them at the beginning of +# any lua %pre, %post, %postun, etc. sections to have them expand into +# those scripts. It only works in lua sections and not anywhere else. +%define glibc_post_funcs() \ +-- We use lua posix.exec because there may be no shell that we can \ +-- run during glibc upgrade. We used to implement much of %%post as a \ +-- C program, but from an overall maintenance perspective the lua in \ +-- the spec file was simpler and safer given the operations required. \ +-- All lua code will be ignored by rpm-ostree; see: \ +-- https://github.com/projectatomic/rpm-ostree/pull/1869 \ +-- If we add new lua actions to the %%post code we should coordinate \ +-- with rpm-ostree and ensure that their glibc install is functional. \ +function post_exec (program, ...) \ + local pid = posix.fork () \ + if pid == 0 then \ + posix.exec (program, ...) \ + assert (nil) \ + elseif pid > 0 then \ + posix.wait (pid) \ + end \ +end \ +\ +function update_gconv_modules_cache () \ + local iconv_dir = "%{_libdir}/gconv" \ + local iconv_cache = iconv_dir .. "/gconv-modules.cache" \ + local iconv_modules = iconv_dir .. "/gconv-modules" \ + if (posix.utime (iconv_modules) == 0) then \ + if (posix.utime (iconv_cache) == 0) then \ + post_exec ("%{_prefix}/sbin/iconvconfig", \ + "-o", iconv_cache, \ + "--nostdlib", \ + iconv_dir) \ + else \ + io.stdout:write ("Error: Missing " .. iconv_cache .. " file.\n") \ + end \ + end \ +end \ +%{nil} + +############################################################################## +# %%package glibc - The GNU C Library (glibc) core package. +############################################################################## +Summary: The GNU libc libraries +Name: glibc +Version: %{glibcversion} +Release: %{glibcrelease} + +# In general, GPLv2+ is used by programs, LGPLv2+ is used for +# libraries. +# +# LGPLv2+ with exceptions is used for things that are linked directly +# into dynamically linked programs and shared libraries (e.g. crt +# files, lib*_nonshared.a). Historically, this exception also applies +# to parts of libio. +# +# GPLv2+ with exceptions is used for parts of the Arm unwinder. +# +# GFDL is used for the documentation. +# +# Some other licenses are used in various places (BSD, Inner-Net, +# ISC, Public Domain). +# +# HSRL and FSFAP are only used in test cases, which currently do not +# ship in binary RPMs, so they are not listed here. MIT is used for +# scripts/install-sh, which does not ship, either. +# +# GPLv3+ is used by manual/texinfo.tex, which we do not use. +# +# LGPLv3+ is used by some Hurd code, which we do not build. +# +# LGPLv2 is used in one place (time/timespec_get.c, by mistake), but +# it is not actually compiled, so it does not matter for libraries. +License: LGPLv2+ and LGPLv2+ with exceptions and GPLv2+ and GPLv2+ with exceptions and BSD and Inner-Net and ISC and Public Domain and GFDL + +URL: http://www.gnu.org/software/glibc/ +Source0: %{?glibc_release_url}%{glibcsrcdir}.tar.xz +Source1: build-locale-archive.c +Source4: nscd.conf +Source8: power6emul.c +Source9: bench.mk +Source10: glibc-bench-compare +# A copy of localedata/SUPPORTED in the Source0 tarball. The +# SUPPORTED file is used below to generate the list of locale +# packages, using a Lua snippet. +Source11: SUPPORTED + +# Include in the source RPM for reference. +Source12: ChangeLog.old + +Source13: wrap-find-debuginfo.sh + +###################################################################### +# Activate the wrapper script for debuginfo generation, by rewriting +# the definition of __debug_install_post. +%{lua: +local wrapper = rpm.expand("%{SOURCE13}") +local sysroot = rpm.expand("%{glibc_sysroot}") +local original = rpm.expand("%{__find_debuginfo}") +rpm.define("__find_debuginfo " .. wrapper .. " " .. sysroot .. " " .. original) +} + +# The wrapper script relies on the fact that debugedit does not change +# build IDs. +%define _no_recompute_build_ids 1 +%undefine _unique_build_ids + +############################################################################## +# Patches: +# - See each individual patch file for origin and upstream status. +# - For new patches follow template.patch format. +############################################################################## +Patch2: glibc-fedora-nscd.patch +Patch3: glibc-rh697421.patch +Patch4: glibc-fedora-linux-tcsetattr.patch +Patch5: glibc-rh741105.patch +Patch6: glibc-fedora-localedef.patch +Patch7: glibc-fedora-nis-rh188246.patch +Patch8: glibc-fedora-manual-dircategory.patch +Patch9: glibc-rh827510.patch +Patch10: glibc-fedora-locarchive.patch +Patch11: glibc-fedora-streams-rh436349.patch +Patch12: glibc-rh819430.patch +Patch13: glibc-fedora-localedata-rh61908.patch +Patch14: glibc-fedora-__libc_multiple_libcs.patch +Patch15: glibc-rh1070416.patch +Patch16: glibc-nscd-sysconfig.patch +Patch17: glibc-cs-path.patch +Patch18: glibc-c-utf8-locale.patch +Patch23: glibc-python3.patch +Patch24: glibc-with-nonshared-cflags.patch +Patch25: glibc-asflags.patch +Patch27: glibc-rh1614253.patch +Patch28: glibc-rh1577365.patch +Patch29: glibc-rh1615781.patch +Patch30: glibc-rh1615784.patch +Patch31: glibc-rh1615790.patch +Patch32: glibc-rh1622675.patch +Patch33: glibc-rh1622678-1.patch +Patch34: glibc-rh1622678-2.patch +Patch35: glibc-rh1631293-1.patch +Patch36: glibc-rh1631293-2.patch +Patch37: glibc-rh1623536.patch +Patch38: glibc-rh1631722.patch +Patch39: glibc-rh1631730.patch +Patch40: glibc-rh1623536-2.patch +Patch41: glibc-rh1614979.patch +Patch42: glibc-rh1645593.patch +Patch43: glibc-rh1645596.patch +Patch44: glibc-rh1645604.patch +Patch45: glibc-rh1646379.patch +Patch46: glibc-rh1645601.patch +Patch52: glibc-rh1638523-1.patch +Patch47: glibc-rh1638523-2.patch +Patch48: glibc-rh1638523-3.patch +Patch49: glibc-rh1638523-4.patch +Patch50: glibc-rh1638523-5.patch +Patch51: glibc-rh1638523-6.patch +Patch53: glibc-rh1641982.patch +Patch54: glibc-rh1645597.patch +Patch55: glibc-rh1650560-1.patch +Patch56: glibc-rh1650560-2.patch +Patch57: glibc-rh1650563.patch +Patch58: glibc-rh1650566.patch +Patch59: glibc-rh1650571.patch +Patch60: glibc-rh1638520.patch +Patch61: glibc-rh1651274.patch +Patch62: glibc-rh1654010-1.patch +Patch63: glibc-rh1635779.patch +Patch64: glibc-rh1654010-2.patch +Patch65: glibc-rh1654010-3.patch +Patch66: glibc-rh1654010-4.patch +Patch67: glibc-rh1654010-5.patch +Patch68: glibc-rh1654010-6.patch +Patch69: glibc-rh1642094-1.patch +Patch70: glibc-rh1642094-2.patch +Patch71: glibc-rh1642094-3.patch +Patch72: glibc-rh1654872-1.patch +Patch73: glibc-rh1654872-2.patch +Patch74: glibc-rh1651283-1.patch +Patch75: glibc-rh1662843-1.patch +Patch76: glibc-rh1662843-2.patch +Patch77: glibc-rh1623537.patch +Patch78: glibc-rh1577438.patch +Patch79: glibc-rh1664408.patch +Patch80: glibc-rh1651742.patch +Patch81: glibc-rh1672773.patch +Patch82: glibc-rh1651283-2.patch +Patch83: glibc-rh1651283-3.patch +Patch84: glibc-rh1651283-4.patch +Patch85: glibc-rh1651283-5.patch +Patch86: glibc-rh1651283-6.patch +Patch87: glibc-rh1651283-7.patch +Patch88: glibc-rh1659293-1.patch +Patch89: glibc-rh1659293-2.patch +Patch90: glibc-rh1639343-1.patch +Patch91: glibc-rh1639343-2.patch +Patch92: glibc-rh1639343-3.patch +Patch93: glibc-rh1639343-4.patch +Patch94: glibc-rh1639343-5.patch +Patch95: glibc-rh1639343-6.patch +Patch96: glibc-rh1663035.patch +Patch97: glibc-rh1658901.patch +Patch98: glibc-rh1659512-1.patch +Patch99: glibc-rh1659512-2.patch +Patch100: glibc-rh1659438-1.patch +Patch101: glibc-rh1659438-2.patch +Patch102: glibc-rh1659438-3.patch +Patch103: glibc-rh1659438-4.patch +Patch104: glibc-rh1659438-5.patch +Patch105: glibc-rh1659438-6.patch +Patch106: glibc-rh1659438-7.patch +Patch107: glibc-rh1659438-8.patch +Patch108: glibc-rh1659438-9.patch +Patch109: glibc-rh1659438-10.patch +Patch110: glibc-rh1659438-11.patch +Patch111: glibc-rh1659438-12.patch +Patch112: glibc-rh1659438-13.patch +Patch113: glibc-rh1659438-14.patch +Patch114: glibc-rh1659438-15.patch +Patch115: glibc-rh1659438-16.patch +Patch116: glibc-rh1659438-17.patch +Patch117: glibc-rh1659438-18.patch +Patch118: glibc-rh1659438-19.patch +Patch119: glibc-rh1659438-20.patch +Patch120: glibc-rh1659438-21.patch +Patch121: glibc-rh1659438-22.patch +Patch122: glibc-rh1659438-23.patch +Patch123: glibc-rh1659438-24.patch +Patch124: glibc-rh1659438-25.patch +Patch125: glibc-rh1659438-26.patch +Patch126: glibc-rh1659438-27.patch +Patch127: glibc-rh1659438-28.patch +Patch128: glibc-rh1659438-29.patch +Patch129: glibc-rh1659438-30.patch +Patch130: glibc-rh1659438-31.patch +Patch131: glibc-rh1659438-32.patch +Patch132: glibc-rh1659438-33.patch +Patch133: glibc-rh1659438-34.patch +Patch134: glibc-rh1659438-35.patch +Patch135: glibc-rh1659438-36.patch +Patch136: glibc-rh1659438-37.patch +Patch137: glibc-rh1659438-38.patch +Patch138: glibc-rh1659438-39.patch +Patch139: glibc-rh1659438-40.patch +Patch140: glibc-rh1659438-41.patch +Patch141: glibc-rh1659438-42.patch +Patch142: glibc-rh1659438-43.patch +Patch143: glibc-rh1659438-44.patch +Patch144: glibc-rh1659438-45.patch +Patch145: glibc-rh1659438-46.patch +Patch146: glibc-rh1659438-47.patch +Patch147: glibc-rh1659438-48.patch +Patch148: glibc-rh1659438-49.patch +Patch149: glibc-rh1659438-50.patch +Patch150: glibc-rh1659438-51.patch +Patch151: glibc-rh1659438-52.patch +Patch152: glibc-rh1659438-53.patch +Patch153: glibc-rh1659438-54.patch +Patch154: glibc-rh1659438-55.patch +Patch155: glibc-rh1659438-56.patch +Patch156: glibc-rh1659438-57.patch +Patch157: glibc-rh1659438-58.patch +Patch158: glibc-rh1659438-59.patch +Patch159: glibc-rh1659438-60.patch +Patch160: glibc-rh1659438-61.patch +Patch161: glibc-rh1659438-62.patch +Patch162: glibc-rh1702539-1.patch +Patch163: glibc-rh1702539-2.patch +Patch164: glibc-rh1701605-1.patch +Patch165: glibc-rh1701605-2.patch +Patch166: glibc-rh1691528-1.patch +Patch167: glibc-rh1691528-2.patch +Patch168: glibc-rh1706777.patch +Patch169: glibc-rh1710478.patch +Patch170: glibc-rh1670043-1.patch +Patch171: glibc-rh1670043-2.patch +Patch172: glibc-rh1710894.patch +Patch173: glibc-rh1699194-1.patch +Patch174: glibc-rh1699194-2.patch +Patch175: glibc-rh1699194-3.patch +Patch176: glibc-rh1699194-4.patch +Patch177: glibc-rh1727241-1.patch +Patch178: glibc-rh1727241-2.patch +Patch179: glibc-rh1727241-3.patch +Patch180: glibc-rh1717438.patch +Patch181: glibc-rh1727152.patch +Patch182: glibc-rh1724975.patch +Patch183: glibc-rh1722215.patch +Patch184: glibc-rh1764234-1.patch +Patch185: glibc-rh1764234-2.patch +Patch186: glibc-rh1764234-3.patch +Patch187: glibc-rh1764234-4.patch +Patch188: glibc-rh1764234-5.patch +Patch189: glibc-rh1764234-6.patch +Patch190: glibc-rh1764234-7.patch +Patch191: glibc-rh1764234-8.patch +Patch192: glibc-rh1747505-1.patch +Patch193: glibc-rh1747505-2.patch +Patch194: glibc-rh1747505-3.patch +Patch195: glibc-rh1747505-4.patch +Patch196: glibc-rh1747453.patch +Patch197: glibc-rh1764241.patch +Patch198: glibc-rh1746933-1.patch +Patch199: glibc-rh1746933-2.patch +Patch200: glibc-rh1746933-3.patch +Patch201: glibc-rh1735747-1.patch +Patch202: glibc-rh1735747-2.patch +Patch203: glibc-rh1764226-1.patch +Patch204: glibc-rh1764226-2.patch +Patch205: glibc-rh1764226-3.patch +Patch206: glibc-rh1764218-1.patch +Patch207: glibc-rh1764218-2.patch +Patch208: glibc-rh1764218-3.patch +Patch209: glibc-rh1682954.patch +Patch210: glibc-rh1746928.patch +Patch211: glibc-rh1747502.patch +Patch212: glibc-rh1747502-1.patch +Patch213: glibc-rh1747502-2.patch +Patch214: glibc-rh1747502-3.patch +Patch215: glibc-rh1747502-4.patch +Patch216: glibc-rh1747502-5.patch +Patch217: glibc-rh1747502-6.patch +Patch218: glibc-rh1747502-7.patch +Patch219: glibc-rh1747502-8.patch +Patch220: glibc-rh1747502-9.patch +Patch221: glibc-rh1726638-1.patch +Patch222: glibc-rh1726638-2.patch +Patch223: glibc-rh1726638-3.patch +Patch224: glibc-rh1764238-1.patch +Patch225: glibc-rh1764238-2.patch +Patch226: glibc-rh1764242.patch +Patch227: glibc-rh1769304.patch +Patch228: glibc-rh1749439-1.patch +Patch229: glibc-rh1749439-2.patch +Patch230: glibc-rh1749439-3.patch +Patch231: glibc-rh1749439-4.patch +Patch232: glibc-rh1749439-5.patch +Patch233: glibc-rh1749439-6.patch +Patch234: glibc-rh1749439-7.patch +Patch235: glibc-rh1749439-8.patch +Patch236: glibc-rh1749439-9.patch +Patch237: glibc-rh1749439-10.patch +Patch238: glibc-rh1749439-11.patch +Patch239: glibc-rh1749439-12.patch +Patch240: glibc-rh1749439-13.patch +Patch241: glibc-rh1764231-1.patch +Patch242: glibc-rh1764231-2.patch +Patch243: glibc-rh1764235.patch +Patch244: glibc-rh1361965.patch +Patch245: glibc-rh1764223.patch +Patch246: glibc-rh1764214.patch +Patch247: glibc-rh1774021.patch +Patch248: glibc-rh1775294.patch +Patch249: glibc-rh1777241.patch +Patch250: glibc-rh1410154-1.patch +Patch251: glibc-rh1410154-2.patch +Patch252: glibc-rh1410154-3.patch +Patch253: glibc-rh1410154-4.patch +Patch254: glibc-rh1410154-5.patch +Patch255: glibc-rh1410154-6.patch +Patch256: glibc-rh1410154-7.patch +Patch257: glibc-rh1410154-8.patch +Patch258: glibc-rh1410154-9.patch +Patch259: glibc-rh1410154-10.patch +Patch260: glibc-rh1410154-11.patch +Patch261: glibc-rh1410154-12.patch +Patch262: glibc-rh1410154-13.patch +Patch263: glibc-rh1410154-14.patch +Patch264: glibc-rh1410154-15.patch +Patch265: glibc-rh1410154-16.patch +Patch266: glibc-rh1810142-1.patch +Patch267: glibc-rh1810142-2.patch +Patch268: glibc-rh1810142-3.patch +Patch269: glibc-rh1810142-4.patch +Patch270: glibc-rh1810142-5.patch +Patch271: glibc-rh1810142-6.patch +Patch272: glibc-rh1743445-1.patch +Patch273: glibc-rh1743445-2.patch +Patch274: glibc-rh1780204-01.patch +Patch275: glibc-rh1780204-02.patch +Patch276: glibc-rh1780204-03.patch +Patch277: glibc-rh1780204-04.patch +Patch278: glibc-rh1780204-05.patch +Patch279: glibc-rh1780204-06.patch +Patch280: glibc-rh1780204-07.patch +Patch281: glibc-rh1780204-08.patch +Patch282: glibc-rh1780204-09.patch +Patch283: glibc-rh1780204-10.patch +Patch284: glibc-rh1780204-11.patch +Patch285: glibc-rh1780204-12.patch +Patch286: glibc-rh1780204-13.patch +Patch287: glibc-rh1780204-14.patch +Patch288: glibc-rh1780204-15.patch +Patch289: glibc-rh1780204-16.patch +Patch290: glibc-rh1780204-17.patch +Patch291: glibc-rh1780204-18.patch +Patch292: glibc-rh1780204-19.patch +Patch293: glibc-rh1780204-20.patch +Patch294: glibc-rh1780204-21.patch +Patch295: glibc-rh1780204-22.patch +Patch296: glibc-rh1780204-23.patch +Patch297: glibc-rh1780204-24.patch +Patch298: glibc-rh1780204-25.patch +Patch299: glibc-rh1780204-26.patch +Patch300: glibc-rh1780204-27.patch +Patch301: glibc-rh1780204-28.patch +Patch302: glibc-rh1784519.patch +Patch303: glibc-rh1775819.patch +Patch304: glibc-rh1774114.patch +Patch305: glibc-rh1812756-1.patch +Patch306: glibc-rh1812756-2.patch +Patch307: glibc-rh1812756-3.patch +Patch308: glibc-rh1757354.patch +Patch309: glibc-rh1784520.patch +Patch310: glibc-rh1784525.patch +Patch311: glibc-rh1810146.patch +Patch312: glibc-rh1810223-1.patch +Patch313: glibc-rh1810223-2.patch +Patch314: glibc-rh1811796-1.patch +Patch315: glibc-rh1811796-2.patch +Patch316: glibc-rh1813398.patch +Patch317: glibc-rh1813399.patch +Patch318: glibc-rh1810224-1.patch +Patch319: glibc-rh1810224-2.patch +Patch320: glibc-rh1810224-3.patch +Patch321: glibc-rh1810224-4.patch +Patch322: glibc-rh1783303-1.patch +Patch323: glibc-rh1783303-2.patch +Patch324: glibc-rh1783303-3.patch +Patch325: glibc-rh1783303-4.patch +Patch326: glibc-rh1783303-5.patch +Patch327: glibc-rh1783303-6.patch +Patch328: glibc-rh1783303-7.patch +Patch329: glibc-rh1783303-8.patch +Patch330: glibc-rh1783303-9.patch +Patch331: glibc-rh1783303-10.patch +Patch332: glibc-rh1783303-11.patch +Patch333: glibc-rh1783303-12.patch +Patch334: glibc-rh1783303-13.patch +Patch335: glibc-rh1783303-14.patch +Patch336: glibc-rh1783303-15.patch +Patch337: glibc-rh1783303-16.patch +Patch338: glibc-rh1783303-17.patch +Patch339: glibc-rh1783303-18.patch +Patch340: glibc-rh1642150-1.patch +Patch341: glibc-rh1642150-2.patch +Patch342: glibc-rh1642150-3.patch +Patch343: glibc-rh1774115.patch +Patch344: glibc-rh1780204-29.patch +Patch345: glibc-rh1748197-1.patch +Patch346: glibc-rh1748197-2.patch +Patch347: glibc-rh1748197-3.patch +Patch348: glibc-rh1748197-4.patch +Patch349: glibc-rh1748197-5.patch +Patch350: glibc-rh1748197-6.patch +Patch351: glibc-rh1748197-7.patch +Patch352: glibc-rh1642150-4.patch +Patch353: glibc-rh1836867.patch +Patch354: glibc-rh1821531-1.patch +Patch355: glibc-rh1821531-2.patch +Patch356: glibc-rh1845098-1.patch +Patch357: glibc-rh1845098-2.patch +Patch358: glibc-rh1845098-3.patch +Patch359: glibc-rh1871387-1.patch +Patch360: glibc-rh1871387-2.patch +Patch361: glibc-rh1871387-3.patch +Patch362: glibc-rh1871387-4.patch +Patch363: glibc-rh1871387-5.patch +Patch364: glibc-rh1871387-6.patch +Patch365: glibc-rh1871394-1.patch +Patch366: glibc-rh1871394-2.patch +Patch367: glibc-rh1871394-3.patch +Patch368: glibc-rh1871395-1.patch +Patch369: glibc-rh1871395-2.patch +Patch370: glibc-rh1871397-1.patch +Patch371: glibc-rh1871397-2.patch +Patch372: glibc-rh1871397-3.patch +Patch373: glibc-rh1871397-4.patch +Patch374: glibc-rh1871397-5.patch +Patch375: glibc-rh1871397-6.patch +Patch376: glibc-rh1871397-7.patch +Patch377: glibc-rh1871397-8.patch +Patch378: glibc-rh1871397-9.patch +Patch379: glibc-rh1871397-10.patch +Patch380: glibc-rh1871397-11.patch +Patch381: glibc-rh1880670.patch +Patch382: glibc-rh1868106-1.patch +Patch383: glibc-rh1868106-2.patch +Patch384: glibc-rh1868106-3.patch +Patch385: glibc-rh1868106-4.patch +Patch386: glibc-rh1868106-5.patch +Patch387: glibc-rh1868106-6.patch +Patch388: glibc-rh1856398.patch +Patch389: glibc-rh1880670-2.patch +Patch390: glibc-rh1704868-1.patch +Patch391: glibc-rh1704868-2.patch +Patch392: glibc-rh1704868-3.patch +Patch393: glibc-rh1704868-4.patch +Patch394: glibc-rh1704868-5.patch +Patch395: glibc-rh1893662-1.patch +Patch396: glibc-rh1893662-2.patch +Patch397: glibc-rh1855790-1.patch +Patch398: glibc-rh1855790-2.patch +Patch399: glibc-rh1855790-3.patch +Patch400: glibc-rh1855790-4.patch +Patch401: glibc-rh1855790-5.patch +Patch402: glibc-rh1855790-6.patch +Patch403: glibc-rh1855790-7.patch +Patch404: glibc-rh1855790-8.patch +Patch405: glibc-rh1855790-9.patch +Patch406: glibc-rh1855790-10.patch +Patch407: glibc-rh1855790-11.patch +Patch408: glibc-rh1817513-1.patch +Patch409: glibc-rh1817513-2.patch +Patch410: glibc-rh1817513-3.patch +Patch411: glibc-rh1817513-4.patch +Patch412: glibc-rh1817513-5.patch +Patch413: glibc-rh1817513-6.patch +Patch414: glibc-rh1817513-7.patch +Patch415: glibc-rh1817513-8.patch +Patch416: glibc-rh1817513-9.patch +Patch417: glibc-rh1817513-10.patch +Patch418: glibc-rh1817513-11.patch +Patch419: glibc-rh1817513-12.patch +Patch420: glibc-rh1817513-13.patch +Patch421: glibc-rh1817513-14.patch +Patch422: glibc-rh1817513-15.patch +Patch423: glibc-rh1817513-16.patch +Patch424: glibc-rh1817513-17.patch +Patch425: glibc-rh1817513-18.patch +Patch426: glibc-rh1817513-19.patch +Patch427: glibc-rh1817513-20.patch +Patch428: glibc-rh1817513-21.patch +Patch429: glibc-rh1817513-22.patch +Patch430: glibc-rh1817513-23.patch +Patch431: glibc-rh1817513-24.patch +Patch432: glibc-rh1817513-25.patch +Patch433: glibc-rh1817513-26.patch +Patch434: glibc-rh1817513-27.patch +Patch435: glibc-rh1817513-28.patch +Patch436: glibc-rh1817513-29.patch +Patch437: glibc-rh1817513-30.patch +Patch438: glibc-rh1817513-31.patch +Patch439: glibc-rh1817513-32.patch +Patch440: glibc-rh1817513-33.patch +Patch441: glibc-rh1817513-34.patch +Patch442: glibc-rh1817513-35.patch +Patch443: glibc-rh1817513-36.patch +Patch444: glibc-rh1817513-37.patch +Patch445: glibc-rh1817513-38.patch +Patch446: glibc-rh1817513-39.patch +Patch447: glibc-rh1817513-40.patch +Patch448: glibc-rh1817513-41.patch +Patch449: glibc-rh1817513-42.patch +Patch450: glibc-rh1817513-43.patch +Patch451: glibc-rh1817513-44.patch +Patch452: glibc-rh1817513-45.patch +Patch453: glibc-rh1817513-46.patch +Patch454: glibc-rh1817513-47.patch +Patch455: glibc-rh1817513-48.patch +Patch456: glibc-rh1817513-49.patch +Patch457: glibc-rh1817513-50.patch +Patch458: glibc-rh1817513-51.patch +Patch459: glibc-rh1817513-52.patch +Patch460: glibc-rh1817513-53.patch +Patch461: glibc-rh1817513-54.patch +Patch462: glibc-rh1817513-55.patch +Patch463: glibc-rh1817513-56.patch +Patch464: glibc-rh1817513-57.patch +Patch465: glibc-rh1817513-58.patch +Patch466: glibc-rh1817513-59.patch +Patch467: glibc-rh1817513-60.patch +Patch468: glibc-rh1817513-61.patch +Patch469: glibc-rh1817513-62.patch +Patch470: glibc-rh1817513-63.patch +Patch471: glibc-rh1817513-64.patch +Patch472: glibc-rh1817513-65.patch +Patch473: glibc-rh1817513-66.patch +Patch474: glibc-rh1817513-67.patch +Patch475: glibc-rh1817513-68.patch +Patch476: glibc-rh1817513-69.patch +Patch477: glibc-rh1817513-70.patch +Patch478: glibc-rh1817513-71.patch +Patch479: glibc-rh1817513-72.patch +Patch480: glibc-rh1817513-73.patch +Patch481: glibc-rh1817513-74.patch +Patch482: glibc-rh1817513-75.patch +Patch483: glibc-rh1817513-76.patch +Patch484: glibc-rh1817513-77.patch +Patch485: glibc-rh1817513-78.patch +Patch486: glibc-rh1817513-79.patch +Patch487: glibc-rh1817513-80.patch +Patch488: glibc-rh1817513-81.patch +Patch489: glibc-rh1817513-82.patch +Patch490: glibc-rh1817513-83.patch +Patch491: glibc-rh1817513-84.patch +Patch492: glibc-rh1817513-85.patch +Patch493: glibc-rh1817513-86.patch +Patch494: glibc-rh1817513-87.patch +Patch495: glibc-rh1817513-88.patch +Patch496: glibc-rh1817513-89.patch +Patch497: glibc-rh1817513-90.patch +Patch498: glibc-rh1817513-91.patch +Patch499: glibc-rh1817513-92.patch +Patch500: glibc-rh1817513-93.patch +Patch501: glibc-rh1817513-94.patch +Patch502: glibc-rh1817513-95.patch +Patch503: glibc-rh1817513-96.patch +Patch504: glibc-rh1817513-97.patch +Patch505: glibc-rh1817513-98.patch +Patch506: glibc-rh1817513-99.patch +Patch507: glibc-rh1817513-100.patch +Patch508: glibc-rh1817513-101.patch +Patch509: glibc-rh1817513-102.patch +Patch510: glibc-rh1817513-103.patch +Patch511: glibc-rh1817513-104.patch +Patch512: glibc-rh1817513-105.patch +Patch513: glibc-rh1817513-106.patch +Patch514: glibc-rh1817513-107.patch +Patch515: glibc-rh1817513-108.patch +Patch516: glibc-rh1817513-109.patch +Patch517: glibc-rh1817513-110.patch +Patch518: glibc-rh1817513-111.patch +Patch519: glibc-rh1817513-112.patch +Patch520: glibc-rh1817513-113.patch +Patch521: glibc-rh1817513-114.patch +Patch522: glibc-rh1817513-115.patch +Patch523: glibc-rh1817513-116.patch +Patch524: glibc-rh1817513-117.patch +Patch525: glibc-rh1817513-118.patch +Patch526: glibc-rh1817513-119.patch +Patch527: glibc-rh1817513-120.patch +Patch528: glibc-rh1817513-121.patch +Patch529: glibc-rh1817513-122.patch +Patch530: glibc-rh1817513-123.patch +Patch531: glibc-rh1817513-124.patch +Patch532: glibc-rh1817513-125.patch +Patch533: glibc-rh1817513-126.patch +Patch534: glibc-rh1817513-127.patch +Patch535: glibc-rh1817513-128.patch +Patch536: glibc-rh1817513-129.patch +Patch537: glibc-rh1817513-130.patch +Patch538: glibc-rh1817513-131.patch +Patch539: glibc-rh1817513-132.patch +Patch540: glibc-rh1882466-1.patch +Patch541: glibc-rh1882466-2.patch +Patch542: glibc-rh1882466-3.patch +Patch543: glibc-rh1817513-133.patch +Patch544: glibc-rh1912544.patch +Patch545: glibc-rh1918115.patch +Patch546: glibc-rh1924919.patch +Patch547: glibc-rh1932770.patch +Patch548: glibc-rh1936864.patch +Patch549: glibc-rh1871386-1.patch +Patch550: glibc-rh1871386-2.patch +Patch551: glibc-rh1871386-3.patch +Patch552: glibc-rh1871386-4.patch +Patch553: glibc-rh1871386-5.patch +Patch554: glibc-rh1871386-6.patch +Patch555: glibc-rh1871386-7.patch +Patch556: glibc-rh1912670-1.patch +Patch557: glibc-rh1912670-2.patch +Patch558: glibc-rh1912670-3.patch +Patch559: glibc-rh1912670-4.patch +Patch560: glibc-rh1912670-5.patch +Patch561: glibc-rh1930302-1.patch +Patch562: glibc-rh1930302-2.patch +Patch563: glibc-rh1927877.patch +Patch564: glibc-rh1918719-1.patch +Patch565: glibc-rh1918719-2.patch +Patch566: glibc-rh1918719-3.patch +Patch567: glibc-rh1934155-1.patch +Patch568: glibc-rh1934155-2.patch +Patch569: glibc-rh1934155-3.patch +Patch570: glibc-rh1934155-4.patch +Patch571: glibc-rh1934155-5.patch +Patch572: glibc-rh1934155-6.patch +Patch573: glibc-rh1956357-1.patch +Patch574: glibc-rh1956357-2.patch +Patch575: glibc-rh1956357-3.patch +Patch576: glibc-rh1956357-4.patch +Patch577: glibc-rh1956357-5.patch +Patch578: glibc-rh1956357-6.patch +Patch579: glibc-rh1956357-7.patch +Patch580: glibc-rh1956357-8.patch +Patch581: glibc-rh1979127.patch +Patch582: glibc-rh1966472-1.patch +Patch583: glibc-rh1966472-2.patch +Patch584: glibc-rh1966472-3.patch +Patch585: glibc-rh1966472-4.patch +Patch586: glibc-rh1971664-1.patch +Patch587: glibc-rh1971664-2.patch +Patch588: glibc-rh1971664-3.patch +Patch589: glibc-rh1971664-4.patch +Patch590: glibc-rh1971664-5.patch +Patch591: glibc-rh1971664-6.patch +Patch592: glibc-rh1971664-7.patch +Patch593: glibc-rh1971664-8.patch +Patch594: glibc-rh1971664-9.patch +Patch595: glibc-rh1971664-10.patch +Patch596: glibc-rh1971664-11.patch +Patch597: glibc-rh1971664-12.patch +Patch598: glibc-rh1971664-13.patch +Patch599: glibc-rh1971664-14.patch +Patch600: glibc-rh1971664-15.patch +Patch601: glibc-rh1977614.patch +Patch602: glibc-rh1983203-1.patch +Patch603: glibc-rh1983203-2.patch +Patch604: glibc-rh2021452.patch +Patch605: glibc-rh1937515.patch +Patch606: glibc-rh1934162-1.patch +Patch607: glibc-rh1934162-2.patch +Patch608: glibc-rh2000374.patch +Patch609: glibc-rh1991001-1.patch +Patch610: glibc-rh1991001-2.patch +Patch611: glibc-rh1991001-3.patch +Patch612: glibc-rh1991001-4.patch +Patch613: glibc-rh1991001-5.patch +Patch614: glibc-rh1991001-6.patch +Patch615: glibc-rh1991001-7.patch +Patch616: glibc-rh1991001-8.patch +Patch617: glibc-rh1991001-9.patch +Patch618: glibc-rh1991001-10.patch +Patch619: glibc-rh1991001-11.patch +Patch620: glibc-rh1991001-12.patch +Patch621: glibc-rh1991001-13.patch +Patch622: glibc-rh1991001-14.patch +Patch623: glibc-rh1991001-15.patch +Patch624: glibc-rh1991001-16.patch +Patch625: glibc-rh1991001-17.patch +Patch626: glibc-rh1991001-18.patch +Patch627: glibc-rh1991001-19.patch +Patch628: glibc-rh1991001-20.patch +Patch629: glibc-rh1991001-21.patch +Patch630: glibc-rh1991001-22.patch +Patch631: glibc-rh1929928-1.patch +Patch632: glibc-rh1929928-2.patch +Patch633: glibc-rh1929928-3.patch +Patch634: glibc-rh1929928-4.patch +Patch635: glibc-rh1929928-5.patch +Patch636: glibc-rh1984802-1.patch +Patch637: glibc-rh1984802-2.patch +Patch638: glibc-rh1984802-3.patch +Patch639: glibc-rh2023420-1.patch +Patch640: glibc-rh2023420-2.patch +Patch641: glibc-rh2023420-3.patch +Patch642: glibc-rh2023420-4.patch +Patch643: glibc-rh2023420-5.patch +Patch644: glibc-rh2023420-6.patch +Patch645: glibc-rh2023420-7.patch +Patch646: glibc-rh2033648-1.patch +Patch647: glibc-rh2033648-2.patch +Patch648: glibc-rh2036955.patch +Patch649: glibc-rh2033655.patch +Patch650: glibc-rh2007327-1.patch +Patch651: glibc-rh2007327-2.patch +Patch652: glibc-rh2032281-1.patch +Patch653: glibc-rh2032281-2.patch +Patch654: glibc-rh2032281-3.patch +Patch655: glibc-rh2032281-4.patch +Patch656: glibc-rh2032281-5.patch +Patch657: glibc-rh2032281-6.patch +Patch658: glibc-rh2032281-7.patch +Patch659: glibc-rh2045063-1.patch +Patch660: glibc-rh2045063-2.patch +Patch661: glibc-rh2045063-3.patch +Patch662: glibc-rh2045063-4.patch +Patch663: glibc-rh2045063-5.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 +Patch691: glibc-rh2065588-4.patch +Patch692: glibc-rh2065588-5.patch +Patch693: glibc-rh2065588-6.patch +Patch694: glibc-rh2065588-7.patch +Patch695: glibc-rh2065588-8.patch +Patch696: glibc-rh2065588-9.patch +Patch697: glibc-rh2065588-10.patch +Patch698: glibc-rh2065588-11.patch +Patch699: glibc-rh2065588-12.patch +Patch700: glibc-rh2065588-13.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 +Patch842: glibc-rh2183081-1.patch +Patch843: glibc-rh2183081-2.patch +Patch844: glibc-rh2172949.patch +Patch845: glibc-rh2180155-1.patch +Patch846: glibc-rh2180155-2.patch +Patch847: glibc-rh2180155-3.patch +Patch848: glibc-rh2213909.patch +Patch849: glibc-rh2176707-1.patch +Patch850: glibc-rh2176707-2.patch +Patch851: glibc-rh2186781.patch +Patch852: glibc-rh2224348.patch +Patch853: glibc-rh2176707-3.patch +Patch854: glibc-rh2180462-1.patch +Patch855: glibc-rh2180462-2.patch +Patch856: glibc-rh2180462-3.patch +Patch857: glibc-rh2180462-4.patch +# (Reverted fixes for rh2233338 were here.) +Patch864: glibc-rh2234714.patch +Patch865: glibc-RHEL-2435.patch +Patch866: glibc-RHEL-2435-2.patch +Patch867: glibc-RHEL-2423.patch +Patch868: glibc-RHEL-3036.patch +Patch869: glibc-RHEL-3757.patch +Patch870: glibc-RHEL-2122.patch +Patch871: glibc-RHEL-1192.patch +Patch872: glibc-RHEL-3639.patch +Patch873: glibc-RHEL-10481.patch +Patch874: glibc-RHEL-13720-1.patch +Patch875: glibc-RHEL-13720-2.patch +Patch876: glibc-RHEL-15867.patch +Patch877: glibc-RHEL-16825-1.patch +Patch878: glibc-RHEL-16825-2.patch +Patch879: glibc-RHEL-16825-3.patch +Patch880: glibc-RHEL-16825-4.patch +Patch881: glibc-RHEL-15696-1.patch +Patch882: glibc-RHEL-15696-2.patch +Patch883: glibc-RHEL-15696-3.patch +Patch884: glibc-RHEL-15696-4.patch +Patch885: glibc-RHEL-15696-5.patch +Patch886: glibc-RHEL-15696-6.patch +Patch887: glibc-RHEL-15696-7.patch +Patch888: glibc-RHEL-15696-8.patch +Patch889: glibc-RHEL-15696-9.patch +Patch890: glibc-RHEL-15696-10.patch +Patch891: glibc-RHEL-15696-11.patch +Patch892: glibc-RHEL-15696-12.patch +Patch893: glibc-RHEL-15696-13.patch +Patch894: glibc-RHEL-15696-14.patch +Patch895: glibc-RHEL-15696-15.patch +Patch896: glibc-RHEL-15696-16.patch +Patch897: glibc-RHEL-15696-17.patch +Patch898: glibc-RHEL-15696-18.patch +Patch899: glibc-RHEL-15696-19.patch +Patch900: glibc-RHEL-15696-20.patch +Patch901: glibc-RHEL-15696-21.patch +Patch902: glibc-RHEL-15696-22.patch +Patch903: glibc-RHEL-15696-23.patch +Patch904: glibc-RHEL-15696-24.patch +Patch905: glibc-RHEL-15696-25.patch +Patch906: glibc-RHEL-15696-26.patch +Patch907: glibc-RHEL-15696-27.patch +Patch908: glibc-RHEL-15696-28.patch +Patch909: glibc-RHEL-15696-29.patch +Patch910: glibc-RHEL-15696-30.patch +Patch911: glibc-RHEL-15696-31.patch +Patch912: glibc-RHEL-15696-32.patch +Patch913: glibc-RHEL-15696-33.patch +Patch914: glibc-RHEL-15696-34.patch +Patch915: glibc-RHEL-15696-35.patch +Patch916: glibc-RHEL-15696-36.patch +Patch917: glibc-RHEL-15696-37.patch +Patch918: glibc-RHEL-15696-38.patch +Patch919: glibc-RHEL-15696-39.patch +Patch920: glibc-RHEL-15696-40.patch +Patch921: glibc-RHEL-15696-41.patch +Patch922: glibc-RHEL-15696-42.patch +Patch923: glibc-RHEL-15696-43.patch +Patch924: glibc-RHEL-15696-44.patch +Patch925: glibc-RHEL-15696-45.patch +Patch926: glibc-RHEL-15696-46.patch +Patch927: glibc-RHEL-15696-47.patch +Patch928: glibc-RHEL-15696-48.patch +Patch929: glibc-RHEL-15696-49.patch +Patch930: glibc-RHEL-15696-50.patch +Patch931: glibc-RHEL-15696-51.patch +Patch932: glibc-RHEL-15696-52.patch +Patch933: glibc-RHEL-15696-53.patch +Patch934: glibc-RHEL-15696-54.patch +Patch935: glibc-RHEL-15696-55.patch +Patch936: glibc-RHEL-15696-56.patch +Patch937: glibc-RHEL-15696-57.patch +Patch938: glibc-RHEL-15696-58.patch +Patch939: glibc-RHEL-15696-59.patch +Patch940: glibc-RHEL-15696-60.patch +Patch941: glibc-RHEL-15696-61.patch +Patch942: glibc-RHEL-15696-62.patch +Patch943: glibc-RHEL-15696-63.patch +Patch944: glibc-RHEL-15696-64.patch +Patch945: glibc-RHEL-15696-65.patch +Patch946: glibc-RHEL-15696-66.patch +Patch947: glibc-RHEL-15696-67.patch +Patch948: glibc-RHEL-15696-68.patch +Patch949: glibc-RHEL-15696-69.patch +Patch950: glibc-RHEL-15696-70.patch +Patch951: glibc-RHEL-15696-71.patch +Patch952: glibc-RHEL-15696-72.patch +Patch953: glibc-RHEL-15696-73.patch +Patch954: glibc-RHEL-15696-74.patch +Patch955: glibc-RHEL-15696-75.patch +Patch956: glibc-RHEL-15696-76.patch +Patch957: glibc-RHEL-15696-77.patch +Patch958: glibc-RHEL-15696-78.patch +Patch959: glibc-RHEL-15696-79.patch +Patch960: glibc-RHEL-15696-80.patch +Patch961: glibc-RHEL-15696-81.patch +Patch962: glibc-RHEL-15696-82.patch +Patch963: glibc-RHEL-15696-83.patch +Patch964: glibc-RHEL-15696-84.patch +Patch965: glibc-RHEL-15696-85.patch +Patch966: glibc-RHEL-15696-86.patch +Patch967: glibc-RHEL-15696-87.patch +Patch968: glibc-RHEL-15696-88.patch +Patch969: glibc-RHEL-15696-89.patch +Patch970: glibc-RHEL-15696-90.patch +Patch971: glibc-RHEL-15696-91.patch +Patch972: glibc-RHEL-15696-92.patch +Patch973: glibc-RHEL-15696-93.patch +Patch974: glibc-RHEL-15696-94.patch +Patch975: glibc-RHEL-15696-95.patch +Patch976: glibc-RHEL-15696-96.patch +Patch977: glibc-RHEL-15696-97.patch +Patch978: glibc-RHEL-15696-98.patch +Patch979: glibc-RHEL-15696-99.patch +Patch980: glibc-RHEL-15696-100.patch +Patch981: glibc-RHEL-15696-101.patch +Patch982: glibc-RHEL-15696-102.patch +Patch983: glibc-RHEL-15696-103.patch +Patch984: glibc-RHEL-15696-104.patch +Patch985: glibc-RHEL-15696-105.patch +Patch986: glibc-RHEL-15696-106.patch +Patch987: glibc-RHEL-15696-107.patch +Patch988: glibc-RHEL-15696-108.patch +Patch989: glibc-RHEL-15696-109.patch +Patch990: glibc-RHEL-15696-110.patch +Patch991: glibc-RHEL-17468-1.patch +Patch992: glibc-RHEL-17468-2.patch +Patch993: glibc-RHEL-19824.patch +Patch994: glibc-RHEL-3010-1.patch +Patch995: glibc-RHEL-3010-2.patch +Patch996: glibc-RHEL-3010-3.patch +Patch997: glibc-RHEL-19445.patch +Patch998: glibc-RHEL-21997.patch + +############################################################################## +# Continued list of core "glibc" package information: +############################################################################## +Obsoletes: glibc-profile < 2.4 +Provides: ldconfig + +# The dynamic linker supports DT_GNU_HASH +Provides: rtld(GNU_HASH) +Requires: glibc-common = %{version}-%{release} + +# Various components (regex, glob) have been imported from gnulib. +Provides: bundled(gnulib) + +Requires(pre): basesystem + +%ifarch %{ix86} +# Automatically install the 32-bit variant if the 64-bit variant has +# been installed. This covers the case when glibc.i686 is installed +# after nss_db.x86_64. (See below for the other ordering.) +Recommends: (nss_db(x86-32) if nss_db(x86-64)) +%endif + +# This is for building auxiliary programs like memusage, nscd +# For initial glibc bootstraps it can be commented out +%if %{without bootstrap} +BuildRequires: gd-devel libpng-devel zlib-devel +%endif +%if %{with docs} +%endif +%if %{without bootstrap} +BuildRequires: libselinux-devel >= 1.33.4-3 +%endif +BuildRequires: audit-libs-devel >= 1.1.3, sed >= 3.95, libcap-devel, gettext +# We need procps-ng (/bin/ps), util-linux (/bin/kill), and gawk (/bin/awk), +# but it is more flexible to require the actual programs and let rpm infer +# the packages. However, until bug 1259054 is widely fixed we avoid the +# following: +# BuildRequires: /bin/ps, /bin/kill, /bin/awk +# And use instead (which should be reverted some time in the future): +BuildRequires: procps-ng, util-linux, gawk +BuildRequires: systemtap-sdt-devel + +%if %{with valgrind} +# Require valgrind for smoke testing the dynamic loader to make sure we +# have not broken valgrind. +BuildRequires: valgrind +%endif + +# We use systemd rpm macros for nscd +BuildRequires: systemd + +# We use python for the microbenchmarks and locale data regeneration +# from unicode sources (carried out manually). We choose python3 +# explicitly because it supports both use cases. On some +# distributions, python3 does not actually install /usr/bin/python3, +# so we also depend on python3-devel. +BuildRequires: python3 python3-devel + +# This is the first GCC version with -moutline-atomics (#1856398) +BuildRequires: gcc >= 8.3.1-5.2 +%define enablekernel 3.2 +Conflicts: kernel < %{enablekernel} +%define target %{_target_cpu}-redhat-linux +%ifarch %{arm} +%define target %{_target_cpu}-redhat-linuxeabi +%endif +%ifarch %{power64} +%ifarch ppc64le +%define target ppc64le-redhat-linux +%else +%define target ppc64-redhat-linux +%endif +%endif + +# GNU make 4.0 introduced the -O option. +BuildRequires: make >= 4.0 + +# The intl subsystem generates a parser using bison. +BuildRequires: bison >= 2.7 + +# binutils 2.30-51 is needed for z13 support on s390x. +BuildRequires: binutils >= 2.30-51 + +# Earlier releases have broken support for IRELATIVE relocations +Conflicts: prelink < 0.4.2 + +%if 0%{?_enable_debug_packages} +BuildRequires: elfutils >= 0.72 +# -20 adds __find_debuginfo macro +BuildRequires: rpm >= 4.14.3-20 +%endif + +%if %{without bootstrap} +%if %{with testsuite} +# The testsuite builds static C++ binaries that require a C++ compiler, +# static C++ runtime from libstdc++-static, and lastly static glibc. +BuildRequires: gcc-c++ +BuildRequires: libstdc++-static +# A configure check tests for the ability to create static C++ binaries +# before glibc is built and therefore we need a glibc-static for that +# check to pass even if we aren't going to use any of those objects to +# build the tests. +BuildRequires: glibc-static + +# libidn2 (but not libidn2-devel) is needed for testing AI_IDN/NI_IDN. +BuildRequires: libidn2 +%endif +%endif + +# Filter out all GLIBC_PRIVATE symbols since they are internal to +# the package and should not be examined by any other tool. +%global __filter_GLIBC_PRIVATE 1 + +# For language packs we have glibc require a virtual dependency +# "glibc-langpack" wich gives us at least one installed langpack. +# If no langpack providing 'glibc-langpack' was installed you'd +# get all of them, and that would make the transition from a +# system without langpacks smoother (you'd get all the locales +# installed). You would then trim that list, and the trimmed list +# is preserved. One problem is you can't have "no" locales installed, +# in that case we offer a "glibc-minimal-langpack" sub-pakcage for +# this purpose. +Requires: glibc-langpack = %{version}-%{release} +Suggests: glibc-all-langpacks = %{version}-%{release} + +# Suggest extra gconv modules so that they are installed by default but can be +# removed if needed to build a minimal OS image. +Recommends: glibc-gconv-extra%{_isa} = %{version}-%{release} + +%description +The glibc package contains standard libraries which are used by +multiple programs on the system. In order to save disk space and +memory, as well as to make upgrading easier, common system code is +kept in one place and shared between programs. This particular package +contains the most important sets of shared libraries: the standard C +library and the standard math library. Without these two libraries, a +Linux system will not function. + +###################################################################### +# libnsl subpackage +###################################################################### + +%package -n libnsl +Summary: Legacy support library for NIS +Requires: %{name}%{_isa} = %{version}-%{release} + +%description -n libnsl +This package provides the legacy version of libnsl library, for +accessing NIS services. + +This library is provided for backwards compatibility only; +applications should use libnsl2 instead to gain IPv6 support. + +############################################################################## +# glibc "devel" sub-package +############################################################################## +%package devel +Summary: Object files for development using standard C libraries. +Requires(pre): /sbin/install-info +Requires(pre): %{name}-headers +Requires: %{name}-headers = %{version}-%{release} +Requires: %{name} = %{version}-%{release} +Requires: libgcc%{_isa} +Requires: libxcrypt-devel%{_isa} >= 4.0.0 + +%description devel +The glibc-devel package contains the object files necessary +for developing programs which use the standard C libraries (which are +used by nearly all programs). If you are developing programs which +will use the standard C libraries, your system needs to have these +standard object files available in order to create the +executables. + +Install glibc-devel if you are going to develop programs which will +use the standard C libraries. + +############################################################################## +# glibc "doc" sub-package +############################################################################## +%if %{with docs} +%package doc +Summary: Documentation for GNU libc +BuildArch: noarch +Requires: %{name} = %{version}-%{release} + +# Removing texinfo will cause check-safety.sh test to fail because it seems to +# trigger documentation generation based on dependencies. We need to fix this +# upstream in some way that doesn't depend on generating docs to validate the +# texinfo. I expect it's simply the wrong dependency for that target. +BuildRequires: texinfo >= 5.0 + +%description doc +The glibc-doc package contains The GNU C Library Reference Manual in info +format. Additional package documentation is also provided. +%endif + +############################################################################## +# glibc "static" sub-package +############################################################################## +%package static +Summary: C library static libraries for -static linking. +Requires: %{name}-devel = %{version}-%{release} +Requires: libxcrypt-static%{?_isa} >= 4.0.0 + +%description static +The glibc-static package contains the C library static libraries +for -static linking. You don't need these, unless you link statically, +which is highly discouraged. + +############################################################################## +# glibc "headers" sub-package +# - The headers package includes all common headers that are shared amongst +# the multilib builds. It was created to reduce the download size, and +# thus avoid downloading one header package per multilib. The package is +# identical both in content and file list, any difference is an error. +# Files like gnu/stubs.h which have gnu/stubs-32.h (i686) and gnu/stubs-64.h +# are included in glibc-headers, but the -32 and -64 files are in their +# respective i686 and x86_64 devel packages. +############################################################################## +%package headers +Summary: Header files for development using standard C libraries. +Provides: %{name}-headers(%{_target_cpu}) +Requires(pre): kernel-headers +Requires: kernel-headers >= 2.2.1, %{name} = %{version}-%{release} +BuildRequires: kernel-headers >= 3.2 + +%description headers +The glibc-headers package contains the header files necessary +for developing programs which use the standard C libraries (which are +used by nearly all programs). If you are developing programs which +will use the standard C libraries, your system needs to have these +standard header files available in order to create the +executables. + +Install glibc-headers if you are going to develop programs which will +use the standard C libraries. + +############################################################################## +# glibc "common" sub-package +############################################################################## +%package common +Summary: Common binaries and locale data for glibc +Requires: %{name} = %{version}-%{release} +Requires: tzdata >= 2003a + +%description common +The glibc-common package includes common binaries for the GNU libc +libraries, as well as national language (locale) support. + +###################################################################### +# File triggers to do ldconfig calls automatically (see rhbz#1380878) +###################################################################### + +# File triggers for when libraries are added or removed in standard +# paths. +%transfiletriggerin common -P 2000000 -- /lib /usr/lib /lib64 /usr/lib64 +/sbin/ldconfig +%end + +%transfiletriggerpostun common -P 2000000 -- /lib /usr/lib /lib64 /usr/lib64 +/sbin/ldconfig +%end + +# We need to run ldconfig manually because __brp_ldconfig assumes that +# glibc itself is always installed in $RPM_BUILD_ROOT, but with sysroots +# we may be installed into a subdirectory of that path. Therefore we +# unset __brp_ldconfig and run ldconfig by hand with the sysroots path +# passed to -r. +%undefine __brp_ldconfig + +###################################################################### + +%package locale-source +Summary: The sources for the locales +Requires: %{name} = %{version}-%{release} +Requires: %{name}-common = %{version}-%{release} + +%description locale-source +The sources for all locales provided in the language packs. +If you are building custom locales you will most likely use +these sources as the basis for your new locale. + +%{lua: +-- Array of languages (ISO-639 codes). +local languages = {} +-- Dictionary from language codes (as in the languages array) to arrays +-- of regions. +local supplements = {} +do + -- Parse the SUPPORTED file. Eliminate duplicates. + local lang_region_seen = {} + for line in io.lines(rpm.expand("%{SOURCE11}")) do + -- Match lines which contain a language (eo) or language/region + -- (en_US) strings. + local lang_region = string.match(line, "^([a-z][^/@.]+)") + if lang_region ~= nil then + if lang_region_seen[lang_region] == nil then + lang_region_seen[lang_region] = true + + -- Split language/region pair. + local lang, region = string.match(lang_region, "^(.+)_(.+)") + if lang == nil then + -- Region is missing, use only the language. + lang = lang_region + end + local suppl = supplements[lang] + if suppl == nil then + suppl = {} + supplements[lang] = suppl + -- New language not seen before. + languages[#languages + 1] = lang + end + if region ~= nil then + -- New region because of the check against + -- lang_region_seen above. + suppl[#suppl + 1] = region + end + end + end + end + -- Sort for determinism. + table.sort(languages) + for _, supples in pairs(supplements) do + table.sort(supplements) + end +end + +-- Compute the Supplements: list for a language, based on the regions. +local function compute_supplements(lang) + result = "langpacks-" .. lang + regions = supplements[lang] + if regions ~= nil then + for i = 1, #regions do + result = result .. " or langpacks-" .. lang .. "_" .. regions[i] + end + end + return result +end + +-- Emit the definition of a language pack package. +local function lang_package(lang) + local suppl = compute_supplements(lang) + print(rpm.expand([[ + +%package langpack-]]..lang..[[ + +Summary: Locale data for ]]..lang..[[ + +Provides: glibc-langpack = %{version}-%{release} +Requires: %{name} = %{version}-%{release} +Requires: %{name}-common = %{version}-%{release} +Supplements: (glibc and (]]..suppl..[[)) +%description langpack-]]..lang..[[ + +The glibc-langpack-]]..lang..[[ package includes the basic information required +to support the ]]..lang..[[ language in your applications. +%ifnarch %{auxarches} +%files -f langpack-]]..lang..[[.filelist langpack-]]..lang..[[ + +%endif +]])) +end + +for i = 1, #languages do + lang_package(languages[i]) +end +} + +# The glibc-all-langpacks provides the virtual glibc-langpack, +# and thus satisfies glibc's requirement for installed locales. +# Users can add one more other langauge packs and then eventually +# uninstall all-langpacks to save space. +%package all-langpacks +Summary: All language packs for %{name}. +Requires: %{name} = %{version}-%{release} +Requires: %{name}-common = %{version}-%{release} +Provides: %{name}-langpack = %{version}-%{release} +%description all-langpacks + +# No %files, this is an empty pacakge. The C/POSIX and +# C.UTF-8 files are already installed by glibc. We create +# minimal-langpack because the virtual provide of +# glibc-langpack needs at least one package installed +# to satisfy it. Given that no-locales installed is a valid +# use case we support it here with this package. +%package minimal-langpack +Summary: Minimal language packs for %{name}. +Provides: glibc-langpack = %{version}-%{release} +Requires: %{name} = %{version}-%{release} +Requires: %{name}-common = %{version}-%{release} +%description minimal-langpack +This is a Meta package that is used to install minimal language packs. +This package ensures you can use C, POSIX, or C.UTF-8 locales, but +nothing else. It is designed for assembling a minimal system. +%ifnarch %{auxarches} +%files minimal-langpack +%endif + +# Infrequently used iconv converter modules. +%package gconv-extra +Summary: All iconv converter modules for %{name}. +Requires: %{name}%{_isa} = %{version}-%{release} +Requires: %{name}-common = %{version}-%{release} + +%description gconv-extra +This package contains all iconv converter modules built in %{name}. + +############################################################################## +# glibc "nscd" sub-package +############################################################################## +%package -n nscd +Summary: A Name Service Caching Daemon (nscd). +Requires: %{name} = %{version}-%{release} +%if %{without bootstrap} +Requires: libselinux >= 1.17.10-1 +%endif +Requires: audit-libs >= 1.1.3 +Requires(pre): /usr/sbin/useradd, coreutils +Requires(post): systemd +Requires(preun): systemd +Requires(postun): systemd, /usr/sbin/userdel + +%description -n nscd +The nscd daemon caches name service lookups and can improve +performance with LDAP, and may help with DNS as well. + +############################################################################## +# Subpackages for NSS modules except nss_files, nss_compat, nss_dns +############################################################################## + +# This should remain it's own subpackage or "Provides: nss_db" to allow easy +# migration from old systems that previously had the old nss_db package +# installed. Note that this doesn't make the migration that smooth, the +# databases still need rebuilding because the formats were different. +# The nss_db package was deprecated in F16 and onwards: +# https://lists.fedoraproject.org/pipermail/devel/2011-July/153665.html +# The different database format does cause some issues for users: +# https://lists.fedoraproject.org/pipermail/devel/2011-December/160497.html +%package -n nss_db +Summary: Name Service Switch (NSS) module using hash-indexed files +Requires: %{name}%{_isa} = %{version}-%{release} +%ifarch x86_64 +# Automatically install the 32-bit variant if the 64-bit variant has +# been installed. This covers the case when glibc.i686 is installed +# before nss_db.x86_64. (See above for the other ordering.) +Recommends: (nss_db(x86-32) if glibc(x86-32)) +%endif + +%description -n nss_db +The nss_db Name Service Switch module uses hash-indexed files in /var/db +to speed up user, group, service, host name, and other NSS-based lookups. + +%package -n nss_hesiod +Summary: Name Service Switch (NSS) module using Hesiod +Requires: %{name}%{_isa} = %{version}-%{release} + +%description -n nss_hesiod +The nss_hesiod Name Service Switch module uses the Domain Name System +(DNS) as a source for user, group, and service information, following +the Hesiod convention of Project Athena. + +%package nss-devel +Summary: Development files for directly linking NSS service modules +Requires: %{name}%{_isa} = %{version}-%{release} +Requires: nss_db%{_isa} = %{version}-%{release} +Requires: nss_hesiod%{_isa} = %{version}-%{release} + +%description nss-devel +The glibc-nss-devel package contains the object files necessary to +compile applications and libraries which directly link against NSS +modules supplied by glibc. + +This is a rare and special use case; regular development has to use +the glibc-devel package instead. + +############################################################################## +# glibc "utils" sub-package +############################################################################## +%package utils +Summary: Development utilities from GNU C library +Requires: %{name} = %{version}-%{release} + +%description utils +The glibc-utils package contains memusage, a memory usage profiler, +mtrace, a memory leak tracer and xtrace, a function call tracer +which can be helpful during program debugging. + +If unsure if you need this, don't install this package. + +%if %{with benchtests} +%package benchtests +Summary: Benchmarking binaries and scripts for %{name} +%description benchtests +This package provides built benchmark binaries and scripts to run +microbenchmark tests on the system. +%endif + +############################################################################## +# compat-libpthread-nonshared +# See: https://sourceware.org/bugzilla/show_bug.cgi?id=23500 +############################################################################## +%package -n compat-libpthread-nonshared +Summary: Compatibility support for linking against libpthread_nonshared.a. + +%description -n compat-libpthread-nonshared +This package provides compatibility support for applications that expect +libpthread_nonshared.a to exist. The support provided is in the form of +an empty libpthread_nonshared.a that allows dynamic links to succeed. +Such applications should be adjusted to avoid linking against +libpthread_nonshared.a which is no longer used. The static library +libpthread_nonshared.a is an internal implementation detail of the C +runtime and should not be expected to exist. + +############################################################################## +# Prepare for the build. +############################################################################## +%prep +%autosetup -n %{glibcsrcdir} -p1 + +############################################################################## +# %%prep - Additional prep required... +############################################################################## +# Make benchmark scripts executable +chmod +x benchtests/scripts/*.py scripts/pylint + +# Remove all files generated from patching. +find . -type f -size 0 -o -name "*.orig" -exec rm -f {} \; + +# Ensure timestamps on configure files are current to prevent +# regenerating them. +touch `find . -name configure` + +# Ensure *-kw.h files are current to prevent regenerating them. +touch locale/programs/*-kw.h + +# Verify that our copy of localedata/SUPPORTED matches the glibc +# version. +# +# The separate file copy is used by the Lua parser above. +# Patches or new upstream versions may change the list of locales, +# which changes the set of langpacks we need to build. Verify the +# differences then update the copy of SUPPORTED. This approach has +# two purposes: (a) avoid spurious changes to the set of langpacks, +# and (b) the Lua snippet can use a fully patched-up version +# of the localedata/SUPPORTED file. +diff -u %{SOURCE11} localedata/SUPPORTED + +############################################################################## +# Build glibc... +############################################################################## +%build +# Log system information +uname -a +LD_SHOW_AUXV=1 /bin/true +cat /proc/cpuinfo +cat /proc/sysinfo 2>/dev/null || true +cat /proc/meminfo +df + +# We build using the native system compilers. +GCC=gcc +GXX=g++ + +# Part of rpm_inherit_flags. Is overridden below. +rpm_append_flag () +{ + BuildFlags="$BuildFlags $*" +} + +# Propagates the listed flags to rpm_append_flag if supplied by +# redhat-rpm-config. +BuildFlags="-O2 -g" +rpm_inherit_flags () +{ + local reference=" $* " + local flag + for flag in $RPM_OPT_FLAGS $RPM_LD_FLAGS ; do + if echo "$reference" | grep -q -F " $flag " ; then + rpm_append_flag "$flag" + fi + done +} + +# Propgate select compiler flags from redhat-rpm-config. These flags +# are target-dependent, so we use only those which are specified in +# redhat-rpm-config. We keep the -m32/-m32/-m64 flags to support +# multilib builds. +# +# Note: For building alternative run-times, care is required to avoid +# overriding the architecture flags which go into CC/CXX. The flags +# below are passed in CFLAGS. + +rpm_inherit_flags \ + "-Wp,-D_GLIBCXX_ASSERTIONS" \ + "-fasynchronous-unwind-tables" \ + "-fstack-clash-protection" \ + "-funwind-tables" \ + "-m31" \ + "-m32" \ + "-m64" \ + "-march=i686" \ + "-march=x86-64" \ + "-march=z13" \ + "-march=z14" \ + "-march=zEC12" \ + "-mfpmath=sse" \ + "-msse2" \ + "-mstackrealign" \ + "-mtune=generic" \ + "-mtune=z13" \ + "-mtune=z14" \ + "-mtune=zEC12" \ + "-specs=/usr/lib/rpm/redhat/redhat-annobin-cc1" \ + +# Propagate additional build flags to BuildFlagsNonshared. This is +# very special because some of these files are part of the startup +# code. We essentially hope that these flags have little effect +# there, and only specify the, for consistency, so that annobin +# records the expected compiler flags. +BuildFlagsNonshared= +rpm_append_flag () { + BuildFlagsNonshared="$BuildFlagsNonshared $*" +} +rpm_inherit_flags \ + "-Wp,-D_FORTIFY_SOURCE=2" \ + +# Special flag to enable annobin annotations for statically linked +# assembler code. Needs to be passed to make; not preserved by +# configure. +%define glibc_make_flags_as ASFLAGS="-g -Wa,--generate-missing-build-notes=yes" +%define glibc_make_flags %{glibc_make_flags_as} + +%ifarch aarch64 +# BZ 1856398 - Build AArch64 with out-of-line support for LSE atomics +GCC="$GCC -moutline-atomics" +GXX="$GXX -moutline-atomics" +%endif + +############################################################################## +# %%build - Generic options. +############################################################################## +EnableKernel="--enable-kernel=%{enablekernel}" +# Save the used compiler and options into the file "Gcc" for use later +# by %%install. +echo "$GCC" > Gcc + +############################################################################## +# build() +# Build glibc in `build-%{target}$1', passing the rest of the arguments +# as CFLAGS to the build (not the same as configure CFLAGS). Several +# global values are used to determine build flags, kernel version, +# system tap support, etc. +############################################################################## +build() +{ + local builddir=build-%{target}${1:+-$1} + ${1+shift} + rm -rf $builddir + mkdir $builddir + pushd $builddir + ../configure CC="$GCC" CXX="$GXX" CFLAGS="$BuildFlags $*" \ + --prefix=%{_prefix} \ + --with-headers=%{_prefix}/include $EnableKernel \ + --with-nonshared-cflags="$BuildFlagsNonshared" \ + --enable-bind-now \ + --build=%{target} \ + --enable-stack-protector=strong \ +%ifarch %{pie_arches} + --enable-static-pie \ +%endif + --enable-tunables \ + --enable-systemtap \ + ${core_with_options} \ +%ifarch x86_64 %{ix86} + --enable-cet \ +%endif +%ifarch %{ix86} + --disable-multi-arch \ +%endif +%if %{without werror} + --disable-werror \ +%endif + --disable-profile \ +%if %{with bootstrap} + --without-selinux \ +%endif + --disable-crypt || + { cat config.log; false; } + + make %{?_smp_mflags} -O -r %{glibc_make_flags} + popd +} + +# Default set of compiler options. +build + +%if %{buildpower9} +( + GCC="$GCC -mcpu=power9 -mtune=power9" + GXX="$GXX -mcpu=power9 -mtune=power9" + core_with_options="--with-cpu=power9" + build power9 +) +%endif + +############################################################################## +# Install glibc... +############################################################################## +%install + +# The built glibc is installed into a subdirectory of $RPM_BUILD_ROOT. +# For a system glibc that subdirectory is "/" (the root of the filesystem). +# This is called a sysroot (system root) and can be changed if we have a +# distribution that supports multiple installed glibc versions. +%define glibc_sysroot $RPM_BUILD_ROOT + +# Remove existing file lists. +find . -type f -name '*.filelist' -exec rm -rf {} \; + +# Ensure the permissions of errlist.c do not change. When the file is +# regenerated the Makefile sets the permissions to 444. We set it to 644 +# to match what comes out of git. The tarball of the git archive won't have +# correct permissions because git doesn't track all of the permissions +# accurately (see git-cache-meta if you need that). We also set it to 644 to +# match pre-existing rpms. We do this *after* the build because the build +# might regenerate the file and set the permissions to 444. +chmod 644 sysdeps/gnu/errlist.c + +# Reload compiler and build options that were used during %%build. +GCC=`cat Gcc` + +%ifarch riscv64 +# RISC-V ABI wants to install everything in /lib64/lp64d or /usr/lib64/lp64d. +# Make these be symlinks to /lib64 or /usr/lib64 respectively. See: +# https://lists.fedoraproject.org/archives/list/devel@lists.fedoraproject.org/thread/DRHT5YTPK4WWVGL3GIN5BF2IKX2ODHZ3/ +for d in %{glibc_sysroot}%{_libdir} %{glibc_sysroot}/%{_lib}; do + mkdir -p $d + (cd $d && ln -sf . lp64d) +done +%endif + +# Build and install: +make -j1 install_root=%{glibc_sysroot} install -C build-%{target} + +# If we are not building an auxiliary arch then install all of the supported +# locales. +%ifnarch %{auxarches} +pushd build-%{target} +# Do not use a parallel make here because the hardlink optimization in +# localedef is not fully reproducible when running concurrently. +make install_root=%{glibc_sysroot} \ + install-locales -C ../localedata objdir=`pwd` +popd +%endif + +# install_different: +# Install all core libraries into DESTDIR/SUBDIR. Either the file is +# installed as a copy or a symlink to the default install (if it is the +# same). The path SUBDIR_UP is the prefix used to go from +# DESTDIR/SUBDIR to the default installed libraries e.g. +# ln -s SUBDIR_UP/foo.so DESTDIR/SUBDIR/foo.so. +# When you call this function it is expected that you are in the root +# of the build directory, and that the default build directory is: +# "../build-%{target}" (relatively). +# The primary use of this function is to install alternate runtimes +# into the build directory and avoid duplicating this code for each +# runtime. +install_different() +{ + local lib libbase libbaseso dlib + local destdir="$1" + local subdir="$2" + local subdir_up="$3" + local libdestdir="$destdir/$subdir" + # All three arguments must be non-zero paths. + if ! [ "$destdir" \ + -a "$subdir" \ + -a "$subdir_up" ]; then + echo "One of the arguments to install_different was emtpy." + exit 1 + fi + # Create the destination directory and the multilib directory. + mkdir -p "$destdir" + mkdir -p "$libdestdir" + # Walk all of the libraries we installed... + for lib in libc math/libm nptl/libpthread rt/librt nptl_db/libthread_db + do + libbase=${lib#*/} + # Take care that `libbaseso' has a * that needs expanding so + # take care with quoting. + libbaseso=$(basename %{glibc_sysroot}/%{_lib}/${libbase}-*.so) + # Only install if different from default build library. + if cmp -s ${lib}.so ../build-%{target}/${lib}.so; then + ln -sf "$subdir_up"/$libbaseso $libdestdir/$libbaseso + else + cp -a ${lib}.so $libdestdir/$libbaseso + fi + dlib=$libdestdir/$(basename %{glibc_sysroot}/%{_lib}/${libbase}.so.*) + ln -sf $libbaseso $dlib + done +} + +%if %{buildpower9} +pushd build-%{target}-power9 +install_different "$RPM_BUILD_ROOT/%{_lib}/glibc-hwcaps" power9 "../.." +popd +%endif + +############################################################################## +# Remove the files we don't want to distribute +############################################################################## + +# Remove the libNoVersion files. +# XXX: This looks like a bug in glibc that accidentally installed these +# wrong files. We probably don't need this today. +rm -f %{glibc_sysroot}/%{_libdir}/libNoVersion* +rm -f %{glibc_sysroot}/%{_lib}/libNoVersion* + +# Remove the old nss modules. +rm -f %{glibc_sysroot}/%{_lib}/libnss1-* +rm -f %{glibc_sysroot}/%{_lib}/libnss-*.so.1 + +# This statically linked binary is no longer necessary in a world where +# the default Fedora install uses an initramfs, and further we have rpm-ostree +# which captures the whole userspace FS tree. +# Further, see https://github.com/projectatomic/rpm-ostree/pull/1173#issuecomment-355014583 +rm -f %{glibc_sysroot}/{usr/,}sbin/sln + +###################################################################### +# Run ldconfig to create all the symbolic links we need +###################################################################### + +# Note: This has to happen before creating /etc/ld.so.conf. + +mkdir -p %{glibc_sysroot}/var/cache/ldconfig +truncate -s 0 %{glibc_sysroot}/var/cache/ldconfig/aux-cache + +# ldconfig is statically linked, so we can use the new version. +%{glibc_sysroot}/sbin/ldconfig -N -r %{glibc_sysroot} + +############################################################################## +# Install info files +############################################################################## + +%if %{with docs} +# Move the info files if glibc installed them into the wrong location. +if [ -d %{glibc_sysroot}%{_prefix}/info -a "%{_infodir}" != "%{_prefix}/info" ]; then + mkdir -p %{glibc_sysroot}%{_infodir} + mv -f %{glibc_sysroot}%{_prefix}/info/* %{glibc_sysroot}%{_infodir} + rm -rf %{glibc_sysroot}%{_prefix}/info +fi + +# Compress all of the info files. +gzip -9nvf %{glibc_sysroot}%{_infodir}/libc* + +# Copy the debugger interface documentation over to the right location +mkdir -p %{glibc_sysroot}%{_docdir}/glibc +cp elf/rtld-debugger-interface.txt %{glibc_sysroot}%{_docdir}/glibc +cp posix/gai.conf %{glibc_sysroot}%{_docdir}/glibc +%else +rm -f %{glibc_sysroot}%{_infodir}/dir +rm -f %{glibc_sysroot}%{_infodir}/libc.info* +%endif + +############################################################################## +# Create locale sub-package file lists +############################################################################## + +%ifnarch %{auxarches} +olddir=`pwd` +pushd %{glibc_sysroot}%{_prefix}/lib/locale +rm -f locale-archive +# Intentionally we do not pass --alias-file=, aliases will be added +# by build-locale-archive. +$olddir/build-%{target}/testrun.sh \ + $olddir/build-%{target}/locale/localedef \ + --prefix %{glibc_sysroot} --add-to-archive \ + eo *_* +# Setup the locale-archive template for use by glibc-all-langpacks. We +# copy the archive in place to keep the size of the file. Even though we +# mark the file with "ghost" the size is used by rpm to compute the +# required free space (see rhbz#1725131). We do this because there is a +# point in the install when build-locale-archive has copied 100% of the +# template into the new locale archive and so this consumes twice the +# amount of diskspace. Note that this doesn't account for copying +# existing compiled locales into the archive, this may consume even more +# disk space and we can't fix that issue. In upstream we have moved away +# from this process, removing build-locale-archive and installing a +# 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 + lang=${i%%_*} + if [ ! -e langpack-${lang}.filelist ]; then + echo "%dir %{_prefix}/lib/locale" >> langpack-${lang}.filelist + fi + echo "%dir %{_prefix}/lib/locale/$i" >> langpack-${lang}.filelist + echo "%{_prefix}/lib/locale/$i/*" >> langpack-${lang}.filelist +done +popd +pushd %{glibc_sysroot}%{_prefix}/share/locale +for i in */LC_MESSAGES/libc.mo +do + locale=${i%%%%/*} + lang=${locale%%%%_*} + echo "%lang($lang) %{_prefix}/share/locale/${i}" \ + >> %{glibc_sysroot}%{_prefix}/lib/locale/langpack-${lang}.filelist +done +popd +mv %{glibc_sysroot}%{_prefix}/lib/locale/*.filelist . +%endif + +############################################################################## +# Install configuration files for services +############################################################################## + +install -p -m 644 nss/nsswitch.conf %{glibc_sysroot}/etc/nsswitch.conf + +%ifnarch %{auxarches} +# This is for ncsd - in glibc 2.2 +install -m 644 nscd/nscd.conf %{glibc_sysroot}/etc +mkdir -p %{glibc_sysroot}%{_tmpfilesdir} +install -m 644 %{SOURCE4} %{buildroot}%{_tmpfilesdir} +mkdir -p %{glibc_sysroot}/lib/systemd/system +install -m 644 nscd/nscd.service nscd/nscd.socket %{glibc_sysroot}/lib/systemd/system +%endif + +# Include ld.so.conf +echo 'include ld.so.conf.d/*.conf' > %{glibc_sysroot}/etc/ld.so.conf +truncate -s 0 %{glibc_sysroot}/etc/ld.so.cache +chmod 644 %{glibc_sysroot}/etc/ld.so.conf +mkdir -p %{glibc_sysroot}/etc/ld.so.conf.d +%ifnarch %{auxarches} +mkdir -p %{glibc_sysroot}/etc/sysconfig +truncate -s 0 %{glibc_sysroot}/etc/sysconfig/nscd +truncate -s 0 %{glibc_sysroot}/etc/gai.conf +%endif + +# Include %{_libdir}/gconv/gconv-modules.cache +truncate -s 0 %{glibc_sysroot}%{_libdir}/gconv/gconv-modules.cache +chmod 644 %{glibc_sysroot}%{_libdir}/gconv/gconv-modules.cache + +############################################################################## +# Install debug copies of unstripped static libraries +# - This step must be last in order to capture any additional static +# archives we might have added. +############################################################################## + +# Remove any zoneinfo files; they are maintained by tzdata. +rm -rf %{glibc_sysroot}%{_prefix}/share/zoneinfo + +# Make sure %config files have the same timestamp across multilib packages. +# +# XXX: Ideally ld.so.conf should have the timestamp of the spec file, but there +# doesn't seem to be any macro to give us that. So we do the next best thing, +# which is to at least keep the timestamp consistent. The choice of using +# SOURCE0 is arbitrary. +touch -r %{SOURCE0} %{glibc_sysroot}/etc/ld.so.conf +touch -r sunrpc/etc.rpc %{glibc_sysroot}/etc/rpc + +pushd build-%{target} +$GCC -Os -g \ +%ifarch %{pie_arches} + -fPIE \ + -static-pie \ +%else + -static \ +%endif + -o build-locale-archive %{SOURCE1} \ + ../build-%{target}/locale/locarchive.o \ + ../build-%{target}/locale/md5.o \ + ../build-%{target}/locale/record-status.o \ + -I. -DDATADIR=\"%{_datadir}\" -DPREFIX=\"%{_prefix}\" \ + -L../build-%{target} \ + -B../build-%{target}/csu/ -lc -lc_nonshared +install -m 700 build-locale-archive %{glibc_sysroot}%{_prefix}/sbin/build-locale-archive +popd + +%ifarch s390x +# Compatibility symlink +mkdir -p %{glibc_sysroot}/lib +ln -sf /%{_lib}/ld64.so.1 %{glibc_sysroot}/lib/ld64.so.1 +%endif + +%if %{with benchtests} +# Build benchmark binaries. Ignore the output of the benchmark runs. +pushd build-%{target} +make BENCH_DURATION=1 bench-build +popd + +# Copy over benchmark binaries. +mkdir -p %{glibc_sysroot}%{_prefix}/libexec/glibc-benchtests +cp $(find build-%{target}/benchtests -type f -executable) %{glibc_sysroot}%{_prefix}/libexec/glibc-benchtests/ +# ... and the makefile. +for b in %{SOURCE9} %{SOURCE10}; do + cp $b %{glibc_sysroot}%{_prefix}/libexec/glibc-benchtests/ +done +# .. and finally, the comparison scripts. +cp benchtests/scripts/benchout.schema.json %{glibc_sysroot}%{_prefix}/libexec/glibc-benchtests/ +cp benchtests/scripts/compare_bench.py %{glibc_sysroot}%{_prefix}/libexec/glibc-benchtests/ +cp benchtests/scripts/import_bench.py %{glibc_sysroot}%{_prefix}/libexec/glibc-benchtests/ +cp benchtests/scripts/validate_benchout.py %{glibc_sysroot}%{_prefix}/libexec/glibc-benchtests/ +%endif + +%if 0%{?_enable_debug_packages} +# The #line directives gperf generates do not give the proper +# file name relative to the build directory. +pushd locale +ln -s programs/*.gperf . +popd +pushd iconv +ln -s ../locale/programs/charmap-kw.gperf . +popd +%endif + +%if %{with docs} +# Remove the `dir' info-heirarchy file which will be maintained +# by the system as it adds info files to the install. +rm -f %{glibc_sysroot}%{_infodir}/dir +%endif + +%ifnarch %{auxarches} +mkdir -p %{glibc_sysroot}/var/{db,run}/nscd +touch %{glibc_sysroot}/var/{db,run}/nscd/{passwd,group,hosts,services} +touch %{glibc_sysroot}/var/run/nscd/{socket,nscd.pid} +%endif + +# Move libpcprofile.so and libmemusage.so into the proper library directory. +# They can be moved without any real consequences because users would not use +# them directly. +mkdir -p %{glibc_sysroot}%{_libdir} +mv -f %{glibc_sysroot}/%{_lib}/lib{pcprofile,memusage}.so \ + %{glibc_sysroot}%{_libdir} + +# Strip all of the installed object files. +strip -g %{glibc_sysroot}%{_libdir}/*.o + +############################################################################### +# Rebuild libpthread.a using --whole-archive to ensure all of libpthread +# is included in a static link. This prevents any problems when linking +# statically, using parts of libpthread, and other necessary parts not +# being included. Upstream has decided that this is the wrong approach to +# this problem and that the full set of dependencies should be resolved +# such that static linking works and produces the most minimally sized +# static application possible. +############################################################################### +pushd %{glibc_sysroot}%{_prefix}/%{_lib}/ +$GCC -r -nostdlib -o libpthread.o -Wl,--whole-archive ./libpthread.a +rm libpthread.a +ar rcs libpthread.a libpthread.o +rm libpthread.o +popd + +# The xtrace and memusage scripts have hard-coded paths that need to be +# translated to a correct set of paths using the $LIB token which is +# dynamically translated by ld.so as the default lib directory. +for i in %{glibc_sysroot}%{_prefix}/bin/{xtrace,memusage}; do +%if %{with bootstrap} + test -w $i || continue +%endif + sed -e 's~=/%{_lib}/libpcprofile.so~=%{_libdir}/libpcprofile.so~' \ + -e 's~=/%{_lib}/libmemusage.so~=%{_libdir}/libmemusage.so~' \ + -e 's~='\''/\\\$LIB/libpcprofile.so~='\''%{_prefix}/\\$LIB/libpcprofile.so~' \ + -e 's~='\''/\\\$LIB/libmemusage.so~='\''%{_prefix}/\\$LIB/libmemusage.so~' \ + -i $i +done + +############################################################################## +# Build an empty libpthread_nonshared.a for compatiliby with applications +# that have old linker scripts that reference this file. We ship this only +# in compat-libpthread-nonshared sub-package. +############################################################################## +ar cr %{glibc_sysroot}%{_prefix}/%{_lib}/libpthread_nonshared.a + +############################################################################## +# Beyond this point in the install process we no longer modify the set of +# installed files, with one exception, for auxarches we cleanup the file list +# at the end and remove files which we don't intend to ship. We need the file +# list to effect a proper cleanup, and so it happens last. +############################################################################## + +############################################################################## +# Build the file lists used for describing the package and subpackages. +############################################################################## +# There are several main file lists (and many more for +# the langpack sub-packages (langpack-${lang}.filelist)): +# * master.filelist +# - Master file list from which all other lists are built. +# * glibc.filelist +# - Files for the glibc packages. +# * common.filelist +# - Flies for the common subpackage. +# * utils.filelist +# - Files for the utils subpackage. +# * nscd.filelist +# - Files for the nscd subpackage. +# * devel.filelist +# - Files for the devel subpackage. +# * doc.filelist +# - Files for the documentation subpackage. +# * headers.filelist +# - Files for the headers subpackage. +# * static.filelist +# - Files for the static subpackage. +# * libnsl.filelist +# - Files for the libnsl subpackage +# * nss_db.filelist +# * nss_hesiod.filelist +# - File lists for nss_* NSS module subpackages. +# * nss-devel.filelist +# - File list with the .so symbolic links for NSS packages. +# * compat-libpthread-nonshared.filelist. +# - File list for compat-libpthread-nonshared subpackage. + +# Create the main file lists. This way we can append to any one of them later +# wihtout having to create it. Note these are removed at the start of the +# install phase. +touch master.filelist +touch glibc.filelist +touch common.filelist +touch utils.filelist +touch gconv.filelist +touch nscd.filelist +touch devel.filelist +touch doc.filelist +touch headers.filelist +touch static.filelist +touch libnsl.filelist +touch nss_db.filelist +touch nss_hesiod.filelist +touch nss-devel.filelist +touch compat-libpthread-nonshared.filelist + +############################################################################### +# Master file list, excluding a few things. +############################################################################### +{ + # List all files or links that we have created during install. + # Files with 'etc' are configuration files, likewise 'gconv-modules' + # and 'gconv-modules.cache' are caches, and we exclude them. + find %{glibc_sysroot} \( -type f -o -type l \) \ + \( \ + -name etc -printf "%%%%config " -o \ + -name gconv-modules.cache \ + -printf "%%%%verify(not md5 size mtime) " -o \ + -name gconv-modules* \ + -printf "%%%%verify(not md5 size mtime) %%%%config(noreplace) " \ + , \ + ! -path "*/lib/debug/*" -printf "/%%P\n" \) + # List all directories with a %%dir prefix. We omit the info directory and + # all directories in (and including) /usr/share/locale. + find %{glibc_sysroot} -type d \ + \( -path '*%{_prefix}/share/locale' -prune -o \ + \( -path '*%{_prefix}/share/*' \ +%if %{with docs} + ! -path '*%{_infodir}' -o \ +%endif + -path "*%{_prefix}/include/*" \ + \) -printf "%%%%dir /%%P\n" \) +} | { + # Also remove the *.mo entries. We will add them to the + # language specific sub-packages. + # libnss_ files go into subpackages related to NSS modules. + # and .*/share/i18n/charmaps/.*), they go into the sub-package + # "locale-source": + sed -e '\,.*/share/locale/\([^/_]\+\).*/LC_MESSAGES/.*\.mo,d' \ + -e '\,.*/share/i18n/locales/.*,d' \ + -e '\,.*/share/i18n/charmaps/.*,d' \ + -e '\,.*/etc/\(localtime\|nsswitch.conf\|ld\.so\.conf\|ld\.so\.cache\|default\|rpc\|gai\.conf\),d' \ + -e '\,.*/%{_libdir}/lib\(pcprofile\|memusage\)\.so,d' \ + -e '\,.*/bin/\(memusage\|mtrace\|xtrace\|pcprofiledump\),d' +} | sort > master.filelist + +# The master file list is now used by each subpackage to list their own +# files. We go through each package and subpackage now and create their lists. +# Each subpackage picks the files from the master list that they need. +# The order of the subpackage list generation does not matter. + +# Make the master file list read-only after this point to avoid accidental +# modification. +chmod 0444 master.filelist + +############################################################################### +# glibc +############################################################################### + +# Add all files with the following exceptions: +# - The info files '%{_infodir}/dir' +# - The partial (lib*_p.a) static libraries, include files. +# - The static files, objects, unversioned DSOs, and nscd. +# - The bin, locale, some sbin, and share. +# - We want iconvconfig in the main package and we do this by using +# a double negation of -v and [^i] so it removes all files in +# sbin *but* iconvconfig. +# - 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 all-langpacks package. +# - Extra gconv modules. We add the required modules later. +cat master.filelist \ + | grep -v \ + -e '%{_infodir}' \ + -e '%{_libdir}/lib.*_p.a' \ + -e '%{_prefix}/include' \ + -e '%{_libdir}/lib.*\.a' \ + -e '%{_libdir}/.*\.o' \ + -e '%{_libdir}/lib.*\.so' \ + -e '%{_libdir}/gconv/.*\.so$' \ + -e '%{_libdir}/gconv/gconv-modules.d/gconv-modules-extra\.conf$' \ + -e 'nscd' \ + -e '%{_prefix}/bin' \ + -e '%{_prefix}/lib/locale' \ + -e '%{_prefix}/sbin/[^i]' \ + -e '%{_prefix}/share' \ + -e '/var/db/Makefile' \ + -e '/libnss_.*\.so[0-9.]*$' \ + -e '/libnsl' \ + -e 'glibc-benchtests' \ + -e 'aux-cache' \ + -e 'build-locale-archive' \ + > glibc.filelist + +# Add specific files: +# - The nss_files, nss_compat, and nss_db files. +# - The libmemusage.so and libpcprofile.so used by utils. +for module in compat files dns; do + cat master.filelist \ + | grep -E \ + -e "/libnss_$module(\.so\.[0-9.]+|-[0-9.]+\.so)$" \ + >> glibc.filelist +done +grep -e "libmemusage.so" -e "libpcprofile.so" master.filelist >> glibc.filelist + +############################################################################### +# glibc-gconv-extra +############################################################################### + +grep -e "gconv-modules-extra.conf" master.filelist > gconv.filelist + +# Put the essential gconv modules into the main package. +GconvBaseModules="ANSI_X3.110 ISO8859-15 ISO8859-1 CP1252" +GconvBaseModules="$GconvBaseModules UNICODE UTF-16 UTF-32 UTF-7" +%ifarch s390 s390x +GconvBaseModules="$GconvBaseModules ISO-8859-1_CP037_Z900 UTF8_UTF16_Z9" +GconvBaseModules="$GconvBaseModules UTF16_UTF32_Z9 UTF8_UTF32_Z9" +%endif +GconvAllModules=$(cat master.filelist | + sed -n 's|%{_libdir}/gconv/\(.*\)\.so|\1|p') + +# Put the base modules into glibc and the rest into glibc-gconv-extra +for conv in $GconvAllModules; do + if echo $GconvBaseModules | grep -q $conv; then + grep -E -e "%{_libdir}/gconv/$conv.so$" \ + master.filelist >> glibc.filelist + else + grep -E -e "%{_libdir}/gconv/$conv.so$" \ + master.filelist >> gconv.filelist + fi +done + + +############################################################################### +# glibc-devel +############################################################################### + +# Put some static files into the devel package. +grep '%{_libdir}/lib.*\.a' master.filelist \ + | grep '/lib\(\(c\|pthread\|nldbl\|mvec\)_nonshared\|g\|ieee\|mcheck\)\.a$' \ + > devel.filelist + +# Put all of the object files and *.so (not the versioned ones) into the +# devel package. +grep '%{_libdir}/.*\.o' < master.filelist >> devel.filelist +grep '%{_libdir}/lib.*\.so' < master.filelist >> devel.filelist +# The exceptions are: +# - libmemusage.so and libpcprofile.so in glibc used by utils. +# - libnss_*.so which are in nss-devel. +sed -i -e '\,libmemusage.so,d' \ + -e '\,libpcprofile.so,d' \ + -e '\,/libnss_[a-z]*\.so$,d' \ + devel.filelist + +############################################################################### +# glibc-doc +############################################################################### + +%if %{with docs} +# Put the info files into the doc file list, but exclude the generated dir. +grep '%{_infodir}' master.filelist | grep -v '%{_infodir}/dir' > doc.filelist +grep '%{_docdir}' master.filelist >> doc.filelist +%endif + +############################################################################### +# glibc-headers +############################################################################### + +# The glibc-headers package includes only common files which are identical +# across all multilib packages. We must keep gnu/stubs.h and gnu/lib-names.h +# in the glibc-headers package, but the -32, -64, -64-v1, and -64-v2 versions +# go into the development packages. +grep '%{_prefix}/include/gnu/stubs-.*\.h$' < master.filelist >> devel.filelist || : +grep '%{_prefix}/include/gnu/lib-names-.*\.h$' < master.filelist >> devel.filelist || : +# Put the include files into headers file list. +grep '%{_prefix}/include' < master.filelist \ + | egrep -v '%{_prefix}/include/gnu/stubs-.*\.h$' \ + | egrep -v '%{_prefix}/include/gnu/lib-names-.*\.h$' \ + > headers.filelist + +############################################################################### +# glibc-static +############################################################################### + +# Put the rest of the static files into the static package. +grep '%{_libdir}/lib.*\.a' < master.filelist \ + | grep -v '/lib\(\(c\|pthread\|nldbl\|mvec\)_nonshared\|g\|ieee\|mcheck\)\.a$' \ + > static.filelist + +############################################################################### +# glibc-common +############################################################################### + +# All of the bin and certain sbin files go into the common package except +# 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. +# Exceptions: +# - The actual share directory, not owned by us. +# - The info files which go into doc, and the info directory. +# - All documentation files, which go into doc. +grep '%{_prefix}/share' master.filelist \ + | grep -v \ + -e '%{_prefix}/share/info/libc.info.*' \ + -e '%%dir %{prefix}/share/info' \ + -e '%%dir %{prefix}/share' \ + -e '%{_docdir}' \ + >> common.filelist + +############################################################################### +# nscd +############################################################################### + +# The nscd binary must go into the nscd subpackage. +echo '%{_prefix}/sbin/nscd' > nscd.filelist + +############################################################################### +# glibc-utils +############################################################################### + +# Add the utils scripts and programs to the utils subpackage. +cat > utils.filelist < nss_$module.filelist +done + +############################################################################### +# nss-devel +############################################################################### + +# Symlinks go into the nss-devel package (instead of the main devel +# package). +grep '/libnss_[a-z]*\.so$' master.filelist > nss-devel.filelist + +############################################################################### +# libnsl +############################################################################### + +# Prepare the libnsl-related file lists. +grep '/libnsl-[0-9.]*.so$' master.filelist > libnsl.filelist +test $(wc -l < libnsl.filelist) -eq 1 + +%if %{with benchtests} +############################################################################### +# glibc-benchtests +############################################################################### + +# List of benchmarks. +find build-%{target}/benchtests -type f -executable | while read b; do + echo "%{_prefix}/libexec/glibc-benchtests/$(basename $b)" +done >> benchtests.filelist +# ... and the makefile. +for b in %{SOURCE9} %{SOURCE10}; do + echo "%{_prefix}/libexec/glibc-benchtests/$(basename $b)" >> benchtests.filelist +done +# ... and finally, the comparison scripts. +echo "%{_prefix}/libexec/glibc-benchtests/benchout.schema.json" >> benchtests.filelist +echo "%{_prefix}/libexec/glibc-benchtests/compare_bench.py*" >> benchtests.filelist +echo "%{_prefix}/libexec/glibc-benchtests/import_bench.py*" >> benchtests.filelist +echo "%{_prefix}/libexec/glibc-benchtests/validate_benchout.py*" >> benchtests.filelist +%endif + +############################################################################### +# compat-libpthread-nonshared +############################################################################### +echo "%{_libdir}/libpthread_nonshared.a" >> compat-libpthread-nonshared.filelist + +############################################################################## +# Delete files that we do not intended to ship with the auxarch. +# This is the only place where we touch the installed files after generating +# the file lists. +############################################################################## +%ifarch %{auxarches} +echo Cutting down the list of unpackaged files +sed -e '/%%dir/d;/%%config/d;/%%verify/d;s/%%lang([^)]*) //;s#^/*##' \ + common.filelist devel.filelist static.filelist headers.filelist \ + utils.filelist nscd.filelist \ +%ifarch %{debuginfocommonarches} + debuginfocommon.filelist \ +%endif + | (cd %{glibc_sysroot}; xargs --no-run-if-empty rm -f 2> /dev/null || :) +%comment Matches: %ifarch %{auxarches} +%endif + +############################################################################## +# Run the glibc testsuite +############################################################################## +%check +%if %{with testsuite} + +# Run the glibc tests. If any tests fail to build we exit %check with +# an error, otherwise we print the test failure list and the failed +# test output and continue. Write to standard error to avoid +# synchronization issues with make and shell tracing output if +# standard output and standard error are different pipes. +run_tests () { + # This hides a test suite build failure, which should be fatal. We + # check "Summary of test results:" below to verify that all tests + # were built and run. + make %{?_smp_mflags} -O check |& tee rpmbuild.check.log >&2 + test -n tests.sum + if ! grep -q '^Summary of test results:$' rpmbuild.check.log ; then + echo "FAIL: test suite build of target: $(basename "$(pwd)")" >& 2 + exit 1 + fi + set +x + grep -v ^PASS: tests.sum > rpmbuild.tests.sum.not-passing || true + if test -n rpmbuild.tests.sum.not-passing ; then + echo ===================FAILED TESTS===================== >&2 + echo "Target: $(basename "$(pwd)")" >& 2 + cat rpmbuild.tests.sum.not-passing >&2 + while read failed_code failed_test ; do + for suffix in out test-result ; do + if test -e "$failed_test.$suffix"; then + echo >&2 + echo "=====$failed_code $failed_test.$suffix=====" >&2 + cat -- "$failed_test.$suffix" >&2 + echo >&2 + fi + done + done &2 + cat misc/tst-syscall-list.out >&2 + set -x +} + +# Increase timeouts +export TIMEOUTFACTOR=16 +parent=$$ +echo ====================TESTING========================= + +# Default libraries. +pushd build-%{target} +run_tests +popd + +%if %{buildpower9} +echo ====================TESTING -mcpu=power9============= +pushd build-%{target}-power9 +run_tests +popd +%endif + + + +echo ====================TESTING END===================== +PLTCMD='/^Relocation section .*\(\.rela\?\.plt\|\.rela\.IA_64\.pltoff\)/,/^$/p' +echo ====================PLT RELOCS LD.SO================ +readelf -Wr %{glibc_sysroot}/%{_lib}/ld-*.so | sed -n -e "$PLTCMD" +echo ====================PLT RELOCS LIBC.SO============== +readelf -Wr %{glibc_sysroot}/%{_lib}/libc-*.so | sed -n -e "$PLTCMD" +echo ====================PLT RELOCS END================== + +# Obtain a way to run the dynamic loader. Avoid matching the symbolic +# link and then pick the first loader (although there should be only +# one). +run_ldso="$(find %{glibc_sysroot}/%{_lib}/ld-*.so -type f | LC_ALL=C sort | head -n1) --library-path %{glibc_sysroot}/%{_lib}" + +# Show the auxiliary vector as seen by the new library +# (even if we do not perform the valgrind test). +LD_SHOW_AUXV=1 $run_ldso /bin/true + +# Finally, check if valgrind runs with the new glibc. +# We want to fail building if valgrind is not able to run with this glibc so +# that we can then coordinate with valgrind to get it fixed before we update +# glibc. +pushd build-%{target} + +# Show the auxiliary vector as seen by the new library +# (even if we do not perform the valgrind test). +LD_SHOW_AUXV=1 $run_ldso /bin/true + +%if %{with valgrind} +$run_ldso /usr/bin/valgrind --error-exitcode=1 \ + $run_ldso /usr/bin/true +%endif +popd + +%comment Matches: %if %{with testsuite} +%endif + + +%pre -p +-- Check that the running kernel is new enough +required = '%{enablekernel}' +rel = posix.uname("%r") +if rpm.vercmp(rel, required) < 0 then + error("FATAL: kernel too old", 0) +end + +%post -p +%glibc_post_funcs +-- (1) Remove multilib libraries from previous installs. +-- In order to support in-place upgrades, we must immediately remove +-- obsolete platform directories after installing a new glibc +-- version. RPM only deletes files removed by updates near the end +-- of the transaction. If we did not remove the obsolete platform +-- directories here, they may be preferred by the dynamic linker +-- during the execution of subsequent RPM scriptlets, likely +-- resulting in process startup failures. + +-- Full set of libraries glibc may install. +install_libs = { "anl", "BrokenLocale", "c", "dl", "m", "mvec", + "nss_compat", "nss_db", "nss_dns", "nss_files", + "nss_hesiod", "pthread", "resolv", "rt", "SegFault", + "thread_db", "util" } + +-- We are going to remove these libraries. Generally speaking we remove +-- all core libraries in the multilib directory. +-- We employ a tight match where X.Y is in [2.0,9.9*], so we would +-- match "libc-2.0.so" and so on up to "libc-9.9*". +remove_regexps = {} +for i = 1, #install_libs do + remove_regexps[i] = ("lib" .. install_libs[i] + .. "%%-[2-9]%%.[0-9]+%%.so$") +end + +-- Two exceptions: +remove_regexps[#install_libs + 1] = "libthread_db%%-1%%.0%%.so" +remove_regexps[#install_libs + 2] = "libSegFault%%.so" + +-- We are going to search these directories. +local remove_dirs = { "%{_libdir}/i686", + "%{_libdir}/i686/nosegneg", + "%{_libdir}/power6", + "%{_libdir}/power7", + "%{_libdir}/power8", + "%{_libdir}/power9"} + +-- Walk all the directories with files we need to remove... +for _, rdir in ipairs (remove_dirs) do + if posix.access (rdir) then + -- If the directory exists we look at all the files... + local remove_files = posix.files (rdir) + for rfile in remove_files do + for _, rregexp in ipairs (remove_regexps) do + -- Does it match the regexp? + local dso = string.match (rfile, rregexp) + if (dso ~= nil) then + -- Removing file... + os.remove (rdir .. '/' .. rfile) + end + end + end + end +end + +-- (2) Update /etc/ld.so.conf +-- Next we update /etc/ld.so.conf to ensure that it starts with +-- a literal "include ld.so.conf.d/*.conf". + +local ldsoconf = "/etc/ld.so.conf" +local ldsoconf_tmp = "/etc/glibc_post_upgrade.ld.so.conf" + +if posix.access (ldsoconf) then + + -- We must have a "include ld.so.conf.d/*.conf" line. + local have_include = false + for line in io.lines (ldsoconf) do + -- This must match, and we don't ignore whitespace. + if string.match (line, "^include ld.so.conf.d/%%*%%.conf$") ~= nil then + have_include = true + end + end + + if not have_include then + -- Insert "include ld.so.conf.d/*.conf" line at the start of the + -- file. We only support one of these post upgrades running at + -- a time (temporary file name is fixed). + local tmp_fd = io.open (ldsoconf_tmp, "w") + if tmp_fd ~= nil then + tmp_fd:write ("include ld.so.conf.d/*.conf\n") + for line in io.lines (ldsoconf) do + tmp_fd:write (line .. "\n") + end + tmp_fd:close () + local res = os.rename (ldsoconf_tmp, ldsoconf) + if res == nil then + io.stdout:write ("Error: Unable to update configuration file (rename).\n") + end + else + io.stdout:write ("Error: Unable to update configuration file (open).\n") + end + end +end + +-- (3) Rebuild ld.so.cache early. +-- If the format of the cache changes then we need to rebuild +-- the cache early to avoid any problems running binaries with +-- the new glibc. + +-- Note: We use _prefix because Fedora's UsrMove says so. +post_exec ("%{_prefix}/sbin/ldconfig") + +-- (4) Update gconv modules cache. +-- If the /usr/lib/gconv/gconv-modules.cache exists, then update it +-- with the latest set of modules that were just installed. +-- We assume that the cache is in _libdir/gconv and called +-- "gconv-modules.cache". + +update_gconv_modules_cache() + +%posttrans all-langpacks -e -p +-- If at the end of the transaction we are still installed +-- (have a template of non-zero size), then we rebuild the +-- locale cache (locale-archive) from the pre-populated +-- locale cache (locale-archive.tmpl) i.e. template. +if posix.stat("%{_prefix}/lib/locale/locale-archive.tmpl", "size") > 0 then + pid = posix.fork() + if pid == 0 then + posix.exec("%{_prefix}/sbin/build-locale-archive", "--install-langs", "%%{_install_langs}") + elseif pid > 0 then + posix.wait(pid) + end +end + +%postun all-langpacks -p +-- In the postun we remove the locale cache if unstalling. +-- (build-locale-archive will delete the archive during an upgrade.) +if arg[2] == 0 then + os.remove("%{_prefix}/lib/locale/locale-archive") +end + +%if %{with docs} +%post devel +/sbin/install-info %{_infodir}/libc.info.gz %{_infodir}/dir > /dev/null 2>&1 || : +%endif + +%pre headers +# this used to be a link and it is causing nightmares now +if [ -L %{_prefix}/include/scsi ] ; then + rm -f %{_prefix}/include/scsi +fi + +%if %{with docs} +%preun devel +if [ "$1" = 0 ]; then + /sbin/install-info --delete %{_infodir}/libc.info.gz %{_infodir}/dir > /dev/null 2>&1 || : +fi +%endif + +%post gconv-extra -p +%glibc_post_funcs +update_gconv_modules_cache () + +%postun gconv-extra -p +%glibc_post_funcs +update_gconv_modules_cache () + +%pre -n nscd +getent group nscd >/dev/null || /usr/sbin/groupadd -g 28 -r nscd +getent passwd nscd >/dev/null || + /usr/sbin/useradd -M -o -r -d / -s /sbin/nologin \ + -c "NSCD Daemon" -u 28 -g nscd nscd + +%post -n nscd +%systemd_post nscd.service + +%preun -n nscd +%systemd_preun nscd.service + +%postun -n nscd +if test $1 = 0; then + /usr/sbin/userdel nscd > /dev/null 2>&1 || : +fi +%systemd_postun_with_restart nscd.service + +%files -f glibc.filelist +%dir %{_prefix}/%{_lib}/audit +%if %{buildpower9} +%dir /%{_lib}/glibc-hwcaps/power9 +%endif +%ifarch s390x +/lib/ld64.so.1 +%endif +%verify(not md5 size mtime link) %config(noreplace) /etc/nsswitch.conf +%verify(not md5 size mtime) %config(noreplace) /etc/ld.so.conf +%verify(not md5 size mtime) %config(noreplace) /etc/rpc +%dir /etc/ld.so.conf.d +%dir %{_prefix}/libexec/getconf +%dir %{_libdir}/gconv +%dir %{_libdir}/gconv/gconv-modules.d +%dir %attr(0700,root,root) /var/cache/ldconfig +%attr(0600,root,root) %verify(not md5 size mtime) %ghost %config(missingok,noreplace) /var/cache/ldconfig/aux-cache +%attr(0644,root,root) %verify(not md5 size mtime) %ghost %config(missingok,noreplace) /etc/ld.so.cache +%attr(0644,root,root) %verify(not md5 size mtime) %ghost %config(missingok,noreplace) /etc/gai.conf +# If rpm doesn't support %license, then use %doc instead. +%{!?_licensedir:%global license %%doc} +%license COPYING COPYING.LIB LICENSES + +%ifnarch %{auxarches} +%files -f common.filelist common +%dir %{_prefix}/lib/locale +%dir %{_prefix}/lib/locale/C.utf8 +%{_prefix}/lib/locale/C.utf8/* + +%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 +%{_prefix}/share/i18n/locales/* +%dir %{_prefix}/share/i18n/charmaps +%{_prefix}/share/i18n/charmaps/* + +%files -f devel.filelist devel + +%if %{with docs} +%files -f doc.filelist doc +%endif + +%files -f static.filelist static + +%files -f headers.filelist headers + +%files -f utils.filelist utils + +%files -f gconv.filelist gconv-extra + +%files -f nscd.filelist -n nscd +%config(noreplace) /etc/nscd.conf +%dir %attr(0755,root,root) /var/run/nscd +%dir %attr(0755,root,root) /var/db/nscd +/lib/systemd/system/nscd.service +/lib/systemd/system/nscd.socket +%{_tmpfilesdir}/nscd.conf +%attr(0644,root,root) %verify(not md5 size mtime) %ghost %config(missingok,noreplace) /var/run/nscd/nscd.pid +%attr(0666,root,root) %verify(not md5 size mtime) %ghost %config(missingok,noreplace) /var/run/nscd/socket +%attr(0600,root,root) %verify(not md5 size mtime) %ghost %config(missingok,noreplace) /var/run/nscd/passwd +%attr(0600,root,root) %verify(not md5 size mtime) %ghost %config(missingok,noreplace) /var/run/nscd/group +%attr(0600,root,root) %verify(not md5 size mtime) %ghost %config(missingok,noreplace) /var/run/nscd/hosts +%attr(0600,root,root) %verify(not md5 size mtime) %ghost %config(missingok,noreplace) /var/run/nscd/services +%attr(0600,root,root) %verify(not md5 size mtime) %ghost %config(missingok,noreplace) /var/db/nscd/passwd +%attr(0600,root,root) %verify(not md5 size mtime) %ghost %config(missingok,noreplace) /var/db/nscd/group +%attr(0600,root,root) %verify(not md5 size mtime) %ghost %config(missingok,noreplace) /var/db/nscd/hosts +%attr(0600,root,root) %verify(not md5 size mtime) %ghost %config(missingok,noreplace) /var/db/nscd/services +%ghost %config(missingok,noreplace) /etc/sysconfig/nscd +%endif + +%files -f nss_db.filelist -n nss_db +/var/db/Makefile +%files -f nss_hesiod.filelist -n nss_hesiod +%doc hesiod/README.hesiod +%files -f nss-devel.filelist nss-devel + +%files -f libnsl.filelist -n libnsl +/%{_lib}/libnsl.so.1 + +%if %{with benchtests} +%files benchtests -f benchtests.filelist +%endif + +%files -f compat-libpthread-nonshared.filelist -n compat-libpthread-nonshared + +%changelog +* Fri Mar 29 2024 MSVSphere Packaging Team - 2.28-251 +- Rebuilt for MSVSphere 8.10 beta + +* Thu Jan 18 2024 Florian Weimer - 2.28-251 +- Cache information in x86_64 ld.so --list-diagnostics output (RHEL-21997) + +* Wed Jan 10 2024 Arjun Shankar - 2.28-250 +- getaddrinfo: Return correct error EAI_MEMORY when out-of-memory (RHEL-19445) + +* Wed Jan 3 2024 Florian Weimer - 2.28-249 +- Updates for AMD cache size computation (RHEL-3010) + +* Tue Jan 2 2024 Florian Weimer - 2.28-248 +- Re-enable output buffering for wide stdio streams (RHEL-19824) + +* Thu Dec 21 2023 Carlos O'Donell - 2.28-247 +- Fix TLS corruption during dlopen()/dlclose() sequences (RHEL-17468) + +* Thu Dec 14 2023 DJ Delorie - 2.28-246 +- Include CentOS Hyperscaler SIG patches backported by Intel (RHEL-15696) + +* Fri Dec 8 2023 Florian Weimer - 2.28-245 +- Improve compatibility between underlinking and IFUNC resolvers (RHEL-16825) + +* Fri Nov 24 2023 Florian Weimer - 2.28-244 +- Restore compatibility with C90 compilers (RHEL-15867) + +* Tue Nov 21 2023 Florian Weimer - 2.28-243 +- ldconfig should skip temporary files created by RPM (RHEL-13720) + +* Mon Nov 20 2023 Florian Weimer - 2.28-242 +- Fix force-first handling in dlclose (RHEL-10481) + +* Fri Nov 10 2023 Florian Weimer - 2.28-241 +- Avoid lazy binding failures during dlclose (RHEL-3639) + +* Tue Oct 24 2023 Arjun Shankar - 2.28-240 +- Add /usr/share/doc/glibc/gai.conf to glibc-doc (RHEL-12894) + +* Fri Oct 20 2023 Florian Weimer - 2.28-239 +- nscd: Skip unusable entries in first pass in prune_cache (RHEL-1192) + +* Mon Oct 16 2023 DJ Delorie - 2.28-238 +- Fix slow tls access after dlopen (RHEL-2122) + +* Mon Oct 16 2023 Arjun Shankar - 2.28-237 +- Enable running a single test from the testsuite (RHEL-3757) + +* Wed Sep 20 2023 Siddhesh Poyarekar - 2.28-236.7 +- CVE-2023-4911 glibc: buffer overflow in ld.so leading to privilege escalation (RHEL-3036) + +* Tue Sep 19 2023 Carlos O'Donell - 2.28-236.6 +- Revert: Always call destructors in reverse constructor order (#2233338) + +* Tue Sep 19 2023 Siddhesh Poyarekar - 2.28-236.5 +- CVE-2023-4806 glibc: potential use-after-free in getaddrinfo (RHEL-2423) + +* Tue Sep 19 2023 Siddhesh Poyarekar - 2.28-236.4 +- CVE-2023-4813: Work around RHEL-8 limitation in test (RHEL-2435) + +* Fri Sep 15 2023 Siddhesh Poyarekar - 2.28-236.3 +- CVE-2023-4813: potential use-after-free in gaih_inet (RHEL-2435) + +* Wed Sep 13 2023 Florian Weimer - 2.28-236.2 +- CVE-2023-4527: Stack read overflow in getaddrinfo in no-aaaa mode (#2234714) + +* Mon Sep 11 2023 Florian Weimer - 2.28-236.1 +- Always call destructors in reverse constructor order (#2233338) + +* Tue Aug 15 2023 Carlos O'Donell - 2.28-236 +- Fix string and memory function tuning on small systems (#2180462) + +* Tue Aug 8 2023 DJ Delorie - 2.28-235 +- Fix temporal threshold calculations (#2180462) + +* Mon Aug 7 2023 Florian Weimer - 2.28-234 +- Ignore symbolic link change on /etc/nsswitch.conf (#2229709) + +* Wed Jul 26 2023 DJ Delorie - 2.28-233 +- Update test to closer match upstream. (#2176707) + +* Fri Jul 21 2023 Florian Weimer - 2.28-232 +- Make libSegFault.so NODELETE (#2224348) + +* Sun Jul 9 2023 Carlos O'Donell - 2.28-231 +- Update ESTALE error message translations (#2186781) + +* Fri Jul 7 2023 DJ Delorie - 2.28-230 +- Don't block SIGCHILD when system() is called concurrently (#2176707) + +* Mon Jul 3 2023 DJ Delorie - 2.28-229 +- resolv_conf: release lock on allocation failure (#2213909) + +* Mon May 22 2023 Florian Weimer - 2.28-228 +- gmon: Various bug fixes (#2180155) + +* Thu May 18 2023 Patsy Griffin - 2.28-227 +- Change sgetsgent_r to set errno. (#2172949) + +* Wed May 3 2023 Florian Weimer - 2.28-226 +- Fix incorrect inline feraiseexcept on i686, x86-64 (#2183081) + +* Fri Jan 20 2023 Florian Weimer - 2.28-225 +- Enforce a specififc internal ordering for tunables (#2154914) + +* Wed Nov 30 2022 Arjun Shankar - 2.28-224 +- Fix rtld-audit trampoline for aarch64 (#2144568) + +* Fri Nov 25 2022 Arjun Shankar - 2.28-223 +- Backport upstream fixes to tst-pldd (#2142937) + +* Tue Nov 22 2022 Florian Weimer - 2.28-222 +- Restore IPC_64 support in sysvipc *ctl functions (#2141989) + +* Fri Nov 18 2022 Florian Weimer - 2.28-221 +- Switch to fast DSO dependency sorting algorithm (#1159809) + +* Thu Nov 3 2022 Florian Weimer - 2.28-220 +- Explicitly switch to --with-default-link=no (#2109510) +- Define MAP_SYNC on ppc64le (#2139875) + +* Mon Oct 24 2022 Arjun Shankar - 2.28-219 +- Fix -Wstrict-overflow warning when using CMSG_NXTHDR macro (#2116938) + +* 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 + (#2032281) + +* Tue Jan 25 2022 Siddhesh Poyarekar - 2.28-188 +- CVE-2022-23218, CVE-2022-23219: Fix buffer overflows in sunrpc clnt_create + for "unix" and svcunix_create (#2045063). + +* Mon Jan 24 2022 Siddhesh Poyarekar - 2.28-187 +- CVE-2021-3999: getcwd: Set errno to ERANGE for size == 1 (#2032281) + +* Fri Jan 21 2022 Carlos O'Donell - 2.28-186 +- Fix pthread_once regression with C++ exceptions (#2007327) + +* Thu Jan 20 2022 DJ Delorie - 2.28-185 +- Adjust to rpm's find-debuginfo.sh changes, to keep stripping binaries (#1661513) + +* Fri Jan 7 2022 Florian Weimer - 2.28-184 +- Conversion from ISO-2022-JP-3 may emit spurious NUL character (#2033655) + +* Fri Jan 7 2022 Florian Weimer - 2.28-183 +- aarch64: A64FX optimizations break "sve=off" guest mode (#2036955) + +* Fri Jan 7 2022 Patsy Griffin - 2.28-182 +- Handle truncated timezones from tzcode-2021d and later. (#2033648) + +* Tue Jan 4 2022 Siddhesh Poyarekar - 2.28-181 +- Weaken dependency of glibc on glibc-gconv-extra (#2015768) + +* Mon Dec 13 2021 Florian Weimer - 2.28-180 +- Do not install /usr/lib/debug/usr/bin/ld.so.debug (#2023420) + +* Fri Dec 10 2021 Florian Weimer - 2.28-179 +- Add /usr/bin/ld.so --list-diagnostics (#2023420) + +* Fri Dec 10 2021 Carlos O'Donell - 2.28-178 +- Preliminary support for new IBM zSeries hardware (#1984802) + +* Fri Dec 10 2021 Carlos O'Donell - 2.28-177 +- Fix --with and --without builds for benchtests and bootstrap (#2020989) + +* Wed Dec 1 2021 Florian Weimer - 2.28-176 +- A64FX memcpy/memmove/memset optimizations (#1929928) + +* Tue Nov 30 2021 Florian Weimer - 2.28-175 +- Fix dl-tls.c assert failure with pthread_create & dlopen (#1991001) +- Fix x86_64 TLS lazy binding with auditors (#1950056) + +* Thu Nov 25 2021 Arjun Shankar - 2.28-174 +- Introduce new glibc-doc.noarch subpackage (#2021671) +- Move the reference manual info pages from glibc-devel to glibc-doc +- Move debugger interface documentation from glibc to glibc-doc +- Remove unnecessary README, INSTALL, NEWS files from glibc +- Remove unnecessary README.timezone and gai.conf files from glibc-common + +* Wed Nov 17 2021 Patsy Griffin - 2.28-173 +- Add new English-language 12 hour time locale en_US@ampm.UTF-8 (#2000374) + +* Tue Nov 16 2021 Siddhesh Poyarekar - 2.28-172 +- Build build-locale-archive with -static-pie when supported (#1965377) + +* Wed Nov 10 2021 DJ Delorie - 2.28-171 +- elf: Always set link map in _dl_init_paths (#1934162) + +* Wed Nov 10 2021 Arjun Shankar - 2.28-170 +- x86: Properly disable XSAVE related features when its use is disabled via + tunables (#1937515) + +* Wed Nov 10 2021 Arjun Shankar - 2.28-169 +- s390: Use long branches across object boundaries (#2021452) + +* Fri Oct 29 2021 Arjun Shankar - 2.28-168 +- Optimize memcmp, strcpy, and stpcpy for IBM POWER10 (#1983203) + +* Wed Oct 13 2021 Arjun Shankar - 2.28-167 +- malloc: Initiate tcache shutdown even without allocations (#1977614) + +* Wed Oct 13 2021 Siddhesh Poyarekar - 2.28-166 +- Fix debuginfo location for gconv-extra and make glibc Require it (#1971664). + +* Wed Oct 6 2021 Siddhesh Poyarekar - 2.28-165 +- Split extra gconv modules into a separate package (#1971664). + +* Mon Aug 9 2021 Siddhesh Poyarekar - 2.28-164 +- librt: fix NULL pointer dereference (#1966472). + +* Mon Aug 9 2021 Siddhesh Poyarekar - 2.28-163 +- CVE-2021-33574: Deep copy pthread attribute in mq_notify (#1966472) + +* Thu Jul 8 2021 Siddhesh Poyarekar - 2.28-162 +- CVE-2021-35942: wordexp: handle overflow in positional parameter number + (#1979127) + +* Fri Jun 18 2021 Carlos O'Donell - 2.28-161 +- Improve POWER10 performance with POWER9 fallbacks (#1956357) + +* Mon May 31 2021 Arjun Shankar - 2.28-160 +- Backport POWER10 optimized rawmemchr for ppc64le (#1956357) + +* Thu May 27 2021 Arjun Shankar - 2.28-159 +- Backport additional ifunc optimizations for ppc64le (#1956357) + +* Thu Apr 22 2021 Florian Weimer - 2.28-158 +- Rebuild with new binutils (#1946518) + +* Wed Apr 14 2021 Siddhesh Poyarekar - 2.28-157 +- Consistently SXID_ERASE tunables in sxid binaries (#1934155) + +* Wed Mar 31 2021 DJ Delorie - 2.28-156 +- Backport ifunc optimizations for glibc for ppc64le (#1918719) + +* Wed Mar 24 2021 Arjun Shankar - 2.28-155 +- CVE-2021-27645: nscd: Fix double free in netgroupcache (#1927877) + +* Thu Mar 18 2021 Carlos O'Donell - 2.28-154 +- Add IPPROTO_ETHERNET, IPPROTO_MPTCP, and INADDR_ALLSNOOPERS_GROUP defines + (#1930302) + +* Thu Mar 18 2021 Carlos O'Donell - 2.28-153 +- Support SEM_STAT_ANY via semctl. Return EINVAL for unknown commands to semctl, + msgctl, and shmctl. (#1912670) + +* Tue Mar 16 2021 Patsy Griffin - 2.28-152 +- Update syscall-names.list to 5.7, 5.8, 5.9, 5.10 and 5.11. (#1871386) + +* Mon Mar 15 2021 Siddhesh Poyarekar - 2.28-151 +- CVE-2019-9169: Fix buffer overread in regexec.c (#1936864). + +* Mon Mar 15 2021 Siddhesh Poyarekar - 2.28-150 +- Rebuild glibc to update security markup metadata (#1935128) + +* Mon Mar 15 2021 Siddhesh Poyarekar - 2.28-149 +- Fix NSS files and compat service upgrade defect (#1932770). + +* Fri Feb 5 2021 Florian Weimer - 2.28-148 +- CVE-2021-3326: iconv assertion failure in ISO-2022-JP-3 decoding (#1924919) + +* Wed Jan 20 2021 Florian Weimer - 2.28-147 +- x86-64: Fix FMA4 math routine selection after bug 1817513 (#1918115) + +* Mon Jan 18 2021 Siddhesh Poyarekar - 2.28-146 +- CVE-2019-25013:Fix buffer overrun in EUC-KR conversion module (#1912544) + +* Mon Jan 4 2021 Florian Weimer - 2.28-145 +- Update glibc-hwcaps fix from upstream (#1817513) + +* Tue Dec 15 2020 Florian Weimer - 2.28-144 +- Support running libc.so.6 as a main program in more cases (#1882466) + +* Thu Dec 10 2020 Florian Weimer - 2.28-142 +- Add glibc-hwcaps support (#1817513) +- Implement DT_AUDIT support (#1871385) + +* Mon Nov 30 2020 Carlos O'Donell - 2.28-141 +- Update Intel CET support (#1855790) + +* Tue Nov 10 2020 Carlos O'Donell - 2.28-140 +- Fix calling lazily-bound SVE-using functions on AArch64 (#1893662) + +* Tue Nov 10 2020 Arjun Shankar - 2.28-139 +- CVE-2016-10228, CVE-2020-27618: Fix infinite loops in iconv (#1704868, + #1894669) + +* Fri Nov 6 2020 Florian Weimer - 2.28-138 +- Avoid comments after %%endif in the RPM spec file (#1894340) + +* Fri Oct 30 2020 Florian Weimer - 2.28-137 +- x86: Further memcpy optimizations for AMD Zen (#1880670) + +* Tue Oct 27 2020 DJ Delorie - 2.28-136 +- Allow __getauxval in testsuite check (#1856398) + +* Wed Oct 21 2020 DJ Delorie - 2.28-135 +- Use -moutline-atomics for aarch64 (#1856398) + +* Tue Oct 20 2020 Florian Weimer - 2.28-134 +- resolv: Handle DNS transaction ID collisions (#1868106) + +* Tue Oct 20 2020 Florian Weimer - 2.28-133 +- x86: Update auto-tuning of memcpy non-temporal threshold (#1880670) + +* Mon Oct 5 2020 DJ Delorie - 2.28-132 +- Fix fgetsgent_r data corruption bug (#1871397) + +* Fri Oct 02 2020 Patsy Griffin - 2.28-131 +- Improve IBM zSeries (s390x) Performance (#1871395) + +* Fri Oct 02 2020 Patsy Griffin - 2.28-130 +- Fix avx2 strncmp offset compare condition check (#1871394) +- Add strncmp and strcmp testcases for page boundary + +* Fri Sep 18 2020 Arjun Shankar - 2.28-129 +- Improve IBM POWER9 architecture performance (#1871387) + +* Thu Sep 17 2020 Arjun Shankar - 2.28-128 +- Enable glibc for POWER10 (#1845098) + +* Tue Jun 09 2020 Carlos O'Donell - 2.28-127 +- Improve performance of library strstr() function (#1821531) + +* Wed May 27 2020 Florian Weimer - 2.28-126 +- Do not clobber errno in nss_compat (#1836867) + +* Thu May 14 2020 Carlos O'Donell - 2.28-125 +- Support building rpm under newer versions of Coverity Scan (#1835999) + +* Mon May 11 2020 Florian Weimer - 2.28-124 +- Enhance memory protection key support on ppc64le (#1642150) + +* Thu Apr 23 2020 Florian Weimer - 2.28-123 +- Reduce IFUNC resolver usage in libpthread and librt (#1748197) + +* Thu Apr 9 2020 DJ Delorie - 2.28-122 +- Math library optimizations for IBM Z (#1780204) +- Additional patch for s_nearbyint.c + +* Wed Apr 8 2020 Florian Weimer - 2.28-121 +- elf: Assign TLS modid later during dlopen (#1774115) + +* Wed Apr 8 2020 Florian Weimer - 2.28-120 +- x86-64: Automatically install nss_db.i686 for 32-bit environments (#1807824) + +* Tue Apr 7 2020 Florian Weimer - 2.28-119 +- ppc64le: Enable protection key support (#1642150) + +* Tue Apr 7 2020 Florian Weimer - 2.28-118 +- ppc64le: floating-point status and exception optimizations (#1783303) + +* Fri Apr 3 2020 Patsy Griffin - 2.28-117 +- Update to Linux 5.6 syscall-names.list. (#1810224) + +* Fri Apr 3 2020 Patsy Griffin - 2.28-116 +- CVE-2020-1751: Fix an array overflow in backtrace on PowerPC. (#1813399) + +* Fri Apr 3 2020 Patsy Griffin - 2.28-115 +- CVE:2020-1752: Fix a use after free in glob when expanding ~user. (#1813398) + +* Fri Apr 3 2020 Patsy Griffin - 2.28-114 +- CVE-2020-10029: Prevent stack corruption from crafted input in cosl, sinl, + sincosl, and tanl function. (#1811796) + +* Thu Apr 2 2020 Carlos O'Donell - 2.28-113 +- Improve elf/ and nptl/ testsuites (#1810223) + +* Thu Apr 2 2020 Carlos O'Donell - 2.28-112 +- Fix resource leak in getaddrinfo (#1810146) + +* Thu Apr 2 2020 Carlos O'Donell - 2.28-111 +- Protect locale archive against corruption (#1784525) + +* Thu Apr 2 2020 Carlos O'Donell - 2.28-110 +- Properly handle signed vs. unsigned values in mallopt (#1784520) + +* Thu Apr 2 2020 Carlos O'Donell - 2.28-109 +- Update and harmonize locale names with CLDR (#1757354) + +* Thu Apr 2 2020 Carlos O'Donell - 2.28-108 +- Fix filter and auxiliary filter implementation (#1812756) + +* Thu Apr 2 2020 Carlos O'Donell - 2.28-107 +- Handle .dynstr located in separate segment (#1774114) + +* Fri Mar 27 2020 Patsy Griffin - 2.28-106 +- Disable vtable validation for pre-2.1 interposed handles (#1775819) + +* Fri Mar 27 2020 Patsy Griffin - 2.28-105 +- Define __CORRECT_ISO_CPP_STRING_H_PROTO for Clang. (#1784519) + +* Wed Mar 25 2020 DJ Delorie - 2.28-104 +- Math library optimizations for IBM Z (#1780204) + +* Wed Mar 25 2020 DJ Delorie - 2.28-103 +- Filter "ignore" autofs mount entries in getmntent (#1743445) + +* Wed Mar 25 2020 DJ Delorie - 2.28-102 +- Fix /etc/resolv.conf reloading defects (#1810142) + +* Thu Jan 16 2020 Florian Weimer - 2.28-101 +- ld.so: Reset GL (dl_initfirst) pointer on dlopen failure (#1410154) + +* Fri Dec 13 2019 Florian Weimer - 2.28-100 +- Roll back dynamic linker state on dlopen failure (#1410154) + +* Wed Nov 27 2019 Florian Weimer - 2.28-99 +- s390x: Fix z15 strstr for patterns crossing pages (#1777241) + +* Wed Nov 27 2019 Florian Weimer - 2.28-98 +- Rebuild with new rpm (#1654901) + +* Fri Nov 22 2019 Florian Weimer - 2.28-97 +- Avoid invalid __has_include in (#1775294) + +* Fri Nov 22 2019 Florian Weimer - 2.28-96 +- x86-64: Ignore LD_PREFER_MAP_32BIT_EXEC in SUID binaries (#1774021) + +* Thu Nov 14 2019 DJ Delorie - 2.28-95 +- Fix alignment of TLS variables for tls variant TLS_TCB_AT_TP (#1764214) + +* Thu Nov 14 2019 DJ Delorie - 2.28-94 +- Refuse to dlopen PIE objects (#1764223) + +* Thu Nov 14 2019 Carlos O'Donell - 2.28-93 +- Fix C.UTF-8 locale source ellipsis expressions (#1361965) + +* Thu Nov 14 2019 Carlos O'Donell - 2.28-92 +- Fix hangs during malloc tracing (#1764235) + +* Thu Nov 14 2019 Carlos O'Donell - 2.28-91 +- Support moving versioned symbols between sonames (#1764231) + +* Wed Nov 13 2019 Florian Weimer - 2.28-90 +- Avoid creating stale utmp entries for repeated pututxline (#1749439) + +* Wed Nov 6 2019 Florian Weimer - 2.28-89 +- Backport more precise tokenizer for installed headers test (#1769304) + +* Wed Nov 6 2019 Florian Weimer - 2.28-88 +- math: Enable some math builtins for clang in LLVM Toolset (#1764242) + +* Wed Nov 6 2019 Florian Weimer - 2.28-87 +- Support Fortran vectorized math functions with GCC Toolset 9 (#1764238) + +* Wed Nov 6 2019 Florian Weimer - 2.28-86 +- aarch64: Support STO_AARCH64_VARIANT_PCS, DT_AARCH64_VARIANT_PCS (#1726638) + +* Mon Nov 4 2019 DJ Delorie - 2.28-85 +- Add more test-in-container support (#1747502) + +* Fri Nov 1 2019 DJ Delorie - 2.28-84 +- Fix calling getpwent after endpwent (#1747502) + +* Fri Nov 1 2019 DJ Delorie - 2.28-83 +- nptl: Avoid fork handler lock for async-signal-safe fork (#1746928) + +* Thu Oct 31 2019 DJ Delorie - 2.28-82 +- Call _dl_open_check after relocation (#1682954) + +* Thu Oct 31 2019 Arjun Shankar - 2.28-81 +- Add malloc fastbin tunable (#1764218) + +* Thu Oct 31 2019 Arjun Shankar - 2.28-80 +- Fix race condition in tst-clone3 and add a new ldconfig test, + tst-ldconfig-bad-aux-cache (#1764226) + +* Thu Oct 31 2019 Arjun Shankar - 2.28-79 +- Remove unwanted whitespace from size lines and account for top chunk in + malloc_info output (#1735747) + +* Wed Oct 30 2019 Arjun Shankar - 2.28-78 +- Enhance malloc tcache (#1746933) + +* Tue Oct 29 2019 Patsy Griffin - 2.28-77 +- Don't define initgroups in nsswitch.conf (#1747505) + +* Mon Oct 28 2019 Patsy Griffin - 2.28-76 +- libio: Remove codecvt vtable. (#1764241) + +* Mon Oct 28 2019 Patsy Griffin - 2.28-75 +- Implement --preload option for the dynamic linker.(#1747453) + +* Mon Oct 28 2019 Patsy Griffin - 2.28-74 +- Make nsswitch.conf more distribution friendly. + Improve nscd.conf comments. (#1747505) + +* Fri Oct 25 2019 Patsy Griffin - 2.28-73 +- Update system call names list to Linux 5.3 (#1764234) + +* Mon Jul 22 2019 Carlos O'Donell - 2.28-72 +- Skip wide buffer handling for legacy stdio handles (#1722215) + +* Mon Jul 22 2019 Carlos O'Donell - 2.28-71 +- Remove copy_file_range emulation (#1724975) + +* Mon Jul 22 2019 Carlos O'Donell - 2.28-70 +- Avoid nscd assertion failure during persistent db check (#1727152) + +* Mon Jul 22 2019 Carlos O'Donell - 2.28-69 +- Fix invalid free under valgrind with libdl (#1717438) + +* Thu Jul 18 2019 Carlos O'Donell - 2.28-68 +- Account for size of locale-archive in rpm package (#1725131) + +* Thu Jul 18 2019 Carlos O'Donell - 2.28-67 +- Reject IP addresses with trailing characters in getaddrinfo (#1727241) + +* Fri Jun 14 2019 Florian Weimer - 2.28-66 +- Avoid header conflict between and (#1699194) + +* Wed Jun 12 2019 Florian Weimer - 2.28-65 +- glibc-all-langpacks: Do not delete locale archive during update (#1717347) +- Do not mark /usr/lib/locale/locale-archive as a configuration file + because it is always automatically overwritten by build-locale-archive. + +* Mon Jun 10 2019 DJ Delorie - 2.28-64 +- Avoid ABI exposure of the NSS service_user type (#1710894) + +* Thu Jun 6 2019 Patsy Griffin Franklin - 2.28-63 +- Enable full ICMP errors for UDP DNS sockets. (#1670043) + +* Mon Jun 3 2019 Carlos O'Donell - 2.28-62 +- Convert post-install binary to rpm lua scriptlet (#1639346) + +* Mon Jun 3 2019 Florian Weimer - 2.28-61 +- Fix crash during wide stream buffer flush (#1710478) + +* Fri May 31 2019 Carlos O'Donell - 2.28-60 +- Add PF_XDP, AF_XDP and SOL_XDP from Linux 4.18 (#1706777) + +* Wed May 22 2019 DJ Delorie - 2.28-59 +- Add .gdb_index to debug information (#1612448) + +* Wed May 22 2019 DJ Delorie - 2.28-57 +- locale: Add LOCPATH diagnostics to the locale program (#1701605) + +* Fri May 17 2019 Patsy Griffin Franklin - 2.28-56 +- Fix hang in pldd. (#1702539) + +* Mon May 13 2019 Florian Weimer - 2.28-55 +- s390x string function improvements (#1659438) + +* Thu May 2 2019 Patsy Griffin Franklin - 2.28-54 +- Fix test suite failures due to race conditions in posix/tst-spawn + spawned processes. (#1659512) + +* Wed May 1 2019 DJ Delorie - 2.28-53 +- Add missing CFI data to __mpn_* functions on ppc64le (#1658901) + +* Fri Apr 26 2019 Arjun Shankar - 2.28-52 +- intl: Do not return NULL on asprintf failure in gettext (#1663035) + +* Fri Apr 26 2019 Florian Weimer - 2.28-51 +- Increase BIND_NOW coverage (#1639343) + +* Tue Apr 23 2019 Carlos O'Donell - 2.28-50 +- Fix pthread_rwlock_trywrlock and pthread_rwlock_tryrdlock stalls (#1659293) + +* Tue Apr 23 2019 Arjun Shankar - 2.28-49 +- malloc: Improve bad chunk detection (#1651283) + +* Mon Apr 22 2019 Patsy Griffin Franklin - 2.28-48 +- Add compiler barriers around modifications of the robust mutex list + for pthread_mutex_trylock. (#1672773) + +* Tue Apr 16 2019 DJ Delorie - 2.28-47 +- powerpc: Only enable HTM if kernel supports PPC_FEATURE2_HTM_NOSC (#1651742) + +* Fri Apr 12 2019 Florian Weimer - 2.28-46 +- Only build libm with -fno-math-errno (#1664408) + +* Tue Apr 2 2019 Florian Weimer - 2.28-45 +- ja_JP: Add new Japanese Era name (#1577438) + +* Wed Mar 6 2019 Florian Weimer - 2.28-44 +- math: Add XFAILs for some IBM 128-bit long double fma tests (#1623537) + +* Fri Mar 1 2019 Florian Weimer - 2.28-43 +- malloc: realloc ncopies integer overflow (#1662843) + +* Fri Dec 14 2018 Florian Weimer - 2.28-42 +- Fix rdlock stall with PREFER_WRITER_NONRECURSIVE_NP (#1654872) + +* Fri Dec 14 2018 Florian Weimer - 2.28-41 +- malloc: Implement double-free check for the thread cache (#1642094) + +* Thu Dec 13 2018 Florian Weimer - 2.28-40 +- Add upstream test case for CVE-2018-19591 (#1654010) + +* Thu Dec 13 2018 Florian Weimer - 2.28-39 +- Add GCC dependency for new inline string functions on ppc64le (#1652932) + +* Sat Dec 01 2018 Carlos O'Donell - 2.28-38 +- Add requires on explicit glibc version for glibc-nss-devel (#1649890) + +* Fri Nov 30 2018 Carlos O'Donell - 2.28-37 +- Fix data race in dynamic loader when using LD_AUDIT (#1635779) + +* Wed Nov 28 2018 Florian Weimer - 2.28-36 +- CVE-2018-19591: File descriptor leak in if_nametoindex (#1654010) + +* Mon Nov 26 2018 Florian Weimer - 2.28-35 +- Do not use parallel make for building locales (#1652229) + +* Tue Nov 20 2018 Florian Weimer - 2.28-34 +- support: Print timestamps in timeout handler (#1651274) + +* Tue Nov 20 2018 Florian Weimer - 2.28-33 +- Increase test timeout for libio/tst-readline (#1638520) + +* Tue Nov 20 2018 Florian Weimer - 2.28-32 +- Fix tzfile low-memory assertion failure (#1650571) + +* Tue Nov 20 2018 Florian Weimer - 2.28-31 +- Add newlines in __libc_fatal calls (#1650566) + +* Tue Nov 20 2018 Florian Weimer - 2.28-30 +- nscd: Fix use-after-free in addgetnetgrentX (#1650563) + +* Tue Nov 20 2018 Florian Weimer - 2.28-29 +- Update syscall names to Linux 4.19 (#1650560) + +* Tue Nov 13 2018 Florian Weimer - 2.28-28 +- kl_GL: Fix spelling of Sunday, should be "sapaat" (#1645597) + +* Tue Nov 13 2018 Florian Weimer - 2.28-27 +- Fix x86 CPU flags analysis for string function selection (#1641982) + +* Fri Nov 9 2018 Florian Weimer - 2.28-26 +- Reduce RAM requirements for stdlib/test-bz22786 (#1638523) + +* Fri Nov 9 2018 Florian Weimer - 2.28-25 +- x86: Improve enablement for 32-bit code using CET (#1645601) + +* Fri Nov 9 2018 Florian Weimer - 2.28-24 +- Fix crash in getaddrinfo_a when thread creation fails (#1646379) + +* Fri Nov 9 2018 Florian Weimer - 2.28-23 +- Fix race in pthread_mutex_lock related to PTHREAD_MUTEX_ELISION_NP (#1645604) + +* Fri Nov 9 2018 Florian Weimer - 2.28-22 +- Fix misreported errno on preadv2/pwritev2 (#1645596) + +* Fri Nov 9 2018 Florian Weimer - 2.28-21 +- Fix posix/tst-spawn4-compat test case (#1645593) + +* Fri Nov 9 2018 Florian Weimer - 2.28-20 +- Disable CET for binaries created by older link editors (#1614979) + +* Fri Nov 2 2018 Mike FABIAN - 2.28-19 +- Include Esperanto (eo) in glibc-all-langpacks (#1644303) + +* Thu Sep 27 2018 Florian Weimer - 2.28-18 +- stdlib/tst-setcontext9 test suite failure on ppc64le (#1623536) + +* Wed Sep 26 2018 Florian Weimer - 2.28-17 +- Add missing ENDBR32 in start.S (#1631730) + +* Wed Sep 26 2018 Florian Weimer - 2.28-16 +- Fix bug in generic strstr with large needles (#1631722) + +* Wed Sep 26 2018 Florian Weimer - 2.28-15 +- stdlib/tst-setcontext9 test suite failure (#1623536) + +* Wed Sep 26 2018 Florian Weimer - 2.28-14 +- gethostid: Missing NULL check for gethostbyname_r (#1631293) + +* Wed Sep 5 2018 Carlos O'Donell - 2.28-13 +- Provide compatibility support for linking against libpthread_nonshared.a + (#1614439) + +* Wed Sep 5 2018 Florian Weimer - 2.28-12 +- Add python3-devel build dependency (#1625592) + +* Wed Aug 29 2018 Florian Weimer - 2.28-11 +- Drop glibc-ldflags.patch and valgrind bug workaround (#1623456) + +* Wed Aug 29 2018 Florian Weimer - 2.28-10 +- regex: Fix memory overread when pattern contains NUL byte (#1622678) + +* Wed Aug 29 2018 Florian Weimer - 2.28-9 +- nptl: Fix waiters-after-spinning case in pthread_cond_broadcast (#1622675) + +* Tue Aug 14 2018 Florian Weimer - 2.28-8 +- nss_files aliases database file stream leak (#1615790) + +* Tue Aug 14 2018 Florian Weimer - 2.28-7 +- Fix static analysis warning in nscd user name allocation (#1615784) + +* Tue Aug 14 2018 Florian Weimer - 2.28-6 +- error, error_at_line: Add missing va_end calls (#1615781) + +* Mon Aug 13 2018 Carlos O'Donell - 2.28-5 +- Remove abort() warning in manual (#1577365) + +* Fri Aug 10 2018 Florian Weimer - 2.28-4 +- Fix regression in readdir64@GLIBC_2.1 compat symbol (#1614253) + +* Thu Aug 2 2018 Florian Weimer - 2.28-3 +- Log /proc/sysinfo if available (on s390x) + +* Thu Aug 2 2018 Florian Weimer - 2.28-2 +- Honor %%{valgrind_arches} + +* Wed Aug 01 2018 Florian Weimer - 2.27.9000-43 +- Update to glibc 2.28 release tarball: +- Translation updates +- x86/CET: Fix property note parser (swbz#23467) +- x86: Add tst-get-cpu-features-static to $(tests) (swbz#23458) + +* Mon Jul 30 2018 Florian Weimer - 2.27.9000-42 +- Auto-sync with upstream branch master, + commit af86087f02a5522d8801a11d8381e04f95e33162: +- x86/CET: Don't parse beyond the note end +- Fix Linux fcntl OFD locks tests on unsupported kernels +- x86: Populate COMMON_CPUID_INDEX_80000001 for Intel CPUs (swbz#23459) +- x86: Correct index_cpu_LZCNT (swbz#23456) +- Fix string/tst-xbzero-opt if build with gcc head + +* Thu Jul 26 2018 Florian Weimer - 2.27.9000-41 +- Build with --enable-cet on x86_64, i686 +- Auto-sync with upstream branch master, + commit cfba5dbb10cc3abde632b46c60c10b2843917035: +- Keep expected behaviour for [a-z] and [A-z] (#1607286) +- Additional ucontext tests +- Intel CET enhancements +- ISO C11 threads support +- Fix out-of-bounds access in IBM-1390 converter (swbz#23448) +- New locale Yakut (Sakha) for Russia (sah_RU) (swbz#22241) +- os_RU: Add alternative month names (swbz#23140) +- powerpc64: Always restore TOC on longjmp (swbz#21895) +- dsb_DE locale: Fix syntax error and add tests (swbz#23208) +- Improve performance of the generic strstr implementation +- regcomp: Fix off-by-one bug in build_equiv_class (swbz#23396) +- Fix out of bounds access in findidxwc (swbz#23442) + +* Fri Jul 13 2018 Carlos O'Donell - 2.27.9000-40 +- Fix file list for glibc RPM packaging (#1601011). + +* Wed Jul 11 2018 Florian Weimer - 2.27.9000-39 +- Add POWER9 multilib (downstream only) + +* Wed Jul 11 2018 Florian Weimer - 2.27.9000-38 +- Auto-sync with upstream branch master, + commit 93304f5f7a32f73b551266c5a181db51d97a71e4: +- Install header +- Put the correct Unicode version number 11.0.0 into the generated files + +* Wed Jul 11 2018 Florian Weimer - 2.27.9000-37 +- Work around valgrind issue on i686 (#1600034) + +* Tue Jul 10 2018 Florian Weimer - 2.27.9000-36 +- Auto-sync with upstream branch master, + commit fd70af45528d59a00eb3190ef6706cb299488fcd: +- Add the statx function +- regexec: Fix off-by-one bug in weight comparison (#1582229) +- nss_files: Fix re-reading of long lines (swbz#18991) +- aarch64: add HWCAP_ATOMICS to HWCAP_IMPORTANT +- aarch64: Remove HWCAP_CPUID from HWCAP_IMPORTANT +- conform/conformtest.pl: Escape literal braces in regular expressions +- x86: Use AVX_Fast_Unaligned_Load from Zen onwards. + +* Fri Jul 6 2018 Florian Weimer - 2.27.9000-35 +- Remove ppc64 multilibs + +* Fri Jul 06 2018 Florian Weimer - 2.27.9000-34 +- Auto-sync with upstream branch master, + commit 3a885c1f51b18852869a91cf59a1b39da1595c7a. + +* Thu Jul 5 2018 Florian Weimer - 2.27.9000-33 +- Enable build flags inheritance for nonshared flags + +* Wed Jul 4 2018 Florian Weimer - 2.27.9000-32 +- Add annobin annotations to assembler code (#1548438) + +* Wed Jul 4 2018 Florian Weimer - 2.27.9000-31 +- Enable -D_FORTIFY_SOURCE=2 for nonshared code + +* Mon Jul 02 2018 Florian Weimer - 2.27.9000-30 +- Auto-sync with upstream branch master, + commit b7b88cea4151d85eafd7ababc2e4b7ae1daeedf5: +- New locale: dsb_DE (Lower Sorbian) + +* Fri Jun 29 2018 Florian Weimer - 2.27.9000-29 +- Drop glibc-deprecate_libcrypt.patch. Variant applied upstream. (#1566464) +- Drop glibc-linux-timespec-header-compat.patch. Upstreamed. +- Auto-sync with upstream branch master, + commit e69d994a63afc2d367f286a2a7df28cbf710f0fe. + +* Thu Jun 28 2018 Florian Weimer - 2.27.9000-28 +- Drop glibc-rh1315108.patch. extend_alloca was removed upstream. (#1315108) +- Auto-sync with upstream branch master, + commit c49e18222e4c40f21586dabced8a49732d946917. + +* Thu Jun 21 2018 Florian Weimer - 2.27.9000-27 +- Compatibility fix for and + +* Thu Jun 21 2018 Florian Weimer - 2.27.9000-26 +- Auto-sync with upstream branch master, + commit f496b28e61d0342f579bf794c71b80e9c7d0b1b5. + +* Mon Jun 18 2018 Florian Weimer - 2.27.9000-25 +- Auto-sync with upstream branch master, + commit f2857da7cdb65bfad75ee30981f5b2fde5bbb1dc. + +* Mon Jun 18 2018 Florian Weimer - 2.27.9000-24 +- Auto-sync with upstream branch master, + commit 14beef7575099f6373f9a45b4656f1e3675f7372: +- iconv: Make IBM273 equivalent to ISO-8859-1 (#1592270) + +* Mon Jun 18 2018 Florian Weimer - 2.27.9000-23 +- Inherit the -msse2 build flag as well (#1592212) + +* Fri Jun 01 2018 Florian Weimer - 2.27.9000-22 +- Modernise nsswitch.conf defaults (#1581809) +- Adjust build flags inheritence from redhat-rpm-config +- Auto-sync with upstream branch master, + commit 104502102c6fa322515ba0bb3c95c05c3185da7a. + +* Fri May 25 2018 Florian Weimer - 2.27.9000-21 +- Auto-sync with upstream branch master, + commit c1dc1e1b34873db79dfbfa8f2f0a2abbe28c0514. + +* Wed May 23 2018 Florian Weimer - 2.27.9000-20 +- Auto-sync with upstream branch master, + commit 7f9f1ecb710eac4d65bb02785ddf288cac098323: +- CVE-2018-11237: Buffer overflow in __mempcpy_avx512_no_vzeroupper (#1581275) +- Drop glibc-rh1452750-allocate_once.patch, + glibc-rh1452750-libidn2.patch. Applied upstream. + +* Wed May 23 2018 Florian Weimer - 2.27.9000-19 +- Auto-sync with upstream branch master, + commit 8f145c77123a565b816f918969e0e35ee5b89153. + +* Thu May 17 2018 Florian Weimer - 2.27.9000-18 +- Do not run telinit u on upgrades (#1579225) +- Auto-sync with upstream branch master, + commit 632a6cbe44cdd41dba7242887992cdca7b42922a. + +* Fri May 11 2018 Florian Weimer - 2.27.9000-17 +- Avoid exporting some Sun RPC symbols with default versions (#1577210) +- Inherit the -mstackrealign flag if it is set +- Inherit compiler flags in the original order +- Auto-sync with upstream branch master, + commit 89aacb513eb77549a29df2638913a0f8178cf3f5: +- CVE-2018-11236: realpath: Fix path length overflow (#1581270, swbz#22786) + +* Fri May 11 2018 Florian Weimer - 2.27.9000-16 +- Use /usr/bin/python3 for benchmarks scripts (#1577223) + +* Thu Apr 19 2018 Florian Weimer - 2.27.9000-15 +- Auto-sync with upstream branch master, + commit 0085be1415a38b40a5a1a12e49368498f1687380. + +* Mon Apr 09 2018 Florian Weimer - 2.27.9000-14 +- Auto-sync with upstream branch master, + commit 583a27d525ae189bdfaa6784021b92a9a1dae12e. + +* Thu Mar 29 2018 Florian Weimer - 2.27.9000-13 +- Auto-sync with upstream branch master, + commit d39c0a459ef32a41daac4840859bf304d931adab: +- CVE-2017-18269: memory corruption in i386 memmove (#1580934) + +* Mon Mar 19 2018 Florian Weimer - 2.27.9000-12 +- Auto-sync with upstream branch master, + commit fbce6f7260c3847f14dfa38f60c9111978fb33a5. + +* Fri Mar 16 2018 Florian Weimer - 2.27.9000-11 +- Auto-sync with upstream branch master, + commit 700593fdd7aef1e36cfa8bad969faab76a6facda. + +* Wed Mar 14 2018 Florian Weimer - 2.27.9000-10 +- Auto-sync with upstream branch master, + commit 7108f1f944792ac68332967015d5e6418c5ccc88. + +* Mon Mar 12 2018 Florian Weimer - 2.27.9000-9 +- Auto-sync with upstream branch master, + commit da6d4404ecfd7eacba8c096b0761a5758a59da4b. + +* Tue Mar 6 2018 Florian Weimer - 2.27.9000-8 +- Enable annobin annotations (#1548438) + +* Thu Mar 01 2018 Florian Weimer - 2.27.9000-7 +- Auto-sync with upstream branch master, + commit 1a2f44a848663036c8a14671fe0faa3fed0b2a25: +- Remove spurios reference to libpthread_nonshared.a + +* Thu Mar 01 2018 Florian Weimer - 2.27.9000-6 +- Switch back to upstream master branch +- Drop glibc-rh1013801.patch, applied upstream. +- Drop glibc-fedora-nptl-linklibc.patch, no longer needed. +- Auto-sync with upstream branch master, + commit bd60ce86520b781ca24b99b2555e2ad389bbfeaa. + +* Wed Feb 28 2018 Florian Weimer - 2.27-5 +- Inherit as many flags as possible from redhat-rpm-config (#1550914) + +* Mon Feb 19 2018 Richard W.M. Jones - 2.27-4 +- riscv64: Add symlink from /usr/lib64/lp64d -> /usr/lib64 for ABI compat. +- riscv64: Disable valgrind smoke test on this architecture. + +* Wed Feb 14 2018 Florian Weimer - 2.27-3 +- Spec file cleanups: + - Remove %%defattr(-,root,root) + - Use shell to run ldconfig %%transfiletrigger + - Move %%transfiletrigger* to the glibc-common subpackage + - Trim changelog + - Include ChangeLog.old in the source RPM + +* Wed Feb 7 2018 Florian Weimer - 2.27-2.1 +- Linux: use reserved name __key in pkey_get (#1542643) +- Auto-sync with upstream branch release/2.27/master, + commit 56170e064e2b21ce204f0817733e92f1730541ea. + +* Wed Feb 07 2018 Fedora Release Engineering +- Rebuilt for https://fedoraproject.org/wiki/Fedora_28_Mass_Rebuild + +* Mon Feb 05 2018 Carlos O'Donell - 2.27-1 +- Update to released glibc 2.27. +- Auto-sync with upstream branch master, + commit 23158b08a0908f381459f273a984c6fd328363cb. + +* Tue Jan 30 2018 Richard W.M. Jones - 2.26.9000-52 +- Disable -fstack-clash-protection on riscv64: + not supported even by GCC 7.3.1 on this architecture. + +* Mon Jan 29 2018 Florian Weimer - 2.26.9000-51 +- Explicitly run ldconfig in the buildroot +- Do not run ldconfig from scriptlets +- Put triggers into the glibc-common package, do not pass arguments to ldconfig + +* Mon Jan 29 2018 Florian Weimer - 2.26.9000-50 +- Auto-sync with upstream branch master, + commit cdd14619a713ab41e26ba700add4880604324dbb: +- libnsl: Turn remaining symbols into compat symbols (swbz#22701) +- be_BY, be_BY@latin, lt_LT, el_CY, el_GR, ru_RU, ru_UA, uk_UA: + Add alternative month names (swbz#10871) +- x86: Revert Intel CET changes to __jmp_buf_tag (swbz#22743) +- aarch64: Revert the change of the __reserved member of mcontext_t + +* Mon Jan 29 2018 Igor Gnatenko - 2.26.9000-49 +- Add file triggers to do ldconfig calls automatically + +* Mon Jan 22 2018 Florian Weimer - 2.26.9000-48 +- Auto-sync with upstream branch master, + commit 21c0696cdef617517de6e25711958c40455c554f: +- locale: Implement alternative month names (swbz#10871) +- locale: Change month names for pl_PL (swbz#10871) + +* Mon Jan 22 2018 Florian Weimer - 2.26.9000-47 +- Unconditionally build without libcrypt + +* Fri Jan 19 2018 Björn Esser - 2.26.9000-46 +- Remove deprecated libcrypt, gets replaced by libxcrypt +- Add applicable Requires on libxcrypt + +* Fri Jan 19 2018 Florian Weimer - 2.26.9000-45 +- Drop static PIE support on aarch64. It leads to crashes at run time. +- Remove glibc-rpcgen subpackage. See rpcsvc-proto. (#1531540) + +* Fri Jan 19 2018 Florian Weimer - 2.26.9000-44 +- Correct the list of static PIE architectures (#1247050) +- glibc_post_upgrade: Remove process restart logic +- glibc_post_upgrade: Integrate into the build process +- glibc_post_upgrade: Do not clean up tls subdirectories +- glibc_post_upgrade: Drop ia64 support +- Remove architecture-specific symbolic link for iconvconfig +- Auto-sync with upstream branch master, + commit 4612268a0ad8e3409d8ce2314dd2dd8ee0af5269: +- powerpc: Fix syscalls during early process initialization (swbz#22685) + +* Fri Jan 19 2018 Florian Weimer - 2.26.9000-43 +- Enable static PIE support on i386, x86_64 (#1247050) +- Remove add-on support (already gone upstream) +- Rework test suite status reporting +- Auto-sync with upstream branch master, + commit 64f63cb4583ecc1ba16c7253aacc192b6d088511: +- malloc: Fix integer overflows in memalign and malloc functions (swbz#22343) +- x86-64: Properly align La_x86_64_retval to VEC_SIZE (swbz#22715) +- aarch64: Update bits/hwcap.h for Linux 4.15 +- Add NT_ARM_SVE to elf.h + +* Wed Jan 17 2018 Florian Weimer - 2.26.9000-42 +- CVE-2017-14062, CVE-2016-6261, CVE-2016-6263: + Use libidn2 for IDNA support (#1452750) + +* Mon Jan 15 2018 Florian Weimer - 2.26.9000-41 +- CVE-2018-1000001: Make getcwd fail if it cannot obtain an absolute path + (#1533837) +- elf: Synchronize DF_1_* flags with binutils (#1439328) +- Auto-sync with upstream branch master, + commit 860b0240a5645edd6490161de3f8d1d1f2786025: +- aarch64: fix static pie enabled libc when main is in a shared library +- malloc: Ensure that the consolidated fast chunk has a sane size + +* Fri Jan 12 2018 Florian Weimer - 2.26.9000-40 +- libnsl: Do not install libnsl.so, libnsl.a (#1531540) +- Use unversioned Supplements: for langpacks (#1490725) +- Auto-sync with upstream branch master, + commit 9a08a366a7e7ddffe62113a9ffe5e50605ea0924: +- hu_HU locale: Avoid double space (swbz#22657) +- math: Make default libc_feholdsetround_noex_ctx use __feholdexcept + (swbz#22702) + +* Thu Jan 11 2018 Florian Weimer - 2.26.9000-39 +- nptl: Open libgcc.so with RTLD_NOW during pthread_cancel (#1527887) +- Introduce libnsl subpackage and remove NIS headers (#1531540) +- Use versioned Obsoletes: for libcrypt-nss. +- Auto-sync with upstream branch master, + commit 08c6e95234c60a5c2f37532d1111acf084f39345: +- nptl: Add tst-minstack-cancel, tst-minstack-exit (swbz#22636) +- math: ldbl-128ibm log1pl (-qNaN) spurious "invalid" exception (swbz#22693) + +* Wed Jan 10 2018 Florian Weimer - 2.26.9000-38 +- nptl: Fix stack guard size accounting (#1527887) +- Remove invalid Obsoletes: on glibc-header provides +- Require python3 instead of python during builds +- Auto-sync with upstream branch master, + commit 09085ede12fb9650f286bdcd805609ae69f80618: +- math: ldbl-128ibm lrintl/lroundl missing "invalid" exceptions (swbz#22690) +- x86-64: Add sincosf with vector FMA + +* Mon Jan 8 2018 Florian Weimer - 2.26.9000-37 +- Add glibc-rpcgen subpackage, until the replacement is packaged (#1531540) + +* Mon Jan 08 2018 Florian Weimer - 2.26.9000-36 +- Auto-sync with upstream branch master, + commit 579396ee082565ab5f42ff166a264891223b7b82: +- nptl: Add test for callee-saved register restore in pthread_exit +- getrlimit64: fix for 32-bit configurations with default version >= 2.2 +- elf: Add linux-4.15 VDSO hash for RISC-V +- elf: Add RISC-V dynamic relocations to elf.h +- powerpc: Fix error message during relocation overflow +- prlimit: Replace old_rlimit RLIM64_INFINITY with RLIM_INFINITY (swbz#22678) + +* Fri Jan 05 2018 Florian Weimer - 2.26.9000-35 +- Remove sln (#1531546) +- Remove Sun RPC interfaces (#1531540) +- Rebuild with newer GCC to fix pthread_exit stack unwinding issue (#1529549) +- Auto-sync with upstream branch master, + commit f1a844ac6389ea4e111afc019323ca982b5b027d: +- CVE-2017-16997: elf: Check for empty tokens before DST expansion (#1526866) +- i386: In makecontext, align the stack before calling exit (swbz#22667) +- x86, armhfp: sync sys/ptrace.h with Linux 4.15 (swbz#22433) +- elf: check for rpath emptiness before making a copy of it +- elf: remove redundant is_path argument +- elf: remove redundant code from is_dst +- elf: remove redundant code from _dl_dst_substitute +- scandir: fix wrong assumption about errno (swbz#17804) +- Deprecate external use of libio.h and _G_config.h + +* Fri Dec 22 2017 Florian Weimer - 2.26.9000-34 +- Auto-sync with upstream branch master, + commit bad7a0c81f501fbbcc79af9eaa4b8254441c4a1f: +- copy_file_range: New function to copy file data +- nptl: Consolidate pthread_{timed,try}join{_np} +- nptl: Implement pthread_self in libc.so (swbz#22635) +- math: Provide a C++ version of iseqsig (swbz#22377) +- elf: remove redundant __libc_enable_secure check from fillin_rpath +- math: Avoid signed shift overflow in pow (swbz#21309) +- x86: Add feature_1 to tcbhead_t (swbz#22563) +- x86: Update cancel_jmp_buf to match __jmp_buf_tag (swbz#22563) +- ld.so: Examine GLRO to detect inactive loader (swbz#20204) +- nscd: Fix nscd readlink argument aliasing (swbz#22446) +- elf: do not substitute dst in $LD_LIBRARY_PATH twice (swbz#22627) +- ldconfig: set LC_COLLATE to C (swbz#22505) +- math: New generic sincosf +- powerpc: st{r,p}cpy optimization for aligned strings +- CVE-2017-1000409: Count in expanded path in _dl_init_path (#1524867) +- CVE-2017-1000408: Compute correct array size in _dl_init_paths (#1524867) +- x86-64: Remove sysdeps/x86_64/fpu/s_cosf.S +- aarch64: Improve strcmp unaligned performance + +* Wed Dec 13 2017 Florian Weimer - 2.26.9000-33 +- Remove power6 platform directory (#1522675) + +* Wed Dec 13 2017 Florian Weimer - 2.26.9000-32 +- Obsolete the libcrypt-nss subpackage (#1525396) +- armhfp: Disable -fstack-clash-protection due to GCC bug (#1522678) +- ppc64: Disable power6 multilib due to GCC bug (#1522675) +- Auto-sync with upstream branch master, + commit 243b63337c2c02f30ec3a988ecc44bc0f6ffa0ad: +- libio: Free backup area when it not required (swbz#22415) +- math: Fix nextafter and nexttoward declaration (swbz#22593) +- math: New generic cosf +- powerpc: POWER8 memcpy optimization for cached memory +- x86-64: Add sinf with FMA +- x86-64: Remove sysdeps/x86_64/fpu/s_sinf.S +- math: Fix ctanh (0 + i NaN), ctanh (0 + i Inf) (swbz#22568) +- lt_LT locale: Base collation on copy "iso14651_t1" (swbz#22524) +- math: Add _Float32 function aliases +- math: Make cacosh (0 + iNaN) return NaN + i pi/2 (swbz#22561) +- hsb_DE locale: Base collation on copy "iso14651_t1" (swbz#22515) + +* Wed Dec 06 2017 Florian Weimer - 2.26.9000-31 +- Add elision tunables. Drop related configure flag. (#1383986) +- Auto-sync with upstream branch master, + commit 37ac8e635a29810318f6d79902102e2e96b2b5bf: +- Linux: Implement interfaces for memory protection keys +- math: Add _Float64, _Float32x function aliases +- math: Use sign as double for reduced case in sinf +- math: fix sinf(NAN) +- math: s_sinf.c: Replace floor with simple casts +- et_EE locale: Base collation on iso14651_t1 (swbz#22517) +- tr_TR locale: Base collation on iso14651_t1 (swbz#22527) +- hr_HR locale: Avoid single code points for digraphs in LC_TIME (swbz#10580) +- S390: Fix backtrace in vdso functions + +* Mon Dec 04 2017 Florian Weimer - 2.26.9000-30 +- Add build dependency on bison +- Auto-sync with upstream branch master, + commit 7863a7118112fe502e8020a0db0fa74fef281f29: +- math: New generic sinf (swbz#5997) +- is_IS locale: Base collation on iso14651_t1 (swbz#22519) +- intl: Improve reproducibility by using bison (swbz#22432) +- sr_RS, bs_BA locales: make collation rules the same as for hr_HR (wbz#22534) +- hr_HR locale: various updates (swbz#10580) +- x86: Make a space in jmpbuf for shadow stack pointer +- CVE-2017-17426: malloc: Fix integer overflow in tcache (swbz#22375) +- locale: make forward accent sorting the default in collating (swbz#17750) + +* Wed Nov 29 2017 Florian Weimer - 2.26.9000-29 +- Enable -fstack-clash-protection (#1512531) +- Auto-sync with upstream branch master, + commit a55430cb0e261834ce7a4e118dd9e0f2b7fb14bc: +- elf: Properly compute offsets of note descriptor and next note (swbz#22370) +- cs_CZ locale: Base collation on iso14651_t1 (swbz#22336) +- Implement the mlock2 function +- Add _Float64x function aliases +- elf: Consolidate link map sorting +- pl_PL locale: Base collation on iso14651_t1 (swbz#22469) +- nss: Export nscd hash function as __nss_hash (swbz#22459) + +* Thu Nov 23 2017 Florian Weimer - 2.26.9000-28 +- Auto-sync with upstream branch master, + commit cccb6d4e87053ed63c74aee063fa84eb63ebf7b8: +- sigwait can fail with EINTR (#1516394) +- Add memfd_create function +- resolv: Fix p_secstodate overflow handling (swbz#22463) +- resolv: Obsolete p_secstodate +- Avoid use of strlen in getlogin_r (swbz#22447) +- lv_LV locale: fix collation (swbz#15537) +- S390: Add cfi information for start routines in order to stop unwinding +- aarch64: Optimized memset for falkor + +* Sun Nov 19 2017 Florian Weimer - 2.26.9000-27 +- Auto-sync with upstream branch master, + commit f6e965ee94b37289f64ecd3253021541f7c214c3: +- powerpc: AT_HWCAP2 bit PPC_FEATURE2_HTM_NO_SUSPEND +- aarch64: Add HWCAP_DCPOP bit +- ttyname, ttyname_r: Don't bail prematurely (swbz#22145) +- signal: Optimize sigrelse implementation +- inet: Check length of ifname in if_nametoindex (swbz#22442) +- malloc: Account for all heaps in an arena in malloc_info (swbz#22439) +- malloc: Add missing arena lock in malloc_info (swbz#22408) +- malloc: Use __builtin_tgmath in tgmath.h with GCC 8 (swbz#21660) +- locale: Replaced unicode sequences in the ASCII printable range +- resolv: More precise checks in res_hnok, res_dnok (swbz#22409, swbz#22412) +- resolv: ns_name_pton should report trailing \ as error (swbz#22413) +- locale: mfe_MU, miq_NI, an_ES, kab_DZ, om_ET: Escape / in d_fmt (swbz#22403) + +* Tue Nov 07 2017 Florian Weimer - 2.26.9000-26 +- Auto-sync with upstream branch master, + commit 6b86036452b9ac47b4ee7789a50f2f37df7ecc4f: +- CVE-2017-15804: glob: Fix buffer overflow during GLOB_TILDE unescaping +- powerpc: Use latest string function optimization for internal function calls +- math: No _Float128 support for ppc64le -mlong-double-64 (swbz#22402) +- tpi_PG locale: Fix wrong d_fmt +- aarch64: Disable lazy symbol binding of TLSDESC +- tpi_PG locale: fix syntax error (swbz#22382) +- i586: Use conditional branches in strcpy.S (swbz#22353) +- ffsl, ffsll: Declare under __USE_MISC, not just __USE_GNU +- csb_PL locale: Fix abmon/mon for March (swbz#19485) +- locale: Various yesstr/nostr/yesexpr/noexpr fixes (swbz#15260, swbz#15261) +- localedef: Add --no-warnings/--warnings option +- powerpc: Replace lxvd2x/stxvd2x with lvx/stvx in P7's memcpy/memmove +- locale: Use ASCII as much as possible in LC_MESSAGES +- Add new locale yuw_PG (swbz#20952) +- malloc: Add single-threaded path to malloc/realloc/calloc/memalloc +- i386: Replace assembly versions of e_powf with generic e_powf.c +- i386: Replace assembly versions of e_log2f with generic e_log2f.c +- x86-64: Add powf with FMA +- x86-64: Add logf with FMA +- i386: Replace assembly versions of e_logf with generic e_logf.c +- i386: Replace assembly versions of e_exp2f with generic e_exp2f.c +- x86-64: Add exp2f with FMA +- i386: Replace assembly versions of e_expf with generic e_expf.c + +* Sat Oct 21 2017 Florian Weimer - 2.26.9000-25 +- Auto-sync with upstream branch master, + commit 797ba44ba27521261f94cc521f1c2ca74f650147: +- math: Add bits/floatn.h defines for more _FloatN / _FloatNx types +- posix: Fix improper assert in Linux posix_spawn (swbz#22273) +- x86-64: Use fxsave/xsave/xsavec in _dl_runtime_resolve (swbz#21265) +- CVE-2017-15670: glob: Fix one-byte overflow (#1504807) +- malloc: Add single-threaded path to _int_free +- locale: Add new locale kab_DZ (swbz#18812) +- locale: Add new locale shn_MM (swbz#13605) + +* Fri Oct 20 2017 Florian Weimer - 2.26.9000-24 +- Use make -O to serialize make output +- Auto-sync with upstream branch master, + commit 63b4baa44e8d22501c433c4093aa3310f91b6aa2: +- sysconf: Fix missing definition of UIO_MAXIOV on Linux (#1504165) +- Install correct bits/long-double.h for MIPS64 (swbz#22322) +- malloc: Fix deadlock in _int_free consistency check +- x86-64: Don't set GLRO(dl_platform) to NULL (swbz#22299) +- math: Add _Float128 function aliases +- locale: Add new locale mjw_IN (swbz#13994) +- aarch64: Rewrite elf_machine_load_address using _DYNAMIC symbol +- powerpc: fix check-before-set in SET_RESTORE_ROUND +- locale: Use U+202F as thousands separators in pl_PL locale (swbz#16777) +- math: Use __f128 to define FLT128_* constants in include/float.h for old GCC +- malloc: Improve malloc initialization sequence (swbz#22159) +- malloc: Use relaxed atomics for malloc have_fastchunks +- locale: New locale ca_ES@valencia (swbz#2522) +- math: Let signbit use the builtin in C++ mode with gcc < 6.x (swbz#22296) +- locale: Place monetary symbol in el_GR, el_CY after the amount (swbz#22019) + +* Tue Oct 17 2017 Florian Weimer - 2.26.9000-23 +- Switch to .9000 version numbers during development + +* Tue Oct 17 2017 Florian Weimer - 2.26.90-22 +- Auto-sync with upstream branch master, + commit c38a4bfd596db2be2b9c1f96715bdc833eab760a: +- malloc: Use compat_symbol_reference in libmcheck (swbz#22050) + +* Mon Oct 16 2017 Florian Weimer - 2.26.90-21 +- Auto-sync with upstream branch master, + commit 596f70134a8f11967c65c1d55a94a3a2718c731d: +- Silence -O3 -Wall warning in malloc/hooks.c with GCC 7 (swbz#22052) +- locale: No warning for non-symbolic character (swbz#22295) +- locale: Allow "" int_curr_Symbol (swbz#22294) +- locale: Fix localedef exit code (swbz#22292) +- nptl: Preserve error in setxid thread broadcast in coredumps (swbz#22153) +- powerpc: Avoid putting floating point values in memory (swbz#22189) +- powerpc: Fix the carry bit on mpn_[add|sub]_n on POWER7 (swbz#22142) +- Support profiling PIE (swbz#22284) + +* Wed Oct 11 2017 Florian Weimer - 2.26.90-20 +- Auto-sync with upstream branch master, + commit d8425e116cdd954fea0c04c0f406179b5daebbb3: +- nss_files performance issue in multi mode (swbz#22078) +- Ensure C99 and C11 interfaces are available for C++ (swbz#21326) + +* Mon Oct 09 2017 Florian Weimer - 2.26.90-19 +- Move /var/db/Makefile to nss_db (#1498900) +- Auto-sync with upstream branch master, + commit 645ac9aaf89e3311949828546df6334322f48933: +- openpty: use TIOCGPTPEER to open slave side fd + +* Fri Oct 06 2017 Carlos O'Donell - 2.26.90-18 +- Auto-sync with upstream master, + commit 1e26d35193efbb29239c710a4c46a64708643320. +- malloc: Fix tcache leak after thread destruction (swbz#22111) +- powerpc: Fix IFUNC for memrchr. +- aarch64: Optimized implementation of memmove for Qualcomm Falkor +- Always do locking when iterating over list of streams (swbz#15142) +- abort: Do not flush stdio streams (swbz#15436) + +* Wed Oct 04 2017 Florian Weimer - 2.26.90-17 +- Move nss_compat to the main glibc package (#1400538) +- Auto-sync with upstream master, + commit 11c4f5010c58029e73e656d5df4f8f42c9b8e877: +- crypt: Use NSPR header files in addition to NSS header files (#1489339) +- math: Fix yn(n,0) without SVID wrapper (swbz#22244) +- math: Fix log2(0) and log(10) in downward rounding (swbz#22243) +- math: Add C++ versions of iscanonical for ldbl-96, ldbl-128ibm (swbz#22235) +- powerpc: Optimize memrchr for power8 +- Hide various internal functions (swbz#18822) + +* Sat Sep 30 2017 Florian Weimer - 2.26.90-16 +- Auto-sync with upstream master, + commit 1e2bffd05c36a9be30d7092d6593a9e9aa009ada: +- Add IBM858 charset (#1416405) +- Update kernel version in syscall-names.list to 4.13 +- Add Linux 4.13 constants to bits/fcntl-linux.h +- Add fcntl sealing interfaces from Linux 3.17 to bits/fcntl-linux.h +- math: New generic powf, log2f, logf +- Fix nearbyint arithmetic moved before feholdexcept (swbz#22225) +- Mark __dso_handle as hidden (swbz#18822) +- Skip PT_DYNAMIC segment with p_filesz == 0 (swbz#22101) +- glob now matches dangling symbolic links (swbz#866, swbz#22183) +- nscd: Release read lock after resetting timeout (swbz#22161) +- Avoid __MATH_TG in C++ mode with -Os for fpclassify (swbz#22146) +- Fix dlclose/exit race (swbz#22180) +- x86: Add SSE4.1 trunc, truncf (swbz#20142) +- Fix atexit/exit race (swbz#14333) +- Use execveat syscall in fexecve (swbz#22134) +- Enable unwind info in libc-start.c and backtrace.c +- powerpc: Avoid misaligned stores in memset +- powerpc: build some IFUNC math functions for libc and libm (swbz#21745) +- Removed redundant data (LC_TIME and LC_MESSAGES) for niu_NZ (swbz#22023) +- Fix LC_TELEPHONE for az_AZ (swbz#22112) +- x86: Add MathVec_Prefer_No_AVX512 to cpu-features (swbz#21967) +- x86: Add x86_64 to x86-64 HWCAP (swbz#22093) +- Finish change from “Bengali” to “Bangla” (swbz#14925) +- posix: fix glob bugs with long login names (swbz#1062) +- posix: Fix getpwnam_r usage (swbz#1062) +- posix: accept inode 0 is a valid inode number (swbz#19971) +- Remove redundant LC_TIME data in om_KE (swbz#22100) +- Remove remaining _HAVE_STRING_ARCH_* definitions (swbz#18858) +- resolv: Fix memory leak with OOM during resolv.conf parsing (swbz#22095) +- Add miq_NI locale for Miskito (swbz#20498) +- Fix bits/math-finite.h exp10 condition (swbz#22082) + +* Mon Sep 04 2017 Florian Weimer - 2.26.90-15 +- Auto-sync with upstream master, + commit b38042f51430974642616a60afbbf96fd0b98659: +- Implement tmpfile with O_TMPFILE (swbz#21530) +- Obsolete pow10 functions +- math.h: Warn about an already-defined log macro + +* Fri Sep 01 2017 Florian Weimer - 2.26.90-14 +- Build glibc with -O2 (following the upstream default). +- Auto-sync with upstream master, + commit f4a6be2582b8dfe8adfa68da3dd8decf566b3983: +- malloc: Abort on heap corruption, without a backtrace (swbz#21754) +- getaddrinfo: Return EAI_NODATA for gethostbyname2_r with NO_DATA (swbz#21922) +- getaddrinfo: Fix error handling in gethosts (swbz#21915) (swbz#21922) +- Place $(elf-objpfx)sofini.os last (swbz#22051) +- Various locale fixes (swbz#15332, swbz#22044) + +* Wed Aug 30 2017 Florian Weimer - 2.26.90-13 +- Drop glibc-rh952799.patch, applied upstream (#952799, swbz#22025) +- Auto-sync with upstream master, + commit 5f9409b787c5758fc277f8d1baf7478b752b775d: +- Various locale fixes (swbz#22022, swbz#22038, swbz#21951, swbz#13805, + swbz#21971, swbz#21959) +- MIPS/o32: Fix internal_syscall5/6/7 (swbz#21956) +- AArch64: Fix procfs.h not to expose stdint.h types +- iconv_open: Fix heap corruption on gconv_init failure (swbz#22026) +- iconv: Mangle __btowc_fct even without __init_fct (swbz#22025) +- Fix bits/math-finite.h _MSUF_ expansion namespace (swbz#22028) +- Provide a C++ version of iszero that does not use __MATH_TG (swbz#21930) + +* Mon Aug 28 2017 Florian Weimer - 2.26.90-12 +- Auto-sync with upstream master, + commit 2dba5ce7b8115d6a2789bf279892263621088e74. + +* Fri Aug 25 2017 Florian Weimer - 2.26.90-11 +- Auto-sync with upstream master, + commit 3d7b66f66cb223e899a7ebc0f4c20f13e711c9e0: +- string/stratcliff.c: Replace int with size_t (swbz#21982) +- Fix tgmath.h handling of complex integers (swbz#21684) + +* Thu Aug 24 2017 Florian Weimer - 2.26.90-10 +- Use an architecture-independent system call list (#1484729) +- Drop glibc-fedora-include-bits-ldbl.patch (#1482105) + +* Tue Aug 22 2017 Florian Weimer - 2.26.90-9 +- Auto-sync with upstream master, + commit 80f91666fed71fa3dd5eb5618739147cc731bc89. + +* Mon Aug 21 2017 Florian Weimer - 2.26.90-8 +- Auto-sync with upstream master, + commit a8410a5fc9305c316633a5a3033f3927b759be35: +- Obsolete matherr, _LIB_VERSION, libieee.a. + +* Mon Aug 21 2017 Florian Weimer - 2.26.90-7 +- Auto-sync with upstream master, + commit 4504783c0f65b7074204c6126c6255ed89d6594e. + +* Mon Aug 21 2017 Florian Weimer - 2.26.90-6 +- Auto-sync with upstream master, + commit b5889d25e9bf944a89fdd7bcabf3b6c6f6bb6f7c: +- assert: Support types without operator== (int) (#1483005) + +* Mon Aug 21 2017 Florian Weimer - 2.26.90-5 +- Auto-sync with upstream master, + commit 2585d7b839559e665d5723734862fbe62264b25d: +- Do not use generic selection in C++ mode +- Do not use __builtin_types_compatible_p in C++ mode (#1481205) +- x86-64: Check FMA_Usable in ifunc-mathvec-avx2.h (swbz#21966) +- Various locale fixes (swbz#21750, swbz#21960, swbz#21959, swbz#19852) +- Fix sigval namespace (swbz#21944) +- x86-64: Optimize e_expf with FMA (swbz#21912) +- Adjust glibc-rh827510.patch. + +* Wed Aug 16 2017 Tomasz Kłoczko - 2.26-4 +- Remove 'Buildroot' tag, 'Group' tag, and '%%clean' section, and don't + remove the buildroot in '%%install', all per Fedora Packaging Guidelines + (#1476839) + +* Wed Aug 16 2017 Florian Weimer - 2.26.90-3 +- Auto-sync with upstream master, + commit 403143e1df85dadd374f304bd891be0cd7573e3b: +- x86-64: Align L(SP_RANGE)/L(SP_INF_0) to 8 bytes (swbz#21955) +- powerpc: Add values from Linux 4.8 to +- S390: Add new s390 platform z14. +- Various locale fixes (swbz#14925, swbz#20008, swbz#20482, swbz#12349 + swbz#19982, swbz#20756, swbz#20756, swbz#21836, swbz#17563, swbz#16905, + swbz#21920, swbz#21854) +- NSS: Replace exported NSS lookup functions with stubs (swbz#21962) +- i386: Do not set internal_function +- assert: Suppress pedantic warning caused by statement expression (swbz#21242) +- powerpc: Restrict xssqrtqp operands to Vector Registers (swbz#21941) +- sys/ptrace.h: remove obsolete PTRACE_SEIZE_DEVEL constant (swbz#21928) +- Remove __qaddr_t, __long_double_t +- Fix uc_* namespace (swbz#21457) +- nss: Call __resolv_context_put before early return in get*_r (swbz#21932) +- aarch64: Optimized memcpy for Qualcomm Falkor processor +- manual: Document getcontext uc_stack value on Linux (swbz#759) +- i386: Add (swbz#21913) +- Don't use IFUNC resolver for longjmp or system in libpthread (swbz#21041) +- Fix XPG4.2 bits/sigaction.h namespace (swbz#21899) +- x86-64: Add FMA multiarch functions to libm +- i386: Support static PIE in start.S +- Compile tst-prelink.c without PIE (swbz#21815) +- x86-64: Use _dl_runtime_resolve_opt only with AVX512F (swbz#21871) +- x86: Remove __memset_zero_constant_len_parameter (swbz#21790) + +* Wed Aug 16 2017 Florian Weimer - 2.26-2 +- Disable multi-arch (IFUNC string functions) on i686 (#1471427) +- Remove nosegneg 32-bit Xen PV support libraries (#1482027) +- Adjust spec file to RPM changes + +* Thu Aug 03 2017 Carlos O'Donell - 2.26-1 +- Update to released glibc 2.26. +- Auto-sync with upstream master, + commit 2aad4b04ad7b17a2e6b0e66d2cb4bc559376617b. +- getaddrinfo: Release resolver context on error in gethosts (swbz#21885)